diff --git a/code/__DEFINES/status_effects.dm b/code/__DEFINES/status_effects.dm index 756d78c1723..36429737210 100644 --- a/code/__DEFINES/status_effects.dm +++ b/code/__DEFINES/status_effects.dm @@ -12,6 +12,11 @@ /// Use in status effect "tick_interval" to prevent it from calling tick() #define STATUS_EFFECT_NO_TICK -1 +/// Indicates this status effect is an abstract type, ie not instantiated +/// Doesn't actually do anything in practice, primarily just a marker / used in unit tests, +/// so don't worry if your abstract status effect doesn't actually set this +#define STATUS_EFFECT_ID_ABSTRACT "abstract" + ///Processing flags - used to define the speed at which the status will work ///This is fast - 0.2s between ticks (I believe!) #define STATUS_EFFECT_FAST_PROCESS 0 diff --git a/code/datums/quirks/positive_quirks/chipped.dm b/code/datums/quirks/positive_quirks/chipped.dm index 474e8a4adcd..26b4883f9b3 100644 --- a/code/datums/quirks/positive_quirks/chipped.dm +++ b/code/datums/quirks/positive_quirks/chipped.dm @@ -68,6 +68,7 @@ id = "itchy skillchip" tick_interval_lowerbound = 5 SECONDS tick_interval_upperbound = 10 MINUTES + alert_type = null ///lower damage we apply to our itchy owner var/minimum_damage = 1 ///upper damage we apply to our itchy owner diff --git a/code/datums/status_effects/buffs.dm b/code/datums/status_effects/buffs.dm index a24e8d4ccda..e4471f2f4db 100644 --- a/code/datums/status_effects/buffs.dm +++ b/code/datums/status_effects/buffs.dm @@ -406,6 +406,7 @@ /datum/status_effect/mayhem id = "Mayhem" duration = 2 MINUTES + alert_type = null /// The chainsaw spawned by the status effect var/obj/item/chainsaw/doomslayer/chainsaw @@ -450,6 +451,7 @@ duration = 2 SECONDS status_type = STATUS_EFFECT_REPLACE show_duration = TRUE + alert_type = null /datum/status_effect/speed_boost/on_creation(mob/living/new_owner, set_duration) if(isnum(set_duration)) @@ -595,6 +597,7 @@ id = "radiation_immunity" duration = 1 MINUTES show_duration = TRUE + alert_type = null /datum/status_effect/radiation_immunity/on_apply() ADD_TRAIT(owner, TRAIT_RADIMMUNE, type) diff --git a/code/datums/status_effects/debuffs/debuffs.dm b/code/datums/status_effects/debuffs/debuffs.dm index 02fe573ef36..b9b56161e84 100644 --- a/code/datums/status_effects/debuffs/debuffs.dm +++ b/code/datums/status_effects/debuffs/debuffs.dm @@ -8,6 +8,7 @@ //Largely negative status effects go here, even if they have small beneficial effects //STUN EFFECTS /datum/status_effect/incapacitating + id = STATUS_EFFECT_ID_ABSTRACT tick_interval = STATUS_EFFECT_NO_TICK status_type = STATUS_EFFECT_REPLACE alert_type = null @@ -967,6 +968,7 @@ duration = 10 SECONDS status_type = STATUS_EFFECT_REPLACE tick_interval = 0.2 SECONDS + alert_type = null /datum/status_effect/teleport_madness/tick(seconds_between_ticks) dump_in_space(owner) diff --git a/code/datums/status_effects/debuffs/drunk.dm b/code/datums/status_effects/debuffs/drunk.dm index 706ab36fcff..37ab11f130c 100644 --- a/code/datums/status_effects/debuffs/drunk.dm +++ b/code/datums/status_effects/debuffs/drunk.dm @@ -15,6 +15,7 @@ tick_interval = 2 SECONDS status_type = STATUS_EFFECT_REPLACE remove_on_fullheal = TRUE + alert_type = null /// The level of drunkness we are currently at. var/drunk_value = 0 diff --git a/code/datums/status_effects/debuffs/fire_stacks.dm b/code/datums/status_effects/debuffs/fire_stacks.dm index 648f09f31e9..4b071d87e21 100644 --- a/code/datums/status_effects/debuffs/fire_stacks.dm +++ b/code/datums/status_effects/debuffs/fire_stacks.dm @@ -1,5 +1,6 @@ /datum/status_effect/fire_handler duration = STATUS_EFFECT_PERMANENT + id = STATUS_EFFECT_ID_ABSTRACT alert_type = null status_type = STATUS_EFFECT_REFRESH //Custom code on_remove_on_mob_delete = TRUE diff --git a/code/datums/status_effects/debuffs/screwy_hud.dm b/code/datums/status_effects/debuffs/screwy_hud.dm index 2e8fc566cf4..10c20112160 100644 --- a/code/datums/status_effects/debuffs/screwy_hud.dm +++ b/code/datums/status_effects/debuffs/screwy_hud.dm @@ -8,6 +8,7 @@ * accidentally removing another source's hud. */ /datum/status_effect/grouped/screwy_hud + id = STATUS_EFFECT_ID_ABSTRACT alert_type = null /// The priority of this screwyhud over other screwyhuds. var/priority = -1 diff --git a/code/datums/status_effects/debuffs/spacer.dm b/code/datums/status_effects/debuffs/spacer.dm index 1add806c02f..ed14fd28596 100644 --- a/code/datums/status_effects/debuffs/spacer.dm +++ b/code/datums/status_effects/debuffs/spacer.dm @@ -3,6 +3,7 @@ /datum/status_effect/spacer id = "spacer_gravity_effects" status_type = STATUS_EFFECT_REPLACE + alert_type = null /// Essentially, tracks whether this is a planetary map. /// It'd be pretty miserable if you're playing a planetary map and getting the worse of all effects, so we handwave it a bit. VAR_FINAL/nerfed_effects_because_planetary = FALSE diff --git a/code/datums/status_effects/debuffs/speech_debuffs.dm b/code/datums/status_effects/debuffs/speech_debuffs.dm index a557f7ddd4d..1ba85ebe72f 100644 --- a/code/datums/status_effects/debuffs/speech_debuffs.dm +++ b/code/datums/status_effects/debuffs/speech_debuffs.dm @@ -1,5 +1,5 @@ /datum/status_effect/speech - id = null + id = STATUS_EFFECT_ID_ABSTRACT alert_type = null remove_on_fullheal = TRUE tick_interval = STATUS_EFFECT_NO_TICK diff --git a/code/datums/status_effects/debuffs/stamcrit.dm b/code/datums/status_effects/debuffs/stamcrit.dm index 74c3fde12f5..0d4a844a61e 100644 --- a/code/datums/status_effects/debuffs/stamcrit.dm +++ b/code/datums/status_effects/debuffs/stamcrit.dm @@ -1,4 +1,5 @@ /datum/status_effect/incapacitating/stamcrit + id = "stamcrit" status_type = STATUS_EFFECT_UNIQUE // Lasts until we go back to 0 stamina, which is handled by the mob duration = STATUS_EFFECT_PERMANENT diff --git a/code/datums/status_effects/grouped_effect.dm b/code/datums/status_effects/grouped_effect.dm index 601945b83aa..27b37af1e35 100644 --- a/code/datums/status_effects/grouped_effect.dm +++ b/code/datums/status_effects/grouped_effect.dm @@ -1,5 +1,7 @@ /// Status effect from multiple sources, when all sources are removed, so is the effect /datum/status_effect/grouped + id = STATUS_EFFECT_ID_ABSTRACT + alert_type = null // Grouped effects adds itself to [var/sources] and destroys itself if one exists already, there are never actually multiple status_type = STATUS_EFFECT_MULTIPLE /// A list of all sources applying this status effect. Sources are a list of keys diff --git a/code/datums/status_effects/limited_effect.dm b/code/datums/status_effects/limited_effect.dm index b577248d35e..047a7a5ae07 100644 --- a/code/datums/status_effects/limited_effect.dm +++ b/code/datums/status_effects/limited_effect.dm @@ -3,6 +3,7 @@ id = "limited_buff" duration = STATUS_EFFECT_PERMANENT status_type = STATUS_EFFECT_REFRESH + alert_type = null ///How many stacks we currently have var/stacks = 1 ///How many stacks we can have maximum diff --git a/code/datums/status_effects/neutral.dm b/code/datums/status_effects/neutral.dm index 43c4ad7a3f0..23db827daad 100644 --- a/code/datums/status_effects/neutral.dm +++ b/code/datums/status_effects/neutral.dm @@ -110,6 +110,7 @@ /datum/status_effect/bounty id = "bounty" status_type = STATUS_EFFECT_UNIQUE + alert_type = null var/mob/living/rewarded /datum/status_effect/bounty/on_creation(mob/living/new_owner, mob/living/caster) @@ -581,6 +582,7 @@ id = "tinea_luxor_light" processing_speed = STATUS_EFFECT_NORMAL_PROCESS remove_on_fullheal = TRUE + alert_type = null var/obj/effect/dummy/lighting_obj/moblight/mob_light_obj /datum/status_effect/tinlux_light/on_creation(mob/living/new_owner, duration) diff --git a/code/datums/status_effects/stacking_effect.dm b/code/datums/status_effects/stacking_effect.dm index 3ed7846f6ff..acdefd8290c 100644 --- a/code/datums/status_effects/stacking_effect.dm +++ b/code/datums/status_effects/stacking_effect.dm @@ -1,7 +1,7 @@ /// Status effects that can stack. /datum/status_effect/stacking - id = "stacking_base" + id = STATUS_EFFECT_ID_ABSTRACT duration = STATUS_EFFECT_PERMANENT // Only removed under specific conditions. tick_interval = 1 SECONDS // Deciseconds between decays, once decay starts alert_type = null diff --git a/code/modules/antagonists/heretic/magic/void_conduit.dm b/code/modules/antagonists/heretic/magic/void_conduit.dm index 8d2b193de29..16faf3b1a38 100644 --- a/code/modules/antagonists/heretic/magic/void_conduit.dm +++ b/code/modules/antagonists/heretic/magic/void_conduit.dm @@ -116,13 +116,14 @@ falloff_exponent = 20 /datum/status_effect/void_conduit + id = "void_conduit" duration = 15 SECONDS status_type = STATUS_EFFECT_REPLACE alert_type = null /datum/status_effect/void_conduit/on_apply() - ADD_TRAIT(owner, TRAIT_RESISTLOWPRESSURE, "void_conduit") + ADD_TRAIT(owner, TRAIT_RESISTLOWPRESSURE, type) return TRUE /datum/status_effect/void_conduit/on_remove() - REMOVE_TRAIT(owner, TRAIT_RESISTLOWPRESSURE, "void_conduit") + REMOVE_TRAIT(owner, TRAIT_RESISTLOWPRESSURE, type) diff --git a/code/modules/antagonists/voidwalker/voidwalker_status_effects.dm b/code/modules/antagonists/voidwalker/voidwalker_status_effects.dm index 6b7f733265c..6fbe461543a 100644 --- a/code/modules/antagonists/voidwalker/voidwalker_status_effects.dm +++ b/code/modules/antagonists/voidwalker/voidwalker_status_effects.dm @@ -32,15 +32,15 @@ icon_state = "paralysis" /datum/status_effect/void_eatered + id = "void_eatered" duration = 10 SECONDS remove_on_fullheal = TRUE + alert_type = null /datum/status_effect/void_eatered/on_apply() . = ..() - - ADD_TRAIT(owner, TRAIT_NODEATH, REF(src)) + ADD_TRAIT(owner, TRAIT_NODEATH, type) /datum/status_effect/void_eatered/on_remove() . = ..() - - REMOVE_TRAIT(owner, TRAIT_NODEATH, REF(src)) + REMOVE_TRAIT(owner, TRAIT_NODEATH, type) diff --git a/code/modules/mob/living/basic/lavaland/basilisk/basilisk_overheat.dm b/code/modules/mob/living/basic/lavaland/basilisk/basilisk_overheat.dm index c0b49fbdc61..71e938c5164 100644 --- a/code/modules/mob/living/basic/lavaland/basilisk/basilisk_overheat.dm +++ b/code/modules/mob/living/basic/lavaland/basilisk/basilisk_overheat.dm @@ -2,6 +2,7 @@ /datum/status_effect/basilisk_overheat id = "basilisk_overheat" duration = 3 MINUTES + alert_type = null /// Things which will chill us out if we get hit by them var/static/list/chilling_reagents = list( /datum/reagent/medicine/cryoxadone, diff --git a/code/modules/mob/living/basic/space_fauna/revenant/revenant_effects.dm b/code/modules/mob/living/basic/space_fauna/revenant/revenant_effects.dm index b7bc6e34dcf..6b5f63bf00f 100644 --- a/code/modules/mob/living/basic/space_fauna/revenant/revenant_effects.dm +++ b/code/modules/mob/living/basic/space_fauna/revenant/revenant_effects.dm @@ -1,5 +1,7 @@ /// Parent type for all unique revenant status effects /datum/status_effect/revenant + id = STATUS_EFFECT_ID_ABSTRACT + alert_type = null /datum/status_effect/revenant/on_creation(mob/living/new_owner, duration) if(isnum(duration)) diff --git a/code/modules/unit_tests/_unit_tests.dm b/code/modules/unit_tests/_unit_tests.dm index e4f5300006b..4d16d24e9e9 100644 --- a/code/modules/unit_tests/_unit_tests.dm +++ b/code/modules/unit_tests/_unit_tests.dm @@ -288,7 +288,7 @@ #include "spritesheets.dm" #include "stack_singular_name.dm" #include "station_trait_tests.dm" -#include "status_effect_ticks.dm" +#include "status_effect_validity.dm" #include "stomach.dm" #include "storage.dm" #include "strange_reagent.dm" diff --git a/code/modules/unit_tests/status_effect_ticks.dm b/code/modules/unit_tests/status_effect_ticks.dm deleted file mode 100644 index d60ba187abc..00000000000 --- a/code/modules/unit_tests/status_effect_ticks.dm +++ /dev/null @@ -1,23 +0,0 @@ -/// Validates status effect tick interval setup -/datum/unit_test/status_effect_ticks - -/datum/unit_test/status_effect_ticks/Run() - for(var/datum/status_effect/checking as anything in subtypesof(/datum/status_effect)) - var/tick_speed = initial(checking.tick_interval) - if(tick_speed == STATUS_EFFECT_NO_TICK) - 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 - if(tick_speed == 0) - TEST_FAIL("Status effect [checking] has tick_interval set to 0, 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) - TEST_FAIL("Status effect [checking] has tick_interval set to [tick_speed], which is faster than SSfastprocess can tick ([SSfastprocess.wait]).") - if(STATUS_EFFECT_NORMAL_PROCESS) - if(tick_speed < SSprocessing.wait) - TEST_FAIL("Status effect [checking] has tick_interval set to [tick_speed], which is faster than SSprocessing can tick ([SSprocessing.wait]).") - else - TEST_FAIL("Invalid processing speed for status effect [checking] : [initial(checking.processing_speed)]") diff --git a/code/modules/unit_tests/status_effect_validity.dm b/code/modules/unit_tests/status_effect_validity.dm new file mode 100644 index 00000000000..76a367233fd --- /dev/null +++ b/code/modules/unit_tests/status_effect_validity.dm @@ -0,0 +1,61 @@ +/// Validates status effect tick interval setup +/datum/unit_test/status_effect_ticks + +/datum/unit_test/status_effect_ticks/Run() + for(var/datum/status_effect/checking as anything in subtypesof(/datum/status_effect)) + if(initial(checking.id) == STATUS_EFFECT_ID_ABSTRACT) + continue + var/tick_speed = initial(checking.tick_interval) + if(tick_speed == STATUS_EFFECT_NO_TICK) + 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 + if(tick_speed == 0) + TEST_FAIL("Status effect [checking] has tick_interval set to 0, 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) + TEST_FAIL("Status effect [checking] has tick_interval set to [tick_speed], which is faster than SSfastprocess can tick ([SSfastprocess.wait]).") + if(STATUS_EFFECT_NORMAL_PROCESS) + if(tick_speed < SSprocessing.wait) + TEST_FAIL("Status effect [checking] has tick_interval set to [tick_speed], which is faster than SSprocessing can tick ([SSprocessing.wait]).") + else + TEST_FAIL("Invalid processing speed for status effect [checking] : [initial(checking.processing_speed)]") + +/// Validates status effect alert type setup +/datum/unit_test/status_effect_alert + +/datum/unit_test/status_effect_alert/Run() + // The base typepath is used to indicate "I didn't set an alert type" + var/bad_alert_type = /datum/status_effect::alert_type + TEST_ASSERT_NOTNULL(bad_alert_type, "No alert type defined in /datum/status_effect - This test may be redundant now.") + + for(var/datum/status_effect/checking as anything in subtypesof(/datum/status_effect)) + if(initial(checking.id) == STATUS_EFFECT_ID_ABSTRACT) + continue + if(initial(checking.alert_type) != bad_alert_type) + continue + TEST_FAIL("[checking] has not set alert_type. If you don't want an alert, set alert_type = null - \ + Otherwise, give it an alert subtype.") + +/// Validates status effect id setup +/datum/unit_test/status_effect_ids + +/datum/unit_test/status_effect_ids/Run() + // The base id is used to indicate "I didn't set an id" + var/bad_id = /datum/status_effect::id + TEST_ASSERT_NOTNULL(bad_id, "No id defined in /datum/status_effect - This test may be redundant now.") + + for(var/datum/status_effect/checking as anything in subtypesof(/datum/status_effect)) + if(initial(checking.id) == STATUS_EFFECT_ID_ABSTRACT) + // we are just assuming that a child of an abstract should not be abstract. + // of course in practice, this may not always be the case - but if you're + // structuring a status effect like this, you can just change the parent id to anything else + var/datum/status_effect/checking_parent = initial(checking.parent_type) + if(initial(checking_parent.id) != STATUS_EFFECT_ID_ABSTRACT) + continue + if(initial(checking.id) != bad_id) + continue + TEST_FAIL("[checking] has not set an id. This is required for status effects.")