summaryrefslogtreecommitdiff
path: root/backport-03-3_feat-balance-HEAVY_WEAPON_SUPPORT-flag-for-large-mut.patch
blob: 3d84533649183a8f816460e3da63e57b45a8349c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
From 70662ffd3884216bea10ecf804af0f8fc05d188c Mon Sep 17 00:00:00 2001
From: Chaosvolt <chaosvolt@users.noreply.github.com>
Date: Tue, 21 Nov 2023 07:24:44 -0600
Subject: [PATCH] feat(balance): `HEAVY_WEAPON_SUPPORT` flag for large mutation
 and power armors (#3691)

* feat(balance): Active power armor supports heavy weapons

* Update crt_toolarmor.json

* style(autofix.ci): automated formatting

* Huge > Power Armor

You are huge! That means you have huge guts!

* Update ranged.cpp

* Updates per feedback

1. Renamed flag per Coolthulhu's suggestion.
2. Also removed some test messages I left in by mistake.

* style(autofix.ci): automated formatting

* Ideas/fixes per feedback

* Rename function per suggestion

Co-Authored-By: scarf <greenscarf005@gmail.com>

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: scarf <greenscarf005@gmail.com>
---
 data/json/flags.json                          |  8 ++-
 data/json/items/armor/power_armor.json        |  6 +--
 .../CRT_EXPANSION/items/crt_toolarmor.json    |  5 +-
 .../docs/en/mod/json/reference/json_flags.md  |  5 +-
 src/flag.cpp                                  |  1 +
 src/flag.h                                    |  1 +
 src/ranged.cpp                                | 52 +++++++++----------
 7 files changed, 44 insertions(+), 34 deletions(-)

diff --git a/data/json/flags.json b/data/json/flags.json
index b121cbb023f..9764c0c4049 100644
--- a/data/json/flags.json
+++ b/data/json/flags.json
@@ -1573,7 +1573,7 @@
     "id": "MOUNTED_GUN",
     "type": "json_flag",
     "context": [  ],
-    "info": "This weapon is <bad>too unwieldy</bad> to fire on its own and <info>must be mounted</info> on a vehicle or furniture (window, table, mound of dirt, etc.) before use, <info>Large or Huge</info> mutants can fire from the hip with <bad>reduced accuracy.</bad>"
+    "info": "This weapon <bad>can only be fired if mounted</bad> on a vehicle or furniture (window, table, mound of dirt, etc.) to fire, <info>Large or Huge</info> mutants or those with active <info>Power Armor</info> can fire from the hip with <bad>reduced accuracy.</bad>"
   },
   {
     "id": "MYCUS_OK",
@@ -2037,6 +2037,12 @@
     "type": "json_flag",
     "context": [  ]
   },
+  {
+    "id": "HEAVY_WEAPON_SUPPORT",
+    "type": "json_flag",
+    "context": [  ],
+    "info": "This equipment <good>allows you to fire</good> unwieldy weapons without requiring support from mountable terrain, as a <info>Large or Huge</info> mutant could, at the expense of <bad>reduced accuracy.</bad>"
+  },
   {
     "id": "FIRE_TWOHAND",
     "type": "json_flag",
diff --git a/data/json/items/armor/power_armor.json b/data/json/items/armor/power_armor.json
index 87a44cef65c..56f212aa303 100644
--- a/data/json/items/armor/power_armor.json
+++ b/data/json/items/armor/power_armor.json
@@ -91,7 +91,7 @@
     "type": "TOOL_ARMOR",
     "name": { "str": "power armor (active)", "str_pl": "suits of power armor (active)" },
     "description": "These were the second wave of military combat exoskeleton, and got a lot of media attention, with popular Navy commercials featuring them heavily.  It consists of a muscle-boosting exoskeleton frame with overlayed segmented alloy plating.  Despite advancements over the original bulky 'tank suits', the wearer still cannot easily fit through narrow spaces, or sit down comfortably (and it ruins upholstery).  There is an integrated chemical resistant bodyglove that precludes wearing other clothing.  It is currently turned on, activate it to turn it off.",
-    "extend": { "flags": [ "CLIMATE_CONTROL", "TRADER_AVOID" ] },
+    "extend": { "flags": [ "CLIMATE_CONTROL", "HEAVY_WEAPON_SUPPORT", "TRADER_AVOID" ] },
     "power_draw": 1500000,
     "revert_to": "power_armor_basic",
     "use_action": {
@@ -150,7 +150,7 @@
     "type": "TOOL_ARMOR",
     "name": { "str": "heavy power armor (active)", "str_pl": "suits of heavy power armor (active)" },
     "description": "Colloquially known as a 'tank suit' in the media, these bulky exoskeletons, covered in thick segmented armor plates, were tested in military service a few years back and determined to be too heavy and expensive for regular use.  Now that it's in your hands, though, you have a massive suit of power armor capable of resisting almost any small arms fire and most other forms of attack.  On the other hand, it doubles your effective weight, and it's almost impossible not to bump into things.  There is an integrated chemical resistant bodyglove that precludes wearing other clothing.  It is currently turned on, activate it to turn it off.",
-    "extend": { "flags": [ "CLIMATE_CONTROL", "TRADER_AVOID" ] },
+    "extend": { "flags": [ "CLIMATE_CONTROL", "HEAVY_WEAPON_SUPPORT", "TRADER_AVOID" ] },
     "power_draw": 2250000,
     "revert_to": "power_armor_heavy",
     "use_action": {
@@ -207,7 +207,7 @@
     "type": "TOOL_ARMOR",
     "name": { "str": "light power armor (active)", "str_pl": "suits of light power armor (active)" },
     "description": "The final iteration of military power armor before the fall of civilization, this type - a powered exoskeleton with high-tech segmented plating - was designed for actual widespread combat use and was seen on the front lines during the last days of the cataclysm.  Like the heavier suits, it is resistant to most modern weaponry, but it is light and maneuverable, and can fit into normal vehicles and doorways without fuss, a huge advantage over predecessors.  Unfortunately, the world ended before it could roll out in significant numbers.  There is an integrated chemical resistant bodyglove that precludes wearing other clothing.  It is currently turned on, activate it to turn it off.",
-    "extend": { "flags": [ "CLIMATE_CONTROL", "TRADER_AVOID" ] },
+    "extend": { "flags": [ "CLIMATE_CONTROL", "HEAVY_WEAPON_SUPPORT", "TRADER_AVOID" ] },
     "power_draw": 750000,
     "revert_to": "power_armor_light",
     "use_action": {
diff --git a/data/mods/CRT_EXPANSION/items/crt_toolarmor.json b/data/mods/CRT_EXPANSION/items/crt_toolarmor.json
index 708f79d1548..7ea7d2375a2 100644
--- a/data/mods/CRT_EXPANSION/items/crt_toolarmor.json
+++ b/data/mods/CRT_EXPANSION/items/crt_toolarmor.json
@@ -117,7 +117,7 @@
     "type": "TOOL_ARMOR",
     "category": "armor",
     "name": { "str": "C.R.I.T. EM vest (off)", "str_pl": "C.R.I.T. EM vests (off)" },
-    "description": "The C.R.I.T. Spec Ops Enhanced Movement vest is embedded with high-tech filaments and reactive servos which protects its wearer and assists in movement at the cost high  power usage.  It is commonly worn by C.R.I.T. Spec Ops for its ease of use and manuverability.  Turn it on for suit mode, extra protection and movement.",
+    "description": "The C.R.I.T. Spec Ops Enhanced Movement vest is embedded with high-tech filaments and reactive servos which protects its wearer and assists in movement at the cost high of power usage.  It is commonly worn by C.R.I.T. Spec Ops for its ease of use and maneuverability.  Turn it on for suit mode, extra protection and movement.",
     "weight": "10 kg",
     "volume": "6250 ml",
     "price": 7000000,
@@ -214,7 +214,8 @@
       "TRADER_AVOID",
       "USE_UPS",
       "NO_UNLOAD",
-      "OUTER"
+      "OUTER",
+      "HEAVY_WEAPON_SUPPORT"
     ]
   },
   {
diff --git a/doc/src/content/docs/en/mod/json/reference/json_flags.md b/doc/src/content/docs/en/mod/json/reference/json_flags.md
index 39531a105ac..76131e01d11 100644
--- a/doc/src/content/docs/en/mod/json/reference/json_flags.md
+++ b/doc/src/content/docs/en/mod/json/reference/json_flags.md
@@ -761,12 +761,15 @@ List of known flags, used in both `terrain.json` and `furniture.json`.
 - `DISABLE_SIGHTS` Prevents use of the base weapon sights
 - `FIRE_100` Uses 100 shots per firing.
 - `FIRE_50` Uses 50 shots per firing.
+- `HEAVY_WEAPON_SUPPORT` Wearing this will let you hip-fire heavy weapons without needing terrain
+  support, like Large or Huge mutants can.
 - `FIRE_TWOHAND` Gun can only be fired if player has two free hands.
 - `IRREMOVABLE` Makes so that the gunmod cannot be removed.
 - `MECH_BAT` This is an exotic battery designed to power military mechs.
 - `MOUNTED_GUN` Gun can only be used on terrain / furniture with the "MOUNTABLE" flag, if you're a
   normal human. If you're an oversized mutant (Inconveniently Large, Large, Freakishly Huge, Huge),
-  you can fire it regularly in exchange for dispersion and recoil penalties.
+  you can fire it regularly in exchange for dispersion and recoil penalties. Wearing something with
+  the `HEAVY_WEAPON_SUPPORT` flag also works.
 - `NEVER_JAMS` Never malfunctions.
 - `NO_UNLOAD` Cannot be unloaded.
 - `PRIMITIVE_RANGED_WEAPON` Allows using non-gunsmith tools to repair it (but not reinforce).
diff --git a/src/flag.cpp b/src/flag.cpp
index 89506e69860..ecac40cd714 100644
--- a/src/flag.cpp
+++ b/src/flag.cpp
@@ -117,6 +117,7 @@ const flag_id flag_FIREWOOD( "FIREWOOD" );
 const flag_id flag_FIRE_100( "FIRE_100" );
 const flag_id flag_FIRE_20( "FIRE_20" );
 const flag_id flag_FIRE_50( "FIRE_50" );
+const flag_id flag_HEAVY_WEAPON_SUPPORT( "HEAVY_WEAPON_SUPPORT" );
 const flag_id flag_FIRE_TWOHAND( "FIRE_TWOHAND" );
 const flag_id flag_FISH_GOOD( "FISH_GOOD" );
 const flag_id flag_FISH_POOR( "FISH_POOR" );
diff --git a/src/flag.h b/src/flag.h
index 7441a3742c9..4c244badf71 100644
--- a/src/flag.h
+++ b/src/flag.h
@@ -119,6 +119,7 @@ extern const flag_id flag_FIREWOOD;
 extern const flag_id flag_FIRE_100;
 extern const flag_id flag_FIRE_20;
 extern const flag_id flag_FIRE_50;
+extern const flag_id flag_HEAVY_WEAPON_SUPPORT;
 extern const flag_id flag_FIRE_TWOHAND;
 extern const flag_id flag_FISH_GOOD;
 extern const flag_id flag_FISH_POOR;
diff --git a/src/ranged.cpp b/src/ranged.cpp
index ecdfa6384ea..0b933e99187 100644
--- a/src/ranged.cpp
+++ b/src/ranged.cpp
@@ -140,9 +140,6 @@ static const bionic_id bio_railgun( "bio_railgun" );
 static const bionic_id bio_targeting( "bio_targeting" );
 static const bionic_id bio_ups( "bio_ups" );
 
-
-static const std::string flag_MOUNTABLE( "MOUNTABLE" );
-
 static const trait_id trait_PYROMANIA( "PYROMANIA" );
 static const trait_id trait_NORANGEDCRIT( "NO_RANGED_CRIT" );
 
@@ -151,7 +148,7 @@ static constexpr int AIF_DURATION_LIMIT = 10;
 
 static projectile make_gun_projectile( const item &gun );
 static void cycle_action( item &weap, const tripoint &pos );
-bool can_use_bipod( const map &m, const tripoint &pos );
+bool can_use_heavy_weapon( const Character &who, const map &m, const tripoint &pos );
 dispersion_sources calculate_dispersion( const map &m, const Character &who, const item &gun,
         int at_recoil, bool burst );
 
@@ -776,8 +773,12 @@ void npc::pretend_fire( npc *source, int shots, item &gun )
     }
 }
 
-bool can_use_bipod( const map &m, const tripoint &pos )
+bool can_use_heavy_weapon( const Character &who, const map &m, const tripoint &pos )
 {
+    if( who.is_mounted() && who.mounted_creature->has_flag( MF_RIDEABLE_MECH ) ) {
+        return true;
+    }
+
     // usage of any attached bipod is dependent upon terrain
     if( m.has_flag_ter_or_furn( "MOUNTABLE", pos ) ) {
         return true;
@@ -793,7 +794,7 @@ bool can_use_bipod( const map &m, const tripoint &pos )
 dispersion_sources calculate_dispersion( const map &m, const Character &who, const item &gun,
         int at_recoil, bool burst )
 {
-    bool bipod = can_use_bipod( m, who.pos() );
+    bool bipod = can_use_heavy_weapon( who, m, who.pos() );
 
     int gun_recoil = gun.gun_recoil( bipod );
     int eff_recoil = at_recoil + ( burst ? ranged::burst_penalty( who, gun, gun_recoil ) : 0 );
@@ -939,15 +940,18 @@ int ranged::fire_gun( Character &who, const tripoint &target, int max_shots, ite
         // Reset aim for bows and other reload-and-shoot weapons.
         who.recoil = MAX_RECOIL;
     } else {
+        // Hack alert: nearly every other use of can_use_heavy_weapon uses const character, except this one and gunmode_checks_weapon.
+        const Character &shooter = who;
         // Now actually apply recoil for the future shots
         // But only for one shot, because bursts kinda suck
-        int gun_recoil = gun.gun_recoil( can_use_bipod( here, who.pos() ) );
+        int gun_recoil = gun.gun_recoil( can_use_heavy_weapon( shooter, here, shooter.pos() ) );
 
-        // If user is currently able to fire a mounted gun freely, penalize recoil based on size class.
-        if( gun.has_flag( flag_MOUNTED_GUN ) && !can_use_bipod( here, who.pos() ) ) {
-            if( who.get_size() == MS_HUGE ) {
+        // If user is currently able to fire a mounted gun freely, penalize dispersion
+        // HEAVY_WEAPON_SUPPORT flag has highest penalty, Large mutants lower penalty, no penalty for Huge mutants.
+        if( gun.has_flag( flag_MOUNTED_GUN ) && !can_use_heavy_weapon( shooter, here, shooter.pos() ) ) {
+            if( who.get_size() == MS_LARGE ) {
                 gun_recoil = gun_recoil * 2;
-            } else {
+            } else if( who.worn_with_flag( flag_HEAVY_WEAPON_SUPPORT ) && ( who.get_size() <= MS_MEDIUM ) ) {
                 gun_recoil = gun_recoil * 3;
             }
         }
@@ -1943,12 +1947,13 @@ dispersion_sources ranged::get_weapon_dispersion( const Character &who, const it
         dispersion.add_multiplier( 4 );
     }
 
-    // If user is currently able to fire a mounted gun freely, penalize dispersion based on size class.
-    if( obj.has_flag( flag_MOUNTED_GUN ) && !can_use_bipod( get_map(), who.pos() ) ) {
-        if( who.get_size() == MS_HUGE ) {
-            dispersion.add_multiplier( 2 );
-        } else {
-            dispersion.add_multiplier( 3 );
+    // If user is currently able to fire a mounted gun freely, penalize dispersion
+    // HEAVY_WEAPON_SUPPORT flag has highest penalty, Large mutants lower penalty, no penalty for Huge mutants.
+    if( obj.has_flag( flag_MOUNTED_GUN ) && !can_use_heavy_weapon( who, get_map(), who.pos() ) ) {
+        if( who.get_size() == MS_LARGE ) {
+            dispersion.add_range( 500 );
+        } else if( who.worn_with_flag( flag_HEAVY_WEAPON_SUPPORT ) && ( who.get_size() <= MS_MEDIUM ) ) {
+            dispersion.add_range( 1000 );
         }
     }
 
@@ -3772,16 +3777,9 @@ bool ranged::gunmode_checks_weapon( avatar &you, const map &m, std::vector<std::
     }
 
     if( gmode->has_flag( flag_MOUNTED_GUN ) ) {
-
-        bool mech_mount = false;
-        if( you.is_mounted() && you.mounted_creature->has_flag( MF_RIDEABLE_MECH ) ) {
-            mech_mount = true;
-        }
-
-        const bool v_mountable = static_cast<bool>( m.veh_at( you.pos() ).part_with_feature( "MOUNTABLE",
-                                 true ) );
-        bool t_mountable = m.has_flag_ter_or_furn( flag_MOUNTABLE, you.pos() );
-        if( !mech_mount && !t_mountable && !v_mountable && !( you.get_size() > MS_MEDIUM ) ) {
+        const Character &shooter = you;
+        if( !can_use_heavy_weapon( shooter, m, shooter.pos() ) && !( you.get_size() > MS_MEDIUM ) &&
+            !you.worn_with_flag( flag_HEAVY_WEAPON_SUPPORT ) ) {
             messages.push_back( string_format(
                                     _( "You must stand near acceptable terrain or furniture to fire the %s.  A table, a mound of dirt, a broken window, etc." ),
                                     gmode->tname() ) );
-- 
2.42.0