diff --git a/code/__DEFINES/status_effects.dm b/code/__DEFINES/status_effects.dm new file mode 100644 index 00000000000..b214077b684 --- /dev/null +++ b/code/__DEFINES/status_effects.dm @@ -0,0 +1,17 @@ + +//These are all the different status effects. Use the paths for each effect in the defines. + +#define BASIC_STATUS_EFFECT /datum/status_effect //Has no effect. + +/////////// +// BUFFS // +/////////// + +#define STATUS_EFFECT_SHADOW_MEND /datum/status_effect/shadow_mend //Quick, powerful heal that deals damage afterwards. Heals 15 brute/burn every second for 3 seconds. +#define STATUS_EFFECT_VOID_PRICE /datum/status_effect/void_price //The price of healing yourself with void energy. Deals 3 brute damage every 3 seconds for 30 seconds. + +#define STATUS_EFFECT_INATHNEQS_ENDOWMENT /datum/status_effect/inathneqs_endowment //A 15-second invulnerability and stun absorption, granted by Inath-neq. + +///////////// +// DEBUFFS // +///////////// diff --git a/code/_onclick/hud/alert.dm b/code/_onclick/hud/alert.dm index f4afbe8179e..60f0df97dc1 100644 --- a/code/_onclick/hud/alert.dm +++ b/code/_onclick/hud/alert.dm @@ -3,7 +3,7 @@ //PUBLIC - call these wherever you want -/mob/proc/throw_alert(category, type, severity, obj/new_master) +/mob/proc/throw_alert(category, type, severity, obj/new_master, datum/status_effect/effect) /* Proc to create or update an alert. Returns the alert if the alert is new or updated, 0 if it was thrown already category is a text string. Each mob may only have one alert per category; the previous one will be replaced @@ -43,7 +43,13 @@ alert.icon_state = "template" // We'll set the icon to the client's ui pref in reorganize_alerts() alert.master = new_master else - alert.icon_state = "[initial(alert.icon_state)][severity]" + if(effect) + alert.name = effect.name + alert.desc = effect.desc + alert.icon = 'icons/mob/status_effects.dmi' + alert.icon_state = effect.icon_state + else + alert.icon_state = "[initial(alert.icon_state)][severity]" alert.severity = severity alerts[category] = alert @@ -446,6 +452,7 @@ so as to remain in compliance with the most up-to-date laws." if(isliving(usr)) var/mob/living/L = usr return L.resist() + // PRIVATE = only edit, use, or override these if you're editing the system as a whole // Re-render all alerts - also called in /datum/hud/show_hud() because it's needed there diff --git a/code/controllers/subsystem/fastprocess.dm b/code/controllers/subsystem/fastprocess.dm deleted file mode 100644 index dfe0da21bc0..00000000000 --- a/code/controllers/subsystem/fastprocess.dm +++ /dev/null @@ -1,33 +0,0 @@ -var/datum/subsystem/fastprocess/SSfastprocess - -/datum/subsystem/fastprocess - name = "Fast Process" - priority = 25 - flags = SS_BACKGROUND|SS_POST_FIRE_TIMING|SS_NO_INIT - wait = 2 - - var/list/processing = list() - var/list/currentrun = list() - -/datum/subsystem/fastprocess/New() - NEW_SS_GLOBAL(SSfastprocess) - -/datum/subsystem/fastprocess/stat_entry() - ..("FP:[processing.len]") - - -/datum/subsystem/fastprocess/fire(resumed = 0) - if (!resumed) - src.currentrun = processing.Copy() - //cache for sanic speed (lists are references anyways) - var/list/currentrun = src.currentrun - - while(currentrun.len) - var/datum/thing = currentrun[currentrun.len] - currentrun.len-- - if(thing) - thing.process(wait) - else - SSfastprocess.processing -= thing - if (MC_TICK_CHECK) - return diff --git a/code/controllers/subsystem/processing/fastprocess.dm b/code/controllers/subsystem/processing/fastprocess.dm new file mode 100644 index 00000000000..7a46f253efe --- /dev/null +++ b/code/controllers/subsystem/processing/fastprocess.dm @@ -0,0 +1,10 @@ +//Fires five times every second. + +var/datum/subsystem/processing/fastprocess/SSfastprocess +/datum/subsystem/processing/fastprocess + name = "Fast Processing" + wait = 2 + stat_tag = "FP" + +/datum/subsystem/processing/fastprocess/New() + NEW_SS_GLOBAL(SSfastprocess) diff --git a/code/controllers/subsystem/objects.dm b/code/controllers/subsystem/processing/objects.dm similarity index 100% rename from code/controllers/subsystem/objects.dm rename to code/controllers/subsystem/processing/objects.dm diff --git a/code/controllers/subsystem/processing/processing.dm b/code/controllers/subsystem/processing/processing.dm new file mode 100644 index 00000000000..92540ba442f --- /dev/null +++ b/code/controllers/subsystem/processing/processing.dm @@ -0,0 +1,34 @@ +//Used to process objects. Fires once every second. + +var/datum/subsystem/processing/SSprocessing +/datum/subsystem/processing + name = "Processing" + priority = 25 + flags = SS_BACKGROUND|SS_POST_FIRE_TIMING|SS_NO_INIT + wait = 10 + + var/stat_tag = "P" //Used for logging + var/list/processing = list() + var/list/currentrun = list() + +/datum/subsystem/processing/New() + NEW_SS_GLOBAL(SSprocessing) + +/datum/subsystem/processing/stat_entry() + ..("[stat_tag]:[processing.len]") + +/datum/subsystem/processing/fire(resumed = 0) + if (!resumed) + currentrun = processing.Copy() + //cache for sanic speed (lists are references anyways) + var/list/current_run = currentrun + + while(current_run.len) + var/datum/thing = current_run[current_run.len] + current_run.len-- + if(thing) + thing.process(wait) + else + processing -= thing + if (MC_TICK_CHECK) + return diff --git a/code/datums/status_effects/buffs.dm b/code/datums/status_effects/buffs.dm new file mode 100644 index 00000000000..8a5a1543e84 --- /dev/null +++ b/code/datums/status_effects/buffs.dm @@ -0,0 +1,56 @@ +//Largely beneficial effects go here, even if they have drawbacks. An example is provided in Shadow Mend. + +/datum/status_effect/shadow_mend + name = "Shadow Mend" + desc = "Shadowy energies wrap around your wounds, sealing them at a price. After healing, you will slowly lose health every three seconds for thirty seconds." + id = "shadow_mend" + icon_state = "shadow_mend" + duration = 3 + +/datum/status_effect/shadow_mend/on_apply() + owner.visible_message("Violet light wraps around [owner]'s body!", "Violet light wraps around your body!") + playsound(owner, 'sound/magic/Teleport_app.ogg', 50, 1) + +/datum/status_effect/shadow_mend/tick() + owner.adjustBruteLoss(-15) + owner.adjustFireLoss(-15) + +/datum/status_effect/shadow_mend/on_remove() + owner.visible_message("The violet light around [owner] glows black!", "The tendrils around you cinch tightly and reap their toll...") + playsound(owner, 'sound/magic/Teleport_diss.ogg', 50, 1) + owner.apply_status_effect(STATUS_EFFECT_VOID_PRICE) + +/datum/status_effect/void_price + name = "Void Price" + desc = "Black tendrils cinch tightly against you, digging wicked barbs into your flesh." + id = "void_price" + icon_state = "shadow_mend" + duration = 30 + tick_interval = 3 + +/datum/status_effect/void_price/tick() + owner << sound('sound/magic/Summon_Karp.ogg', volume = 25) + owner.adjustBruteLoss(3) + + + +/datum/status_effect/inathneqs_endowment + name = "Inath-neq's Endowment" + desc = "Adrenaline courses through you as the Cogwheel's energy shields you from all harm!" + id = "inathneqs_endowment" + icon_state = "inathneqs_endowment" + duration = 15 + +/datum/status_effect/inathneqs_endowment/on_apply() + owner.visible_message("[owner] shines with azure light!", "You feel Inath-neq's power flow through you! You're invincible!") + owner.color = "#1E8CE1" + owner.fully_heal() + owner.add_stun_absorption("inathneq", 150, 1, "'s flickering blue aura momentarily intensifies!", "Inath-neq's power absorbs the stun!", " is surrounded by blue light!") + owner.status_flags |= GODMODE + animate(owner, color = initial(owner.color), time = 150, easing = EASE_IN) + playsound(owner, 'sound/magic/Ethereal_Enter.ogg', 50, 1) + +/datum/status_effect/inathneqs_endowment/on_remove() + owner.visible_message("The light around [owner] flickers and dissipates!", "Inath-neq's shield wavers and fails!") + owner.status_flags &= ~GODMODE + playsound(owner, 'sound/magic/Ethereal_Exit.ogg', 50, 1) diff --git a/code/datums/status_effects/status_effect.dm b/code/datums/status_effects/status_effect.dm new file mode 100644 index 00000000000..1754843b5fb --- /dev/null +++ b/code/datums/status_effects/status_effect.dm @@ -0,0 +1,64 @@ +//Status effects are used to apply temporary or permanent effects to mobs. Mobs are aware of their status effects at all times. +//This file contains their code, plus code for applying and removing them. +//When making a new status effect, add a define to status_effects.dm in __DEFINES for ease of use! +var/list/status_effects = list() //All status effects affecting literally anyone +/datum/status_effect + var/name = "Curse of Mundanity" + var/desc = "You don't feel any different..." + var/id = "effect" //Used for screen alerts. + var/icon_state //Used for displaying the status effect. + var/duration = -1 //How long the status effect lasts in SECONDS. Enter -1 for an effect that never ends unless removed through some means. + var/tick_interval = 1 //How many seconds between ticks. Leave at 1 for every second. + var/mob/living/owner //The mob affected by the status effect. + var/cosmetic = FALSE //If the status effect only exists for flavor. + var/unique = TRUE //If there can be multiple status effects of this type on one mob. + +/datum/status_effect/New() + ..() + status_effects += src + spawn(1) //Give us time to set any variables + start_ticking() + +/datum/status_effect/Destroy() + status_effects -= src + ..() + +/datum/status_effect/proc/start_ticking() + if(!src) + return + on_apply() + owner.throw_alert(id, /obj/screen/alert, effect = src) + START_PROCESSING(SSprocessing, src) + +/datum/status_effect/process() + if(duration != -1) + duration-- + tick_interval-- + if(!tick_interval) + tick() + tick_interval = initial(tick_interval) + if(!duration && duration != -1) + cancel_effect() + +/datum/status_effect/proc/cancel_effect() + STOP_PROCESSING(SSprocessing, src) + owner.clear_alert(id) + on_remove() + qdel(src) + +/datum/status_effect/proc/on_apply() //Called whenever the buff is applied. +/datum/status_effect/proc/tick() //Called every tick. +/datum/status_effect/proc/on_remove() //Called whenever the buff expires or is removed. + +////////////////// +// HELPER PROCS // +////////////////// + +/mob/living/proc/apply_status_effect(effect) + var/datum/status_effect/S = new effect + for(var/datum/status_effect/S2 in status_effects) + if(S.unique && S2.unique && S.id == S2.id && S2.owner == src) + qdel(S) + return + S.owner = src + return 1 diff --git a/code/game/gamemodes/clock_cult/clock_scripture.dm b/code/game/gamemodes/clock_cult/clock_scripture.dm index 0596d796731..00abf88c55b 100644 --- a/code/game/gamemodes/clock_cult/clock_scripture.dm +++ b/code/game/gamemodes/clock_cult/clock_scripture.dm @@ -1208,21 +1208,10 @@ Judgement: 10 servants, 100 CV, and any existing AIs are converted or destroyed playsound(invoker, 'sound/magic/clockwork/invoke_general.ogg', 50, 0) if(invoker.real_name == "Lucio") clockwork_say(invoker, text2ratvar("Aww, let's break it DOWN!!")) - var/list/affected_servants = list() for(var/mob/living/L in range(7, invoker)) if(!is_servant_of_ratvar(L) || L.stat == DEAD) continue - L << "Inath-neq's power flows through you!" - L.color = "#1E8CE1" - L.fully_heal() - L.add_stun_absorption("inathneq", total_duration, 2, "'s flickering blue aura momentarily intensifies!", "Inath-neq's ward absorbs the stun!", " is glowing with a flickering blue light!") - L.status_flags |= GODMODE - animate(L, color = initial(L.color), time = total_duration, easing = EASE_IN) - affected_servants += L - spawn(total_duration) - for(var/mob/living/L in affected_servants) - L << "You feel Inath-neq's power fade from your body." - L.status_flags &= ~GODMODE + L.apply_status_effect(STATUS_EFFECT_INATHNEQS_ENDOWMENT) return 1 diff --git a/icons/mob/status_effects.dmi b/icons/mob/status_effects.dmi new file mode 100644 index 00000000000..d36af5785a4 Binary files /dev/null and b/icons/mob/status_effects.dmi differ diff --git a/tgstation.dme b/tgstation.dme index 88edc1336b6..702a97f9e2d 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -50,6 +50,7 @@ #include "code\__DEFINES\shuttles.dm" #include "code\__DEFINES\sight.dm" #include "code\__DEFINES\stat.dm" +#include "code\__DEFINES\status_effects.dm" #include "code\__DEFINES\tablecrafting.dm" #include "code\__DEFINES\tgui.dm" #include "code\__DEFINES\tick.dm" @@ -139,7 +140,6 @@ #include "code\controllers\subsystem\augury.dm" #include "code\controllers\subsystem\diseases.dm" #include "code\controllers\subsystem\events.dm" -#include "code\controllers\subsystem\fastprocess.dm" #include "code\controllers\subsystem\garbage.dm" #include "code\controllers\subsystem\icon_smooth.dm" #include "code\controllers\subsystem\ipintel.dm" @@ -150,7 +150,6 @@ #include "code\controllers\subsystem\minimap.dm" #include "code\controllers\subsystem\mobs.dm" #include "code\controllers\subsystem\npcpool.dm" -#include "code\controllers\subsystem\objects.dm" #include "code\controllers\subsystem\pai.dm" #include "code\controllers\subsystem\persistence.dm" #include "code\controllers\subsystem\pool.dm" @@ -164,6 +163,9 @@ #include "code\controllers\subsystem\timer.dm" #include "code\controllers\subsystem\voting.dm" #include "code\controllers\subsystem\weather.dm" +#include "code\controllers\subsystem\processing\fastprocess.dm" +#include "code\controllers\subsystem\processing\objects.dm" +#include "code\controllers\subsystem\processing\processing.dm" #include "code\datums\action.dm" #include "code\datums\ai_laws.dm" #include "code\datums\beam.dm" @@ -247,6 +249,8 @@ #include "code\datums\martial\wrestling.dm" #include "code\datums\ruins\lavaland.dm" #include "code\datums\ruins\space.dm" +#include "code\datums\status_effects\buffs.dm" +#include "code\datums\status_effects\status_effect.dm" #include "code\datums\weather\weather.dm" #include "code\datums\weather\weather_types.dm" #include "code\datums\wires\airalarm.dm"