Files
Bubberstation/code/datums/components/regenerator.dm
SkyratBot 8e08ff0be7 [MIRROR] Basic Mob Carp Part II: Regenerator [MDB IGNORE] (#17699)
* Basic Mob Carp Part II: Regenerator (#71437)

## About The Pull Request

<details>
  <summary>Video</summary>

https://user-images.githubusercontent.com/7483112/203324325-5bf46e0f-b294-4832-9016-aec275036ca9.mp4

</details>

Adds a "Regenerator" component, applies it to carp, and removes the
previous implementation from megacarp.
The function of this component is that any time you take damage a timer
is reset, when that timer expires you will begin regenerating health and
display an animated border for visual feedback.
This was previously a function of mega carp but was extremely obscure
because there was _no_ feedback, so it would only be visible that it was
happening if you were wearing a medical hud.

Additionally because mega carp will pursue a target until it dies you
probably wouldn't notice it even then, it had to survive a fight in
order to gain any value from this.
This will still be true for all carp until AI changes are pushed, so
until then this isn't going to do very much for NPCs but might be a
small buff to player controlled carp (though those can all retreat to a
carp rift for a similar effect).

This also modifies a few "defence" procs which were either directly
setting HP or neglecting to call signals from a base proc, as they would
bypass triggering the effect. This should make them more reliable for
other things which rely on those signals too.

## Why It's Good For The Game

Gives an iconic creature some more unique behaviour than "moves directly
towards you and bites".
Gives visual feedback to some behaviour which has existed invisibly for
a long time.

## Changelog
🆑
add: All Space Carp will now start regenerating health after 6 seconds
of not taking any damage, until they're back to full health. This
behaviour was previously unique to mega carp.
/🆑

* Basic Mob Carp Part II: Regenerator

Co-authored-by: Jacquerel <hnevard@gmail.com>
2022-11-23 14:33:36 -05:00

94 lines
3.4 KiB
Plaintext

#define REGENERATION_FILTER "healing_glow"
/**
* # Regenerator component
*
* A mob with this component will regenerate its health over time, as long as it has not received damage
* in the last X seconds. Taking any damage will reset this cooldown.
*/
/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
/// 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)
if (!isliving(parent))
return COMPONENT_INCOMPATIBLE
src.regeneration_delay = regeneration_delay
src.health_per_second = health_per_second
src.ignore_damage_types = ignore_damage_types
src.outline_colour = outline_colour
/datum/component/regenerator/RegisterWithParent()
. = ..()
RegisterSignal(parent, COMSIG_MOB_APPLY_DAMAGE, PROC_REF(on_take_damage))
/datum/component/regenerator/UnregisterFromParent()
. = ..()
if(regeneration_start_timer)
deltimer(regeneration_start_timer)
UnregisterSignal(parent, COMSIG_MOB_APPLY_DAMAGE)
stop_regenerating()
/datum/component/regenerator/Destroy(force, silent)
stop_regenerating()
. = ..()
if(regeneration_start_timer)
deltimer(regeneration_start_timer)
/// When you take damage, reset the cooldown and start processing
/datum/component/regenerator/proc/on_take_damage(datum/source, damage, damagetype)
SIGNAL_HANDLER
if (damage <= 0)
return
if (locate(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)
/// 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)
return
living_parent.visible_message(span_notice("[living_parent]'s wounds begin to knit closed!"))
START_PROCESSING(SSobj, src)
if (!outline_colour)
return
living_parent.add_filter(REGENERATION_FILTER, 2, list("type" = "outline", "color" = outline_colour, "alpha" = 0, "size" = 1))
var/filter = living_parent.get_filter(REGENERATION_FILTER)
animate(filter, alpha = 200, time = 0.5 SECONDS, loop = -1)
animate(alpha = 0, time = 0.5 SECONDS)
/datum/component/regenerator/proc/stop_regenerating()
STOP_PROCESSING(SSobj, src)
var/mob/living/living_parent = parent
var/filter = living_parent.get_filter(REGENERATION_FILTER)
animate(filter)
living_parent.remove_filter(REGENERATION_FILTER)
/datum/component/regenerator/process(delta_time = SSMOBS_DT)
var/mob/living/living_parent = parent
if (living_parent.stat == DEAD)
stop_regenerating()
return
if (living_parent.health == living_parent.maxHealth)
stop_regenerating()
return
living_parent.heal_overall_damage(health_per_second * delta_time)
#undef REGENERATION_FILTER