From da6a01a8f30543a111d5f09050ba1650555e10f0 Mon Sep 17 00:00:00 2001 From: Robik81 Date: Thu, 15 Oct 2020 17:32:49 +0200 Subject: [PATCH] perspiration, wetness, evaporation --- data/json/body_parts.json | 24 +++++------ data/json/effects.json | 24 ++++++++--- doc/EFFECTS_JSON.md | 9 ++++ src/character.cpp | 91 +++++++++++++++++++++++++-------------- src/effect.cpp | 13 ++++++ src/suffer.cpp | 4 +- 6 files changed, 112 insertions(+), 53 deletions(-) diff --git a/data/json/body_parts.json b/data/json/body_parts.json index abd6148b5e648..00cd0b4ea4860 100644 --- a/data/json/body_parts.json +++ b/data/json/body_parts.json @@ -22,7 +22,7 @@ "fire_warmth_bonus": 150, "squeamish_penalty": 6, "base_hp": 60, - "drench_capacity": 40, + "drench_capacity": 4000, "smash_message": "You smash the %s with a powerful shoulder-check.", "bionic_slots": 80 }, @@ -49,7 +49,7 @@ "fire_warmth_bonus": 150, "squeamish_penalty": 7, "base_hp": 60, - "drench_capacity": 7, + "drench_capacity": 700, "smash_message": "You smash the %s with a firm headbutt.", "smash_efficiency": 0.25, "bionic_slots": 18 @@ -72,7 +72,7 @@ "stylish_bonus": 2, "squeamish_penalty": 8, "base_hp": 60, - "drench_capacity": 1, + "drench_capacity": 100, "flags": [ "IGNORE_TEMP" ], "smash_message": "You use your flippin' face to smash the %s. EXTREME.", "smash_efficiency": 0.25, @@ -98,7 +98,7 @@ "cold_morale_mod": 2, "squeamish_penalty": 9, "base_hp": 60, - "drench_capacity": 1, + "drench_capacity": 100, "smash_message": "You use your flippin' face to smash the %s. EXTREME.", "smash_efficiency": 0.25, "bionic_slots": 4 @@ -129,7 +129,7 @@ "squeamish_penalty": 5, "is_limb": true, "base_hp": 60, - "drench_capacity": 10, + "drench_capacity": 1000, "smash_message": "You elbow-smash the %s.", "bionic_slots": 20 }, @@ -158,7 +158,7 @@ "squeamish_penalty": 5, "is_limb": true, "base_hp": 60, - "drench_capacity": 10, + "drench_capacity": 1000, "smash_message": "You elbow-smash the %s.", "bionic_slots": 20 }, @@ -185,7 +185,7 @@ "fire_warmth_bonus": 1500, "squeamish_penalty": 3, "base_hp": 60, - "drench_capacity": 3, + "drench_capacity": 300, "smash_message": "You smash the %s with your fist.", "bionic_slots": 5 }, @@ -212,7 +212,7 @@ "fire_warmth_bonus": 1500, "squeamish_penalty": 3, "base_hp": 60, - "drench_capacity": 3, + "drench_capacity": 300, "smash_message": "You smash the %s with your fist.", "bionic_slots": 5 }, @@ -242,7 +242,7 @@ "squeamish_penalty": 5, "is_limb": true, "base_hp": 60, - "drench_capacity": 11, + "drench_capacity": 1100, "smash_message": "You bring your knee down on the %s, smashing it.", "bionic_slots": 30 }, @@ -272,7 +272,7 @@ "squeamish_penalty": 5, "is_limb": true, "base_hp": 60, - "drench_capacity": 11, + "drench_capacity": 1100, "smash_message": "You bring your knee down on the %s, smashing it.", "bionic_slots": 30 }, @@ -299,7 +299,7 @@ "fire_warmth_bonus": 300, "squeamish_penalty": 3, "base_hp": 60, - "drench_capacity": 3, + "drench_capacity": 300, "smash_message": "You kick down the %s, smashing it.", "bionic_slots": 7 }, @@ -326,7 +326,7 @@ "fire_warmth_bonus": 300, "squeamish_penalty": 3, "base_hp": 60, - "drench_capacity": 3, + "drench_capacity": 300, "smash_message": "You kick down the %s, smashing it.", "bionic_slots": 7 } diff --git a/data/json/effects.json b/data/json/effects.json index 8142ba8866694..3964b41ad73ca 100644 --- a/data/json/effects.json +++ b/data/json/effects.json @@ -1113,12 +1113,16 @@ "type": "effect_type", "id": "hot", "name": [ "Warm", "Hot", "Scorching" ], - "desc": [ "Your %s feels warm.", "Your %s is sweating from the heat.", "Your %s is sweating profusely!" ], + "desc": [ "Your %s feels warm and sweaty.", "Your %s is sweating a lot from the heat.", "Your %s is sweating profusely!" ], "max_intensity": 3, "part_descs": true, "base_mods": { - "thirst_tick": [ 2400 ], - "thirst_chance": [ 2 ], + "thirst_min": [ 1 ], + "thirst_tick": [ 200 ], + "thirst_chance": [ 6 ], + "perspiration_min": [ 10 ], + "perspiration_tick": [ 60 ], + "perspiration_chance": [ 1 ], "pain_min": [ 1 ], "pain_chance": [ 2 ], "pain_max_val": [ -1 ], @@ -1126,7 +1130,15 @@ "hurt_chance": [ -300 ], "stamina_chance": [ 2 ] }, - "scaling_mods": { "thirst_min": [ 1 ], "thirst_tick": [ -600 ], "pain_max_val": [ 10 ], "hurt_chance": [ 200 ], "stamina_min": [ -1 ] } + "scaling_mods": { + "thirst_tick": [ -50 ], + "thirst_chance": [ -1 ], + "perspiration_min": [ 5 ], + "perspiration_tick": [ -15 ], + "pain_max_val": [ 10 ], + "hurt_chance": [ 200 ], + "stamina_min": [ -1 ] + } }, { "type": "effect_type", @@ -1136,8 +1148,8 @@ "speed_name": "Heat slowdown", "max_intensity": 3, "part_descs": true, - "base_mods": { "speed_mod": [ -2 ] }, - "scaling_mods": { "speed_mod": [ -4 ] } + "base_mods": { "speed_mod": [ -1 ] }, + "scaling_mods": { "speed_mod": [ -2 ] } }, { "type": "effect_type", diff --git a/doc/EFFECTS_JSON.md b/doc/EFFECTS_JSON.md index 025d727918c84..19ba135fe44ac 100644 --- a/doc/EFFECTS_JSON.md +++ b/doc/EFFECTS_JSON.md @@ -412,6 +412,15 @@ Valid arguments: "thirst_chance_bot" "thirst_tick" - Defaults to every tick +"perspiration_amount" - Amount of perspiration it can give/take. +"perspiration_min" - Minimal amount of perspiration, certain effect will give/take +"perspiration_max" - if 0 or missing value will be exactly "perspiration_min" +"perspiration_min_val" - Defaults to 0, which means uncapped +"perspiration_max_val" - Defaults to 0, which means uncapped +"perspiration_chance" - Chance to perspire +"perspiration_chance_bot" +"perspiration_tick" - Defaults to every tick + "fatigue_amount" - Amount of fatigue it can give/take. After certain amount character will need to sleep. "fatigue_min" - Minimal amount of fatigue, certain effect will give/take "fatigue_max" - if 0 or missing value will be exactly "fatigue_min" diff --git a/src/character.cpp b/src/character.cpp index 81a5e83639c0f..24625e2e8c854 100644 --- a/src/character.cpp +++ b/src/character.cpp @@ -1942,71 +1942,83 @@ void Character::update_body_wetness( const w_point &weather ) { // Average number of turns to go from completely soaked to fully dry // assuming average temperature and humidity - constexpr time_duration average_drying = 2_hours; + constexpr time_duration average_drying = 30_minutes; - // A modifier on drying time - double delay = 1.0; - // Weather slows down drying - delay += ( ( weather.humidity - 66 ) - ( weather.temperature - 65 ) ) / 100; - delay = std::max( 0.1, delay ); // Fur/slime retains moisture + double trait_mult = 1.0; if( has_trait( trait_LIGHTFUR ) || has_trait( trait_FUR ) || has_trait( trait_FELINE_FUR ) || has_trait( trait_LUPINE_FUR ) || has_trait( trait_CHITIN_FUR ) || has_trait( trait_CHITIN_FUR2 ) || has_trait( trait_CHITIN_FUR3 ) ) { - delay = delay * 6 / 5; + trait_mult = 2.0; } if( has_trait( trait_URSINE_FUR ) || has_trait( trait_SLIMY ) ) { - delay *= 1.5; - } - - if( !x_in_y( 1, to_turns( average_drying * delay / 100.0 ) ) ) { - // No drying this turn - return; + trait_mult = 4.0; } - // Now per-body-part stuff - // To make drying uniform, make just one roll and reuse it - const int drying_roll = rng( 1, 80 ); + // Weather slows down drying + double weather_mult = 1.0; + weather_mult += ( ( weather.humidity - 66 ) - ( weather.temperature - 65 ) ) / 100; + weather_mult = std::max( 0.1, weather_mult ); for( const bodypart_id &bp : get_all_body_parts() ) { - if( get_part_wetness( bp ) == 0 ) { + const int wetness = get_part_wetness( bp ); + if( wetness == 0 ) { continue; } - // This is to normalize drying times - int drying_chance = get_part_drench_capacity( bp ); - const int temp_conv = get_part_temp_conv( bp ); + // Body temperature affects duration of wetness // Note: Using temp_conv rather than temp_cur, to better approximate environment + const int temp_conv = get_part_temp_conv( bp ); + double temp_mult = 1.0; if( temp_conv >= BODYTEMP_SCORCHING ) { - drying_chance *= 2; + temp_mult = 0.5; } else if( temp_conv >= BODYTEMP_VERY_HOT ) { - drying_chance = drying_chance * 3 / 2; + temp_mult = 0.67; } else if( temp_conv >= BODYTEMP_HOT ) { - drying_chance = drying_chance * 4 / 3; + temp_mult = 0.75 ; } else if( temp_conv > BODYTEMP_COLD ) { // Comfortable, doesn't need any changes } else { // Evaporation doesn't change that much at lower temp - drying_chance = drying_chance * 3 / 4; + temp_mult = 1.2; } - if( drying_chance < 1 ) { - drying_chance = 1; - } + // Make clothing slow down drying + double clothing_mult = 1.0; + for( const item &i : worn ) { + if( i.covers( bp ) ) { + const double item_coverage = static_cast( i.get_coverage( bp ) ) / 100; + const double item_breathability = static_cast( i.breathability() ) / 100; + + // breathability of naked skin + breathability of item + const double breathability = ( 1.0 - item_coverage ) + item_coverage * item_breathability; - // TODO: Make evaporation reduce body heat - if( drying_chance >= drying_roll ) { - mod_part_wetness( bp, -1 ); - if( get_part_wetness( bp ) < 0 ) { - set_part_wetness( bp, 0 ); + clothing_mult += 1.0 - breathability; } } + + const time_duration drying = average_drying * trait_mult * weather_mult * temp_mult * clothing_mult; + const double turns_to_dry = to_turns( drying ); + + const int drench_cap = get_part_drench_capacity( bp ); + const double dry_per_turn = static_cast( drench_cap ) / turns_to_dry; + mod_part_wetness( bp, roll_remainder( dry_per_turn ) * -1 ); + + // Make evaporation reduce body heat + if( !( bp->has_flag( "IGNORE_TEMP" ) ) ) { + const int temp_cur = get_part_temp_cur( bp ); + mod_part_temp_cur( bp, roll_remainder( static_cast( temp_cur ) / clothing_mult / 2000 ) * + -1 ); + } + // Safety measure to keep wetness within bounds + if( get_part_wetness( bp ) < 0 ) { + set_part_wetness( bp, 0 ); + } if( get_part_wetness( bp ) > get_part_drench_capacity( bp ) ) { set_part_wetness( bp, get_part_drench_capacity( bp ) ); } } - // TODO: Make clothing slow down drying } // This must be called when any of the following change: @@ -11906,6 +11918,19 @@ void Character::process_one_effect( effect &it, bool is_new ) } } + // Handle perspiration + val = get_effect( "PERSPIRATION", reduced ); + if( val != 0 ) { + mod = 1; + if( is_new || it.activated( calendar::turn, "PERSPIRATION", val, reduced, mod ) ) { + // multiplier to balance values aroud drench capacity of different body parts + int mult = get_part_drench_capacity( bp ) / 100; + mod_part_wetness( bp, bound_mod_to_vals( get_part_wetness( bp ), val * mult, + it.get_max_val( "PERSPIRATION", reduced ) * mult, + it.get_min_val( "PERSPIRATION", reduced ) * mult ) ); + } + } + // Handle fatigue val = get_effect( "FATIGUE", reduced ); // Prevent ongoing fatigue effects while asleep. diff --git a/src/effect.cpp b/src/effect.cpp index ea8baef799229..35bf7cd106f5f 100644 --- a/src/effect.cpp +++ b/src/effect.cpp @@ -353,6 +353,16 @@ bool effect_type::load_mod_data( const JsonObject &jo, const std::string &member extract_effect( j, mod_data, "thirst_chance_bot", member, "THIRST", "chance_bot" ); extract_effect( j, mod_data, "thirst_tick", member, "THIRST", "tick" ); + // Then thirst + extract_effect( j, mod_data, "perspiration_amount", member, "PERSPIRATION", "amount" ); + extract_effect( j, mod_data, "perspiration_min", member, "PERSPIRATION", "min" ); + extract_effect( j, mod_data, "perspiration_max", member, "PERSPIRATION", "max" ); + extract_effect( j, mod_data, "perspiration_min_val", member, "PERSPIRATION", "min_val" ); + extract_effect( j, mod_data, "perspiration_max_val", member, "PERSPIRATION", "max_val" ); + extract_effect( j, mod_data, "perspiration_chance", member, "PERSPIRATION", "chance_top" ); + extract_effect( j, mod_data, "perspiration_chance_bot", member, "PERSPIRATION", "chance_bot" ); + extract_effect( j, mod_data, "perspiration_tick", member, "PERSPIRATION", "tick" ); + // Then fatigue extract_effect( j, mod_data, "fatigue_amount", member, "FATIGUE", "amount" ); extract_effect( j, mod_data, "fatigue_min", member, "FATIGUE", "min" ); @@ -647,6 +657,9 @@ std::string effect::disp_desc( bool reduced ) const val = get_avg_mod( "THIRST", reduced ); values.push_back( desc_freq( get_percentage( "THIRST", val, reduced ), val, _( "thirst" ), _( "quench" ) ) ); + val = get_avg_mod( "PERSPIRATION", reduced ); + values.push_back( desc_freq( get_percentage( "PERSPIRATION", val, reduced ), val, + _( "perspiration" ), _( "dryness" ) ) ); val = get_avg_mod( "HUNGER", reduced ); values.push_back( desc_freq( get_percentage( "HUNGER", val, reduced ), val, _( "hunger" ), _( "sate" ) ) ); diff --git a/src/suffer.cpp b/src/suffer.cpp index f64171fda5b89..0f882dbfd6077 100644 --- a/src/suffer.cpp +++ b/src/suffer.cpp @@ -1905,7 +1905,7 @@ void Character::drench( int saturation, const body_part_set &flags, bool ignore_ const int wetness_max = std::min( source_wet_max, bp_wetness_max ); const int curr_wetness = get_part_wetness( bp ); if( curr_wetness < wetness_max ) { - set_part_wetness( bp, std::min( wetness_max, curr_wetness + wetness_increment ) ); + set_part_wetness( bp, std::min( wetness_max, curr_wetness + wetness_increment * 100 ) ); } } const int torso_wetness = get_part_wetness( bodypart_id( "torso" ) ); @@ -1942,7 +1942,7 @@ void Character::apply_wetness_morale( int temperature ) const body_part_set wet_friendliness = exclusive_flag_coverage( "WATER_FRIENDLY" ); for( const bodypart_id &bp : get_all_body_parts() ) { // Sum of body wetness can go up to 103 - const int part_drench = get_part_wetness( bp ); + const int part_drench = get_part_wetness( bp ) / 100; if( part_drench == 0 ) { continue; }