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"