Skip to content

Commit

Permalink
[Semi-Experimental] The coldbloodening (#2684)
Browse files Browse the repository at this point in the history
  • Loading branch information
DeltaFire15 authored Sep 13, 2024
1 parent 7544d7c commit 5f1c555
Show file tree
Hide file tree
Showing 13 changed files with 215 additions and 22 deletions.
2 changes: 2 additions & 0 deletions code/__DEFINES/traits.dm
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,8 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
#define TRAIT_SOMMELIER "sommelier" // shows different booze power flavor texts
#define TRAIT_BARMASTER "bar_master" // always can identify reagents
#define TRAIT_HIVE_BURNT "hive-burnt"
///Prevents natural body temperature stabilization.
#define TRAIT_COLDBLOODED "cold_blooded" //NSV13 species trait.

// You can stare into the abyss, but it does not stare back.
// You're immune to the hallucination effect of the supermatter, either
Expand Down
3 changes: 2 additions & 1 deletion code/_globalvars/traits.dm
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,8 @@ GLOBAL_LIST_INIT(traits_by_type, list(
"TRAIT_NICE_SHOT" = TRAIT_NICE_SHOT,
"TRAIT_ALWAYS_STUBS" = TRAIT_ALWAYS_STUBS,
"TRAIT_NAIVE" = TRAIT_NAIVE,
"TRAIT_DROPS_ITEMS_ON_DEATH" = TRAIT_DROPS_ITEMS_ON_DEATH
"TRAIT_DROPS_ITEMS_ON_DEATH" = TRAIT_DROPS_ITEMS_ON_DEATH,
"TRAIT_COLDBLOODED" = TRAIT_COLDBLOODED//NSV13
),
/obj/item/bodypart = list(
"TRAIT_PARALYSIS" = TRAIT_PARALYSIS
Expand Down
4 changes: 2 additions & 2 deletions code/modules/mob/living/carbon/human/life.dm
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@
thermal_protection += THERMAL_PROTECTION_HAND_RIGHT


return min(1,thermal_protection)
return min(1,round(thermal_protection, 0.001)) //NSV13 - rounding because sure, lets split this into 11 values, decimal precision will NOT mess us up :)

//See proc/get_heat_protection_flags(temperature) for the description of this proc.
/mob/living/carbon/human/proc/get_cold_protection_flags(temperature)
Expand Down Expand Up @@ -302,7 +302,7 @@
if(thermal_protection_flags & HAND_RIGHT)
thermal_protection += THERMAL_PROTECTION_HAND_RIGHT

return min(1,thermal_protection)
return min(1,round(thermal_protection, 0.001)) //NSV13 - rounding because sure, lets split this into 11 values, decimal precision will NOT mess us up :)

/mob/living/carbon/human/handle_random_events()
//Puke if toxloss is too high
Expand Down
27 changes: 13 additions & 14 deletions code/modules/mob/living/carbon/human/species.dm
Original file line number Diff line number Diff line change
Expand Up @@ -1883,27 +1883,26 @@ GLOBAL_LIST_EMPTY(roundstart_races)

//Body temperature is adjusted in two parts: first there your body tries to naturally preserve homeostasis (shivering/sweating), then it reacts to the surrounding environment
//Thermal protection (insulation) has mixed benefits in two situations (hot in hot places, cold in hot places)
if(!H.on_fire) //If you're on fire, you do not heat up or cool down based on surrounding gases
var/natural = 0
if(H.stat != DEAD)
natural = H.natural_bodytemperature_stabilization()

//NSV13 - segment adjusted due to jank.
var/natural = 0
if(H.stat != DEAD)
natural = H.natural_bodytemperature_stabilization()
if(!H.on_fire && loc_temp < H.bodytemperature) //Place is colder than we are. But don't cool if we are on fire.
var/thermal_protection = 1
if(loc_temp < H.bodytemperature) //Place is colder than we are
thermal_protection -= H.get_cold_protection(loc_temp) //This returns a 0 - 1 value, which corresponds to the percentage of protection based on what you're wearing and what you're exposed to.
if(H.bodytemperature < BODYTEMP_NORMAL) //we're cold, insulation helps us retain body heat and will reduce the heat we lose to the environment
H.adjust_bodytemperature((thermal_protection+1)*natural + max(thermal_protection * (loc_temp - H.bodytemperature) / BODYTEMP_COLD_DIVISOR, BODYTEMP_COOLING_MAX))
else //we're sweating, insulation hinders our ability to reduce heat - and it will reduce the amount of cooling you get from the environment
H.adjust_bodytemperature(natural*(1/(thermal_protection+1)) + max((thermal_protection * (loc_temp - H.bodytemperature) + BODYTEMP_NORMAL - H.bodytemperature) / BODYTEMP_COLD_DIVISOR , BODYTEMP_COOLING_MAX)) //Extra calculation for hardsuits to bleed off heat
if (loc_temp > H.bodytemperature) //Place is hotter than we are
var/natural = 0
if(H.stat != DEAD)
natural = H.natural_bodytemperature_stabilization()
thermal_protection -= H.get_cold_protection(loc_temp) //This returns a 0 - 1 value, which corresponds to the percentage of protection based on what you're wearing and what you're exposed to.
if(H.bodytemperature < BODYTEMP_NORMAL) //we're cold, insulation helps us retain body heat and will reduce the heat we lose to the environment
H.adjust_bodytemperature((thermal_protection+1)*natural + max(thermal_protection * (loc_temp - H.bodytemperature) / BODYTEMP_COLD_DIVISOR, BODYTEMP_COOLING_MAX))
else //we're sweating, insulation hinders our ability to reduce heat - and it will reduce the amount of cooling you get from the environment
H.adjust_bodytemperature(natural*(1/(thermal_protection+1)) + max((thermal_protection * (loc_temp - H.bodytemperature) + BODYTEMP_NORMAL - H.bodytemperature) / BODYTEMP_COLD_DIVISOR , BODYTEMP_COOLING_MAX)) //Extra calculation for hardsuits to bleed off heat
else if(loc_temp > H.bodytemperature) //Place is hotter than we are
var/thermal_protection = 1
thermal_protection -= H.get_heat_protection(loc_temp) //This returns a 0 - 1 value, which corresponds to the percentage of protection based on what you're wearing and what you're exposed to.
if(H.bodytemperature < BODYTEMP_NORMAL) //and we're cold, insulation enhances our ability to retain body heat but reduces the heat we get from the environment
H.adjust_bodytemperature((thermal_protection+1)*natural + min(thermal_protection * (loc_temp - H.bodytemperature) / BODYTEMP_HEAT_DIVISOR, BODYTEMP_HEATING_MAX))
else //we're sweating, insulation hinders out ability to reduce heat - but will reduce the amount of heat we get from the environment
H.adjust_bodytemperature(natural*(1/(thermal_protection+1)) + min(thermal_protection * (loc_temp - H.bodytemperature) / BODYTEMP_HEAT_DIVISOR, BODYTEMP_HEATING_MAX))
//NSV13 end.

// +/- 50 degrees from 310K is the 'safe' zone, where no damage is dealt.
if(H.bodytemperature > BODYTEMP_HEAT_DAMAGE_LIMIT && !HAS_TRAIT(H, TRAIT_RESISTHEAT))
Expand Down
4 changes: 4 additions & 0 deletions code/modules/mob/living/carbon/life.dm
Original file line number Diff line number Diff line change
Expand Up @@ -547,6 +547,10 @@ GLOBAL_LIST_INIT(ballmer_windows_me_msg, list("Yo man, what if, we like, uh, put

//used in human and monkey handle_environment()
/mob/living/carbon/proc/natural_bodytemperature_stabilization()
//NSV13 - coldblooded beings do not naturally stabilize.
if(HAS_TRAIT(src, TRAIT_COLDBLOODED))
return 0
//NSV13 end.
var/body_temperature_difference = BODYTEMP_NORMAL - bodytemperature
switch(bodytemperature)
if(-INFINITY to BODYTEMP_COLD_DAMAGE_LIMIT) //Cold damage limit is 50 below the default, the temperature where you start to feel effects.
Expand Down
3 changes: 3 additions & 0 deletions code/modules/mob/living/life.dm
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@
var/datum/gas_mixture/environment = loc.return_air()
if(environment)
handle_environment(environment)
///NSV13 - aggressive grab temp exchange hook.
handle_temperature_exchange()
///NSV13 end.

//Handle gravity
var/gravity = has_gravity()
Expand Down
3 changes: 3 additions & 0 deletions nsv13.dme
Original file line number Diff line number Diff line change
Expand Up @@ -3933,13 +3933,16 @@
#include "nsv13\code\modules\mob\mob_helpers.dm"
#include "nsv13\code\modules\mob\dead\new_player\sprite_accessories.dm"
#include "nsv13\code\modules\mob\dead\observer\oberserver.dm"
#include "nsv13\code\modules\mob\living\nsv_life.dm"
#include "nsv13\code\modules\mob\living\carbon\carbon.dm"
#include "nsv13\code\modules\mob\living\carbon\examine_tgui.dm"
#include "nsv13\code\modules\mob\living\carbon\human\human.dm"
#include "nsv13\code\modules\mob\living\carbon\human\nsv_emotes.dm"
#include "nsv13\code\modules\mob\living\carbon\human\nsv_human_helpers.dm"
#include "nsv13\code\modules\mob\living\carbon\human\nsv_species.dm"
#include "nsv13\code\modules\mob\living\carbon\human\species_types\catgirl.dm"
#include "nsv13\code\modules\mob\living\carbon\human\species_types\nanotrasen_knpc.dm"
#include "nsv13\code\modules\mob\living\carbon\human\species_types\nsv_lizardpeople.dm"
#include "nsv13\code\modules\mob\living\carbon\human\species_types\other_knpc.dm"
#include "nsv13\code\modules\mob\living\carbon\human\species_types\spacepirate_knpc.dm"
#include "nsv13\code\modules\mob\living\carbon\human\species_types\syndicate_knpc.dm"
Expand Down
17 changes: 17 additions & 0 deletions nsv13/code/__DEFINES/atmospherics.dm
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,20 @@
#define ATMOS_GAS_MONITOR_OUTPUT_NUCLEIUM "nucleium_out"
#define ATMOS_GAS_MONITOR_SENSOR_NUCLEIUM "nucleium_sensor"
#define ATMOS_TANK_NUCLEIUM "nucleium=750;TEMP=293.15"

//Nerd stuff (coldblooded limited thermoregulation via e.g. muscle fibrillations)

#define LIZARD_ECTOTHERMISM_COLD_MAX_STACKS 10 //! Essentially the maximum life ticks thermogenesis will remain ready / active after the condition has passed.
#define LIZARD_THERMOGENESIS_COLD_TRIGGER_STACKS 5 //! At this many stacks we start using thermogenesis.

#define ECTOTHERM_THERMOGENESIS_MIN_COLDNESS 22 //! An ectotherm humanoid must be at least this many kelvin below the normal bodytemperature target define to actively thermoregulate.
#define ECTOTHERM_THERMOGENESIS_CRIT_COLDNESS 50 //! If this much temperature difference exists (relative to the basic standard temp), we are VERY cold and use a significant portion of energy just to vibrate.
#define ECTOTHERM_RECOVERY_DIVISOR 11 //! The base divisor for total heat difference that is tried to adjust for. For now just the base autorecovery divisor since it usually hits the min or max cap.
#define ECTOTHERM_MIN_RECOVERY 0.2 //! The minimum amount of heat (kelvins) generated by ectotherms if trying to recover. Should be very small
#define ECTOTHERM_MAX_RECOVERY 3 //! The maximum amount of heat (kelvins) generated per tick by ectotherms if trying to recover. Should be fairly small.
#define ECTOTHERM_CRIT_COLD_MAX_RECOVERY_MOD 2 //! Maximum temperature recovery is multiplied by this value if we are below the critical coldness threshold.

#define ECTOTHERM_THERMOGENESIS_NUTRITION_USE 0.2 //! Standard use for temp adjustment for ectotherms.
#define ECTOTHERM_MAJOR_THERMOGENESIS_NUTRITION_USE 1 //! This method of temperature regulation is inefficient, thus its nutrition drain increases disproportionately to the cap gained if very cold.

#define ECTOTHERM_NO_THERMOGENESIS_NEEDED -1 //! Return value if no thermoregulation was needed nor done.
18 changes: 13 additions & 5 deletions nsv13/code/datums/mood_events/nsv_events.dm
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/datum/mood_event/moth_drink_blood
description = "<span class='nicegreen'>That hit the spot!</span>\n"
mood_change = 10
timeout = 10 MINUTES
mood_change = 3
timeout = 7 MINUTES

/datum/mood_event/tailpull
description = "<span class='warning'>OUCH! Stop pulling my tail! It hurts!\n"
Expand Down Expand Up @@ -40,15 +40,23 @@

/datum/mood_event/drink_navy_coffee
description = "<span class='nicegreen'><b>THAT SHIT TASTED FUCKING DELICIOUS LET'S GO FUCK SOME SYNDICATE SHIPS UP, NAVY FOR LIFE WOOOOOO!!</b></span>\n"
mood_change = 10
timeout = 10 MINUTES
mood_change = 3
timeout = 7 MINUTES

/datum/mood_event/drink_navy_coffee/add_effects(list/faction)
if("Syndicate" in faction)
if(FACTION_SYNDICATE in faction)
description = "<span class='nicegreen'><b>THAT SHIT TASTED FUCKING DELICIOUS LET'S GO FUCK SOME NANOTRASEN SHIPS UP, NAVY FOR LIFE WOOOOOO!!</b></span>\n"


/datum/mood_event/cheers
description = "<span class='nicegreen'>Cheers! ¡Salud! Kanpai! Prost! Skål! Santé! Sláinte! Saúde!</span>\n"
mood_change = 3
timeout = 30 SECONDS

/datum/mood_event/lizard_shivers
description = "<span class='warning'>I'm shivering.. I need to find a spot where I can bask in the sun!</span>\n" //Evolved mental response, even if not entirely true here.
mood_change = -2

/datum/mood_event/comfy_lizard_temperature
description = "<span class='nicegreen'>I'm nice and warm! I missed this feeling..</span>\n" //These ships run at 20°C by default, which is.. not very nice for something coldblooded.
mood_change = 2 //This is really hard to hit and maintain so I felt like at least a +2 would be appropriate.
4 changes: 4 additions & 0 deletions nsv13/code/modules/mob/living/carbon/human/human.dm
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,7 @@
if(gravity <= 1) //This is fine.
return
return ..()

//OVERRIDE - Humans handle thermoregulation on species level.
/mob/living/carbon/human/natural_bodytemperature_stabilization()
return dna.species.natural_bodytemperature_stabilization(src)
39 changes: 39 additions & 0 deletions nsv13/code/modules/mob/living/carbon/human/nsv_species.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
//Modular File for NSV species stuff

///The species-level version of bodytemperature stabilization.
/datum/species/proc/natural_bodytemperature_stabilization(mob/living/carbon/human/human_holder)
if(HAS_TRAIT(human_holder, TRAIT_COLDBLOODED))
ectotherm_thermogenesis(human_holder) //Man I love the word "thermogenesis". Such a magic term for what is essentially just "makes heat".
return 0
var/body_temperature_difference = BODYTEMP_NORMAL - human_holder.bodytemperature
switch(human_holder.bodytemperature)
if(-INFINITY to BODYTEMP_COLD_DAMAGE_LIMIT) //Cold damage limit is 50 below the default, the temperature where you start to feel effects.
return max((body_temperature_difference * human_holder.metabolism_efficiency / BODYTEMP_AUTORECOVERY_DIVISOR), BODYTEMP_AUTORECOVERY_MINIMUM)
if(BODYTEMP_COLD_DAMAGE_LIMIT to BODYTEMP_NORMAL)
return max(body_temperature_difference * human_holder.metabolism_efficiency / BODYTEMP_AUTORECOVERY_DIVISOR, min(body_temperature_difference, BODYTEMP_AUTORECOVERY_MINIMUM/4))
if(BODYTEMP_NORMAL to BODYTEMP_HEAT_DAMAGE_LIMIT) // Heat damage limit is 50 above the default, the temperature where you start to feel effects.
return min(body_temperature_difference * human_holder.metabolism_efficiency / BODYTEMP_AUTORECOVERY_DIVISOR, max(body_temperature_difference, -BODYTEMP_AUTORECOVERY_MINIMUM/4))
if(BODYTEMP_HEAT_DAMAGE_LIMIT to INFINITY)
return min((body_temperature_difference / BODYTEMP_AUTORECOVERY_DIVISOR), -BODYTEMP_AUTORECOVERY_MINIMUM) //We're dealing with negative numbers

/**
* A proc for coldblooded species' means of limited thermal control. Also known as "vibrating your muscles".
* * Returns: Amount of kelvin adjustment performed, or ECTOTHERM_NO_THERMOGENESIS_NEEDED (-1) if we are fine.
**/
/datum/species/proc/ectotherm_thermogenesis(mob/living/carbon/human/human_holder, use_temp_diff_range_check = TRUE)
var/temperature_differential = BODYTEMP_NORMAL - human_holder.bodytemperature
if(temperature_differential <= 0 || (use_temp_diff_range_check && temperature_differential < ECTOTHERM_THERMOGENESIS_MIN_COLDNESS))
return ECTOTHERM_NO_THERMOGENESIS_NEEDED
var/adjustment = 0
if(temperature_differential < ECTOTHERM_THERMOGENESIS_CRIT_COLDNESS)
if(human_holder.nutrition < ECTOTHERM_THERMOGENESIS_NUTRITION_USE * human_holder.metabolism_efficiency)
return 0
adjustment = round(CLAMP(temperature_differential / ECTOTHERM_RECOVERY_DIVISOR * human_holder.metabolism_efficiency, ECTOTHERM_MIN_RECOVERY * human_holder.metabolism_efficiency, ECTOTHERM_MAX_RECOVERY * human_holder.metabolism_efficiency), 0.1)
human_holder.adjust_nutrition(-ECTOTHERM_THERMOGENESIS_NUTRITION_USE * human_holder.metabolism_efficiency)
else
if(human_holder.nutrition < ECTOTHERM_MAJOR_THERMOGENESIS_NUTRITION_USE * human_holder.metabolism_efficiency)
return 0
adjustment = round(CLAMP(temperature_differential / ECTOTHERM_RECOVERY_DIVISOR * human_holder.metabolism_efficiency, ECTOTHERM_MIN_RECOVERY * human_holder.metabolism_efficiency, ECTOTHERM_MAX_RECOVERY * human_holder.metabolism_efficiency * ECTOTHERM_CRIT_COLD_MAX_RECOVERY_MOD), 0.1)
human_holder.adjust_nutrition(-ECTOTHERM_MAJOR_THERMOGENESIS_NUTRITION_USE * human_holder.metabolism_efficiency)
human_holder.adjust_bodytemperature(adjustment)
return adjustment
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
//Modular NSV file for special stuff lizards have here.

//Modular type attachment.
/datum/species/lizard
coldmod = 1 // Lizards here have exchanged their inherent damage modifier for them being cold-blooded.
inherent_traits = list(TRAIT_COLDBLOODED) // The aforementioned coldbloodedness
///Controls whether lizards use their muscles to generate additional heat if very cold.
var/cold_stacks = 0
///Stores if we already sent them a message & adjusted stuff.
var/fibrillating = FALSE
///Used to store whether the signal to adjust mood due to good temperatures has been updated.
var/is_comfy = FALSE

//Another modular type attachment.
/datum/species/lizard/ashwalker
inherent_traits = list(TRAIT_NOGUNS,TRAIT_NOBREATH, TRAIT_COLDBLOODED) //Ashwalkers are also coldblooded [we have no lavaland so I don't have to worry about if lavaland always gens with survivable temps :) ]

/datum/species/lizard/ectotherm_thermogenesis(mob/living/carbon/human/human_holder, use_temp_diff_range_check = TRUE)
var/temp_diff = BODYTEMP_NORMAL - human_holder.bodytemperature
switch(temp_diff)
if(ECTOTHERM_THERMOGENESIS_CRIT_COLDNESS to INFINITY) //Being extremely cold quickly triggers thermogenesis.
cold_stacks = min(cold_stacks + 3, LIZARD_ECTOTHERMISM_COLD_MAX_STACKS)
if(ECTOTHERM_THERMOGENESIS_MIN_COLDNESS to ECTOTHERM_THERMOGENESIS_CRIT_COLDNESS)
cold_stacks = min(cold_stacks + 1, LIZARD_ECTOTHERMISM_COLD_MAX_STACKS) //Basic cold takes some time to respond to.
else
cold_stacks = max(cold_stacks - 1, 0) //Takes a while to calm down muscles.

if(cold_stacks < LIZARD_THERMOGENESIS_COLD_TRIGGER_STACKS && !fibrillating)
return ECTOTHERM_NO_THERMOGENESIS_NEEDED
if(!fibrillating) // !fibrillating reaching this point means enough stacks exist.
to_chat(human_holder, "<span class='warning'>You start shivering and feel the urge to find a sunny spot!</span>")
SEND_SIGNAL(human_holder, COMSIG_ADD_MOOD_EVENT, "lizard_shivers", /datum/mood_event/lizard_shivers)
fibrillating = TRUE
else if(cold_stacks == 0) //We also check if we have to stop vibrating here.
to_chat(human_holder, "<span class='notice'>You stop shivering.</span>")
SEND_SIGNAL(human_holder, COMSIG_CLEAR_MOOD_EVENT, "lizard_shivers")
fibrillating = FALSE
return ECTOTHERM_NO_THERMOGENESIS_NEEDED

return ..(human_holder, FALSE) //We already use some fancy logic for our thermoregulation triggering so we don't use the normal temp difference check save for if we would get hot.

//Modular proc attachment
/datum/species/lizard/on_species_loss(mob/living/carbon/human/C, datum/species/new_species, pref_load) //Human variable, named C. What did they mean by this?
SEND_SIGNAL(C, COMSIG_CLEAR_MOOD_EVENT, "lizard_shivers") //Safely remove if our species is changed.
SEND_SIGNAL(C, COMSIG_CLEAR_MOOD_EVENT, "comfy_liz_temp")
return ..()

//Lizards are most comfortable between 30 and 60°C. Good luck managing to stabilize at that temp, but hey if you manage to, you get a mood buff!
#define LIZARD_COMFY_TEMP_MIN 303.15
#define LIZARD_COMFY_TEMP_MAX 333.15 //From what I read some terran lizards have ~40-45°C as their upper targeted bounds, buut firstly these are space lizards, and secondly this is already hard enough to hit, so I extended it to 60°C.

/datum/species/lizard/spec_life(mob/living/carbon/human/H)
. = ..()
var/owner_bodytemperature = H.bodytemperature
if(owner_bodytemperature < LIZARD_COMFY_TEMP_MIN || owner_bodytemperature > LIZARD_COMFY_TEMP_MAX) //Should be low on processing since the first condition will catch almost all the time.
if(!is_comfy)
return
SEND_SIGNAL(H, COMSIG_CLEAR_MOOD_EVENT, "comfy_liz_temp")
is_comfy = FALSE
return
if(is_comfy)
return
SEND_SIGNAL(H, COMSIG_ADD_MOOD_EVENT, "comfy_liz_temp", /datum/mood_event/comfy_lizard_temperature)
is_comfy = TRUE

#undef LIZARD_COMFY_TEMP_MIN
#undef LIZARD_COMFY_TEMP_MAX
Loading

0 comments on commit 5f1c555

Please sign in to comment.