Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Semi-Experimental] The coldbloodening #2684

Merged
merged 10 commits into from
Sep 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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.
Bokkiewokkie marked this conversation as resolved.
Show resolved Hide resolved
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
Loading