From a25041431b610ebd12759b968fa8aa2fd0eb87b0 Mon Sep 17 00:00:00 2001 From: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Date: Wed, 25 Nov 2020 13:56:04 +0100 Subject: [PATCH] [MIRROR] Humans have more complicated body temperatures (#1825) * Humans have more complicated body temperatures (#54550) This changes how carbon/humans stabilize body temperature, and changes how damage and wounds are applied based on temperature. Humans now have a core body temperature along with body temperature. The core temperature is used for natural stabilization and what viruses like fever and shivers target by raising or lowing the core temperature of the mob. The standard body temperature still exists and acts exactly the same for most items at this time but is now treated as surface temperature in humans. Damage from body temperature for humans is now based on the core temperature instead of body temperature now. Humans will now receive burn wounds when the body (surface) temperature is to high for to long. This causes you to see alerts for the area temperature before you take damage in most cases improving visibility of dangerous situations. * Humans have more complicated body temperatures Co-authored-by: NightRed --- code/__DEFINES/atmospherics.dm | 8 +- code/__HELPERS/mobs.dm | 14 + .../datums/diseases/advance/symptoms/fever.dm | 7 +- .../diseases/advance/symptoms/shivering.dm | 7 +- code/datums/status_effects/buffs.dm | 3 + code/game/objects/items/devices/scanners.dm | 1 + .../clothing/spacesuits/_spacesuits.dm | 2 +- code/modules/mob/living/carbon/human/human.dm | 2 + .../mob/living/carbon/human/human_defines.dm | 6 + code/modules/mob/living/carbon/human/life.dm | 16 +- .../mob/living/carbon/human/species.dm | 336 ++++++++++++------ .../human/species_types/lizardpeople.dm | 2 +- .../carbon/human/species_types/zombies.dm | 2 +- code/modules/mob/living/carbon/life.dm | 2 +- .../projectile/special/temperature.dm | 15 +- .../reagents/cat2_medicine_reagents.dm | 10 +- .../chemistry/reagents/medicine_reagents.dm | 6 + .../reagents/pyrotechnic_reagents.dm | 6 + .../chemistry/reagents/toxin_reagents.dm | 3 + .../crossbreeding/_status_effects.dm | 8 +- .../spells/spell_types/construct_spells.dm | 3 + .../mecha/equipment/tools/medical_tools.dm | 7 +- 22 files changed, 322 insertions(+), 144 deletions(-) diff --git a/code/__DEFINES/atmospherics.dm b/code/__DEFINES/atmospherics.dm index 2a10b9ac37f..77d33fd004a 100644 --- a/code/__DEFINES/atmospherics.dm +++ b/code/__DEFINES/atmospherics.dm @@ -136,15 +136,15 @@ /// The natural temperature for a body #define BODYTEMP_NORMAL 310.15 /// This is the divisor which handles how much of the temperature difference between the current body temperature and 310.15K (optimal temperature) humans auto-regenerate each tick. The higher the number, the slower the recovery. This is applied each tick, so long as the mob is alive. -#define BODYTEMP_AUTORECOVERY_DIVISOR 11 +#define BODYTEMP_AUTORECOVERY_DIVISOR 14 /// Minimum amount of kelvin moved toward 310K per tick. So long as abs(310.15 - bodytemp) is more than 50. -#define BODYTEMP_AUTORECOVERY_MINIMUM 12 +#define BODYTEMP_AUTORECOVERY_MINIMUM 6 ///Similar to the BODYTEMP_AUTORECOVERY_DIVISOR, but this is the divisor which is applied at the stage that follows autorecovery. This is the divisor which comes into play when the human's loc temperature is lower than their body temperature. Make it lower to lose bodytemp faster. #define BODYTEMP_COLD_DIVISOR 15 /// Similar to the BODYTEMP_AUTORECOVERY_DIVISOR, but this is the divisor which is applied at the stage that follows autorecovery. This is the divisor which comes into play when the human's loc temperature is higher than their body temperature. Make it lower to gain bodytemp faster. #define BODYTEMP_HEAT_DIVISOR 15 /// The maximum number of degrees that your body can cool in 1 tick, due to the environment, when in a cold area. -#define BODYTEMP_COOLING_MAX -100 +#define BODYTEMP_COOLING_MAX -30 /// The maximum number of degrees that your body can heat up in 1 tick, due to the environment, when in a hot area. #define BODYTEMP_HEATING_MAX 30 /// The body temperature limit the human body can take before it starts taking damage from heat. @@ -155,6 +155,8 @@ /// This also affects how fast the body normalises it's temperature when cold. /// 270k is about -3c, that is below freezing and would hurt over time. #define BODYTEMP_COLD_DAMAGE_LIMIT (BODYTEMP_NORMAL - 40) +/// The body temperature limit the human body can take before it will take wound damage. +#define BODYTEMP_HEAT_WOUND_LIMIT (BODYTEMP_NORMAL + 90) // 400.5 k /// what min_cold_protection_temperature is set to for space-helmet quality headwear. MUST NOT BE 0. #define SPACE_HELM_MIN_TEMP_PROTECT 2.0 diff --git a/code/__HELPERS/mobs.dm b/code/__HELPERS/mobs.dm index af5963ae4c8..99a4fd02d69 100644 --- a/code/__HELPERS/mobs.dm +++ b/code/__HELPERS/mobs.dm @@ -612,4 +612,18 @@ GLOBAL_LIST_EMPTY(species_list) . = pick(ais) return . +/** + * Used to get the amount of change between two body temperatures + * + * When passed the difference between two temperatures returns the amount of change to temperature to apply. + * The change rate should be kept at a low value tween 0.16 and 0.02 for optimal results. + * vars: + * * temp_diff (required) The differance between two temperatures + * * change_rate (optional)(Default: 0.06) The rate of range multiplyer + */ +/proc/get_temp_change_amount(temp_diff, change_rate = 0.06) + if(temp_diff < 0) + return (log((temp_diff * -1) * change_rate + 1) * BODYTEMP_AUTORECOVERY_DIVISOR) * -1 + return log(temp_diff * change_rate + 1) * BODYTEMP_AUTORECOVERY_DIVISOR + #define ISADVANCEDTOOLUSER(mob) (HAS_TRAIT(mob, TRAIT_ADVANCEDTOOLUSER) && !HAS_TRAIT(mob, TRAIT_MONKEYLIKE)) diff --git a/code/datums/diseases/advance/symptoms/fever.dm b/code/datums/diseases/advance/symptoms/fever.dm index 2af943a474a..cf3c66f96b9 100644 --- a/code/datums/diseases/advance/symptoms/fever.dm +++ b/code/datums/diseases/advance/symptoms/fever.dm @@ -41,7 +41,6 @@ Bonus unsafe = TRUE if(A.properties["resistance"] >= 10) power = 2.5 - set_body_temp(A.affected_mob, A) /datum/symptom/fever/Activate(datum/disease/advance/A) if(!..()) @@ -51,6 +50,7 @@ Bonus to_chat(M, "[pick("You feel hot.", "You feel like you're burning.")]") else to_chat(M, "[pick("You feel too hot.", "You feel like your blood is boiling.")]") + set_body_temp(A.affected_mob, A) /** * set_body_temp Sets the body temp change @@ -61,7 +61,10 @@ Bonus * * datum/disease/advance/A The disease applying the symptom */ /datum/symptom/fever/proc/set_body_temp(mob/living/M, datum/disease/advance/A) - M.add_body_temperature_change("fever", (6 * power) * A.stage) + if(!unsafe) + M.add_body_temperature_change("fever", max((6 * power) * A.stage, (BODYTEMP_HEAT_DAMAGE_LIMIT - 1))) + else + M.add_body_temperature_change("fever", max((6 * power) * A.stage, (BODYTEMP_HEAT_DAMAGE_LIMIT + 20))) /// Update the body temp change based on the new stage /datum/symptom/fever/on_stage_change(datum/disease/advance/A) diff --git a/code/datums/diseases/advance/symptoms/shivering.dm b/code/datums/diseases/advance/symptoms/shivering.dm index d8216acada1..da8e213a57d 100644 --- a/code/datums/diseases/advance/symptoms/shivering.dm +++ b/code/datums/diseases/advance/symptoms/shivering.dm @@ -40,7 +40,6 @@ Bonus unsafe = TRUE if(A.properties["stage_rate"] >= 10) power = 2.5 - set_body_temp(A.affected_mob, A) /datum/symptom/shivering/Activate(datum/disease/advance/A) if(!..()) @@ -50,6 +49,7 @@ Bonus to_chat(M, "[pick("You feel cold.", "You shiver.")]") else to_chat(M, "[pick("You feel your blood run cold.", "You feel ice in your veins.", "You feel like you can't heat up.", "You shiver violently." )]") + set_body_temp(A.affected_mob, A) /** * set_body_temp Sets the body temp change @@ -60,7 +60,10 @@ Bonus * * datum/disease/advance/A The disease applying the symptom */ /datum/symptom/shivering/proc/set_body_temp(mob/living/M, datum/disease/advance/A) - M.add_body_temperature_change("shivering", -((6 * power) * A.stage)) + if(!unsafe) + M.add_body_temperature_change("shivering", max(-((6 * power) * A.stage), (BODYTEMP_COLD_DAMAGE_LIMIT + 1))) + else + M.add_body_temperature_change("shivering", max(-((6 * power) * A.stage), (BODYTEMP_COLD_DAMAGE_LIMIT - 20))) /// Update the body temp change based on the new stage /datum/symptom/shivering/on_stage_change(datum/disease/advance/A) diff --git a/code/datums/status_effects/buffs.dm b/code/datums/status_effects/buffs.dm index d41bf0980bd..fa530a00d63 100644 --- a/code/datums/status_effects/buffs.dm +++ b/code/datums/status_effects/buffs.dm @@ -344,6 +344,9 @@ owner.adjustFireLoss(-25) owner.remove_CC() owner.bodytemperature = owner.get_body_temp_normal() + if(istype(owner, /mob/living/carbon/human)) + var/mob/living/carbon/human/humi = owner + humi.coretemperature = humi.get_body_temp_normal() return TRUE /datum/status_effect/regenerative_core/on_remove() diff --git a/code/game/objects/items/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm index 037b07bcff7..fc190be1b67 100644 --- a/code/game/objects/items/devices/scanners.dm +++ b/code/game/objects/items/devices/scanners.dm @@ -356,6 +356,7 @@ GENE SCANNER || S.flying_species != initial(S.flying_species) render_list += "Species: [S.name][mutant ? "-derived mutant" : ""]\n" + render_list += "Core temperature: [round(H.coretemperature-T0C,0.1)] °C ([round(H.coretemperature*1.8-459.67,0.1)] °F)\n" render_list += "Body temperature: [round(M.bodytemperature-T0C,0.1)] °C ([round(M.bodytemperature*1.8-459.67,0.1)] °F)\n" // Time of death diff --git a/code/modules/clothing/spacesuits/_spacesuits.dm b/code/modules/clothing/spacesuits/_spacesuits.dm index 4a23747a7fa..e93837a34a9 100644 --- a/code/modules/clothing/spacesuits/_spacesuits.dm +++ b/code/modules/clothing/spacesuits/_spacesuits.dm @@ -97,7 +97,7 @@ // If we got here, it means thermals are on, the cell is in and the cell has // just had enough charge subtracted from it to power the thermal regulator - user.adjust_bodytemperature((temperature_setting - user.bodytemperature), use_steps=TRUE, capped=FALSE) + user.adjust_bodytemperature(get_temp_change_amount((temperature_setting - user.bodytemperature), 0.16)) update_hud_icon(user) // Clean up the cell on destroy diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index d7e374e73b1..240f48aaedc 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -905,6 +905,8 @@ for(var/datum/mutation/human/HM in dna.mutations) if(HM.quality != POSITIVE) dna.remove_mutation(HM.name) + coretemperature = get_body_temp_normal(apply_change=FALSE) + heat_exposure_stacks = 0 return ..() /mob/living/carbon/human/is_literate() diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm index 3c197bb32f5..32b1017186d 100644 --- a/code/modules/mob/living/carbon/human/human_defines.dm +++ b/code/modules/mob/living/carbon/human/human_defines.dm @@ -70,3 +70,9 @@ /// How many "units of blood" we have on our hands var/blood_in_hands = 0 + /// The core temperature of the human compaired to the skin temp of the body + var/coretemperature = BODYTEMP_NORMAL + + ///Exposure to damaging heat levels increases stacks, stacks clean over time when temperatures are lower. Stack is consumed to add a wound. + var/heat_exposure_stacks = 0 + diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm index 85f949bd20a..c8c97565f75 100644 --- a/code/modules/mob/living/carbon/human/life.dm +++ b/code/modules/mob/living/carbon/human/life.dm @@ -38,6 +38,9 @@ handle_heart() handle_liver() + //Body temperature stability and damage + dna.species.handle_body_temperature(src) + dna.species.spec_life(src) // for mutantraces else for(var/i in all_wounds) @@ -111,8 +114,17 @@ return dna.species.handle_environment(environment, src) - dna.species.handle_environment_pressure(environment, src) - dna.species.handle_body_temperature(src) + +/** + * Adjust the core temperature of a mob + * + * vars: + * * amount The amount of degrees to change body temperature by + * * min_temp (optional) The minimum body temperature after adjustment + * * max_temp (optional) The maximum body temperature after adjustment + */ +/mob/living/carbon/human/proc/adjust_coretemperature(amount, min_temp=0, max_temp=INFINITY) + coretemperature = clamp(coretemperature + amount, min_temp, max_temp) /** * get_body_temperature Returns the body temperature with any modifications applied diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm index ccc72c4d6d1..eb80611af0d 100644 --- a/code/modules/mob/living/carbon/human/species.dm +++ b/code/modules/mob/living/carbon/human/species.dm @@ -1614,87 +1614,244 @@ GLOBAL_LIST_EMPTY(roundstart_races) ////////////////////////// /** - * environment handler for species + * Environment handler for species * * vars: - * * environment The environment gas mix - * * H The mob we will stabilize + * * environment (required) The environment gas mix + * * humi (required)(type: /mob/living/carbon/human) The mob we will target */ -/datum/species/proc/handle_environment(datum/gas_mixture/environment, mob/living/carbon/human/H) - var/areatemp = H.get_temperature(environment) +/datum/species/proc/handle_environment(datum/gas_mixture/environment, mob/living/carbon/human/humi) + handle_environment_pressure(environment, humi) - if(H.stat != DEAD) // If you are dead your body does not stabilize naturally - natural_bodytemperature_stabilization(environment, H) +/** + * Body temperature handler for species + * + * These procs manage body temp, bamage, and alerts + * Some of these will still fire when not alive to balance body temp to the room temp. + * vars: + * * humi (required)(type: /mob/living/carbon/human) The mob we will target + */ +/datum/species/proc/handle_body_temperature(mob/living/carbon/human/humi) + //when in a cryo unit we suspend all natural body regulation + if(istype(humi.loc, /obj/machinery/atmospherics/components/unary/cryo_cell)) + return + //when dead the air still effects your skin temp + if(humi.stat == DEAD) + body_temperature_skin(humi) + else //when alive do all the things + body_temperature_core(humi) + body_temperature_skin(humi) + body_temperature_alerts(humi) + body_temperature_damage(humi) - if(!H.on_fire || areatemp > H.bodytemperature) // If we are not on fire or the area is hotter - H.adjust_bodytemperature((areatemp - H.bodytemperature), use_insulation=TRUE, use_steps=TRUE) +/** + * Used to stabilize the core temperature back to normal on living mobs + * + * The metabolisim heats up the core of the mob trying to keep it at the normal body temp + * vars: + * * humi (required) The mob we will stabilize + */ +/datum/species/proc/body_temperature_core(mob/living/carbon/human/humi) + var/natural_change = get_temp_change_amount(humi.get_body_temp_normal() - humi.coretemperature, 0.12) + humi.adjust_coretemperature(humi.metabolism_efficiency * natural_change) -/// Handle the body temperature status effects for the species -/// Traits for resitance to heat or cold are handled here. -/datum/species/proc/handle_body_temperature(mob/living/carbon/human/H) +/** + * Used to normalize the skin temperature on living mobs + * + * The core temp effects the skin, then the enviroment effects the skin, then we refect that back to the core. + * This happens even when dead so bodies revert to room temp over time. + * vars: + * * humi (required) The mob we will targeting + */ +/datum/species/proc/body_temperature_skin(mob/living/carbon/human/humi) + + // change the core based on the skin temp + var/skin_core_diff = humi.bodytemperature - humi.coretemperature + // change rate of 0.08 to be slightly below area to skin change rate and still have a solid curve + var/skin_core_change = get_temp_change_amount(skin_core_diff, 0.08) + + humi.adjust_coretemperature(skin_core_change) + + // get the enviroment details of where the mob is standing + var/datum/gas_mixture/environment = humi.loc.return_air() + if(!environment) // if there is no environment (nullspace) drop out here. + return + + // Get the temperature of the environment for area + var/area_temp = humi.get_temperature(environment) + + // Get the insulation value based on the area's temp + var/thermal_protection = humi.get_insulation_protection(area_temp) + + // Changes to the skin temperature based on the area + var/area_skin_diff = area_temp - humi.bodytemperature + if(!humi.on_fire || area_skin_diff > 0) + // change rate of 0.1 as area temp has large impact on the surface + var/area_skin_change = get_temp_change_amount(area_skin_diff, 0.1) + + // We need to apply the thermal protection of the clothing when applying area to surface change + // If the core bodytemp goes over the normal body temp you are overheating and becom sweaty + // This will cause the insulation value of any clothing to reduced in effect (70% normal rating) + // we add 10 degree over normal body temp before triggering as thick insulation raises body temp + if(humi.get_body_temp_normal(apply_change=FALSE) + 10 < humi.coretemperature) + // we are overheating and sweaty insulation is not as good reducing thermal protection + area_skin_change = (1 - (thermal_protection * 0.7)) * area_skin_change + else + area_skin_change = (1 - thermal_protection) * area_skin_change + + humi.adjust_bodytemperature(area_skin_change) + + // Core to skin temp transfer, when not on fire + if(!humi.on_fire) + // Get the changes to the skin from the core temp + var/core_skin_diff = humi.coretemperature - humi.bodytemperature + // change rate of 0.08 to reflect temp back in to the core at the same rate as core to skin + var/core_skin_change = (1 + thermal_protection) * get_temp_change_amount(core_skin_diff, 0.08) + + // We do not want to over shoot after using protection + if(core_skin_diff > 0) + core_skin_change = min(core_skin_change, core_skin_diff) + else + core_skin_change = max(core_skin_change, core_skin_diff) + + humi.adjust_bodytemperature(core_skin_change) + + +/** + * Used to set alerts and debuffs based on body temperature + * vars: + * * humi (required) The mob we will targeting + */ +/datum/species/proc/body_temperature_alerts(mob/living/carbon/human/humi) // Body temperature is too hot, and we do not have resist traits - if(H.bodytemperature > bodytemp_heat_damage_limit && !HAS_TRAIT(H, TRAIT_RESISTHEAT)) + if(humi.bodytemperature > bodytemp_heat_damage_limit && !HAS_TRAIT(humi, TRAIT_RESISTHEAT)) // Clear cold mood and apply hot mood - SEND_SIGNAL(H, COMSIG_CLEAR_MOOD_EVENT, "cold") - SEND_SIGNAL(H, COMSIG_ADD_MOOD_EVENT, "hot", /datum/mood_event/hot) + SEND_SIGNAL(humi, COMSIG_CLEAR_MOOD_EVENT, "cold") + SEND_SIGNAL(humi, COMSIG_ADD_MOOD_EVENT, "hot", /datum/mood_event/hot) //Remove any slowdown from the cold. - H.remove_movespeed_modifier(/datum/movespeed_modifier/cold) - - var/burn_damage = 0 - var/firemodifier = H.fire_stacks / 50 - if (!H.on_fire) // We are not on fire, reduce the modifier - firemodifier = min(firemodifier, 0) - - // this can go below 5 at log 2.5 - burn_damage = max(log(2 - firemodifier, (H.bodytemperature - H.get_body_temp_normal(apply_change=FALSE))) - 5,0) - - // Display alerts based on the amount of fire damage being taken - if (burn_damage) - switch(burn_damage) - if(0 to 2) - H.throw_alert("temp", /atom/movable/screen/alert/hot, 1) - if(2 to 4) - H.throw_alert("temp", /atom/movable/screen/alert/hot, 2) - else - H.throw_alert("temp", /atom/movable/screen/alert/hot, 3) - - // Apply species and physiology modifiers to heat damage - burn_damage = burn_damage * heatmod * H.physiology.heat_mod - - // 40% for level 3 damage on humans to scream in pain - if (H.stat < UNCONSCIOUS && (prob(burn_damage) * 10) / 4) - H.emote("scream") - - // Apply the damage to all body parts - H.apply_damage(burn_damage, BURN, spread_damage = TRUE) + humi.remove_movespeed_modifier(/datum/movespeed_modifier/cold) + // display alerts based on how hot it is + switch(humi.bodytemperature) + if(0 to 461) + humi.throw_alert("temp", /atom/movable/screen/alert/hot, 1) + if(460 to 700) + humi.throw_alert("temp", /atom/movable/screen/alert/hot, 2) + else + humi.throw_alert("temp", /atom/movable/screen/alert/hot, 3) // Body temperature is too cold, and we do not have resist traits - else if(H.bodytemperature < bodytemp_cold_damage_limit && !HAS_TRAIT(H, TRAIT_RESISTCOLD)) + else if(humi.bodytemperature < bodytemp_cold_damage_limit && !HAS_TRAIT(humi, TRAIT_RESISTCOLD)) // clear any hot moods and apply cold mood - SEND_SIGNAL(H, COMSIG_CLEAR_MOOD_EVENT, "hot") - SEND_SIGNAL(H, COMSIG_ADD_MOOD_EVENT, "cold", /datum/mood_event/cold) + SEND_SIGNAL(humi, COMSIG_CLEAR_MOOD_EVENT, "hot") + SEND_SIGNAL(humi, COMSIG_ADD_MOOD_EVENT, "cold", /datum/mood_event/cold) // Apply cold slow down - H.add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/cold, multiplicative_slowdown = ((bodytemp_cold_damage_limit - H.bodytemperature) / COLD_SLOWDOWN_FACTOR)) - // Display alerts based on the amount of cold damage being taken - // Apply more damage based on how cold you are - switch(H.bodytemperature) - if(200 to bodytemp_cold_damage_limit) - H.throw_alert("temp", /atom/movable/screen/alert/cold, 1) - H.apply_damage(COLD_DAMAGE_LEVEL_1 * coldmod * H.physiology.cold_mod, BURN) + humi.add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/cold, multiplicative_slowdown = ((bodytemp_cold_damage_limit - humi.bodytemperature) / COLD_SLOWDOWN_FACTOR)) + // Display alerts based how cold it is + switch(humi.bodytemperature) + if(201 to bodytemp_cold_damage_limit) + humi.throw_alert("temp", /atom/movable/screen/alert/cold, 1) if(120 to 200) - H.throw_alert("temp", /atom/movable/screen/alert/cold, 2) - H.apply_damage(COLD_DAMAGE_LEVEL_2 * coldmod * H.physiology.cold_mod, BURN) + humi.throw_alert("temp", /atom/movable/screen/alert/cold, 2) else - H.throw_alert("temp", /atom/movable/screen/alert/cold, 3) - H.apply_damage(COLD_DAMAGE_LEVEL_3 * coldmod * H.physiology.cold_mod, BURN) + humi.throw_alert("temp", /atom/movable/screen/alert/cold, 3) // We are not to hot or cold, remove status and moods else - H.clear_alert("temp") - H.remove_movespeed_modifier(/datum/movespeed_modifier/cold) - SEND_SIGNAL(H, COMSIG_CLEAR_MOOD_EVENT, "cold") - SEND_SIGNAL(H, COMSIG_CLEAR_MOOD_EVENT, "hot") + humi.clear_alert("temp") + humi.remove_movespeed_modifier(/datum/movespeed_modifier/cold) + SEND_SIGNAL(humi, COMSIG_CLEAR_MOOD_EVENT, "cold") + SEND_SIGNAL(humi, COMSIG_CLEAR_MOOD_EVENT, "hot") + +/** + * Used to apply wounds and damage based on core/body temp + * vars: + * * humi (required) The mob we will targeting + */ +/datum/species/proc/body_temperature_damage(mob/living/carbon/human/humi) + + //If the body temp is above the wound limit start adding exposure stacks + if(humi.bodytemperature > BODYTEMP_HEAT_WOUND_LIMIT) + humi.heat_exposure_stacks = min(humi.heat_exposure_stacks + 1, 40) + else //When below the wound limit, reduce the exposure stacks fast. + humi.heat_exposure_stacks = max(humi.heat_exposure_stacks - 4, 0) + + //when exposure stacks are greater then 10 + rand20 try to apply wounds and reset stacks + if(humi.heat_exposure_stacks > (10 + rand(0, 20))) + apply_burn_wounds(humi) + humi.heat_exposure_stacks = 0 + + // Body temperature is too hot, and we do not have resist traits + // Apply some burn damage to the body + if(humi.coretemperature > bodytemp_heat_damage_limit && !HAS_TRAIT(humi, TRAIT_RESISTHEAT)) + var/firemodifier = humi.fire_stacks / 50 + if (!humi.on_fire) // We are not on fire, reduce the modifier + firemodifier = min(firemodifier, 0) + + // this can go below 5 at log 2.5 + var/burn_damage = max(log(2 - firemodifier, (humi.coretemperature - humi.get_body_temp_normal(apply_change=FALSE))) - 5,0) + + // Apply species and physiology modifiers to heat damage + burn_damage = burn_damage * heatmod * humi.physiology.heat_mod + + // 40% for level 3 damage on humans to scream in pain + if (humi.stat < UNCONSCIOUS && (prob(burn_damage) * 10) / 4) + humi.emote("scream") + + // Apply the damage to all body parts + humi.apply_damage(burn_damage, BURN, spread_damage = TRUE) + + // Apply some burn damage to the body + if(humi.coretemperature < bodytemp_cold_damage_limit && !HAS_TRAIT(humi, TRAIT_RESISTCOLD)) + switch(humi.coretemperature) + if(201 to bodytemp_cold_damage_limit) + humi.apply_damage(COLD_DAMAGE_LEVEL_1 * coldmod * humi.physiology.cold_mod, BURN) + if(120 to 200) + humi.apply_damage(COLD_DAMAGE_LEVEL_2 * coldmod * humi.physiology.cold_mod, BURN) + else + humi.apply_damage(COLD_DAMAGE_LEVEL_3 * coldmod * humi.physiology.cold_mod, BURN) + +/** + * Used to apply burn wounds on random limbs + * + * This is called from body_temperature_damage when exposure to extream heat adds up and causes a wound. + * The wounds will increase in severity as the temperature increases. + * vars: + * * humi (required) The mob we will targeting + */ +/datum/species/proc/apply_burn_wounds(mob/living/carbon/human/humi) + // If we are resistant to heat exit + if(HAS_TRAIT(humi, TRAIT_RESISTHEAT)) + return + + // If our body temp is to low for a wound exit + if(humi.bodytemperature < BODYTEMP_HEAT_WOUND_LIMIT) + return + + // Lets pick a random body part and check for an existing burn + var/obj/item/bodypart/bodypart = pick(humi.bodyparts) + var/datum/wound/burn/existing_burn = locate(/datum/wound/burn) in bodypart.wounds + + // If we have an existing burn try to upgrade it + if(existing_burn) + switch(existing_burn.severity) + if(WOUND_SEVERITY_MODERATE) + if(humi.bodytemperature > BODYTEMP_HEAT_WOUND_LIMIT + 400) // 800k + bodypart.force_wound_upwards(/datum/wound/burn/severe) + if(WOUND_SEVERITY_SEVERE) + if(humi.bodytemperature > BODYTEMP_HEAT_WOUND_LIMIT + 2800) // 3200k + bodypart.force_wound_upwards(/datum/wound/burn/critical) + else // If we have no burn apply the lowest level burn + bodypart.force_wound_upwards(/datum/wound/burn/moderate) + + // always take some burn damage + var/burn_damage = HEAT_DAMAGE_LEVEL_1 + if(humi.bodytemperature > BODYTEMP_HEAT_WOUND_LIMIT + 400) + burn_damage = HEAT_DAMAGE_LEVEL_2 + if(humi.bodytemperature > BODYTEMP_HEAT_WOUND_LIMIT + 2800) + burn_damage = HEAT_DAMAGE_LEVEL_3 + + humi.apply_damage(burn_damage, BURN, bodypart) /// Handle the air pressure of the environment /datum/species/proc/handle_environment_pressure(datum/gas_mixture/environment, mob/living/carbon/human/H) @@ -1738,61 +1895,6 @@ GLOBAL_LIST_EMPTY(roundstart_races) H.adjustBruteLoss(LOW_PRESSURE_DAMAGE * H.physiology.pressure_mod) H.throw_alert("pressure", /atom/movable/screen/alert/lowpressure, 2) -/** - * Used to stabilize the body temperature back to normal on living mobs - * - * vars: - * * environment The environment gas mix - * * H The mob we will stabilize - */ -/datum/species/proc/natural_bodytemperature_stabilization(datum/gas_mixture/environment, mob/living/carbon/human/H) - var/areatemp = H.get_temperature(environment) - var/body_temp = H.bodytemperature // Get current body temperature - var/body_temperature_difference = H.get_body_temp_normal() - body_temp - var/natural_change = 0 - - // We are very cold, increate body temperature - if(body_temp <= bodytemp_cold_damage_limit) - natural_change = max((body_temperature_difference * H.metabolism_efficiency / BODYTEMP_AUTORECOVERY_DIVISOR), \ - bodytemp_autorecovery_min) - - // we are cold, reduce the minimum increment and do not jump over the difference - else if(body_temp > bodytemp_cold_damage_limit && body_temp < H.get_body_temp_normal()) - natural_change = max(body_temperature_difference * H.metabolism_efficiency / BODYTEMP_AUTORECOVERY_DIVISOR, \ - min(body_temperature_difference, bodytemp_autorecovery_min / 4)) - - // We are hot, reduce the minimum increment and do not jump below the difference - else if(body_temp > H.get_body_temp_normal() && body_temp <= bodytemp_heat_damage_limit) - natural_change = min(body_temperature_difference * H.metabolism_efficiency / BODYTEMP_AUTORECOVERY_DIVISOR, \ - max(body_temperature_difference, -(bodytemp_autorecovery_min / 4))) - - // We are very hot, reduce the body temperature - else if(body_temp >= bodytemp_heat_damage_limit) - natural_change = min((body_temperature_difference / BODYTEMP_AUTORECOVERY_DIVISOR), -bodytemp_autorecovery_min) - - var/thermal_protection = H.get_insulation_protection(body_temp + natural_change) - if(areatemp > body_temp) // It is hot here - if(body_temp < H.get_body_temp_normal()) - // Our bodytemp is below normal we are cold, insulation helps us retain body heat - // and will reduce the heat we lose to the environment - natural_change = (thermal_protection + 1) * natural_change - else - // Our bodytemp is above normal and sweating, insulation hinders out ability to reduce heat - // but will reduce the amount of heat we get from the environment - natural_change = (1 / (thermal_protection + 1)) * natural_change - else // It is cold here - if(!H.on_fire) // If on fire ignore ignore local temperature in cold areas - if(body_temp < H.get_body_temp_normal()) - // Our bodytemp is below normal, insulation helps us retain body heat - // and will reduce the heat we lose to the environment - natural_change = (thermal_protection + 1) * natural_change - else - // Our bodytemp is above normal and sweating, insulation hinders out ability to reduce heat - // but will reduce the amount of heat we get from the environment - natural_change = (1 / (thermal_protection + 1)) * natural_change - - // Apply the natural stabilization changes - H.adjust_bodytemperature(natural_change) ////////// // FIRE // diff --git a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm index 9360203fa84..ac3579cb3cb 100644 --- a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm @@ -33,7 +33,7 @@ ass_image = 'icons/ass/asslizard.png' /// Lizards are cold blooded and do not stabilize body temperature naturally -/datum/species/lizard/natural_bodytemperature_stabilization(datum/gas_mixture/environment, mob/living/carbon/human/H) +/datum/species/lizard/body_temperature_core(mob/living/carbon/human/humi) return /datum/species/lizard/random_name(gender,unique,lastname) diff --git a/code/modules/mob/living/carbon/human/species_types/zombies.dm b/code/modules/mob/living/carbon/human/species_types/zombies.dm index a156440dd86..e42864ec1c2 100644 --- a/code/modules/mob/living/carbon/human/species_types/zombies.dm +++ b/code/modules/mob/living/carbon/human/species_types/zombies.dm @@ -37,7 +37,7 @@ changesource_flags = MIRROR_BADMIN | WABBAJACK | ERT_SPAWN /// Zombies do not stabilize body temperature they are the walking dead and are cold blooded -/datum/species/zombie/natural_bodytemperature_stabilization(datum/gas_mixture/environment, mob/living/carbon/human/H) +/datum/species/zombie/body_temperature_core(mob/living/carbon/human/humi) return /datum/species/zombie/infectious/check_roundstart_eligible() diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm index 34a7fcf2a46..9d581f8eae5 100644 --- a/code/modules/mob/living/carbon/life.dm +++ b/code/modules/mob/living/carbon/life.dm @@ -701,7 +701,7 @@ All effects don't start immediately, but rather get worse over time; the rate is amount = (amount > 0) ? min(amount, BODYTEMP_HEATING_MAX) : max(amount, BODYTEMP_COOLING_MAX) if(bodytemperature >= min_temp && bodytemperature <= max_temp) - bodytemperature = clamp(bodytemperature + amount,min_temp,max_temp) + bodytemperature = clamp(bodytemperature + amount, min_temp, max_temp) /////////// diff --git a/code/modules/projectiles/projectile/special/temperature.dm b/code/modules/projectiles/projectile/special/temperature.dm index 8be7523d4b2..2ee245cc36b 100644 --- a/code/modules/projectiles/projectile/special/temperature.dm +++ b/code/modules/projectiles/projectile/special/temperature.dm @@ -11,21 +11,16 @@ . = ..() if(iscarbon(target)) var/mob/living/carbon/hit_mob = target - var/thermal_protection = 1 // The inverse of the amount of protection + var/thermal_protection = 1 - hit_mob.get_insulation_protection(hit_mob.bodytemperature + temperature) - if(temperature > 0) // The projectile is hot - thermal_protection -= hit_mob.get_heat_protection(hit_mob.bodytemperature + temperature) - else // The projectile was cold - thermal_protection -= hit_mob.get_cold_protection(hit_mob.bodytemperature + temperature) - - // The new body temperature is adjusted by 100-blocked % of the bullet's effect temperature + // The new body temperature is adjusted by the bullet's effect temperature // Reduce the amount of the effect temperature change based on the amount of insulation the mob is wearing - hit_mob.adjust_bodytemperature(((100 - blocked) / 100) * (thermal_protection * temperature)) + hit_mob.adjust_bodytemperature((thermal_protection * temperature) + temperature) else if(isliving(target)) var/mob/living/L = target - // the new body temperature is adjusted by 100-blocked % of the bullet's effect temperature - L.adjust_bodytemperature(((100 - blocked) / 100) * temperature) + // the new body temperature is adjusted by the bullet's effect temperature + L.adjust_bodytemperature((1 - blocked) * temperature) /obj/projectile/temp/hot name = "heat beam" diff --git a/code/modules/reagents/chemistry/reagents/cat2_medicine_reagents.dm b/code/modules/reagents/chemistry/reagents/cat2_medicine_reagents.dm index 24db8ceab05..62cec750952 100644 --- a/code/modules/reagents/chemistry/reagents/cat2_medicine_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/cat2_medicine_reagents.dm @@ -183,7 +183,10 @@ M.adjustFireLoss(-2*REM, FALSE) else M.adjustFireLoss(-1.25*REM, FALSE) - M.adjust_bodytemperature(rand(-25,-5)*(TEMPERATURE_DAMAGE_COEFFICIENT*REM), 50) + M.adjust_bodytemperature(rand(-25,-5) * (TEMPERATURE_DAMAGE_COEFFICIENT*REM), 50) + if(ishuman(M)) + var/mob/living/carbon/human/humi = M + humi.adjust_coretemperature(rand(-25,-5) * (TEMPERATURE_DAMAGE_COEFFICIENT*REM), 50) M.reagents?.chem_temp +=(-10*REM) M.adjust_fire_stacks(-1) ..() @@ -200,7 +203,10 @@ exposed_mob.extinguish_mob() /datum/reagent/medicine/c2/hercuri/overdose_process(mob/living/carbon/M) - M.adjust_bodytemperature(-10*TEMPERATURE_DAMAGE_COEFFICIENT*REM,50) //chilly chilly + M.adjust_bodytemperature(-10 * TEMPERATURE_DAMAGE_COEFFICIENT*REM,50) //chilly chilly + if(ishuman(M)) + var/mob/living/carbon/human/humi = M + humi.adjust_coretemperature(-10 * TEMPERATURE_DAMAGE_COEFFICIENT*REM,50) ..() diff --git a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm index 9f15efc0618..a9752477bad 100644 --- a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm @@ -26,6 +26,12 @@ M.adjust_bodytemperature(-40 * TEMPERATURE_DAMAGE_COEFFICIENT, M.get_body_temp_normal(apply_change=FALSE)) else if(M.bodytemperature < (M.get_body_temp_normal(apply_change=FALSE) + 1)) M.adjust_bodytemperature(40 * TEMPERATURE_DAMAGE_COEFFICIENT, 0, M.get_body_temp_normal(apply_change=FALSE)) + if(ishuman(M)) + var/mob/living/carbon/human/humi = M + if(humi.coretemperature > humi.get_body_temp_normal(apply_change=FALSE)) + humi.adjust_coretemperature(-40 * TEMPERATURE_DAMAGE_COEFFICIENT, humi.get_body_temp_normal(apply_change=FALSE)) + else if(humi.coretemperature < (humi.get_body_temp_normal(apply_change=FALSE) + 1)) + humi.adjust_coretemperature(40 * TEMPERATURE_DAMAGE_COEFFICIENT, 0, humi.get_body_temp_normal(apply_change=FALSE)) ..() /datum/reagent/medicine/adminordrazine //An OP chemical for admins diff --git a/code/modules/reagents/chemistry/reagents/pyrotechnic_reagents.dm b/code/modules/reagents/chemistry/reagents/pyrotechnic_reagents.dm index f466b8d837c..9bfbd954097 100644 --- a/code/modules/reagents/chemistry/reagents/pyrotechnic_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/pyrotechnic_reagents.dm @@ -214,6 +214,9 @@ if(M.reagents.has_reagent(/datum/reagent/oxygen)) M.reagents.remove_reagent(/datum/reagent/oxygen, 0.5) M.adjust_bodytemperature(-15) + if(ishuman(M)) + var/mob/living/carbon/human/humi = M + humi.adjust_coretemperature(-15) ..() /datum/reagent/cryostylane/expose_turf(turf/exposed_turf, reac_volume) @@ -235,6 +238,9 @@ if(holder.has_reagent(/datum/reagent/oxygen)) holder.remove_reagent(/datum/reagent/oxygen, 0.5) M.adjust_bodytemperature(15) + if(ishuman(M)) + var/mob/living/carbon/human/humi = M + humi.adjust_coretemperature(15) ..() /datum/reagent/teslium //Teslium. Causes periodic shocks, and makes shocks against the target much more effective. diff --git a/code/modules/reagents/chemistry/reagents/toxin_reagents.dm b/code/modules/reagents/chemistry/reagents/toxin_reagents.dm index d3407330a2e..91ca8b0821a 100644 --- a/code/modules/reagents/chemistry/reagents/toxin_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/toxin_reagents.dm @@ -116,6 +116,9 @@ holder.remove_reagent(/datum/reagent/medicine/epinephrine, 2*REM) M.adjustPlasma(20) M.adjust_bodytemperature(-7 * TEMPERATURE_DAMAGE_COEFFICIENT, M.get_body_temp_normal()) + if(ishuman(M)) + var/mob/living/carbon/human/humi = M + humi.adjust_coretemperature(-7 * TEMPERATURE_DAMAGE_COEFFICIENT, M.get_body_temp_normal()) return ..() /datum/reagent/toxin/lexorin diff --git a/code/modules/research/xenobiology/crossbreeding/_status_effects.dm b/code/modules/research/xenobiology/crossbreeding/_status_effects.dm index 41000f19f77..c5a2e0477b1 100644 --- a/code/modules/research/xenobiology/crossbreeding/_status_effects.dm +++ b/code/modules/research/xenobiology/crossbreeding/_status_effects.dm @@ -210,6 +210,9 @@ owner.adjustFireLoss(1) owner.Jitter(3) owner.adjust_bodytemperature(-10) + if(ishuman(owner)) + var/mob/living/carbon/human/humi = owner + humi.adjust_coretemperature(-10) /datum/status_effect/bonechill/on_remove() owner.remove_movespeed_modifier(/datum/movespeed_modifier/status_effect/bonechill) @@ -469,7 +472,10 @@ /datum/status_effect/stabilized/orange/tick() var/body_temperature_difference = owner.get_body_temp_normal(apply_change=FALSE) - owner.bodytemperature - owner.adjust_bodytemperature(min(5,body_temperature_difference)) + owner.adjust_bodytemperature(min(5, body_temperature_difference)) + if(ishuman(owner)) + var/mob/living/carbon/human/humi = owner + humi.adjust_coretemperature(min(5, humi.get_body_temp_normal(apply_change=FALSE) - humi.coretemperature)) return ..() /datum/status_effect/stabilized/purple diff --git a/code/modules/spells/spell_types/construct_spells.dm b/code/modules/spells/spell_types/construct_spells.dm index 05c6920d99f..7062334c272 100644 --- a/code/modules/spells/spell_types/construct_spells.dm +++ b/code/modules/spells/spell_types/construct_spells.dm @@ -211,6 +211,9 @@ user.playsound_local(get_turf(user), 'sound/effects/ghost2.ogg', 50, 1) target.become_blind(ABYSSAL_GAZE_BLIND) addtimer(CALLBACK(src, .proc/cure_blindness, target), 40) + if(ishuman(targets[1])) + var/mob/living/carbon/human/humi = targets[1] + humi.adjust_coretemperature(-200) target.adjust_bodytemperature(-200) /** diff --git a/code/modules/vehicles/mecha/equipment/tools/medical_tools.dm b/code/modules/vehicles/mecha/equipment/tools/medical_tools.dm index bbd2a030fc9..49fea9fdfb3 100644 --- a/code/modules/vehicles/mecha/equipment/tools/medical_tools.dm +++ b/code/modules/vehicles/mecha/equipment/tools/medical_tools.dm @@ -170,8 +170,13 @@ t1 = "*dead*" else t1 = "Unknown" + var/core_temp = "" + if(ishuman(patient)) + var/mob/living/carbon/human/humi = patient + core_temp = {"Body Temperature: [humi.bodytemperature-T0C]°C ([humi.bodytemperature*1.8-459.67]°F)
"} return {"Health: [patient.stat > 1 ? "[t1]" : "[patient.health]% ([t1])"]
- Core Temperature: [patient.bodytemperature-T0C]°C ([patient.bodytemperature*1.8-459.67]°F)
+ [core_temp] + Body Temperature: [patient.bodytemperature-T0C]°C ([patient.bodytemperature*1.8-459.67]°F)
Brute Damage: [patient.getBruteLoss()]%
Respiratory Damage: [patient.getOxyLoss()]%
Toxin Content: [patient.getToxLoss()]%