From 85c030b3e282d57a5d819613be91ca09fb9a2b0b Mon Sep 17 00:00:00 2001 From: _0Steven <42909981+00-Steven@users.noreply.github.com> Date: Thu, 4 Apr 2024 04:35:37 +0200 Subject: [PATCH] Fix all nighter runtimes (#82405) ## About The Pull Request So, recently, someone asked me why their All Nighter eyebags weren't working, and though after a short conversation we worked out it was working as intended and they had just taken a few naps to train fitness, I still checked the round logs once they were public. https://scrubby.melonmesa.com/round/226476/runtimes ![image](https://github.com/tgstation/tgstation/assets/42909981/162d76ae-2d43-428b-bc7e-37371ba27a1c) Coincidentally! Someone else _did_ have an All Nighter runtime! Well. Time to fix it. I look into the code, and lo and behold, it seems we're really just not caring about whether the head actually exists. https://github.com/tgstation/tgstation/blob/d38f9385b863e49f83455a227764d302629e2867/code/datums/quirks/negative_quirks/all_nighter.dm#L50-L56 But that reminds me. We have more ways to lose your head, like H.A.R.S.... So... I boot the game, and... Oh no. _Oh no._ That's a _lot_ of runtimes huh. (See "Why It's Good For The Game") Soooo we just add a check for whether our head-in-question actually exists to both adding and removing our bags, and be done with it. ```dm ///adds the bag overlay /datum/quirk/all_nighter/proc/add_bags() var/mob/living/carbon/human/sleepy_head = quirk_holder var/obj/item/bodypart/head/face = sleepy_head?.get_bodypart(BODY_ZONE_HEAD) if(isnull(face)) return bodypart_overlay = new() //creates our overlay face.add_bodypart_overlay(bodypart_overlay) sleepy_head.update_body_parts() //make sure to update icon ///removes the bag overlay /datum/quirk/all_nighter/proc/remove_bags() var/mob/living/carbon/human/sleepy_head = quirk_holder var/obj/item/bodypart/head/face = sleepy_head?.get_bodypart(BODY_ZONE_HEAD) if(face) //our overlay is stored as a datum var, so referencing it is easy face.remove_bodypart_overlay(bodypart_overlay) sleepy_head.update_body_parts() QDEL_NULL(bodypart_overlay) ``` Right? Well, no. Yes, this stops the runtimes, but while testing this I also noticed that the bags don't come back. We lose our head, we regenerate a new one, and we don't have bags. Even though we removed our head, we never actually removed _our bags_. So our `bodypart_overlay` is never set to null, and it's never actually attempting to apply them to our new head. To resolve this, we then just add a new proc called on `COMSIG_CARBON_REMOVE_LIMB`, which handles removing the eyebags before we remove our head if needed. ```dm ///if we have bags and lost a head, remove them /datum/quirk/all_nighter/proc/on_removed_limb(datum/source, obj/item/bodypart/removed_limb, special, dismembered) if(bodypart_overlay && istype(removed_limb, /obj/item/bodypart/head)) remove_bags() ``` Oh, we also remove the unused `client/client_source` argument from both the `add_bags(...)` and `remove_bags(...)` procs. ## Why It's Good For The Game ![image](https://github.com/tgstation/tgstation/assets/42909981/31fd97b5-dce3-46ec-9388-abf568fe4f0b) ## Changelog :cl: fix: All Nighter: fixed a runtime from not having a head, whether from hars/deletion/somesuch. fix: All Nighter: losing and regaining your head while you had eyebags no longer removes your eyebags until you've slept. /:cl: --- .../quirks/negative_quirks/all_nighter.dm | 26 +++++++++++++------ 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/code/datums/quirks/negative_quirks/all_nighter.dm b/code/datums/quirks/negative_quirks/all_nighter.dm index 0062537fde8..7f9f051ecf7 100644 --- a/code/datums/quirks/negative_quirks/all_nighter.dm +++ b/code/datums/quirks/negative_quirks/all_nighter.dm @@ -30,30 +30,40 @@ ///adds the corresponding moodlet and visual effects /datum/quirk/all_nighter/add(client/client_source) + RegisterSignal(quirk_holder, COMSIG_CARBON_REMOVE_LIMB, PROC_REF(on_removed_limb)) quirk_holder.add_mood_event("all_nighter", /datum/mood_event/all_nighter) add_bags() ///removes the corresponding moodlet and visual effects /datum/quirk/all_nighter/remove(client/client_source) + UnregisterSignal(quirk_holder, COMSIG_CARBON_REMOVE_LIMB) quirk_holder.clear_mood_event("all_nighter", /datum/mood_event/all_nighter) - remove_bags() + if(bodypart_overlay) + remove_bags() + +///if we have bags and lost a head, remove them +/datum/quirk/all_nighter/proc/on_removed_limb(datum/source, obj/item/bodypart/removed_limb, special, dismembered) + if(bodypart_overlay && istype(removed_limb, /obj/item/bodypart/head)) + remove_bags() ///adds the bag overlay -/datum/quirk/all_nighter/proc/add_bags(client/client_source) +/datum/quirk/all_nighter/proc/add_bags() var/mob/living/carbon/human/sleepy_head = quirk_holder - var/obj/item/bodypart/head/face = sleepy_head.get_bodypart(BODY_ZONE_HEAD) + var/obj/item/bodypart/head/face = sleepy_head?.get_bodypart(BODY_ZONE_HEAD) + if(isnull(face)) + return bodypart_overlay = new() //creates our overlay face.add_bodypart_overlay(bodypart_overlay) sleepy_head.update_body_parts() //make sure to update icon ///removes the bag overlay -/datum/quirk/all_nighter/proc/remove_bags(client/client_source) +/datum/quirk/all_nighter/proc/remove_bags() var/mob/living/carbon/human/sleepy_head = quirk_holder - var/obj/item/bodypart/head/face = sleepy_head.get_bodypart(BODY_ZONE_HEAD) - //our overlay is stored as a datum var, so referencing it is easy - face.remove_bodypart_overlay(bodypart_overlay) + var/obj/item/bodypart/head/face = sleepy_head?.get_bodypart(BODY_ZONE_HEAD) + if(face) + face.remove_bodypart_overlay(bodypart_overlay) + sleepy_head.update_body_parts() QDEL_NULL(bodypart_overlay) - sleepy_head.update_body_parts() /** *Here we actively handle our moodlet & eye bags, adding/removing them as necessary