Moves disfiguration to be handled by the head instead of the mob itself (#94948)

## About The Pull Request
TRAIT_DISFIGURED and physical disfiguration are now handled by the head
bodypart rather than being on the mob itself. This is mostly for
internal purposes, but it does mean that:
- Players can now perform plastic surgery on torn off heads.
- Disfigured mobs' heads keep their face hidden, and when attached to a
different body won't magically get repaired and vice versa, attaching a
new head to a disfigured corpse no longer disfigures it.
- Robotic (and other non-huskable) heads no longer become disfigured
from husking
- Also in the rare case of grafting a head torn off from a husk onto
another body, they no longer permanently turn into an Unknown. (lol)

## Why It's Good For The Game

Saner code, we generally want limb-specific behaviors to be on limbs
themselves and not on the mob. Also yeah that one weird edge case.
~~Husks are next on the chopping block~~

## Changelog
🆑
qol: Plastic surgery can now be done on detached heads.
refactor: Refactored how disfiguration is handled to be stored on head's
side
fix: Robotic (and other non-huskable) heads no longer become disfigured
from husking
fix: Attaching a head from a husk to a different body no longer
permanently turns them into an Unknown.
/🆑
This commit is contained in:
SmArtKar
2026-01-28 20:25:25 +00:00
committed by GitHub
parent c88b9a2554
commit 8e63bdd337
18 changed files with 177 additions and 126 deletions
@@ -159,7 +159,9 @@
for(var/i in affected_mob.all_wounds)
var/datum/wound/iter_wound = i
iter_wound.on_xadone(0.5 * power * metabolization_ratio * seconds_per_tick)
REMOVE_TRAIT(affected_mob, TRAIT_DISFIGURED, TRAIT_GENERIC) //fixes common causes for disfiguration
var/obj/item/bodypart/head = affected_mob.get_bodypart(BODY_ZONE_HEAD)
if (head)
REMOVE_TRAIT(head, TRAIT_DISFIGURED, TRAIT_GENERIC) //fixes common causes for disfiguration
if(need_mob_update)
return UPDATE_MOB_HEALTH
@@ -178,29 +180,32 @@
/datum/reagent/medicine/pyroxadone/on_mob_life(mob/living/carbon/affected_mob, seconds_per_tick, metabolization_ratio)
. = ..()
if(affected_mob.bodytemperature > BODYTEMP_HEAT_DAMAGE_LIMIT)
var/power = 0
switch(affected_mob.bodytemperature)
if(BODYTEMP_HEAT_DAMAGE_LIMIT to 400)
power = 2
if(400 to 460)
power = 3
else
power = 5
if(affected_mob.on_fire)
power *= 2
if(affected_mob.bodytemperature <= BODYTEMP_HEAT_DAMAGE_LIMIT)
return
var/power = 0
switch(affected_mob.bodytemperature)
if(BODYTEMP_HEAT_DAMAGE_LIMIT to 400)
power = 2
if(400 to 460)
power = 3
else
power = 5
if(affected_mob.on_fire)
power *= 2
var/need_mob_update
need_mob_update = affected_mob.adjust_oxy_loss(-1 * power * metabolization_ratio * seconds_per_tick, updating_health = FALSE, required_biotype = affected_biotype, required_respiration_type = affected_respiration_type)
need_mob_update += affected_mob.adjust_brute_loss(-0.5 * power * metabolization_ratio * seconds_per_tick, updating_health = FALSE, required_bodytype = affected_bodytype)
need_mob_update += affected_mob.adjust_fire_loss(-0.75 * power * metabolization_ratio * seconds_per_tick, updating_health = FALSE, required_bodytype = affected_bodytype)
need_mob_update += affected_mob.adjust_tox_loss(-0.5 * power * metabolization_ratio * seconds_per_tick, updating_health = FALSE, forced = TRUE, required_biotype = affected_biotype)
if(need_mob_update)
. = UPDATE_MOB_HEALTH
for(var/i in affected_mob.all_wounds)
var/datum/wound/iter_wound = i
iter_wound.on_xadone(0.5 * power * metabolization_ratio * seconds_per_tick)
REMOVE_TRAIT(affected_mob, TRAIT_DISFIGURED, TRAIT_GENERIC)
var/need_mob_update
need_mob_update = affected_mob.adjust_oxy_loss(-1 * power * metabolization_ratio * seconds_per_tick, updating_health = FALSE, required_biotype = affected_biotype, required_respiration_type = affected_respiration_type)
need_mob_update += affected_mob.adjust_brute_loss(-0.5 * power * metabolization_ratio * seconds_per_tick, updating_health = FALSE, required_bodytype = affected_bodytype)
need_mob_update += affected_mob.adjust_fire_loss(-0.75 * power * metabolization_ratio * seconds_per_tick, updating_health = FALSE, required_bodytype = affected_bodytype)
need_mob_update += affected_mob.adjust_tox_loss(-0.5 * power * metabolization_ratio * seconds_per_tick, updating_health = FALSE, forced = TRUE, required_biotype = affected_biotype)
if(need_mob_update)
. = UPDATE_MOB_HEALTH
for(var/i in affected_mob.all_wounds)
var/datum/wound/iter_wound = i
iter_wound.on_xadone(0.5 * power * metabolization_ratio * seconds_per_tick)
var/obj/item/bodypart/head = affected_mob.get_bodypart(BODY_ZONE_HEAD)
if (head)
REMOVE_TRAIT(head, TRAIT_DISFIGURED, TRAIT_GENERIC)
/datum/reagent/medicine/rezadone
name = "Rezadone"
@@ -223,7 +228,9 @@
required_bodytype = affected_biotype
))
. = UPDATE_MOB_HEALTH
REMOVE_TRAIT(affected_mob, TRAIT_DISFIGURED, TRAIT_GENERIC)
var/obj/item/bodypart/head = affected_mob.get_bodypart(BODY_ZONE_HEAD)
if (head)
REMOVE_TRAIT(head, TRAIT_DISFIGURED, TRAIT_GENERIC)
/datum/reagent/medicine/rezadone/overdose_process(mob/living/affected_mob, seconds_per_tick, metabolization_ratio)
. = ..()