diff --git a/code/datums/status_effects/_status_effect.dm b/code/datums/status_effects/_status_effect.dm
index 2b44e8bbaf0..4a569858655 100644
--- a/code/datums/status_effects/_status_effect.dm
+++ b/code/datums/status_effects/_status_effect.dm
@@ -3,19 +3,16 @@
/datum/status_effect
/// The ID of the effect. ID is used in adding and removing effects to check for duplicates, among other things.
var/id = "effect"
- /// When set initially / in on_creation, this is how long the status effect lasts in deciseconds.
- /// While processing, this becomes the world.time when the status effect will expire.
- /// -1 = infinite duration.
+ /// This is how long the status effect lasts in deciseconds.
+ /// You can put STATUS_EFFECT_PERMANENT (or INFINITY) here for infinite duration.
var/duration = STATUS_EFFECT_PERMANENT
- /// When set initially / in on_creation, this is how long between [proc/tick] calls in deciseconds.
- /// Note that this cannot be faster than the processing subsystem you choose to fire the effect on. (See: [var/processing_speed])
- /// While processing, this becomes the world.time when the next tick will occur.
- /// -1 = will prevent ticks, and if duration is also unlimited (-1), stop processing wholesale.
+ /// This is how long between [proc/tick] calls in deciseconds.
+ /// This has to be a multiple of the [var/wait] of the subsystem this status effect is running on, which is based on [var/processing_speed].
+ /// Putting STATUS_EFFECT_NO_TICK here will stop [proc/tick] calls, and if [var/duration] is STATUS_EFFECT_PERMANENT, it stops processing entirely.
+ /// Putting STATUS_EFFECT_AUTO_TICK here will make every subsystem tick call [proc/tick], making the tick interval depend entirely on [var/processing_speed]
var/tick_interval = 1 SECONDS
- ///If our tick intervals are set to be a dynamic value within a range, the lowerbound of said range
- var/tick_interval_lowerbound
- ///If our tick intervals are set to be a dynamic value within a range, the upperbound of said range
- var/tick_interval_upperbound
+ /// The time until the next [proc/tick] call, gets set to [var/tick_interval] after every [proc/tick] call and decrements on every [proc/process] call.
+ var/time_until_next_tick
/// The mob affected by the status effect.
VAR_FINAL/mob/living/owner
/// How many of the effect can be on one mob, and/or what happens when you try to add a duplicate.
@@ -58,10 +55,9 @@
// we will optionally allow INFINITY, because i imagine it'll be convenient in some places,
// but we'll still set it to -1 / STATUS_EFFECT_PERMANENT for proper unified handling
duration = STATUS_EFFECT_PERMANENT
- if(duration != STATUS_EFFECT_PERMANENT)
- duration = world.time + duration
+
if(tick_interval != STATUS_EFFECT_NO_TICK)
- tick_interval = world.time + tick_interval
+ time_until_next_tick = tick_interval
if(alert_type)
var/atom/movable/screen/alert/status_effect/new_alert = owner.throw_alert(id, alert_type)
@@ -69,7 +65,7 @@
linked_alert = new_alert //so we can reference the alert, if we need to
update_shown_duration()
- if(duration > world.time || tick_interval > world.time) //don't process if we don't care
+ if(duration != STATUS_EFFECT_PERMANENT || tick_interval != STATUS_EFFECT_NO_TICK) //don't process if we don't care
switch(processing_speed)
if(STATUS_EFFECT_FAST_PROCESS)
START_PROCESSING(SSfastprocess, src)
@@ -108,7 +104,7 @@
if(!linked_alert || !show_duration)
return
- linked_alert.maptext = MAPTEXT_TINY_UNICODE("[round((duration - world.time)/10, 1)]s")
+ linked_alert.maptext = MAPTEXT_TINY_UNICODE("[round(duration / 10, 1)]s")
// Status effect process. Handles adjusting its duration and ticks.
// If you're adding processed effects, put them in [proc/tick]
@@ -120,19 +116,23 @@
qdel(src)
return
+ if (duration != STATUS_EFFECT_PERMANENT)
+ duration = max(0, duration - (seconds_per_tick SECONDS)) // doing it first means its more up to date for ticks to read
+
+ if (tick_interval != STATUS_EFFECT_NO_TICK)
+ time_until_next_tick = max(0, time_until_next_tick - (seconds_per_tick SECONDS)) // same here
+
if(tick_interval == STATUS_EFFECT_AUTO_TICK)
tick(seconds_per_tick)
- else if(tick_interval != STATUS_EFFECT_NO_TICK && tick_interval < world.time)
- var/tick_length = (tick_interval_upperbound && tick_interval_lowerbound) ? rand(tick_interval_lowerbound, tick_interval_upperbound) : initial(tick_interval)
- tick(tick_length / (1 SECONDS))
- tick_interval = world.time + tick_length
+ else if(tick_interval != STATUS_EFFECT_NO_TICK && time_until_next_tick <= 0)
+ time_until_next_tick = tick_interval // same here as well
+ tick(tick_interval / 10)
if(QDELING(src))
- // tick deleted us, no need to continue
- return
+ return // tick deleted us, no need to continue
if(duration != STATUS_EFFECT_PERMANENT)
- if(duration < world.time)
+ if(duration <= 0)
qdel(src)
return
update_shown_duration()
@@ -185,10 +185,7 @@
/// Called when a status effect of status_type STATUS_EFFECT_REFRESH
/// has its duration refreshed in apply_status_effect - is passed New() args
/datum/status_effect/proc/refresh(effect, ...)
- var/original_duration = initial(duration)
- if(original_duration == STATUS_EFFECT_PERMANENT)
- return
- duration = world.time + original_duration
+ duration = initial(duration)
/// Adds nextmove modifier multiplicatively to the owner while applied
/datum/status_effect/proc/nextmove_modifier()
@@ -208,13 +205,14 @@
if(!heal_flag_necessary || (heal_flags & heal_flag_necessary))
qdel(src)
-/// Remove [seconds] of duration from the status effect, qdeling / ending if we eclipse the current world time.
+/// Removes [seconds] of duration from the status effect.
+/// Returns whether or not the status effect was qdeleted due to running out of duration.
/datum/status_effect/proc/remove_duration(seconds)
if(duration == STATUS_EFFECT_PERMANENT) // Infinite duration
return FALSE
- duration -= seconds
- if(duration <= world.time)
+ duration -= (seconds SECONDS)
+ if(duration <= 0)
qdel(src)
return TRUE
diff --git a/code/datums/status_effects/buffs.dm b/code/datums/status_effects/buffs.dm
index d51ebe144ff..75edc87b4ec 100644
--- a/code/datums/status_effects/buffs.dm
+++ b/code/datums/status_effects/buffs.dm
@@ -236,7 +236,7 @@
var/skill_level_boost = (new_owner.mind?.get_skill_level(/datum/skill/athletics) - 1) * 2 SECONDS
bonus_time = (bonus_time + food_boost + skill_level_boost) * modifier
- var/exhaustion_limit = new_owner.mind?.get_skill_modifier(/datum/skill/athletics, SKILL_VALUE_MODIFIER) + world.time
+ var/exhaustion_limit = new_owner.mind?.get_skill_modifier(/datum/skill/athletics, SKILL_VALUE_MODIFIER)
if(duration + bonus_time >= exhaustion_limit)
duration = exhaustion_limit
to_chat(new_owner, span_userdanger("Your muscles are exhausted! Might be a good idea to sleep..."))
@@ -274,7 +274,7 @@
id = "Hippocratic Oath"
status_type = STATUS_EFFECT_UNIQUE
duration = STATUS_EFFECT_PERMANENT
- tick_interval = 2.5 SECONDS
+ tick_interval = 2.6 SECONDS
alert_type = null
var/datum/component/aura_healing/aura_healing
diff --git a/code/datums/status_effects/buffs/stop_drop_roll.dm b/code/datums/status_effects/buffs/stop_drop_roll.dm
index e7ff393a1dd..8618aea5bc3 100644
--- a/code/datums/status_effects/buffs/stop_drop_roll.dm
+++ b/code/datums/status_effects/buffs/stop_drop_roll.dm
@@ -8,8 +8,7 @@
if(!iscarbon(owner))
return FALSE
- var/actual_interval = initial(tick_interval)
- if(!owner.Knockdown(actual_interval * 2, ignore_canstun = TRUE) || owner.body_position != LYING_DOWN)
+ if(!owner.Knockdown(tick_interval * 2, ignore_canstun = TRUE) || owner.body_position != LYING_DOWN)
to_chat(owner, span_warning("You try to stop, drop, and roll - but you can't get on the ground!"))
return FALSE
@@ -40,12 +39,11 @@
qdel(src)
return
- var/actual_interval = initial(tick_interval)
- if(!owner.Knockdown(actual_interval * 1.2, ignore_canstun = TRUE))
+ if(!owner.Knockdown(tick_interval * 1.2, ignore_canstun = TRUE))
stop_rolling()
return
- owner.spin(spintime = actual_interval, speed = actual_interval / 4)
+ owner.spin(spintime = tick_interval, speed = tick_interval / 4)
if(!reduce_firestacks(1))
return
diff --git a/code/datums/status_effects/debuffs/choke.dm b/code/datums/status_effects/debuffs/choke.dm
index e8af4b1b94d..05f41dcd178 100644
--- a/code/datums/status_effects/debuffs/choke.dm
+++ b/code/datums/status_effects/debuffs/choke.dm
@@ -66,7 +66,7 @@
if(flaming)
ash = new(owner, /particles/smoke/ash, PARTICLE_ATTACH_MOB)
var/clear_in = rand(15 SECONDS, 25 SECONDS)
- if(duration != -1)
+ if(duration != STATUS_EFFECT_PERMANENT)
clear_in = min(duration, clear_in)
addtimer(CALLBACK(src, PROC_REF(clear_flame)), clear_in)
return TRUE
diff --git a/code/datums/status_effects/debuffs/dizziness.dm b/code/datums/status_effects/debuffs/dizziness.dm
index b47083aa5e3..547ba44df50 100644
--- a/code/datums/status_effects/debuffs/dizziness.dm
+++ b/code/datums/status_effects/debuffs/dizziness.dm
@@ -26,7 +26,7 @@
/datum/status_effect/dizziness/tick(seconds_between_ticks)
// How much time is left, in seconds
- var/amount = (duration - world.time) / 10
+ var/amount = duration / 10
if(amount <= 0)
return
diff --git a/code/datums/status_effects/debuffs/dna_transformation.dm b/code/datums/status_effects/debuffs/dna_transformation.dm
index 46e125a391e..bd2a079d6f8 100644
--- a/code/datums/status_effects/debuffs/dna_transformation.dm
+++ b/code/datums/status_effects/debuffs/dna_transformation.dm
@@ -82,10 +82,10 @@
if(duration == STATUS_EFFECT_PERMANENT)
return // Already paused
- time_before_pause = duration - world.time
+ time_before_pause = duration
duration = STATUS_EFFECT_PERMANENT
// Resume if we're none of the above and also were paused
else if(time_before_pause != -1)
- duration = time_before_pause + world.time
+ duration = time_before_pause
time_before_pause = -1
diff --git a/code/datums/status_effects/debuffs/hallucination.dm b/code/datums/status_effects/debuffs/hallucination.dm
index e5528a66382..9c40203c1dd 100644
--- a/code/datums/status_effects/debuffs/hallucination.dm
+++ b/code/datums/status_effects/debuffs/hallucination.dm
@@ -94,7 +94,7 @@
var/lower_cd = lower_tick_interval
var/upper_cd = upper_tick_interval
if(variable_tier)
- var/seconds_left = (duration - world.time) / 10
+ var/seconds_left = duration / 10
switch(seconds_left)
if(0 to 20)
max_hallucination_tier = HALLUCINATION_TIER_COMMON
diff --git a/code/datums/status_effects/debuffs/jitteriness.dm b/code/datums/status_effects/debuffs/jitteriness.dm
index ad9a7625133..50bb8b5e09f 100644
--- a/code/datums/status_effects/debuffs/jitteriness.dm
+++ b/code/datums/status_effects/debuffs/jitteriness.dm
@@ -25,7 +25,7 @@
owner.update_offsets()
/datum/status_effect/jitter/get_examine_text()
- switch(duration - world.time)
+ switch(duration)
if(5 MINUTES to INFINITY)
return span_boldwarning("[owner.p_They()] [owner.p_are()] convulsing violently!")
if(3 MINUTES to 5 MINUTES)
@@ -47,7 +47,7 @@
if(owner.resting && remove_duration(4 * seconds_between_ticks))
return
- var/time_left_in_seconds = (duration - world.time) / 10
+ var/time_left_in_seconds = duration / 10
owner.do_jitter_animation(time_left_in_seconds)
/// Helper proc that causes the mob to do a jittering animation by jitter_amount.
diff --git a/code/datums/status_effects/debuffs/screen_blur.dm b/code/datums/status_effects/debuffs/screen_blur.dm
index acdce13b5a0..ee893610c12 100644
--- a/code/datums/status_effects/debuffs/screen_blur.dm
+++ b/code/datums/status_effects/debuffs/screen_blur.dm
@@ -49,7 +49,7 @@
game_plane_master_controller.remove_filter("eye_blur")
return
- var/time_left_in_seconds = (duration - world.time) / (1 SECONDS)
+ var/time_left_in_seconds = duration / 10
var/amount_of_blur = clamp(time_left_in_seconds * BLUR_DURATION_TO_INTENSITY, 0.6, 3)
game_plane_master_controller.add_filter("eye_blur", 1, gauss_blur_filter(amount_of_blur))
diff --git a/code/datums/status_effects/debuffs/staggered.dm b/code/datums/status_effects/debuffs/staggered.dm
index 9919a156c31..4d640b64331 100644
--- a/code/datums/status_effects/debuffs/staggered.dm
+++ b/code/datums/status_effects/debuffs/staggered.dm
@@ -51,7 +51,7 @@
/datum/status_effect/dazed
id = "dazed"
status_type = STATUS_EFFECT_UNIQUE
- tick_interval = 0.5 SECONDS
+ tick_interval = 0.6 SECONDS
alert_type = null
remove_on_fullheal = TRUE
/// Our visual cue for the vulnerable state this status effect puts us in.
@@ -121,9 +121,9 @@
/// Only applied by shoving someone to paralyze them
/datum/status_effect/no_side_kick
id = "no side kick"
- duration = 3.5 SECONDS
+ duration = 3.6 SECONDS
status_type = STATUS_EFFECT_UNIQUE
- tick_interval = 0.5 SECONDS
+ tick_interval = 0.6 SECONDS
alert_type = null
remove_on_fullheal = TRUE
diff --git a/code/datums/status_effects/stacking_effect.dm b/code/datums/status_effects/stacking_effect.dm
index 287419028b0..327c614f8de 100644
--- a/code/datums/status_effects/stacking_effect.dm
+++ b/code/datums/status_effects/stacking_effect.dm
@@ -123,7 +123,7 @@
on_threshold_drop()
if(stacks_added > 0)
- tick_interval += delay_before_decay // refreshes time until decay
+ time_until_next_tick += delay_before_decay // refreshes time until decay
if (status_overlay)
status_overlay.icon_state = "[overlay_state][stacks]"
diff --git a/code/modules/antagonists/changeling/powers/darkness_adaptation.dm b/code/modules/antagonists/changeling/powers/darkness_adaptation.dm
index 47fe31c215b..4d8e8a7e474 100644
--- a/code/modules/antagonists/changeling/powers/darkness_adaptation.dm
+++ b/code/modules/antagonists/changeling/powers/darkness_adaptation.dm
@@ -51,7 +51,7 @@
/// Makes the user harder to see in the dark (and makes the user see in the dark easier)
/datum/status_effect/darkness_adapted
id = "darkness_adapted"
- tick_interval = 0.5 SECONDS
+ tick_interval = 0.6 SECONDS
alert_type = null
/// Threshold before the dark color is applied
var/dark_color_threshold = 70
diff --git a/code/modules/antagonists/heretic/magic/fire_blast.dm b/code/modules/antagonists/heretic/magic/fire_blast.dm
index 873f131c28f..36ed3b4caab 100644
--- a/code/modules/antagonists/heretic/magic/fire_blast.dm
+++ b/code/modules/antagonists/heretic/magic/fire_blast.dm
@@ -157,7 +157,7 @@
id = "fire_blasted"
alert_type = null
duration = 5 SECONDS
- tick_interval = 0.5 SECONDS
+ tick_interval = 0.6 SECONDS
/// How much fire / stam to do per tick (stamina damage is doubled this)
var/tick_damage = 1
/// How long does the animation of the appearance last? If 0 or negative, we make no overlay
diff --git a/code/modules/mining/lavaland/cain_and_abel/dagger_status_effects.dm b/code/modules/mining/lavaland/cain_and_abel/dagger_status_effects.dm
index 0f535f31951..a6cb6c04e67 100644
--- a/code/modules/mining/lavaland/cain_and_abel/dagger_status_effects.dm
+++ b/code/modules/mining/lavaland/cain_and_abel/dagger_status_effects.dm
@@ -1,8 +1,8 @@
///status effect applied to us when we're wildly swinging
/datum/status_effect/dagger_swinging
id = "dagger swinging"
- tick_interval = 0.25 SECONDS
- duration = 1.75 SECONDS
+ tick_interval = 0.2 SECONDS
+ duration = 1.6 SECONDS
alert_type = null
///base damage we apply to mobs near us
var/base_damage = 5
diff --git a/code/modules/mob/living/basic/farm_animals/goose/goose_vomit.dm b/code/modules/mob/living/basic/farm_animals/goose/goose_vomit.dm
index 2b347903e22..2d3f2b6df20 100644
--- a/code/modules/mob/living/basic/farm_animals/goose/goose_vomit.dm
+++ b/code/modules/mob/living/basic/farm_animals/goose/goose_vomit.dm
@@ -124,7 +124,7 @@
/// Stop fucking around and get the rest of it out
/datum/status_effect/goose_vomit/proc/vomit_finale()
- tick_interval = 0.1 SECONDS
+ tick_interval = 0.2 SECONDS
owner.set_jitter_if_lower(1 SECONDS)
hurl_item(vomit_strongly = TRUE)
@@ -176,7 +176,7 @@
/datum/status_effect/goose_choking/on_remove()
UnregisterSignal(owner, COMSIG_LIVING_DEATH)
- if (duration >= world.time)
+ if (duration > 0)
return // Saved by something, although probably by dying early
owner.death_message = "lets out one final oxygen-deprived honk before [owner.p_they()] go[owner.p_es()] limp and lifeless.."
owner.death()
diff --git a/code/modules/mob/living/status_procs.dm b/code/modules/mob/living/status_procs.dm
index 58677d64bef..867c975ad21 100644
--- a/code/modules/mob/living/status_procs.dm
+++ b/code/modules/mob/living/status_procs.dm
@@ -36,7 +36,7 @@
/mob/living/proc/AmountStun() //How many deciseconds remain in our stun
var/datum/status_effect/incapacitating/stun/S = IsStun()
if(S)
- return S.duration - world.time
+ return S.duration
return 0
/mob/living/proc/Stun(amount, ignore_canstun = FALSE) //Can't go below remaining duration
@@ -46,7 +46,7 @@
return
var/datum/status_effect/incapacitating/stun/S = IsStun()
if(S)
- S.duration = max(world.time + amount, S.duration)
+ S.duration = max(amount, S.duration)
else if(amount > 0)
S = apply_status_effect(/datum/status_effect/incapacitating/stun, amount)
return S
@@ -62,7 +62,7 @@
qdel(S)
else
if(S)
- S.duration = world.time + amount
+ S.duration = amount
else
S = apply_status_effect(/datum/status_effect/incapacitating/stun, amount)
return S
@@ -86,7 +86,7 @@
/mob/living/proc/AmountKnockdown() //How many deciseconds remain in our knockdown
var/datum/status_effect/incapacitating/knockdown/K = IsKnockdown()
if(K)
- return K.duration - world.time
+ return K.duration
return 0
/mob/living/proc/Knockdown(amount, daze_amount = 0, ignore_canstun = FALSE) //Can't go below remaining duration
@@ -96,7 +96,7 @@
return
var/datum/status_effect/incapacitating/knockdown/K = IsKnockdown()
if(K)
- K.duration = max(world.time + amount, K.duration)
+ K.duration = max(amount, K.duration)
else if(amount > 0)
K = apply_status_effect(/datum/status_effect/incapacitating/knockdown, amount)
if(daze_amount > 0)
@@ -114,7 +114,7 @@
qdel(K)
else
if(K)
- K.duration = world.time + amount
+ K.duration = amount
else
K = apply_status_effect(/datum/status_effect/incapacitating/knockdown, amount)
return K
@@ -140,7 +140,7 @@
/mob/living/proc/AmountImmobilized() //How many deciseconds remain in our Immobilized status effect
var/datum/status_effect/incapacitating/immobilized/I = IsImmobilized()
if(I)
- return I.duration - world.time
+ return I.duration
return 0
/mob/living/proc/Immobilize(amount, ignore_canstun = FALSE) //Can't go below remaining duration
@@ -150,7 +150,7 @@
return
var/datum/status_effect/incapacitating/immobilized/I = IsImmobilized()
if(I)
- I.duration = max(world.time + amount, I.duration)
+ I.duration = max(amount, I.duration)
else if(amount > 0)
I = apply_status_effect(/datum/status_effect/incapacitating/immobilized, amount)
return I
@@ -166,7 +166,7 @@
qdel(I)
else
if(I)
- I.duration = world.time + amount
+ I.duration = amount
else
I = apply_status_effect(/datum/status_effect/incapacitating/immobilized, amount)
return I
@@ -190,7 +190,7 @@
/mob/living/proc/AmountParalyzed() //How many deciseconds remain in our Paralyzed status effect
var/datum/status_effect/incapacitating/paralyzed/P = IsParalyzed(FALSE)
if(P)
- return P.duration - world.time
+ return P.duration
return 0
/mob/living/proc/Paralyze(amount, ignore_canstun = FALSE) //Can't go below remaining duration
@@ -200,7 +200,7 @@
return
var/datum/status_effect/incapacitating/paralyzed/P = IsParalyzed(FALSE)
if(P)
- P.duration = max(world.time + amount, P.duration)
+ P.duration = max(amount, P.duration)
else if(amount > 0)
P = apply_status_effect(/datum/status_effect/incapacitating/paralyzed, amount)
return P
@@ -216,7 +216,7 @@
qdel(P)
else
if(P)
- P.duration = world.time + amount
+ P.duration = amount
else
P = apply_status_effect(/datum/status_effect/incapacitating/paralyzed, amount)
return P
@@ -240,7 +240,7 @@
/mob/living/proc/amount_incapacitated()
var/datum/status_effect/incapacitating/incapacitated/incapacitated_status_effect = has_status_effect(/datum/status_effect/incapacitating/incapacitated)
if (incapacitated_status_effect)
- return incapacitated_status_effect.duration - world.time
+ return incapacitated_status_effect.duration
else
return 0
@@ -256,7 +256,7 @@
return
var/datum/status_effect/incapacitating/incapacitated/incapacitated_status_effect = has_status_effect(/datum/status_effect/incapacitating/incapacitated)
if(incapacitated_status_effect)
- incapacitated_status_effect.duration = max(world.time + amount, incapacitated_status_effect.duration)
+ incapacitated_status_effect.duration = max(amount, incapacitated_status_effect.duration)
else if(amount > 0)
incapacitated_status_effect = apply_status_effect(/datum/status_effect/incapacitating/incapacitated, amount)
return incapacitated_status_effect
@@ -278,7 +278,7 @@
qdel(incapacitated_status_effect)
else
if(incapacitated_status_effect)
- incapacitated_status_effect.duration = world.time + amount
+ incapacitated_status_effect.duration = amount
else
incapacitated_status_effect = apply_status_effect(/datum/status_effect/incapacitating/incapacitated, amount)
return incapacitated_status_effect
@@ -333,7 +333,7 @@
/mob/living/proc/AmountUnconscious() //How many deciseconds remain in our unconsciousness
var/datum/status_effect/incapacitating/unconscious/U = IsUnconscious()
if(U)
- return U.duration - world.time
+ return U.duration
return 0
/mob/living/proc/Unconscious(amount, ignore_canstun = FALSE) //Can't go below remaining duration
@@ -343,7 +343,7 @@
return
var/datum/status_effect/incapacitating/unconscious/U = IsUnconscious()
if(U)
- U.duration = max(world.time + amount, U.duration)
+ U.duration = max(amount, U.duration)
else if(amount > 0)
U = apply_status_effect(/datum/status_effect/incapacitating/unconscious, amount)
return U
@@ -358,7 +358,7 @@
if(U)
qdel(U)
else if(U)
- U.duration = world.time + amount
+ U.duration = amount
else
U = apply_status_effect(/datum/status_effect/incapacitating/unconscious, amount)
return U
@@ -383,7 +383,7 @@
/mob/living/proc/AmountSleeping() //How many deciseconds remain in our sleep
var/datum/status_effect/incapacitating/sleeping/S = IsSleeping()
if(S)
- return S.duration - world.time
+ return S.duration
return 0
/mob/living/proc/Sleeping(amount) //Can't go below remaining duration
@@ -393,7 +393,7 @@
return
var/datum/status_effect/incapacitating/sleeping/S = IsSleeping()
if(S)
- S.duration = max(world.time + amount, S.duration)
+ S.duration = max(amount, S.duration)
else if(amount > 0)
S = apply_status_effect(/datum/status_effect/incapacitating/sleeping, amount)
return S
@@ -408,7 +408,7 @@
if(S)
qdel(S)
else if(S)
- S.duration = world.time + amount
+ S.duration = amount
else
S = apply_status_effect(/datum/status_effect/incapacitating/sleeping, amount)
return S
@@ -622,13 +622,12 @@
if(isnum(max_duration) && duration > 0)
// Check the duration remaining on the existing status effect
// If it's greater than / equal to our passed max duration, we don't need to do anything
- var/remaining_duration = existing.duration - world.time
- if(remaining_duration >= max_duration)
+ if(existing.duration >= max_duration)
return
// Otherwise, add duration up to the max (max_duration - remaining_duration),
// or just add duration if it doesn't exceed our max at all
- existing.duration += min(max_duration - remaining_duration, duration)
+ existing.duration += min(max_duration - existing.duration, duration)
else
existing.duration += duration
@@ -636,7 +635,7 @@
// If the duration was decreased and is now less 0 seconds,
// qdel it / clean up the status effect immediately
// (rather than waiting for the process tick to handle it)
- if(existing.duration <= world.time)
+ if(existing.duration <= 0)
qdel(existing)
else if(duration > 0)
@@ -669,12 +668,11 @@
if(only_if_higher)
// If the existing status effect has a higher remaining duration
// than what we aim to set it to, don't downgrade it - do nothing (return)
- var/remaining_duration = existing.duration - world.time
- if(remaining_duration >= duration)
+ if(existing.duration >= duration)
return
// Set the duration accordingly
- existing.duration = world.time + duration
+ existing.duration = duration
else if(duration > 0)
apply_status_effect(effect, duration)
@@ -697,7 +695,7 @@
if(existing.duration == STATUS_EFFECT_PERMANENT)
return INFINITY
- return existing.duration - world.time
+ return existing.duration
/**
* Adjust the "drunk value" the mob is currently experiencing,
diff --git a/code/modules/projectiles/ammunition/ballistic/rifle.dm b/code/modules/projectiles/ammunition/ballistic/rifle.dm
index 2ec850950b0..ab4e38dbb95 100644
--- a/code/modules/projectiles/ammunition/ballistic/rifle.dm
+++ b/code/modules/projectiles/ammunition/ballistic/rifle.dm
@@ -154,7 +154,7 @@
if (can_sleep && (owner.mob_biotypes & MOB_ORGANIC))
owner.adjust_drowsiness(drowsy_per_second * seconds_per_tick)
var/datum/status_effect/drowsiness/drowsiness = owner.has_status_effect(/datum/status_effect/drowsiness)
- if (drowsiness?.duration - world.time >= drowsy_knockout)
+ if (drowsiness?.duration >= drowsy_knockout)
owner.Sleeping(3 SECONDS)
if (casing.heals_left <= 0)
fall_out()
diff --git a/code/modules/spells/spell_types/cone/cone_of_cold.dm b/code/modules/spells/spell_types/cone/cone_of_cold.dm
index 9327e2c2fad..3b8f880a842 100644
--- a/code/modules/spells/spell_types/cone/cone_of_cold.dm
+++ b/code/modules/spells/spell_types/cone/cone_of_cold.dm
@@ -50,7 +50,7 @@
if(ispath(frozen_status_effect_path) && unfreeze_mob_duration > 0 SECONDS) // 0 duration = don't apply the status effect
var/datum/status_effect/freeze = target_mob.apply_status_effect(frozen_status_effect_path)
if(unfreeze_mob_duration != INFINITY)
- freeze.duration = world.time + unfreeze_mob_duration
+ freeze.duration = unfreeze_mob_duration
if(on_freeze_brute_damage || on_freeze_burn_damage)
target_mob.take_overall_damage(on_freeze_brute_damage, on_freeze_burn_damage)
diff --git a/code/modules/unit_tests/burning.dm b/code/modules/unit_tests/burning.dm
index daf99875f28..a23d5423c27 100644
--- a/code/modules/unit_tests/burning.dm
+++ b/code/modules/unit_tests/burning.dm
@@ -10,8 +10,8 @@
TEST_ASSERT(dummy.on_fire, "Dummy is not on fire despite having 20 fire stacks and being ignited.")
// Manually tick it a few times
var/datum/status_effect/fire_handler/fire_stacks/handler = locate() in dummy.status_effects
+ handler.tick_interval = STATUS_EFFECT_AUTO_TICK
for(var/i in 1 to 5)
- handler.tick_interval = world.time - 1
- handler.process()
+ handler.process(1)
TEST_ASSERT(dummy.fire_stacks < 20, "Dummy should have decayed firestacks, but did not. (Dummy stacks: [dummy.fire_stacks]).")
TEST_ASSERT(dummy.bodytemperature > initial_temp, "Dummy did not heat up despite being on fire. (Dummy temp: [dummy.bodytemperature], initial temp: [initial_temp])")
diff --git a/code/modules/unit_tests/mob_damage.dm b/code/modules/unit_tests/mob_damage.dm
index 1cc63466bc9..5567e3aa454 100644
--- a/code/modules/unit_tests/mob_damage.dm
+++ b/code/modules/unit_tests/mob_damage.dm
@@ -608,7 +608,7 @@
TEST_ASSERT_NOTNULL(tox_effect, "Dummy didn't get tox_vomit status effect despite at [dummy.getToxLoss()] toxin damage (Method: SET)!")
// Clear the toxin damage away, and force a status effect tick: It should delete itself
dummy.setToxLoss(0)
- tox_effect.tick(initial(tox_effect.tick_interval))
+ tox_effect.tick(tox_effect.tick_interval)
TEST_ASSERT(QDELETED(tox_effect), "Dummy still has tox_vomit status effect despite at [dummy.getToxLoss()] toxin damage (Method: SET)!")
// Test another method of gaining tox damage, use an entirely clean slate just to be sure
var/mob/living/carbon/human/dummy_two = allocate(/mob/living/carbon/human/consistent)
diff --git a/code/modules/unit_tests/status_effect_validity.dm b/code/modules/unit_tests/status_effect_validity.dm
index 44c7b391610..e9c7cd70c90 100644
--- a/code/modules/unit_tests/status_effect_validity.dm
+++ b/code/modules/unit_tests/status_effect_validity.dm
@@ -8,23 +8,95 @@
var/tick_speed = initial(checking.tick_interval)
if(tick_speed == STATUS_EFFECT_NO_TICK)
continue
+ if(tick_speed < 0)
+ TEST_FAIL("Status effect [checking] has tick_interval set to a negative value other than STATUS_EFFECT_NO_TICK, this is not how you prevent ticks - use tick_interval = STATUS_EFFECT_NO_TICK instead.")
+ continue
if(tick_speed == INFINITY)
TEST_FAIL("Status effect [checking] has tick_interval set to INFINITY, this is not how you prevent ticks - use tick_interval = STATUS_EFFECT_NO_TICK instead.")
continue
switch(initial(checking.processing_speed))
if(STATUS_EFFECT_FAST_PROCESS)
- if(tick_speed < SSfastprocess.wait && tick_speed != STATUS_EFFECT_AUTO_TICK)
- TEST_FAIL("Status effect [checking] has tick_interval set to [tick_speed], which is faster than SSfastprocess can tick ([SSfastprocess.wait]).")
+ if(tick_speed % SSfastprocess.wait != 0 && tick_speed != STATUS_EFFECT_AUTO_TICK)
+ TEST_FAIL("Status effect [checking] has tick_interval set to [tick_speed], which is not a multiple of SSfastprocess wait time ([SSfastprocess.wait]).")
if(STATUS_EFFECT_NORMAL_PROCESS)
- if(tick_speed < SSprocessing.wait && tick_speed != STATUS_EFFECT_AUTO_TICK)
- TEST_FAIL("Status effect [checking] has tick_interval set to [tick_speed], which is faster than SSprocessing can tick ([SSprocessing.wait]).")
+ if(tick_speed % SSprocessing.wait != 0 && tick_speed != STATUS_EFFECT_AUTO_TICK)
+ TEST_FAIL("Status effect [checking] has tick_interval set to [tick_speed], which is not a multiple of SSprocessing wait time ([SSprocessing.wait]).")
if(STATUS_EFFECT_PRIORITY)
var/priority_wait = world.tick_lag * SSpriority_effects.wait // SSpriority_effects has the SS_TICKER flag, so its wait is in ticks, so we have to convert it to deciseconds.
- if(tick_speed < priority_wait && tick_speed != STATUS_EFFECT_AUTO_TICK)
- TEST_FAIL("Status effect [checking] has tick_interval set to [tick_speed], which is faster than SSpriority_effects can tick ([priority_wait]).")
+ if(tick_speed % priority_wait != 0 && tick_speed != STATUS_EFFECT_AUTO_TICK)
+ TEST_FAIL("Status effect [checking] has tick_interval set to [tick_speed], which is not a multiple of SSpriority_effects wait time ([priority_wait]).")
else
TEST_FAIL("Invalid processing speed for status effect [checking] : [initial(checking.processing_speed)]")
+/// Validates status effect duration setup
+/datum/unit_test/status_effect_duration
+
+/datum/unit_test/status_effect_duration/Run()
+ for(var/datum/status_effect/checking as anything in subtypesof(/datum/status_effect))
+ if(initial(checking.id) == STATUS_EFFECT_ID_ABSTRACT)
+ continue
+ var/duration = initial(checking.duration)
+ if(duration == STATUS_EFFECT_PERMANENT)
+ continue
+ if(duration == INFINITY) // for some god forsaken reason, this is allowed
+ continue
+ if(duration < 0)
+ TEST_FAIL("Status effect [checking] has duration set to a negative value other than STATUS_EFFECT_PERMANENT, this is not how you make effects last forever - use duration = STATUS_EFFECT_PERMANENT instead.")
+ continue
+ switch(initial(checking.processing_speed))
+ if(STATUS_EFFECT_FAST_PROCESS)
+ if(duration % SSfastprocess.wait != 0)
+ TEST_FAIL("Status effect [checking] has duration set to [duration], which is not a multiple of SSfastprocess wait time ([SSfastprocess.wait]).")
+ if(STATUS_EFFECT_NORMAL_PROCESS)
+ if(duration % SSprocessing.wait != 0)
+ TEST_FAIL("Status effect [checking] has duration set to [duration], which is not a multiple of SSprocessing wait time ([SSprocessing.wait]).")
+ if(STATUS_EFFECT_PRIORITY)
+ var/priority_wait = world.tick_lag * SSpriority_effects.wait // SSpriority_effects has the SS_TICKER flag, so its wait is in ticks, so we have to convert it to deciseconds.
+ if(duration % priority_wait != 0)
+ TEST_FAIL("Status effect [checking] has duration set to [duration], which is not a multiple of SSpriority_effects wait time ([priority_wait]).")
+ else
+ TEST_FAIL("Invalid processing speed for status effect [checking] : [initial(checking.processing_speed)]")
+
+/// Validates that status effect tick counts are directly proportional to duration, and that seconds_between_ticks added up is equal to duration.
+/datum/unit_test/status_effect_tick_counts
+
+/datum/unit_test/status_effect_tick_counts/Run()
+ var/mob/living/carbon/human/user = allocate(/mob/living/carbon/human/consistent, run_loc_floor_bottom_left)
+
+ var/datum/status_effect/unit_test_tick_counter/counter = user.apply_status_effect(/datum/status_effect/unit_test_tick_counter)
+
+ // The 0.2 here and in the for loop is arbitrary and can be any value that divides evenly into the duration and tick interval of the unit test status effect.
+ // I chose 0.2 specifically because it just happens to be the SSfastprocess.wait in seconds, which basically simulates this status effect running on SSfastprocess.
+ var/ticks_required = counter.duration / 10 / 0.2 + 1
+
+ for (var/i in 1 to ticks_required)
+ if (!QDELETED(counter))
+ counter.process(0.2)
+
+ var/expected_tick_count = initial(counter.duration) / counter.tick_interval
+ if (abs(counter.total_tick_count - expected_tick_count) > 0.01)
+ TEST_FAIL("Status effect tick count is not directly proportional to duration. Expected [expected_tick_count] ticks, got [counter.total_tick_count] ticks.")
+
+ var/expected_seconds = initial(counter.duration) / 10
+ if (abs(counter.total_seconds - expected_seconds) > 0.01)
+ TEST_FAIL("Status effect seconds_between_ticks accumulated together does not equal duration. Expected [expected_seconds] seconds, got [counter.total_seconds] seconds.")
+
+ QDEL_NULL(counter)
+
+/datum/status_effect/unit_test_tick_counter
+ duration = 10 SECONDS
+ tick_interval = 0.4 SECONDS
+
+ id = "unit_test_tick_counter"
+ alert_type = null
+
+ var/total_tick_count = 0
+ var/total_seconds = 0
+
+/datum/status_effect/unit_test_tick_counter/tick(seconds_between_ticks)
+ total_tick_count++
+ total_seconds += seconds_between_ticks
+
/// Validates status effect alert type setup
/datum/unit_test/status_effect_alert