From f9b9163c688d7b38f352ad5c41e155be396294f3 Mon Sep 17 00:00:00 2001 From: RenechCDDA <84619419+RenechCDDA@users.noreply.github.com> Date: Mon, 29 Apr 2024 18:52:30 -0400 Subject: [PATCH] Reasonable incendiary ammo & dragon's breath (#73069) * Incendiary only a chance to give target onfire effect Flesh burns less well than wood/paper/veggy/etc * Multi-projectile shots don't apply ammo effects multiple times * Replace dragon's breath huge fire chance with a reasonable one Add new effect that looks like previous fire effect * Migrate most INCENDIARY effects to IGNITE * Add multi_projectile_effects to gauss shotgun --- data/json/ammo_effects.json | 18 +++++- data/json/field_type.json | 15 +++++ data/json/items/ammo/shot.json | 2 +- data/json/items/fuel.json | 10 ++-- data/json/items/gun/ups.json | 6 +- data/mods/Aftershock/ammo_effects.json | 5 ++ .../mods/Aftershock/items/ammo/flashbulb.json | 2 +- data/mods/Aftershock/items/ammo/plasma.json | 2 +- data/mods/Aftershock/items/gun/laser.json | 4 +- .../Aftershock/items/gunmods/shotguns.json | 2 +- data/mods/CrazyCataclysm/crazy_items.json | 2 +- data/mods/Generic_Guns/ammo/shot.json | 2 +- data/mods/Magiclysm/items/fuel.json | 2 +- .../items/teleporter_start_items.json | 2 +- data/mods/MindOverMatter/items/weapons.json | 2 +- data/mods/Xedra_Evolved/items/ammo.json | 2 +- .../Xedra_Evolved/items/inventor/gun.json | 6 +- doc/JSON_INFO.md | 1 + src/ballistics.cpp | 1 + src/creature.cpp | 56 ++++++++++--------- src/item.cpp | 4 +- src/item_factory.cpp | 1 + src/itype.h | 4 ++ src/map.cpp | 15 +++-- src/projectile.cpp | 1 + src/projectile.h | 2 + src/ranged.cpp | 7 +++ 27 files changed, 119 insertions(+), 57 deletions(-) diff --git a/data/json/ammo_effects.json b/data/json/ammo_effects.json index 150e76345fb51..079515e28b464 100644 --- a/data/json/ammo_effects.json +++ b/data/json/ammo_effects.json @@ -86,12 +86,14 @@ { "id": "INCENDIARY", "type": "ammo_effect", - "//": "Creature, that got hit with this projectile, would be ignited for a short duration, up to 4 seconds, (6 if creature is made out of flammable material or made out of veggy). Hardcoded" + "//": "Creature, that got hit with this projectile, would be ignited for a short duration, up to 4 seconds, (6 if creature is made out of flammable material or made out of veggy). Hardcoded in projectile::apply_effects_damage", + "//2": "10% chance to start fires on flammable (has flag FLAMMABLE_ASH) furniture/terrain **with defined shoot data**, hardcoded in map::shoot" }, { "id": "IGNITE", "type": "ammo_effect", - "//": "Same as INCENDIARY, creature that got hit with this projectile, would be ignited for a short duration, up to 6 seconds, (10 if creature is made out of flammable material or made out of veggy). Hardcoded" + "//": "Same as INCENDIARY, creature that got hit with this projectile, would be ignited for a short duration, up to 6 seconds, (10 if creature is made out of flammable material or made out of veggy). Hardcoded", + "//2": "Guaranteed to start fires on flammable (has flag FLAMMABLE_ASH) furniture/terrain **with defined shoot data**, hardcoded in map::shoot" }, { "id": "JET", @@ -389,6 +391,12 @@ "//": "Creates a trail of smoke", "trail": { "field_type": "fd_smoke", "intensity_min": 1, "intensity_max": 2, "chance": 75 } }, + { + "id": "STREAM_TINY", + "type": "ammo_effect", + "//": "Sometimes leaves a trail of small fire fields. All of these STREAM_XXXXXX effects have hardcoded interactions in projectile_attack (ballistics.cpp)", + "trail": { "field_type": "fd_fire", "intensity_min": 1, "intensity_max": 1, "chance": 10 } + }, { "id": "STREAM", "type": "ammo_effect", @@ -401,6 +409,12 @@ "//": "Leaves a trail of intense fire fields", "trail": { "field_type": "fd_fire", "intensity_min": 2, "intensity_max": 2, "chance": 75 } }, + { + "id": "PYROTECHNIC_DISPLAY", + "type": "ammo_effect", + "//": "Looks like huge fires, but doesn't actually burn stuff.", + "trail": { "field_type": "fd_fire_FAKE", "intensity_min": 1, "intensity_max": 3, "chance": 85 } + }, { "id": "STREAM_GAS_FUNGICIDAL", "type": "ammo_effect", diff --git a/data/json/field_type.json b/data/json/field_type.json index a2b02ec3df920..f134e17775c04 100644 --- a/data/json/field_type.json +++ b/data/json/field_type.json @@ -333,6 +333,21 @@ "display_items": false, "display_field": true }, + { + "id": "fd_fire_FAKE", + "looks_like": "fd_fire", + "type": "field_type", + "intensity_levels": [ + { "name": "glittering embers", "sym": "4", "color": "yellow", "light_emitted": 5, "translucency": 0.7 }, + { "name": "spark shower", "color": "light_red", "light_emitted": 15, "translucency": 0.4 }, + { "name": "wall of flames", "color": "red", "light_emitted": 40, "translucency": 0.1 } + ], + "priority": 4, + "half_life": "1 seconds", + "phase": "plasma", + "display_items": false, + "display_field": true + }, { "id": "fd_extinguisher", "type": "field_type", diff --git a/data/json/items/ammo/shot.json b/data/json/items/ammo/shot.json index e521607984246..bfd2248186183 100644 --- a/data/json/items/ammo/shot.json +++ b/data/json/items/ammo/shot.json @@ -178,7 +178,7 @@ "price": "10 USD", "price_postapoc": "16 USD", "proportional": { "damage": { "damage_type": "bullet", "amount": 0.2 }, "recoil": 0.6, "loudness": 0.8, "range": 0.5 }, - "extend": { "effects": [ "INCENDIARY", "STREAM", "NOGIB" ] } + "extend": { "effects": [ "INCENDIARY", "STREAM_TINY", "PYROTECHNIC_DISPLAY", "NOGIB" ] } }, { "id": "shot_flechette", diff --git a/data/json/items/fuel.json b/data/json/items/fuel.json index 43c6a2c62cfcc..2b752fc2772d2 100644 --- a/data/json/items/fuel.json +++ b/data/json/items/fuel.json @@ -76,7 +76,7 @@ "ammo_type": "diesel", "damage": { "damage_type": "heat", "amount": 5, "armor_penetration": 4 }, "range": 4, - "effects": [ "FLAME", "STREAM", "INCENDIARY", "NEVER_MISFIRES" ] + "effects": [ "FLAME", "STREAM", "IGNITE", "NEVER_MISFIRES" ] }, { "id": "jp8", @@ -99,7 +99,7 @@ "ammo_type": "jp8", "damage": { "damage_type": "heat", "amount": 5, "armor_penetration": 5 }, "range": 4, - "effects": [ "FLAME", "STREAM", "INCENDIARY", "NEVER_MISFIRES" ] + "effects": [ "FLAME", "STREAM", "IGNITE", "NEVER_MISFIRES" ] }, { "id": "avgas", @@ -122,7 +122,7 @@ "ammo_type": "avgas", "damage": { "damage_type": "heat", "amount": 5, "armor_penetration": 5 }, "range": 4, - "effects": [ "FLAME", "STREAM", "INCENDIARY", "NEVER_MISFIRES" ] + "effects": [ "FLAME", "STREAM", "IGNITE", "NEVER_MISFIRES" ] }, { "id": "biodiesel", @@ -155,7 +155,7 @@ "ammo_type": "gasoline", "damage": { "damage_type": "heat", "amount": 5, "armor_penetration": 5 }, "range": 4, - "effects": [ "FLAME", "STREAM", "INCENDIARY", "NEVER_MISFIRES" ] + "effects": [ "FLAME", "STREAM", "IGNITE", "NEVER_MISFIRES" ] }, { "id": "lamp_oil", @@ -223,7 +223,7 @@ "ammo_type": "flammable", "damage": { "damage_type": "heat", "amount": 15, "armor_penetration": 30 }, "range": 6, - "effects": [ "FLAME", "STREAM_BIG", "INCENDIARY", "NEVER_MISFIRES" ] + "effects": [ "FLAME", "STREAM_BIG", "IGNITE", "NEVER_MISFIRES" ] }, { "id": "gelled_gasoline", diff --git a/data/json/items/gun/ups.json b/data/json/items/gun/ups.json index c568aadff9cf9..9ce1d00eff25e 100644 --- a/data/json/items/gun/ups.json +++ b/data/json/items/gun/ups.json @@ -66,7 +66,7 @@ "energy_drain": "20 kJ", "reload": 0, "modes": [ [ "DEFAULT", "3 rd.", 3 ], [ "BURST", "5 rd.", 5 ], [ "AUTO", "high auto", 15 ] ], - "ammo_effects": [ "LASER", "PLASMA_BUBBLE", "INCENDIARY" ], + "ammo_effects": [ "LASER", "PLASMA_BUBBLE", "IGNITE" ], "flags": [ "NO_UNLOAD", "NEVER_JAMS", "NO_UNWIELD", "NO_SALVAGE", "NO_REPAIR", "UNBREAKABLE_MELEE", "NON_FOULING", "USE_UPS" ], "overheat_threshold": 200, "cooling_value": 2, @@ -97,7 +97,7 @@ "loudness": 1, "energy_drain": "50 kJ", "reload": 0, - "ammo_effects": [ "LASER", "PLASMA_BUBBLE", "INCENDIARY" ], + "ammo_effects": [ "LASER", "PLASMA_BUBBLE", "IGNITE" ], "flags": [ "NO_UNLOAD", "NEVER_JAMS", @@ -154,7 +154,7 @@ [ "stock accessory", 1 ], [ "underbarrel", 1 ] ], - "ammo_effects": [ "LASER", "INCENDIARY" ], + "ammo_effects": [ "LASER", "IGNITE" ], "flags": [ "NEVER_JAMS", "NO_UNLOAD", "NON_FOULING", "NEEDS_NO_LUBE", "USE_UPS", "OVERHEATS" ], "faults": [ "fault_overheat_melting", "fault_overheat_safety" ], "melee_damage": { "bash": 12 } diff --git a/data/mods/Aftershock/ammo_effects.json b/data/mods/Aftershock/ammo_effects.json index f5c70831f0fdf..bf78685440550 100644 --- a/data/mods/Aftershock/ammo_effects.json +++ b/data/mods/Aftershock/ammo_effects.json @@ -40,5 +40,10 @@ "id": "SEISMIC_MAPPING", "type": "ammo_effect", "aoe": { "field_type": "fd_clairvoyant", "intensity_min": 10, "intensity_max": 10 } + }, + { + "id": "MULTI_EFFECTS", + "type": "ammo_effect", + "//": "Applies multi_projectile_effects to all ammo used by this weapon, even if the ammo doesn't normally have it. Hardcoded in projectile_attack (ranged.cpp)" } ] diff --git a/data/mods/Aftershock/items/ammo/flashbulb.json b/data/mods/Aftershock/items/ammo/flashbulb.json index 13323c2f1628d..ed58f93adbeb5 100644 --- a/data/mods/Aftershock/items/ammo/flashbulb.json +++ b/data/mods/Aftershock/items/ammo/flashbulb.json @@ -19,6 +19,6 @@ "recoil": 45, "count": 4, "stack_size": 1, - "effects": [ "COOKOFF", "NEVER_MISFIRES", "LASER", "INCENDIARY", "DAZZLE_BEAM", "PUMP_LASER", "PLASMA_BUBBLE" ] + "effects": [ "COOKOFF", "NEVER_MISFIRES", "LASER", "IGNITE", "DAZZLE_BEAM", "PUMP_LASER", "PLASMA_BUBBLE" ] } ] diff --git a/data/mods/Aftershock/items/ammo/plasma.json b/data/mods/Aftershock/items/ammo/plasma.json index ecf357cd88e96..488b733f592fb 100644 --- a/data/mods/Aftershock/items/ammo/plasma.json +++ b/data/mods/Aftershock/items/ammo/plasma.json @@ -15,6 +15,6 @@ "ammo_type": "afs_shydrogen", "range": 0, "count": 1, - "effects": [ "INCENDIARY" ] + "effects": [ "IGNITE" ] } ] diff --git a/data/mods/Aftershock/items/gun/laser.json b/data/mods/Aftershock/items/gun/laser.json index 5151eb4eb5f35..1aec31fea0a48 100644 --- a/data/mods/Aftershock/items/gun/laser.json +++ b/data/mods/Aftershock/items/gun/laser.json @@ -72,7 +72,7 @@ [ "stock mount", 1 ], [ "underbarrel mount", 1 ] ], - "ammo_effects": [ "LASER", "INCENDIARY" ], + "ammo_effects": [ "LASER", "IGNITE" ], "flags": [ "NO_UNLOAD", "NON_FOULING", "NEEDS_NO_LUBE", "USE_UPS" ], "melee_damage": { "bash": 4 } }, @@ -168,7 +168,7 @@ "overheat_threshold": 150, "modes": [ [ "DEFAULT", "pulse", 1 ], [ "BURST", "2s sequence", 2 ] ], "ammo_to_fire": 0, - "ammo_effects": [ "INCENDIARY", "DAZZLE_BEAM", "PLASMA_BUBBLE" ], + "ammo_effects": [ "IGNITE", "DAZZLE_BEAM", "PLASMA_BUBBLE" ], "delete": { "flags": [ "NO_UNLOAD", "NO_RELOAD" ] }, "energy_drain": "30 kJ", "built_in_mods": [ "afs_holo_aim_assist" ], diff --git a/data/mods/Aftershock/items/gunmods/shotguns.json b/data/mods/Aftershock/items/gunmods/shotguns.json index d27ac0698afd7..7ab05f670674e 100644 --- a/data/mods/Aftershock/items/gunmods/shotguns.json +++ b/data/mods/Aftershock/items/gunmods/shotguns.json @@ -40,7 +40,7 @@ "mod_targets": [ "shotgun" ], "damage_modifier": { "damage_type": "electric", "amount": 3, "armor_penetration": 7 }, "energy_drain_modifier": "20 kJ", - "ammo_effects": [ "SMALL_ELECTRIC_BURST" ], + "ammo_effects": [ "SMALL_ELECTRIC_BURST", "MULTI_EFFECTS" ], "dispersion_modifier": 15, "range_modifier": 5, "handling_modifier": -2, diff --git a/data/mods/CrazyCataclysm/crazy_items.json b/data/mods/CrazyCataclysm/crazy_items.json index 1e29b99d78d15..817d45487517c 100644 --- a/data/mods/CrazyCataclysm/crazy_items.json +++ b/data/mods/CrazyCataclysm/crazy_items.json @@ -81,7 +81,7 @@ "durability": 10, "loudness": 50, "reload": 0, - "ammo_effects": [ "PLASMA", "EXPLOSIVE_HUGE", "STREAM_BIG", "INCENDIARY", "WIDE" ], + "ammo_effects": [ "PLASMA", "EXPLOSIVE_HUGE", "STREAM_BIG", "IGNITE", "WIDE" ], "flags": [ "NEVER_JAMS", "NO_UNLOAD", "TRADER_AVOID", "BIONIC_WEAPON", "USES_BIONIC_POWER" ], "melee_damage": { "bash": 12 } }, diff --git a/data/mods/Generic_Guns/ammo/shot.json b/data/mods/Generic_Guns/ammo/shot.json index 4533d753c4cb9..18b93a57cb95c 100644 --- a/data/mods/Generic_Guns/ammo/shot.json +++ b/data/mods/Generic_Guns/ammo/shot.json @@ -58,7 +58,7 @@ "dispersion": 1.2, "range": 0.5 }, - "extend": { "effects": [ "INCENDIARY", "STREAM", "NOGIB" ] } + "extend": { "effects": [ "INCENDIARY", "PYROTECHNIC_DISPLAY", "STREAM_TINY", "NOGIB" ] } }, { "id": "shot_explosive", diff --git a/data/mods/Magiclysm/items/fuel.json b/data/mods/Magiclysm/items/fuel.json index 91745d907254e..28a042c066ecf 100644 --- a/data/mods/Magiclysm/items/fuel.json +++ b/data/mods/Magiclysm/items/fuel.json @@ -16,7 +16,7 @@ "ammo_type": "dragon_blood", "damage": { "damage_type": "stab", "amount": 5, "armor_penetration": 5 }, "range": 4, - "effects": [ "FLAME", "STREAM", "INCENDIARY", "NEVER_MISFIRES" ] + "effects": [ "FLAME", "STREAM", "IGNITE", "NEVER_MISFIRES" ] }, { "id": "blood_tainted", diff --git a/data/mods/MindOverMatter/items/teleporter_start_items.json b/data/mods/MindOverMatter/items/teleporter_start_items.json index 20c47e69e07ca..f166f31ca8916 100644 --- a/data/mods/MindOverMatter/items/teleporter_start_items.json +++ b/data/mods/MindOverMatter/items/teleporter_start_items.json @@ -20,7 +20,7 @@ "loudness": 20, "reload": 200, "range": 45, - "ammo_effects": [ "PLASMA", "PLASMA_BUBBLE", "INCENDIARY" ], + "ammo_effects": [ "PLASMA", "PLASMA_BUBBLE", "IGNITE" ], "ammo": [ "mom_fusion_ammo" ], "pocket_data": [ { "pocket_type": "MAGAZINE_WELL", "magazine_well": "25 ml", "item_restriction": [ "mom_fusion_mag" ] } ], "flags": [ "NEVER_JAMS", "NON_FOULING", "NEEDS_NO_LUBE" ] diff --git a/data/mods/MindOverMatter/items/weapons.json b/data/mods/MindOverMatter/items/weapons.json index fdbabf3d76f66..d5f7a01018a47 100644 --- a/data/mods/MindOverMatter/items/weapons.json +++ b/data/mods/MindOverMatter/items/weapons.json @@ -91,7 +91,7 @@ [ "underbarrel", 1 ] ], "ammo": [ "mom_pulse_rifle_ammo" ], - "ammo_effects": [ "LASER", "INCENDIARY" ], + "ammo_effects": [ "LASER", "IGNITE" ], "flags": [ "NEVER_JAMS", "NO_UNLOAD", "NON_FOULING", "NEEDS_NO_LUBE", "NO_REPAIR", "OVERHEATS" ], "faults": [ "fault_overheat_explosion", "fault_overheat_melting" ], "pocket_data": [ { "pocket_type": "MAGAZINE", "ammo_restriction": { "mom_pulse_rifle_ammo": 1 } } ], diff --git a/data/mods/Xedra_Evolved/items/ammo.json b/data/mods/Xedra_Evolved/items/ammo.json index 7765c24eb96d5..fea98aa4f7598 100644 --- a/data/mods/Xedra_Evolved/items/ammo.json +++ b/data/mods/Xedra_Evolved/items/ammo.json @@ -98,7 +98,7 @@ "range": 12, "count": 1, "recoil": 900, - "effects": [ "INCENDIARY" ], + "effects": [ "IGNITE" ], "flags": [ "ZERO_WEIGHT" ] }, { diff --git a/data/mods/Xedra_Evolved/items/inventor/gun.json b/data/mods/Xedra_Evolved/items/inventor/gun.json index 7c8753ab86fdd..8e7079b418d76 100644 --- a/data/mods/Xedra_Evolved/items/inventor/gun.json +++ b/data/mods/Xedra_Evolved/items/inventor/gun.json @@ -99,7 +99,7 @@ [ "stock accessory", 1 ], [ "underbarrel", 1 ] ], - "ammo_effects": [ "LASER", "INCENDIARY" ], + "ammo_effects": [ "LASER", "IGNITE" ], "faults": [ "fault_overheat_explosion", "fault_overheat_venting", "fault_overheat_melting", "fault_overheat_safety" ], "flags": [ "NEVER_JAMS", @@ -162,7 +162,7 @@ [ "stock accessory", 1 ], [ "underbarrel", 1 ] ], - "ammo_effects": [ "LASER", "INCENDIARY" ], + "ammo_effects": [ "LASER", "IGNITE" ], "faults": [ "fault_overheat_explosion", "fault_overheat_venting", "fault_overheat_melting", "fault_overheat_safety" ], "flags": [ "NEVER_JAMS", @@ -222,7 +222,7 @@ [ "stock accessory", 1 ], [ "underbarrel", 1 ] ], - "ammo_effects": [ "LASER", "PLASMA_BUBBLE", "INCENDIARY" ], + "ammo_effects": [ "LASER", "PLASMA_BUBBLE", "IGNITE" ], "faults": [ "fault_overheat_explosion", "fault_overheat_venting", "fault_overheat_melting", "fault_overheat_safety" ], "flags": [ "NEVER_JAMS", diff --git a/doc/JSON_INFO.md b/doc/JSON_INFO.md index fe945e4a7f85b..b73373d020a68 100644 --- a/doc/JSON_INFO.md +++ b/doc/JSON_INFO.md @@ -3494,6 +3494,7 @@ See [GAME_BALANCE.md](GAME_BALANCE.md)'s `MELEE_WEAPONS` section for the criteri "dispersion" : 0, // Inaccuracy of ammo, measured in 100ths of Minutes Of Angle (MOA) "shot_counter": 5, // Increases amount of shots produced by gun by this amount. `"shot_counter": 5` means each shot will be counted as 6 shots (1 you actually perform + 5); designed for using in suppressor mod breakage and for stuff like replaceable barrels, but not used anywhere at this moment "projectile_count": 5,// amount of pellets, that the ammo will shot, like in shotgun-like weapon; if used, shot_damage should be specified +"multi_projectile_effects": true,// (Optional) Boolean, default false. If the projectile_count is greater than 1, determines if the extra projectiles will also trigger any ammo effects. (For more on ammo effects see below) "shot_damage": { "damage_type": "bullet", "amount": 15 } // Optional field specifying the damage caused by a single projectile fired from this round. If present projectile_count must also be specified; syntax is equal to damage "critical_multiplier": 4, // All ranged damage dealt would be multiplied by this, if it was a critical hit "shot_spread": 100, // Optional field specifying the additional dispersion of single projectiles. Only meaningful if shot_count is present. diff --git a/src/ballistics.cpp b/src/ballistics.cpp index 72bfd44d0a5d1..063b5c5c82c5c 100644 --- a/src/ballistics.cpp +++ b/src/ballistics.cpp @@ -240,6 +240,7 @@ dealt_projectile_attack projectile_attack( const projectile &proj_arg, const tri const auto &proj_effects = proj.proj_effects; const bool stream = proj_effects.count( "STREAM" ) > 0 || + proj_effects.count( "STREAM_TINY" ) > 0 || proj_effects.count( "STREAM_BIG" ) > 0 || proj_effects.count( "JET" ) > 0; const char bullet = stream ? '#' : '*'; diff --git a/src/creature.cpp b/src/creature.cpp index c7e2ace516fb7..bce766d515c6e 100644 --- a/src/creature.cpp +++ b/src/creature.cpp @@ -879,34 +879,38 @@ void projectile::apply_effects_damage( Creature &target, Creature *source, Character &player_character = get_player_character(); if( proj_effects.count( "INCENDIARY" ) ) { - if( target.made_of( material_veggy ) || target.made_of_any( Creature::cmat_flammable ) ) { - target.add_effect( effect_source( source ), effect_onfire, rng( 2_turns, 6_turns ), - dealt_dam.bp_hit ); - } else if( target.made_of_any( Creature::cmat_flesh ) && one_in( 4 ) ) { - target.add_effect( effect_source( source ), effect_onfire, rng( 1_turns, 4_turns ), - dealt_dam.bp_hit ); - } - if( player_character.has_trait( trait_PYROMANIA ) && - !player_character.has_morale( MORALE_PYROMANIA_STARTFIRE ) && - player_character.sees( target ) ) { - player_character.add_msg_if_player( m_good, - _( "You feel a surge of euphoria as flame engulfs %s!" ), target.get_name() ); - player_character.add_morale( MORALE_PYROMANIA_STARTFIRE, 15, 15, 8_hours, 6_hours ); - player_character.rem_morale( MORALE_PYROMANIA_NOFIRE ); + if( x_in_y( 1, 100 ) ) { // 1% chance + if( target.made_of( material_veggy ) || target.made_of_any( Creature::cmat_flammable ) ) { + target.add_effect( effect_source( source ), effect_onfire, rng( 2_turns, 6_turns ), + dealt_dam.bp_hit ); + } else if( target.made_of_any( Creature::cmat_flesh ) && one_in( 4 ) ) { + target.add_effect( effect_source( source ), effect_onfire, rng( 1_turns, 4_turns ), + dealt_dam.bp_hit ); + } + if( player_character.has_trait( trait_PYROMANIA ) && + !player_character.has_morale( MORALE_PYROMANIA_STARTFIRE ) && + player_character.sees( target ) ) { + player_character.add_msg_if_player( m_good, + _( "You feel a surge of euphoria as flame engulfs %s!" ), target.get_name() ); + player_character.add_morale( MORALE_PYROMANIA_STARTFIRE, 15, 15, 8_hours, 6_hours ); + player_character.rem_morale( MORALE_PYROMANIA_NOFIRE ); + } } } else if( proj_effects.count( "IGNITE" ) ) { - if( target.made_of( material_veggy ) || target.made_of_any( Creature::cmat_flammable ) ) { - target.add_effect( effect_source( source ), effect_onfire, 6_turns, dealt_dam.bp_hit ); - } else if( target.made_of_any( Creature::cmat_flesh ) ) { - target.add_effect( effect_source( source ), effect_onfire, 10_turns, dealt_dam.bp_hit ); - } - if( player_character.has_trait( trait_PYROMANIA ) && - !player_character.has_morale( MORALE_PYROMANIA_STARTFIRE ) && - player_character.sees( target ) ) { - player_character.add_msg_if_player( m_good, - _( "You feel a surge of euphoria as flame engulfs %s!" ), target.get_name() ); - player_character.add_morale( MORALE_PYROMANIA_STARTFIRE, 15, 15, 8_hours, 6_hours ); - player_character.rem_morale( MORALE_PYROMANIA_NOFIRE ); + if( x_in_y( 1, 2 ) ) { // 50% chance + if( target.made_of( material_veggy ) || target.made_of_any( Creature::cmat_flammable ) ) { + target.add_effect( effect_source( source ), effect_onfire, 10_turns, dealt_dam.bp_hit ); + } else if( target.made_of_any( Creature::cmat_flesh ) ) { + target.add_effect( effect_source( source ), effect_onfire, 6_turns, dealt_dam.bp_hit ); + } + if( player_character.has_trait( trait_PYROMANIA ) && + !player_character.has_morale( MORALE_PYROMANIA_STARTFIRE ) && + player_character.sees( target ) ) { + player_character.add_msg_if_player( m_good, + _( "You feel a surge of euphoria as flame engulfs %s!" ), target.get_name() ); + player_character.add_morale( MORALE_PYROMANIA_STARTFIRE, 15, 15, 8_hours, 6_hours ); + player_character.rem_morale( MORALE_PYROMANIA_NOFIRE ); + } } } diff --git a/src/item.cpp b/src/item.cpp index a0c3b853e6c14..2b217c4492bef 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -3087,9 +3087,9 @@ void item::ammo_info( std::vector &info, const iteminfo_query *parts, } } } - if( ammo.ammo_effects.count( "INCENDIARY" ) && + if( ( ammo.ammo_effects.count( "INCENDIARY" ) || ammo.ammo_effects.count( "IGNITE" ) ) && parts->test( iteminfo_parts::AMMO_FX_INCENDIARY ) ) { - fx.emplace_back( _( "This ammo starts fires." ) ); + fx.emplace_back( _( "This ammo may start fires." ) ); } if( !fx.empty() ) { insert_separation_line( info ); diff --git a/src/item_factory.cpp b/src/item_factory.cpp index 7a8d64dbd8597..b94d34d5c2abb 100644 --- a/src/item_factory.cpp +++ b/src/item_factory.cpp @@ -2679,6 +2679,7 @@ void islot_ammo::load( const JsonObject &jo ) assign( jo, "drop_chance", drop_chance, strict, 0.0f, 1.0f ); optional( jo, was_loaded, "drop_active", drop_active, true ); optional( jo, was_loaded, "projectile_count", count, 1 ); + optional( jo, was_loaded, "multi_projectile_effects", multi_projectile_effects, false ); optional( jo, was_loaded, "shot_spread", shot_spread, 0 ); assign( jo, "shot_damage", shot_damage, strict ); // Damage instance assign reader handles pierce and prop_damage diff --git a/src/itype.h b/src/itype.h index 30fa621a27c0e..bb006a1e1b3aa 100644 --- a/src/itype.h +++ b/src/itype.h @@ -992,6 +992,10 @@ struct islot_ammo : common_ranged_data { * Number of projectiles fired per round, e.g. shotgun shot. */ int count = 1; + /** + * Whether this multi-projectile shot has its effects applied to all projectiles + */ + bool multi_projectile_effects = false; /** * Spread/dispersion between projectiles fired from the same round. */ diff --git a/src/map.cpp b/src/map.cpp index 4803ed2411103..e07d964e9ba98 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -4493,12 +4493,14 @@ void map::shoot( const tripoint &p, projectile &proj, const bool hit_items ) const auto &ammo_effects = proj.proj_effects; const bool incendiary = ammo_effects.count( "INCENDIARY" ); + const bool ignite = ammo_effects.count( "IGNITE" ); const bool laser = ammo_effects.count( "LASER" ); if( const optional_vpart_position vp = veh_at( p ) ) { dam = vp->vehicle().damage( *this, vp->part_index(), dam, main_damage_type, hit_items ); } + // This lambda is only called if the furniture/terrain has shoot data! const auto shoot_furn_ter = [&]( const map_data_common_t &data ) { const map_shoot_info &shoot = *data.shoot; bool destroyed = false; @@ -4526,8 +4528,13 @@ void map::shoot( const tripoint &p, projectile &proj, const bool hit_items ) add_msg( _( "The shot is stopped by the %s!" ), data.name() ); } // only very flammable furn/ter can be set alight with incendiary rounds - if( incendiary && data.has_flag( ter_furn_flag::TFLAG_FLAMMABLE_ASH ) ) { - add_field( p, fd_fire, 1 ); + if( data.has_flag( ter_furn_flag::TFLAG_FLAMMABLE_ASH ) ) { + if( incendiary && x_in_y( 1, 10 ) ) { // 10% chance + add_field( p, fd_fire, 1 ); + } + if( ignite ) { + add_field( p, fd_fire, 1 ); + } } // bash_ter_furn already triggers the alarm // TODO: fix alarm event weirdness (not just here, also in bash, hack, etc) @@ -4545,9 +4552,9 @@ void map::shoot( const tripoint &p, projectile &proj, const bool hit_items ) bool hit_something = false; // shoot through furniture or terrain and see if we hit something - if( furniture->shoot ) { + if( furniture->shoot ) { // Shoot data is optional, most furniture will never trigger this hit_something |= shoot_furn_ter( furniture.obj() ); - } else if( terrain->shoot ) { + } else if( terrain->shoot ) { // Shoot data is optional, most terrain will never trigger this hit_something |= shoot_furn_ter( terrain.obj() ); // fall back to just bashing when shoot data is not defined } else if( impassable( p ) && !is_transparent( p ) ) { diff --git a/src/projectile.cpp b/src/projectile.cpp index 28c715d14576b..127242d25a2bd 100644 --- a/src/projectile.cpp +++ b/src/projectile.cpp @@ -48,6 +48,7 @@ projectile &projectile::operator=( const projectile &other ) speed = other.speed; range = other.range; count = other.count; + multi_projectile_effects = other.multi_projectile_effects; shot_spread = other.shot_spread; shot_impact = other.shot_impact; proj_effects = other.proj_effects; diff --git a/src/projectile.h b/src/projectile.h index dc8e617252958..fd03d07ea80d3 100644 --- a/src/projectile.h +++ b/src/projectile.h @@ -22,6 +22,8 @@ struct projectile { int range = 0; // Number of projectiles fired at a time, one except in cases like shotgun rounds. int count = 1; + // Whether ammo effects apply to all projectiles + bool multi_projectile_effects = false; // The potential dispersion between different projectiles fired from one round. int shot_spread = 0; // Damage dealt by a single shot. diff --git a/src/ranged.cpp b/src/ranged.cpp index 0a339a14cb413..f07a5999078fc 100644 --- a/src/ranged.cpp +++ b/src/ranged.cpp @@ -969,6 +969,9 @@ int Character::fire_gun( const tripoint &target, int shots, item &gun, item_loca bool multishot = proj.count > 1; std::map< Creature *, std::pair < int, int >> targets_hit; for( int projectile_number = 0; projectile_number < proj.count; ++projectile_number ) { + if( !first && !proj.multi_projectile_effects ) { + proj.proj_effects.erase( proj.proj_effects.begin(), proj.proj_effects.end() ); + } dealt_projectile_attack shot = projectile_attack( proj, pos(), aim, dispersion, this, in_veh, wp_attack, first ); first = false; @@ -2097,6 +2100,10 @@ static projectile make_gun_projectile( const item &gun ) const auto &ammo = gun.ammo_data()->ammo; proj.critical_multiplier = ammo->critical_multiplier; proj.count = ammo->count; + proj.multi_projectile_effects = ammo->multi_projectile_effects; + if( fx.count( "MULTI_EFFECTS" ) ) { + proj.multi_projectile_effects = true; + } proj.shot_spread = ammo->shot_spread * gun.gun_shot_spread_multiplier(); if( !ammo->drop.is_null() && x_in_y( ammo->drop_chance, 1.0 ) ) { item drop( ammo->drop );