/
regenerator.dm
140 lines (123 loc) · 5.08 KB
/
regenerator.dm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#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
/// 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,
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.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
/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)
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 (damagetype in ignore_damage_types)
return
stop_regenerating()
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()
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))
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(seconds_per_tick = SSMOBS_DT)
if (!should_be_regenning(parent))
stop_regenerating()
return
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