Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expand implementation of liquid ammo #72271

Draft
wants to merge 6 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions data/json/ammo_effects.json
Original file line number Diff line number Diff line change
Expand Up @@ -427,5 +427,10 @@
"type": "ammo_effect",
"//": "runs EoC that cause you to mutate",
"eoc": [ "EOC_random_mutate" ]
},
{
"id": "LIQUID",
"type": "ammo_effect",
"//": "This is basically a flag for liquid ammo, it is set automatically when the material of the ammo is liquid"
}
]
62 changes: 62 additions & 0 deletions data/json/monster_special_attacks/monster_ammo.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
[
{
"type": "ammunition_type",
"id": "bile",
"name": "boomer bile",
"default": "boomer_bile"
},
{
"id": "boomer_bile",
"type": "AMMO",
"name": { "str_sp": "boomer bile" },
"description": "Boomer bile, if you see this it's a bug",
"weight": "3 g",
"volume": "250 ml",
"price": 600,
"price_postapoc": 500,
"material": [ "water" ],
"symbol": "=",
"color": "pink",
"container": "bottle_plastic",
"sealed": false,
"phase": "liquid",
"ammo_type": "bile",
"range": 4,
"count": 100,
"effects": [ "NEVER_MISFIRES", "JET", "BILE_GLOW" ]
},
{
"id": "boomer_stomach",
"looks_like": "pressurized_tank",
"type": "MAGAZINE",
"name": { "str": "boomer stomach" },
"description": "Boomer stomach, if you see this it's a bug.",
"weight": "800 g",
"volume": "2 L",
"price": 5000,
"price_postapoc": 50,
"material": [ "flesh" ],
"symbol": "O",
"color": "pink",
"ammo_type": [ "bile" ],
"reload_time": 3,
"pocket_data": [ { "pocket_type": "MAGAZINE", "rigid": true, "ammo_restriction": { "bile": 800 }, "watertight": true } ]
},
{
"id": "BILE_BOMB",
"type": "ammo_effect",
"//": "Leaves a pool of bile on detonation",
"aoe": { "field_type": "fd_bile", "intensity_min": 3, "intensity_max": 3 }
},
{
"id": "BILE_JET",
"type": "ammo_effect",
"//": "Creates a trail of bile",
"trail": { "field_type": "fd_bile", "intensity_min": 1, "intensity_max": 2, "chance": 75 }
},
{
"id": "BILE_GLOW",
"type": "ammo_effect",
"on_hit_effects": [ { "effect": "glowing", "duration": "5 m", "intensity": 1 } ]
}
]
18 changes: 18 additions & 0 deletions data/json/monster_special_attacks/monster_gun.json
Original file line number Diff line number Diff line change
Expand Up @@ -295,5 +295,23 @@
"range": 100,
"dispersion": 1000,
"ranged_damage": { "damage_type": "stab", "amount": 30 }
},
{
"id": "boomer_head",
"copy-from": "fake_item",
"type": "GUN",
"reload_noise": "slosh.",
"name": { "str": "boomer head" },
"description": "The head of a boomer, if you see this item it's a bug.",
"material": [ "flesh" ],
"flags": [ "NEVER_JAMS", "NON_FOULING" ],
"ammo_effects": [ "NEVER_MISFIRES", "NO_PENETRATE_OBSTACLES", "BILE_BOMB", "BILE_JET" ],
"ammo": [ "bile" ],
"skill": "rifle",
"dispersion": 300,
"durability": 10,
"range": 10,
"pocket_data": [ { "magazine_well": "2 L", "pocket_type": "MAGAZINE_WELL", "item_restriction": [ "boomer_stomach" ] } ],
"melee_damage": { "bash": 9 }
}
]
13 changes: 13 additions & 0 deletions src/ammo_effect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,19 @@ void ammo_effect::load( const JsonObject &jo, const std::string_view )
JsonObject joe = jo.get_object( "explosion" );
aoe_explosion_data = load_explosion_data( joe );
}
if( jo.has_member( "on_hit_effects" ) ) {
JsonArray json_arr = jo.get_array( "on_hit_effects" );
for( JsonObject joe : json_arr ) {
on_hit_effect new_effect;
optional( joe, was_loaded, "bp_to_hit", new_effect.bp_to_hit, bodypart_str_id::NULL_ID() );
optional( joe, was_loaded, "need_touch_skin", new_effect.need_touch_skin, false );
optional( joe, was_loaded, "affected_bps", new_effect.affected_bps );
mandatory( joe, was_loaded, "duration", new_effect.duration );
mandatory( joe, was_loaded, "effect", new_effect.effect );
mandatory( joe, was_loaded, "intensity", new_effect.intensity );
on_hit_effects.push_back( new_effect );
}
}
optional( jo, was_loaded, "do_flashbang", do_flashbang, false );
optional( jo, was_loaded, "do_emp_blast", do_emp_blast, false );
optional( jo, was_loaded, "foamcrete_build", foamcrete_build, false );
Expand Down
11 changes: 11 additions & 0 deletions src/ammo_effect.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,15 @@ template <typename T> class generic_factory;

generic_factory<ammo_effect> &get_all_ammo_effects();

struct on_hit_effect {
bodypart_id bp_to_hit;
bool need_touch_skin;
efftype_id effect;
time_duration duration;
int intensity;
std::vector<bodypart_id> affected_bps;
};

struct ammo_effect {
public:
void load( const JsonObject &jo, std::string_view src );
Expand Down Expand Up @@ -55,6 +64,8 @@ struct ammo_effect {
int trail_intensity_max = 0;
int trail_chance = 100;

std::vector<on_hit_effect> on_hit_effects;

// Used by generic_factory
ammo_effect_str_id id;
std::vector<std::pair<ammo_effect_str_id, mod_id>> src;
Expand Down
45 changes: 42 additions & 3 deletions src/creature.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <string>
#include <tuple>

#include "ammo_effect.h"
#include "anatomy.h"
#include "body_part_set.h"
#include "cached_options.h"
Expand Down Expand Up @@ -85,6 +86,7 @@ static const ammo_effect_str_id ammo_effect_FOAMCRETE( "FOAMCRETE" );
static const ammo_effect_str_id ammo_effect_IGNITE( "IGNITE" );
static const ammo_effect_str_id ammo_effect_INCENDIARY( "INCENDIARY" );
static const ammo_effect_str_id ammo_effect_LARGE_BEANBAG( "LARGE_BEANBAG" );
static const ammo_effect_str_id ammo_effect_LIQUID( "LIQUID" );
static const ammo_effect_str_id ammo_effect_MAGIC( "MAGIC" );
static const ammo_effect_str_id ammo_effect_NOGIB( "NOGIB" );
static const ammo_effect_str_id ammo_effect_NO_DAMAGE_SCALING( "NO_DAMAGE_SCALING" );
Expand Down Expand Up @@ -969,11 +971,34 @@ double Creature::accuracy_projectile_attack( dealt_projectile_attack &attack ) c
return attack.missed_by + std::max( 0.0, std::min( 1.0, dodge_rescaled ) );
}

void projectile::apply_effects_nodamage( Creature &target, Creature *source ) const
void projectile::apply_effects_nodamage( Creature &target, Creature *source,
const dealt_damage_instance &dealt_dam, bool soaked_through ) const
Fris0uman marked this conversation as resolved.
Show resolved Hide resolved
{
bool is_liquid = proj_effects.count( ammo_effect_LIQUID );
if( proj_effects.count( ammo_effect_BOUNCE ) ) {
target.add_effect( effect_source( source ), effect_bounced, 1_turns );
}

for( const ammo_effect_str_id &proj_effect : proj_effects ) {
for( const on_hit_effect &on_hit_eff : proj_effect->on_hit_effects ) {
if( on_hit_eff.need_touch_skin && is_liquid && !soaked_through ) {
continue;
}
if( on_hit_eff.bp_to_hit ) {
if( on_hit_eff.bp_to_hit != dealt_dam.bp_hit ) {
continue;
}
}
if( !on_hit_eff.affected_bps.empty() ) {
for( const bodypart_id &bp : on_hit_eff.affected_bps ) {
target.add_effect( on_hit_eff.effect, on_hit_eff.duration, bp, false, on_hit_eff.intensity );
}
} else {
target.add_effect( on_hit_eff.effect, on_hit_eff.duration, false, on_hit_eff.intensity );
}

}
}
}

void projectile::apply_effects_damage( Creature &target, Creature *source,
Expand Down Expand Up @@ -1316,8 +1341,6 @@ void Creature::deal_projectile_attack( Creature *source, dealt_projectile_attack
return;
}

proj.apply_effects_nodamage( *this, source );

projectile_attack_results hit_selection = select_body_part_projectile_attack( proj, goodhit,
missed_by );
// Create a copy that records whether the attack is a crit.
Expand Down Expand Up @@ -1346,6 +1369,20 @@ void Creature::deal_projectile_attack( Creature *source, dealt_projectile_attack
}
}

bool soaked_through = false;
if( attack.proj.proj_effects.count( ammo_effect_LIQUID ) > 0 ) {
if( Character *char_target = as_character() ) {
// clothing_wetness_mult returns the effective permeability of the armor on bp_hit
// as a float between 0 and 1
// 0 permeability means no liquid touches the skin and the damage is negated
// 1 permeability means all liquid touches the skin and no damage is negated
float permeability = char_target->worn.clothing_wetness_mult( hit_selection.bp_hit );
permeability = std::clamp( permeability, 0.0f, 1.0f );
soaked_through = permeability > 0;
Fris0uman marked this conversation as resolved.
Show resolved Hide resolved
impact.mult_damage( permeability );
}
}

dealt_dam = deal_damage( source, hit_selection.bp_hit, impact, wp_attack_copy );
// Force damage instance to match the selected body point
dealt_dam.bp_hit = hit_selection.bp_hit;
Expand All @@ -1354,6 +1391,8 @@ void Creature::deal_projectile_attack( Creature *source, dealt_projectile_attack

proj.apply_effects_damage( *this, source, dealt_dam, goodhit < accuracy_critical );

proj.apply_effects_nodamage( *this, source, dealt_dam, soaked_through );
Fris0uman marked this conversation as resolved.
Show resolved Hide resolved

if( print_messages ) {
messaging_projectile_attack( source, hit_selection, dealt_dam.total_damage() );
}
Expand Down
3 changes: 2 additions & 1 deletion src/projectile.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ struct projectile {
const dealt_damage_instance &dealt_dam,
bool critical ) const;
// pplies proj_effects to a creature that was hit but not damaged
void apply_effects_nodamage( Creature &target, Creature *source ) const;
void apply_effects_nodamage( Creature &target, Creature *source,
const dealt_damage_instance &dealt_dam, bool soaked_through = false ) const;

projectile();
projectile( const projectile & );
Expand Down
5 changes: 5 additions & 0 deletions src/ranged.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ static const ammo_effect_str_id ammo_effect_HEAVY_HIT( "HEAVY_HIT" );
static const ammo_effect_str_id ammo_effect_IGNITE( "IGNITE" );
static const ammo_effect_str_id ammo_effect_LASER( "LASER" );
static const ammo_effect_str_id ammo_effect_LIGHTNING( "LIGHTNING" );
static const ammo_effect_str_id ammo_effect_LIQUID( "LIQUID" );
static const ammo_effect_str_id ammo_effect_MATCHHEAD( "MATCHHEAD" );
static const ammo_effect_str_id ammo_effect_MULTI_EFFECTS( "MULTI_EFFECTS" );
static const ammo_effect_str_id ammo_effect_NON_FOULING( "NON_FOULING" );
Expand Down Expand Up @@ -2193,6 +2194,10 @@ static projectile make_gun_projectile( const item &gun )
proj.range = gun.gun_range();
proj.proj_effects = gun.ammo_effects();

if( gun.ammo_data()->phase == phase_id::LIQUID ) {
proj.proj_effects.insert( ammo_effect_LIQUID );
}

auto &fx = proj.proj_effects;

if( ( gun.has_ammo_data() && gun.ammo_data()->phase == phase_id::LIQUID ) ||
Expand Down
Loading