diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index 6e7a24cd9c3..95f2bc94d47 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -332,11 +332,46 @@ var/global/objects_thrown_when_explode = FALSE
..(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!
- to_chat(user, "It's stuck to your hands!")
+ if(user.is_holding_item(src))
+ if(reagents?.total_volume && isliving(user))
+ held_examine_temperature_message(user)
+ if(cant_drop != FALSE) //Item can't be dropped, and is either in left or right hand!
+ to_chat(user, "It's stuck to your hands!")
if(daemon && daemon.flags & DAEMON_EXAMINE)
daemon.examine(user)
+/obj/item/proc/held_examine_temperature_message(mob/living/examiner)
+ #define HEAT_LEVEL_SPAN 20
+ var/temperature_delta = (reagents.chem_temp - examiner.bodytemperature) * heat_conductivity ** (1/3) //Cubed root to skew it towards being perceptible.
+ if (ishuman(examiner))
+ var/mob/living/carbon/human/H = examiner
+ temperature_delta *= (H.gloves ? H.gloves.heat_conductivity ** (1/3) : 1)
+ var/safetemp_excursion = examiner.get_safe_temperature_excursion(examiner.bodytemperature + temperature_delta)
+ if (!examiner.feels_pain() || examiner.has_painkillers())
+ safetemp_excursion = 0
+ else if(safetemp_excursion > 0)
+ safetemp_excursion = min(ceil(safetemp_excursion / HEAT_LEVEL_SPAN), 3)
+ else if (safetemp_excursion < 0)
+ safetemp_excursion = max(round(safetemp_excursion / HEAT_LEVEL_SPAN), -3)
+ switch (safetemp_excursion)
+ if (0)
+ if (temperature_delta >= HEAT_LEVEL_SPAN)
+ to_chat(examiner, "It feels warm.")
+ else if(abs(temperature_delta) >= HEAT_LEVEL_SPAN)
+ to_chat(examiner, "It feels cool.")
+ if (1)
+ to_chat(examiner, "It feels very hot.")
+ if (-1)
+ to_chat(examiner, "It feels very cold.")
+ if (2)
+ to_chat(examiner, "It feels searing hot.")
+ if (-2)
+ to_chat(examiner, "It feels freezing cold.")
+ if (3)
+ to_chat(examiner, "It feels blisteringly hot.")
+ if (-3)
+ to_chat(examiner, "It feels piercingly cold.")
+ #undef HEAT_LEVEL_SPAN
/obj/item/attack_ai(mob/user as mob)
..()
diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm
index 40ff1f030ec..41f9868bfdd 100644
--- a/code/modules/mob/living/carbon/human/human_defense.dm
+++ b/code/modules/mob/living/carbon/human/human_defense.dm
@@ -593,4 +593,4 @@ emp_act
return PACID
/mob/living/carbon/human/beam_defense(var/obj/effect/beam/B)
- return is_wearing_item(/obj/item/clothing/suit/reticulatedvest) ? 0.4 : 1
\ No newline at end of file
+ return is_wearing_item(/obj/item/clothing/suit/reticulatedvest) ? 0.4 : 1
diff --git a/code/modules/mob/living/carbon/shock.dm b/code/modules/mob/living/carbon/shock.dm
index 944baaa3b3c..862782ee0cc 100644
--- a/code/modules/mob/living/carbon/shock.dm
+++ b/code/modules/mob/living/carbon/shock.dm
@@ -46,10 +46,9 @@
/mob/living/carbon/proc/handle_shock() //Currently only used for humans
update_pain_level()
-
-/mob/living/carbon/proc/total_painkillers()
+/mob/living/proc/total_painkillers()
for(var/datum/reagent/R in reagents.reagent_list)
. += R.pain_resistance
-/mob/living/carbon/proc/has_painkillers()
+/mob/living/proc/has_painkillers()
return total_painkillers() > 0
diff --git a/code/modules/mob/living/helper_procs.dm b/code/modules/mob/living/helper_procs.dm
index 0384504448c..6d91467285d 100644
--- a/code/modules/mob/living/helper_procs.dm
+++ b/code/modules/mob/living/helper_procs.dm
@@ -44,3 +44,33 @@ default behaviour is:
/mob/living/proc/isDeadorDying() //returns 1 if dead or in crit
if(stat == DEAD || health <= config.health_threshold_crit)
return TRUE
+
+/mob/living/proc/get_safe_temperature_excursion(the_temp)
+ //Returns how many degrees K a temperature is outside of the safe range the mob can tolerate. returns 0 if within the safe range. can be negative for cold.
+ return 0
+
+/mob/living/simple_animal/get_safe_temperature_excursion(the_temp)
+ if (the_temp > maxbodytemp)
+ return the_temp - maxbodytemp
+ else if (the_temp < minbodytemp)
+ return the_temp - minbodytemp
+ return 0
+
+/mob/living/carbon/monkey/get_safe_temperature_excursion(the_temp)
+ if (the_temp > BODYTEMP_HEAT_DAMAGE_LIMIT)
+ return the_temp - BODYTEMP_HEAT_DAMAGE_LIMIT
+ else if (the_temp < BODYTEMP_COLD_DAMAGE_LIMIT)
+ return the_temp - BODYTEMP_COLD_DAMAGE_LIMIT
+ return 0
+
+/mob/living/carbon/human/get_safe_temperature_excursion(the_temp)
+ if (species)
+ if (the_temp > species.heat_level_1)
+ return the_temp - species.heat_level_1
+ else if (the_temp < species.cold_level_1)
+ return the_temp - species.cold_level_1
+ else if (the_temp > BODYTEMP_HEAT_DAMAGE_LIMIT)
+ return the_temp - BODYTEMP_HEAT_DAMAGE_LIMIT
+ else if (the_temp < BODYTEMP_COLD_DAMAGE_LIMIT)
+ return the_temp - BODYTEMP_COLD_DAMAGE_LIMIT
+ return 0