From f83723c3892e4f3682604f2706ef26e43a66a97d Mon Sep 17 00:00:00 2001 From: Ling Date: Wed, 8 Feb 2023 01:52:57 +0100 Subject: [PATCH] Ports SSfoam and SSsmoke (#17742) * Ports SSfoam and SSsmoke * Remove dupe define --- code/__DEFINES/MC.dm | 8 + code/__DEFINES/maths.dm | 6 + code/__DEFINES/subsystems.dm | 3 +- code/__HELPERS/_lists.dm | 10 +- code/__HELPERS/reagents.dm | 14 + code/controllers/subsystem/fluids.dm | 261 ++++++++++ .../processing/{fluids.dm => plumbing.dm} | 4 +- code/datums/components/plumbing/plumbing.dm | 6 +- code/game/machinery/ai_slipper.dm | 4 +- code/game/mecha/mecha.dm | 4 +- code/game/objects/effects/anomalies.dm | 2 +- .../effects/effect_system/effect_system.dm | 13 +- .../effect_system/effects_explosion.dm | 5 +- .../effects/effect_system/effects_foam.dm | 355 -------------- .../effects/effect_system/effects_smoke.dm | 336 ------------- .../fluid_spread/_fluid_spread.dm | 159 ++++++ .../fluid_spread/effects_foam.dm | 404 ++++++++++++++++ .../fluid_spread/effects_smoke.dm | 455 ++++++++++++++++++ code/game/objects/effects/step_triggers.dm | 8 +- code/game/objects/items/cigs_lighters.dm | 12 +- code/game/objects/items/clown_items.dm | 2 +- code/game/objects/items/grenades/smokebomb.dm | 4 +- .../objects/items/robot/robot_upgrades.dm | 4 +- code/game/objects/items/scrolls.dm | 4 +- code/game/objects/items/tanks/watertank.dm | 11 +- code/game/objects/structures/hivebot.dm | 4 +- .../objects/structures/lavaland/geyser.dm | 2 +- .../antagonists/_common/antag_spawner.dm | 2 +- code/modules/antagonists/blob/blob_mobs.dm | 4 +- .../bloodsuckers/powers/gangrel.dm | 2 +- .../antagonists/bloodsuckers/powers/gohome.dm | 2 +- .../bloodsuckers/powers/targeted/lunge.dm | 2 +- .../bloodsuckers/powers/targeted/trespass.dm | 4 +- .../antagonists/bloodsuckers/powers/veil.dm | 9 +- .../eldritch_cult/eldritch_effects.dm | 4 +- .../nukeop/equipment/nuclearbomb.dm | 6 +- .../modules/awaymissions/super_secret_room.dm | 4 +- .../under/jobs/Plasmaman/civilian_service.dm | 8 +- code/modules/events/immovable_rod.dm | 9 +- code/modules/events/scrubber_overflow.dm | 133 +++++ code/modules/events/vent_clog.dm | 138 ------ code/modules/events/wizard/curseditems.dm | 4 +- code/modules/events/wizard/imposter.dm | 2 +- code/modules/events/wizard/shuffle.dm | 12 +- .../food_and_drinks/food/snacks_burgers.dm | 2 +- .../kitchen_machinery/grill.dm | 4 +- code/modules/goals/station_goals/bsa.dm | 6 +- code/modules/hydroponics/grown/onion.dm | 4 +- code/modules/hydroponics/plant_genes.dm | 4 +- code/modules/mining/equipment/survival_pod.dm | 2 +- .../mob/living/simple_animal/bot/atmosbot.dm | 2 +- .../mob/living/simple_animal/bot/cleanbot.dm | 4 +- .../mob/living/simple_animal/bot/firebot.dm | 4 +- .../hostile/mining_mobs/elites/legionnaire.dm | 4 +- .../simple_animal/hostile/retaliate/clown.dm | 16 +- .../simple_animal/hostile/venus_human_trap.dm | 4 +- .../ninja/suit/n_suit_verbs/ninja_smoke.dm | 7 +- code/modules/projectiles/guns/magic/wand.dm | 8 +- code/modules/projectiles/projectile/magic.dm | 9 +- .../chemistry/machinery/smoke_machine.dm | 32 +- .../reagents/pyrotechnic_reagents.dm | 30 +- .../reagents/chemistry/recipes/drugs.dm | 4 +- .../reagents/chemistry/recipes/others.dm | 35 +- .../chemistry/recipes/pyrotechnics.dm | 8 +- code/modules/research/experimentor.dm | 48 +- .../xenobiology/crossbreeding/burning.dm | 18 +- .../research/xenobiology/xenobiology.dm | 6 +- code/modules/spells/spell.dm | 23 +- .../spells/spell_types/construct_spells.dm | 2 +- code/modules/spells/spell_types/devil.dm | 10 +- code/modules/spells/spell_types/wizard.dm | 8 +- code/modules/vehicles/cars/clowncar.dm | 26 +- config/config.txt | 2 +- yogstation.dme | 10 +- .../objects/items/grenades/glitterbombs.dm | 16 +- .../game/objects/structures/toilet_bong.dm | 4 +- .../shadowling/shadowling_abilities.dm | 4 +- .../code/modules/events/immovable_duck.dm | 9 +- 78 files changed, 1707 insertions(+), 1113 deletions(-) create mode 100644 code/controllers/subsystem/fluids.dm rename code/controllers/subsystem/processing/{fluids.dm => plumbing.dm} (58%) delete mode 100644 code/game/objects/effects/effect_system/effects_foam.dm delete mode 100644 code/game/objects/effects/effect_system/effects_smoke.dm create mode 100644 code/game/objects/effects/effect_system/fluid_spread/_fluid_spread.dm create mode 100644 code/game/objects/effects/effect_system/fluid_spread/effects_foam.dm create mode 100644 code/game/objects/effects/effect_system/fluid_spread/effects_smoke.dm create mode 100644 code/modules/events/scrubber_overflow.dm delete mode 100644 code/modules/events/vent_clog.dm diff --git a/code/__DEFINES/MC.dm b/code/__DEFINES/MC.dm index 9f3ffe0a4d47..7c84b693e31c 100644 --- a/code/__DEFINES/MC.dm +++ b/code/__DEFINES/MC.dm @@ -103,3 +103,11 @@ PreInit();\ }\ /datum/controller/subsystem/processing/##X + +#define FLUID_SUBSYSTEM_DEF(X) GLOBAL_REAL(SS##X, /datum/controller/subsystem/fluids/##X);\ +/datum/controller/subsystem/fluids/##X/New(){\ + NEW_SS_GLOBAL(SS##X);\ + PreInit();\ +}\ +/datum/controller/subsystem/fluids/##X/fire() {..() /*just so it shows up on the profiler*/} \ +/datum/controller/subsystem/fluids/##X diff --git a/code/__DEFINES/maths.dm b/code/__DEFINES/maths.dm index fdce39226ccf..0b565af6399e 100644 --- a/code/__DEFINES/maths.dm +++ b/code/__DEFINES/maths.dm @@ -36,6 +36,9 @@ // Similar to clamp but the bottom rolls around to the top and vice versa. min is inclusive, max is exclusive #define WRAP(val, min, max) ( min == max ? min : (val) - (round(((val) - (min))/((max) - (min))) * ((max) - (min))) ) +/// Increments a value and wraps it if it exceeds some value. Can be used to circularly iterate through a list through `idx = WRAP_UP(idx, length_of_list)`. +#define WRAP_UP(val, max) (((val) % (max)) + 1) + // Real modulus that handles decimals #define MODULUS(x, y) ( (x) - (y) * round((x) / (y)) ) @@ -220,3 +223,6 @@ /// Like DT_PROB_RATE but easier to use, simply put `if(DT_PROB(10, 5))` #define DT_PROB(prob_per_second_percent, delta_time) (prob(100*DT_PROB_RATE(prob_per_second_percent/100, delta_time))) // ) + +/// The number of cells in a taxicab circle (rasterized diamond) of radius X. +#define DIAMOND_AREA(X) (1 + 2*(X)*((X)+1)) diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm index 76ea46108b04..de181ce0e61c 100644 --- a/code/__DEFINES/subsystems.dm +++ b/code/__DEFINES/subsystems.dm @@ -175,6 +175,7 @@ #define FIRE_PRIORITY_VIS 10 #define FIRE_PRIORITY_GARBAGE 15 #define FIRE_PRIORITY_WET_FLOORS 20 +#define FIRE_PRIORITY_FLUIDS 20 #define FIRE_PRIORITY_AIR 20 #define FIRE_PRIORITY_NPC 20 #define FIRE_PRIORITY_PROCESS 25 @@ -261,7 +262,7 @@ // Subsystem delta times or tickrates, in seconds. I.e, how many seconds in between each process() call for objects being processed by that subsystem. // Only use these defines if you want to access some other objects processing delta_time, otherwise use the delta_time that is sent as a parameter to process() -#define SSFLUIDS_DT (SSfluids.wait/10) +#define SSFLUIDS_DT (SSplumbing.wait/10) #define SSMACHINES_DT (SSmachines.wait/10) #define SSMOBS_DT (SSmobs.wait/10) #define SSOBJ_DT (SSobj.wait/10) diff --git a/code/__HELPERS/_lists.dm b/code/__HELPERS/_lists.dm index 722e68d051e6..2898017fb27a 100644 --- a/code/__HELPERS/_lists.dm +++ b/code/__HELPERS/_lists.dm @@ -18,8 +18,16 @@ #define LAZYACCESS(L, I) (L ? (isnum(I) ? (I > 0 && I <= length(L) ? L[I] : null) : L[I]) : null) #define LAZYSET(L, K, V) if(!L) { L = list(); } L[K] = V; #define LAZYLEN(L) length(L) -#define LAZYCLEARLIST(L) if(L) L.Cut() +///Accesses an associative list, returns null if nothing is found #define LAZYACCESSASSOC(L, I, K) L ? L[I] ? L[I][K] ? L[I][K] : null : null : null +///Qdel every item in the list before setting the list to null +#define QDEL_LAZYLIST(L) for(var/I in L) qdel(I); L = null; +//These methods don't null the list +///Use LAZYLISTDUPLICATE instead if you want it to null with no entries +#define LAZYCOPY(L) (L ? L.Copy() : list() ) +/// Consider LAZYNULL instead +#define LAZYCLEARLIST(L) if(L) L.Cut() +///Returns the list if it's actually a valid list, otherwise will initialize it #define SANITIZE_LIST(L) ( islist(L) ? L : list() ) #define reverseList(L) reverseRange(L.Copy()) #define LAZYADDASSOC(L, K, V) if(!L) { L = list(); } L[K] += list(V); diff --git a/code/__HELPERS/reagents.dm b/code/__HELPERS/reagents.dm index f1208abdd300..1b9c171241e8 100644 --- a/code/__HELPERS/reagents.dm +++ b/code/__HELPERS/reagents.dm @@ -72,3 +72,17 @@ if(!GLOB.chemical_reactions_list[primary_reagent]) GLOB.chemical_reactions_list[primary_reagent] = list() GLOB.chemical_reactions_list[primary_reagent] += R + +//Creates foam from the reagent. Metaltype is for metal foam, notification is what to show people in textbox +/datum/reagents/proc/create_foam(foamtype, foam_volume, result_type = null, notification = null, log = FALSE) + var/location = get_turf(my_atom) + + var/datum/effect_system/fluid_spread/foam/foam = new foamtype() + foam.set_up(amount = foam_volume, holder = my_atom, location = location, carry = src, result_type = result_type) + foam.start(log = log) + + clear_reagents() + if(!notification) + return + for(var/mob/M in viewers(5, location)) + to_chat(M, notification) diff --git a/code/controllers/subsystem/fluids.dm b/code/controllers/subsystem/fluids.dm new file mode 100644 index 000000000000..4a06cb59c351 --- /dev/null +++ b/code/controllers/subsystem/fluids.dm @@ -0,0 +1,261 @@ +// Flags indicating what parts of the fluid the subsystem processes. +/// Indicates that a fluid subsystem processes fluid spreading. +#define SS_PROCESSES_SPREADING (1<<0) +/// Indicates that a fluid subsystem processes fluid effects. +#define SS_PROCESSES_EFFECTS (1<<1) + +/** + * # Fluid Subsystem + * + * A subsystem that processes the propagation and effects of a particular fluid. + * + * Both fluid spread and effect processing are handled through a carousel system. + * Fluids being spread and fluids being processed are organized into buckets. + * Each fresh (non-resumed) fire one bucket of each is selected to be processed. + * These selected buckets are then fully processed. + * The next fresh fire selects the next bucket in each set for processing. + * If this would walk off the end of a carousel list we wrap back to the first element. + * This effectively makes each set a circular list, hence a carousel. + */ +SUBSYSTEM_DEF(fluids) + name = "Fluid" + wait = 0 // Will be autoset to whatever makes the most sense given the spread and effect waits. + flags = SS_BACKGROUND|SS_KEEP_TIMING + runlevels = RUNLEVEL_GAME|RUNLEVEL_POSTGAME + + // Fluid spread processing: + /// The amount of time (in deciseconds) before a fluid node is created and when it spreads. + var/spread_wait = 1 SECONDS + /// The number of buckets in the spread carousel. + var/num_spread_buckets + /// The set of buckets containing fluid nodes to spread. + var/list/spread_carousel + /// The index of the spread carousel bucket currently being processed. + var/spread_bucket_index + /// The set of fluid nodes we are currently processing spreading for. + var/list/currently_spreading + /// Whether the subsystem has resumed spreading fluid. + var/resumed_spreading + + // Fluid effect processing: + /// The amount of time (in deciseconds) between effect processing ticks for each fluid node. + var/effect_wait = 1 SECONDS + /// The number of buckets in the effect carousel. + var/num_effect_buckets + /// The set of buckets containing fluid nodes to process effects for. + var/list/effect_carousel + /// The index of the currently processing bucket on the effect carousel. + var/effect_bucket_index + /// The set of fluid nodes we are currently processing effects for. + var/list/currently_processing + /// Whether the subsystem has resumed processing fluid effects. + var/resumed_effect_processing + +/datum/controller/subsystem/fluids/Initialize() + initialize_waits() + initialize_spread_carousel() + initialize_effect_carousel() + return SS_INIT_SUCCESS + +/** + * Initializes the subsystem waits. + * + * Ensures that the subsystem's fire wait evenly splits the spread and effect waits. + */ +/datum/controller/subsystem/fluids/proc/initialize_waits() + if (spread_wait <= 0) + WARNING("[src] has the invalid spread wait [spread_wait].") + spread_wait = 1 SECONDS + if (effect_wait <= 0) + WARNING("[src] has the invalid effect wait [effect_wait].") + spread_wait = 1 SECONDS + + // Sets the overall wait of the subsystem to evenly divide both the effect and spread waits. + var/max_wait = Gcd(spread_wait, effect_wait) + if (max_wait < wait || wait <= 0) + wait = max_wait + else + // If the wait of the subsystem overall is set to a valid value make the actual wait of the subsystem evenly divide that as well. + // Makes effect bubbling possible with identical spread and effect waits. + wait = Gcd(wait, max_wait) + + +/** + * Initializes the carousel used to process fluid spreading. + * + * Synchronizes the spread delta time with the actual target spread tick rate. + * Builds the carousel buckets used to queue spreads. + */ +/datum/controller/subsystem/fluids/proc/initialize_spread_carousel() + // Make absolutely certain that the spread wait is in sync with the target spread tick rate. + num_spread_buckets = round(spread_wait / wait) + spread_wait = wait * num_spread_buckets + + spread_carousel = list() + spread_carousel.len = num_spread_buckets + for(var/i in 1 to num_spread_buckets) + spread_carousel[i] = list() + currently_spreading = list() + spread_bucket_index = 1 + +/** + * Initializes the carousel used to process fluid effects. + * + * Synchronizes the spread delta time with the actual target spread tick rate. + * Builds the carousel buckets used to bubble processing. + */ +/datum/controller/subsystem/fluids/proc/initialize_effect_carousel() + // Make absolutely certain that the effect wait is in sync with the target effect tick rate. + num_effect_buckets = round(effect_wait / wait) + effect_wait = wait * num_effect_buckets + + effect_carousel = list() + effect_carousel.len = num_effect_buckets + for(var/i in 1 to num_effect_buckets) + effect_carousel[i] = list() + currently_processing = list() + effect_bucket_index = 1 + + +/datum/controller/subsystem/fluids/fire(resumed) + var/delta_time + var/cached_bucket_index + var/list/obj/effect/particle_effect/fluid/currentrun + MC_SPLIT_TICK_INIT(2) + + MC_SPLIT_TICK // Start processing fluid spread: + if(!resumed_spreading) + spread_bucket_index = WRAP_UP(spread_bucket_index, num_spread_buckets) + currently_spreading = spread_carousel[spread_bucket_index] + spread_carousel[spread_bucket_index] = list() // Reset the bucket so we don't process an _entire station's worth of foam_ spreading every 2 ticks when the foam flood event happens. + resumed_spreading = TRUE + + delta_time = spread_wait / (1 SECONDS) + currentrun = currently_spreading + while(currentrun.len) + var/obj/effect/particle_effect/fluid/to_spread = currentrun[currentrun.len] + currentrun.len-- + + if(!QDELETED(to_spread)) + to_spread.spread(delta_time) + to_spread.spread_bucket = null + + if (MC_TICK_CHECK) + break + + if(!currentrun.len) + resumed_spreading = FALSE + + MC_SPLIT_TICK // Start processing fluid effects: + if(!resumed_effect_processing) + effect_bucket_index = WRAP_UP(effect_bucket_index, num_effect_buckets) + var/list/tmp_list = effect_carousel[effect_bucket_index] + currently_processing = tmp_list.Copy() + resumed_effect_processing = TRUE + + delta_time = effect_wait / (1 SECONDS) + cached_bucket_index = effect_bucket_index + currentrun = currently_processing + while(currentrun.len) + var/obj/effect/particle_effect/fluid/to_process = currentrun[currentrun.len] + currentrun.len-- + + if (QDELETED(to_process) || to_process.process(delta_time) == PROCESS_KILL) + effect_carousel[cached_bucket_index] -= to_process + to_process.effect_bucket = null + to_process.datum_flags &= ~DF_ISPROCESSING + + if (MC_TICK_CHECK) + break + + if(!currentrun.len) + resumed_effect_processing = FALSE + + +/** + * Queues a fluid node to spread later after one full carousel rotation. + * + * Arguments: + * - [node][/obj/effect/particle_effect/fluid]: The node to queue to spread. + */ +/datum/controller/subsystem/fluids/proc/queue_spread(obj/effect/particle_effect/fluid/node) + if (node.spread_bucket) + return + + spread_carousel[spread_bucket_index] += node + node.spread_bucket = spread_bucket_index + +/** + * Cancels a queued spread of a fluid node. + * + * Arguments: + * - [node][/obj/effect/particle_effect/fluid]: The node to cancel the spread of. + */ +/datum/controller/subsystem/fluids/proc/cancel_spread(obj/effect/particle_effect/fluid/node) + if(!node.spread_bucket) + return + + var/bucket_index = node.spread_bucket + spread_carousel[bucket_index] -= node + if (bucket_index == spread_bucket_index) + currently_spreading -= node + + node.spread_bucket = null + +/** + * Starts processing the effects of a fluid node. + * + * The fluid node will next process after one full bucket rotation. + * + * Arguments: + * - [node][/obj/effect/particle_effect/fluid]: The node to start processing. + */ +/datum/controller/subsystem/fluids/proc/start_processing(obj/effect/particle_effect/fluid/node) + if (node.datum_flags & DF_ISPROCESSING || node.effect_bucket) + return + + // Edit this value to make all fluids process effects (at the same time|offset by when they started processing| -> offset by a random amount <- ) + var/bucket_index = rand(1, num_effect_buckets) + effect_carousel[bucket_index] += node + node.effect_bucket = bucket_index + node.datum_flags |= DF_ISPROCESSING + +/** + * Stops processing the effects of a fluid node. + * + * Arguments: + * - [node][/obj/effect/particle_effect/fluid]: The node to stop processing. + */ +/datum/controller/subsystem/fluids/proc/stop_processing(obj/effect/particle_effect/fluid/node) + if(!(node.datum_flags & DF_ISPROCESSING)) + return + + var/bucket_index = node.effect_bucket + if(!bucket_index) + return + + effect_carousel[bucket_index] -= node + if (bucket_index == effect_bucket_index) + currently_processing -= node + + node.effect_bucket = null + node.datum_flags &= ~DF_ISPROCESSING + +#undef SS_PROCESSES_SPREADING +#undef SS_PROCESSES_EFFECTS + + +// Subtypes: + +/// The subsystem responsible for processing smoke propagation and effects. +FLUID_SUBSYSTEM_DEF(smoke) + name = "Smoke" + spread_wait = 0.1 SECONDS + effect_wait = 2.0 SECONDS + +/// The subsystem responsible for processing foam propagation and effects. +FLUID_SUBSYSTEM_DEF(foam) + name = "Foam" + wait = 0.1 SECONDS // Makes effect bubbling work with foam. + spread_wait = 0.2 SECONDS + effect_wait = 0.2 SECONDS diff --git a/code/controllers/subsystem/processing/fluids.dm b/code/controllers/subsystem/processing/plumbing.dm similarity index 58% rename from code/controllers/subsystem/processing/fluids.dm rename to code/controllers/subsystem/processing/plumbing.dm index 70903e0088c7..34d6d8f882e9 100644 --- a/code/controllers/subsystem/processing/fluids.dm +++ b/code/controllers/subsystem/processing/plumbing.dm @@ -1,5 +1,5 @@ -PROCESSING_SUBSYSTEM_DEF(fluids) - name = "Fluids" +PROCESSING_SUBSYSTEM_DEF(plumbing) + name = "Plumbing" wait = 10 stat_tag = "FD" //its actually Fluid Ducts flags = SS_NO_INIT diff --git a/code/datums/components/plumbing/plumbing.dm b/code/datums/components/plumbing/plumbing.dm index 797cffb5656b..377a9694f1a2 100644 --- a/code/datums/components/plumbing/plumbing.dm +++ b/code/datums/components/plumbing/plumbing.dm @@ -29,7 +29,7 @@ /datum/component/plumbing/process() if(!demand_connects || !reagents) - STOP_PROCESSING(SSfluids, src) + STOP_PROCESSING(SSplumbing, src) return if(reagents.total_volume < reagents.maximum_volume) for(var/D in GLOB.cardinals) @@ -117,7 +117,7 @@ /datum/component/plumbing/proc/disable() //we stop acting like a plumbing thing and disconnect if we are, so we can safely be moved and stuff if(!active) return - STOP_PROCESSING(SSfluids, src) + STOP_PROCESSING(SSplumbing, src) for(var/A in ducts) var/datum/ductnet/D = ducts[A] D.remove_plumber(src) @@ -131,7 +131,7 @@ active = TRUE if(demand_connects) - START_PROCESSING(SSfluids, src) + START_PROCESSING(SSplumbing, src) for(var/D in GLOB.cardinals) if(D & (demand_connects + supply_connects)) diff --git a/code/game/machinery/ai_slipper.dm b/code/game/machinery/ai_slipper.dm index e33f66772993..639587a3520c 100644 --- a/code/game/machinery/ai_slipper.dm +++ b/code/game/machinery/ai_slipper.dm @@ -35,7 +35,9 @@ if(cooldown_time > world.time) to_chat(user, span_danger("[src] cannot be activated for [DisplayTimeText(world.time - cooldown_time)].")) return - new /obj/effect/particle_effect/foam(loc) + var/datum/effect_system/fluid_spread/foam/foam = new + foam.set_up(4, holder = src, location = loc) + foam.start() uses-- to_chat(user, span_notice("You activate [src]. It now has [uses] uses of foam remaining.")) cooldown = world.time + cooldown_time diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm index 55dd080e2d94..3190ee2ed91c 100644 --- a/code/game/mecha/mecha.dm +++ b/code/game/mecha/mecha.dm @@ -108,7 +108,7 @@ var/datum/action/innate/mecha/mech_toggle_thrusters/thrusters_action = new var/datum/action/innate/mecha/mech_defence_mode/defence_action = new var/datum/action/innate/mecha/mech_overload_mode/overload_action = new - var/datum/effect_system/smoke_spread/smoke_system = new //not an action, but trigged by one + var/datum/effect_system/fluid_spread/smoke/smoke_system = new //not an action, but trigged by one var/datum/action/innate/mecha/mech_smoke/smoke_action = new var/datum/action/innate/mecha/mech_zoom/zoom_action = new var/datum/action/innate/mecha/mech_switch_damtype/switch_damtype_action = new @@ -150,7 +150,7 @@ add_airtank() spark_system.set_up(2, 0, src) spark_system.attach(src) - smoke_system.set_up(3, src) + smoke_system.set_up(3, location = src) smoke_system.attach(src) add_cell() add_scanmod() diff --git a/code/game/objects/effects/anomalies.dm b/code/game/objects/effects/anomalies.dm index cc97027934f3..e81b9c49fbea 100644 --- a/code/game/objects/effects/anomalies.dm +++ b/code/game/objects/effects/anomalies.dm @@ -67,7 +67,7 @@ qdel(src) /obj/effect/anomaly/proc/anomalyNeutralize() - new /obj/effect/particle_effect/smoke/bad(loc) + new /obj/effect/particle_effect/fluid/smoke/bad(loc) for(var/atom/movable/O in src) O.forceMove(drop_location()) diff --git a/code/game/objects/effects/effect_system/effect_system.dm b/code/game/objects/effects/effect_system/effect_system.dm index 4ded3e4efe47..30cd89f7b5f4 100644 --- a/code/game/objects/effects/effect_system/effect_system.dm +++ b/code/game/objects/effects/effect_system/effect_system.dm @@ -37,15 +37,10 @@ would spawn and follow the beaker, even if it is carried or thrown. location = null return ..() -/datum/effect_system/proc/set_up(n = 3, c = FALSE, loca) - if(n > 10) - n = 10 - number = n - cardinals = c - if(isturf(loca)) - location = loca - else - location = get_turf(loca) +/datum/effect_system/proc/set_up(number = 3, cardinals_only = FALSE, location) + src.number = min(number, 10) + src.cardinals = cardinals_only + src.location = get_turf(location) /datum/effect_system/proc/attach(atom/atom) holder = atom diff --git a/code/game/objects/effects/effect_system/effects_explosion.dm b/code/game/objects/effects/effect_system/effects_explosion.dm index 33a267570e49..7dcc3cbd1dbd 100644 --- a/code/game/objects/effects/effect_system/effects_explosion.dm +++ b/code/game/objects/effects/effect_system/effects_explosion.dm @@ -50,9 +50,10 @@ /datum/effect_system/explosion/smoke /datum/effect_system/explosion/smoke/proc/create_smoke() - var/datum/effect_system/smoke_spread/S = new - S.set_up(2, location) + var/datum/effect_system/fluid_spread/smoke/S = new + S.set_up(2, location = location) S.start() + /datum/effect_system/explosion/smoke/start() ..() addtimer(CALLBACK(src, .proc/create_smoke), 5) diff --git a/code/game/objects/effects/effect_system/effects_foam.dm b/code/game/objects/effects/effect_system/effects_foam.dm deleted file mode 100644 index 023ae192b67b..000000000000 --- a/code/game/objects/effects/effect_system/effects_foam.dm +++ /dev/null @@ -1,355 +0,0 @@ -// Foam -// Similar to smoke, but slower and mobs absorb its reagent through their exposed skin. -#define ALUMINUM_FOAM 1 -#define IRON_FOAM 2 -#define RESIN_FOAM 3 - - -/obj/effect/particle_effect/foam - name = "foam" - icon_state = "foam" - opacity = 0 - anchored = TRUE - density = FALSE - layer = EDGED_TURF_LAYER - mouse_opacity = MOUSE_OPACITY_TRANSPARENT - var/amount = 3 - animate_movement = 0 - var/metal = 0 - var/lifetime = 40 - var/reagent_divisor = 7 - var/static/list/blacklisted_turfs = typecacheof(list( - /turf/open/space/transit, - /turf/open/chasm, - /turf/open/lava)) - var/slippery_foam = TRUE - var/one_apply_per_object = FALSE - var/list/applied_atoms - -/obj/effect/particle_effect/foam/firefighting - name = "firefighting foam" - lifetime = 20 //doesn't last as long as normal foam - amount = 0 //no spread - slippery_foam = FALSE - var/absorbed_plasma = 0 - -/obj/effect/particle_effect/foam/firefighting/process() - ..() - - var/turf/open/T = get_turf(src) - var/obj/effect/hotspot/hotspot = (locate(/obj/effect/hotspot) in T) - if(hotspot && istype(T) && T.air) - qdel(hotspot) - var/datum/gas_mixture/G = T.air - var/plas_amt = min(30,G.get_moles(/datum/gas/plasma)) //Absorb some plasma - G.adjust_moles(/datum/gas/plasma, -plas_amt) - absorbed_plasma += plas_amt - if(G.return_temperature() > T20C) - G.set_temperature(max(G.return_temperature()/2,T20C)) - T.air_update_turf() - -/obj/effect/particle_effect/foam/firefighting/kill_foam() - STOP_PROCESSING(SSprocessing, src) - - if(absorbed_plasma) - var/obj/effect/decal/cleanable/plasma/P = (locate(/obj/effect/decal/cleanable/plasma) in get_turf(src)) - if(!P) - P = new(loc) - P.reagents.add_reagent(/datum/reagent/stable_plasma, absorbed_plasma) - - flick("[icon_state]-disolve", src) - QDEL_IN(src, 5) - -/obj/effect/particle_effect/foam/firefighting/foam_mob(mob/living/L) - if(!istype(L)) - return - L.adjust_fire_stacks(-2) - L.ExtinguishMob() - -/obj/effect/particle_effect/foam/firefighting/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume) - return - -/obj/effect/particle_effect/foam/metal - name = "aluminium foam" - metal = ALUMINUM_FOAM - icon_state = "mfoam" - slippery_foam = FALSE - -/obj/effect/particle_effect/foam/metal/smart - name = "smart foam" - -/obj/effect/particle_effect/foam/metal/iron - name = "iron foam" - metal = IRON_FOAM - -/obj/effect/particle_effect/foam/metal/resin - name = "resin foam" - metal = RESIN_FOAM - -/obj/effect/particle_effect/foam/long_life - lifetime = 150 - -/obj/effect/particle_effect/foam/Initialize() - . = ..() - create_reagents(1000) //limited by the size of the reagent holder anyway. - START_PROCESSING(SSprocessing, src) - playsound(src, 'sound/effects/bubbles2.ogg', 80, 1, -3) - applied_atoms = list() - -/obj/effect/particle_effect/foam/ComponentInitialize() - . = ..() - if(slippery_foam) - AddComponent(/datum/component/slippery, 100) - -/obj/effect/particle_effect/foam/Destroy() - STOP_PROCESSING(SSprocessing, src) - return ..() - - -/obj/effect/particle_effect/foam/proc/kill_foam() - set waitfor = FALSE - STOP_PROCESSING(SSprocessing, src) - switch(metal) - if(ALUMINUM_FOAM) - new /obj/structure/foamedmetal(get_turf(src)) - if(IRON_FOAM) - new /obj/structure/foamedmetal/iron(get_turf(src)) - if(RESIN_FOAM) - new /obj/structure/foamedmetal/resin(get_turf(src)) - flick("[icon_state]-disolve", src) - QDEL_IN(src, 5) - -/obj/effect/particle_effect/foam/smart/kill_foam() //Smart foam adheres to area borders for walls - STOP_PROCESSING(SSprocessing, src) - if(metal) - var/turf/T = get_turf(src) - if(isspaceturf(T)) //Block up any exposed space - T.PlaceOnTop(/turf/open/floor/plating/foam, flags = CHANGETURF_INHERIT_AIR) - for(var/direction in GLOB.cardinals) - var/turf/cardinal_turf = get_step(T, direction) - if(get_area(cardinal_turf) != get_area(T)) //We're at an area boundary, so let's block off this turf! - new/obj/structure/foamedmetal(T) - break - flick("[icon_state]-disolve", src) - QDEL_IN(src, 5) - -/obj/effect/particle_effect/foam/process() - lifetime-- - if(lifetime < 1) - kill_foam() - return - - var/fraction = 1/initial(reagent_divisor) - for(var/obj/O in range(0,src)) - if(O.type == src.type) - continue - if(one_apply_per_object && (O in applied_atoms)) - continue - if(isturf(O.loc)) - var/turf/T = O.loc - if(T.intact && O.level == 1) //hidden under the floor - continue - if(lifetime % reagent_divisor) - reagents.reaction(O, VAPOR, fraction) - applied_atoms += O - CHECK_TICK - var/hit = 0 - for(var/mob/living/L in range(0,src)) - hit += foam_mob(L) - CHECK_TICK - if(hit) - lifetime++ //this is so the decrease from mobs hit and the natural decrease don't cumulate. - var/T = get_turf(src) - if(!(one_apply_per_object && (T in applied_atoms))) - if(lifetime % reagent_divisor) - reagents.reaction(T, VAPOR, fraction) - applied_atoms += T - - if(--amount < 0) - return - CHECK_TICK - spread_foam() - -/obj/effect/particle_effect/foam/proc/foam_mob(mob/living/L) - if(lifetime<1) - return 0 - if(!istype(L)) - return 0 - var/fraction = 1/initial(reagent_divisor) - if(lifetime % reagent_divisor) - reagents.reaction(L, VAPOR, fraction) - lifetime-- - return 1 - -/obj/effect/particle_effect/foam/proc/spread_foam() - set waitfor = FALSE - var/turf/t_loc = get_turf(src) - for(var/turf/T in t_loc.GetAtmosAdjacentTurfs()) - var/obj/effect/particle_effect/foam/foundfoam = locate() in T //Don't spread foam where there's already foam! - if(foundfoam) - continue - - if(is_type_in_typecache(T, blacklisted_turfs)) - continue - - for(var/mob/living/L in T) - foam_mob(L) - var/obj/effect/particle_effect/foam/F = new src.type(T) - F.amount = amount - reagents.copy_to(F, (reagents.total_volume)) - F.add_atom_colour(color, FIXED_COLOUR_PRIORITY) - F.metal = metal - F.one_apply_per_object = one_apply_per_object - - -/obj/effect/particle_effect/foam/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume) - if(prob(max(0, exposed_temperature - 475))) //foam dissolves when heated - kill_foam() - - -/obj/effect/particle_effect/foam/metal/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume) - return - - -/////////////////////////////////////////////// -//FOAM EFFECT DATUM -/datum/effect_system/foam_spread - var/amount = 10 // the size of the foam spread. - var/obj/chemholder - effect_type = /obj/effect/particle_effect/foam - var/metal = 0 - var/one_apply_per_object = FALSE - - -/datum/effect_system/foam_spread/metal - effect_type = /obj/effect/particle_effect/foam/metal - - -/datum/effect_system/foam_spread/metal/smart - effect_type = /obj/effect/particle_effect/foam/smart - - -/datum/effect_system/foam_spread/long - effect_type = /obj/effect/particle_effect/foam/long_life - -/datum/effect_system/foam_spread/New() - ..() - chemholder = new /obj() - var/datum/reagents/R = new/datum/reagents(1000) - chemholder.reagents = R - R.my_atom = chemholder - -/datum/effect_system/foam_spread/Destroy() - qdel(chemholder) - chemholder = null - return ..() - -/datum/effect_system/foam_spread/set_up(amt=5, loca, datum/reagents/carry = null) - if(isturf(loca)) - location = loca - else - location = get_turf(loca) - - amount = round(sqrt(amt / 2), 1) - carry.copy_to(chemholder, carry.total_volume) - -/datum/effect_system/foam_spread/metal/set_up(amt=5, loca, datum/reagents/carry = null, metaltype) - ..() - metal = metaltype - -/datum/effect_system/foam_spread/start() - var/obj/effect/particle_effect/foam/F = new effect_type(location) - F.one_apply_per_object = one_apply_per_object - var/foamcolor = mix_color_from_reagents(chemholder.reagents.reagent_list) - chemholder.reagents.copy_to(F, chemholder.reagents.total_volume/amount) - F.add_atom_colour(foamcolor, FIXED_COLOUR_PRIORITY) - F.amount = amount - F.metal = metal - - -////////////////////////////////////////////////////////// -// FOAM STRUCTURE. Formed by metal foams. Dense and opaque, but easy to break -/obj/structure/foamedmetal - icon = 'icons/effects/effects.dmi' - icon_state = "metalfoam" - density = TRUE - opacity = 1 // changed in New() - anchored = TRUE - layer = EDGED_TURF_LAYER - resistance_flags = FIRE_PROOF | ACID_PROOF - name = "foamed metal" - desc = "A lightweight foamed metal wall." - gender = PLURAL - max_integrity = 20 - CanAtmosPass = ATMOS_PASS_DENSITY - -/obj/structure/foamedmetal/Initialize() - . = ..() - air_update_turf(1) - -/obj/structure/foamedmetal/Move() - var/turf/T = loc - . = ..() - move_update_air(T) - -/obj/structure/foamedmetal/attack_paw(mob/user) - return attack_hand(user) - -/obj/structure/foamedmetal/play_attack_sound(damage_amount, damage_type = BRUTE, damage_flag = 0) - playsound(src.loc, 'sound/weapons/tap.ogg', 100, 1) - -/obj/structure/foamedmetal/attack_hand(mob/user) - . = ..() - if(.) - return - user.changeNext_move(CLICK_CD_MELEE) - user.do_attack_animation(src, ATTACK_EFFECT_PUNCH) - to_chat(user, span_warning("You hit [src] but bounce off it!")) - playsound(src.loc, 'sound/weapons/tap.ogg', 100, 1) - -/obj/structure/foamedmetal/iron - max_integrity = 50 - icon_state = "ironfoam" - -//Atmos Backpack Resin, transparent, prevents atmos and filters the air -/obj/structure/foamedmetal/resin - name = "\improper ATMOS Resin" - desc = "A lightweight, transparent resin used to suffocate fires, scrub the air of toxins, and restore the air to a safe temperature." - opacity = FALSE - icon_state = "atmos_resin" - alpha = 120 - max_integrity = 10 - -/obj/structure/foamedmetal/resin/Initialize() - . = ..() - if(isopenturf(loc)) - var/turf/open/O = loc - O.ClearWet() - if(O.air) - var/datum/gas_mixture/G = O.air - G.set_temperature(293.15) - for(var/obj/effect/hotspot/H in O) - qdel(H) - for(var/I in G.get_gases()) - if(I == /datum/gas/oxygen || I == /datum/gas/nitrogen) - continue - G.set_moles(I, 0) - O.air_update_turf() - for(var/obj/machinery/atmospherics/components/unary/U in O) - if(!U.welded) - U.welded = TRUE - U.update_icon() - U.visible_message(span_danger("[U] sealed shut!")) - for(var/mob/living/L in O) - L.ExtinguishMob() - for(var/obj/item/Item in O) - Item.extinguish() - -/obj/structure/foamedmetal/resin/CanAllowThrough(atom/movable/mover, turf/target) - . = ..() - if(istype(mover) && (mover.pass_flags & PASSGLASS)) - return TRUE - -#undef ALUMINUM_FOAM -#undef IRON_FOAM -#undef RESIN_FOAM diff --git a/code/game/objects/effects/effect_system/effects_smoke.dm b/code/game/objects/effects/effect_system/effects_smoke.dm deleted file mode 100644 index 29b4a3fd7ff9..000000000000 --- a/code/game/objects/effects/effect_system/effects_smoke.dm +++ /dev/null @@ -1,336 +0,0 @@ -///////////////////////////////////////////// -//// SMOKE SYSTEMS -///////////////////////////////////////////// - -/obj/effect/particle_effect/smoke - name = "smoke" - icon = 'icons/effects/96x96.dmi' - icon_state = "smoke" - pixel_x = -32 - pixel_y = -32 - opacity = 0 - layer = FLY_LAYER - anchored = TRUE - mouse_opacity = MOUSE_OPACITY_TRANSPARENT - animate_movement = 0 - var/amount = 4 - var/lifetime = 5 - var/opaque = 1 //whether the smoke can block the view when in enough amount - - -/obj/effect/particle_effect/smoke/proc/fade_out(frames = 16) - if(alpha == 0) //Handle already transparent case - return - if(frames == 0) - frames = 1 //We will just assume that by 0 frames, the coder meant "during one frame". - var/lighting_updated = FALSE - var/step = alpha / frames - for(var/i = 0, i < frames, i++) - alpha -= step - if(alpha < 160) - set_opacity(0) //if we were blocking view, we aren't now because we're fading out - if(!lighting_updated) // Only update lights around me once we have sufficiently faded, and only do it once - lighting_updated = TRUE - for(var/atom/L in view(15, src)) // Floodlights reach 15 tiles max, this should be sufficient - L.light?.force_update() - CHECK_TICK - stoplag() - -/obj/effect/particle_effect/smoke/Initialize() - . = ..() - create_reagents(500) - START_PROCESSING(SSobj, src) - - -/obj/effect/particle_effect/smoke/Destroy() - STOP_PROCESSING(SSobj, src) - return ..() - -/obj/effect/particle_effect/smoke/proc/kill_smoke() - STOP_PROCESSING(SSobj, src) - INVOKE_ASYNC(src, .proc/fade_out) - QDEL_IN(src, 10) - -/obj/effect/particle_effect/smoke/process() - lifetime-- - if(lifetime < 1) - kill_smoke() - return 0 - for(var/mob/living/L in range(0,src)) - smoke_mob(L) - return 1 - -/obj/effect/particle_effect/smoke/proc/smoke_mob(mob/living/carbon/C) - if(!istype(C)) - return 0 - if(lifetime<1) - return 0 - if(C.internal != null || C.has_smoke_protection()) - return 0 - if(C.smoke_delay) - return 0 - C.smoke_delay++ - addtimer(CALLBACK(src, .proc/remove_smoke_delay, C), 10) - return 1 - -/obj/effect/particle_effect/smoke/proc/remove_smoke_delay(mob/living/carbon/C) - if(C) - C.smoke_delay = 0 - -/obj/effect/particle_effect/smoke/proc/spread_smoke() - var/turf/t_loc = get_turf(src) - if(!t_loc) - return - var/list/newsmokes = list() - for(var/turf/T in t_loc.GetAtmosAdjacentTurfs()) - var/obj/effect/particle_effect/smoke/foundsmoke = locate() in T //Don't spread smoke where there's already smoke! - if(foundsmoke) - continue - for(var/mob/living/L in T) - smoke_mob(L) - var/obj/effect/particle_effect/smoke/S = new type(T) - reagents.copy_to(S, reagents.total_volume) - S.setDir(pick(GLOB.cardinals)) - S.amount = amount-1 - S.add_atom_colour(color, FIXED_COLOUR_PRIORITY) - S.lifetime = lifetime - if(S.amount>0) - if(opaque) - S.set_opacity(TRUE) - newsmokes.Add(S) - - if(newsmokes.len) - spawn(1) //the smoke spreads rapidly but not instantly - for(var/obj/effect/particle_effect/smoke/SM in newsmokes) - SM.spread_smoke() - - -/datum/effect_system/smoke_spread - var/amount = 10 - effect_type = /obj/effect/particle_effect/smoke - -/datum/effect_system/smoke_spread/set_up(radius = 5, loca) - if(isturf(loca)) - location = loca - else - location = get_turf(loca) - amount = radius - -/datum/effect_system/smoke_spread/start() - if(holder) - location = get_turf(holder) - var/obj/effect/particle_effect/smoke/S = new effect_type(location) - S.amount = amount - if(S.amount) - S.spread_smoke() - - -///////////////////////////////////////////// -// Bad smoke -///////////////////////////////////////////// - -/obj/effect/particle_effect/smoke/bad - lifetime = 8 - -/obj/effect/particle_effect/smoke/bad/smoke_mob(mob/living/carbon/M) - if(..()) - M.drop_all_held_items() - M.adjustOxyLoss(1) - M.emote("cough") - return 1 - -/obj/effect/particle_effect/smoke/bad/Crossed(atom/movable/AM, oldloc) - . = ..() - if(istype(AM, /obj/item/projectile/beam)) - var/obj/item/projectile/beam/B = AM - B.damage = (B.damage/2) - -/datum/effect_system/smoke_spread/bad - effect_type = /obj/effect/particle_effect/smoke/bad - -///////////////////////////////////////////// -// Nanofrost smoke -///////////////////////////////////////////// - -/obj/effect/particle_effect/smoke/freezing - name = "nanofrost smoke" - color = "#B2FFFF" - opaque = 0 - -/datum/effect_system/smoke_spread/freezing - effect_type = /obj/effect/particle_effect/smoke/freezing - var/blast = 0 - var/temperature = 2 - var/weldvents = TRUE - var/distcheck = TRUE - -/datum/effect_system/smoke_spread/freezing/proc/Chilled(atom/A) - if(isopenturf(A)) - var/turf/open/T = A - if(T.air) - var/datum/gas_mixture/G = T.air - if(!distcheck || get_dist(T, location) < blast) // Otherwise we'll get silliness like people using Nanofrost to kill people through walls with cold air - G.set_temperature(temperature) - T.air_update_turf() - for(var/obj/effect/hotspot/H in T) - qdel(H) - if(G.get_moles(/datum/gas/plasma)) - G.adjust_moles(/datum/gas/nitrogen, G.get_moles(/datum/gas/plasma)) - G.set_moles(/datum/gas/plasma, 0) - if (weldvents) - for(var/obj/machinery/atmospherics/components/unary/U in T) - if(!isnull(U.welded) && !U.welded) //must be an unwelded vent pump or vent scrubber. - U.welded = TRUE - U.update_icon() - U.visible_message(span_danger("[U] was frozen shut!")) - for(var/mob/living/L in T) - L.ExtinguishMob() - for(var/obj/item/Item in T) - Item.extinguish() - -/datum/effect_system/smoke_spread/freezing/set_up(radius = 5, loca, blast_radius = 0) - ..() - blast = blast_radius - -/datum/effect_system/smoke_spread/freezing/start() - if(blast) - for(var/turf/T in RANGE_TURFS(blast, location)) - Chilled(T) - ..() - -/datum/effect_system/smoke_spread/freezing/decon - temperature = 293.15 - distcheck = FALSE - weldvents = FALSE - - -///////////////////////////////////////////// -// Sleep smoke -///////////////////////////////////////////// - -/obj/effect/particle_effect/smoke/sleeping - color = "#9C3636" - lifetime = 10 - -/obj/effect/particle_effect/smoke/sleeping/smoke_mob(mob/living/carbon/M) - if(..()) - M.Sleeping(200) - M.emote("cough") - return 1 - -/datum/effect_system/smoke_spread/sleeping - effect_type = /obj/effect/particle_effect/smoke/sleeping - -///////////////////////////////////////////// -// Chem smoke -///////////////////////////////////////////// - -/obj/effect/particle_effect/smoke/chem - lifetime = 10 - - -/obj/effect/particle_effect/smoke/chem/process() - if(..()) - var/turf/T = get_turf(src) - var/fraction = 1/initial(lifetime) - for(var/atom/movable/AM in T) - if(AM.type == src.type) - continue - if(T.intact && AM.level == 1) //hidden under the floor - continue - reagents.reaction(AM, TOUCH, fraction) - - reagents.reaction(T, TOUCH, fraction) - return 1 - -/obj/effect/particle_effect/smoke/chem/smoke_mob(mob/living/carbon/M) - if(lifetime<1) - return 0 - if(!istype(M)) - return 0 - var/mob/living/carbon/C = M - if(C.internal != null || C.has_smoke_protection()) - return 0 - var/fraction = 1/initial(lifetime) - reagents.copy_to(C, fraction*reagents.total_volume) - reagents.reaction(M, INGEST, fraction) - return 1 - - - -/datum/effect_system/smoke_spread/chem - var/obj/chemholder - effect_type = /obj/effect/particle_effect/smoke/chem - -/datum/effect_system/smoke_spread/chem/New() - ..() - chemholder = new /obj() - var/datum/reagents/R = new/datum/reagents(500) - chemholder.reagents = R - R.my_atom = chemholder - -/datum/effect_system/smoke_spread/chem/Destroy() - qdel(chemholder) - chemholder = null - return ..() - -/datum/effect_system/smoke_spread/chem/set_up(datum/reagents/carry = null, radius = 1, loca, silent = FALSE) - if(isturf(loca)) - location = loca - else - location = get_turf(loca) - amount = radius - carry.copy_to(chemholder, carry.total_volume) - - if(!silent) - var/contained = "" - for(var/reagent in carry.reagent_list) - contained += " [reagent] " - if(contained) - contained = "\[[contained]\]" - - var/where = "[AREACOORD(location)]" - if(carry.my_atom.fingerprintslast) - var/mob/M = get_mob_by_key(carry.my_atom.fingerprintslast) - var/more = "" - if(M) - more = "[ADMIN_LOOKUPFLW(M)] " - message_admins("Smoke: ([ADMIN_VERBOSEJMP(location)])[contained]. Key: [more ? more : carry.my_atom.fingerprintslast].") - log_game("A chemical smoke reaction has taken place in ([where])[contained]. Last touched by [carry.my_atom.fingerprintslast].") - else - message_admins("Smoke: ([ADMIN_VERBOSEJMP(location)])[contained]. No associated key.") - log_game("A chemical smoke reaction has taken place in ([where])[contained]. No associated key.") - - -/datum/effect_system/smoke_spread/chem/start() - var/mixcolor = mix_color_from_reagents(chemholder.reagents.reagent_list) - if(holder) - location = get_turf(holder) - var/obj/effect/particle_effect/smoke/chem/S = new effect_type(location) - - if(chemholder.reagents.total_volume > 1) // can't split 1 very well - chemholder.reagents.copy_to(S, chemholder.reagents.total_volume) - - if(mixcolor) - S.add_atom_colour(mixcolor, FIXED_COLOUR_PRIORITY) // give the smoke color, if it has any to begin with - S.amount = amount - if(S.amount) - S.spread_smoke() //calling process right now so the smoke immediately attacks mobs. - - -///////////////////////////////////////////// -// Transparent smoke -///////////////////////////////////////////// - -//Same as the base type, but the smoke produced is not opaque -/datum/effect_system/smoke_spread/transparent - effect_type = /obj/effect/particle_effect/smoke/transparent - -/obj/effect/particle_effect/smoke/transparent - opaque = FALSE - -/proc/do_smoke(range=0, location=null, smoke_type=/obj/effect/particle_effect/smoke) - var/datum/effect_system/smoke_spread/smoke = new - smoke.effect_type = smoke_type - smoke.set_up(range, location) - smoke.start() diff --git a/code/game/objects/effects/effect_system/fluid_spread/_fluid_spread.dm b/code/game/objects/effects/effect_system/fluid_spread/_fluid_spread.dm new file mode 100644 index 000000000000..9987eef158cb --- /dev/null +++ b/code/game/objects/effects/effect_system/fluid_spread/_fluid_spread.dm @@ -0,0 +1,159 @@ +///////////////////////////////////////////// +//// SMOKE SYSTEMS +///////////////////////////////////////////// + +/** + * A group of fluid objects. + */ +/datum/fluid_group + /// The set of fluid objects currently in this group. + var/list/nodes + /// The number of fluid object that this group wants to have contained. + var/target_size + /// The total number of fluid objects that have ever been in this group. + var/total_size = 0 + +/datum/fluid_group/New(target_size = 0) + . = ..() + src.nodes = list() + src.target_size = target_size + +/datum/fluid_group/Destroy(force) + QDEL_LAZYLIST(nodes) + return ..() + +/** + * Adds a fluid node to this fluid group. + * + * Is a noop if the node is already in the group. + * Removes the node from any other fluid groups it is in. + * Syncs the group of the node with the group it is being added to (this one). + * Increments the total size of the fluid group. + * + * Arguments: + * - [node][/obj/effect/particle_effect/fluid]: The fluid node that is going to be added to this group. + * + * Returns: + * - [TRUE]: If the node to be added is in this group by the end of the proc. + * - [FALSE]: Otherwise. + */ +/datum/fluid_group/proc/add_node(obj/effect/particle_effect/fluid/node) + if(!istype(node)) + CRASH("Attempted to add non-fluid node [isnull(node) ? "NULL" : node] to a fluid group.") + if(QDELING(node)) + CRASH("Attempted to add qdeling node to a fluid group") + + if(node.group) + if(node.group == src) + return TRUE + if(!node.group.remove_node(node)) + return FALSE + + nodes += node + node.group = src + total_size++ + return TRUE + + +/** + * Removes a fluid node from this fluid group. + * + * Is a noop if the node is not in this group. + * Nulls the nodes fluid group ref to sync it with its new state. + * DOES NOT decrement the total size of the fluid group. + * + * Arguments: + * - [node][/obj/effect/particle_effect/fluid]: The fluid node that is going to be removed from this group. + * + * Returns: + * - [TRUE]: If the node to be removed is not in the group by the end of the proc. + */ +/datum/fluid_group/proc/remove_node(obj/effect/particle_effect/fluid/node) + if(node.group != src) + return TRUE + + nodes -= node + node.group = null + return TRUE // Note: does not decrement total size since we don't want the group to expand again when it begins to dissipate or it will never stop. + + +/** + * A particle effect that belongs to a fluid group. + */ +/obj/effect/particle_effect/fluid + name = "fluid" + /// The fluid group that this particle effect belongs to. + var/datum/fluid_group/group + /// What SSfluid bucket this particle effect is currently in. + var/tmp/effect_bucket + /// The index of the fluid spread bucket this is being spread in. + var/tmp/spread_bucket + +/obj/effect/particle_effect/fluid/Initialize(mapload, datum/fluid_group/group, obj/effect/particle_effect/fluid/source) + // We don't pass on explosions. Don't wanna set off a chain reaction in our reagents + flags_1 |= PREVENT_CONTENTS_EXPLOSION_1 + . = ..() + if(!group) + group = source?.group || new + group.add_node(src) + source?.transfer_fingerprints_to(src) + +/obj/effect/particle_effect/fluid/Destroy() + group.remove_node(src) + return ..() + +/** + * Attempts to spread this fluid node to wherever it can spread. + * + * Exact results vary by subtype implementation. + */ +/obj/effect/particle_effect/fluid/proc/spread() + CRASH("The base fluid spread proc is not implemented and should not be called. You called it.") + + +/** + * A factory which produces fluid groups. + */ +/datum/effect_system/fluid_spread + effect_type = /obj/effect/particle_effect/fluid + /// The amount of smoke to produce. + var/amount = 10 + +/datum/effect_system/fluid_spread/set_up(range = 1, amount = DIAMOND_AREA(range), atom/holder, atom/location, ...) + src.holder = holder + src.location = location + src.amount = amount + +/datum/effect_system/fluid_spread/start(log = FALSE) + var/location = src.location || get_turf(holder) + var/obj/effect/particle_effect/fluid/flood = new effect_type(location, new /datum/fluid_group(amount)) + if (log) // Smoke is used as an aesthetic effect in a tonne of places and we don't want, say, a broken secway spamming admin chat. + help_out_the_admins(flood, holder, location) + flood.spread() + +/** + * Handles logging the beginning of a fluid flood. + * + * Arguments: + * - [flood][/obj/effect/particle_effect/fluid]: The first cell of the fluid flood. + * - [holder][/atom]: What the flood originated from. + * - [location][/atom]: Where the flood originated. + */ +/datum/effect_system/fluid_spread/proc/help_out_the_admins(obj/effect/particle_effect/fluid/flood, atom/holder, atom/location) + var/source_msg + var/blame_msg + if (holder) + holder.transfer_fingerprints_to(flood) // This is important. If this doesn't exist thermobarics are annoying to adjudicate. + + source_msg = "from inside of [ismob(holder) ? ADMIN_LOOKUPFLW(holder) : ADMIN_VERBOSEJMP(holder)]" + var/lastkey = holder.fingerprintslast + if (lastkey) + var/mob/scapegoat = get_mob_by_key(lastkey) + blame_msg = " last touched by [ADMIN_LOOKUPFLW(scapegoat)]" + else + blame_msg = " with no known fingerprints" + else + source_msg = "with no known source" + + message_admins("\A [flood] flood started at [ADMIN_VERBOSEJMP(location)] [source_msg][blame_msg].") + log_game("\A [flood] flood started at [location || "nonexistant location"] [holder ? "from [holder] last touched by [holder || "N/A"]" : "with no known source"].") diff --git a/code/game/objects/effects/effect_system/fluid_spread/effects_foam.dm b/code/game/objects/effects/effect_system/fluid_spread/effects_foam.dm new file mode 100644 index 000000000000..7480b2a40330 --- /dev/null +++ b/code/game/objects/effects/effect_system/fluid_spread/effects_foam.dm @@ -0,0 +1,404 @@ +/// The minimum foam range required to start diluting the reagents past the minimum dilution rate. +#define MINIMUM_FOAM_DILUTION_RANGE 3 +/// The minumum foam-area based divisor used to decrease foam exposure volume. +#define MINIMUM_FOAM_DILUTION DIAMOND_AREA(MINIMUM_FOAM_DILUTION_RANGE) +/// The effective scaling of the reagents in the foam. (Total delivered at or below [MINIMUM_FOAM_DILUTION]) +#define FOAM_REAGENT_SCALE 3.2 + +/** + * ## Foam + * + * Similar to smoke, but slower and mobs absorb its reagent through their exposed skin. + */ +/obj/effect/particle_effect/fluid/foam + name = "foam" + icon_state = "foam" + opacity = FALSE + anchored = TRUE + density = FALSE + layer = EDGED_TURF_LAYER + mouse_opacity = MOUSE_OPACITY_TRANSPARENT + animate_movement = NO_STEPS + /// The types of turfs that this foam cannot spread to. + var/static/list/blacklisted_turfs = typecacheof(list( + /turf/open/space/transit, + /turf/open/chasm, + /turf/open/lava, + )) + /// The typepath for what this foam leaves behind when it dissipates. + var/atom/movable/result_type = null + /// Whether or not this foam can produce a remnant movable if something of the same type is already on its turf. + var/allow_duplicate_results = TRUE + /// The amount of time this foam stick around for before it dissipates. + var/lifetime = 8 SECONDS + /// Whether or not this foam should be slippery. + var/slippery_foam = TRUE + + +/obj/effect/particle_effect/fluid/foam/Initialize(mapload) + . = ..() + if(slippery_foam) + AddComponent(/datum/component/slippery, 100) + create_reagents(1000) + playsound(src, 'sound/effects/bubbles2.ogg', 80, TRUE, -3) + //AddElement(/datum/element/atmos_sensitive, mapload) + SSfoam.start_processing(src) + +/obj/effect/particle_effect/fluid/foam/Destroy() + SSfoam.stop_processing(src) + if (spread_bucket) + SSfoam.cancel_spread(src) + return ..() + +/** + * Makes the foam dissipate and create whatever remnants it must. + */ +/obj/effect/particle_effect/fluid/foam/proc/kill_foam() + SSfoam.stop_processing(src) + if (spread_bucket) + SSfoam.cancel_spread(src) + make_result() + flick("[icon_state]-disolve", src) + QDEL_IN(src, 0.5 SECONDS) + +/** + * Makes the foam leave behind something when it dissipates. + * + * Returns the thing the foam leaves behind for further modification by subtypes. + */ +/obj/effect/particle_effect/fluid/foam/proc/make_result() + if(isnull(result_type)) + return null + + var/atom/location = loc + var/atom/movable/result = (!allow_duplicate_results && (locate(result_type) in location)) || (new result_type(location)) + transfer_fingerprints_to(result) + return result + +/obj/effect/particle_effect/fluid/foam/process(delta_time) + var/ds_delta_time = delta_time SECONDS + lifetime -= ds_delta_time + if(lifetime <= 0) + kill_foam() + return + + var/fraction = (ds_delta_time * MINIMUM_FOAM_DILUTION) / (initial(lifetime) * max(MINIMUM_FOAM_DILUTION, group.total_size)) + var/turf/location = loc + for(var/obj/object in location) + if(object == src) + continue + if(isturf(object.loc)) + var/turf/turf = object.loc + if(turf.intact && object.level == 1) //hidden under the floor + continue + reagents.reaction(object, VAPOR, fraction) + + var/hit = 0 + for(var/mob/living/foamer in location) + hit += foam_mob(foamer, delta_time) + if(hit) + lifetime += ds_delta_time //this is so the decrease from mobs hit and the natural decrease don't cumulate. + + reagents.reaction(location, VAPOR, fraction) + +/** + * Applies the effect of this foam to a mob. + * + * Arguments: + * - [foaming][/mob/living]: The mob that this foam is acting on. + * - delta_time: The amount of time that this foam is acting on them over. + * + * Returns: + * - [TRUE]: If the foam was successfully applied to the mob. Used to scale how quickly foam dissipates according to the number of mobs it is applied to. + * - [FALSE]: Otherwise. + */ +/obj/effect/particle_effect/fluid/foam/proc/foam_mob(mob/living/foaming, delta_time) + if(lifetime <= 0) + return FALSE + if(!istype(foaming)) + return FALSE + + delta_time = min(delta_time SECONDS, lifetime) + var/fraction = (delta_time * MINIMUM_FOAM_DILUTION) / (initial(lifetime) * max(MINIMUM_FOAM_DILUTION, group.total_size)) + reagents.reaction(foaming, VAPOR, fraction) + lifetime -= delta_time + return TRUE + +/obj/effect/particle_effect/fluid/foam/spread(delta_time = 0.2 SECONDS) + if(group.total_size > group.target_size) + return + var/turf/location = get_turf(src) + if(!istype(location)) + return FALSE + + for(var/turf/spread_turf as anything in location.reachableAdjacentTurfs()) + var/obj/effect/particle_effect/fluid/foam/foundfoam = locate() in spread_turf //Don't spread foam where there's already foam! + if(foundfoam) + continue + + if(is_type_in_typecache(spread_turf, blacklisted_turfs)) + continue + + for(var/mob/living/foaming in spread_turf) + foam_mob(foaming, delta_time) + + var/obj/effect/particle_effect/fluid/foam/spread_foam = new type(spread_turf, group, src) + reagents.copy_to(spread_foam, (reagents.total_volume)) + spread_foam.add_atom_colour(color, FIXED_COLOUR_PRIORITY) + spread_foam.result_type = result_type + SSfoam.queue_spread(spread_foam) + +/obj/effect/particle_effect/fluid/foam/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume) + if(prob(max(0, exposed_temperature - 475))) //foam dissolves when heated + kill_foam() + +/obj/effect/particle_effect/fluid/foam/metal/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume) + return + +/// A factory for foam fluid floods. +/datum/effect_system/fluid_spread/foam + effect_type = /obj/effect/particle_effect/fluid/foam + /// A container for all of the chemicals we distribute through the foam. + var/datum/reagents/chemholder + /// The amount that + var/reagent_scale = FOAM_REAGENT_SCALE + /// What type of thing the foam should leave behind when it dissipates. + var/atom/movable/result_type = null + + +/datum/effect_system/fluid_spread/foam/New() + ..() + chemholder = new(1000, NO_REACT) + +/datum/effect_system/fluid_spread/foam/Destroy() + QDEL_NULL(chemholder) + return ..() + +/datum/effect_system/fluid_spread/foam/set_up(range = 1, amount = DIAMOND_AREA(range), atom/holder, atom/location = null, datum/reagents/carry = null, result_type = null) + . = ..() + carry?.copy_to(chemholder, carry.total_volume) + if(!isnull(result_type)) + src.result_type = result_type + +/datum/effect_system/fluid_spread/foam/start(log = FALSE) + var/obj/effect/particle_effect/fluid/foam/foam = new effect_type(location, new /datum/fluid_group(amount)) + var/foamcolor = mix_color_from_reagents(chemholder.reagent_list) + if(reagent_scale > 1) // Make room in case we were created by a particularly stuffed payload. + foam.reagents.maximum_volume *= reagent_scale + chemholder.copy_to(foam, chemholder.total_volume, reagent_scale) // Foam has an amplifying effect on the reagents it is supplied with. This is balanced by the reagents being diluted as the area the foam covers increases. + foam.add_atom_colour(foamcolor, FIXED_COLOUR_PRIORITY) + if(!isnull(result_type)) + foam.result_type = result_type + if (log) + help_out_the_admins(foam, holder, location) + SSfoam.queue_spread(foam) + + +// Short-lived foam +/// A foam variant which dissipates quickly. +/obj/effect/particle_effect/fluid/foam/short_life + lifetime = 1 SECONDS + +/datum/effect_system/fluid_spread/foam/short + effect_type = /obj/effect/particle_effect/fluid/foam/short_life + +// Long lasting foam +/// A foam variant which lasts for an extended amount of time. +/obj/effect/particle_effect/fluid/foam/long_life + lifetime = 30 SECONDS + +/// A factory which produces foam with an extended lifespan. +/datum/effect_system/fluid_spread/foam/long + effect_type = /obj/effect/particle_effect/fluid/foam/long_life + reagent_scale = FOAM_REAGENT_SCALE * (30 / 8) + + +// Firefighting foam +/// A variant of foam which absorbs plasma in the air if there is a fire. +/obj/effect/particle_effect/fluid/foam/firefighting + name = "firefighting foam" + lifetime = 20 //doesn't last as long as normal foam + result_type = /obj/effect/decal/cleanable/plasma + allow_duplicate_results = FALSE + slippery_foam = FALSE + /// The amount of plasma gas this foam has absorbed. To be deposited when the foam dissipates. + var/absorbed_plasma = 0 + +/obj/effect/particle_effect/fluid/foam/firefighting/Initialize(mapload) + . = ..() + //RemoveElement(/datum/element/atmos_sensitive) + +/obj/effect/particle_effect/fluid/foam/firefighting/process() + ..() + + var/turf/open/location = loc + if(!istype(location)) + return + + var/obj/effect/hotspot/hotspot = locate() in location + if(!(hotspot && location.air)) + return + + QDEL_NULL(hotspot) + var/datum/gas_mixture/air = location.air + var/scrub_amt = min(30, air.get_moles(/datum/gas/plasma)) //Absorb some plasma + air.adjust_moles(/datum/gas/plasma, -scrub_amt) + absorbed_plasma += scrub_amt + + if (air.return_temperature() > T20C) + air.set_temperature(max(air.return_temperature() / 2, T20C)) + + location.air_update_turf(FALSE, FALSE) + +/obj/effect/particle_effect/fluid/foam/firefighting/make_result() + var/atom/movable/deposit = ..() + if(istype(deposit) && deposit.reagents && absorbed_plasma > 0) + deposit.reagents.add_reagent(/datum/reagent/stable_plasma, absorbed_plasma) + absorbed_plasma = 0 + return deposit + +/obj/effect/particle_effect/fluid/foam/firefighting/foam_mob(mob/living/foaming, delta_time) + if(!istype(foaming)) + return + foaming.adjust_fire_stacks(-2) + foaming.ExtinguishMob() + +/// A factory which produces firefighting foam +/datum/effect_system/fluid_spread/foam/firefighting + effect_type = /obj/effect/particle_effect/fluid/foam/firefighting + +// Metal foam + +/// A foam variant which +/obj/effect/particle_effect/fluid/foam/metal + name = "aluminium foam" + result_type = /obj/structure/foamedmetal + icon_state = "mfoam" + slippery_foam = FALSE + +/// A factory which produces aluminium metal foam. +/datum/effect_system/fluid_spread/foam/metal + effect_type = /obj/effect/particle_effect/fluid/foam/metal + +/// FOAM STRUCTURE. Formed by metal foams. Dense and opaque, but easy to break +/obj/structure/foamedmetal + icon = 'icons/effects/effects.dmi' + icon_state = "metalfoam" + density = TRUE + opacity = TRUE // changed in New() + anchored = TRUE + layer = EDGED_TURF_LAYER + resistance_flags = FIRE_PROOF | ACID_PROOF + name = "foamed metal" + desc = "A lightweight foamed metal wall that can be used as base to construct a wall." + gender = PLURAL + max_integrity = 20 + CanAtmosPass = ATMOS_PASS_DENSITY + ///Var used to prevent spamming of the construction sound + var/next_beep = 0 + +/obj/structure/foamedmetal/Initialize(mapload) + . = ..() + air_update_turf(1) + +/obj/structure/foamedmetal/Move() + var/turf/T = loc + . = ..() + move_update_air(T) + +/obj/structure/foamedmetal/attack_paw(mob/user, list/modifiers) + return attack_hand(user, modifiers) + +/obj/structure/foamedmetal/play_attack_sound(damage_amount, damage_type = BRUTE, damage_flag = 0) + playsound(src.loc, 'sound/weapons/tap.ogg', 100, TRUE) + +/obj/structure/foamedmetal/attack_hand(mob/user, list/modifiers) + . = ..() + if(.) + return + user.changeNext_move(CLICK_CD_MELEE) + user.do_attack_animation(src, ATTACK_EFFECT_PUNCH) + to_chat(user, span_warning("You hit [src] but bounce off it!")) + playsound(src.loc, 'sound/weapons/tap.ogg', 100, TRUE) + +/// A metal foam variant which produces slightly sturdier walls. +/obj/effect/particle_effect/fluid/foam/metal/iron + name = "iron foam" + result_type = /obj/structure/foamedmetal/iron + +/// A factory which produces iron metal foam. +/datum/effect_system/fluid_spread/foam/metal/iron + effect_type = /obj/effect/particle_effect/fluid/foam/metal/iron + +/// A variant of metal foam walls with higher durability. +/obj/structure/foamedmetal/iron + max_integrity = 50 + icon_state = "ironfoam" + +/// A variant of metal foam which only produces walls at area boundaries. +/obj/effect/particle_effect/fluid/foam/metal/smart + name = "smart foam" + +/// A factory which produces smart aluminium metal foam. +/datum/effect_system/fluid_spread/foam/metal/smart + effect_type = /obj/effect/particle_effect/fluid/foam/metal/smart + +/obj/effect/particle_effect/fluid/foam/metal/smart/make_result() //Smart foam adheres to area borders for walls + var/turf/open/location = loc + if(isspaceturf(location)) + location.PlaceOnTop(/turf/open/floor/plating/foam) + + for(var/cardinal in GLOB.cardinals) + var/turf/cardinal_turf = get_step(location, cardinal) + if(get_area(cardinal_turf) != get_area(location)) + return ..() + return null + +/datum/effect_system/fluid_spread/foam/metal/resin + effect_type = /obj/effect/particle_effect/fluid/foam/metal/resin + +/// A foam variant which produces atmos resin walls. +/obj/effect/particle_effect/fluid/foam/metal/resin + name = "resin foam" + result_type = /obj/structure/foamedmetal/resin + +/// Atmos Backpack Resin, transparent, prevents atmos and filters the air +/obj/structure/foamedmetal/resin + name = "\improper ATMOS Resin" + desc = "A lightweight, transparent resin used to suffocate fires, scrub the air of toxins, and restore the air to a safe temperature. It can be used as base to construct a wall." + opacity = FALSE + icon_state = "atmos_resin" + alpha = 120 + max_integrity = 10 + +/obj/structure/foamedmetal/resin/Initialize(mapload) + . = ..() + var/turf/open/location = loc + if(!istype(location)) + return + + location.ClearWet() + if(location.air) + var/datum/gas_mixture/air = location.air + air.set_temperature(T20C) + for(var/obj/effect/hotspot/fire in location) + qdel(fire) + + for(var/gas_type in air.get_gases()) + switch(gas_type) + if(/datum/gas/oxygen, /datum/gas/nitrogen) + continue + else + air.set_moles(gas_type, 0) + location.air_update_turf() + + for(var/obj/machinery/atmospherics/components/unary/comp in location) + if(!comp.welded) + comp.welded = TRUE + comp.update_icon() + comp.visible_message(span_danger("[comp] sealed shut!")) + + for(var/mob/living/potential_tinder in location) + potential_tinder.ExtinguishMob() + for(var/obj/item/potential_tinder in location) + potential_tinder.extinguish() diff --git a/code/game/objects/effects/effect_system/fluid_spread/effects_smoke.dm b/code/game/objects/effects/effect_system/fluid_spread/effects_smoke.dm new file mode 100644 index 000000000000..5bc55db1d9c6 --- /dev/null +++ b/code/game/objects/effects/effect_system/fluid_spread/effects_smoke.dm @@ -0,0 +1,455 @@ +/** + * A fluid which spreads through the air affecting every mob it engulfs. + */ +/obj/effect/particle_effect/fluid/smoke + name = "smoke" + icon = 'icons/effects/96x96.dmi' + icon_state = "smoke" + pixel_x = -32 + pixel_y = -32 + opacity = TRUE + layer = FLY_LAYER + anchored = TRUE + mouse_opacity = MOUSE_OPACITY_TRANSPARENT + animate_movement = FALSE + /// How long the smoke sticks around before it dissipates. + var/lifetime = 10 SECONDS + /// Makes the smoke react to changes on/of its turf. + var/static/loc_connections = list( + COMSIG_TURF_CALCULATED_ADJACENT_ATMOS = .proc/react_to_atmos_adjacency_changes + ) + +/obj/effect/particle_effect/fluid/smoke/Initialize(mapload, datum/fluid_group/group, ...) + . = ..() + create_reagents(500) + setDir(pick(GLOB.cardinals)) + //AddElement(/datum/element/connect_loc, loc_connections) + SSsmoke.start_processing(src) + +/obj/effect/particle_effect/fluid/smoke/Destroy() + SSsmoke.stop_processing(src) + if (spread_bucket) + SSsmoke.cancel_spread(src) + return ..() + + +/** + * Makes the smoke fade out and then deletes it. + */ +/obj/effect/particle_effect/fluid/smoke/proc/kill_smoke() + SSsmoke.stop_processing(src) + if (spread_bucket) + SSsmoke.cancel_spread(src) + INVOKE_ASYNC(src, .proc/fade_out) + QDEL_IN(src, 1 SECONDS) + +/** + * Animates the smoke gradually fading out of visibility. + * Also makes the smoke turf transparent as it passes 160 alpha. + * + * Arguments: + * - frames = 0.8 [SECONDS]: The amount of time the smoke should fade out over. + */ +/obj/effect/particle_effect/fluid/smoke/proc/fade_out(frames = 0.8 SECONDS) + if(alpha == 0) //Handle already transparent case + if(opacity) + set_opacity(FALSE) + return + + if(frames == 0) + set_opacity(FALSE) + alpha = 0 + return + + var/time_to_transparency = round(((alpha - 160) / alpha) * frames) + if(time_to_transparency >= 1) + addtimer(CALLBACK(src, /atom.proc/set_opacity, FALSE), time_to_transparency) + else + set_opacity(FALSE) + animate(src, time = frames, alpha = 0) + + +/obj/effect/particle_effect/fluid/smoke/spread(delta_time = 0.1 SECONDS) + if(group.total_size > group.target_size) + return + var/turf/t_loc = get_turf(src) + if(!t_loc) + return + + for(var/turf/spread_turf in t_loc.GetAtmosAdjacentTurfs()) + if(group.total_size > group.target_size) + break + if(locate(type) in spread_turf) + continue // Don't spread smoke where there's already smoke! + for(var/mob/living/smoker in spread_turf) + smoke_mob(smoker, delta_time) + + var/obj/effect/particle_effect/fluid/smoke/spread_smoke = new type(spread_turf, group, src) + reagents.copy_to(spread_smoke, reagents.total_volume) + spread_smoke.add_atom_colour(color, FIXED_COLOUR_PRIORITY) + spread_smoke.lifetime = lifetime + + // the smoke spreads rapidly, but not instantly + SSfoam.queue_spread(spread_smoke) + + +/obj/effect/particle_effect/fluid/smoke/process(delta_time) + lifetime -= delta_time SECONDS + if(lifetime <= 0) + kill_smoke() + return FALSE + for(var/mob/living/smoker in loc) // In case smoke somehow winds up in a locker or something this should still behave sanely. + smoke_mob(smoker, delta_time) + return TRUE + +/** + * Handles the effects of this smoke on any mobs it comes into contact with. + * + * Arguments: + * - [smoker][/mob/living/carbon]: The mob that is being exposed to this smoke. + * - delta_time: A scaling factor for the effects this has. Primarily based off of tick rate to normalize effects to units of rate/sec. + * + * Returns whether the smoke effect was applied to the mob. + */ +/obj/effect/particle_effect/fluid/smoke/proc/smoke_mob(mob/living/carbon/smoker, delta_time) + if(!istype(smoker)) + return FALSE + if(lifetime < 1) + return FALSE + if(smoker.internal != null || smoker.has_smoke_protection()) + return FALSE + if(smoker.smoke_delay) + return FALSE + + smoker.smoke_delay = TRUE + addtimer(VARSET_CALLBACK(smoker, smoke_delay, FALSE), 1 SECONDS) + return TRUE + +/** + * Makes the smoke react to nearby opening/closing airlocks and the like. + * Makes it possible for smoke to spread through airlocks that open after the edge of the smoke cloud has already spread past them. + * + * Arguments: + * - [source][/turf]: The turf that has been touched by an atmos adjacency change. + */ +/obj/effect/particle_effect/fluid/smoke/proc/react_to_atmos_adjacency_changes(turf/source) + SIGNAL_HANDLER + if(!group) + return NONE + if (spread_bucket) + return NONE + SSsmoke.queue_spread(src) + +/// A factory which produces clouds of smoke. +/datum/effect_system/fluid_spread/smoke + effect_type = /obj/effect/particle_effect/fluid/smoke + +///////////////////////////////////////////// +// Transparent smoke +///////////////////////////////////////////// + +/// Same as the base type, but the smoke produced is not opaque +/datum/effect_system/fluid_spread/smoke/transparent + effect_type = /obj/effect/particle_effect/fluid/smoke/transparent + +/// Same as the base type, but is not opaque. +/obj/effect/particle_effect/fluid/smoke/transparent + opacity = FALSE + +/** + * A helper proc used to spawn small puffs of smoke. + * + * Arguments: + * - range: The amount of smoke to produce as number of steps from origin covered. + * - amount: The amount of smoke to produce as the total desired coverage area. Autofilled from the range arg if not set. + * - location: Where to produce the smoke cloud. + * - smoke_type: The smoke typepath to spawn. + */ +/proc/do_smoke(range = 0, amount = DIAMOND_AREA(range), atom/holder = null, location = null, smoke_type = /obj/effect/particle_effect/fluid/smoke, log = FALSE) + var/datum/effect_system/fluid_spread/smoke/smoke = new + smoke.effect_type = smoke_type + smoke.set_up(amount = amount, holder = holder, location = location) + smoke.start(log = log) + +///////////////////////////////////////////// +// Quick smoke +///////////////////////////////////////////// + +/// Smoke that dissipates as quickly as possible. +/obj/effect/particle_effect/fluid/smoke/quick + lifetime = 1 SECONDS + opacity = FALSE + +/// A factory which produces smoke that dissipates as quickly as possible. +/datum/effect_system/fluid_spread/smoke/quick + effect_type = /obj/effect/particle_effect/fluid/smoke/quick + +///////////////////////////////////////////// +// Bad smoke +///////////////////////////////////////////// + +/// Smoke that makes you cough and reduces the power of lasers. +/obj/effect/particle_effect/fluid/smoke/bad + lifetime = 16 SECONDS + +/obj/effect/particle_effect/fluid/smoke/bad/Initialize(mapload) + . = ..() + /*var/static/list/loc_connections = list( + COMSIG_ATOM_ENTERED = .proc/on_entered, + )*/ + RegisterSignal(src, COMSIG_ATOM_ENTERED, .proc/on_entered) + //AddElement(/datum/element/connect_loc, loc_connections) + +/obj/effect/particle_effect/fluid/smoke/bad/smoke_mob(mob/living/carbon/smoker) + . = ..() + if(!.) + return + + smoker.drop_all_held_items() + smoker.adjustOxyLoss(1) + smoker.emote("cough") + +/** + * Reduces the power of any beam projectile that passes through the smoke. + * + * Arguments: + * - [source][/datum]: The location that has just been entered. If [/datum/element/connect_loc] is working this is [src.loc][/atom/var/loc]. + * - [arrived][/atom/movable]: The atom that has just entered the source location. + * - [old_loc][/atom]: The location the entering atom just was in. + * - [old_locs][/list/atom]: The set of locations the entering atom was just in. + */ +/obj/effect/particle_effect/fluid/smoke/bad/proc/on_entered(datum/source, atom/movable/arrived, atom/oldloc) + SIGNAL_HANDLER + if(istype(arrived, /obj/item/projectile/beam)) + var/obj/item/projectile/beam/beam = arrived + beam.damage = (beam.damage/2) + +/// A factory which produces smoke that makes you cough. +/datum/effect_system/fluid_spread/smoke/bad + effect_type = /obj/effect/particle_effect/fluid/smoke/bad + +///////////////////////////////////////////// +// Bad Smoke (But Green (and Black)) +///////////////////////////////////////////// + +/// Green smoke that makes you cough. +/obj/effect/particle_effect/fluid/smoke/bad/green + name = "green smoke" + color = "#00FF00" + opacity = FALSE + +/// A factory which produces green smoke that makes you cough. +/datum/effect_system/fluid_spread/smoke/bad/green + effect_type = /obj/effect/particle_effect/fluid/smoke/bad/green + +/// Black smoke that makes you cough. (Actually dark grey) +/obj/effect/particle_effect/fluid/smoke/bad/black + name = "black smoke" + color = "#383838" + opacity = FALSE + +/// A factory which produces black smoke that makes you cough. +/datum/effect_system/fluid_spread/smoke/bad/black + effect_type = /obj/effect/particle_effect/fluid/smoke/bad/black + +///////////////////////////////////////////// +// Nanofrost smoke +///////////////////////////////////////////// + +/// Light blue, transparent smoke which is usually paired with a blast that chills every turf in the area. +/obj/effect/particle_effect/fluid/smoke/freezing + name = "nanofrost smoke" + color = "#B2FFFF" + opacity = FALSE + +/// A factory which produces light blue, transparent smoke and a blast that chills every turf in the area. +/datum/effect_system/fluid_spread/smoke/freezing + effect_type = /obj/effect/particle_effect/fluid/smoke/freezing + /// The radius in which to chill every open turf. + var/blast = 0 + /// The temperature to set the turfs air temperature to. + var/temperature = 2 + /// Whether to weld every vent and air scrubber in the affected area shut. + var/weldvents = TRUE + /// Whether to make sure each affected turf is actually within range before cooling it. + var/distcheck = TRUE + +/** + * Chills an open turf. + * + * Forces the air temperature to a specific value. + * Transmutes all of the plasma in the air into nitrogen. + * Extinguishes all fires and burning objects/mobs in the turf. + * May freeze all vents and vent scrubbers shut. + * + * Arguments: + * - [chilly][/turf/open]: The open turf to chill + */ +/datum/effect_system/fluid_spread/smoke/freezing/proc/Chilled(turf/open/chilly) + if(!istype(chilly)) + return + + if(chilly.air) + var/datum/gas_mixture/air = chilly.air + if(!distcheck || get_dist(location, chilly) < blast) // Otherwise we'll get silliness like people using Nanofrost to kill people through walls with cold air + air.set_temperature(temperature) + + if(air.get_moles(/datum/gas/plasma)) + air.adjust_moles(/datum/gas/nitrogen, air.get_moles(/datum/gas/plasma)) + air.set_moles(/datum/gas/plasma, 0) + + for(var/obj/effect/hotspot/fire in chilly) + qdel(fire) + chilly.air_update_turf() + + if(weldvents) + for(var/obj/machinery/atmospherics/components/unary/comp in chilly) + if(!isnull(comp.welded) && !comp.welded) //must be an unwelded vent pump or vent scrubber. + comp.welded = TRUE + comp.update_icon() + comp.visible_message(span_danger("[comp] is frozen shut!")) + + // Extinguishes everything in the turf + for(var/mob/living/potential_tinder in chilly) + potential_tinder.ExtinguishMob() + for(var/obj/item/potential_tinder in chilly) + potential_tinder.extinguish() + +/datum/effect_system/fluid_spread/smoke/freezing/set_up(range = 5, amount = DIAMOND_AREA(range), atom/holder, atom/location, blast_radius = 0) + . = ..() + blast = blast_radius + +/datum/effect_system/fluid_spread/smoke/freezing/start(log = FALSE) + if(blast) + for(var/turf/T in RANGE_TURFS(blast, location)) + Chilled(T) + return ..() + +/// A variant of the base freezing smoke formerly used by the vent decontamination event. +/datum/effect_system/fluid_spread/smoke/freezing/decon + temperature = 293.15 + distcheck = FALSE + weldvents = FALSE + + +///////////////////////////////////////////// +// Sleep smoke +///////////////////////////////////////////// + +/// Smoke which knocks you out if you breathe it in. +/obj/effect/particle_effect/fluid/smoke/sleeping + color = "#9C3636" + lifetime = 20 SECONDS + +/obj/effect/particle_effect/fluid/smoke/sleeping/smoke_mob(mob/living/carbon/smoker, delta_time) + if(..()) + smoker.Sleeping(20 SECONDS) + smoker.emote("cough") + return TRUE + +/// A factory which produces sleeping smoke. +/datum/effect_system/fluid_spread/smoke/sleeping + effect_type = /obj/effect/particle_effect/fluid/smoke/sleeping + +///////////////////////////////////////////// +// Chem smoke +///////////////////////////////////////////// + +/** + * Smoke which contains reagents which it applies to everything it comes into contact with. + */ +/obj/effect/particle_effect/fluid/smoke/chem + lifetime = 20 SECONDS + +/obj/effect/particle_effect/fluid/smoke/chem/process(delta_time) + . = ..() + if(!.) + return + + var/turf/location = get_turf(src) + var/fraction = (delta_time SECONDS) / initial(lifetime) + for(var/atom/movable/thing as anything in location) + if(thing == src) + continue + if(location.intact && thing.level == 1) //hidden under the floor + continue + reagents.reaction(thing, TOUCH, fraction) + + reagents.reaction(location, TOUCH, fraction) + return TRUE + +/obj/effect/particle_effect/fluid/smoke/chem/smoke_mob(mob/living/carbon/smoker, delta_time) + if(lifetime < 1) + return FALSE + if(!istype(smoker)) + return FALSE + if(smoker.internal != null || smoker.has_smoke_protection()) + return FALSE + + var/fraction = (delta_time SECONDS) / initial(lifetime) + reagents.copy_to(smoker, reagents.total_volume, fraction) + reagents.reaction(smoker, INGEST, fraction) + return TRUE + + +/// A factory which produces clouds of chemical bearing smoke. +/datum/effect_system/fluid_spread/smoke/chem + /// Evil evil hack so we have something to "hold" our reagents + var/datum/reagents/chemholder + effect_type = /obj/effect/particle_effect/fluid/smoke/chem + +/datum/effect_system/fluid_spread/smoke/chem/New() + ..() + chemholder = new(1000, NO_REACT) + +/datum/effect_system/fluid_spread/smoke/chem/Destroy() + QDEL_NULL(chemholder) + return ..() + + +/datum/effect_system/fluid_spread/smoke/chem/set_up(range = 1, amount = DIAMOND_AREA(range), atom/holder, atom/location = null, datum/reagents/carry = null, silent = FALSE) + . = ..() + carry?.copy_to(chemholder, carry.total_volume) + + if(silent) + return + + var/list/contained_reagents = list() + for(var/datum/reagent/reagent as anything in chemholder.reagent_list) + contained_reagents += "[reagent.volume]u [reagent]" + + var/where = "[AREACOORD(location)]" + var/contained = length(contained_reagents) ? "[contained_reagents.Join(", ", " \[", "\]")] @ [chemholder.chem_temp]K" : null + if(carry.my_atom?.fingerprintslast) //Some reagents don't have a my_atom in some cases + var/mob/M = get_mob_by_key(carry.my_atom.fingerprintslast) + var/more = "" + if(M) + more = "[ADMIN_LOOKUPFLW(M)] " + message_admins("Smoke: ([ADMIN_VERBOSEJMP(location)])[contained]. Key: [more ? more : carry.my_atom.fingerprintslast].") + log_game("A chemical smoke reaction has taken place in ([where])[contained]. Last touched by [carry.my_atom.fingerprintslast].") + else + message_admins("Smoke: ([ADMIN_VERBOSEJMP(location)])[contained]. No associated key.") + log_game("A chemical smoke reaction has taken place in ([where])[contained]. No associated key.") + +/datum/effect_system/fluid_spread/smoke/chem/start(log = FALSE) + var/start_loc = holder ? get_turf(holder) : src.location + var/mixcolor = mix_color_from_reagents(chemholder.reagent_list) + var/obj/effect/particle_effect/fluid/smoke/chem/smoke = new effect_type(start_loc, new /datum/fluid_group(amount)) + chemholder.copy_to(smoke, chemholder.total_volume) + + if(mixcolor) + smoke.add_atom_colour(mixcolor, FIXED_COLOUR_PRIORITY) // give the smoke color, if it has any to begin with + if (log) + help_out_the_admins(smoke, holder, location) + smoke.spread() // Making the smoke spread immediately. + +/** + * A version of chemical smoke with a very short lifespan. + */ +/obj/effect/particle_effect/fluid/smoke/chem/quick + lifetime = 4 SECONDS + opacity = FALSE + alpha = 100 + +/datum/effect_system/fluid_spread/smoke/chem/quick + effect_type = /obj/effect/particle_effect/fluid/smoke/chem/quick diff --git a/code/game/objects/effects/step_triggers.dm b/code/game/objects/effects/step_triggers.dm index c271dfb79c31..c430cdbd0307 100644 --- a/code/game/objects/effects/step_triggers.dm +++ b/code/game/objects/effects/step_triggers.dm @@ -161,12 +161,12 @@ s.start() if(entersmoke) - var/datum/effect_system/smoke_spread/s = new - s.set_up(4, 1, src, 0) + var/datum/effect_system/fluid_spread/smoke/s = new + s.set_up(4, holder = src, location = src) s.start() if(exitsmoke) - var/datum/effect_system/smoke_spread/s = new - s.set_up(4, 1, dest, 0) + var/datum/effect_system/fluid_spread/smoke/s = new + s.set_up(4, holder = src, location = dest) s.start() uses-- diff --git a/code/game/objects/items/cigs_lighters.dm b/code/game/objects/items/cigs_lighters.dm index 40497b687830..04b83d8b0b3c 100644 --- a/code/game/objects/items/cigs_lighters.dm +++ b/code/game/objects/items/cigs_lighters.dm @@ -928,15 +928,15 @@ CIGARETTE PACKETS ARE IN FANCY.DM //open flame removed because vapes are a closed system, they wont light anything on fire if(super && vapetime >= vapedelay)//Time to start puffing those fat vapes, yo. - var/datum/effect_system/smoke_spread/chem/smoke_machine/s = new - s.set_up(reagents, 1, 24, loc) - s.start() + var/datum/effect_system/fluid_spread/smoke/chem/smoke_machine/puff = new + puff.set_up(1, location = loc, carry = reagents, efficiency = 24) + puff.start() vapetime -= vapedelay if((obj_flags & EMAGGED) && vapetime >= vapedelay) - var/datum/effect_system/smoke_spread/chem/smoke_machine/s = new - s.set_up(reagents, 4, 24, loc) - s.start() + var/datum/effect_system/fluid_spread/smoke/chem/smoke_machine/puff = new + puff.set_up(4, location = loc, carry = reagents, efficiency = 24) + puff.start() vapetime -= vapedelay 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, 0) diff --git a/code/game/objects/items/clown_items.dm b/code/game/objects/items/clown_items.dm index 9118383d3cf1..cc7acc7fd760 100644 --- a/code/game/objects/items/clown_items.dm +++ b/code/game/objects/items/clown_items.dm @@ -76,7 +76,7 @@ /obj/item/soap/suicide_act(mob/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(TRUE)]'ll never get that BB gun now!")) - new /obj/effect/particle_effect/foam(loc) + new /obj/effect/particle_effect/fluid/foam(loc) return (TOXLOSS) /obj/item/soap/proc/decreaseUses(mob/user, amount = 1) diff --git a/code/game/objects/items/grenades/smokebomb.dm b/code/game/objects/items/grenades/smokebomb.dm index 28d872c9ce34..52f611271e01 100644 --- a/code/game/objects/items/grenades/smokebomb.dm +++ b/code/game/objects/items/grenades/smokebomb.dm @@ -5,7 +5,7 @@ icon_state = "smokewhite" item_state = "flashbang" slot_flags = ITEM_SLOT_BELT - var/datum/effect_system/smoke_spread/bad/smoke + var/datum/effect_system/fluid_spread/smoke/bad/smoke /obj/item/grenade/smokebomb/Initialize() . = ..() @@ -19,7 +19,7 @@ /obj/item/grenade/smokebomb/prime() update_mob() playsound(src, 'sound/effects/smoke.ogg', 50, 1, -3) - smoke.set_up(4, src) + smoke.set_up(4, location = src) smoke.start() diff --git a/code/game/objects/items/robot/robot_upgrades.dm b/code/game/objects/items/robot/robot_upgrades.dm index d5c8ae6cd863..f0285773ec63 100644 --- a/code/game/objects/items/robot/robot_upgrades.dm +++ b/code/game/objects/items/robot/robot_upgrades.dm @@ -776,8 +776,8 @@ R.SetLockdown(1) R.anchored = TRUE R.expansion_count++ - var/datum/effect_system/smoke_spread/smoke = new - smoke.set_up(1, R.loc) + var/datum/effect_system/fluid_spread/smoke/smoke = new + smoke.set_up(1, location = R.loc) smoke.start() sleep(0.2 SECONDS) for(var/i in 1 to 4) diff --git a/code/game/objects/items/scrolls.dm b/code/game/objects/items/scrolls.dm index f5dc2e2a204c..d25009a16241 100644 --- a/code/game/objects/items/scrolls.dm +++ b/code/game/objects/items/scrolls.dm @@ -60,8 +60,8 @@ return var/area/thearea = GLOB.teleportlocs[A] - var/datum/effect_system/smoke_spread/smoke = new - smoke.set_up(2, user.loc) + var/datum/effect_system/fluid_spread/smoke/smoke = new + smoke.set_up(2, location = user.loc) smoke.attach(user) smoke.start() var/list/L = list() diff --git a/code/game/objects/items/tanks/watertank.dm b/code/game/objects/items/tanks/watertank.dm index ad68779abc62..0f304d8c18f3 100644 --- a/code/game/objects/items/tanks/watertank.dm +++ b/code/game/objects/items/tanks/watertank.dm @@ -285,12 +285,12 @@ if(!Adj|| !isturf(target)) return for(var/S in target) - if(istype(S, /obj/effect/particle_effect/foam/metal/resin) || istype(S, /obj/structure/foamedmetal/resin)) + if(istype(S, /obj/effect/particle_effect/fluid/foam/metal/resin) || istype(S, /obj/structure/foamedmetal/resin)) to_chat(user, span_warning("There's already resin here!")) return if(resin_charges) - var/obj/effect/particle_effect/foam/metal/resin/F = new (get_turf(target)) - F.amount = 0 + var/obj/effect/particle_effect/fluid/foam/metal/resin/foam = new (get_turf(target)) + foam.group.target_size = 0 resin_charges-- addtimer(CALLBACK(src, .proc/add_foam_charge), 5 SECONDS) else @@ -313,8 +313,9 @@ anchored = TRUE /obj/effect/resin_container/proc/Smoke() - var/obj/effect/particle_effect/foam/metal/resin/S = new /obj/effect/particle_effect/foam/metal/resin(get_turf(loc)) - S.amount = 4 + var/datum/effect_system/fluid_spread/foam/metal/resin/foaming = new + foaming.set_up(4, location = src) + foaming.start() playsound(src,'sound/effects/bamf.ogg',100,1) qdel(src) diff --git a/code/game/objects/structures/hivebot.dm b/code/game/objects/structures/hivebot.dm index 0dad2c71766d..8fcff298ac22 100644 --- a/code/game/objects/structures/hivebot.dm +++ b/code/game/objects/structures/hivebot.dm @@ -10,8 +10,8 @@ /obj/structure/hivebot_beacon/Initialize() . = ..() - var/datum/effect_system/smoke_spread/smoke = new - smoke.set_up(2, loc) + var/datum/effect_system/fluid_spread/smoke/smoke = new + smoke.set_up(2, location = loc) smoke.start() visible_message(span_boldannounce("[src] warps in!")) playsound(src.loc, 'sound/effects/empulse.ogg', 25, 1) diff --git a/code/game/objects/structures/lavaland/geyser.dm b/code/game/objects/structures/lavaland/geyser.dm index e7ab0b398172..66d0f9e77615 100644 --- a/code/game/objects/structures/lavaland/geyser.dm +++ b/code/game/objects/structures/lavaland/geyser.dm @@ -40,7 +40,7 @@ activated = TRUE create_reagents(max_volume, DRAINABLE) reagents.add_reagent(reagent_id, start_volume) - START_PROCESSING(SSfluids, src) //It's main function is to be plumbed, so use SSfluids + START_PROCESSING(SSplumbing, src) //It's main function is to be plumbed, so use SSplumbing if(erupting_state) icon_state = erupting_state else diff --git a/code/modules/antagonists/_common/antag_spawner.dm b/code/modules/antagonists/_common/antag_spawner.dm index 7d6a66f4a57e..ce68abeb8a92 100644 --- a/code/modules/antagonists/_common/antag_spawner.dm +++ b/code/modules/antagonists/_common/antag_spawner.dm @@ -86,7 +86,7 @@ to_chat(H, "Unable to reach your apprentice! You can either attack the spellbook with the contract to refund your points, or wait and try again later.") /obj/item/antag_spawner/contract/spawn_antag(client/C, turf/T, kind ,datum/mind/user) - new /obj/effect/particle_effect/smoke(T) + new /obj/effect/particle_effect/fluid/smoke(T) var/mob/living/carbon/human/M = new/mob/living/carbon/human(T) C.prefs.apply_prefs_to(M) M.key = C.key diff --git a/code/modules/antagonists/blob/blob_mobs.dm b/code/modules/antagonists/blob/blob_mobs.dm index 5b64f2a89889..147173b50967 100644 --- a/code/modules/antagonists/blob/blob_mobs.dm +++ b/code/modules/antagonists/blob/blob_mobs.dm @@ -172,7 +172,7 @@ /mob/living/simple_animal/hostile/blob/blobspore/death(gibbed) // On death, create a small smoke of harmful gas (s-Acid) - var/datum/effect_system/smoke_spread/chem/S = new + var/datum/effect_system/fluid_spread/smoke/chem/S = new var/turf/location = get_turf(src) // Create the reagents to put into the air @@ -187,7 +187,7 @@ // Attach the smoke spreader and setup/start it. S.attach(location) - S.set_up(reagents, death_cloud_size, location, silent = TRUE) + S.set_up(death_cloud_size, location = location, carry = reagents, silent = TRUE) S.start() if(factory) factory.spore_delay = world.time + factory.spore_cooldown //put the factory on cooldown diff --git a/code/modules/antagonists/bloodsuckers/powers/gangrel.dm b/code/modules/antagonists/bloodsuckers/powers/gangrel.dm index 44dd57770122..a4d322008240 100644 --- a/code/modules/antagonists/bloodsuckers/powers/gangrel.dm +++ b/code/modules/antagonists/bloodsuckers/powers/gangrel.dm @@ -138,7 +138,7 @@ /datum/action/bloodsucker/targeted/haste/batdash/FireTargetedPower(atom/target_atom) . = ..() - do_smoke(2, owner.loc, smoke_type = /obj/effect/particle_effect/smoke/transparent) //so you can attack people after hasting + do_smoke(2, owner.loc, smoke_type = /obj/effect/particle_effect/fluid/smoke/transparent) //so you can attack people after hasting /datum/action/bloodsucker/targeted/bloodbolt name = "Blood Bolt" diff --git a/code/modules/antagonists/bloodsuckers/powers/gohome.dm b/code/modules/antagonists/bloodsuckers/powers/gohome.dm index d0b86fa0d0eb..8cf6fbc165a4 100644 --- a/code/modules/antagonists/bloodsuckers/powers/gohome.dm +++ b/code/modules/antagonists/bloodsuckers/powers/gohome.dm @@ -124,7 +124,7 @@ DeactivatePower() /datum/effect_system/steam_spread/bloodsucker - effect_type = /obj/effect/particle_effect/smoke/vampsmoke + effect_type = /obj/effect/particle_effect/fluid/smoke/vampsmoke #undef GOHOME_START #undef GOHOME_FLICKER_ONE diff --git a/code/modules/antagonists/bloodsuckers/powers/targeted/lunge.dm b/code/modules/antagonists/bloodsuckers/powers/targeted/lunge.dm index b90d72da8461..70ab7c29b1d6 100644 --- a/code/modules/antagonists/bloodsuckers/powers/targeted/lunge.dm +++ b/code/modules/antagonists/bloodsuckers/powers/targeted/lunge.dm @@ -108,7 +108,7 @@ span_notice("You spin!"), ) return - do_smoke(0, owner.loc, smoke_type = /obj/effect/particle_effect/smoke/transparent) + do_smoke(0, owner.loc, smoke_type = /obj/effect/particle_effect/fluid/smoke/transparent) /datum/action/bloodsucker/targeted/lunge/proc/lunge_end(atom/hit_atom) var/mob/living/user = owner diff --git a/code/modules/antagonists/bloodsuckers/powers/targeted/trespass.dm b/code/modules/antagonists/bloodsuckers/powers/targeted/trespass.dm index 88a87770432d..a6b9dffc3182 100644 --- a/code/modules/antagonists/bloodsuckers/powers/targeted/trespass.dm +++ b/code/modules/antagonists/bloodsuckers/powers/targeted/trespass.dm @@ -81,7 +81,7 @@ var/sound_dist = max(-6, -level_current) // world.view is 7, so 7-6 = hearing distance of 1 playsound(get_turf(owner), 'sound/magic/summon_karp.ogg', sound_strength, 1, sound_dist) var/datum/effect_system/steam_spread/puff = new /datum/effect_system/steam_spread/() - puff.effect_type = /obj/effect/particle_effect/smoke/vampsmoke + puff.effect_type = /obj/effect/particle_effect/fluid/smoke/vampsmoke puff.set_up(3, 0, my_turf) puff.start() @@ -110,7 +110,7 @@ // Effect Destination playsound(get_turf(owner), 'sound/magic/summon_karp.ogg', sound_strength, 1, sound_dist) puff = new /datum/effect_system/steam_spread/() - puff.effect_type = /obj/effect/particle_effect/smoke/vampsmoke + puff.effect_type = /obj/effect/particle_effect/fluid/smoke/vampsmoke puff.set_up(3, 0, target_turf) puff.start() diff --git a/code/modules/antagonists/bloodsuckers/powers/veil.dm b/code/modules/antagonists/bloodsuckers/powers/veil.dm index 09538a1f7a41..de1b1b0ab183 100644 --- a/code/modules/antagonists/bloodsuckers/powers/veil.dm +++ b/code/modules/antagonists/bloodsuckers/powers/veil.dm @@ -124,16 +124,15 @@ // Effect playsound(get_turf(owner), 'sound/magic/smoke.ogg', 20, 1) var/datum/effect_system/steam_spread/puff = new /datum/effect_system/steam_spread/() - puff.effect_type = /obj/effect/particle_effect/smoke/vampsmoke + puff.effect_type = /obj/effect/particle_effect/fluid/smoke/vampsmoke puff.set_up(3, 0, get_turf(owner)) puff.attach(owner) //OPTIONAL puff.start() owner.spin(8, 1) //Spin around like a loon. -/obj/effect/particle_effect/smoke/vampsmoke - opaque = FALSE - amount = 0 +/obj/effect/particle_effect/fluid/smoke/vampsmoke + opacity = FALSE lifetime = 0 -/obj/effect/particle_effect/smoke/vampsmoke/fade_out(frames = 6) +/obj/effect/particle_effect/fluid/smoke/vampsmoke/fade_out(frames = 6) ..(frames) diff --git a/code/modules/antagonists/eldritch_cult/eldritch_effects.dm b/code/modules/antagonists/eldritch_cult/eldritch_effects.dm index 4308034d745b..96a31a0e1506 100644 --- a/code/modules/antagonists/eldritch_cult/eldritch_effects.dm +++ b/code/modules/antagonists/eldritch_cult/eldritch_effects.dm @@ -338,8 +338,8 @@ ..() /datum/status_effect/brazil_penance/on_apply() - var/datum/effect_system/smoke_spread/S = new - S.set_up(1, get_turf(owner)) + var/datum/effect_system/fluid_spread/smoke/S = new + S.set_up(1, location = get_turf(owner)) S.start() owner.revive(full_heal = TRUE) //this totally won't be used to bypass stuff(tm) owner.regenerate_organs() diff --git a/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm b/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm index 763f2c27392c..a4a44efe2f9d 100644 --- a/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm +++ b/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm @@ -546,7 +546,7 @@ disarm() return if(is_station_level(bomb_location.z)) - var/datum/round_event_control/E = locate(/datum/round_event_control/vent_clog/beer) in SSevents.control + var/datum/round_event_control/E = locate(/datum/round_event_control/scrubber_overflow/beer) in SSevents.control if(E) E.runEvent() addtimer(CALLBACK(src, .proc/really_actually_explode), 110) @@ -570,8 +570,8 @@ R.my_atom = src R.add_reagent(/datum/reagent/consumable/ethanol/beer, 100) - var/datum/effect_system/foam_spread/foam = new - foam.set_up(200, get_turf(src), R) + var/datum/effect_system/fluid_spread/foam/foam = new + foam.set_up(200, location = get_turf(src), carry = R) foam.start() disarm() diff --git a/code/modules/awaymissions/super_secret_room.dm b/code/modules/awaymissions/super_secret_room.dm index 176102e7ee3a..0c4c8269e48d 100644 --- a/code/modules/awaymissions/super_secret_room.dm +++ b/code/modules/awaymissions/super_secret_room.dm @@ -28,8 +28,8 @@ SpeakPeace(list("Welcome to the error handling room.","Something's goofed up bad to send you here.","You should probably tell an admin what you were doing, or make a bug report.")) for(var/obj/structure/signpost/salvation/S in orange(7)) S.invisibility = 0 - var/datum/effect_system/smoke_spread/smoke = new - smoke.set_up(1, S.loc) + var/datum/effect_system/fluid_spread/smoke/smoke = new + smoke.set_up(1, location = S.loc) smoke.start() break if(1) diff --git a/code/modules/clothing/under/jobs/Plasmaman/civilian_service.dm b/code/modules/clothing/under/jobs/Plasmaman/civilian_service.dm index c6150f370b76..a220deb6b013 100644 --- a/code/modules/clothing/under/jobs/Plasmaman/civilian_service.dm +++ b/code/modules/clothing/under/jobs/Plasmaman/civilian_service.dm @@ -76,7 +76,11 @@ return next_extinguish = world.time + extinguish_cooldown extinguishes_left-- - H.visible_message(span_warning("[H]'s suit spews out a tonne of space lube!"),span_warning("Your suit spews out a tonne of space lube!")) + H.visible_message(span_warning("[H]'s suit spews out a tonne of space lube!"), span_warning("Your suit spews out a tonne of space lube!")) H.ExtinguishMob() - new /obj/effect/particle_effect/foam(loc) //Truely terrifying. + var/datum/effect_system/fluid_spread/foam/foam = new + var/datum/reagents/foamreagent = new /datum/reagents(15) + foamreagent.add_reagent(/datum/reagent/lube, 15) + foam.set_up(4, holder = src, location = loc, carry = foamreagent) + foam.start() //Truly terrifying. return 0 diff --git a/code/modules/events/immovable_rod.dm b/code/modules/events/immovable_rod.dm index f5878a061ac8..f8a30a7016bf 100644 --- a/code/modules/events/immovable_rod.dm +++ b/code/modules/events/immovable_rod.dm @@ -133,16 +133,15 @@ In my current plan for it, 'solid' will be defined as anything with density == 1 penetrate(clong) else if(istype(clong, type)) var/obj/effect/immovablerod/other = clong - visible_message("[src] collides with [other]!\ - ") - var/datum/effect_system/smoke_spread/smoke = new - smoke.set_up(2, get_turf(src)) + visible_message(span_danger("[src] collides with [other]!")) + var/datum/effect_system/fluid_spread/smoke/smoke = new + smoke.set_up(2, location = get_turf(src)) smoke.start() qdel(src) qdel(other) /obj/effect/immovablerod/proc/penetrate(mob/living/L) - L.visible_message(span_danger("[L] is penetrated by an immovable rod!") , span_userdanger("The rod penetrates you!") , "You hear a CLANG!") + L.visible_message(span_danger("[L] is penetrated by an immovable rod!") , span_userdanger("The rod penetrates you!") , span_danger("You hear a CLANG!")) if(ishuman(L)) var/mob/living/carbon/human/H = L H.adjustBruteLoss(160) diff --git a/code/modules/events/scrubber_overflow.dm b/code/modules/events/scrubber_overflow.dm new file mode 100644 index 000000000000..790b021f04f5 --- /dev/null +++ b/code/modules/events/scrubber_overflow.dm @@ -0,0 +1,133 @@ +/datum/round_event_control/scrubber_overflow + name = "Scrubber Overflow: Normal" + typepath = /datum/round_event/scrubber_overflow + weight = 10 + max_occurrences = 3 + min_players = 10 + +/datum/round_event/scrubber_overflow + announceWhen = 1 + startWhen = 5 + endWhen = 35 + /// The probability that the ejected reagents will be dangerous + var/danger_chance = 1 + /// Amount of reagents ejected from each scrubber + var/reagents_amount = 50 + /// Probability of an individual scrubber overflowing + var/overflow_probability = 50 + /// Specific reagent to force all scrubbers to use, null for random reagent choice + var/forced_reagent + /// A list of scrubbers that will have reagents ejected from them + var/list/scrubbers = list() + /// The list of chems that scrubbers can produce + var/list/safer_chems = list( + /datum/reagent/water, + /datum/reagent/carbon, + /datum/reagent/consumable/flour, + /datum/reagent/space_cleaner, + /datum/reagent/consumable/nutriment, + /datum/reagent/consumable/condensedcapsaicin, + /datum/reagent/drug/mushroomhallucinogen, + /datum/reagent/lube, + /datum/reagent/glitter/pink, + /datum/reagent/cryptobiolin, + /datum/reagent/toxin/plantbgone, + /datum/reagent/blood, + /datum/reagent/medicine/charcoal, + /datum/reagent/drug/space_drugs, + /datum/reagent/medicine/morphine, + /datum/reagent/water/holywater, + /datum/reagent/consumable/ethanol, + /datum/reagent/consumable/hot_coco, + /datum/reagent/toxin/acid, + /datum/reagent/toxin/mindbreaker, + /datum/reagent/toxin/rotatium, + /datum/reagent/bluespace, + /datum/reagent/pax, + /datum/reagent/consumable/laughter, + /datum/reagent/concentrated_barbers_aid, + /datum/reagent/colorful_reagent, + /datum/reagent/peaceborg/confuse, + /datum/reagent/peaceborg/tire, + /datum/reagent/consumable/sodiumchloride, + /datum/reagent/consumable/ethanol/beer, + /datum/reagent/hair_dye, + /datum/reagent/consumable/sugar, + /datum/reagent/glitter/white, + /datum/reagent/growthserum + ) + //needs to be chemid unit checked at some point + +/datum/round_event/scrubber_overflow/announce(fake) + priority_announce("The scrubbers network is experiencing a backpressure surge. Some ejection of contents may occur.", "Atmospherics alert") + +/datum/round_event/scrubber_overflow/setup() + for(var/obj/machinery/atmospherics/components/unary/vent_scrubber/temp_vent in GLOB.machines) + var/turf/scrubber_turf = get_turf(temp_vent) + if(!scrubber_turf) + continue + if(!is_station_level(scrubber_turf.z)) + continue + if(temp_vent.welded) + continue + if(!prob(overflow_probability)) + continue + scrubbers += temp_vent + + if(!scrubbers.len) + return kill() + +/datum/round_event/scrubber_overflow/start() + for(var/obj/machinery/atmospherics/components/unary/vent_scrubber/vent as anything in scrubbers) + if(!vent.loc) + CRASH("SCRUBBER SURGE: [vent] has no loc somehow?") + + var/datum/reagents/dispensed_reagent = new /datum/reagents(reagents_amount) + dispensed_reagent.my_atom = vent + if (forced_reagent) + dispensed_reagent.add_reagent(forced_reagent, reagents_amount) + else if (prob(danger_chance)) + dispensed_reagent.add_reagent(get_random_reagent_id(), reagents_amount) + new /mob/living/simple_animal/cockroach(get_turf(vent)) + new /mob/living/simple_animal/cockroach(get_turf(vent)) + else + dispensed_reagent.add_reagent(pick(safer_chems), reagents_amount) + + dispensed_reagent.create_foam(/datum/effect_system/fluid_spread/foam/short, reagents_amount) + + CHECK_TICK + +/datum/round_event_control/scrubber_overflow/threatening + name = "Scrubber Overflow: Threatening" + typepath = /datum/round_event/scrubber_overflow/threatening + weight = 4 + min_players = 25 + max_occurrences = 1 + earliest_start = 35 MINUTES + +/datum/round_event/scrubber_overflow/threatening + danger_chance = 10 + reagents_amount = 100 + +/datum/round_event_control/scrubber_overflow/catastrophic + name = "Scrubber Overflow: Catastrophic" + typepath = /datum/round_event/scrubber_overflow/catastrophic + weight = 2 + min_players = 35 + max_occurrences = 1 + earliest_start = 45 MINUTES + +/datum/round_event/scrubber_overflow/catastrophic + danger_chance = 30 + reagents_amount = 150 + +/datum/round_event_control/scrubber_overflow/beer // Used when the beer nuke "detonates" + name = "Scrubber Overflow: Beer" + typepath = /datum/round_event/scrubber_overflow/beer + weight = 0 + max_occurrences = 0 + +/datum/round_event/scrubber_overflow/beer + overflow_probability = 100 + forced_reagent = /datum/reagent/consumable/ethanol/beer + reagents_amount = 100 diff --git a/code/modules/events/vent_clog.dm b/code/modules/events/vent_clog.dm deleted file mode 100644 index 8f2c5e892afb..000000000000 --- a/code/modules/events/vent_clog.dm +++ /dev/null @@ -1,138 +0,0 @@ -/datum/round_event_control/vent_clog - name = "Clogged Vents: Normal" - typepath = /datum/round_event/vent_clog - weight = 10 - max_occurrences = 3 - min_players = 10 - -/datum/round_event/vent_clog - announceWhen = 1 - startWhen = 5 - endWhen = 35 - var/interval = 2 - var/list/vents = list() - var/randomProbability = 1 - var/reagentsAmount = 100 - var/list/saferChems = list(/datum/reagent/water,/datum/reagent/carbon,/datum/reagent/consumable/flour,/datum/reagent/space_cleaner,/datum/reagent/consumable/nutriment,/datum/reagent/consumable/condensedcapsaicin,/datum/reagent/drug/mushroomhallucinogen,/datum/reagent/lube,/datum/reagent/glitter/pink,/datum/reagent/cryptobiolin, - /datum/reagent/toxin/plantbgone,/datum/reagent/blood,/datum/reagent/medicine/charcoal,/datum/reagent/drug/space_drugs,/datum/reagent/medicine/morphine,/datum/reagent/water/holywater,/datum/reagent/consumable/ethanol,/datum/reagent/consumable/hot_coco,/datum/reagent/toxin/acid,/datum/reagent/toxin/mindbreaker,/datum/reagent/toxin/rotatium,/datum/reagent/bluespace, - /datum/reagent/pax,/datum/reagent/consumable/laughter,/datum/reagent/concentrated_barbers_aid,/datum/reagent/colorful_reagent,/datum/reagent/peaceborg/confuse,/datum/reagent/peaceborg/tire,/datum/reagent/consumable/sodiumchloride,/datum/reagent/consumable/ethanol/beer,/datum/reagent/hair_dye,/datum/reagent/consumable/sugar,/datum/reagent/glitter/white,/datum/reagent/growthserum) - //needs to be chemid unit checked at some point - -/datum/round_event/vent_clog/announce() - priority_announce("The scrubbers network is experiencing a backpressure surge. Some ejection of contents may occur.", "Atmospherics alert") - -/datum/round_event/vent_clog/setup() - endWhen = rand(25, 100) - for(var/obj/machinery/atmospherics/components/unary/vent_scrubber/temp_vent in GLOB.machines) - var/turf/T = get_turf(temp_vent) - if(T && is_station_level(T.z) && !temp_vent.welded) - vents += temp_vent - if(!vents.len) - return kill() - -/datum/round_event/vent_clog/start() - for(var/obj/machinery/atmospherics/components/unary/vent in vents) - if(vent && vent.loc) - var/datum/reagents/R = new/datum/reagents(1000) - R.my_atom = vent - if (prob(randomProbability)) - R.add_reagent(get_random_reagent_id(), reagentsAmount) - else - R.add_reagent(pick(saferChems), reagentsAmount) - - var/datum/effect_system/foam_spread/foam = new - foam.one_apply_per_object = TRUE - foam.set_up(200, get_turf(vent), R) - foam.start() - - CHECK_TICK - -/datum/round_event_control/vent_clog/threatening - name = "Clogged Vents: Threatening" - typepath = /datum/round_event/vent_clog/threatening - weight = 4 - min_players = 25 - max_occurrences = 1 - earliest_start = 35 MINUTES - -/datum/round_event/vent_clog/threatening - randomProbability = 10 - reagentsAmount = 200 - -/datum/round_event_control/vent_clog/catastrophic - name = "Clogged Vents: Catastrophic" - typepath = /datum/round_event/vent_clog/catastrophic - weight = 2 - min_players = 35 - max_occurrences = 1 - earliest_start = 45 MINUTES - -/datum/round_event/vent_clog/catastrophic - randomProbability = 30 - reagentsAmount = 250 - -/datum/round_event_control/vent_clog/beer - name = "Foamy beer stationwide" - typepath = /datum/round_event/vent_clog/beer - max_occurrences = 0 - -/datum/round_event_control/vent_clog/cleaner - name = "Cleaner stationwide" - typepath = /datum/round_event/vent_clog/cleaner - max_occurrences = 0 - weight = 10 - min_players = 5 - max_occurrences = 1 - -/datum/round_event_control/vent_clog/plasma_decon - name = "Plasma decontamination" - typepath = /datum/round_event/vent_clog/plasma_decon - max_occurrences = 0 - -/datum/round_event/vent_clog/beer - reagentsAmount = 100 - -/datum/round_event/vent_clog/beer/announce() - priority_announce("The scrubbers network is experiencing an unexpected surge of pressurized beer. Some ejection of contents may occur.", "Atmospherics alert") - -/datum/round_event/vent_clog/beer/start() - for(var/obj/machinery/atmospherics/components/unary/vent in vents) - if(vent && vent.loc) - var/datum/reagents/R = new/datum/reagents(100) - R.my_atom = vent - R.add_reagent(/datum/reagent/consumable/ethanol/beer, reagentsAmount) - - var/datum/effect_system/foam_spread/foam = new - foam.one_apply_per_object = TRUE - foam.set_up(200, get_turf(vent), R) - foam.start() - CHECK_TICK - -/datum/round_event/vent_clog/cleaner - reagentsAmount = 100 - -/datum/round_event/vent_clog/cleaner/announce() - priority_announce("The scrubbers network cleaning cycle has been triggered. Some ejection of contents may occur.", "Atmospherics alert") - -/datum/round_event/vent_clog/cleaner/start() - for(var/obj/machinery/atmospherics/components/unary/vent in vents) - if(vent && vent.loc) - var/datum/reagents/R = new/datum/reagents(100) - R.my_atom = vent - R.add_reagent(/datum/reagent/space_cleaner, reagentsAmount) - - var/datum/effect_system/foam_spread/foam = new - foam.set_up(200, get_turf(vent), R) - foam.start() - CHECK_TICK - -/datum/round_event/vent_clog/plasma_decon/announce() - priority_announce("We are deploying an experimental plasma decontamination system. Please stand away from the vents and do not breathe the smoke that comes out.", "Central Command Update") - -/datum/round_event/vent_clog/plasma_decon/start() - for(var/obj/machinery/atmospherics/components/unary/vent in vents) - if(vent && vent.loc) - var/datum/effect_system/smoke_spread/freezing/decon/smoke = new - smoke.set_up(7, get_turf(vent), 7) - smoke.start() - CHECK_TICK diff --git a/code/modules/events/wizard/curseditems.dm b/code/modules/events/wizard/curseditems.dm index 41ee4246b1ab..d7bc152f4555 100644 --- a/code/modules/events/wizard/curseditems.dm +++ b/code/modules/events/wizard/curseditems.dm @@ -55,6 +55,6 @@ I.name = "cursed " + I.name for(var/mob/living/carbon/human/H in GLOB.alive_mob_list) - var/datum/effect_system/smoke_spread/smoke = new - smoke.set_up(0, H.loc) + var/datum/effect_system/fluid_spread/smoke/smoke = new + smoke.set_up(0, location = H.loc) smoke.start() diff --git a/code/modules/events/wizard/imposter.dm b/code/modules/events/wizard/imposter.dm index 1c8ef95baae8..968db4909e0b 100644 --- a/code/modules/events/wizard/imposter.dm +++ b/code/modules/events/wizard/imposter.dm @@ -15,7 +15,7 @@ return //Sad Trombone var/mob/dead/observer/C = pick(candidates) - new /obj/effect/particle_effect/smoke(W.loc) + new /obj/effect/particle_effect/fluid/smoke(W.loc) var/mob/living/carbon/human/I = new /mob/living/carbon/human(W.loc) W.dna.transfer_identity(I, transfer_SE=1) diff --git a/code/modules/events/wizard/shuffle.dm b/code/modules/events/wizard/shuffle.dm index 7e3742922321..c3e71ab28898 100644 --- a/code/modules/events/wizard/shuffle.dm +++ b/code/modules/events/wizard/shuffle.dm @@ -31,8 +31,8 @@ moblocs.len -= 1 for(var/mob/living/carbon/human/H in GLOB.alive_mob_list) - var/datum/effect_system/smoke_spread/smoke = new - smoke.set_up(0, H.loc) + var/datum/effect_system/fluid_spread/smoke/smoke = new + smoke.set_up(0, location = H.loc) smoke.start() //---// @@ -65,8 +65,8 @@ mobnames.len -= 1 for(var/mob/living/carbon/human/H in GLOB.alive_mob_list) - var/datum/effect_system/smoke_spread/smoke = new - smoke.set_up(0, H.loc) + var/datum/effect_system/fluid_spread/smoke/smoke = new + smoke.set_up(0, location = H.loc) smoke.start() //---// @@ -99,6 +99,6 @@ mobs -= mobs[mobs.len] for(var/mob/living/carbon/human/H in GLOB.alive_mob_list) - var/datum/effect_system/smoke_spread/smoke = new - smoke.set_up(0, H.loc) + var/datum/effect_system/fluid_spread/smoke/smoke = new + smoke.set_up(0, location = H.loc) smoke.start() diff --git a/code/modules/food_and_drinks/food/snacks_burgers.dm b/code/modules/food_and_drinks/food/snacks_burgers.dm index 119e77507fb4..aeefecf45357 100644 --- a/code/modules/food_and_drinks/food/snacks_burgers.dm +++ b/code/modules/food_and_drinks/food/snacks_burgers.dm @@ -16,7 +16,7 @@ /obj/item/reagent_containers/food/snacks/burger/plain/Initialize() . = ..() if(prob(1)) - new/obj/effect/particle_effect/smoke(get_turf(src)) + new/obj/effect/particle_effect/fluid/smoke(get_turf(src)) playsound(src, 'sound/effects/smoke.ogg', 50, TRUE) visible_message(span_warning("Oh, ye gods! [src] is ruined! But what if...?")) name = "steamed ham" diff --git a/code/modules/food_and_drinks/kitchen_machinery/grill.dm b/code/modules/food_and_drinks/kitchen_machinery/grill.dm index 6458482f39e5..1c4109e19985 100644 --- a/code/modules/food_and_drinks/kitchen_machinery/grill.dm +++ b/code/modules/food_and_drinks/kitchen_machinery/grill.dm @@ -80,8 +80,8 @@ if(!grilled_item) grill_fuel -= GRILL_FUELUSAGE_IDLE if(DT_PROB(0.5, delta_time)) - var/datum/effect_system/smoke_spread/bad/smoke = new - smoke.set_up(1, loc) + var/datum/effect_system/fluid_spread/smoke/bad/smoke = new + smoke.set_up(1, location = loc) smoke.start() if(grilled_item) SEND_SIGNAL(grilled_item, COMSIG_ITEM_GRILLED, src, 1) diff --git a/code/modules/goals/station_goals/bsa.dm b/code/modules/goals/station_goals/bsa.dm index 704a334a8c93..11149fb38997 100644 --- a/code/modules/goals/station_goals/bsa.dm +++ b/code/modules/goals/station_goals/bsa.dm @@ -319,9 +319,9 @@ if(notice) return null //Totally nanite construction system not an immersion breaking spawning - var/datum/effect_system/smoke_spread/s = new - s.set_up(4,get_turf(centerpiece)) - s.start() + var/datum/effect_system/fluid_spread/smoke/fourth_wall_guard = new + fourth_wall_guard.set_up(4, location = get_turf(centerpiece)) + fourth_wall_guard.start() var/obj/machinery/bsa/full/cannon = new(get_turf(centerpiece),centerpiece.get_cannon_direction()) qdel(centerpiece.front) qdel(centerpiece.back) diff --git a/code/modules/hydroponics/grown/onion.dm b/code/modules/hydroponics/grown/onion.dm index 00cba98b1556..e7d3ffb69ca4 100644 --- a/code/modules/hydroponics/grown/onion.dm +++ b/code/modules/hydroponics/grown/onion.dm @@ -56,10 +56,10 @@ wine_power = 60 /obj/item/reagent_containers/food/snacks/grown/onion/slice(accuracy, obj/item/W, mob/user) - var/datum/effect_system/smoke_spread/chem/S = new //Since the onion is destroyed when it's sliced, + var/datum/effect_system/fluid_spread/smoke/chem/S = new //Since the onion is destroyed when it's sliced, var/splat_location = get_turf(src) //we need to set up the smoke beforehand S.attach(splat_location) - S.set_up(reagents, 0, splat_location, 0) + S.set_up(0, location = splat_location, carry = reagents) if(..()) S.start() return TRUE diff --git a/code/modules/hydroponics/plant_genes.dm b/code/modules/hydroponics/plant_genes.dm index 939e5bcd2e5f..f2284e674a2b 100644 --- a/code/modules/hydroponics/plant_genes.dm +++ b/code/modules/hydroponics/plant_genes.dm @@ -401,11 +401,11 @@ name = "gaseous decomposition" /datum/plant_gene/trait/smoke/on_squash(obj/item/reagent_containers/food/snacks/grown/G, atom/target) - var/datum/effect_system/smoke_spread/chem/S = new + var/datum/effect_system/fluid_spread/smoke/chem/S = new var/splat_location = get_turf(target) var/smoke_amount = round(sqrt(G.seed.potency * 0.1), 1) S.attach(splat_location) - S.set_up(G.reagents, smoke_amount, splat_location, 0) + S.set_up(smoke_amount, location = splat_location, carry = G.reagents) S.start() G.reagents.clear_reagents() diff --git a/code/modules/mining/equipment/survival_pod.dm b/code/modules/mining/equipment/survival_pod.dm index 115d9b1864ea..10fd17df362c 100644 --- a/code/modules/mining/equipment/survival_pod.dm +++ b/code/modules/mining/equipment/survival_pod.dm @@ -64,7 +64,7 @@ log_admin("[key_name(usr)] activated a bluespace capsule away from the mining level at [AREACOORD(T)]") playsound(src, 'sound/effects/phasein.ogg', 100, TRUE) - new /obj/effect/particle_effect/smoke(get_turf(src)) + new /obj/effect/particle_effect/fluid/smoke(get_turf(src)) qdel(src) /obj/item/survivalcapsule/luxury diff --git a/code/modules/mob/living/simple_animal/bot/atmosbot.dm b/code/modules/mob/living/simple_animal/bot/atmosbot.dm index 868674d90709..cff40711067f 100644 --- a/code/modules/mob/living/simple_animal/bot/atmosbot.dm +++ b/code/modules/mob/living/simple_animal/bot/atmosbot.dm @@ -124,7 +124,7 @@ explosion(src.loc,1,2,4,flame_range = 2) qdel(src) else - deployed_smartmetal = WEAKREF(new /obj/effect/particle_effect/foam/metal/smart(get_turf(src))) + deployed_smartmetal = WEAKREF(new /obj/effect/particle_effect/fluid/foam/metal/smart(get_turf(src))) qdel(src) return diff --git a/code/modules/mob/living/simple_animal/bot/cleanbot.dm b/code/modules/mob/living/simple_animal/bot/cleanbot.dm index 9d2322702e91..b87f6a0f1076 100644 --- a/code/modules/mob/living/simple_animal/bot/cleanbot.dm +++ b/code/modules/mob/living/simple_animal/bot/cleanbot.dm @@ -253,7 +253,9 @@ T.MakeSlippery(TURF_WET_WATER, min_wet_time = 20 SECONDS, wet_time_to_add = 15 SECONDS) else visible_message(span_danger("[src] whirs and bubbles violently, before releasing a plume of froth!")) - new /obj/effect/particle_effect/foam(loc) + var/datum/effect_system/fluid_spread/foam/foam = new + foam.set_up(2, holder = src, location = loc) + foam.start() else ..() diff --git a/code/modules/mob/living/simple_animal/bot/firebot.dm b/code/modules/mob/living/simple_animal/bot/firebot.dm index 94c88c21f294..1d992c22bc6b 100644 --- a/code/modules/mob/living/simple_animal/bot/firebot.dm +++ b/code/modules/mob/living/simple_animal/bot/firebot.dm @@ -273,7 +273,9 @@ /mob/living/simple_animal/bot/firebot/temperature_expose(datum/gas_mixture/air, temperature, volume) if((temperature > T0C + 200 || temperature < BODYTEMP_COLD_DAMAGE_LIMIT) && foam_cooldown + FOAM_INTERVAL < world.time) - new /obj/effect/particle_effect/foam/firefighting(loc) + var/datum/effect_system/fluid_spread/foam/firefighting/foam = new + foam.set_up(3, holder = src, location = loc) + foam.start() foam_cooldown = world.time ..() diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/legionnaire.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/legionnaire.dm index 5f8faf06d873..a7345351c8e7 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/legionnaire.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/legionnaire.dm @@ -210,8 +210,8 @@ visible_message(span_boldwarning("[src] spews smoke from the tip of their spine!")) else visible_message(span_boldwarning("[src] spews smoke from its maw!")) - var/datum/effect_system/smoke_spread/smoke = new - smoke.set_up(2, T) + var/datum/effect_system/fluid_spread/smoke/smoke = new + smoke.set_up(2, location = T) smoke.start() /obj/item/gps/internal/legionnaire diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/clown.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/clown.dm index d80d8d4b5972..94062df2f0cf 100644 --- a/code/modules/mob/living/simple_animal/hostile/retaliate/clown.dm +++ b/code/modules/mob/living/simple_animal/hostile/retaliate/clown.dm @@ -72,7 +72,7 @@ response_help = "dips a finger into" response_disarm = "gently scoops and pours aside" emote_see = list("bubbles", "oozes") - loot = list(/obj/item/clothing/mask/gas/clown_hat, /obj/effect/particle_effect/foam) + loot = list(/obj/item/clothing/mask/gas/clown_hat, /obj/effect/particle_effect/fluid/foam) /mob/living/simple_animal/hostile/retaliate/clown/lube/Life() . = ..() @@ -226,7 +226,7 @@ armour_penetration = 20 attacktext = "steals the girlfriend of" attack_sound = 'sound/items/airhorn2.ogg' - loot = list(/obj/item/clothing/mask/gas/clown_hat, /obj/effect/gibspawner/human, /obj/effect/particle_effect/foam, /obj/item/soap) + loot = list(/obj/item/clothing/mask/gas/clown_hat, /obj/effect/gibspawner/human, /obj/effect/particle_effect/fluid/foam, /obj/item/soap) /mob/living/simple_animal/hostile/retaliate/clown/clownhulk/honcmunculus name = "Honkmunculus" @@ -246,7 +246,7 @@ melee_damage_upper = 10 attacktext = "ferociously mauls" environment_smash = ENVIRONMENT_SMASH_NONE - loot = list(/obj/item/clothing/mask/gas/clown_hat, /obj/effect/gibspawner/xeno/bodypartless, /obj/effect/particle_effect/foam, /obj/item/soap) + loot = list(/obj/item/clothing/mask/gas/clown_hat, /obj/effect/gibspawner/xeno/bodypartless, /obj/effect/particle_effect/fluid/foam, /obj/item/soap) attack_reagent = /datum/reagent/peaceborg/confuse /mob/living/simple_animal/hostile/retaliate/clown/clownhulk/destroyer @@ -267,7 +267,7 @@ attacktext = "acts out divine vengeance on" obj_damage = 50 environment_smash = ENVIRONMENT_SMASH_RWALLS - loot = list(/obj/item/clothing/mask/gas/clown_hat, /obj/effect/gibspawner/human, /obj/effect/particle_effect/foam, /obj/item/soap) + loot = list(/obj/item/clothing/mask/gas/clown_hat, /obj/effect/gibspawner/human, /obj/effect/particle_effect/fluid/foam, /obj/item/soap) /mob/living/simple_animal/hostile/retaliate/clown/clownhulk/punisher name = "The Punisher" @@ -288,7 +288,7 @@ attacktext = "flexes on" obj_damage = 50 environment_smash = ENVIRONMENT_SMASH_RWALLS - loot = list(/obj/item/clothing/mask/gas/clown_hat, /obj/effect/gibspawner/human, /obj/effect/particle_effect/foam, /obj/item/soap) + loot = list(/obj/item/clothing/mask/gas/clown_hat, /obj/effect/gibspawner/human, /obj/effect/particle_effect/fluid/foam, /obj/item/soap) /mob/living/simple_animal/hostile/retaliate/clown/mutant name = "Unknown" @@ -324,7 +324,7 @@ mob_size = MOB_SIZE_LARGE speed = 20 attacktext = "bounces off of" - loot = list(/obj/item/clothing/mask/gas/clown_hat, /obj/effect/gibspawner/xeno/bodypartless, /obj/effect/particle_effect/foam, /obj/item/soap, /obj/effect/gibspawner/generic, /obj/effect/gibspawner/generic/animal, /obj/effect/gibspawner/human/bodypartless, /obj/effect/gibspawner/human) + loot = list(/obj/item/clothing/mask/gas/clown_hat, /obj/effect/gibspawner/xeno/bodypartless, /obj/effect/particle_effect/fluid/foam, /obj/item/soap, /obj/effect/gibspawner/generic, /obj/effect/gibspawner/generic/animal, /obj/effect/gibspawner/human/bodypartless, /obj/effect/gibspawner/human) attack_reagent = /datum/reagent/toxin/mindbreaker /mob/living/simple_animal/hostile/retaliate/clown/mutant/thicc @@ -338,5 +338,5 @@ mob_size = MOB_SIZE_LARGE speed = 20 attacktext = "bounces off of" - loot = list(/obj/item/clothing/mask/gas/clown_hat, /obj/effect/gibspawner/xeno/bodypartless, /obj/effect/particle_effect/foam, /obj/item/soap, /obj/effect/gibspawner/generic, /obj/effect/gibspawner/generic/animal, /obj/effect/gibspawner/human/bodypartless, /obj/effect/gibspawner/human) - attack_reagent = /datum/reagent/consumable/banana \ No newline at end of file + loot = list(/obj/item/clothing/mask/gas/clown_hat, /obj/effect/gibspawner/xeno/bodypartless, /obj/effect/particle_effect/fluid/foam, /obj/item/soap, /obj/effect/gibspawner/generic, /obj/effect/gibspawner/generic/animal, /obj/effect/gibspawner/human/bodypartless, /obj/effect/gibspawner/human) + attack_reagent = /datum/reagent/consumable/banana diff --git a/code/modules/mob/living/simple_animal/hostile/venus_human_trap.dm b/code/modules/mob/living/simple_animal/hostile/venus_human_trap.dm index 565d81edaa22..1487bbef3a9a 100644 --- a/code/modules/mob/living/simple_animal/hostile/venus_human_trap.dm +++ b/code/modules/mob/living/simple_animal/hostile/venus_human_trap.dm @@ -224,8 +224,8 @@ /mob/living/simple_animal/hostile/venus_human_trap/proc/check_gas() for(var/contents in src.loc) - if(istype(contents, /obj/effect/particle_effect/smoke/chem)) - var/obj/effect/particle_effect/smoke/chem/gas = contents + if(istype(contents, /obj/effect/particle_effect/fluid/smoke/chem)) + var/obj/effect/particle_effect/fluid/smoke/chem/gas = contents if(gas.reagents.has_reagent(/datum/reagent/toxin/plantbgone, 1)) return TRUE return FALSE diff --git a/code/modules/ninja/suit/n_suit_verbs/ninja_smoke.dm b/code/modules/ninja/suit/n_suit_verbs/ninja_smoke.dm index e6898dd10983..66c0325922a4 100644 --- a/code/modules/ninja/suit/n_suit_verbs/ninja_smoke.dm +++ b/code/modules/ninja/suit/n_suit_verbs/ninja_smoke.dm @@ -2,11 +2,10 @@ //Smoke bomb /obj/item/clothing/suit/space/space_ninja/proc/ninjasmoke() - - if(!ninjacost(0,N_SMOKE_BOMB)) + if(!ninjacost(0, N_SMOKE_BOMB)) var/mob/living/carbon/human/H = affecting - var/datum/effect_system/smoke_spread/bad/smoke = new - smoke.set_up(4, H.loc) + var/datum/effect_system/fluid_spread/smoke/bad/smoke = new + smoke.set_up(4, location = H.loc) smoke.start() playsound(H.loc, 'sound/effects/bamf.ogg', 50, 2) s_bombs-- diff --git a/code/modules/projectiles/guns/magic/wand.dm b/code/modules/projectiles/guns/magic/wand.dm index 8634866a5932..2d7fb5451255 100644 --- a/code/modules/projectiles/guns/magic/wand.dm +++ b/code/modules/projectiles/guns/magic/wand.dm @@ -145,8 +145,8 @@ /obj/item/gun/magic/wand/teleport/zap_self(mob/living/user) if(do_teleport(user, user, 10, channel = TELEPORT_CHANNEL_MAGIC)) - var/datum/effect_system/smoke_spread/smoke = new - smoke.set_up(3, user.loc) + var/datum/effect_system/fluid_spread/smoke/smoke = new + smoke.set_up(3, location = user.loc) smoke.start() charges-- ..() @@ -166,8 +166,8 @@ if(do_teleport(user, destination, channel=TELEPORT_CHANNEL_MAGIC)) for(var/t in list(origin, destination)) - var/datum/effect_system/smoke_spread/smoke = new - smoke.set_up(0, t) + var/datum/effect_system/fluid_spread/smoke/smoke = new + smoke.set_up(0, location = t) smoke.start() ..() diff --git a/code/modules/projectiles/projectile/magic.dm b/code/modules/projectiles/projectile/magic.dm index 5e246cd7afb1..8c10d168661d 100644 --- a/code/modules/projectiles/projectile/magic.dm +++ b/code/modules/projectiles/projectile/magic.dm @@ -71,8 +71,9 @@ if(!stuff.anchored && stuff.loc && !isobserver(stuff)) if(do_teleport(stuff, stuff, 10, channel = TELEPORT_CHANNEL_MAGIC)) teleammount++ - var/datum/effect_system/smoke_spread/smoke = new - smoke.set_up(max(round(4 - teleammount),0), stuff.loc) //Smoke drops off if a lot of stuff is moved for the sake of sanity + var/smoke_range = max(round(4 - teleammount), 0) + var/datum/effect_system/fluid_spread/smoke/smoke = new + smoke.set_up(smoke_range, location = stuff.loc) //Smoke drops off if a lot of stuff is moved for the sake of sanity smoke.start() /obj/item/projectile/magic/safety @@ -92,8 +93,8 @@ if(do_teleport(target, destination_turf, channel=TELEPORT_CHANNEL_MAGIC)) for(var/t in list(origin_turf, destination_turf)) - var/datum/effect_system/smoke_spread/smoke = new - smoke.set_up(0, t) + var/datum/effect_system/fluid_spread/smoke/smoke = new + smoke.set_up(0, location = t) smoke.start() /obj/item/projectile/magic/door diff --git a/code/modules/reagents/chemistry/machinery/smoke_machine.dm b/code/modules/reagents/chemistry/machinery/smoke_machine.dm index 2de5234a132c..c7477ce9d10f 100644 --- a/code/modules/reagents/chemistry/machinery/smoke_machine.dm +++ b/code/modules/reagents/chemistry/machinery/smoke_machine.dm @@ -15,17 +15,19 @@ var/setting = 1 // displayed range is 3 * setting var/max_range = 3 // displayed max range is 3 * max range -/datum/effect_system/smoke_spread/chem/smoke_machine/set_up(datum/reagents/carry, setting=1, efficiency=10, loc, silent=FALSE) - amount = setting - carry.copy_to(chemholder, 20) - carry.remove_any(amount * 16 / efficiency) - location = loc +/datum/effect_system/fluid_spread/smoke/chem/smoke_machine/set_up(range = 1, amount = DIAMOND_AREA(range), atom/location = null, datum/reagents/carry = null, efficiency = 10, silent=FALSE) + src.location = get_turf(location) + src.amount = amount + carry?.copy_to(chemholder, 20) + carry?.remove_any(amount / efficiency) -/datum/effect_system/smoke_spread/chem/smoke_machine - effect_type = /obj/effect/particle_effect/smoke/chem/smoke_machine +/// A factory which produces clouds of smoke for the smoke machine. +/datum/effect_system/fluid_spread/smoke/chem/smoke_machine + effect_type = /obj/effect/particle_effect/fluid/smoke/chem/smoke_machine -/obj/effect/particle_effect/smoke/chem/smoke_machine - opaque = FALSE +/// Smoke which is produced by the smoke machine. Slightly transparent and does not block line of sight. +/obj/effect/particle_effect/fluid/smoke/chem/smoke_machine + opacity = FALSE alpha = 100 /obj/machinery/smoke_machine/Initialize() @@ -54,9 +56,9 @@ if(new_volume < reagents.total_volume) reagents.reaction(loc, TOUCH) // if someone manages to downgrade it without deconstructing reagents.clear_reagents() - efficiency = 9 + efficiency = 18 for(var/obj/item/stock_parts/capacitor/C in component_parts) - efficiency += C.rating + efficiency += 2 * C.rating max_range = 1 for(var/obj/item/stock_parts/manipulator/M in component_parts) max_range += M.rating @@ -70,12 +72,12 @@ on = FALSE update_icon() return - var/turf/T = get_turf(src) - var/smoke_test = locate(/obj/effect/particle_effect/smoke) in T + var/turf/location = get_turf(src) + var/smoke_test = locate(/obj/effect/particle_effect/fluid/smoke) in location if(on && !smoke_test) update_icon() - var/datum/effect_system/smoke_spread/chem/smoke_machine/smoke = new() - smoke.set_up(reagents, setting*3, efficiency, T) + var/datum/effect_system/fluid_spread/smoke/chem/smoke_machine/smoke = new() + smoke.set_up(setting * 3, location = location, carry = reagents, efficiency = efficiency) smoke.start() /obj/machinery/smoke_machine/attackby(obj/item/I, mob/user, params) diff --git a/code/modules/reagents/chemistry/reagents/pyrotechnic_reagents.dm b/code/modules/reagents/chemistry/reagents/pyrotechnic_reagents.dm index 5bc0f7fbb2c5..bf0b84919df5 100644 --- a/code/modules/reagents/chemistry/reagents/pyrotechnic_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/pyrotechnic_reagents.dm @@ -249,25 +249,25 @@ color = "#A6FAFF55" taste_description = "the inside of a fire extinguisher" -/datum/reagent/firefighting_foam/reaction_turf(turf/open/T, reac_volume) - if (!istype(T)) +/datum/reagent/firefighting_foam/reaction_turf(turf/open/exposed_turf, reac_volume) + . = ..() + if (!istype(exposed_turf)) return if(reac_volume >= 1) - var/obj/effect/particle_effect/foam/firefighting/F = (locate(/obj/effect/particle_effect/foam) in T) - if(!F) - F = new(T) - else if(istype(F)) - F.lifetime = initial(F.lifetime) //reduce object churn a little bit when using smoke by keeping existing foam alive a bit longer + var/obj/effect/particle_effect/fluid/foam/firefighting/foam = (locate(/obj/effect/particle_effect/fluid/foam) in exposed_turf) + if(!foam) + foam = new(exposed_turf) + else if(istype(foam)) + foam.lifetime = initial(foam.lifetime) //reduce object churn a little bit when using smoke by keeping existing foam alive a bit longer - var/obj/effect/hotspot/hotspot = (locate(/obj/effect/hotspot) in T) - if(hotspot && !isspaceturf(T)) - if(T.air) - var/datum/gas_mixture/G = T.air - if(G.return_temperature() > T20C) - G.set_temperature(max(G.return_temperature()/2,T20C)) - G.react(src) - qdel(hotspot) + var/obj/effect/hotspot/hotspot = (locate(/obj/effect/hotspot) in exposed_turf) + if(hotspot && !isspaceturf(exposed_turf) && exposed_turf.air) + var/datum/gas_mixture/air = exposed_turf.air + if(air.return_temperature() > T20C) + air.set_temperature(max(air.return_temperature()/2, T20C)) + air.react(src) + qdel(hotspot) /datum/reagent/firefighting_foam/reaction_obj(obj/O, reac_volume) O.extinguish() diff --git a/code/modules/reagents/chemistry/recipes/drugs.dm b/code/modules/reagents/chemistry/recipes/drugs.dm index 269ec1d35056..5d500bfd9954 100644 --- a/code/modules/reagents/chemistry/recipes/drugs.dm +++ b/code/modules/reagents/chemistry/recipes/drugs.dm @@ -32,8 +32,8 @@ var/datum/reagents/R = new/datum/reagents(5) R.my_atom = holder.my_atom R.add_reagent(/datum/reagent/toxin/acid/fluacid, 5) - var/datum/effect_system/smoke_spread/chem/S = new - S.set_up(R, 0.5, holder.my_atom, 0) + var/datum/effect_system/fluid_spread/smoke/chem/S = new + S.set_up(0.5, location = holder, carry = R,) S.start() playsound(get_turf(holder.my_atom), 'sound/effects/smoke.ogg', 50, 1, -3) diff --git a/code/modules/reagents/chemistry/recipes/others.dm b/code/modules/reagents/chemistry/recipes/others.dm index 118a3a411ae2..a8906f9861b4 100644 --- a/code/modules/reagents/chemistry/recipes/others.dm +++ b/code/modules/reagents/chemistry/recipes/others.dm @@ -382,15 +382,7 @@ mob_react = FALSE /datum/chemical_reaction/foam/on_reaction(datum/reagents/holder, created_volume) - var/location = get_turf(holder.my_atom) - for(var/mob/M in viewers(5, location)) - to_chat(M, span_danger("The solution spews out foam!")) - var/datum/effect_system/foam_spread/s = new() - s.set_up(created_volume*2, location, holder) - s.start() - holder.clear_reagents() - return - + holder.create_foam(/datum/effect_system/fluid_spread/foam, 2 * created_volume, notification = span_danger("The solution spews out foam!")) /datum/chemical_reaction/metalfoam name = "Metal Foam" @@ -399,15 +391,7 @@ mob_react = FALSE /datum/chemical_reaction/metalfoam/on_reaction(datum/reagents/holder, created_volume) - var/location = get_turf(holder.my_atom) - - for(var/mob/M in viewers(5, location)) - to_chat(M, span_danger("The solution spews out a metallic foam!")) - - var/datum/effect_system/foam_spread/metal/s = new() - s.set_up(created_volume*5, location, holder, 1) - s.start() - holder.clear_reagents() + holder.create_foam(/datum/effect_system/fluid_spread/foam/metal, 5 * created_volume, /obj/structure/foamedmetal, span_danger("The solution spews out a metallic foam!")) /datum/chemical_reaction/smart_foam name = "Smart Metal Foam" @@ -416,12 +400,7 @@ mob_react = TRUE /datum/chemical_reaction/smart_foam/on_reaction(datum/reagents/holder, created_volume) - var/turf/location = get_turf(holder.my_atom) - location.visible_message(span_danger("The solution spews out metallic foam!")) - var/datum/effect_system/foam_spread/metal/smart/s = new() - s.set_up(created_volume * 5, location, holder, TRUE) - s.start() - holder.clear_reagents() + holder.create_foam(/datum/effect_system/fluid_spread/foam/metal/smart, 5 * created_volume, /obj/structure/foamedmetal, span_danger("The solution spews out metallic foam!")) /datum/chemical_reaction/ironfoam name = "Iron Foam" @@ -430,13 +409,7 @@ mob_react = FALSE /datum/chemical_reaction/ironfoam/on_reaction(datum/reagents/holder, created_volume) - var/location = get_turf(holder.my_atom) - for(var/mob/M in viewers(5, location)) - to_chat(M, span_danger("The solution spews out a metallic foam!")) - var/datum/effect_system/foam_spread/metal/s = new() - s.set_up(created_volume*5, location, holder, 2) - s.start() - holder.clear_reagents() + holder.create_foam(/datum/effect_system/fluid_spread/foam/metal/iron, 5 * created_volume, /obj/structure/foamedmetal/iron, span_danger("The solution spews out a metallic foam!")) /datum/chemical_reaction/foaming_agent name = "Foaming Agent" diff --git a/code/modules/reagents/chemistry/recipes/pyrotechnics.dm b/code/modules/reagents/chemistry/recipes/pyrotechnics.dm index 24f81e284d08..37f7145870d3 100644 --- a/code/modules/reagents/chemistry/recipes/pyrotechnics.dm +++ b/code/modules/reagents/chemistry/recipes/pyrotechnics.dm @@ -292,11 +292,11 @@ holder.remove_reagent(/datum/reagent/smoke_powder, created_volume*3) var/smoke_radius = round(sqrt(created_volume * 1.5), 1) var/location = get_turf(holder.my_atom) - var/datum/effect_system/smoke_spread/chem/S = new + var/datum/effect_system/fluid_spread/smoke/chem/S = new S.attach(location) playsound(location, 'sound/effects/smoke.ogg', 50, 1, -3) if(S) - S.set_up(holder, smoke_radius, location, 0) + S.set_up(smoke_radius, location = location, carry = holder) S.start() if(holder && holder.my_atom) holder.clear_reagents() @@ -311,11 +311,11 @@ /datum/chemical_reaction/smoke_powder_smoke/on_reaction(datum/reagents/holder, created_volume) var/location = get_turf(holder.my_atom) var/smoke_radius = round(sqrt(created_volume / 2), 1) - var/datum/effect_system/smoke_spread/chem/S = new + var/datum/effect_system/fluid_spread/smoke/chem/S = new S.attach(location) playsound(location, 'sound/effects/smoke.ogg', 50, 1, -3) if(S) - S.set_up(holder, smoke_radius, location, 0) + S.set_up(smoke_radius, location = location, carry = holder) S.start() if(holder && holder.my_atom) holder.clear_reagents() diff --git a/code/modules/research/experimentor.dm b/code/modules/research/experimentor.dm index 5be45906a8a8..4c306bfbe516 100644 --- a/code/modules/research/experimentor.dm +++ b/code/modules/research/experimentor.dm @@ -254,8 +254,8 @@ loaded_item = null /obj/machinery/rnd/experimentor/proc/throwSmoke(turf/where) - var/datum/effect_system/smoke_spread/smoke = new - smoke.set_up(0, where) + var/datum/effect_system/fluid_spread/smoke/smoke = new + smoke.set_up(0, location = where) smoke.start() @@ -338,28 +338,28 @@ autoexperiment = 0 visible_message(span_danger("[src] destroys [exp_on], leaking dangerous gas!")) chosenchem = pick(/datum/reagent/carbon,/datum/reagent/uranium/radium,/datum/reagent/toxin,/datum/reagent/consumable/condensedcapsaicin,/datum/reagent/drug/mushroomhallucinogen,/datum/reagent/drug/space_drugs,/datum/reagent/consumable/ethanol,/datum/reagent/consumable/ethanol/beepsky_smash) - var/datum/reagents/R = new/datum/reagents(50) - R.my_atom = src - R.add_reagent(chosenchem , 50) + var/datum/reagents/tmp_holder = new/datum/reagents(50) + tmp_holder.my_atom = src + tmp_holder.add_reagent(chosenchem , 50) investigate_log("Experimentor has released [chosenchem] smoke.", INVESTIGATE_EXPERIMENTOR) - var/datum/effect_system/smoke_spread/chem/smoke = new - smoke.set_up(R, 0, src, silent = TRUE) + var/datum/effect_system/fluid_spread/smoke/chem/smoke = new + smoke.set_up(0, location = src, carry = tmp_holder, silent = TRUE) playsound(src, 'sound/effects/smoke.ogg', 50, 1, -3) smoke.start() - qdel(R) + qdel(tmp_holder) ejectItem(TRUE) else if(prob(EFFECT_PROB_VERYLOW-badThingCoeffIfCrit)) autoexperiment = 0 visible_message(span_danger("[src]'s chemical chamber has sprung a leak!")) chosenchem = pick(/datum/reagent/mutationtoxin/felinid,/datum/reagent/nanomachines,/datum/reagent/toxin/acid) - var/datum/reagents/R = new/datum/reagents(50) - R.my_atom = src - R.add_reagent(chosenchem , 50) - var/datum/effect_system/smoke_spread/chem/smoke = new - smoke.set_up(R, 0, src, silent = TRUE) + var/datum/reagents/tmp_holder = new/datum/reagents(50) + tmp_holder.my_atom = src + tmp_holder.add_reagent(chosenchem , 50) + var/datum/effect_system/fluid_spread/smoke/chem/smoke = new + smoke.set_up(0, location = src, carry = tmp_holder, silent = TRUE) playsound(src, 'sound/effects/smoke.ogg', 50, 1, -3) smoke.start() - qdel(R) + qdel(tmp_holder) ejectItem(TRUE) warn_admins(usr, "[chosenchem] smoke") investigate_log("Experimentor has released [chosenchem] smoke!", INVESTIGATE_EXPERIMENTOR) @@ -444,15 +444,15 @@ else if(prob(EFFECT_PROB_VERYLOW-badThingCoeff)) autoexperiment = 0 visible_message(span_danger("[src] malfunctions, shattering [exp_on] and releasing a dangerous cloud of coolant!")) - var/datum/reagents/R = new/datum/reagents(50) - R.my_atom = src - R.add_reagent(/datum/reagent/consumable/frostoil, 50) + var/datum/reagents/tmp_holder = new/datum/reagents(50) + tmp_holder.my_atom = src + tmp_holder.add_reagent(/datum/reagent/consumable/frostoil, 50) investigate_log("Experimentor has released frostoil gas.", INVESTIGATE_EXPERIMENTOR) - var/datum/effect_system/smoke_spread/chem/smoke = new - smoke.set_up(R, 0, src, silent = TRUE) + var/datum/effect_system/fluid_spread/smoke/chem/smoke = new + smoke.set_up(0, location = src, carry = tmp_holder, silent = TRUE) playsound(src, 'sound/effects/smoke.ogg', 50, 1, -3) smoke.start() - qdel(R) + qdel(tmp_holder) ejectItem(TRUE) else if(prob(EFFECT_PROB_LOW-badThingCoeff)) autoexperiment = 0 @@ -472,8 +472,8 @@ else if(prob(EFFECT_PROB_MEDIUM-badThingCoeff)) autoexperiment = 0 visible_message(span_warning("[src] malfunctions, releasing a flurry of chilly air as [exp_on] pops out!")) - var/datum/effect_system/smoke_spread/smoke = new - smoke.set_up(0, loc) + var/datum/effect_system/fluid_spread/smoke/smoke = new + smoke.set_up(0, location = loc) smoke.start() ejectItem() //////////////////////////////////////////////////////////////////////////////////////////////// @@ -639,8 +639,8 @@ //////////////// RELIC PROCS ///////////////////////////// /obj/item/relic/proc/throwSmoke(turf/where) - var/datum/effect_system/smoke_spread/smoke = new - smoke.set_up(0, get_turf(where)) + var/datum/effect_system/fluid_spread/smoke/smoke = new + smoke.set_up(0, location = get_turf(where)) smoke.start() /obj/item/relic/proc/corgicannon(mob/user) diff --git a/code/modules/research/xenobiology/crossbreeding/burning.dm b/code/modules/research/xenobiology/crossbreeding/burning.dm index 06680dde49da..292d61e4063e 100644 --- a/code/modules/research/xenobiology/crossbreeding/burning.dm +++ b/code/modules/research/xenobiology/crossbreeding/burning.dm @@ -45,11 +45,11 @@ Burning extracts: /obj/item/slimecross/burning/orange/do_effect(mob/user) user.visible_message(span_danger("[src] boils over with a caustic gas!")) - var/datum/reagents/R = new/datum/reagents(100) - R.add_reagent(/datum/reagent/consumable/condensedcapsaicin, 100) + var/datum/reagents/tmp_holder = new/datum/reagents(100) + tmp_holder.add_reagent(/datum/reagent/consumable/condensedcapsaicin, 100) - var/datum/effect_system/smoke_spread/chem/smoke = new - smoke.set_up(R, 7, get_turf(user)) + var/datum/effect_system/fluid_spread/smoke/chem/smoke = new + smoke.set_up(7, location = get_turf(user), carry = tmp_holder) smoke.start() ..() @@ -120,11 +120,11 @@ Burning extracts: /obj/item/slimecross/burning/darkblue/do_effect(mob/user) user.visible_message(span_danger("[src] releases a burst of chilling smoke!")) - var/datum/reagents/R = new/datum/reagents(100) - R.add_reagent(/datum/reagent/consumable/frostoil, 40) - user.reagents.add_reagent(/datum/reagent/medicine/cryoxadone,10) - var/datum/effect_system/smoke_spread/chem/smoke = new - smoke.set_up(R, 7, get_turf(user)) + var/datum/reagents/tmp_holder = new/datum/reagents(100) + tmp_holder.add_reagent(/datum/reagent/consumable/frostoil, 40) + user.reagents.add_reagent(/datum/reagent/medicine/regen_jelly, 10) + var/datum/effect_system/fluid_spread/smoke/chem/smoke = new + smoke.set_up(7, location = get_turf(user), carry = tmp_holder) smoke.start() ..() diff --git a/code/modules/research/xenobiology/xenobiology.dm b/code/modules/research/xenobiology/xenobiology.dm index 0022f70a258b..f3fa1049406a 100644 --- a/code/modules/research/xenobiology/xenobiology.dm +++ b/code/modules/research/xenobiology/xenobiology.dm @@ -320,11 +320,7 @@ return 250 if(SLIME_ACTIVATE_MAJOR) - var/location = get_turf(user) - var/datum/effect_system/foam_spread/s = new() - s.set_up(20, location, user.reagents) - s.start() - user.reagents.clear_reagents() + user.reagents.create_foam(/datum/effect_system/fluid_spread/foam, 20) user.visible_message(span_danger("Foam spews out from [user]'s skin!"), span_warning("You activate [src], and foam bursts out of your skin!")) return 600 diff --git a/code/modules/spells/spell.dm b/code/modules/spells/spell.dm index 81a9eba699ed..c88e2af1ee8b 100644 --- a/code/modules/spells/spell.dm +++ b/code/modules/spells/spell.dm @@ -147,8 +147,10 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th var/sparks_spread = 0 var/sparks_amt = 0 //cropped at 10 - var/smoke_spread = 0 //1 - harmless, 2 - harmful - var/smoke_amt = 0 //cropped at 10 + /// The typepath of the smoke to create on cast. + var/smoke_spread = null + /// The amount of smoke to create on case. This is a range so a value of 5 will create enough smoke to cover everything within 5 steps. + var/smoke_amt = 0 var/centcom_cancast = TRUE //Whether or not the spell should be allowed on z2 @@ -356,19 +358,10 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th to_chat(target, text("[message]")) if(sparks_spread) do_sparks(sparks_amt, FALSE, location) - if(smoke_spread) - if(smoke_spread == 1) - var/datum/effect_system/smoke_spread/smoke = new - smoke.set_up(smoke_amt, location) - smoke.start() - else if(smoke_spread == 2) - var/datum/effect_system/smoke_spread/bad/smoke = new - smoke.set_up(smoke_amt, location) - smoke.start() - else if(smoke_spread == 3) - var/datum/effect_system/smoke_spread/sleeping/smoke = new - smoke.set_up(smoke_amt, location) - smoke.start() + if(ispath(smoke_spread, /datum/effect_system/fluid_spread/smoke)) // Dear god this code is :agony: + var/datum/effect_system/fluid_spread/smoke/smoke = new smoke_spread() + smoke.set_up(smoke_amt, location = location) + smoke.start() /obj/effect/proc_holder/spell/proc/cast(list/targets,mob/user = usr) diff --git a/code/modules/spells/spell_types/construct_spells.dm b/code/modules/spells/spell_types/construct_spells.dm index d6f507697ad9..8a933b15e30a 100644 --- a/code/modules/spells/spell_types/construct_spells.dm +++ b/code/modules/spells/spell_types/construct_spells.dm @@ -183,7 +183,7 @@ include_user = TRUE cooldown_min = 20 //25 deciseconds reduction per rank - smoke_spread = 3 + smoke_spread = /datum/effect_system/fluid_spread/smoke/sleeping smoke_amt = 4 action_icon_state = "smoke" action_background_icon_state = "bg_cult" diff --git a/code/modules/spells/spell_types/devil.dm b/code/modules/spells/spell_types/devil.dm index 62533f29a5ac..aebd488225ae 100644 --- a/code/modules/spells/spell_types/devil.dm +++ b/code/modules/spells/spell_types/devil.dm @@ -220,7 +220,7 @@ var/list/dancefloor_turfs var/list/dancefloor_turfs_types var/dancefloor_exists = FALSE - var/datum/effect_system/smoke_spread/transparent/dancefloor_devil/smoke + var/datum/effect_system/fluid_spread/smoke/transparent/dancefloor_devil/smoke /obj/effect/proc_holder/spell/targeted/summon_dancefloor/cast(list/targets, mob/user = usr) @@ -229,7 +229,7 @@ if(!smoke) smoke = new() - smoke.set_up(0, get_turf(user)) + smoke.set_up(0, location = get_turf(user)) smoke.start() if(dancefloor_exists) @@ -253,8 +253,8 @@ T.ChangeTurf((i % 2 == 0) ? /turf/open/floor/light/colour_cycle/dancefloor_a : /turf/open/floor/light/colour_cycle/dancefloor_b, flags = CHANGETURF_INHERIT_AIR) i++ -/datum/effect_system/smoke_spread/transparent/dancefloor_devil - effect_type = /obj/effect/particle_effect/smoke/transparent/dancefloor_devil +/datum/effect_system/fluid_spread/smoke/transparent/dancefloor_devil + effect_type = /obj/effect/particle_effect/fluid/smoke/transparent/dancefloor_devil -/obj/effect/particle_effect/smoke/transparent/dancefloor_devil +/obj/effect/particle_effect/fluid/smoke/transparent/dancefloor_devil lifetime = 2 diff --git a/code/modules/spells/spell_types/wizard.dm b/code/modules/spells/spell_types/wizard.dm index 1a911e94c779..505ddbe6329f 100644 --- a/code/modules/spells/spell_types/wizard.dm +++ b/code/modules/spells/spell_types/wizard.dm @@ -72,7 +72,7 @@ include_user = TRUE cooldown_min = 20 //25 deciseconds reduction per rank - smoke_spread = 2 + smoke_spread = /datum/effect_system/fluid_spread/smoke/bad smoke_amt = 4 action_icon_state = "smoke" @@ -90,7 +90,7 @@ range = -1 include_user = TRUE - smoke_spread = 1 + smoke_spread = /datum/effect_system/fluid_spread/smoke smoke_amt = 2 action_icon_state = "smoke" @@ -124,7 +124,7 @@ cooldown_min = 5 //4 deciseconds reduction per rank - smoke_spread = 1 + smoke_spread = /datum/effect_system/fluid_spread/smoke smoke_amt = 0 inner_tele_radius = 0 @@ -155,7 +155,7 @@ include_user = TRUE cooldown_min = 200 //100 deciseconds reduction per rank - smoke_spread = 1 + smoke_spread = /datum/effect_system/fluid_spread/smoke smoke_amt = 2 sound1 = 'sound/magic/teleport_diss.ogg' sound2 = 'sound/magic/teleport_app.ogg' diff --git a/code/modules/vehicles/cars/clowncar.dm b/code/modules/vehicles/cars/clowncar.dm index 607d62cbff7f..a244aa9a7d0a 100644 --- a/code/modules/vehicles/cars/clowncar.dm +++ b/code/modules/vehicles/cars/clowncar.dm @@ -47,7 +47,11 @@ . = ..() if(prob(33)) visible_message(span_danger("[src] spews out a ton of space lube!")) - new /obj/effect/particle_effect/foam(loc) //YEET + var/datum/effect_system/fluid_spread/foam/foam = new + var/datum/reagents/foamreagent = new /datum/reagents(25) + foamreagent.add_reagent(/datum/reagent/lube, 25) + foam.set_up(4, holder = src, location = loc, carry = foamreagent) + foam.start() /obj/vehicle/sealed/car/clowncar/attacked_by(obj/item/I, mob/living/user) . = ..() @@ -106,11 +110,11 @@ new /obj/item/grown/bananapeel/specialpeel(loc) if(2) visible_message(span_danger("[user] has pressed one of the colorful buttons on [src] and unknown chemicals flood out of it.")) - var/datum/reagents/R = new/datum/reagents(300) - R.my_atom = src - R.add_reagent(get_random_reagent_id(), 100) - var/datum/effect_system/foam_spread/foam = new - foam.set_up(200, loc, R) + var/datum/reagents/tmp_holder = new/datum/reagents(300) + tmp_holder.my_atom = src + tmp_holder.add_reagent(get_random_reagent_id(), 100) + var/datum/effect_system/fluid_spread/foam/short/foam = new + foam.set_up(4, location = loc, carry = tmp_holder) foam.start() if(3) visible_message(span_danger("[user] has pressed one of the colorful buttons on [src] and the clown car turns on its singularity disguise system.")) @@ -119,11 +123,11 @@ addtimer(CALLBACK(src, .proc/ResetIcon), 100) if(4) visible_message(span_danger("[user] has pressed one of the colorful buttons on [src] and the clown car spews out a cloud of laughing gas.")) - var/datum/reagents/R = new/datum/reagents(300) - R.my_atom = src - R.add_reagent(/datum/reagent/consumable/superlaughter, 50) - var/datum/effect_system/smoke_spread/chem/smoke = new() - smoke.set_up(R, 4) + var/datum/reagents/tmp_holder = new/datum/reagents(300) + tmp_holder.my_atom = src + tmp_holder.add_reagent(/datum/reagent/consumable/superlaughter, 50) + var/datum/effect_system/fluid_spread/smoke/chem/smoke = new() + smoke.set_up(4, location = loc, carry = tmp_holder) smoke.attach(src) smoke.start() if(5) diff --git a/config/config.txt b/config/config.txt index c7d1b7fb6dee..77e123f1df4a 100644 --- a/config/config.txt +++ b/config/config.txt @@ -126,7 +126,7 @@ LOG_VIRUS LOG_CLONING ## Enable the demo subsystem -DEMOS_ENABLED +#DEMOS_ENABLED ##Log camera pictures - Must have picture logging enabled # PICTURE_LOGGING_CAMERA diff --git a/yogstation.dme b/yogstation.dme index e305378f5fcd..6129c4052a29 100644 --- a/yogstation.dme +++ b/yogstation.dme @@ -331,6 +331,7 @@ #include "code\controllers\subsystem\events.dm" #include "code\controllers\subsystem\explosions.dm" #include "code\controllers\subsystem\fire_burning.dm" +#include "code\controllers\subsystem\fluids.dm" #include "code\controllers\subsystem\garbage.dm" #include "code\controllers\subsystem\icon_smooth.dm" #include "code\controllers\subsystem\idlenpcpool.dm" @@ -378,11 +379,11 @@ #include "code\controllers\subsystem\weather.dm" #include "code\controllers\subsystem\processing\fastprocess.dm" #include "code\controllers\subsystem\processing\fields.dm" -#include "code\controllers\subsystem\processing\fluids.dm" #include "code\controllers\subsystem\processing\instruments.dm" #include "code\controllers\subsystem\processing\nanites.dm" #include "code\controllers\subsystem\processing\networks.dm" #include "code\controllers\subsystem\processing\obj.dm" +#include "code\controllers\subsystem\processing\plumbing.dm" #include "code\controllers\subsystem\processing\processing.dm" #include "code\controllers\subsystem\processing\projectiles.dm" #include "code\controllers\subsystem\processing\quirks.dm" @@ -1003,11 +1004,12 @@ #include "code\game\objects\effects\decals\turfdecal\weather.dm" #include "code\game\objects\effects\effect_system\effect_system.dm" #include "code\game\objects\effects\effect_system\effects_explosion.dm" -#include "code\game\objects\effects\effect_system\effects_foam.dm" #include "code\game\objects\effects\effect_system\effects_other.dm" -#include "code\game\objects\effects\effect_system\effects_smoke.dm" #include "code\game\objects\effects\effect_system\effects_sparks.dm" #include "code\game\objects\effects\effect_system\effects_water.dm" +#include "code\game\objects\effects\effect_system\fluid_spread\_fluid_spread.dm" +#include "code\game\objects\effects\effect_system\fluid_spread\effects_foam.dm" +#include "code\game\objects\effects\effect_system\fluid_spread\effects_smoke.dm" #include "code\game\objects\effects\spawners\bombspawner.dm" #include "code\game\objects\effects\spawners\bundle.dm" #include "code\game\objects\effects\spawners\food_drink.dm" @@ -2105,6 +2107,7 @@ #include "code\modules\events\prison_break.dm" #include "code\modules\events\processor_overload.dm" #include "code\modules\events\radiation_storm.dm" +#include "code\modules\events\scrubber_overflow.dm" #include "code\modules\events\sentience.dm" #include "code\modules\events\shuttle_catastrophe.dm" #include "code\modules\events\shuttle_loan.dm" @@ -2117,7 +2120,6 @@ #include "code\modules\events\supermatter_surge.dm" #include "code\modules\events\swarmer.dm" #include "code\modules\events\tzimisce.dm" -#include "code\modules\events\vent_clog.dm" #include "code\modules\events\wormholes.dm" #include "code\modules\events\zombie_infection.dm" #include "code\modules\events\holiday\halloween.dm" diff --git a/yogstation/code/game/objects/items/grenades/glitterbombs.dm b/yogstation/code/game/objects/items/grenades/glitterbombs.dm index 552b512b4266..89ab5f151316 100644 --- a/yogstation/code/game/objects/items/grenades/glitterbombs.dm +++ b/yogstation/code/game/objects/items/grenades/glitterbombs.dm @@ -4,12 +4,12 @@ can_attach_mob = TRUE var/glitter_type = "glitter" -/datum/effect_system/smoke_spread/chem/glitter - effect_type = /obj/effect/particle_effect/smoke/chem/glitter +datum/effect_system/fluid_spread/smoke/chem/glitter + effect_type = /obj/effect/particle_effect/fluid/smoke/chem/glitter -/obj/effect/particle_effect/smoke/chem/glitter - lifetime = 6 - opaque = TRUE +/obj/effect/particle_effect/fluid/smoke/chem/glitter + lifetime = 6 SECONDS + opacity = TRUE /obj/item/grenade/plastic/glitterbomb/Initialize() . = ..() @@ -17,8 +17,8 @@ reagents.add_reagent(glitter_type, 20) /obj/item/grenade/plastic/glitterbomb/prime() - var/datum/effect_system/smoke_spread/chem/glitter/smoke = new() - smoke.set_up(reagents, 4, target) + var/datum/effect_system/fluid_spread/smoke/chem/glitter/smoke = new() + smoke.set_up(4, location = target, carry = reagents) smoke.start() playsound(target, 'sound/items/party_horn.ogg', 50, 1, -1) target.cut_overlay(plastic_overlay, TRUE) @@ -41,4 +41,4 @@ /obj/item/grenade/plastic/glitterbomb/white desc = "Used to put the party in specific locations. This one seems to be white colored and makes you feel sleepy by just looking at it." - glitter_type = "white_glitter" \ No newline at end of file + glitter_type = "white_glitter" diff --git a/yogstation/code/game/objects/structures/toilet_bong.dm b/yogstation/code/game/objects/structures/toilet_bong.dm index 0b3787b027e4..0933f27fce5d 100644 --- a/yogstation/code/game/objects/structures/toilet_bong.dm +++ b/yogstation/code/game/objects/structures/toilet_bong.dm @@ -42,9 +42,9 @@ user.visible_message(span_danger("[user] coughs while using [src], filling the area with smoke!"), span_userdanger("You cough while using [src], filling the area with smoke!")) smoke_spread = 5 var/turf/location = get_turf(user) - var/datum/effect_system/smoke_spread/chem/smoke = new + var/datum/effect_system/fluid_spread/smoke/chem/smoke = new smoke.attach(location) - smoke.set_up(boof.reagents, smoke_spread, location, silent = TRUE) + smoke.set_up(smoke_spread, location = location, carry = boof.reagents, silent = TRUE) smoke.start() qdel(boof) update_icon() diff --git a/yogstation/code/modules/antagonists/shadowling/shadowling_abilities.dm b/yogstation/code/modules/antagonists/shadowling/shadowling_abilities.dm index 5c39824f1cc3..9beaa239b099 100644 --- a/yogstation/code/modules/antagonists/shadowling/shadowling_abilities.dm +++ b/yogstation/code/modules/antagonists/shadowling/shadowling_abilities.dm @@ -534,10 +534,10 @@ B.reagents.clear_reagents() //Just in case! B.invisibility = INFINITY //This ought to do the trick B.reagents.add_reagent(/datum/reagent/shadowling_blindness_smoke, 10) - var/datum/effect_system/smoke_spread/chem/S = new + var/datum/effect_system/fluid_spread/smoke/chem/S = new S.attach(B) if(S) - S.set_up(B.reagents, 4, 0, B.loc) + S.set_up(4, location = B.loc, carry = B.reagents) S.start() qdel(B) diff --git a/yogstation/code/modules/events/immovable_duck.dm b/yogstation/code/modules/events/immovable_duck.dm index b3fba39cb09f..ec593ddeb12b 100644 --- a/yogstation/code/modules/events/immovable_duck.dm +++ b/yogstation/code/modules/events/immovable_duck.dm @@ -55,16 +55,15 @@ penetrate(clong) else if(istype(clong, type)) var/obj/effect/immovablerod/other = clong - visible_message("[src] collides with [other]!\ - ") - var/datum/effect_system/smoke_spread/smoke = new - smoke.set_up(2, get_turf(src)) + visible_message(span_danger("[src] collides with [other]!")) + var/datum/effect_system/fluid_spread/smoke/smoke = new + smoke.set_up(2, location = get_turf(src)) smoke.start() qdel(src) qdel(other) /obj/effect/immovablerod/duck/penetrate(mob/living/L) - L.visible_message(span_danger("[L] is QUACKED by an immovable duck!") , span_userdanger("You get QUACKED!!!") , "You hear a QUACK!") + L.visible_message(span_danger("[L] is QUACKED by an immovable duck!") , span_userdanger("You get QUACKED!!!") , span_danger("You hear a QUACK!")) if(ishuman(L)) var/mob/living/carbon/human/H = L H.adjustBruteLoss(160)