Refactors effect_system (#94999)

## About The Pull Request

This PR refactors ``effect_system``s to be a bit easier to use by
getting rid of ``set_up``, allowing ``attach()`` to be chained into
``start()`` and refactoring most direct system usages in our code to use
helper procs.

``set_up`` was unnecessary and only existed to allow ``New``'s behavior
to be fully overriden, which is not required if we split
sparks/lightning/steam into a new ``/datum/effect_system/basic`` subtype
which houses the effect spreading behavior. This allows us to roll all
logic from ``set_up`` into ``New`` and cut down on code complexity.
Chaining setup as ``system.attach(src).start()`` also helps a bit in
case no helper method exists

I've added ``do_chem_smoke`` and ``do_foam`` helpers, which respectively
allow chemical smoke or foam to be spawned easily without having to
manually create effect datums and reagent holders.

Also turns out we've had some nonfunctional effect systems which either
never set themselves up, or never started, so I fixed those while I was
at it (mostly by moving them to aforementioned helper procs)

## Why It's Good For The Game

Cleaner code, makes it significantly easier for users to work with. Also
most of our effect system usage was copypasta which was passing booleans
as numbers, while perfectly fine helper procs existed in our code.

## Changelog
🆑
refactor: Refactored sparks, foam, smoke, and other miscellaneous effect
systems.
refactor: Vapes now have consistent rigging with cigs using the new
system.
fix: Fixed some effects never working.
/🆑
This commit is contained in:
SmArtKar
2026-02-03 22:23:09 -05:00
committed by GitHub
parent b1e6830ec5
commit f58b8511f0
134 changed files with 621 additions and 904 deletions
+11 -16
View File
@@ -1122,9 +1122,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
balloon_alert(user, "voltage maximized")
icon_state = "vapeopen_high"
set_greyscale(new_config = /datum/greyscale_config/vape/open_high)
var/datum/effect_system/spark_spread/sp = new /datum/effect_system/spark_spread //for effect
sp.set_up(5, 1, src)
sp.start()
do_sparks(5, TRUE, src)
return TRUE
/obj/item/vape/attack_self(mob/user)
@@ -1170,11 +1168,10 @@ CIGARETTE PACKETS ARE IN FANCY.DM
vaper.adjust_fire_stacks(2)
vaper.ignite_mob()
if(reagents.get_reagent_amount(/datum/reagent/toxin/plasma)) // the plasma explodes when exposed to fire
var/datum/effect_system/reagents_explosion/e = new()
e.set_up(round(reagents.get_reagent_amount(/datum/reagent/toxin/plasma) / 2.5, 1), get_turf(src), 0)
e.start(src)
// Preserve old welding fuel behavior
if(reagents.spark_act(0, TRUE, banned_reagents = /datum/reagent/fuel) & SPARK_ACT_DESTRUCTIVE)
qdel(src)
return
if(!reagents.trans_to(vaper, REAGENTS_METABOLISM, methods = INHALE, ignore_stomach = TRUE))
reagents.remove_all(REAGENTS_METABOLISM)
@@ -1198,23 +1195,21 @@ CIGARETTE PACKETS ARE IN FANCY.DM
//Time to start puffing those fat vapes, yo.
COOLDOWN_START(src, drag_cooldown, dragtime)
if(obj_flags & EMAGGED)
var/datum/effect_system/fluid_spread/smoke/chem/smoke_machine/puff = new
puff.set_up(4, holder = src, location = loc, carry = reagents, efficiency = 24)
puff.start()
var/smoke_amount = DIAMOND_AREA(4)
do_chem_smoke(amount = smoke_amount, holder = src, location = loc, carry = reagents, carry_limit = 20, smoke_type = /datum/effect_system/fluid_spread/smoke/chem/smoke_machine)
reagents.remove_all(smoke_amount / 24)
if(prob(5)) //small chance for the vape to break and deal damage if it's emagged
playsound(get_turf(src), 'sound/effects/pop_expl.ogg', 50, FALSE)
M.apply_damage(20, BURN, BODY_ZONE_HEAD)
M.Paralyze(300)
var/datum/effect_system/spark_spread/sp = new /datum/effect_system/spark_spread
sp.set_up(5, 1, src)
sp.start()
do_sparks(5, TRUE, src)
to_chat(M, span_userdanger("[src] suddenly explodes in your mouth!"))
qdel(src)
return
else if(super)
var/datum/effect_system/fluid_spread/smoke/chem/smoke_machine/puff = new
puff.set_up(1, holder = src, location = loc, carry = reagents, efficiency = 24)
puff.start()
var/smoke_amount = DIAMOND_AREA(1)
do_chem_smoke(amount = smoke_amount, holder = src, location = loc, carry = reagents, carry_limit = 20, smoke_type = /datum/effect_system/fluid_spread/smoke/chem/smoke_machine)
reagents.remove_all(smoke_amount / 24)
handle_reagents()
+1 -3
View File
@@ -141,9 +141,7 @@
/obj/item/soap/suicide_act(mob/living/user)
user.say(";FFFFFFFFFFFFFFFFUUUUUUUDGE!!", forced="soap suicide")
user.visible_message(span_suicide("[user] lifts [src] to [user.p_their()] mouth and gnaws on it furiously, producing a thick froth! [user.p_They()]'ll never get that BB gun now!"))
var/datum/effect_system/fluid_spread/foam/foam = new
foam.set_up(1, holder = src, location = get_turf(user))
foam.start()
do_foam(1, src, get_turf(user))
return TOXLOSS
/obj/item/soap/proc/should_clean(datum/cleaning_source, atom/atom_to_clean, mob/living/cleaner)
@@ -101,10 +101,7 @@
if(active_dummy)
for(var/mob/M in active_dummy)
to_chat(M, span_danger("Your chameleon projector deactivates."))
var/datum/effect_system/spark_spread/spark_system = new /datum/effect_system/spark_spread
spark_system.set_up(5, 0, src)
spark_system.attach(src)
spark_system.start()
do_sparks(5, FALSE, src, src)
eject_all()
if(delete_dummy)
qdel(active_dummy)
@@ -72,10 +72,7 @@
step(L, pick(GLOB.cardinals))
to_chat(L, span_danger("You feel a sharp shock!"))
var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
s.set_up(3, 1, L)
s.start()
do_sparks(3, TRUE, L)
L.Paralyze(100)
if(master)
+5 -5
View File
@@ -389,7 +389,7 @@
//Cookie
selected_turf.visible_message(span_userdanger("A cookie appears out of thin air!"))
var/obj/item/food/cookie/ooh_a_cookie = new(drop_location())
do_smoke(0, holder = src, location = drop_location())
do_smoke(0, src, drop_location())
ooh_a_cookie.name = "Cookie of Fate"
if(12)
//Healing
@@ -410,12 +410,12 @@
if(14)
//Free Gun
selected_turf.visible_message(span_userdanger("An impressive gun appears!"))
do_smoke(0, holder = src, location = drop_location())
do_smoke(0, src, drop_location())
new /obj/item/gun/ballistic/revolver/mateba(drop_location())
if(15)
//Random One-use spellbook
selected_turf.visible_message(span_userdanger("A magical looking book drops to the floor!"))
do_smoke(0, holder = src, location = drop_location())
do_smoke(0, src, drop_location())
new /obj/item/book/granter/action/spell/random(drop_location())
if(16)
//Servant & Servant Summon
@@ -426,12 +426,12 @@
//Tator Kit
selected_turf.visible_message(span_userdanger("A suspicious box appears!"))
new /obj/item/storage/box/syndicate/bundle_a(drop_location())
do_smoke(0, holder = src, location = drop_location())
do_smoke(0, src, drop_location())
if(18)
//Captain ID
selected_turf.visible_message(span_userdanger("A golden identification card appears!"))
new /obj/item/card/id/advanced/gold/captains_spare(drop_location())
do_smoke(0, holder = src, location = drop_location())
do_smoke(0, src, drop_location())
if(19)
//Instrinct Resistance
selected_turf.visible_message(span_userdanger("[user] looks very robust!"))
+1 -3
View File
@@ -697,9 +697,7 @@
/obj/item/food/burger/crazy/process(seconds_per_tick) // DIT EES HORRIBLE
if(SPT_PROB(2.5, seconds_per_tick))
var/datum/effect_system/fluid_spread/smoke/bad/green/smoke = new
smoke.set_up(0, holder = src, location = src)
smoke.start()
do_smoke(0, src, loc, smoke_type = /datum/effect_system/fluid_spread/smoke/bad/green)
// empty burger you can customize
/obj/item/food/burger/empty
@@ -43,10 +43,7 @@
update_mob()
playsound(src, 'sound/effects/smoke.ogg', 50, TRUE, -3)
var/datum/effect_system/fluid_spread/smoke/bad/smoke = new
smoke.set_up(4, holder = src, location = src)
smoke.start()
qdel(smoke) //And deleted again. Sad really.
do_smoke(4, src, loc, smoke_type = /datum/effect_system/fluid_spread/smoke/bad)
for(var/obj/structure/blob/blob in view(8, src))
var/damage = round(30/(get_dist(blob, src) + 1))
blob.take_damage(damage, BURN, MELEE, 0)
@@ -56,9 +56,7 @@
/obj/item/implant/smoke/activate()
. = ..()
uses--
var/datum/effect_system/fluid_spread/smoke/bad/smoke = new
smoke.set_up(6, holder = imp_in, location = imp_in)
smoke.start()
do_smoke(6, imp_in, imp_in.loc, smoke_type = /datum/effect_system/fluid_spread/smoke/bad)
if(!uses)
qdel(src)
@@ -40,9 +40,7 @@
to_chat(teleportee, span_holoparasite("You feel yourself teleporting, but are suddenly flung back to where you just were!"))
teleportee.apply_status_effect(/datum/status_effect/incapacitating/paralyzed, 5 SECONDS)
var/datum/effect_system/spark_spread/quantum/spark_system = new()
spark_system.set_up(5, TRUE, teleportee)
spark_system.start()
do_sparks(5, TRUE, teleportee, spark_type = /datum/effect_system/basic/spark_spread/quantum)
return TRUE
/// Signal for COMSIG_MOB_PRE_JAUNT that prevents a user from entering a jaunt.
@@ -52,9 +50,7 @@
to_chat(jaunter, span_holoparasite("As you attempt to jaunt, you slam directly into the barrier between realities and are sent crashing back into corporeality!"))
jaunter.apply_status_effect(/datum/status_effect/incapacitating/paralyzed, 5 SECONDS)
var/datum/effect_system/spark_spread/quantum/spark_system = new()
spark_system.set_up(5, TRUE, jaunter)
spark_system.start()
do_sparks(5, TRUE, jaunter, spark_type = /datum/effect_system/basic/spark_spread/quantum)
return COMPONENT_BLOCK_JAUNT
/obj/item/implantcase/teleport_blocker
+2 -3
View File
@@ -21,7 +21,7 @@
armor_type = /datum/armor/item_construction
resistance_flags = FIRE_PROOF
/// the spark system which sparks whever the ui options are dited
var/datum/effect_system/spark_spread/spark_system
var/datum/effect_system/basic/spark_spread/spark_system
/// current local matter inside the device, not used when silo link is on
var/matter = 0
/// maximum local matter this device can hold, not used when silo link is on
@@ -47,8 +47,7 @@
/obj/item/construction/Initialize(mapload)
. = ..()
spark_system = new /datum/effect_system/spark_spread
spark_system.set_up(5, 0, src)
spark_system = new(5, FALSE, src)
spark_system.attach(src)
if(construction_upgrades & RCD_UPGRADE_SILO_LINK)
silo_mats = new (src, mapload, FALSE)
+2 -3
View File
@@ -40,7 +40,7 @@
pickup_sound = 'sound/items/handling/tools/rpd_pickup.ogg'
sound_vary = TRUE
///Sparks system used when changing device in the UI
var/datum/effect_system/spark_spread/spark_system
var/datum/effect_system/basic/spark_spread/spark_system
///Direction of the device we are going to spawn, set up in the UI
var/p_dir = NORTH
///Initial direction of the smart pipe we are going to spawn, set up in the UI
@@ -80,8 +80,7 @@
/obj/item/pipe_dispenser/Initialize(mapload)
. = ..()
spark_system = new
spark_system.set_up(5, 0, src)
spark_system = new(src, 5, FALSE)
spark_system.attach(src)
if(!first_atmos)
first_atmos = GLOB.atmos_pipe_recipes[GLOB.atmos_pipe_recipes[1]][1]
@@ -605,9 +605,7 @@
var/prev_lockcharge = borg.lockcharge
borg.SetLockdown(TRUE)
borg.set_anchored(TRUE)
var/datum/effect_system/fluid_spread/smoke/smoke = new
smoke.set_up(1, holder = borg, location = borg.loc)
smoke.start()
do_smoke(1, borg, borg.loc)
sleep(0.2 SECONDS)
for(var/i in 1 to 4)
playsound(borg, pick(
+1 -3
View File
@@ -358,9 +358,7 @@
anchored = TRUE
/obj/effect/resin_container/proc/Smoke()
var/datum/effect_system/fluid_spread/foam/metal/resin/foaming = new
foaming.set_up(4, holder = src, location = loc)
foaming.start()
do_foam(4, src, loc, foam_type = /datum/effect_system/fluid_spread/foam/metal/resin)
playsound(src,'sound/effects/bamf.ogg',100,TRUE)
qdel(src)
+2 -4
View File
@@ -829,10 +829,8 @@
w_class = WEIGHT_CLASS_TINY
var/ash_type = /obj/effect/decal/cleanable/ash
/obj/item/toy/snappop/proc/pop_burst(n=3, c=1)
var/datum/effect_system/spark_spread/s = new()
s.set_up(n, c, src)
s.start()
/obj/item/toy/snappop/proc/pop_burst(n = 3, c = TRUE)
do_sparks(n, c, src)
new ash_type(loc)
visible_message(span_warning("[src] explodes!"),
span_hear("You hear a snap!"))
@@ -358,7 +358,7 @@
heat = 3500
w_class = WEIGHT_CLASS_BULKY
/// Our linked spark system that emits from our sword.
var/datum/effect_system/spark_spread/spark_system
var/datum/effect_system/basic/spark_spread/spark_system
var/list/alt_continuous = list("stabs", "pierces", "impales")
var/list/alt_simple = list("stab", "pierce", "impale")
@@ -368,8 +368,7 @@
alt_continuous = string_list(alt_continuous)
alt_simple = string_list(alt_simple)
AddComponent(/datum/component/alternative_sharpness, SHARP_POINTY, alt_continuous, alt_simple, -10)
spark_system = new /datum/effect_system/spark_spread()
spark_system.set_up(5, 0, src)
spark_system = new(5, FALSE, src)
spark_system.attach(src)
START_PROCESSING(SSobj, src)
ADD_TRAIT(src, TRAIT_TRANSFORM_ACTIVE, INNATE_TRAIT) // Functions as an extended esword