From 1f897ac44ee4e47b189972436e7bbf97d5458720 Mon Sep 17 00:00:00 2001 From: MrMelbert <51863163+MrMelbert@users.noreply.github.com> Date: Wed, 1 Mar 2023 01:11:52 -0600 Subject: [PATCH] Fixes an issue with nightmare revival, Unit tests some fully heal stuff (#73612) ## About The Pull Request - Same issue as Ethereals. Owner was `null`ed because the heart was recreated. I opted for a more permanent solution, that being introducing a new flag to avoid recreating organs. - Adds some unit tests for fully heal stuff to make sure it works. ## Why It's Good For The Game More cases of revival working as expected ## Changelog :cl: Melbert fix: Nightmare revival acts less funky - stops it from re-creating the Light Eater. /:cl: --------- Co-authored-by: san7890 --- code/__DEFINES/mobs.dm | 26 ++++---- .../antagonists/nightmare/nightmare_organs.dm | 2 +- code/modules/mob/living/carbon/carbon.dm | 4 +- .../mob/living/carbon/human/species.dm | 2 +- .../chemistry/reagents/medicine_reagents.dm | 4 +- code/modules/surgery/organs/_organ.dm | 13 ++-- code/modules/surgery/organs/heart.dm | 2 +- code/modules/unit_tests/_unit_tests.dm | 1 + code/modules/unit_tests/full_heal.dm | 60 +++++++++++++++++++ 9 files changed, 90 insertions(+), 24 deletions(-) create mode 100644 code/modules/unit_tests/full_heal.dm diff --git a/code/__DEFINES/mobs.dm b/code/__DEFINES/mobs.dm index 52aff1df475..a44f161ac52 100644 --- a/code/__DEFINES/mobs.dm +++ b/code/__DEFINES/mobs.dm @@ -828,33 +828,35 @@ GLOBAL_LIST_INIT(layers_to_offset, list( #define HEAL_STAM (1<<6) /// Restore all limbs to their initial state. #define HEAL_LIMBS (1<<7) -/// Heals all organs from failing. If done as a part of an admin heal, will instead restore all organs to their initial state. +/// Heals all organs from failing. #define HEAL_ORGANS (1<<8) +/// A "super" heal organs, this refreshes all organs entirely, deleting old and replacing them with new. +#define HEAL_REFRESH_ORGANS (1<<9) /// Removes all wounds. -#define HEAL_WOUNDS (1<<9) +#define HEAL_WOUNDS (1<<10) /// Removes all brain traumas, not including permanent ones. -#define HEAL_TRAUMAS (1<<10) +#define HEAL_TRAUMAS (1<<11) /// Removes all reagents present. -#define HEAL_ALL_REAGENTS (1<<11) +#define HEAL_ALL_REAGENTS (1<<12) /// Removes all non-positive diseases. -#define HEAL_NEGATIVE_DISEASES (1<<12) +#define HEAL_NEGATIVE_DISEASES (1<<13) /// Restores body temperature back to nominal. -#define HEAL_TEMP (1<<13) +#define HEAL_TEMP (1<<14) /// Restores blood levels to normal. -#define HEAL_BLOOD (1<<14) +#define HEAL_BLOOD (1<<15) /// Removes all non-positive mutations (neutral included). -#define HEAL_NEGATIVE_MUTATIONS (1<<15) +#define HEAL_NEGATIVE_MUTATIONS (1<<16) /// Removes status effects with this flag set that also have remove_on_fullheal = TRUE. -#define HEAL_STATUS (1<<16) +#define HEAL_STATUS (1<<17) /// Same as above, removes all CC related status effects with this flag set that also have remove_on_fullheal = TRUE. -#define HEAL_CC_STATUS (1<<17) +#define HEAL_CC_STATUS (1<<18) /// Deletes any restraints on the mob (handcuffs / legcuffs) -#define HEAL_RESTRAINTS (1<<18) +#define HEAL_RESTRAINTS (1<<19) /// Combination flag to only heal the main damage types. #define HEAL_DAMAGE (HEAL_BRUTE|HEAL_BURN|HEAL_TOX|HEAL_OXY|HEAL_CLONE|HEAL_STAM) /// Combination flag to only heal things messed up things about the mob's body itself. -#define HEAL_BODY (HEAL_LIMBS|HEAL_ORGANS|HEAL_WOUNDS|HEAL_TRAUMAS|HEAL_BLOOD|HEAL_TEMP) +#define HEAL_BODY (HEAL_LIMBS|HEAL_ORGANS|HEAL_REFRESH_ORGANS|HEAL_WOUNDS|HEAL_TRAUMAS|HEAL_BLOOD|HEAL_TEMP) /// Combination flag to heal negative things affecting the mob. #define HEAL_AFFLICTIONS (HEAL_NEGATIVE_DISEASES|HEAL_NEGATIVE_MUTATIONS|HEAL_ALL_REAGENTS|HEAL_STATUS|HEAL_CC_STATUS) diff --git a/code/modules/antagonists/nightmare/nightmare_organs.dm b/code/modules/antagonists/nightmare/nightmare_organs.dm index 33170008012..18d3c041950 100644 --- a/code/modules/antagonists/nightmare/nightmare_organs.dm +++ b/code/modules/antagonists/nightmare/nightmare_organs.dm @@ -93,7 +93,7 @@ if(respawn_progress < HEART_RESPAWN_THRESHHOLD) return - owner.revive(HEAL_ALL) + owner.revive(HEAL_ALL & ~HEAL_REFRESH_ORGANS) if(!(owner.dna.species.id == SPECIES_SHADOW || owner.dna.species.id == SPECIES_NIGHTMARE)) var/mob/living/carbon/old_owner = owner Remove(owner, HEART_SPECIAL_SHADOWIFY) diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index cd4f0f07ab8..91b9d18ae1e 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -895,8 +895,8 @@ if(heal_flags & HEAL_LIMBS) regenerate_limbs() - if(heal_flags & HEAL_ORGANS) - regenerate_organs() + if(heal_flags & (HEAL_REFRESH_ORGANS|HEAL_ORGANS)) + regenerate_organs(regenerate_existing = (heal_flags & HEAL_REFRESH_ORGANS)) if(heal_flags & HEAL_TRAUMAS) cure_all_traumas(TRAUMA_RESILIENCE_MAGIC) diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm index 0f36915cbb3..5925eeea842 100644 --- a/code/modules/mob/living/carbon/human/species.dm +++ b/code/modules/mob/living/carbon/human/species.dm @@ -355,7 +355,7 @@ GLOBAL_LIST_EMPTY(features_by_species) /* * There is an existing organ in this slot, what should we do with it? Probably remove it! * - * We will removit if and only if: + * We will remove it if (and only if): * - We should not have the organ OR replace_current is passed to force old organs to regenerate * - The replaced organ is not in an excluded zone * - The replaced organ is not unremovable or synthetic (an implant) diff --git a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm index 70b40805fe1..aa73917706d 100644 --- a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm @@ -43,7 +43,7 @@ taste_description = "badmins" chemical_flags = REAGENT_DEAD_PROCESS /// Flags to fullheal every metabolism tick - var/full_heal_flags = ~(HEAL_BRUTE|HEAL_BURN|HEAL_TOX|HEAL_RESTRAINTS) + var/full_heal_flags = ~(HEAL_BRUTE|HEAL_BURN|HEAL_TOX|HEAL_RESTRAINTS|HEAL_REFRESH_ORGANS) // The best stuff there is. For testing/debugging. /datum/reagent/medicine/adminordrazine/on_hydroponics_apply(obj/item/seeds/myseed, datum/reagents/chems, obj/machinery/hydroponics/mytray, mob/user) @@ -77,7 +77,7 @@ name = "Quantum Medicine" description = "Rare and experimental particles, that apparently swap the user's body with one from an alternate dimension where it's completely healthy." taste_description = "science" - full_heal_flags = ~(HEAL_ADMIN|HEAL_BRUTE|HEAL_BURN|HEAL_TOX|HEAL_RESTRAINTS|HEAL_ALL_REAGENTS) + full_heal_flags = ~(HEAL_ADMIN|HEAL_BRUTE|HEAL_BURN|HEAL_TOX|HEAL_RESTRAINTS|HEAL_ALL_REAGENTS|HEAL_REFRESH_ORGANS) /datum/reagent/medicine/synaptizine name = "Synaptizine" diff --git a/code/modules/surgery/organs/_organ.dm b/code/modules/surgery/organs/_organ.dm index d32787a2918..54bfe2250dd 100644 --- a/code/modules/surgery/organs/_organ.dm +++ b/code/modules/surgery/organs/_organ.dm @@ -229,14 +229,17 @@ INITIALIZE_IMMEDIATE(/obj/item/organ) //Try code/modules/mob/living/carbon/brain/brain_item.dm /** - * Recreates all of this mob's organs, and heals them to full. + * Heals all of the mob's organs, and re-adds any missing ones. + * + * * regenerate_existing - if TRUE, existing organs will be deleted and replaced with new ones */ -/mob/living/carbon/proc/regenerate_organs() +/mob/living/carbon/proc/regenerate_organs(regenerate_existing = FALSE) + // Delegate to species if possible. if(dna?.species) - dna.species.regenerate_organs(src) - // Species regenerate organs doesn't handling healing the organs here, - // it's more concerned with just putting the necessary organs back in. + dna.species.regenerate_organs(src, replace_current = regenerate_existing) + + // Species regenerate organs doesn't ALWAYS handle healing the organs because it's dumb for(var/obj/item/organ/organ as anything in internal_organs) organ.setOrganDamage(0) set_heartattack(FALSE) diff --git a/code/modules/surgery/organs/heart.dm b/code/modules/surgery/organs/heart.dm index 4040767be59..f79d79cb5b7 100644 --- a/code/modules/surgery/organs/heart.dm +++ b/code/modules/surgery/organs/heart.dm @@ -514,7 +514,7 @@ playsound(get_turf(regenerating), 'sound/effects/ethereal_revive.ogg', 100) to_chat(regenerating, span_notice("You burst out of the crystal with vigour... But at a cost.")) regenerating.gain_trauma(picked_trauma, TRAUMA_RESILIENCE_ABSOLUTE) - regenerating.revive(HEAL_ALL) + regenerating.revive(HEAL_ALL & ~HEAL_REFRESH_ORGANS) // revive calls fully heal -> deletes the crystal. // this qdeleted check is just for sanity. if(!QDELETED(src)) diff --git a/code/modules/unit_tests/_unit_tests.dm b/code/modules/unit_tests/_unit_tests.dm index 7e18d531f6d..3648417e05c 100644 --- a/code/modules/unit_tests/_unit_tests.dm +++ b/code/modules/unit_tests/_unit_tests.dm @@ -114,6 +114,7 @@ #include "emoting.dm" #include "focus_only_tests.dm" #include "food_edibility_check.dm" +#include "full_heal.dm" #include "gas_transfer.dm" #include "get_turf_pixel.dm" #include "geyser.dm" diff --git a/code/modules/unit_tests/full_heal.dm b/code/modules/unit_tests/full_heal.dm new file mode 100644 index 00000000000..850334ea4f1 --- /dev/null +++ b/code/modules/unit_tests/full_heal.dm @@ -0,0 +1,60 @@ +/// Tests the fully heal flag [HEAL_ORGANS]. +/datum/unit_test/full_heal_heals_organs + +/datum/unit_test/full_heal_heals_organs/Run() + var/mob/living/carbon/human/dummy = allocate(/mob/living/carbon/human/consistent) + + for(var/obj/item/organ/internal/organ in dummy.internal_organs) + organ.applyOrganDamage(50) + + dummy.fully_heal(HEAL_ORGANS) + + for(var/obj/item/organ/internal/organ in dummy.internal_organs) + if(organ.damage <= 0) + continue + TEST_FAIL("Organ [organ] did not get healed by fullyheal flag HEAL_ORGANS.") + +/// Tests the fully heal flag [HEAL_REFRESH_ORGANS]. +/datum/unit_test/full_heal_regenerates_organs + +/datum/unit_test/full_heal_regenerates_organs/Run() + var/mob/living/carbon/human/dummy = allocate(/mob/living/carbon/human/consistent) + + var/list/we_started_with = list() + + for(var/obj/item/organ/internal/organ in dummy.internal_organs) + if(organ.organ_flags & ORGAN_VITAL) // leave this for now + continue + we_started_with += organ.type + qdel(organ) + + TEST_ASSERT(length(we_started_with), "Dummy didn't spawn with any organs to regenerate.") + + dummy.fully_heal(HEAL_REFRESH_ORGANS) + + for(var/obj/item/organ/organ_type as anything in we_started_with) + if(dummy.getorgan(organ_type)) + continue + TEST_FAIL("Organ [initial(organ_type.name)] didn't regenerate in the dummy after fullyheal flag HEAL_REFRESH_ORGANS.") + +/// Tests the fully heal combination flag [HEAL_DAMAGE]. +/datum/unit_test/full_heal_damage_types + +/datum/unit_test/full_heal_damage_types/Run() + var/mob/living/carbon/human/dummy = allocate(/mob/living/carbon/human/consistent) + + dummy.apply_damages(brute = 10, burn = 10, tox = 10, oxy = 10, clone = 10, stamina = 10) + dummy.fully_heal(HEAL_DAMAGE) + + if(dummy.getBruteLoss()) + TEST_FAIL("The dummy still had brute damage after a fully heal!") + if(dummy.getFireLoss()) + TEST_FAIL("The dummy still had burn damage after a fully heal!") + if(dummy.getToxLoss()) + TEST_FAIL("The dummy still had toxins damage after a fully heal!") + if(dummy.getOxyLoss()) + TEST_FAIL("The dummy still had oxy damage after a fully heal!") + if(dummy.getCloneLoss()) + TEST_FAIL("The dummy still had clone damage after a fully heal!") + if(dummy.getStaminaLoss()) + TEST_FAIL("The dummy still had stamina damage after a fully heal!")