From 3f0b4704ab70f7d8588ca965c1906414668c5b5c Mon Sep 17 00:00:00 2001 From: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Date: Wed, 25 Oct 2023 00:18:39 +0200 Subject: [PATCH] [MIRROR] Zombies use the regenerator component [MDB IGNORE] (#24546) * Zombies use the regenerator component * Update zombies.dm --------- Co-authored-by: MrMelbert <51863163+MrMelbert@users.noreply.github.com> Co-authored-by: Bloop <13398309+vinylspiders@users.noreply.github.com> --- code/datums/components/regenerator.dm | 87 ++++++++++++++----- .../living/basic/space_fauna/bear/_bear.dm | 3 +- .../space_fauna/changeling/flesh_spider.dm | 2 +- .../carbon/human/species_types/zombies.dm | 55 ++++++------ 4 files changed, 94 insertions(+), 53 deletions(-) diff --git a/code/datums/components/regenerator.dm b/code/datums/components/regenerator.dm index a6182935a3f..42d0a0f636c 100644 --- a/code/datums/components/regenerator.dm +++ b/code/datums/components/regenerator.dm @@ -9,8 +9,16 @@ /datum/component/regenerator /// You will only regain health if you haven't been hurt for this many seconds var/regeneration_delay - /// Health to regenerate per second - var/health_per_second + /// Brute reagined every second + var/brute_per_second + /// Burn reagined every second + var/burn_per_second + /// Toxin reagined every second + var/tox_per_second + /// Oxygen reagined every second + var/oxy_per_second + /// If TRUE, we'll try to heal wounds as well. Useless for non-humans. + var/heals_wounds = FALSE /// List of damage types we don't care about, in case you want to only remove this with fire damage or something var/list/ignore_damage_types /// Colour of regeneration animation, or none if you don't want one @@ -18,12 +26,25 @@ /// When this timer completes we start restoring health, it is a timer rather than a cooldown so we can do something on its completion var/regeneration_start_timer -/datum/component/regenerator/Initialize(regeneration_delay = 6 SECONDS, health_per_second = 2, ignore_damage_types = list(STAMINA), outline_colour = COLOR_PALE_GREEN) +/datum/component/regenerator/Initialize( + regeneration_delay = 6 SECONDS, + brute_per_second = 2, + burn_per_second = 0, + tox_per_second = 0, + oxy_per_second = 0, + heals_wounds = FALSE, + ignore_damage_types = list(STAMINA), + outline_colour = COLOR_PALE_GREEN, +) if (!isliving(parent)) return COMPONENT_INCOMPATIBLE src.regeneration_delay = regeneration_delay - src.health_per_second = health_per_second + src.brute_per_second = brute_per_second + src.burn_per_second = burn_per_second + src.tox_per_second = tox_per_second + src.oxy_per_second = oxy_per_second + src.heals_wounds = heals_wounds src.ignore_damage_types = ignore_damage_types src.outline_colour = outline_colour @@ -48,24 +69,19 @@ /datum/component/regenerator/proc/on_take_damage(datum/source, damage, damagetype) SIGNAL_HANDLER - if (damage <= 0) - return - if (locate(damagetype) in ignore_damage_types) + if (damagetype in ignore_damage_types) return stop_regenerating() - if(regeneration_start_timer) - deltimer(regeneration_start_timer) - regeneration_start_timer = addtimer(CALLBACK(src, PROC_REF(start_regenerating)), regeneration_delay, TIMER_STOPPABLE) + regeneration_start_timer = addtimer(CALLBACK(src, PROC_REF(start_regenerating)), regeneration_delay, TIMER_UNIQUE|TIMER_OVERRIDE|TIMER_STOPPABLE) /// Start processing health regeneration, and show animation if provided /datum/component/regenerator/proc/start_regenerating() - var/mob/living/living_parent = parent - if (living_parent.stat == DEAD) - return - if (living_parent.health == living_parent.maxHealth) + if (!should_be_regenning(parent)) return + var/mob/living/living_parent = parent living_parent.visible_message(span_notice("[living_parent]'s wounds begin to knit closed!")) START_PROCESSING(SSobj, src) + regeneration_start_timer = null if (!outline_colour) return living_parent.add_filter(REGENERATION_FILTER, 2, list("type" = "outline", "color" = outline_colour, "alpha" = 0, "size" = 1)) @@ -81,13 +97,44 @@ living_parent.remove_filter(REGENERATION_FILTER) /datum/component/regenerator/process(seconds_per_tick = SSMOBS_DT) - var/mob/living/living_parent = parent - if (living_parent.stat == DEAD) + if (!should_be_regenning(parent)) stop_regenerating() return - if (living_parent.health == living_parent.maxHealth) - stop_regenerating() - return - living_parent.heal_overall_damage(health_per_second * seconds_per_tick) + + var/mob/living/living_parent = parent + // Heal bonus for being in crit. Only applies to carbons + var/heal_mod = HAS_TRAIT(living_parent, TRAIT_CRITICAL_CONDITION) ? 2 : 1 + + var/need_mob_update = FALSE + if(brute_per_second) + need_mob_update += living_parent.adjustBruteLoss(-1 * heal_mod * brute_per_second * seconds_per_tick, updating_health = FALSE) + if(burn_per_second) + need_mob_update += living_parent.adjustFireLoss(-1 * heal_mod * burn_per_second * seconds_per_tick, updating_health = FALSE) + if(tox_per_second) + need_mob_update += living_parent.adjustToxLoss(-1 * heal_mod * tox_per_second * seconds_per_tick, updating_health = FALSE) + if(oxy_per_second) + need_mob_update += living_parent.adjustOxyLoss(-1 * heal_mod * oxy_per_second * seconds_per_tick, updating_health = FALSE) + + if(heals_wounds && iscarbon(parent)) + var/mob/living/carbon/carbon_parent = living_parent + for(var/datum/wound/iter_wound as anything in carbon_parent.all_wounds) + if(SPT_PROB(2 - (iter_wound.severity / 2), seconds_per_tick)) + iter_wound.remove_wound() + need_mob_update++ + + if(need_mob_update) + living_parent.updatehealth() + +/// Checks if the passed mob is in a valid state to be regenerating +/datum/component/regenerator/proc/should_be_regenning(mob/living/who) + if(who.stat == DEAD) + return FALSE + if(heals_wounds && iscarbon(who)) + var/mob/living/carbon/carbon_who = who + if(length(carbon_who.all_wounds) > 0) + return TRUE + if(who.health != who.maxHealth) + return TRUE + return FALSE #undef REGENERATION_FILTER diff --git a/code/modules/mob/living/basic/space_fauna/bear/_bear.dm b/code/modules/mob/living/basic/space_fauna/bear/_bear.dm index 924cf854276..8ba6699648e 100644 --- a/code/modules/mob/living/basic/space_fauna/bear/_bear.dm +++ b/code/modules/mob/living/basic/space_fauna/bear/_bear.dm @@ -130,7 +130,7 @@ AddComponent(/datum/component/regenerator,\ regeneration_delay = 1 SECONDS,\ - health_per_second = 5,\ + brute_per_second = 5,\ outline_colour = COLOR_YELLOW,\ ) @@ -167,4 +167,3 @@ victim.Knockdown(20) playsound(loc, 'sound/misc/slip.ogg', 15) victim.visible_message(span_danger("[victim] slips on [src]'s butter!")) - diff --git a/code/modules/mob/living/basic/space_fauna/changeling/flesh_spider.dm b/code/modules/mob/living/basic/space_fauna/changeling/flesh_spider.dm index c73b008d6b4..a64250d891c 100644 --- a/code/modules/mob/living/basic/space_fauna/changeling/flesh_spider.dm +++ b/code/modules/mob/living/basic/space_fauna/changeling/flesh_spider.dm @@ -59,7 +59,7 @@ AddComponent(\ /datum/component/regenerator,\ regeneration_delay = 4 SECONDS,\ - health_per_second = maxHealth / 6,\ + brute_per_second = maxHealth / 6,\ outline_colour = COLOR_PINK,\ ) diff --git a/code/modules/mob/living/carbon/human/species_types/zombies.dm b/code/modules/mob/living/carbon/human/species_types/zombies.dm index 4f9b6f1b4af..54382dcf021 100644 --- a/code/modules/mob/living/carbon/human/species_types/zombies.dm +++ b/code/modules/mob/living/carbon/human/species_types/zombies.dm @@ -1,5 +1,3 @@ -#define REGENERATION_DELAY 6 SECONDS // After taking damage, how long it takes for automatic regeneration to begin - /datum/species/zombie // 1spooky name = "High-Functioning Zombie" @@ -131,49 +129,48 @@ BODY_ZONE_L_LEG = /obj/item/bodypart/leg/left/zombie/infectious, BODY_ZONE_R_LEG = /obj/item/bodypart/leg/right/zombie/infectious, ) - /// The rate the zombies regenerate at - var/heal_rate = 0.5 - /// The cooldown before the zombie can start regenerating - COOLDOWN_DECLARE(regen_cooldown) /datum/species/zombie/infectious/on_species_gain(mob/living/carbon/human/new_zombie, datum/species/old_species) . = ..() - new_zombie.AddComponent(/datum/component/mutant_hands, mutant_hand_path = /obj/item/mutant_hand/zombie) + new_zombie.set_combat_mode(TRUE) + + // Deal with the source of this zombie corruption + // Infection organ needs to be handled separately from mutant_organs + // because it persists through species transitions + var/obj/item/organ/internal/zombie_infection/infection = new_zombie.get_organ_slot(ORGAN_SLOT_ZOMBIE) + if(isnull(infection)) + infection = new() + infection.Insert(new_zombie) + + new_zombie.AddComponent( \ + /datum/component/mutant_hands, \ + mutant_hand_path = /obj/item/mutant_hand/zombie, \ + ) + new_zombie.AddComponent( \ + /datum/component/regenerator, \ + regeneration_delay = 6 SECONDS, \ + brute_per_second = 0.5, \ + burn_per_second = 0.5, \ + tox_per_second = 0.5, \ + oxy_per_second = 0.25, \ + heals_wounds = TRUE, \ + ) /datum/species/zombie/infectious/on_species_loss(mob/living/carbon/human/was_zombie, datum/species/new_species, pref_load) . = ..() qdel(was_zombie.GetComponent(/datum/component/mutant_hands)) + qdel(was_zombie.GetComponent(/datum/component/regenerator)) /datum/species/zombie/infectious/check_roundstart_eligible() return FALSE /datum/species/zombie/infectious/spec_stun(mob/living/carbon/human/H,amount) - . = min(20, amount) - -/datum/species/zombie/infectious/apply_damage(damage, damagetype = BRUTE, def_zone = null, blocked, mob/living/carbon/human/H, spread_damage = FALSE, forced = FALSE, wound_bonus = 0, bare_wound_bonus = 0, sharpness = NONE, attack_direction = null, attacking_item) - . = ..() - if(.) - COOLDOWN_START(src, regen_cooldown, REGENERATION_DELAY) + return min(2 SECONDS, amount) /datum/species/zombie/infectious/spec_life(mob/living/carbon/carbon_mob, seconds_per_tick, times_fired) . = ..() carbon_mob.set_combat_mode(TRUE) // THE SUFFERING MUST FLOW - //Zombies never actually die, they just fall down until they regenerate enough to rise back up. - //They must be restrained, beheaded or gibbed to stop being a threat. - if(COOLDOWN_FINISHED(src, regen_cooldown)) - var/heal_amt = heal_rate - if(HAS_TRAIT(carbon_mob, TRAIT_CRITICAL_CONDITION)) - heal_amt *= 2 - var/need_mob_update = FALSE - need_mob_update += carbon_mob.heal_overall_damage(heal_amt * seconds_per_tick, heal_amt * seconds_per_tick, updating_health = FALSE) - need_mob_update += carbon_mob.adjustToxLoss(-heal_amt * seconds_per_tick, updating_health = FALSE) - if(need_mob_update) - carbon_mob.updatehealth() - for(var/i in carbon_mob.all_wounds) - var/datum/wound/iter_wound = i - if(SPT_PROB(2-(iter_wound.severity/2), seconds_per_tick)) - iter_wound.remove_wound() if(!HAS_TRAIT(carbon_mob, TRAIT_CRITICAL_CONDITION) && SPT_PROB(2, seconds_per_tick)) playsound(carbon_mob, pick(spooks), 50, TRUE, 10) @@ -212,5 +209,3 @@ BODY_ZONE_L_LEG = /obj/item/bodypart/leg/left/zombie, BODY_ZONE_R_LEG = /obj/item/bodypart/leg/right/zombie ) - -#undef REGENERATION_DELAY