Skip to content

Commit

Permalink
Character::bodytemp - store items worn per bp
Browse files Browse the repository at this point in the history
First, get a list of the items worn on each body part, then pass that
list to each function that previous iterated through all the body parts
and only acted on the ones covering the queried body part.

Removes item::covers from the profile in several places.
  • Loading branch information
anothersimulacrum committed Aug 12, 2021
1 parent 331794a commit 4f63583
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 45 deletions.
110 changes: 71 additions & 39 deletions src/character.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4768,30 +4768,31 @@ bool Character::in_climate_control()
return regulated_area;
}

int Character::get_wind_resistance( const bodypart_id &bp ) const
int Character::get_wind_resistance( const bodypart_id &bp,
const std::map<bodypart_id, std::vector<const item *>> &clothing_map ) const
{
int coverage = 0;
float totalExposed = 1.0f;
int totalCoverage = 0;
int penalty = 100;

for( const item &i : worn ) {
if( i.covers( bp ) ) {
if( i.made_of( material_id( "leather" ) ) || i.made_of( material_id( "plastic" ) ) ||
i.made_of( material_id( "bone" ) ) ||
i.made_of( material_id( "chitin" ) ) || i.made_of( material_id( "nomex" ) ) ) {
penalty = 10; // 90% effective
} else if( i.made_of( material_id( "cotton" ) ) ) {
penalty = 30;
} else if( i.made_of( material_id( "wool" ) ) ) {
penalty = 40;
} else {
penalty = 1; // 99% effective
}

coverage = std::max( 0, i.get_coverage( bp ) - penalty );
totalExposed *= ( 1.0 - coverage / 100.0 ); // Coverage is between 0 and 1?
const std::vector<const item *> &worn_here = clothing_map.at( bp );
for( const item *it : worn_here ) {
const item &i = *it;
if( i.made_of( material_id( "leather" ) ) || i.made_of( material_id( "plastic" ) ) ||
i.made_of( material_id( "bone" ) ) ||
i.made_of( material_id( "chitin" ) ) || i.made_of( material_id( "nomex" ) ) ) {
penalty = 10; // 90% effective
} else if( i.made_of( material_id( "cotton" ) ) ) {
penalty = 30;
} else if( i.made_of( material_id( "wool" ) ) ) {
penalty = 40;
} else {
penalty = 1; // 99% effective
}

coverage = std::max( 0, i.get_coverage( bp ) - penalty );
totalExposed *= ( 1.0 - coverage / 100.0 ); // Coverage is between 0 and 1?
}

// Your shell provides complete wind protection if you're inside it
Expand Down Expand Up @@ -6703,6 +6704,17 @@ void Character::update_bodytemp()
const int mutation_heat_bonus = mutation_heat_high - mutation_heat_low;

const int h_radiation = get_heat_radiation( pos(), false );

std::map<bodypart_id, std::vector<const item *>> clothing_map;
for( const bodypart_id &bp : get_all_body_parts() ) {
clothing_map.emplace( bp, std::vector<const item *>() );
}
for( const item &it : worn ) {
for( const bodypart_str_id &covered : it.get_covered_body_parts() ) {
clothing_map[covered.id()].emplace_back( &it );
}
}

// Current temperature and converging temperature calculations
for( const bodypart_id &bp : get_all_body_parts() ) {

Expand All @@ -6720,13 +6732,14 @@ void Character::update_bodytemp()
get_part_temp_cur( bp ) );
// Produces a smooth curve between 30.0 and 60.0.
double homeostasis_adjustment = 30.0 * ( 1.0 + scaled_temperature );
int clothing_warmth_adjustment = static_cast<int>( homeostasis_adjustment * warmth( bp ) );
int clothing_warmth_adjustment = static_cast<int>( homeostasis_adjustment * warmth( bp,
clothing_map ) );
int clothing_warmth_adjusted_bonus = static_cast<int>( homeostasis_adjustment * bonus_item_warmth(
bp ) );
// WINDCHILL

bp_windpower = static_cast<int>( static_cast<float>( bp_windpower ) * ( 1 - get_wind_resistance(
bp ) / 100.0 ) );
bp, clothing_map ) / 100.0 ) );
// Calculate windchill
int windchill = get_local_windchill( player_local_temp,
get_local_humidity( weather.humidity, get_weather().weather_id, sheltered ),
Expand Down Expand Up @@ -6772,7 +6785,7 @@ void Character::update_bodytemp()
// BLISTERS : Skin gets blisters from intense heat exposure.
// Fire protection protects from blisters.
// Heatsinks give near-immunity.
if( blister_count - get_armor_fire( bp ) - ( has_heatsink ? 20 : 0 ) > 0 ) {
if( blister_count - get_armor_fire( bp, clothing_map ) - ( has_heatsink ? 20 : 0 ) > 0 ) {
add_effect( effect_blisters, 1_turns, bp );
if( pyromania ) {
add_morale( MORALE_PYROMANIA_NEARFIRE, 10, 10, 1_hours,
Expand Down Expand Up @@ -6916,7 +6929,7 @@ void Character::update_bodytemp()
remove_effect( effect_hot_speed, bp );
}

update_frostbite( bp, bp_windpower );
update_frostbite( bp, bp_windpower, clothing_map );

// Warn the player if condition worsens
if( temp_before > BODYTEMP_FREEZING && temp_after < BODYTEMP_FREEZING ) {
Expand Down Expand Up @@ -6978,7 +6991,8 @@ void Character::update_bodytemp()
}
}

void Character::update_frostbite( const bodypart_id &bp, const int FBwindPower )
void Character::update_frostbite( const bodypart_id &bp, const int FBwindPower,
const std::map<bodypart_id, std::vector<const item *>> &clothing_map )
{
// FROSTBITE - only occurs to hands, feet, face
/**
Expand Down Expand Up @@ -7017,7 +7031,7 @@ void Character::update_frostbite( const bodypart_id &bp, const int FBwindPower )
int wetness_percentage = 100 * get_part_wetness_percentage( bp ); // 0 - 100
// Warmth gives a slight buff to temperature resistance
// Wetness gives a heavy nerf to temperature resistance
double adjusted_warmth = warmth( bp ) - wetness_percentage;
double adjusted_warmth = warmth( bp, clothing_map ) - wetness_percentage;
int Ftemperature = static_cast<int>( player_local_temp + 0.2 * adjusted_warmth );

int intense = get_effect_int( effect_frostbite, bp );
Expand Down Expand Up @@ -8588,6 +8602,25 @@ int Character::get_armor_bullet( bodypart_id bp ) const
}

int Character::get_armor_type( damage_type dt, bodypart_id bp ) const
{
std::map<bodypart_id, std::vector<const item *>> clothing_map;
for( const bodypart_id &part : get_all_body_parts() ) {
clothing_map.emplace( part, std::vector<const item *>() );
}
for( const item &it : worn ) {
for( const bodypart_str_id &covered : it.get_covered_body_parts() ) {
const bodypart_id &covered_int = covered.id();
if( covered_int != bp ) {
continue;
}
clothing_map[covered_int].emplace_back( &it );
}
}
return get_armor_type( dt, bp, clothing_map );
}

int Character::get_armor_type( damage_type dt, bodypart_id bp,
const std::map<bodypart_id, std::vector<const item *>> &clothing_map ) const
{
switch( dt ) {
case damage_type::PURE:
Expand All @@ -8606,10 +8639,8 @@ int Character::get_armor_type( damage_type dt, bodypart_id bp ) const
case damage_type::COLD:
case damage_type::ELECTRIC: {
int ret = 0;
for( const item &i : worn ) {
if( i.covers( bp ) ) {
ret += i.damage_resist( dt );
}
for( const item *it : clothing_map.at( bp ) ) {
ret += it->damage_resist( dt );
}

ret += mutation_armor( bp, dt );
Expand Down Expand Up @@ -9920,9 +9951,10 @@ float Character::bionic_armor_bonus( const bodypart_id &bp, damage_type dt ) con
return result;
}

int Character::get_armor_fire( const bodypart_id &bp ) const
int Character::get_armor_fire( const bodypart_id &bp,
const std::map<bodypart_id, std::vector<const item *>> &clothing_map ) const
{
return get_armor_type( damage_type::HEAT, bp );
return get_armor_type( damage_type::HEAT, bp, clothing_map );
}

void Character::did_hit( Creature &target )
Expand Down Expand Up @@ -11244,21 +11276,21 @@ std::string Character::is_snuggling() const
return "nothing";
}

int Character::warmth( const bodypart_id &bp ) const
int Character::warmth( const bodypart_id &bp,
const std::map<bodypart_id, std::vector<const item *>> &clothing_map ) const
{
int ret = 0;
double warmth = 0.0;

for( const item &i : worn ) {
if( i.covers( bp ) ) {
warmth = i.get_warmth();
// Wool items do not lose their warmth due to being wet.
// Warmth is reduced by 0 - 66% based on wetness.
if( !i.made_of( material_id( "wool" ) ) ) {
warmth *= 1.0 - 0.66 * get_part_wetness_percentage( bp );
}
ret += std::round( warmth );
for( const item *it : clothing_map.at( bp ) ) {
const item &i = *it;
warmth = i.get_warmth();
// Wool items do not lose their warmth due to being wet.
// Warmth is reduced by 0 - 66% based on wetness.
if( !i.made_of( material_id( "wool" ) ) ) {
warmth *= 1.0 - 0.66 * get_part_wetness_percentage( bp );
}
ret += std::round( warmth );
}
ret += get_effect_int( effect_heating_bionic, bp );
return ret;
Expand Down
14 changes: 10 additions & 4 deletions src/character.h
Original file line number Diff line number Diff line change
Expand Up @@ -668,7 +668,8 @@ class Character : public Creature, public visitable
bool is_hibernating() const;
/** Maintains body temperature */
void update_bodytemp();
void update_frostbite( const bodypart_id &bp, int FBwindPower );
void update_frostbite( const bodypart_id &bp, int FBwindPower,
const std::map<bodypart_id, std::vector<const item *>> &clothing_map );
/** Equalizes heat between body parts */
void temp_equalizer( const bodypart_id &bp1, const bodypart_id &bp2 );

Expand Down Expand Up @@ -707,7 +708,8 @@ class Character : public Creature, public visitable
bool in_climate_control();

/** Returns wind resistance provided by armor, etc **/
int get_wind_resistance( const bodypart_id &bp ) const;
int get_wind_resistance( const bodypart_id &bp,
const std::map<bodypart_id, std::vector<const item *>> &clothing_map ) const;

/** Returns true if the player isn't able to see */
bool is_blind() const;
Expand Down Expand Up @@ -961,7 +963,8 @@ class Character : public Creature, public visitable
/** Returns the armor bonus against given type from martial arts buffs */
int mabuff_armor_bonus( damage_type type ) const;
/** Returns overall fire resistance for the body part */
int get_armor_fire( const bodypart_id &bp ) const;
int get_armor_fire( const bodypart_id &bp,
const std::map<bodypart_id, std::vector<const item *>> &clothing_map ) const;
// --------------- Mutation Stuff ---------------
// In newcharacter.cpp
/** Returns the id of a random starting trait that costs >= 0 points */
Expand Down Expand Up @@ -2303,6 +2306,8 @@ class Character : public Creature, public visitable
int get_armor_acid( bodypart_id bp ) const;
/** Returns overall resistance to given type on the bod part */
int get_armor_type( damage_type dt, bodypart_id bp ) const override;
int get_armor_type( damage_type dt, bodypart_id bp,
const std::map<bodypart_id, std::vector<const item *>> &clothing_map ) const;

int get_stim() const;
void set_stim( int new_stim );
Expand Down Expand Up @@ -2464,7 +2469,8 @@ class Character : public Creature, public visitable
void set_destination_activity( const player_activity &new_destination_activity );
void clear_destination_activity();
/** Returns warmth provided by armor, etc. */
int warmth( const bodypart_id &bp ) const;
int warmth( const bodypart_id &bp,
const std::map<bodypart_id, std::vector<const item *>> &clothing_map ) const;
/** Returns warmth provided by an armor's bonus, like hoods, pockets, etc. */
int bonus_item_warmth( const bodypart_id &bp ) const;
/** Can the player lie down and cover self with blankets etc. **/
Expand Down
15 changes: 13 additions & 2 deletions src/weather.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -412,8 +412,19 @@ void wet_character( Character &target, int amount )
if( !calendar::once_every( 6_seconds ) ) {
return;
}
const int warmth_delay = target.warmth( body_part_torso ) * 4 / 5 + target.warmth(
body_part_head ) / 5;

std::map<bodypart_id, std::vector<const item *>> clothing_map;
for( const bodypart_id &bp : target.get_all_body_parts() ) {
clothing_map.emplace( bp, std::vector<const item *>() );
}
for( const item &it : target.worn ) {
for( const bodypart_str_id &covered : it.get_covered_body_parts() ) {
clothing_map[covered.id()].emplace_back( &it );
}
}

const int warmth_delay = target.warmth( body_part_torso, clothing_map ) * 0.8 +
target.warmth( body_part_head, clothing_map ) * 0.2;
if( rng( 0, 100 - amount + warmth_delay ) > 10 ) {
// Thick clothing slows down (but doesn't cap) soaking
return;
Expand Down

0 comments on commit 4f63583

Please sign in to comment.