Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[MIRROR] Zombies use the regenerator component #273

Merged
merged 1 commit into from
Oct 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 67 additions & 20 deletions code/datums/components/regenerator.dm
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,42 @@
/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
var/outline_colour
/// 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

Expand All @@ -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))
Expand All @@ -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
3 changes: 1 addition & 2 deletions code/modules/mob/living/basic/space_fauna/bear/_bear.dm
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@

AddComponent(/datum/component/regenerator,\
regeneration_delay = 1 SECONDS,\
health_per_second = 5,\
brute_per_second = 5,\
outline_colour = COLOR_YELLOW,\
)

Expand Down Expand Up @@ -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!"))

Original file line number Diff line number Diff line change
Expand Up @@ -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,\
)

Expand Down
55 changes: 25 additions & 30 deletions code/modules/mob/living/carbon/human/species_types/zombies.dm
Original file line number Diff line number Diff line change
@@ -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"
Expand Down Expand Up @@ -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)

Expand Down Expand Up @@ -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
Loading