From 4abdbc8eec0c78c111aa6c37bda485c4d8a81051 Mon Sep 17 00:00:00 2001 From: Dillon Matchett Date: Sun, 24 Jul 2022 17:17:38 -0300 Subject: [PATCH] damaged armor scaling appropriately (#59529) * default thickness for items set to 1mm --- src/item.cpp | 201 +++++++++++++++++++++------------------------------ src/item.h | 5 ++ 2 files changed, 87 insertions(+), 119 deletions(-) diff --git a/src/item.cpp b/src/item.cpp index 27962e5ee1d4a..220ce5fc787ac 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -795,6 +795,15 @@ int item::damage_level( int dmg ) const } } +float item::damage_scaling( bool to_self ) const +{ + float scale = damage_level() * .125f; + // caps the scale if this is a hit to the player vs the item itself + scale = 1.0f - scale; + // reinforce only effects damage to the item proper otherwise max scaling is 100f + return to_self ? scale : std::min( scale, 1.0f ); +} + int item::damage_floor( bool allow_negative ) const { return std::max( min_damage() + degradation(), allow_negative ? min_damage() : 0 ); @@ -7843,8 +7852,10 @@ const armor_portion_data *item::portion_for_bodypart( const sub_bodypart_id &bod float item::get_thickness() const { const islot_armor *t = find_armor_data(); + // if an item isn't armor we assume it is 1mm thick + // TODO: Estimate normal items thickness or protection based on weight and density if( t == nullptr ) { - return is_pet_armor() ? type->pet_armor->thickness : 0.0f; + return is_pet_armor() ? type->pet_armor->thickness : 1.0f; } return t->avg_thickness(); } @@ -7852,6 +7863,7 @@ float item::get_thickness() const float item::get_thickness( const bodypart_id &bp ) const { const islot_armor *t = find_armor_data(); + // don't return a fixed value for this one since an item is never going to be covering a body part if( t == nullptr ) { return is_pet_armor() ? type->pet_armor->thickness : 0.0f; } @@ -8040,32 +8052,30 @@ float item::bash_resist( bool to_self, const bodypart_id &bp, int roll ) const float resist = 0.0f; float mod = get_clothing_mod_val( clothing_mod_type_bash ); - const int dmg = damage_level(); - const float eff_damage = to_self ? std::min( dmg, 0 ) : std::max( dmg, 0 ); + + const float damage_scale = damage_scaling( to_self ); if( !bp_null ) { const std::vector &armor_mats = armor_made_of( bp ); // If we have armour portion materials for this body part, use that instead if( !armor_mats.empty() ) { for( const part_material *m : armor_mats ) { - const float eff_thic = std::max( 0.1f, m->thickness - eff_damage ); // only count the material if it's hit // if roll is -1 each material is rolled at this point individually int internal_roll; roll < 0 ? internal_roll = rng( 0, 99 ) : internal_roll = roll; if( internal_roll < m->cover ) { - resist += m->id->bash_resist() * eff_thic; + resist += m->id->bash_resist() * m->thickness; } } - return resist + mod; + return ( resist + mod ) * damage_scale; } } // base resistance // Don't give reinforced items +armor, just more resistance to ripping const float avg_thickness = bp_null ? get_thickness() : get_thickness( bp ); - const float eff_thickness = std::max( 0.1f, avg_thickness - eff_damage ); const int total = type->mat_portion_total == 0 ? 1 : type->mat_portion_total; const std::map mats = made_of(); if( !mats.empty() ) { @@ -8076,7 +8086,7 @@ float item::bash_resist( bool to_self, const bodypart_id &bp, int roll ) const resist /= total; } - return ( resist * eff_thickness ) + mod; + return ( resist * avg_thickness + mod ) * damage_scale; } float item::bash_resist( const sub_bodypart_id &bp, bool to_self, int roll ) const @@ -8087,30 +8097,27 @@ float item::bash_resist( const sub_bodypart_id &bp, bool to_self, int roll ) con float resist = 0.0f; float mod = get_clothing_mod_val( clothing_mod_type_bash ); - const int dmg = damage_level(); - const float eff_damage = to_self ? std::min( dmg, 0 ) : std::max( dmg, 0 ); + const float damage_scale = damage_scaling( to_self ); const std::vector &armor_mats = armor_made_of( bp ); // If we have armour portion materials for this body part, use that instead if( !armor_mats.empty() ) { for( const part_material *m : armor_mats ) { - const float eff_thic = std::max( 0.1f, m->thickness - eff_damage ); // only count the material if it's hit // if roll is -1 each material is rolled at this point individually int internal_roll; roll < 0 ? internal_roll = rng( 0, 99 ) : internal_roll = roll; if( internal_roll < m->cover ) { - resist += m->id->bash_resist() * eff_thic; + resist += m->id->bash_resist() * m->thickness; } } - return resist + mod; + return ( resist + mod ) * damage_scale; } // base resistance this chunk is needed for items defined the old materials way // Don't give reinforced items +armor, just more resistance to ripping const float avg_thickness = get_thickness( bp->parent ); - const float eff_thickness = std::max( 0.1f, avg_thickness - eff_damage ); const int total = type->mat_portion_total == 0 ? 1 : type->mat_portion_total; const std::map mats = made_of(); if( !mats.empty() ) { @@ -8121,7 +8128,7 @@ float item::bash_resist( const sub_bodypart_id &bp, bool to_self, int roll ) con resist /= total; } - return ( resist * eff_thickness ) + mod; + return ( resist * avg_thickness + mod ) * damage_scale; } @@ -8133,33 +8140,31 @@ float item::cut_resist( bool to_self, const bodypart_id &bp, int roll ) const const bool bp_null = bp == bodypart_id(); float resist = 0.0f; - float mod = get_clothing_mod_val( clothing_mod_type_cut ); - const int dmg = damage_level(); - const float eff_damage = to_self ? std::min( dmg, 0 ) : std::max( dmg, 0 ); + float mod = get_clothing_mod_val( clothing_mod_type_bash ); + + const float damage_scale = damage_scaling( to_self ); if( !bp_null ) { const std::vector &armor_mats = armor_made_of( bp ); // If we have armour portion materials for this body part, use that instead if( !armor_mats.empty() ) { for( const part_material *m : armor_mats ) { - const float eff_thic = std::max( 0.1f, m->thickness - eff_damage ); // only count the material if it's hit // if roll is -1 each material is rolled at this point individually int internal_roll; roll < 0 ? internal_roll = rng( 0, 99 ) : internal_roll = roll; if( internal_roll < m->cover ) { - resist += m->id->cut_resist() * eff_thic; + resist += m->id->cut_resist() * m->thickness; } } - return resist + mod; + return ( resist + mod ) * damage_scale; } } // base resistance // Don't give reinforced items +armor, just more resistance to ripping const float avg_thickness = bp_null ? get_thickness() : get_thickness( bp ); - const float eff_thickness = std::max( 0.1f, avg_thickness - eff_damage ); const int total = type->mat_portion_total == 0 ? 1 : type->mat_portion_total; const std::map mats = made_of(); if( !mats.empty() ) { @@ -8170,7 +8175,7 @@ float item::cut_resist( bool to_self, const bodypart_id &bp, int roll ) const resist /= total; } - return ( resist * eff_thickness ) + mod; + return ( resist * avg_thickness + mod ) * damage_scale; } float item::cut_resist( const sub_bodypart_id &bp, bool to_self, int roll ) const @@ -8180,31 +8185,28 @@ float item::cut_resist( const sub_bodypart_id &bp, bool to_self, int roll ) cons } float resist = 0.0f; - float mod = get_clothing_mod_val( clothing_mod_type_cut ); - const int dmg = damage_level(); - const float eff_damage = to_self ? std::min( dmg, 0 ) : std::max( dmg, 0 ); + float mod = get_clothing_mod_val( clothing_mod_type_bash ); + const float damage_scale = damage_scaling( to_self ); const std::vector &armor_mats = armor_made_of( bp ); // If we have armour portion materials for this body part, use that instead if( !armor_mats.empty() ) { for( const part_material *m : armor_mats ) { - const float eff_thic = std::max( 0.1f, m->thickness - eff_damage ); // only count the material if it's hit // if roll is -1 each material is rolled at this point individually int internal_roll; roll < 0 ? internal_roll = rng( 0, 99 ) : internal_roll = roll; if( internal_roll < m->cover ) { - resist += m->id->cut_resist() * eff_thic; + resist += m->id->cut_resist() * m->thickness; } } - return resist + mod; + return ( resist + mod ) * damage_scale; } // base resistance this chunk is needed for items defined the old materials way // Don't give reinforced items +armor, just more resistance to ripping const float avg_thickness = get_thickness( bp->parent ); - const float eff_thickness = std::max( 0.1f, avg_thickness - eff_damage ); const int total = type->mat_portion_total == 0 ? 1 : type->mat_portion_total; const std::map mats = made_of(); if( !mats.empty() ) { @@ -8215,7 +8217,8 @@ float item::cut_resist( const sub_bodypart_id &bp, bool to_self, int roll ) cons resist /= total; } - return ( resist * eff_thickness ) + mod; + return ( resist * avg_thickness + mod ) * damage_scale; + } #if defined(_MSC_VER) @@ -8242,33 +8245,31 @@ float item::bullet_resist( bool to_self, const bodypart_id &bp, int roll ) const const bool bp_null = bp == bodypart_id(); float resist = 0.0f; - float mod = get_clothing_mod_val( clothing_mod_type_bullet ); - const int dmg = damage_level(); - const float eff_damage = to_self ? std::min( dmg, 0 ) : std::max( dmg, 0 ); + float mod = get_clothing_mod_val( clothing_mod_type_bash ); + + const float damage_scale = damage_scaling( to_self ); if( !bp_null ) { const std::vector &armor_mats = armor_made_of( bp ); // If we have armour portion materials for this body part, use that instead if( !armor_mats.empty() ) { for( const part_material *m : armor_mats ) { - const float eff_thic = std::max( 0.1f, m->thickness - eff_damage ); // only count the material if it's hit // if roll is -1 each material is rolled at this point individually int internal_roll; roll < 0 ? internal_roll = rng( 0, 99 ) : internal_roll = roll; if( internal_roll < m->cover ) { - resist += m->id->bullet_resist() * eff_thic; + resist += m->id->bullet_resist() * m->thickness; } } - return resist + mod; + return ( resist + mod ) * damage_scale; } } // base resistance // Don't give reinforced items +armor, just more resistance to ripping const float avg_thickness = bp_null ? get_thickness() : get_thickness( bp ); - const float eff_thickness = std::max( 0.1f, avg_thickness - eff_damage ); const int total = type->mat_portion_total == 0 ? 1 : type->mat_portion_total; const std::map mats = made_of(); if( !mats.empty() ) { @@ -8279,7 +8280,7 @@ float item::bullet_resist( bool to_self, const bodypart_id &bp, int roll ) const resist /= total; } - return ( resist * eff_thickness ) + mod; + return ( resist * avg_thickness + mod ) * damage_scale; } float item::bullet_resist( const sub_bodypart_id &bp, bool to_self, int roll ) const @@ -8289,31 +8290,28 @@ float item::bullet_resist( const sub_bodypart_id &bp, bool to_self, int roll ) c } float resist = 0.0f; - float mod = get_clothing_mod_val( clothing_mod_type_bullet ); - const int dmg = damage_level(); - const float eff_damage = to_self ? std::min( dmg, 0 ) : std::max( dmg, 0 ); + float mod = get_clothing_mod_val( clothing_mod_type_bash ); + const float damage_scale = damage_scaling( to_self ); const std::vector &armor_mats = armor_made_of( bp ); // If we have armour portion materials for this body part, use that instead if( !armor_mats.empty() ) { for( const part_material *m : armor_mats ) { - const float eff_thic = std::max( 0.1f, m->thickness - eff_damage ); // only count the material if it's hit // if roll is -1 each material is rolled at this point individually int internal_roll; roll < 0 ? internal_roll = rng( 0, 99 ) : internal_roll = roll; if( internal_roll < m->cover ) { - resist += m->id->bullet_resist() * eff_thic; + resist += m->id->bullet_resist() * m->thickness; } } - return resist + mod; + return ( resist + mod ) * damage_scale; } // base resistance this chunk is needed for items defined the old materials way // Don't give reinforced items +armor, just more resistance to ripping const float avg_thickness = get_thickness( bp->parent ); - const float eff_thickness = std::max( 0.1f, avg_thickness - eff_damage ); const int total = type->mat_portion_total == 0 ? 1 : type->mat_portion_total; const std::map mats = made_of(); if( !mats.empty() ) { @@ -8324,48 +8322,43 @@ float item::bullet_resist( const sub_bodypart_id &bp, bool to_self, int roll ) c resist /= total; } - return ( resist * eff_thickness ) + mod; + return ( resist * avg_thickness + mod ) * damage_scale; + } float item::biological_resist( bool to_self, const bodypart_id &bp, int roll ) const { - if( to_self ) { - // Currently no items are damaged by acid - return std::numeric_limits::max(); - } - if( is_null() ) { return 0.0f; } const bool bp_null = bp == bodypart_id(); float resist = 0.0f; - const int dmg = damage_level(); - const float eff_damage = to_self ? std::min( dmg, 0 ) : std::max( dmg, 0 ); + float mod = get_clothing_mod_val( clothing_mod_type_bash ); + + const float damage_scale = damage_scaling( to_self ); if( !bp_null ) { const std::vector &armor_mats = armor_made_of( bp ); // If we have armour portion materials for this body part, use that instead if( !armor_mats.empty() ) { for( const part_material *m : armor_mats ) { - const float eff_thic = std::max( 0.1f, m->thickness - eff_damage ); // only count the material if it's hit // if roll is -1 each material is rolled at this point individually int internal_roll; roll < 0 ? internal_roll = rng( 0, 99 ) : internal_roll = roll; if( internal_roll < m->cover ) { - resist += m->id->biological_resist() * eff_thic; + resist += m->id->biological_resist() * m->thickness; } } - return resist; + return ( resist + mod ) * damage_scale; } } // base resistance // Don't give reinforced items +armor, just more resistance to ripping const float avg_thickness = bp_null ? get_thickness() : get_thickness( bp ); - const float eff_thickness = std::max( 0.1f, avg_thickness - eff_damage ); const int total = type->mat_portion_total == 0 ? 1 : type->mat_portion_total; const std::map mats = made_of(); if( !mats.empty() ) { @@ -8376,45 +8369,38 @@ float item::biological_resist( bool to_self, const bodypart_id &bp, int roll ) c resist /= total; } - return resist * eff_thickness; + return ( resist * avg_thickness + mod ) * damage_scale; } float item::biological_resist( const sub_bodypart_id &bp, bool to_self, int roll ) const { - if( to_self ) { - // Currently no items are damaged by acid - return std::numeric_limits::max(); - } - if( is_null() ) { return 0.0f; } float resist = 0.0f; - const int dmg = damage_level(); - const float eff_damage = to_self ? std::min( dmg, 0 ) : std::max( dmg, 0 ); + float mod = get_clothing_mod_val( clothing_mod_type_bash ); + const float damage_scale = damage_scaling( to_self ); const std::vector &armor_mats = armor_made_of( bp ); // If we have armour portion materials for this body part, use that instead if( !armor_mats.empty() ) { for( const part_material *m : armor_mats ) { - const float eff_thic = std::max( 0.1f, m->thickness - eff_damage ); // only count the material if it's hit // if roll is -1 each material is rolled at this point individually int internal_roll; roll < 0 ? internal_roll = rng( 0, 99 ) : internal_roll = roll; if( internal_roll < m->cover ) { - resist += m->id->biological_resist() * eff_thic; + resist += m->id->biological_resist() * m->thickness; } } - return resist; + return ( resist + mod ) * damage_scale; } // base resistance this chunk is needed for items defined the old materials way // Don't give reinforced items +armor, just more resistance to ripping const float avg_thickness = get_thickness( bp->parent ); - const float eff_thickness = std::max( 0.1f, avg_thickness - eff_damage ); const int total = type->mat_portion_total == 0 ? 1 : type->mat_portion_total; const std::map mats = made_of(); if( !mats.empty() ) { @@ -8425,48 +8411,43 @@ float item::biological_resist( const sub_bodypart_id &bp, bool to_self, int roll resist /= total; } - return resist * eff_thickness; + return ( resist * avg_thickness + mod ) * damage_scale; + } float item::electric_resist( bool to_self, const bodypart_id &bp, int roll ) const { - if( to_self ) { - // Currently no items are damaged by acid - return std::numeric_limits::max(); - } - if( is_null() ) { return 0.0f; } const bool bp_null = bp == bodypart_id(); float resist = 0.0f; - const int dmg = damage_level(); - const float eff_damage = to_self ? std::min( dmg, 0 ) : std::max( dmg, 0 ); + float mod = get_clothing_mod_val( clothing_mod_type_bash ); + + const float damage_scale = damage_scaling( to_self ); if( !bp_null ) { const std::vector &armor_mats = armor_made_of( bp ); // If we have armour portion materials for this body part, use that instead if( !armor_mats.empty() ) { for( const part_material *m : armor_mats ) { - const float eff_thic = std::max( 0.1f, m->thickness - eff_damage ); // only count the material if it's hit // if roll is -1 each material is rolled at this point individually int internal_roll; roll < 0 ? internal_roll = rng( 0, 99 ) : internal_roll = roll; if( internal_roll < m->cover ) { - resist += m->id->elec_resist() * eff_thic; + resist += m->id->elec_resist() * m->thickness; } } - return resist; + return ( resist + mod ) * damage_scale; } } // base resistance // Don't give reinforced items +armor, just more resistance to ripping const float avg_thickness = bp_null ? get_thickness() : get_thickness( bp ); - const float eff_thickness = std::max( 0.1f, avg_thickness - eff_damage ); const int total = type->mat_portion_total == 0 ? 1 : type->mat_portion_total; const std::map mats = made_of(); if( !mats.empty() ) { @@ -8477,45 +8458,38 @@ float item::electric_resist( bool to_self, const bodypart_id &bp, int roll ) con resist /= total; } - return resist * eff_thickness; + return ( resist * avg_thickness + mod ) * damage_scale; } float item::electric_resist( const sub_bodypart_id &bp, bool to_self, int roll ) const { - if( to_self ) { - // Currently no items are damaged by acid - return std::numeric_limits::max(); - } - if( is_null() ) { return 0.0f; } float resist = 0.0f; - const int dmg = damage_level(); - const float eff_damage = to_self ? std::min( dmg, 0 ) : std::max( dmg, 0 ); + float mod = get_clothing_mod_val( clothing_mod_type_bash ); + const float damage_scale = damage_scaling( to_self ); const std::vector &armor_mats = armor_made_of( bp ); // If we have armour portion materials for this body part, use that instead if( !armor_mats.empty() ) { for( const part_material *m : armor_mats ) { - const float eff_thic = std::max( 0.1f, m->thickness - eff_damage ); // only count the material if it's hit // if roll is -1 each material is rolled at this point individually int internal_roll; roll < 0 ? internal_roll = rng( 0, 99 ) : internal_roll = roll; if( internal_roll < m->cover ) { - resist += m->id->elec_resist() * eff_thic; + resist += m->id->elec_resist() * m->thickness; } } - return resist; + return ( resist + mod ) * damage_scale; } // base resistance this chunk is needed for items defined the old materials way // Don't give reinforced items +armor, just more resistance to ripping const float avg_thickness = get_thickness( bp->parent ); - const float eff_thickness = std::max( 0.1f, avg_thickness - eff_damage ); const int total = type->mat_portion_total == 0 ? 1 : type->mat_portion_total; const std::map mats = made_of(); if( !mats.empty() ) { @@ -8526,48 +8500,43 @@ float item::electric_resist( const sub_bodypart_id &bp, bool to_self, int roll ) resist /= total; } - return resist * eff_thickness; + return ( resist * avg_thickness + mod ) * damage_scale; + } float item::cold_resist( bool to_self, const bodypart_id &bp, int roll ) const { - if( to_self ) { - // Currently no items are damaged by acid - return std::numeric_limits::max(); - } - if( is_null() ) { return 0.0f; } const bool bp_null = bp == bodypart_id(); float resist = 0.0f; - const int dmg = damage_level(); - const float eff_damage = to_self ? std::min( dmg, 0 ) : std::max( dmg, 0 ); + float mod = get_clothing_mod_val( clothing_mod_type_bash ); + + const float damage_scale = damage_scaling( to_self ); if( !bp_null ) { const std::vector &armor_mats = armor_made_of( bp ); // If we have armour portion materials for this body part, use that instead if( !armor_mats.empty() ) { for( const part_material *m : armor_mats ) { - const float eff_thic = std::max( 0.1f, m->thickness - eff_damage ); // only count the material if it's hit // if roll is -1 each material is rolled at this point individually int internal_roll; roll < 0 ? internal_roll = rng( 0, 99 ) : internal_roll = roll; if( internal_roll < m->cover ) { - resist += m->id->cold_resist() * eff_thic; + resist += m->id->cold_resist() * m->thickness; } } - return resist; + return ( resist + mod ) * damage_scale; } } // base resistance // Don't give reinforced items +armor, just more resistance to ripping const float avg_thickness = bp_null ? get_thickness() : get_thickness( bp ); - const float eff_thickness = std::max( 0.1f, avg_thickness - eff_damage ); const int total = type->mat_portion_total == 0 ? 1 : type->mat_portion_total; const std::map mats = made_of(); if( !mats.empty() ) { @@ -8578,45 +8547,38 @@ float item::cold_resist( bool to_self, const bodypart_id &bp, int roll ) const resist /= total; } - return resist * eff_thickness; + return ( resist * avg_thickness + mod ) * damage_scale; } float item::cold_resist( const sub_bodypart_id &bp, bool to_self, int roll ) const { - if( to_self ) { - // Currently no items are damaged by acid - return std::numeric_limits::max(); - } - if( is_null() ) { return 0.0f; } float resist = 0.0f; - const int dmg = damage_level(); - const float eff_damage = to_self ? std::min( dmg, 0 ) : std::max( dmg, 0 ); + float mod = get_clothing_mod_val( clothing_mod_type_bash ); + const float damage_scale = damage_scaling( to_self ); const std::vector &armor_mats = armor_made_of( bp ); // If we have armour portion materials for this body part, use that instead if( !armor_mats.empty() ) { for( const part_material *m : armor_mats ) { - const float eff_thic = std::max( 0.1f, m->thickness - eff_damage ); // only count the material if it's hit // if roll is -1 each material is rolled at this point individually int internal_roll; roll < 0 ? internal_roll = rng( 0, 99 ) : internal_roll = roll; if( internal_roll < m->cover ) { - resist += m->id->cold_resist() * eff_thic; + resist += m->id->cold_resist() * m->thickness; } } - return resist; + return ( resist + mod ) * damage_scale; } // base resistance this chunk is needed for items defined the old materials way // Don't give reinforced items +armor, just more resistance to ripping const float avg_thickness = get_thickness( bp->parent ); - const float eff_thickness = std::max( 0.1f, avg_thickness - eff_damage ); const int total = type->mat_portion_total == 0 ? 1 : type->mat_portion_total; const std::map mats = made_of(); if( !mats.empty() ) { @@ -8627,7 +8589,8 @@ float item::cold_resist( const sub_bodypart_id &bp, bool to_self, int roll ) con resist /= total; } - return resist * eff_thickness; + return ( resist * avg_thickness + mod ) * damage_scale; + } float item::acid_resist( bool to_self, int base_env_resist, const bodypart_id &bp ) const diff --git a/src/item.h b/src/item.h index 09016c5e1b80a..62bf94e7daf19 100644 --- a/src/item.h +++ b/src/item.h @@ -1298,6 +1298,11 @@ class item : public visitable */ int damage_level( int dmg = INT_MIN ) const; + /** + * Returns a scaling value for armor values based on damage taken + */ + float damage_scaling( bool to_self = false ) const; + /** * Get the minimum possible damage this item can be repaired to, * accounting for degradation.