From 068a3be8595f8fdd7ae140bc78a57929d3eb9e3b Mon Sep 17 00:00:00 2001 From: TemporalOroboros Date: Sat, 7 May 2022 13:10:37 -0700 Subject: [PATCH] Makes smoke and foam attempt to fill the available space. (#65281) Have you ever noticed that the chemical smoke and chemical foam reactions are a lot less effective in confined spaces? This is because they currently attempt to spread to all tiles within n steps of their origin. If they can't expand onto a tile they get blocked and the expanding cloud/flood misses out on all the tiles that would be in range, but that can't be reached. Obviously smoke and foam getting blocked by walls and the like makes intuitive sense, but it seemed a bit nonsensical that walls would basically delete a significant chunk of an expanding, amoebic mass. The solution I came up with is making smoke and foam expand until they cover a certain area, with a shared tracker for the target size and total size of the flood. The flood will simply expand as normal until it covers the desired target area. Blocked expansions just don't count and will be made up for with expansion elsewhere. Attendant to these changes are a whole bunch of minor code improvement to smoke, foam, and one for wizard spells because I was already in the area and :pain:. There have been some minor balance changes to the chemical smoke and foam reactions: I converted them over to passing the desired area of the resulting smoke cloud/foam flood. The old equation for the resulting area was along the lines of 2sqrt(x)(sqrt(x) + 1) + 1 given reaction volume x and given unobstructed expansion. I've made them just pass around 2x instead. This is actually less than they used to try for, but now they're guaranteed to reach that unless the flood is fully contained. Not entirely certain if buff or nerf. Probably buff on the station. Also, foam dilution is now based on covered area instead of target expansion range. Since this scales faster than it used to foam has been effectively nerfed at high volumes. To compensate for this I removed the jank 6/7 effect multiplier and increased the base reagent scaling a bit. Again, not certain if buff or nerf. --- code/__DEFINES/MC.dm | 8 + code/__DEFINES/maths.dm | 6 + code/__DEFINES/subsystems.dm | 3 +- code/__HELPERS/reagents.dm | 8 +- 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 | 2 +- code/game/machinery/suit_storage_unit.dm | 4 +- code/game/objects/effects/anomalies.dm | 2 +- .../effect_system/effects_explosion.dm | 4 +- .../effects/effect_system/effects_foam.dm | 386 --------------- .../effects/effect_system/effects_smoke.dm | 381 --------------- .../fluid_spread/_fluid_spread.dm | 126 +++++ .../fluid_spread/effects_foam.dm | 429 +++++++++++++++++ .../fluid_spread/effects_smoke.dm | 438 ++++++++++++++++++ code/game/objects/effects/mines.dm | 2 +- 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/food/burgers.dm | 6 +- code/game/objects/items/grenades/smokebomb.dm | 4 +- code/game/objects/items/nitrium_crystals.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 +- code/game/objects/structures/watercloset.dm | 2 +- .../antagonists/_common/antag_spawner.dm | 2 +- code/modules/antagonists/blob/blob_mobs.dm | 8 +- .../nukeop/equipment/nuclearbomb.dm | 6 +- .../awaymissions/mission_code/Academy.dm | 12 +- .../modules/awaymissions/super_secret_room.dm | 4 +- code/modules/clothing/head/tophat.dm | 2 +- .../under/jobs/Plasmaman/civilian_service.dm | 2 +- code/modules/events/immovable_rod.dm | 4 +- code/modules/events/wisdomcow.dm | 2 +- code/modules/events/wizard/curseditems.dm | 4 +- code/modules/events/wizard/imposter.dm | 2 +- code/modules/events/wizard/shuffle.dm | 12 +- code/modules/explorer_drone/exodrone.dm | 2 +- .../kitchen_machinery/grill.dm | 4 +- code/modules/hydroponics/grown/onion.dm | 10 +- code/modules/hydroponics/plant_genes.dm | 6 +- code/modules/mining/equipment/survival_pod.dm | 2 +- .../mob/living/basic/farm_animals/cows.dm | 2 +- .../mob/living/simple_animal/bot/cleanbot.dm | 2 +- .../mob/living/simple_animal/bot/firebot.dm | 2 +- .../living/simple_animal/bot/hygienebot.dm | 2 +- .../hostile/mining_mobs/elites/legionnaire.dm | 4 +- .../simple_animal/hostile/retaliate/clown.dm | 8 +- code/modules/mod/modules/modules_security.dm | 5 +- code/modules/projectiles/guns/magic/wand.dm | 8 +- code/modules/projectiles/projectile/magic.dm | 9 +- .../chemistry/machinery/smoke_machine.dm | 34 +- .../reagents/pyrotechnic_reagents.dm | 2 +- code/modules/reagents/chemistry/recipes.dm | 8 +- .../reagents/chemistry/recipes/others.dm | 8 +- .../chemistry/recipes/pyrotechnics.dm | 10 +- .../chemistry/recipes/slime_extracts.dm | 2 +- code/modules/research/experimentor.dm | 48 +- .../xenobiology/crossbreeding/burning.dm | 18 +- .../vatgrowing/samples/_micro_organism.dm | 4 +- .../research/xenobiology/xenobiology.dm | 2 +- code/modules/spells/spell.dm | 23 +- .../spells/spell_types/construct_spells.dm | 2 +- code/modules/spells/spell_types/wizard.dm | 8 +- code/modules/station_goals/bsa.dm | 6 +- code/modules/vehicles/atv.dm | 4 +- code/modules/vehicles/cars/clowncar.dm | 8 +- code/modules/vehicles/mecha/_mecha.dm | 4 +- .../mecha/equipment/tools/other_tools.dm | 2 +- code/modules/vehicles/secway.dm | 4 +- tgstation.dme | 8 +- 75 files changed, 1483 insertions(+), 981 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 diff --git a/code/__DEFINES/MC.dm b/code/__DEFINES/MC.dm index 3b39140fcde..94593dec5b2 100644 --- a/code/__DEFINES/MC.dm +++ b/code/__DEFINES/MC.dm @@ -102,3 +102,11 @@ }\ /datum/controller/subsystem/processing/##X/fire() {..() /*just so it shows up on the profiler*/} \ /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 91831182b99..b4de855bef9 100644 --- a/code/__DEFINES/maths.dm +++ b/code/__DEFINES/maths.dm @@ -44,6 +44,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) clamp(( min == max ? min : (val) - (round(((val) - (min))/((max) - (min))) * ((max) - (min))) ),min,max) +/// 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) - FLOOR(x, y)) @@ -226,3 +229,6 @@ // ) #define GET_TRUE_DIST(a, b) (a == null || b == null) ? -1 : max(abs(a.x -b.x), abs(a.y-b.y), abs(a.z-b.z)) + +/// 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 91dc340204a..aa942b9d13e 100644 --- a/code/__DEFINES/subsystems.dm +++ b/code/__DEFINES/subsystems.dm @@ -175,6 +175,7 @@ #define FIRE_PRIORITY_GARBAGE 15 #define FIRE_PRIORITY_DATABASE 16 #define FIRE_PRIORITY_WET_FLOORS 20 +#define FIRE_PRIORITY_FLUIDS 20 #define FIRE_PRIORITY_AIR 20 #define FIRE_PRIORITY_NPC 20 #define FIRE_PRIORITY_NPC_MOVEMENT 21 @@ -302,7 +303,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/reagents.dm b/code/__HELPERS/reagents.dm index 39d5b1ea37b..bfd00ed4698 100644 --- a/code/__HELPERS/reagents.dm +++ b/code/__HELPERS/reagents.dm @@ -79,11 +79,13 @@ GLOB.chemical_reactions_list_reactant_index[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,metaltype = 0,notification = null) +/datum/reagents/proc/create_foam(foamtype, foam_volume, result_type = null, notification = null) var/location = get_turf(my_atom) - var/datum/effect_system/foam_spread/foam = new foamtype() - foam.set_up(foam_volume, location, src, metaltype) + + var/datum/effect_system/fluid_spread/foam/foam = new foamtype() + foam.set_up(amount = foam_volume, location = location, carry = src, result_type = result_type) foam.start() + clear_reagents() if(!notification) return diff --git a/code/controllers/subsystem/fluids.dm b/code/controllers/subsystem/fluids.dm new file mode 100644 index 00000000000..cc77430b7d2 --- /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(start_timeofday) + initialize_waits() + initialize_spread_carousel() + initialize_effect_carousel() + return ..() + +/** + * 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 70903e0088c..34d6d8f882e 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 c8547a9b271..47e4f580732 100644 --- a/code/datums/components/plumbing/_plumbing.dm +++ b/code/datums/components/plumbing/_plumbing.dm @@ -68,7 +68,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) @@ -199,7 +199,7 @@ if(!active) return - STOP_PROCESSING(SSfluids, src) + STOP_PROCESSING(SSplumbing, src) for(var/A in ducts) var/datum/ductnet/D = ducts[A] @@ -231,7 +231,7 @@ D.disconnect_duct() if(demand_connects) - START_PROCESSING(SSfluids, src) + START_PROCESSING(SSplumbing, src) for(var/D in GLOB.cardinals) diff --git a/code/game/machinery/ai_slipper.dm b/code/game/machinery/ai_slipper.dm index 2a28d35cb95..1427f16e77b 100644 --- a/code/game/machinery/ai_slipper.dm +++ b/code/game/machinery/ai_slipper.dm @@ -37,7 +37,7 @@ if(cooldown_time > world.time) to_chat(user, span_warning("[src] cannot be activated for [DisplayTimeText(world.time - cooldown_time)]!")) return - new /obj/effect/particle_effect/foam(loc) + new /obj/effect/particle_effect/fluid/foam(loc) 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/machinery/suit_storage_unit.dm b/code/game/machinery/suit_storage_unit.dm index 7fa56c56c8c..7bcda26b8b0 100644 --- a/code/game/machinery/suit_storage_unit.dm +++ b/code/game/machinery/suit_storage_unit.dm @@ -388,8 +388,8 @@ if(uv_super) visible_message(span_warning("[src]'s door creaks open with a loud whining noise. A cloud of foul black smoke escapes from its chamber.")) playsound(src, 'sound/machines/airlock_alien_prying.ogg', 50, TRUE) - var/datum/effect_system/smoke_spread/bad/black/smoke = new - smoke.set_up(0, src) + var/datum/effect_system/fluid_spread/smoke/bad/black/smoke = new + smoke.set_up(0, location = src) smoke.start() QDEL_NULL(helmet) QDEL_NULL(suit) diff --git a/code/game/objects/effects/anomalies.dm b/code/game/objects/effects/anomalies.dm index 5c69ad2e9d4..f1e3dd3ba8d 100644 --- a/code/game/objects/effects/anomalies.dm +++ b/code/game/objects/effects/anomalies.dm @@ -79,7 +79,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) if(drops_core) aSignal.forceMove(drop_location()) diff --git a/code/game/objects/effects/effect_system/effects_explosion.dm b/code/game/objects/effects/effect_system/effects_explosion.dm index 60ed4f31dcb..13d32870de8 100644 --- a/code/game/objects/effects/effect_system/effects_explosion.dm +++ b/code/game/objects/effects/effect_system/effects_explosion.dm @@ -57,8 +57,8 @@ /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() 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 59ef1d376c2..00000000000 --- a/code/game/objects/effects/effect_system/effects_foam.dm +++ /dev/null @@ -1,386 +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 = FALSE - anchored = TRUE - density = FALSE - layer = EDGED_TURF_LAYER - plane = GAME_PLANE_UPPER - mouse_opacity = MOUSE_OPACITY_TRANSPARENT - var/amount = 3 - animate_movement = NO_STEPS - 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 - -/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/Initialize(mapload) - . = ..() - RemoveElement(/datum/element/atmos_sensitive) - -/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 - if(G.gases[/datum/gas/plasma]) - var/plas_amt = min(30,G.gases[/datum/gas/plasma][MOLES]) //Absorb some plasma - G.gases[/datum/gas/plasma][MOLES] -= plas_amt - absorbed_plasma += plas_amt - if(G.temperature > T20C) - G.temperature = max(G.temperature/2,T20C) - G.garbage_collect() - T.air_update_turf(FALSE, FALSE) - -/obj/effect/particle_effect/foam/firefighting/kill_foam() - STOP_PROCESSING(SSfastprocess, 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_wet_stacks(2) - -/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(mapload) - . = ..() - create_reagents(1000) //limited by the size of the reagent holder anyway. - START_PROCESSING(SSfastprocess, src) - playsound(src, 'sound/effects/bubbles2.ogg', 80, TRUE, -3) - AddElement(/datum/element/atmos_sensitive, mapload) - -/obj/effect/particle_effect/foam/ComponentInitialize() - . = ..() - if(slippery_foam) - AddComponent(/datum/component/slippery, 100) - -/obj/effect/particle_effect/foam/Destroy() - STOP_PROCESSING(SSfastprocess, src) - return ..() - - -/obj/effect/particle_effect/foam/proc/kill_foam() - STOP_PROCESSING(SSfastprocess, 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(SSfastprocess, 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(isturf(O.loc)) - var/turf/T = O.loc - if(T.underfloor_accessibility < UNDERFLOOR_INTERACTABLE && HAS_TRAIT(O, TRAIT_T_RAY_VISIBLE)) - continue - if(lifetime % reagent_divisor) - reagents.expose(O, VAPOR, fraction) - var/hit = 0 - for(var/mob/living/L in range(0,src)) - hit += foam_mob(L) - if(hit) - lifetime++ //this is so the decrease from mobs hit and the natural decrease don't cumulate. - var/T = get_turf(src) - if(lifetime % reagent_divisor) - reagents.expose(T, VAPOR, fraction) - - if(--amount < 0) - return - spread_foam() - -/obj/effect/particle_effect/foam/proc/foam_mob(mob/living/L) - if(lifetime<1) - return FALSE - if(!istype(L)) - return FALSE - var/fraction = 1/initial(reagent_divisor) - if(lifetime % reagent_divisor) - reagents.expose(L, VAPOR, fraction) - lifetime-- - return TRUE - -/obj/effect/particle_effect/foam/proc/spread_foam() - var/turf/t_loc = get_turf(src) - //This should just be atmos adjacent turfs, come on guys - for(var/turf/T in t_loc.reachableAdjacentTurfs()) - 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 - -/obj/effect/particle_effect/foam/should_atmos_process(datum/gas_mixture/air, exposed_temperature) - return exposed_temperature > 475 - -/obj/effect/particle_effect/foam/atmos_expose(datum/gas_mixture/air, exposed_temperature) - if(prob(max(0, exposed_temperature - 475))) //foam dissolves when heated - kill_foam() - - -/////////////////////////////////////////////// -//FOAM EFFECT DATUM -/datum/effect_system/foam_spread - /// the size of the foam spread. - var/amount = 10 - /// Stupid hack alertm exists to hold chems for us - var/atom/movable/chem_holder/chemholder - effect_type = /obj/effect/particle_effect/foam - var/metal = 0 - - -/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() - chemholder.create_reagents(1000, NO_REACT) - -/datum/effect_system/foam_spread/Destroy() - QDEL_NULL(chemholder) - return ..() - -/datum/effect_system/foam_spread/set_up(amt=5, loca, datum/reagents/carry = null, metaltype = 0) - if(isturf(loca)) - location = loca - else - location = get_turf(loca) - - amount = round(sqrt(amt / 2), 1) - carry.copy_to(chemholder, carry.total_volume) - if(metaltype) - metal = metaltype - -/datum/effect_system/foam_spread/start() - var/obj/effect/particle_effect/foam/F = new effect_type(location) - var/foamcolor = mix_color_from_reagents(chemholder.reagents.reagent_list) - // To prevent insane reagent multiplication with 1u foam - // I am capping amount of reagent foam recieves by limiting how low it can go - // Any radius of foam less than 3 makes foam recieve same amount of reagents as foam of radius 3 - // Maximum multiplication of reagents is about 166% (3 times as low as before, it was about 500% with 1u foam) - // - // amount is radius of the foam - // 10u foam has radius of 3 - // 5u foam has radius of 2 - // 1u foam has radius of 1 - var/effective_amount = chemholder.reagents.total_volume / max(amount, 3) - chemholder.reagents.copy_to(F, effective_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 = TRUE // changed in New() - anchored = TRUE - layer = EDGED_TURF_LAYER - plane = GAME_PLANE_UPPER - 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 - can_atmos_pass = ATMOS_PASS_DENSITY - obj_flags = CAN_BE_HIT | BLOCK_Z_IN_DOWN | BLOCK_Z_IN_UP - ///Var used to prevent spamming of the construction sound - var/next_beep = 0 - -/obj/structure/foamedmetal/Initialize(mapload) - . = ..() - air_update_turf(TRUE, TRUE) - -/obj/structure/foamedmetal/Destroy() - air_update_turf(TRUE, FALSE) - . = ..() - -/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) - -/obj/structure/foamedmetal/attackby(obj/item/W, mob/user, params) - ///A speed modifier for how fast the wall is build - var/platingmodifier = 1 - if(HAS_TRAIT(user, TRAIT_QUICK_BUILD)) - platingmodifier = 0.7 - if(next_beep <= world.time) - next_beep = world.time + 1 SECONDS - playsound(src, 'sound/machines/clockcult/integration_cog_install.ogg', 50, TRUE) - add_fingerprint(user) - - if(!istype(W, /obj/item/stack/sheet)) - return ..() - - var/obj/item/stack/sheet/sheet_for_plating = W - if(istype(sheet_for_plating, /obj/item/stack/sheet/iron)) - if(sheet_for_plating.get_amount() < 2) - to_chat(user, span_warning("You need two sheets of iron to finish a wall on [src]!")) - return - to_chat(user, span_notice("You start adding plating to the foam structure...")) - if (do_after(user, 40*platingmodifier, target = src)) - if(!sheet_for_plating.use(2)) - return - to_chat(user, span_notice("You add the plating.")) - var/turf/T = get_turf(src) - T.PlaceOnTop(/turf/closed/wall/metal_foam_base) - transfer_fingerprints_to(T) - qdel(src) - return - - add_hiddenprint(user) - -/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. It can be used as base to construct a wall." - opacity = FALSE - icon_state = "atmos_resin" - alpha = 120 - max_integrity = 10 - pass_flags_self = PASSGLASS - -/obj/structure/foamedmetal/resin/Initialize(mapload) - . = ..() - if(isopenturf(loc)) - var/turf/open/O = loc - O.ClearWet() - if(O.air) - var/datum/gas_mixture/G = O.air - G.temperature = 293.15 - for(var/obj/effect/hotspot/H in O) - qdel(H) - var/list/G_gases = G.gases - for(var/I in G_gases) - if(I == /datum/gas/oxygen || I == /datum/gas/nitrogen) - continue - G_gases[I][MOLES] = 0 - G.garbage_collect() - for(var/obj/machinery/atmospherics/components/unary/U in O) - if(!U.welded) - U.welded = TRUE - U.update_appearance() - U.visible_message(span_danger("[U] sealed shut!")) - for(var/mob/living/L in O) - L.extinguish_mob() - for(var/obj/item/Item in O) - Item.extinguish() - -#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 69609a41026..00000000000 --- a/code/game/objects/effects/effect_system/effects_smoke.dm +++ /dev/null @@ -1,381 +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 = FALSE - plane = ABOVE_GAME_PLANE - layer = FLY_LAYER - anchored = TRUE - mouse_opacity = MOUSE_OPACITY_TRANSPARENT - animate_movement = FALSE - 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/step = alpha / frames - for(var/i in 1 to frames) - alpha -= step - if(alpha < 160) - set_opacity(0) //if we were blocking view, we aren't now because we're fading out - stoplag() - -/obj/effect/particle_effect/smoke/Initialize(mapload) - . = ..() - create_reagents(1000) - 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 FALSE - for(var/mob/living/L in range(0,src)) - smoke_mob(L) - return TRUE - -/obj/effect/particle_effect/smoke/proc/smoke_mob(mob/living/carbon/C) - if(!istype(C)) - return FALSE - if(lifetime<1) - return FALSE - if(C.internal != null || C.has_smoke_protection()) - return FALSE - if(C.smoke_delay) - return FALSE - C.smoke_delay++ - addtimer(CALLBACK(src, .proc/remove_smoke_delay, C), 10) - return TRUE - -/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.get_atmos_adjacent_turfs()) - 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) - - //the smoke spreads rapidly but not instantly - for(var/obj/effect/particle_effect/smoke/SM in newsmokes) - addtimer(CALLBACK(SM, /obj/effect/particle_effect/smoke.proc/spread_smoke), 1) - - -/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/Initialize(mapload) - . = ..() - var/static/list/loc_connections = list( - COMSIG_ATOM_ENTERED = .proc/on_entered, - ) - AddElement(/datum/element/connect_loc, loc_connections) - -/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 TRUE - -/obj/effect/particle_effect/smoke/bad/proc/on_entered(datum/source, atom/movable/arrived, atom/old_loc, list/atom/old_locs) - SIGNAL_HANDLER - if(istype(arrived, /obj/projectile/beam)) - var/obj/projectile/beam/beam = arrived - beam.damage *= 0.5 - -/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 = FALSE - -/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.temperature = temperature - T.air_update_turf(FALSE, FALSE) - for(var/obj/effect/hotspot/H in T) - qdel(H) - var/list/G_gases = G.gases - if(G_gases[/datum/gas/plasma]) - G.assert_gas(/datum/gas/nitrogen) - G_gases[/datum/gas/nitrogen][MOLES] += (G_gases[/datum/gas/plasma][MOLES]) - G_gases[/datum/gas/plasma][MOLES] = 0 - G.garbage_collect() - 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_appearance() - U.visible_message(span_danger("[U] is frozen shut!")) - for(var/mob/living/L in T) - L.extinguish_mob() - 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.underfloor_accessibility < UNDERFLOOR_INTERACTABLE && HAS_TRAIT(AM, TRAIT_T_RAY_VISIBLE)) - continue - reagents.expose(AM, TOUCH, fraction) - - reagents.expose(T, TOUCH, fraction) - return TRUE - -/obj/effect/particle_effect/smoke/chem/smoke_mob(mob/living/carbon/M) - if(lifetime<1) - return FALSE - if(!istype(M)) - return FALSE - var/mob/living/carbon/C = M - if(C.internal != null || C.has_smoke_protection()) - return FALSE - var/fraction = 1/initial(lifetime) - reagents.copy_to(C, fraction*reagents.total_volume) - reagents.expose(M, INGEST, fraction) - return TRUE - - - -/datum/effect_system/smoke_spread/chem - /// Evil evil hack so we have something to "hold" our reagents - var/atom/movable/chem_holder/chemholder - effect_type = /obj/effect/particle_effect/smoke/chem - -/datum/effect_system/smoke_spread/chem/New() - ..() - chemholder = new() - chemholder.create_reagents(1000, NO_REACT) - -/datum/effect_system/smoke_spread/chem/Destroy() - QDEL_NULL(chemholder) - 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) //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)] " - if(!istype(carry.my_atom, /obj/machinery/plumbing)) - 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 - if(!istype(carry.my_atom, /obj/machinery/plumbing)) - 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() - -///////////////////////////////////////////// -// Bad Smoke (But Green (and Black)) -///////////////////////////////////////////// - -/obj/effect/particle_effect/smoke/bad/green - name = "green smoke" - color = "#00FF00" - opaque = FALSE - -/datum/effect_system/smoke_spread/bad/green - effect_type = /obj/effect/particle_effect/smoke/bad/green - -/obj/effect/particle_effect/smoke/bad/black - name = "black smoke" - color = "#383838" - opaque = FALSE - -/datum/effect_system/smoke_spread/bad/black - effect_type = /obj/effect/particle_effect/smoke/bad/black - -///////////////////////////////////////////// -// Quick smoke -///////////////////////////////////////////// - -/obj/effect/particle_effect/smoke/quick - lifetime = 1 - opaque = FALSE - -/datum/effect_system/smoke_spread/quick - effect_type = /obj/effect/particle_effect/smoke/quick - -/obj/effect/particle_effect/smoke/chem/quick - lifetime = 2 //under lifetime 1, this kills itself the first time it processes, not working. i hate smoke code - opaque = FALSE - alpha = 100 - -/datum/effect_system/smoke_spread/chem/quick - effect_type = /obj/effect/particle_effect/smoke/chem/quick 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 00000000000..1e1df733396 --- /dev/null +++ b/code/game/objects/effects/effect_system/fluid_spread/_fluid_spread.dm @@ -0,0 +1,126 @@ +///////////////////////////////////////////// +//// 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) + . = ..() + if(!group) + group = source?.group || new + group.add_node(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/location, ...) + src.location = get_turf(location) + src.amount = amount + +/datum/effect_system/fluid_spread/start() + var/location = holder ? get_turf(holder) : src.location + var/obj/effect/particle_effect/fluid/flood = new effect_type(location, new /datum/fluid_group(amount)) + flood.spread() 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 00000000000..aa13d37e576 --- /dev/null +++ b/code/game/objects/effects/effect_system/fluid_spread/effects_foam.dm @@ -0,0 +1,429 @@ +/// 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 + plane = GAME_PLANE_UPPER + 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) + . = ..() + 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/ComponentInitialize() + . = ..() + if(slippery_foam) + AddComponent(/datum/component/slippery, 100) + +/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 + return (!allow_duplicate_results && (locate(result_type) in location)) || (new result_type(location)) + +/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(location.underfloor_accessibility < UNDERFLOOR_INTERACTABLE && HAS_TRAIT(object, TRAIT_T_RAY_VISIBLE)) + continue + reagents.expose(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.expose(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.expose(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/should_atmos_process(datum/gas_mixture/air, exposed_temperature) + return exposed_temperature > 475 + +/obj/effect/particle_effect/fluid/foam/atmos_expose(datum/gas_mixture/air, exposed_temperature) + if(prob(max(0, exposed_temperature - 475))) //foam dissolves when heated + kill_foam() + +/// 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/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() + 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 + SSfoam.queue_spread(foam) + + +// 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/list/gases = air.gases + if (gases[/datum/gas/plasma]) + var/scrub_amt = min(30, gases[/datum/gas/plasma][MOLES]) //Absorb some plasma + gases[/datum/gas/plasma][MOLES] -= scrub_amt + absorbed_plasma += scrub_amt + if (air.temperature > T20C) + air.temperature = max(air.temperature / 2, T20C) + air.garbage_collect() + 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_wet_stacks(2) + + +// 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 + plane = GAME_PLANE_UPPER + 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 + can_atmos_pass = ATMOS_PASS_DENSITY + obj_flags = CAN_BE_HIT | BLOCK_Z_IN_DOWN | BLOCK_Z_IN_UP + ///Var used to prevent spamming of the construction sound + var/next_beep = 0 + +/obj/structure/foamedmetal/Initialize(mapload) + . = ..() + air_update_turf(TRUE, TRUE) + +/obj/structure/foamedmetal/Destroy() + air_update_turf(TRUE, FALSE) + . = ..() + +/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) + +/obj/structure/foamedmetal/attackby(obj/item/W, mob/user, params) + ///A speed modifier for how fast the wall is build + var/platingmodifier = 1 + if(HAS_TRAIT(user, TRAIT_QUICK_BUILD)) + platingmodifier = 0.7 + if(next_beep <= world.time) + next_beep = world.time + 1 SECONDS + playsound(src, 'sound/machines/clockcult/integration_cog_install.ogg', 50, TRUE) + add_fingerprint(user) + + if(!istype(W, /obj/item/stack/sheet)) + return ..() + + var/obj/item/stack/sheet/sheet_for_plating = W + if(istype(sheet_for_plating, /obj/item/stack/sheet/iron)) + if(sheet_for_plating.get_amount() < 2) + to_chat(user, span_warning("You need two sheets of iron to finish a wall on [src]!")) + return + to_chat(user, span_notice("You start adding plating to the foam structure...")) + if (do_after(user, 40 * platingmodifier, target = src)) + if(!sheet_for_plating.use(2)) + return + to_chat(user, span_notice("You add the plating.")) + var/turf/T = get_turf(src) + T.PlaceOnTop(/turf/closed/wall/metal_foam_base) + transfer_fingerprints_to(T) + qdel(src) + return + + add_hiddenprint(user) + +/// 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 + pass_flags_self = PASSGLASS + +/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.temperature = 293.15 + for(var/obj/effect/hotspot/fire in location) + qdel(fire) + + var/list/gases = air.gases + for(var/gas_type in gases) + switch(gas_type) + if(/datum/gas/oxygen, /datum/gas/nitrogen) + continue + else + gases[gas_type][MOLES] = 0 + air.garbage_collect() + + for(var/obj/machinery/atmospherics/components/unary/comp in location) + if(!comp.welded) + comp.welded = TRUE + comp.update_appearance() + comp.visible_message(span_danger("[comp] sealed shut!")) + + for(var/mob/living/potential_tinder in location) + potential_tinder.extinguish_mob() + 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 00000000000..320c2b5add1 --- /dev/null +++ b/code/game/objects/effects/effect_system/fluid_spread/effects_smoke.dm @@ -0,0 +1,438 @@ +/** + * 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 + plane = ABOVE_GAME_PLANE + 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 + +/obj/effect/particle_effect/fluid/smoke/Initialize(mapload, datum/fluid_group/group, ...) + . = ..() + create_reagents(1000) + setDir(pick(GLOB.cardinals)) + 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.get_atmos_adjacent_turfs()) + 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) + 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 + +/// 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), location = null, smoke_type = /obj/effect/particle_effect/fluid/smoke) + var/datum/effect_system/fluid_spread/smoke/smoke = new + smoke.effect_type = smoke_type + smoke.set_up(amount = amount, location = location) + smoke.start() + +///////////////////////////////////////////// +// 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, + ) + 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/old_loc, list/atom/old_locs) + SIGNAL_HANDLER + if(istype(arrived, /obj/projectile/beam)) + var/obj/projectile/beam/beam = arrived + beam.damage *= 0.5 + +/// 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.temperature = temperature + + var/list/gases = air.gases + if(gases[/datum/gas/plasma]) + air.assert_gas(/datum/gas/nitrogen) + gases[/datum/gas/nitrogen][MOLES] += gases[/datum/gas/plasma][MOLES] + gases[/datum/gas/plasma][MOLES] = 0 + air.garbage_collect() + + for(var/obj/effect/hotspot/fire in chilly) + qdel(fire) + chilly.air_update_turf(FALSE, FALSE) + + 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_appearance() + comp.visible_message(span_danger("[comp] is frozen shut!")) + + // Extinguishes everything in the turf + for(var/mob/living/potential_tinder in chilly) + potential_tinder.extinguish_mob() + 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/location, blast_radius = 0) + . = ..() + blast = blast_radius + +/datum/effect_system/fluid_spread/smoke/freezing/start() + 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.underfloor_accessibility < UNDERFLOOR_INTERACTABLE && HAS_TRAIT(thing, TRAIT_T_RAY_VISIBLE)) + continue + reagents.expose(thing, TOUCH, fraction) + + reagents.expose(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.expose(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/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)] " + if(!istype(carry.my_atom, /obj/machinery/plumbing)) + 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 + if(!istype(carry.my_atom, /obj/machinery/plumbing)) + 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() + 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 + 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/mines.dm b/code/game/objects/effects/mines.dm index 0faa180d74f..5221955196a 100644 --- a/code/game/objects/effects/mines.dm +++ b/code/game/objects/effects/mines.dm @@ -205,6 +205,6 @@ playsound(loc, 'sound/machines/chime.ogg', 30, FALSE, -3) var/obj/effect/mine/new_mine = new mine_type(get_turf(src)) visible_message(span_danger("\The [src] releases a puff of smoke, revealing \a [new_mine]!")) - var/obj/effect/particle_effect/smoke/poof = new (get_turf(src)) + var/obj/effect/particle_effect/fluid/smoke/poof = new (get_turf(src)) poof.lifetime = 3 qdel(src) diff --git a/code/game/objects/effects/step_triggers.dm b/code/game/objects/effects/step_triggers.dm index e1f83b002b9..821cba8c495 100644 --- a/code/game/objects/effects/step_triggers.dm +++ b/code/game/objects/effects/step_triggers.dm @@ -163,12 +163,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, 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, location = dest) s.start() uses-- diff --git a/code/game/objects/items/cigs_lighters.dm b/code/game/objects/items/cigs_lighters.dm index 10b19f187ca..f5745958ecb 100644 --- a/code/game/objects/items/cigs_lighters.dm +++ b/code/game/objects/items/cigs_lighters.dm @@ -1055,9 +1055,9 @@ CIGARETTE PACKETS ARE IN FANCY.DM //Time to start puffing those fat vapes, yo. COOLDOWN_START(src, drag_cooldown, dragtime) if(obj_flags & EMAGGED) - var/datum/effect_system/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() if(prob(5)) //small chance for the vape to break and deal damage if it's emagged playsound(get_turf(src), 'sound/effects/pop_expl.ogg', 50, FALSE) M.apply_damage(20, BURN, BODY_ZONE_HEAD) @@ -1069,8 +1069,8 @@ CIGARETTE PACKETS ARE IN FANCY.DM qdel(src) return else if(super) - 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() handle_reagents() diff --git a/code/game/objects/items/clown_items.dm b/code/game/objects/items/clown_items.dm index 4d1290eee0e..a87d15d3af0 100644 --- a/code/game/objects/items/clown_items.dm +++ b/code/game/objects/items/clown_items.dm @@ -100,7 +100,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) /** diff --git a/code/game/objects/items/food/burgers.dm b/code/game/objects/items/food/burgers.dm index 90fc6dee78d..363b74027d1 100644 --- a/code/game/objects/items/food/burgers.dm +++ b/code/game/objects/items/food/burgers.dm @@ -19,7 +19,7 @@ /obj/item/food/burger/plain/Initialize(mapload) . = ..() 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" @@ -428,8 +428,8 @@ /obj/item/food/burger/crazy/process(delta_time) // DIT EES HORRIBLE if(DT_PROB(2.5, delta_time)) - var/datum/effect_system/smoke_spread/bad/green/smoke = new - smoke.set_up(0, src) + var/datum/effect_system/fluid_spread/smoke/bad/green/smoke = new + smoke.set_up(0, location = src) smoke.start() // empty burger you can customize diff --git a/code/game/objects/items/grenades/smokebomb.dm b/code/game/objects/items/grenades/smokebomb.dm index 3184c0e9d35..6bb7ad0b19d 100644 --- a/code/game/objects/items/grenades/smokebomb.dm +++ b/code/game/objects/items/grenades/smokebomb.dm @@ -26,8 +26,8 @@ update_mob() playsound(src, 'sound/effects/smoke.ogg', 50, TRUE, -3) - var/datum/effect_system/smoke_spread/bad/smoke = new - smoke.set_up(4, src) + var/datum/effect_system/fluid_spread/smoke/bad/smoke = new + smoke.set_up(4, location = src) smoke.start() qdel(smoke) //And deleted again. Sad really. for(var/obj/structure/blob/blob in view(8, src)) diff --git a/code/game/objects/items/nitrium_crystals.dm b/code/game/objects/items/nitrium_crystals.dm index b81a96bca18..f40961e1326 100644 --- a/code/game/objects/items/nitrium_crystals.dm +++ b/code/game/objects/items/nitrium_crystals.dm @@ -7,12 +7,12 @@ /obj/item/nitrium_crystal/attack_self(mob/user) . = ..() - var/datum/effect_system/smoke_spread/chem/smoke = new + var/datum/effect_system/fluid_spread/smoke/chem/smoke = new var/turf/location = get_turf(src) create_reagents(5) reagents.add_reagent(/datum/reagent/nitrium_low_metabolization, 3) reagents.add_reagent(/datum/reagent/nitrium_high_metabolization, 2) smoke.attach(location) - smoke.set_up(reagents, cloud_size, location, silent = TRUE) + smoke.set_up(cloud_size, location = location, carry = reagents, silent = TRUE) smoke.start() qdel(src) diff --git a/code/game/objects/items/robot/robot_upgrades.dm b/code/game/objects/items/robot/robot_upgrades.dm index 9fe29d87639..90b70e89f8f 100644 --- a/code/game/objects/items/robot/robot_upgrades.dm +++ b/code/game/objects/items/robot/robot_upgrades.dm @@ -562,8 +562,8 @@ var/prev_lockcharge = R.lockcharge R.SetLockdown(TRUE) R.set_anchored(TRUE) - 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(2) for(var/i in 1 to 4) diff --git a/code/game/objects/items/scrolls.dm b/code/game/objects/items/scrolls.dm index c55f4def71c..108cb8c0e0c 100644 --- a/code/game/objects/items/scrolls.dm +++ b/code/game/objects/items/scrolls.dm @@ -50,8 +50,8 @@ return var/area/thearea = GLOB.teleportlocs[jump_target] - 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/possible_locations = list() diff --git a/code/game/objects/items/tanks/watertank.dm b/code/game/objects/items/tanks/watertank.dm index abd1e7a9a0c..29cf2d3a80d 100644 --- a/code/game/objects/items/tanks/watertank.dm +++ b/code/game/objects/items/tanks/watertank.dm @@ -324,12 +324,12 @@ balloon_alert(user, "too far!") 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)) balloon_alert(user, "already has resin!") return if(metal_synthesis_cooldown < 5) - 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 metal_synthesis_cooldown++ addtimer(CALLBACK(src, .proc/reduce_metal_synth_cooldown), 10 SECONDS) else @@ -363,8 +363,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,TRUE) qdel(src) diff --git a/code/game/objects/structures/hivebot.dm b/code/game/objects/structures/hivebot.dm index 493c7eabca0..c86748137e3 100644 --- a/code/game/objects/structures/hivebot.dm +++ b/code/game/objects/structures/hivebot.dm @@ -10,8 +10,8 @@ /obj/structure/hivebot_beacon/Initialize(mapload) . = ..() - 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, TRUE) diff --git a/code/game/objects/structures/lavaland/geyser.dm b/code/game/objects/structures/lavaland/geyser.dm index bfa9bcd80d0..cba7f2b01b9 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/game/objects/structures/watercloset.dm b/code/game/objects/structures/watercloset.dm index 32897631252..b615dc9874f 100644 --- a/code/game/objects/structures/watercloset.dm +++ b/code/game/objects/structures/watercloset.dm @@ -437,7 +437,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/urinal, 32) /obj/structure/sink/proc/begin_reclamation() if(!reclaiming) reclaiming = TRUE - START_PROCESSING(SSfluids, src) + START_PROCESSING(SSplumbing, src) /obj/structure/sink/kitchen name = "kitchen sink" diff --git a/code/modules/antagonists/_common/antag_spawner.dm b/code/modules/antagonists/_common/antag_spawner.dm index eedc2314789..b01a8551534 100644 --- a/code/modules/antagonists/_common/antag_spawner.dm +++ b/code/modules/antagonists/_common/antag_spawner.dm @@ -67,7 +67,7 @@ spawn_antag(student.client, get_turf(src), apprentice_school, teacher.mind) /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.safe_transfer_prefs_to(M, is_antag = TRUE) M.key = C.key diff --git a/code/modules/antagonists/blob/blob_mobs.dm b/code/modules/antagonists/blob/blob_mobs.dm index 457da47373f..44adf6483cc 100644 --- a/code/modules/antagonists/blob/blob_mobs.dm +++ b/code/modules/antagonists/blob/blob_mobs.dm @@ -198,7 +198,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/spores = new var/turf/location = get_turf(src) // Create the reagents to put into the air @@ -212,9 +212,9 @@ reagents.add_reagent(/datum/reagent/toxin/spore, 10) // Attach the smoke spreader and setup/start it. - S.attach(location) - S.set_up(reagents, death_cloud_size, location, silent = TRUE) - S.start() + spores.attach(location) + spores.set_up(death_cloud_size, location = location, carry = reagents, silent = TRUE) + spores.start() if(factory) factory.spore_delay = world.time + factory.spore_cooldown //put the factory on cooldown diff --git a/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm b/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm index a41eacdc3e3..9a44528380f 100644 --- a/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm +++ b/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm @@ -589,8 +589,8 @@ GLOBAL_VAR(station_nuke_source) 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() @@ -605,7 +605,7 @@ GLOBAL_VAR(station_nuke_source) var/datum/reagents/beer = new /datum/reagents(1000) beer.my_atom = vent beer.add_reagent(/datum/reagent/consumable/ethanol/beer, 100) - beer.create_foam(/datum/effect_system/foam_spread, 200) + beer.create_foam(/datum/effect_system/fluid_spread/foam, DIAMOND_AREA(10)) CHECK_TICK diff --git a/code/modules/awaymissions/mission_code/Academy.dm b/code/modules/awaymissions/mission_code/Academy.dm index cd32ccec532..fb303cd5aeb 100644 --- a/code/modules/awaymissions/mission_code/Academy.dm +++ b/code/modules/awaymissions/mission_code/Academy.dm @@ -284,7 +284,7 @@ //Cookie T.visible_message(span_userdanger("A cookie appears out of thin air!")) var/obj/item/food/cookie/C = new(drop_location()) - do_smoke(0, drop_location()) + do_smoke(DIAMOND_AREA(0), drop_location()) C.name = "Cookie of Fate" if(12) //Healing @@ -305,18 +305,18 @@ if(14) //Free Gun T.visible_message(span_userdanger("An impressive gun appears!")) - do_smoke(0, drop_location()) + do_smoke(DIAMOND_AREA(0), drop_location()) new /obj/item/gun/ballistic/revolver/mateba(drop_location()) if(15) //Random One-use spellbook T.visible_message(span_userdanger("A magical looking book drops to the floor!")) - do_smoke(0, drop_location()) + do_smoke(DIAMOND_AREA(0), drop_location()) new /obj/item/book/granter/spell/random(drop_location()) if(16) //Servant & Servant Summon T.visible_message(span_userdanger("A Dice Servant appears in a cloud of smoke!")) var/mob/living/carbon/human/H = new(drop_location()) - do_smoke(0, drop_location()) + do_smoke(DIAMOND_AREA(0), drop_location()) H.equipOutfit(/datum/outfit/butler) var/datum/mind/servant_mind = new /datum/mind() @@ -339,12 +339,12 @@ //Tator Kit T.visible_message(span_userdanger("A suspicious box appears!")) new /obj/item/storage/box/syndicate/bundle_a(drop_location()) - do_smoke(0, drop_location()) + do_smoke(DIAMOND_AREA(0), drop_location()) if(18) //Captain ID T.visible_message(span_userdanger("A golden identification card appears!")) new /obj/item/card/id/advanced/gold/captains_spare(drop_location()) - do_smoke(0, drop_location()) + do_smoke(DIAMOND_AREA(0), drop_location()) if(19) //Instrinct Resistance T.visible_message(span_userdanger("[user] looks very robust!")) diff --git a/code/modules/awaymissions/super_secret_room.dm b/code/modules/awaymissions/super_secret_room.dm index af9ee82a6ca..e04a268f6bc 100644 --- a/code/modules/awaymissions/super_secret_room.dm +++ b/code/modules/awaymissions/super_secret_room.dm @@ -29,8 +29,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/head/tophat.dm b/code/modules/clothing/head/tophat.dm index dd60bab0510..17aa72ea43f 100644 --- a/code/modules/clothing/head/tophat.dm +++ b/code/modules/clothing/head/tophat.dm @@ -22,7 +22,7 @@ COOLDOWN_START(src, rabbit_cooldown, RABBIT_CD_TIME) playsound(get_turf(src), 'sound/weapons/emitter.ogg', 70) - do_smoke(range=1, location=src, smoke_type=/obj/effect/particle_effect/smoke/quick) + do_smoke(amount = DIAMOND_AREA(1), location=src, smoke_type=/obj/effect/particle_effect/fluid/smoke/quick) if(prob(10)) magician.visible_message(span_danger("[magician] taps [src] with [hitby_wand], then reaches in and pulls out a bu- wait, those are bees!"), span_danger("You tap [src] with your [hitby_wand.name] and pull out... BEES!")) diff --git a/code/modules/clothing/under/jobs/Plasmaman/civilian_service.dm b/code/modules/clothing/under/jobs/Plasmaman/civilian_service.dm index c785574e6fb..9811ccf812c 100644 --- a/code/modules/clothing/under/jobs/Plasmaman/civilian_service.dm +++ b/code/modules/clothing/under/jobs/Plasmaman/civilian_service.dm @@ -132,4 +132,4 @@ extinguishes_left-- H.visible_message(span_warning("[H]'s suit spews space lube everywhere!"),span_warning("Your suit spews space lube everywhere!")) H.extinguish_mob() - new /obj/effect/particle_effect/foam(loc) //Truely terrifying. + new /obj/effect/particle_effect/fluid/foam(loc) //Truely terrifying. diff --git a/code/modules/events/immovable_rod.dm b/code/modules/events/immovable_rod.dm index b68dbead040..dce106ee6d1 100644 --- a/code/modules/events/immovable_rod.dm +++ b/code/modules/events/immovable_rod.dm @@ -211,8 +211,8 @@ In my current plan for it, 'solid' will be defined as anything with density == 1 // they ALSO collapse into a singulo. if(istype(clong, /obj/effect/immovablerod)) visible_message(span_danger("[src] collides with [clong]! This cannot end well.")) - var/datum/effect_system/smoke_spread/smoke = new - smoke.set_up(2, get_turf(src)) + var/datum/effect_system/fluid_spread/smoke/smoke = new + smoke.set_up(2, location = get_turf(src)) smoke.start() var/obj/singularity/bad_luck = new(get_turf(src)) bad_luck.energy = 800 diff --git a/code/modules/events/wisdomcow.dm b/code/modules/events/wisdomcow.dm index b12938b3f94..c04bb38f5e1 100644 --- a/code/modules/events/wisdomcow.dm +++ b/code/modules/events/wisdomcow.dm @@ -10,5 +10,5 @@ /datum/round_event/wisdomcow/start() var/turf/targetloc = get_safe_random_station_turf() new /mob/living/basic/cow/wisdom(targetloc) - do_smoke(1, targetloc) + do_smoke(DIAMOND_AREA(1), targetloc) diff --git a/code/modules/events/wizard/curseditems.dm b/code/modules/events/wizard/curseditems.dm index c3701c0908c..cdd44547d11 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 1a272265836..34bca08f3f9 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 c00917edd73..f8e37ee3a42 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/explorer_drone/exodrone.dm b/code/modules/explorer_drone/exodrone.dm index 3f28b312320..ff5fc05f40a 100644 --- a/code/modules/explorer_drone/exodrone.dm +++ b/code/modules/explorer_drone/exodrone.dm @@ -418,7 +418,7 @@ GLOBAL_LIST_EMPTY(exodrone_launchers) */ /obj/machinery/exodrone_launcher/proc/launch_effect() playsound(src,'sound/effects/podwoosh.ogg',50, FALSE) - do_smoke(1,get_turf(src)) + do_smoke(DIAMOND_AREA(1), get_turf(src)) /obj/machinery/exodrone_launcher/handle_atom_del(atom/A) if(A == fuel_canister) diff --git a/code/modules/food_and_drinks/kitchen_machinery/grill.dm b/code/modules/food_and_drinks/kitchen_machinery/grill.dm index e00492ad33f..78ef29110c7 100644 --- a/code/modules/food_and_drinks/kitchen_machinery/grill.dm +++ b/code/modules/food_and_drinks/kitchen_machinery/grill.dm @@ -85,8 +85,8 @@ else grill_fuel -= GRILL_FUELUSAGE_IDLE * delta_time 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, delta_time) diff --git a/code/modules/hydroponics/grown/onion.dm b/code/modules/hydroponics/grown/onion.dm index 25a046acd6d..93940e1a82c 100644 --- a/code/modules/hydroponics/grown/onion.dm +++ b/code/modules/hydroponics/grown/onion.dm @@ -50,12 +50,12 @@ AddElement(/datum/element/processable, TOOL_KNIFE, /obj/item/food/onion_slice/red, 2, 15) /obj/item/food/grown/onion/UsedforProcessing(mob/living/user, obj/item/I, list/chosen_option) - 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/cry_about_it = 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.start() - qdel(S) + cry_about_it.attach(splat_location) + cry_about_it.set_up(0, location = splat_location, carry = reagents, silent = FALSE) + cry_about_it.start() + qdel(cry_about_it) return ..() /obj/item/food/onion_slice diff --git a/code/modules/hydroponics/plant_genes.dm b/code/modules/hydroponics/plant_genes.dm index 5195978eef0..24a2ec57450 100644 --- a/code/modules/hydroponics/plant_genes.dm +++ b/code/modules/hydroponics/plant_genes.dm @@ -646,12 +646,12 @@ SIGNAL_HANDLER our_plant.investigate_log("made smoke at [AREACOORD(target)]. Last touched by: [our_plant.fingerprintslast].", INVESTIGATE_BOTANY) - var/datum/effect_system/smoke_spread/chem/smoke = new () + var/datum/effect_system/fluid_spread/smoke/chem/smoke = new () var/obj/item/seeds/our_seed = our_plant.get_plant_seed() var/splat_location = get_turf(target) - var/smoke_amount = round(sqrt(our_seed.potency * 0.1), 1) + var/range = sqrt(our_seed.potency * 0.1) smoke.attach(splat_location) - smoke.set_up(our_plant.reagents, smoke_amount, splat_location, 0) + smoke.set_up(round(range), location = splat_location, carry = our_plant.reagents, silent = FALSE) smoke.start() our_plant.reagents.clear_reagents() diff --git a/code/modules/mining/equipment/survival_pod.dm b/code/modules/mining/equipment/survival_pod.dm index 0baefc9041b..66b5a7cc465 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) //Non-default pods diff --git a/code/modules/mob/living/basic/farm_animals/cows.dm b/code/modules/mob/living/basic/farm_animals/cows.dm index e1960d2143e..2f66d4601cb 100644 --- a/code/modules/mob/living/basic/farm_animals/cows.dm +++ b/code/modules/mob/living/basic/farm_animals/cows.dm @@ -109,7 +109,7 @@ if(!stat && !user.combat_mode) to_chat(user, span_nicegreen("[src] whispers you some intense wisdoms and then disappears!")) user.mind?.adjust_experience(pick(GLOB.skill_types), 500) - do_smoke(1, get_turf(src)) + do_smoke(DIAMOND_AREA(1), get_turf(src)) qdel(src) return return ..() diff --git a/code/modules/mob/living/simple_animal/bot/cleanbot.dm b/code/modules/mob/living/simple_animal/bot/cleanbot.dm index 8395dc4fb09..98b583a4c1d 100644 --- a/code/modules/mob/living/simple_animal/bot/cleanbot.dm +++ b/code/modules/mob/living/simple_animal/bot/cleanbot.dm @@ -355,7 +355,7 @@ 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) + new /obj/effect/particle_effect/fluid/foam(loc) else ..() diff --git a/code/modules/mob/living/simple_animal/bot/firebot.dm b/code/modules/mob/living/simple_animal/bot/firebot.dm index 9ffc4680868..64a6510299c 100644 --- a/code/modules/mob/living/simple_animal/bot/firebot.dm +++ b/code/modules/mob/living/simple_animal/bot/firebot.dm @@ -267,7 +267,7 @@ /mob/living/simple_animal/bot/firebot/atmos_expose(datum/gas_mixture/air, exposed_temperature) if(COOLDOWN_FINISHED(src, foam_cooldown)) - new /obj/effect/particle_effect/foam/firefighting(loc) + new /obj/effect/particle_effect/fluid/foam/firefighting(loc) COOLDOWN_START(src, foam_cooldown, FOAM_INTERVAL) /mob/living/simple_animal/bot/firebot/proc/spray_water(atom/target, mob/user) diff --git a/code/modules/mob/living/simple_animal/bot/hygienebot.dm b/code/modules/mob/living/simple_animal/bot/hygienebot.dm index 41ef078a6ec..a1d9ab81793 100644 --- a/code/modules/mob/living/simple_animal/bot/hygienebot.dm +++ b/code/modules/mob/living/simple_animal/bot/hygienebot.dm @@ -53,7 +53,7 @@ ADD_TRAIT(src, TRAIT_SPRAY_PAINTABLE, INNATE_TRAIT) /mob/living/simple_animal/bot/hygienebot/explode() - new /obj/effect/particle_effect/foam(loc) + new /obj/effect/particle_effect/fluid/foam(loc) return ..() 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 9769cdd7b23..f4aa963e61f 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 @@ -230,8 +230,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, smoke_location) + var/datum/effect_system/fluid_spread/smoke/smoke = new + smoke.set_up(2, location = smoke_location) smoke.start() //The legionnaire's head. Basically the same as any legion head, but we have to tell our creator when we die so they can generate another head. 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 6bb9f05f2a2..0c9a4e569ad 100644 --- a/code/modules/mob/living/simple_animal/hostile/retaliate/clown.dm +++ b/code/modules/mob/living/simple_animal/hostile/retaliate/clown.dm @@ -65,7 +65,7 @@ response_disarm_continuous = "gently scoops and pours aside" response_disarm_simple = "gently scoop and pour 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/Initialize(mapload) . = ..() @@ -293,7 +293,7 @@ attack_verb_continuous = "steals the girlfriend of" attack_verb_simple = "steal 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" @@ -316,7 +316,7 @@ attack_verb_continuous = "ferociously mauls" attack_verb_simple = "ferociously maul" 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 @@ -339,7 +339,7 @@ attack_verb_simple = "act 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/mutant name = "Unknown" diff --git a/code/modules/mod/modules/modules_security.dm b/code/modules/mod/modules/modules_security.dm index 067735b092d..24076d99d1d 100644 --- a/code/modules/mod/modules/modules_security.dm +++ b/code/modules/mod/modules/modules_security.dm @@ -154,9 +154,10 @@ playsound(src, 'sound/effects/spray.ogg', 30, TRUE, -6) var/datum/reagents/capsaicin_holder = new(10) capsaicin_holder.add_reagent(/datum/reagent/consumable/condensedcapsaicin, 10) - var/datum/effect_system/smoke_spread/chem/quick/smoke = new - smoke.set_up(capsaicin_holder, 1, get_turf(src)) + var/datum/effect_system/fluid_spread/smoke/chem/quick/smoke = new + smoke.set_up(1, location = get_turf(src), carry = capsaicin_holder) smoke.start() + QDEL_NULL(capsaicin_holder) // Reagents have a ref to their holder which has a ref to them. No leaks please. /obj/item/mod/module/pepper_shoulders/proc/on_check_shields() SIGNAL_HANDLER diff --git a/code/modules/projectiles/guns/magic/wand.dm b/code/modules/projectiles/guns/magic/wand.dm index 228328629d4..67fca3ba646 100644 --- a/code/modules/projectiles/guns/magic/wand.dm +++ b/code/modules/projectiles/guns/magic/wand.dm @@ -169,8 +169,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-- ..() @@ -192,8 +192,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 070369cc580..252afe41300 100644 --- a/code/modules/projectiles/projectile/magic.dm +++ b/code/modules/projectiles/projectile/magic.dm @@ -77,8 +77,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/projectile/magic/safety @@ -98,8 +99,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/projectile/magic/door diff --git a/code/modules/reagents/chemistry/machinery/smoke_machine.dm b/code/modules/reagents/chemistry/machinery/smoke_machine.dm index e7a62c7c2df..f5cd71c5c02 100644 --- a/code/modules/reagents/chemistry/machinery/smoke_machine.dm +++ b/code/modules/reagents/chemistry/machinery/smoke_machine.dm @@ -10,7 +10,7 @@ circuit = /obj/item/circuitboard/machine/smoke_machine processing_flags = NONE - var/efficiency = 10 + var/efficiency = 20 var/on = FALSE var/cooldown = 0 var/screen = "home" @@ -18,17 +18,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(mapload) @@ -59,9 +61,9 @@ if(new_volume < reagents.total_volume) reagents.expose(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 @@ -80,12 +82,12 @@ on = FALSE update_appearance() 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_appearance() - 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() use_power(active_power_usage) diff --git a/code/modules/reagents/chemistry/reagents/pyrotechnic_reagents.dm b/code/modules/reagents/chemistry/reagents/pyrotechnic_reagents.dm index e745a777c4f..dd4d7fe633e 100644 --- a/code/modules/reagents/chemistry/reagents/pyrotechnic_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/pyrotechnic_reagents.dm @@ -371,7 +371,7 @@ return if(reac_volume >= 1) - var/obj/effect/particle_effect/foam/firefighting/foam = (locate(/obj/effect/particle_effect/foam) in exposed_turf) + 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)) diff --git a/code/modules/reagents/chemistry/recipes.dm b/code/modules/reagents/chemistry/recipes.dm index bc133b55a48..f17574d1f53 100644 --- a/code/modules/reagents/chemistry/recipes.dm +++ b/code/modules/reagents/chemistry/recipes.dm @@ -359,7 +359,7 @@ //Spews out the inverse of the chems in the beaker of the products/reactants only /datum/chemical_reaction/proc/explode_invert_smoke(datum/reagents/holder, datum/equilibrium/equilibrium, force_range = 0, clear_products = TRUE, clear_reactants = TRUE, accept_impure = TRUE) var/datum/reagents/invert_reagents = new (2100, NO_REACT)//I think the biggest size we can get is 2100? - var/datum/effect_system/smoke_spread/chem/smoke = new() + var/datum/effect_system/fluid_spread/smoke/chem/smoke = new() var/sum_volume = 0 invert_reagents.my_atom = holder.my_atom //Give the gas a fingerprint for(var/datum/reagent/reagent as anything in holder.reagent_list) //make gas for reagents, has to be done this way, otherwise it never stops Exploding @@ -379,7 +379,7 @@ if(!force_range) force_range = (sum_volume/6) + 3 if(invert_reagents.reagent_list) - smoke.set_up(invert_reagents, force_range, holder.my_atom) + smoke.set_up(force_range, location = holder.my_atom, carry = invert_reagents) smoke.start() holder.my_atom.audible_message("The [holder.my_atom] suddenly explodes, launching the aerosolized reagents into the air!") if(clear_reactants) @@ -390,7 +390,7 @@ //Spews out the corrisponding reactions reagents (products/required) of the beaker in a smokecloud. Doesn't spew catalysts /datum/chemical_reaction/proc/explode_smoke(datum/reagents/holder, datum/equilibrium/equilibrium, force_range = 0, clear_products = TRUE, clear_reactants = TRUE) var/datum/reagents/reagents = new/datum/reagents(2100, NO_REACT)//Lets be safe first - var/datum/effect_system/smoke_spread/chem/smoke = new() + var/datum/effect_system/fluid_spread/smoke/chem/smoke = new() reagents.my_atom = holder.my_atom //fingerprint var/sum_volume = 0 for (var/datum/reagent/reagent as anything in holder.reagent_list) @@ -400,7 +400,7 @@ if(!force_range) force_range = (sum_volume/6) + 3 if(reagents.reagent_list) - smoke.set_up(reagents, force_range, holder.my_atom) + smoke.set_up(force_range, location = holder.my_atom, carry = reagents) smoke.start() holder.my_atom.audible_message("The [holder.my_atom] suddenly explodes, launching the aerosolized reagents into the air!") if(clear_reactants) diff --git a/code/modules/reagents/chemistry/recipes/others.dm b/code/modules/reagents/chemistry/recipes/others.dm index 49e3b8ac06d..ac88ba89f78 100644 --- a/code/modules/reagents/chemistry/recipes/others.dm +++ b/code/modules/reagents/chemistry/recipes/others.dm @@ -328,7 +328,7 @@ reaction_flags = REACTION_INSTANT /datum/chemical_reaction/foam/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume) - holder.create_foam(/datum/effect_system/foam_spread,2*created_volume,notification=span_danger("The solution spews out foam!")) + holder.create_foam(/datum/effect_system/fluid_spread/foam, 2 * created_volume, notification = span_danger("The solution spews out foam!")) reaction_tags = REACTION_TAG_EASY | REACTION_TAG_UNIQUE /datum/chemical_reaction/metalfoam @@ -338,7 +338,7 @@ reaction_tags = REACTION_TAG_EASY | REACTION_TAG_UNIQUE /datum/chemical_reaction/metalfoam/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume) - holder.create_foam(/datum/effect_system/foam_spread/metal,5*created_volume,1,span_danger("The solution spews out a metallic foam!")) + 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 required_reagents = list(/datum/reagent/aluminium = 3, /datum/reagent/smart_foaming_agent = 1, /datum/reagent/toxin/acid/fluacid = 1) @@ -347,7 +347,7 @@ reaction_tags = REACTION_TAG_EASY | REACTION_TAG_UNIQUE /datum/chemical_reaction/smart_foam/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume) - holder.create_foam(/datum/effect_system/foam_spread/metal/smart,5*created_volume,1,span_danger("The solution spews out metallic foam!")) + 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 required_reagents = list(/datum/reagent/iron = 3, /datum/reagent/foaming_agent = 1, /datum/reagent/toxin/acid/fluacid = 1) @@ -356,7 +356,7 @@ reaction_tags = REACTION_TAG_EASY | REACTION_TAG_UNIQUE /datum/chemical_reaction/ironfoam/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume) - holder.create_foam(/datum/effect_system/foam_spread/metal,5*created_volume,2,span_danger("The solution spews out a metallic foam!")) + 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 results = list(/datum/reagent/foaming_agent = 1) diff --git a/code/modules/reagents/chemistry/recipes/pyrotechnics.dm b/code/modules/reagents/chemistry/recipes/pyrotechnics.dm index bc47036a636..7c5f4e80cc7 100644 --- a/code/modules/reagents/chemistry/recipes/pyrotechnics.dm +++ b/code/modules/reagents/chemistry/recipes/pyrotechnics.dm @@ -331,13 +331,12 @@ if(holder.has_reagent(/datum/reagent/stabilizing_agent)) return 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, TRUE, -3) if(S) - S.set_up(holder, smoke_radius, location, 0) + S.set_up(amount = created_volume * 3, location = location, carry = holder, silent = FALSE) S.start() if(holder?.my_atom) holder.clear_reagents() @@ -351,12 +350,11 @@ /datum/chemical_reaction/smoke_powder_smoke/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, 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, TRUE, -3) if(S) - S.set_up(holder, smoke_radius, location, 0) + S.set_up(amount = created_volume, location = location, carry = holder, silent = FALSE) S.start() if(holder?.my_atom) holder.clear_reagents() diff --git a/code/modules/reagents/chemistry/recipes/slime_extracts.dm b/code/modules/reagents/chemistry/recipes/slime_extracts.dm index 331a8431dac..49398f41bc2 100644 --- a/code/modules/reagents/chemistry/recipes/slime_extracts.dm +++ b/code/modules/reagents/chemistry/recipes/slime_extracts.dm @@ -190,7 +190,7 @@ required_other = TRUE /datum/chemical_reaction/slime/slimefoam/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume) - holder.create_foam(/datum/effect_system/foam_spread,80, span_danger("[src] spews out foam!")) + holder.create_foam(/datum/effect_system/fluid_spread/foam, 80, span_danger("[src] spews out foam!")) //Dark Blue /datum/chemical_reaction/slime/slimefreeze diff --git a/code/modules/research/experimentor.dm b/code/modules/research/experimentor.dm index 629333422dc..5266c89ad01 100644 --- a/code/modules/research/experimentor.dm +++ b/code/modules/research/experimentor.dm @@ -232,8 +232,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() @@ -305,27 +305,27 @@ else if(prob(EFFECT_PROB_VERYLOW-badThingCoeff)) 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, TRUE, -3) smoke.start() - qdel(R) + qdel(tmp_holder) ejectItem(TRUE) else if(prob(EFFECT_PROB_VERYLOW-badThingCoeff)) visible_message(span_danger("[src]'s chemical chamber has sprung a leak!")) chosenchem = pick(/datum/reagent/mutationtoxin/classic,/datum/reagent/cyborg_mutation_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, TRUE, -3) smoke.start() - qdel(R) + qdel(tmp_holder) ejectItem(TRUE) warn_admins(usr, "[chosenchem] smoke") investigate_log("Experimentor has released [chosenchem] smoke!", INVESTIGATE_EXPERIMENTOR) @@ -401,15 +401,15 @@ investigate_log("Experimentor has made a cup of [chosenchem] coffee.", INVESTIGATE_EXPERIMENTOR) else if(prob(EFFECT_PROB_VERYLOW-badThingCoeff)) 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, TRUE, -3) smoke.start() - qdel(R) + qdel(tmp_holder) ejectItem(TRUE) else if(prob(EFFECT_PROB_LOW-badThingCoeff)) visible_message(span_warning("[src] malfunctions, shattering [exp_on] and leaking cold air!")) @@ -427,8 +427,8 @@ ejectItem(TRUE) else if(prob(EFFECT_PROB_MEDIUM-badThingCoeff)) 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() //////////////////////////////////////////////////////////////////////////////////////////////// @@ -598,8 +598,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 5b364021dc2..80a856ce453 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/regen_jelly,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/vatgrowing/samples/_micro_organism.dm b/code/modules/research/xenobiology/vatgrowing/samples/_micro_organism.dm index b3d2b45f566..da1bf67c7ad 100644 --- a/code/modules/research/xenobiology/vatgrowing/samples/_micro_organism.dm +++ b/code/modules/research/xenobiology/vatgrowing/samples/_micro_organism.dm @@ -95,8 +95,8 @@ QDEL_NULL(vat.biological_sample) /datum/micro_organism/cell_line/proc/succeed_growing(obj/machinery/plumbing/growing_vat/vat) - var/datum/effect_system/smoke_spread/smoke = new - smoke.set_up(0, vat.loc) + var/datum/effect_system/fluid_spread/smoke/smoke = new + smoke.set_up(0, location = vat.loc) smoke.start() for(var/created_thing in resulting_atoms) for(var/x in 1 to resulting_atoms[created_thing]) diff --git a/code/modules/research/xenobiology/xenobiology.dm b/code/modules/research/xenobiology/xenobiology.dm index f34e1dba11c..e626ea76467 100644 --- a/code/modules/research/xenobiology/xenobiology.dm +++ b/code/modules/research/xenobiology/xenobiology.dm @@ -316,7 +316,7 @@ return 250 if(SLIME_ACTIVATE_MAJOR) - user.reagents.create_foam(/datum/effect_system/foam_spread,20) + 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 370dbbdd788..6188ec76be4 100644 --- a/code/modules/spells/spell.dm +++ b/code/modules/spells/spell.dm @@ -146,8 +146,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 @@ -340,19 +342,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 12c1c815357..35f9810e489 100644 --- a/code/modules/spells/spell_types/construct_spells.dm +++ b/code/modules/spells/spell_types/construct_spells.dm @@ -178,7 +178,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/wizard.dm b/code/modules/spells/spell_types/wizard.dm index e803bf74d74..2160c7a2991 100644 --- a/code/modules/spells/spell_types/wizard.dm +++ b/code/modules/spells/spell_types/wizard.dm @@ -62,7 +62,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" @@ -81,7 +81,7 @@ include_user = TRUE antimagic_flags = NONE // no cast restrictions - smoke_spread = 1 + smoke_spread = /datum/effect_system/fluid_spread/smoke smoke_amt = 2 action_icon_state = "smoke" @@ -115,7 +115,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 @@ -139,7 +139,7 @@ cooldown_min = 200 //100 deciseconds reduction per rank action_icon_state = "teleport" - 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/station_goals/bsa.dm b/code/modules/station_goals/bsa.dm index af2324a2608..f77b8d78fc1 100644 --- a/code/modules/station_goals/bsa.dm +++ b/code/modules/station_goals/bsa.dm @@ -350,9 +350,9 @@ GLOBAL_VAR_INIT(bsa_unlock, FALSE) 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_NULL(centerpiece.front_ref) QDEL_NULL(centerpiece.back_ref) diff --git a/code/modules/vehicles/atv.dm b/code/modules/vehicles/atv.dm index 86a5cd35320..88d9431e0d1 100644 --- a/code/modules/vehicles/atv.dm +++ b/code/modules/vehicles/atv.dm @@ -88,8 +88,8 @@ return PROCESS_KILL if(DT_PROB(10, delta_time)) return - var/datum/effect_system/smoke_spread/smoke = new - smoke.set_up(0, src) + var/datum/effect_system/fluid_spread/smoke/smoke = new + smoke.set_up(0, location = src) smoke.start() /obj/vehicle/ridden/atv/bullet_act(obj/projectile/P) diff --git a/code/modules/vehicles/cars/clowncar.dm b/code/modules/vehicles/cars/clowncar.dm index 2c68c55baf3..99322ba93ea 100644 --- a/code/modules/vehicles/cars/clowncar.dm +++ b/code/modules/vehicles/cars/clowncar.dm @@ -82,7 +82,7 @@ . = ..() if(prob(33)) visible_message(span_danger("[src] spews out a ton of space lube!")) - new /obj/effect/particle_effect/foam(loc) //YEET + new /obj/effect/particle_effect/fluid/foam(loc) //YEET /obj/vehicle/sealed/car/clowncar/attacked_by(obj/item/I, mob/living/user) . = ..() @@ -154,7 +154,7 @@ var/datum/reagents/randomchems = new/datum/reagents(300) randomchems.my_atom = src randomchems.add_reagent(get_random_reagent_id(), 100) - var/datum/effect_system/foam_spread/foam = new + var/datum/effect_system/fluid_spread/foam/foam = new foam.set_up(200, loc, randomchems) foam.start() if(3) @@ -167,8 +167,8 @@ var/datum/reagents/funnychems = new/datum/reagents(300) funnychems.my_atom = src funnychems.add_reagent(/datum/reagent/consumable/superlaughter, 50) - var/datum/effect_system/smoke_spread/chem/smoke = new() - smoke.set_up(funnychems, 4) + var/datum/effect_system/fluid_spread/smoke/chem/smoke = new() + smoke.set_up(4, location = src, carry = funnychems) smoke.attach(src) smoke.start() if(5) diff --git a/code/modules/vehicles/mecha/_mecha.dm b/code/modules/vehicles/mecha/_mecha.dm index b1c3cbbd6b3..bb9e4af3430 100644 --- a/code/modules/vehicles/mecha/_mecha.dm +++ b/code/modules/vehicles/mecha/_mecha.dm @@ -149,7 +149,7 @@ ///Safety for weapons. Won't fire if enabled, and toggled by middle click. var/weapons_safety = FALSE - var/datum/effect_system/smoke_spread/smoke_system = new + var/datum/effect_system/fluid_spread/smoke/smoke_system = new ////Action vars ///Ref to any active thrusters we might have @@ -209,7 +209,7 @@ 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) radio = new(src) diff --git a/code/modules/vehicles/mecha/equipment/tools/other_tools.dm b/code/modules/vehicles/mecha/equipment/tools/other_tools.dm index 276138e8b2d..0bdfc2b72f7 100644 --- a/code/modules/vehicles/mecha/equipment/tools/other_tools.dm +++ b/code/modules/vehicles/mecha/equipment/tools/other_tools.dm @@ -434,7 +434,7 @@ /obj/item/mecha_parts/mecha_equipment/thrusters/gas name = "RCS thruster package" desc = "A set of thrusters that allow for exosuit movement in zero-gravity environments, by expelling gas from the internal life support tank." - effect_type = /obj/effect/particle_effect/smoke + effect_type = /obj/effect/particle_effect/fluid/smoke var/move_cost = 20 //moles per step /obj/item/mecha_parts/mecha_equipment/thrusters/gas/try_attach_part(mob/user, obj/vehicle/sealed/mecha/M, attach_right = FALSE) diff --git a/code/modules/vehicles/secway.dm b/code/modules/vehicles/secway.dm index 55641607fd1..1a2e6472441 100644 --- a/code/modules/vehicles/secway.dm +++ b/code/modules/vehicles/secway.dm @@ -24,8 +24,8 @@ return PROCESS_KILL if(DT_PROB(10, delta_time)) return - var/datum/effect_system/smoke_spread/smoke = new - smoke.set_up(0, src) + var/datum/effect_system/fluid_spread/smoke/smoke = new + smoke.set_up(0, location = src) smoke.start() /obj/vehicle/ridden/secway/welder_act(mob/living/user, obj/item/I) diff --git a/tgstation.dme b/tgstation.dme index 13f14fa898a..dc8232e70dc 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -456,6 +456,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\id_access.dm" @@ -528,11 +529,11 @@ #include "code\controllers\subsystem\processing\clock_component.dm" #include "code\controllers\subsystem\processing\conveyors.dm" #include "code\controllers\subsystem\processing\fastprocess.dm" -#include "code\controllers\subsystem\processing\fluids.dm" #include "code\controllers\subsystem\processing\greyscale.dm" #include "code\controllers\subsystem\processing\instruments.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" @@ -1386,11 +1387,12 @@ #include "code\game\objects\effects\effect_system\effect_shield.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\costume.dm" #include "code\game\objects\effects\spawners\gibspawner.dm"