mirror of
https://github.com/vgstation-coders/vgstation13.git
synced 2025-12-10 18:32:03 +00:00
Reagents added to a mob can heat up or cool down the mob (#33698)
* Some basic stuff. * Heating stuff. * Room temperature pills. * Attempt to fix unit test. * Fix order. * Fix fat calculation. * Plasmamen specific heat. * Comment change. * Slight, mostly comment changes. * Remove unnecessary check. * Feeling if reagents are hot or cold. Add electronic thermometer to chemistry locker. * Still feeling warm or cool but with painkillers. * More inheritance + defines for body thermal mass calculation. * Attempt to fix mouse runtime and possibly unit test. * Move into new file. * Change scaling, and reagent dispensers dispensing reagents at the ambient temperature.
This commit is contained in:
11
__DEFINES/mob_material_defines.dm
Normal file
11
__DEFINES/mob_material_defines.dm
Normal file
@@ -0,0 +1,11 @@
|
||||
//Mob-reagent thermal interactions
|
||||
#define MOB_HEAT_MULT 0.05 //Multiplier to mob thermal mass to scale how drinking hot or cold reagents impacts the mob's body temperature. Lower causes the thermal shift to be higher.
|
||||
#define SPECHEATCAP_HUMANBODY 2.98 //Specific heat capacity of the human body.
|
||||
#define SPECHEATCAP_MUSHROOM 3.935 //Specific heat of mushrooms.
|
||||
#define SPECHEATCAP_LEAF 4.2 //Dionaea
|
||||
#define SPECHEATCAP_BONE 1.313 //Cortical bone.
|
||||
#define SPECHEATCAP_PLASMA (200 / 405) //For plasmamen, values taken from XGM_gases.dm. It's gas phase there and solid here but should be okay.
|
||||
#define SPECHEATCAP_SLIME 1.24 //Same as slime jelly.
|
||||
#define SPECHEATCAP_ADAMANTINE 0.2 //For golems, around the same range as gold and silver.
|
||||
#define HUMANBODY_BONE_FRACTION 0.15 //Skellington and plasmaman mass multiplier to account for being mostly bones (or plasma bones).
|
||||
#define HUMANBODY_BLOOD_FRACTION 0.1 //Blood mass fraction of the human body.
|
||||
@@ -988,3 +988,13 @@ its easier to just keep the beam vertical.
|
||||
for(var/atom/location = A.loc, location, location = location.loc)
|
||||
if(location == src)
|
||||
return TRUE
|
||||
|
||||
/atom/proc/get_loc_temp(var/datum/gas_mixture/environment)
|
||||
var/loc_temp
|
||||
if(!environment)
|
||||
environment = loc.return_air()
|
||||
if(environment)
|
||||
loc_temp = environment.temperature
|
||||
else
|
||||
loc_temp = T0C + 20
|
||||
return loc_temp
|
||||
@@ -319,11 +319,65 @@
|
||||
..(user, size, show_name)
|
||||
if(price && price > 0)
|
||||
to_chat(user, "You read '[price] space bucks' on the tag.")
|
||||
if((cant_drop != FALSE) && user.is_holding_item(src)) //Item can't be dropped, and is either in left or right hand!
|
||||
if(user.is_holding_item(src))
|
||||
if(reagents.total_volume)
|
||||
//If the examiner is holding the item and can feel that the item contains hot or cold reagents, indicate that the item feels hot or cold.
|
||||
var/can_feel_temperature = FALSE
|
||||
var/nopain = FALSE
|
||||
if(isliving(user))
|
||||
can_feel_temperature = TRUE
|
||||
var/mob/living/L = user
|
||||
if(!L.feels_pain() || L.has_painkillers())
|
||||
nopain = TRUE
|
||||
//If we have something covering our hands, we can't feel the searing heat of the beverage we're about to enjoy.
|
||||
if(iscarbon(user))
|
||||
var/mob/living/carbon/C = user
|
||||
if(C.check_body_part_coverage(HANDS))
|
||||
can_feel_temperature = FALSE
|
||||
if(can_feel_temperature)
|
||||
var/held_item_temperature_message = held_item_temperature_message(user, nopain)
|
||||
if(held_item_temperature_message)
|
||||
to_chat(user, held_item_temperature_message)
|
||||
if(cant_drop != FALSE) //Item can't be dropped, and is either in left or right hand!
|
||||
to_chat(user, "<span class='danger'>It's stuck to your hands!</span>")
|
||||
if(daemon && daemon.flags & DAEMON_EXAMINE)
|
||||
daemon.examine(user)
|
||||
|
||||
/obj/item/proc/held_item_temperature_message(mob/living/L, nopain = FALSE)
|
||||
var/safetemp_excession_level = 0
|
||||
var/coldbound
|
||||
var/hotbound
|
||||
if(iscarbon(L))
|
||||
hotbound = BODYTEMP_HEAT_DAMAGE_LIMIT
|
||||
coldbound = BODYTEMP_COLD_DAMAGE_LIMIT
|
||||
else if(isanimal(L))
|
||||
var/mob/living/simple_animal/S = L
|
||||
coldbound = S.minbodytemp
|
||||
hotbound = S.maxbodytemp
|
||||
var/safetemp_excession = max(0, reagents.chem_temp - hotbound)
|
||||
if(!safetemp_excession)
|
||||
safetemp_excession = min(0, reagents.chem_temp - coldbound)
|
||||
safetemp_excession_level = round(min(3, abs(safetemp_excession) / 50)) * (safetemp_excession > 0 ? 1 : -1)
|
||||
if(safetemp_excession_level && !nopain)
|
||||
switch(safetemp_excession_level)
|
||||
if(-3)
|
||||
return "<span class='warning'>It feels piercingly cold.</span>"
|
||||
if(-2)
|
||||
return "<span class='warning'>It feels freezing cold.</span>"
|
||||
if(-1)
|
||||
return "<span class='warning'>It feels very cold.</span>"
|
||||
if(1)
|
||||
return "<span class='warning'>It feels very hot.</span>"
|
||||
if(2)
|
||||
return "<span class='warning'>It feels searing hot.</span>"
|
||||
if(3)
|
||||
return "<span class='warning'>It feels blisteringly hot.</span>"
|
||||
else
|
||||
var/temperature_difference = reagents.chem_temp - L.bodytemperature
|
||||
if(temperature_difference >= 20)
|
||||
return "<span class='notice'>It feels warm.</span>"
|
||||
else if(temperature_difference <= -20)
|
||||
return "<span class='notice'>It feels cool.</span>"
|
||||
|
||||
/obj/item/attack_ai(mob/user as mob)
|
||||
..()
|
||||
|
||||
@@ -168,7 +168,8 @@
|
||||
/obj/item/weapon/storage/fancy/vials,
|
||||
/obj/item/weapon/storage/box/pillbottles = 2,
|
||||
/obj/item/weapon/book/manual/chemistry_manual,
|
||||
/obj/item/weapon/reagent_containers/glass/jar/erlenmeyer = 2
|
||||
/obj/item/weapon/reagent_containers/glass/jar/erlenmeyer = 2,
|
||||
/obj/item/weapon/thermometer/electronic
|
||||
)
|
||||
|
||||
/obj/structure/closet/secure_closet/medical_wall
|
||||
|
||||
@@ -136,7 +136,7 @@ emp_act
|
||||
return protection
|
||||
|
||||
|
||||
/mob/living/carbon/human/proc/check_body_part_coverage(var/body_part_flags=0, var/obj/item/ignored)
|
||||
/mob/living/carbon/proc/check_body_part_coverage(var/body_part_flags=0, var/obj/item/ignored)
|
||||
if(!body_part_flags)
|
||||
return 0
|
||||
var/parts_to_check = body_part_flags
|
||||
|
||||
@@ -39,6 +39,8 @@
|
||||
|
||||
survival_gear = /obj/item/weapon/storage/box/survival/plasmaman
|
||||
|
||||
body_specheatcap = SPECHEATCAP_PLASMA
|
||||
|
||||
/datum/species/plasmaman/New()
|
||||
..()
|
||||
speech_filter = new /datum/speech_filter/unathi
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
/mob/living/carbon/proc/handle_shock() //Currently only used for humans
|
||||
update_pain_level()
|
||||
|
||||
/mob/living/carbon/proc/has_painkillers()
|
||||
/mob/living/proc/has_painkillers()
|
||||
if(reagents.has_reagent(PARACETAMOL))
|
||||
return TRUE
|
||||
if(reagents.has_reagent(TRAMADOL))
|
||||
|
||||
@@ -155,6 +155,8 @@ var/global/list/playable_species = list("Human")
|
||||
|
||||
var/datum/speech_filter/speech_filter
|
||||
|
||||
var/body_specheatcap = SPECHEATCAP_HUMANBODY
|
||||
|
||||
/datum/species/New()
|
||||
..()
|
||||
if(all_species[name])
|
||||
@@ -446,6 +448,8 @@ var/global/list/playable_species = list("Human")
|
||||
You can not eat normally, as your necrotic state only permits you to only eat raw flesh. As you lack skin, you can not be injected via syringe.<br>\
|
||||
You are also incredibly weak to brute damage, but you're fast and don't need to breathe, so that's going for you."
|
||||
|
||||
body_specheatcap = SPECHEATCAP_BONE
|
||||
|
||||
/datum/species/skellington/conditional_playable()
|
||||
var/MM = text2num(time2text(world.timeofday, "MM"))
|
||||
return MM == 10 //October
|
||||
@@ -902,6 +906,8 @@ var/global/list/playable_species = list("Human")
|
||||
"eyes" = /datum/organ/internal/eyes
|
||||
)
|
||||
|
||||
body_specheatcap = SPECHEATCAP_LEAF
|
||||
|
||||
/datum/species/diona/gib(mob/living/carbon/human/H)
|
||||
..()
|
||||
H.default_gib()
|
||||
@@ -953,6 +959,8 @@ var/global/list/playable_species = list("Human")
|
||||
"brain" = /datum/organ/internal/brain,
|
||||
)
|
||||
|
||||
body_specheatcap = SPECHEATCAP_ADAMANTINE
|
||||
|
||||
/datum/species/golem/makeName()
|
||||
return capitalize(pick(golem_names))
|
||||
|
||||
@@ -1117,6 +1125,8 @@ var/list/has_died_as_golem = list()
|
||||
"brain" = /datum/organ/internal/brain/slime_core,
|
||||
)
|
||||
|
||||
body_specheatcap = SPECHEATCAP_SLIME
|
||||
|
||||
/datum/species/slime/handle_death(var/mob/living/carbon/human/H) //Handles any species-specific death events (such as dionaea nymph spawns).
|
||||
H.dropBorers()
|
||||
for(var/atom/movable/I in H.contents)
|
||||
@@ -1329,6 +1339,9 @@ var/list/has_died_as_golem = list()
|
||||
You have a resistance to burn and toxin, but you are vulnerable to brute attacks.<br>\
|
||||
You are adept at seeing in the dark, moreso with your light inversion ability. When you speak, it will only go to the target chosen with your Fungal Telepathy.<br>\
|
||||
You also have access to the Sporemind, which allows you to communicate with others on the Sporemind through :~"
|
||||
|
||||
body_specheatcap = SPECHEATCAP_MUSHROOM
|
||||
|
||||
var/mob/living/telepathic_target[] = list()
|
||||
|
||||
/datum/species/mushroom/makeName()
|
||||
|
||||
@@ -1938,3 +1938,42 @@ Thanks.
|
||||
if(B.host_brain.ckey)
|
||||
to_chat(src, "<span class='danger'>You send a punishing spike of psychic agony lancing into your host's brain.</span>")
|
||||
to_chat(B.host_brain, "<span class='danger'><FONT size=3>Horrific, burning agony lances through you, ripping a soundless scream from your trapped mind!</FONT></span>")
|
||||
|
||||
//Returns the thermal mass of the mob's body, excluding reagents but including blood.
|
||||
/mob/living/proc/body_thermal_mass()
|
||||
|
||||
//Start with the mass of the body.
|
||||
var/body_thermal_mass = bodymass()
|
||||
|
||||
if(ishuman(src))
|
||||
|
||||
//First, get the non-blood thermal mass of the body.
|
||||
var/mob/living/carbon/human/H = src
|
||||
if(M_FAT in H.mutations)
|
||||
body_thermal_mass *= 1.5
|
||||
body_thermal_mass *= (1 - HUMANBODY_BLOOD_FRACTION) //First, only consider the non-blood fraction of the body mass.
|
||||
//Turn the body mass into thermal mass by multiplying by specific heat.
|
||||
if(H.species)
|
||||
body_thermal_mass *= H.species.body_specheatcap
|
||||
else
|
||||
body_thermal_mass *= SPECHEATCAP_HUMANBODY //Value does include blood, but it shouldn't be too much of a difference.
|
||||
|
||||
//Add blood thermal mass component
|
||||
body_thermal_mass += H.vessel.get_thermal_mass()
|
||||
|
||||
else
|
||||
|
||||
//Turn the body mass into thermal mass by multiplying by specific heat of the human body (generalization).
|
||||
body_thermal_mass *= SPECHEATCAP_HUMANBODY
|
||||
|
||||
return body_thermal_mass * MOB_HEAT_MULT
|
||||
|
||||
//Returns the thermal mass of the mob's body, including reagents.
|
||||
/mob/living/proc/total_thermal_mass()
|
||||
return body_thermal_mass() + reagents.get_thermal_mass()
|
||||
|
||||
/mob/living/proc/bodymass()
|
||||
var/mult = 1
|
||||
if(isskellington(src) || isskelevox(src) || isplasmaman(src))
|
||||
mult *= HUMANBODY_BONE_FRACTION
|
||||
return mult * ((size * 13.737) ** 3) //Approximately 70kg for a non-obese human.
|
||||
@@ -126,7 +126,7 @@
|
||||
/mob/living/proc/get_cold_protection(var/thermal_protection_flags)
|
||||
return 0
|
||||
|
||||
/mob/living/proc/get_loc_temp(var/datum/gas_mixture/environment)
|
||||
/mob/living/get_loc_temp(var/datum/gas_mixture/environment)
|
||||
if(!environment)
|
||||
environment = loc.return_air()
|
||||
var/loc_temp = T0C
|
||||
|
||||
@@ -64,7 +64,6 @@ var/const/INGEST = 2
|
||||
//now we no longer break because we didn't add all the reagents to reaction_ids - we want to add the reaction to everything in
|
||||
//reaction_ids, which will be over everything in the first reagent in the table
|
||||
|
||||
|
||||
/datum/reagents/proc/remove_any(var/amount=1)
|
||||
var/total_transfered = 0
|
||||
var/current_list_element = 1
|
||||
@@ -358,9 +357,22 @@ trans_to_atmos(var/datum/gas_mixture/target, var/amount=1, var/multiplier=1, var
|
||||
return total_transfered
|
||||
*/
|
||||
|
||||
/datum/reagents/proc/equalize_temperature_with_mob(var/mob/living/M)
|
||||
if(!M)
|
||||
return
|
||||
if(M.bodytemperature == chem_temp)
|
||||
return
|
||||
var/new_equalized_temperature = get_equalized_temperature(M.bodytemperature, M.body_thermal_mass(), chem_temp, get_thermal_mass())
|
||||
chem_temp = new_equalized_temperature
|
||||
M.bodytemperature = new_equalized_temperature
|
||||
M.reagents.chem_temp = new_equalized_temperature
|
||||
if(ishuman(M))
|
||||
var/mob/living/carbon/human/H = M
|
||||
H.vessel.chem_temp = new_equalized_temperature
|
||||
|
||||
/datum/reagents/proc/metabolize(var/mob/living/M, var/alien)
|
||||
if(M && chem_temp != M.bodytemperature)
|
||||
chem_temp = M.bodytemperature
|
||||
if(M)
|
||||
equalize_temperature_with_mob(M)
|
||||
handle_reactions()
|
||||
for(var/A in reagent_list)
|
||||
var/datum/reagent/R = A
|
||||
@@ -606,6 +618,16 @@ trans_to_atmos(var/datum/gas_mixture/target, var/amount=1, var/multiplier=1, var
|
||||
for(var/datum/reagent/R in reagent_list)
|
||||
R.reaction_dropper_obj(A, R.volume+volume_modifier)
|
||||
|
||||
/datum/reagents/proc/get_equalized_temperature(temperature_A, thermalmass_A, temperature_B, thermalmass_B)
|
||||
//Gets the equalized temperature of two thermal masses
|
||||
if(temperature_A == temperature_B)
|
||||
return temperature_A
|
||||
if(thermalmass_A + thermalmass_B)
|
||||
return ((temperature_A * thermalmass_A) + (temperature_B * thermalmass_B)) / (thermalmass_A + thermalmass_B)
|
||||
else
|
||||
warning("[usr] tried to equalize the temperature of a thermally-massless mixture.")
|
||||
return T0C+20 //Sanity but this shouldn't happen.
|
||||
|
||||
/datum/reagents/proc/add_reagent(var/reagent, var/amount, var/list/data=null, var/reagtemp = T0C+20)
|
||||
if(!my_atom)
|
||||
return 0
|
||||
@@ -616,10 +638,14 @@ trans_to_atmos(var/datum/gas_mixture/target, var/amount=1, var/multiplier=1, var
|
||||
update_total()
|
||||
if(total_volume + amount > maximum_volume)
|
||||
amount = (maximum_volume - total_volume) //Doesnt fit in. Make it disappear. Shouldn't happen. Will happen.
|
||||
chem_temp = round(((amount * reagtemp) + (total_volume * chem_temp)) / (total_volume + amount)) //equalize with new chems
|
||||
for (var/datum/reagent/R in reagent_list)
|
||||
if (R.id == reagent)
|
||||
|
||||
//Equalize temperatures
|
||||
chem_temp = get_equalized_temperature(chem_temp, get_thermal_mass(), reagtemp, amount * R.density * R.specheatcap)
|
||||
|
||||
R.volume += amount
|
||||
|
||||
update_total()
|
||||
my_atom.on_reagent_change()
|
||||
|
||||
@@ -641,6 +667,10 @@ trans_to_atmos(var/datum/gas_mixture/target, var/amount=1, var/multiplier=1, var
|
||||
if(D)
|
||||
|
||||
var/datum/reagent/R = new D.type()
|
||||
|
||||
//Equalize temperatures
|
||||
chem_temp = get_equalized_temperature(chem_temp, get_thermal_mass(), reagtemp, amount * R.density * R.specheatcap)
|
||||
|
||||
reagent_list += R
|
||||
R.holder = src
|
||||
R.volume = amount
|
||||
@@ -901,26 +931,19 @@ trans_to_atmos(var/datum/gas_mixture/target, var/amount=1, var/multiplier=1, var
|
||||
/datum/reagents/proc/is_full()
|
||||
return total_volume >= maximum_volume
|
||||
|
||||
/datum/reagents/proc/get_heatcapacity()
|
||||
var/heat_capacity = 0
|
||||
|
||||
if(reagent_list.len)
|
||||
for(var/datum/reagent/R in reagent_list)
|
||||
heat_capacity += R.volume*R.specheatcap
|
||||
|
||||
return heat_capacity
|
||||
|
||||
/datum/reagents/proc/get_overall_mass()
|
||||
//M = DV
|
||||
|
||||
var/overall_mass = 0
|
||||
|
||||
if(reagent_list.len)
|
||||
for(var/datum/reagent/R in reagent_list)
|
||||
overall_mass += R.density*R.volume
|
||||
|
||||
return overall_mass
|
||||
|
||||
/datum/reagents/proc/get_thermal_mass()
|
||||
var/total_thermal_mass = 0
|
||||
for(var/datum/reagent/R in reagent_list)
|
||||
total_thermal_mass += R.volume * R.density * R.specheatcap
|
||||
return total_thermal_mass * 10 //multiply by 10 because 1 u = 10 mL
|
||||
|
||||
/datum/reagents/proc/heating(var/power_transfer, var/received_temperature)
|
||||
/*
|
||||
Q/mc = deltaT
|
||||
@@ -931,10 +954,8 @@ trans_to_atmos(var/datum/gas_mixture/target, var/amount=1, var/multiplier=1, var
|
||||
*/
|
||||
if(received_temperature == chem_temp || !total_volume || !reagent_list.len)
|
||||
return
|
||||
var/heat_capacity = get_heatcapacity()
|
||||
var/energy = power_transfer
|
||||
var/mass = get_overall_mass()
|
||||
var/temp_change = (energy / (mass * heat_capacity))* HEAT_TRANSFER_MULTIPLIER
|
||||
var/temp_change = (energy / (get_thermal_mass())) * HEAT_TRANSFER_MULTIPLIER
|
||||
if(power_transfer > 0)
|
||||
chem_temp = min(chem_temp + temp_change, received_temperature)
|
||||
else
|
||||
|
||||
@@ -297,7 +297,7 @@ USE THIS CHEMISTRY DISPENSER FOR MAPS SO THEY START AT 100 ENERGY
|
||||
B = null
|
||||
return
|
||||
var/space = R.maximum_volume - R.total_volume
|
||||
var/reagent_temperature = dispensable_reagents[reagent] ? dispensable_reagents[reagent] : T0C+20
|
||||
var/reagent_temperature = get_loc_temp()
|
||||
R.add_reagent(reagent, min(amount, energy * 10, space), reagtemp = reagent_temperature)
|
||||
energy = max(energy - min(amount, energy * 10, space) / 10, 0)
|
||||
|
||||
|
||||
@@ -422,6 +422,9 @@ var/global/list/pillIcon2Name = list("oblong purple-pink", "oblong green-white",
|
||||
|
||||
var/logged_message = " - [key_name(usr)] has made [count] pill[count > 1 ? "s, each" : ""] named '[name]' and containing "
|
||||
|
||||
//Bring the pills to room temperature, due to contact with the pilling machinery.
|
||||
var/pill_temperature = get_loc_temp()
|
||||
|
||||
while(count--)
|
||||
if(amount_per_pill == 0 || reagents.total_volume == 0)
|
||||
break
|
||||
@@ -434,6 +437,8 @@ var/global/list/pillIcon2Name = list("oblong purple-pink", "oblong green-white",
|
||||
P.pixel_y = rand(-7, 7) * PIXEL_MULTIPLIER
|
||||
P.icon_state = "pill"+pillsprite
|
||||
reagents.trans_to(P,amount_per_pill)
|
||||
//Avoid scalding hot pills
|
||||
P.reagents.chem_temp = pill_temperature
|
||||
if(src.loaded_pill_bottle)
|
||||
if(loaded_pill_bottle.contents.len < loaded_pill_bottle.storage_slots)
|
||||
P.forceMove(loaded_pill_bottle)
|
||||
|
||||
@@ -47,6 +47,7 @@
|
||||
#include "__DEFINES\materials.dm"
|
||||
#include "__DEFINES\math_physics.dm"
|
||||
#include "__DEFINES\MC.dm"
|
||||
#include "__DEFINES\mob_material_defines.dm"
|
||||
#include "__DEFINES\mobs.dm"
|
||||
#include "__DEFINES\nanoui.dm"
|
||||
#include "__DEFINES\obj_defines.dm"
|
||||
|
||||
Reference in New Issue
Block a user