|
17 | 17 | var/is_regenerating = TRUE
|
18 | 18 | //unga bunga
|
19 | 19 | var/process_stamina = TRUE
|
| 20 | + /// Used to determine when the stamina changes, to properly run on_stamina_update on the parent. |
| 21 | + VAR_PRIVATE/should_notify_parent = FALSE |
20 | 22 |
|
21 | 23 | ///cooldowns
|
22 | 24 | ///how long until we can lose stamina again
|
23 | 25 | COOLDOWN_DECLARE(stamina_grace_period)
|
24 | 26 | ///how long stamina is paused for
|
25 | 27 | COOLDOWN_DECLARE(paused_stamina)
|
26 | 28 |
|
| 29 | + /// Signals which we react in order to re-check if we should be processing or not. |
| 30 | + var/static/list/update_on_signals = list( |
| 31 | + COMSIG_MOB_STATCHANGE, |
| 32 | + SIGNAL_ADDTRAIT(TRAIT_NO_TRANSFORM), |
| 33 | + SIGNAL_REMOVETRAIT(TRAIT_NO_TRANSFORM), |
| 34 | + ) |
| 35 | + |
27 | 36 | /datum/stamina_container/New(parent, maximum = STAMINA_MAX, regen_rate = STAMINA_REGEN)
|
28 | 37 | if(maximum <= 0)
|
29 | 38 | stack_trace("Attempted to initialize stamina container with an invalid maximum limit of [maximum], defaulting to [STAMINA_MAX]")
|
|
32 | 41 | src.maximum = maximum
|
33 | 42 | src.regen_rate = regen_rate
|
34 | 43 | src.current = maximum
|
35 |
| - START_PROCESSING(SSstamina, src) |
| 44 | + RegisterSignals(parent, update_on_signals, PROC_REF(update_process)) |
| 45 | + RegisterSignal(parent, COMSIG_MOVABLE_MOVED, PROC_REF(nullspace_move_check)) |
| 46 | + update_process() |
36 | 47 |
|
37 | 48 | /datum/stamina_container/Destroy()
|
38 |
| - parent?.stamina = null |
| 49 | + if(!isnull(parent)) |
| 50 | + parent.stamina = null |
| 51 | + UnregisterSignal(parent, update_on_signals) |
| 52 | + UnregisterSignal(parent, COMSIG_MOVABLE_MOVED) |
39 | 53 | parent = null
|
40 | 54 | STOP_PROCESSING(SSstamina, src)
|
41 | 55 | return ..()
|
42 | 56 |
|
43 | 57 | /datum/stamina_container/proc/update(seconds_per_tick = 1)
|
| 58 | + var/last_current = current |
44 | 59 | if(process_stamina == TRUE)
|
45 | 60 | if(!is_regenerating)
|
46 | 61 | if(!COOLDOWN_FINISHED(src, paused_stamina))
|
|
49 | 64 |
|
50 | 65 | if(seconds_per_tick)
|
51 | 66 | current = min(current + (regen_rate*seconds_per_tick), maximum)
|
52 |
| - if(seconds_per_tick && decrement) |
53 |
| - current = max(current + (-decrement*seconds_per_tick), 0) |
| 67 | + if(decrement) |
| 68 | + current = max(current + (-decrement*seconds_per_tick), 0) |
| 69 | + if(current != last_current) |
| 70 | + should_notify_parent = TRUE |
54 | 71 | loss = maximum - current
|
55 | 72 | loss_as_percent = loss ? (loss == maximum ? 0 : loss / maximum * 100) : 0
|
56 | 73 |
|
|
59 | 76 | else if(!(current == maximum))
|
60 | 77 | process_stamina = TRUE
|
61 | 78 |
|
62 |
| - parent.on_stamina_update() |
| 79 | + if(should_notify_parent) |
| 80 | + parent.on_stamina_update() |
| 81 | + should_notify_parent = FALSE |
63 | 82 |
|
64 | 83 | ///Pause stamina regeneration for some period of time. Does not support doing this from multiple sources at once because I do not do that and I will add it later if I want to.
|
65 | 84 | /datum/stamina_container/proc/pause(time)
|
|
86 | 105 | var/modify = parent.pre_stamina_change(amt, forced)
|
87 | 106 | if(base_modify)
|
88 | 107 | modify = amt
|
| 108 | + var/old_current = current |
89 | 109 | current = round(clamp(current + modify, 0, maximum), DAMAGE_PRECISION)
|
| 110 | + if(current != old_current) |
| 111 | + should_notify_parent = TRUE |
90 | 112 | update()
|
91 | 113 | if((amt < 0) && is_regenerating)
|
92 | 114 | pause(STAMINA_REGEN_TIME)
|
|
104 | 126 | if(stamina_after_loss < lowest_stamina_value)
|
105 | 127 | amount = current - lowest_stamina_value
|
106 | 128 |
|
| 129 | + var/old_current = current |
107 | 130 | current = round(clamp(current + amount, 0, maximum), DAMAGE_PRECISION)
|
| 131 | + if(current != old_current) |
| 132 | + should_notify_parent = TRUE |
108 | 133 | update()
|
109 | 134 | if((amount < 0) && is_regenerating)
|
110 | 135 | pause(STAMINA_REGEN_TIME)
|
111 | 136 | return amount
|
112 | 137 |
|
| 138 | +/// Signal handler for COMSIG_MOVABLE_MOVED to ensure that update_process() gets called whenever moving to/from nullspace. |
| 139 | +/datum/stamina_container/proc/nullspace_move_check(atom/movable/mover, atom/old_loc, dir, force) |
| 140 | + SIGNAL_HANDLER |
| 141 | + if(isnull(old_loc) || isnull(mover.loc)) |
| 142 | + update_process() |
| 143 | + |
| 144 | +/// Returns if the container should currently be processing or not. |
| 145 | +/datum/stamina_container/proc/should_process() |
| 146 | + SHOULD_BE_PURE(TRUE) |
| 147 | + if(QDELETED(parent) || isnull(parent.loc)) |
| 148 | + return FALSE |
| 149 | + if(!parent.uses_stamina) |
| 150 | + return FALSE |
| 151 | + if(parent.stat == DEAD) |
| 152 | + return FALSE |
| 153 | + if(HAS_TRAIT(parent, TRAIT_NO_TRANSFORM)) |
| 154 | + return FALSE |
| 155 | + return TRUE |
| 156 | + |
| 157 | +/// Checks to see if the container should be processing, and starts/stops it. |
| 158 | +/datum/stamina_container/proc/update_process() |
| 159 | + SIGNAL_HANDLER |
| 160 | + if(should_process()) |
| 161 | + START_PROCESSING(SSstamina, src) |
| 162 | + else |
| 163 | + STOP_PROCESSING(SSstamina, src) |
| 164 | + |
113 | 165 | /// Sets the maximum amount of stamina.
|
114 | 166 | /// Always use this instead of directly setting the stamina var, as this has sanity checks, and immediately updates afterwards.
|
115 | 167 | /datum/stamina_container/proc/set_maximum(value = STAMINA_MAX)
|
|
122 | 174 | maximum = value
|
123 | 175 | update()
|
124 | 176 | return TRUE
|
| 177 | + |
| 178 | +/mob/living/carbon |
| 179 | + uses_stamina = TRUE |
| 180 | + |
| 181 | +/mob/living/carbon/alien |
| 182 | + uses_stamina = FALSE |
| 183 | + |
| 184 | +/mob/living/basic |
| 185 | + uses_stamina = TRUE |
| 186 | + |
| 187 | +/mob/living/simple_animal |
| 188 | + uses_stamina = TRUE |
0 commit comments