From bfb9e8c132d3747ef5f38a028e2da9d52e21e25d Mon Sep 17 00:00:00 2001 From: Luc <89928798+lewcc@users.noreply.github.com> Date: Fri, 28 Jun 2024 13:39:26 -0700 Subject: [PATCH] Refactors Foam (#25436) * foam starts * foam fixes * foam foam foam * remove widefoam, get cleaning grenades working as they should * sirryan reeview * Apply suggestions from code review Co-authored-by: Matt <116982774+Burzah@users.noreply.github.com> Signed-off-by: Luc <89928798+lewcc@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: DGamerL <108773801+DGamerL@users.noreply.github.com> Signed-off-by: Luc <89928798+lewcc@users.noreply.github.com> * locs good to me * dgamer review --------- Signed-off-by: Luc <89928798+lewcc@users.noreply.github.com> Co-authored-by: Matt <116982774+Burzah@users.noreply.github.com> Co-authored-by: DGamerL <108773801+DGamerL@users.noreply.github.com> --- code/__DEFINES/misc_defines.dm | 15 +- .../effects/effect_system/effects_foam.dm | 287 +++++++++++------- .../objects/items/weapons/tanks/watertank.dm | 2 +- code/game/turfs/simulated/floor/plating.dm | 13 +- .../kitchen_machinery/deep_fryer.dm | 5 +- .../mod/modules/modules_engineering.dm | 2 +- .../reagents/chemistry/recipes/others.dm | 11 +- 7 files changed, 210 insertions(+), 125 deletions(-) diff --git a/code/__DEFINES/misc_defines.dm b/code/__DEFINES/misc_defines.dm index a63bc5a8673..27c6936d320 100644 --- a/code/__DEFINES/misc_defines.dm +++ b/code/__DEFINES/misc_defines.dm @@ -167,8 +167,19 @@ // Metal foam states // teehee no one will find these here -#define MFOAM_ALUMINUM 1 -#define MFOAM_IRON 2 +#define METAL_FOAM_ALUMINUM 1 +#define METAL_FOAM_IRON 2 + +// Defines for foam + +/// The chemicals in the foam (if any) will never react. +#define FOAM_REACT_NEVER (1<<0) +/// Chemicals in the foam will only react when the foam dissipates. +#define FOAM_REACT_ON_DISSIPATE (1<<1) +/// Chemicals in the foam will react while the foam is still processing. +#define FOAM_REACT_DURING_SPREAD (1<<2) +/// Chemicals in the foam will react when the foam first reaches a tile. +#define FOAM_REACT_BEFORE_SPREAD (1<<3) //Human Overlays Indexes///////// #define EYES_OVERLAY_LAYER 44 diff --git a/code/game/objects/effects/effect_system/effects_foam.dm b/code/game/objects/effects/effect_system/effects_foam.dm index e058c3c0efc..88c6793212d 100644 --- a/code/game/objects/effects/effect_system/effects_foam.dm +++ b/code/game/objects/effects/effect_system/effects_foam.dm @@ -7,79 +7,109 @@ icon_state = "foam" opacity = FALSE density = FALSE + gender = PLURAL layer = OBJ_LAYER + 0.9 animate_movement = NO_STEPS - var/amount = 3 - var/expand = 1 - var/metal = 0 + /// How many times this one bit of foam can spread around itself + var/spread_amount = 3 + /// How long it takes this to initially start spreading after being dispersed + var/spread_time = 0.9 SECONDS + /// How long it takes this, once it's spread, to stop spreading and disperse its chems + var/solidify_time = 12 SECONDS + /// Whether it reacts on or after dispersion (or both) + var/react_mode = FOAM_REACT_ON_DISSIPATE | FOAM_REACT_BEFORE_SPREAD + /// Maximum amount of reagents gained by spreading onto a foamed tile + var/max_amount_on_spread = 27 + /// We will never fill a mob with more than this many units of a given reagent + var/max_reagent_filling = 25 + /// Whether or not to spread at a range when spreading + var/spread_at_range = TRUE -/obj/effect/particle_effect/foam/New(loc, ismetal = FALSE) - ..(loc) - icon_state = "[ismetal ? "m":""]foam" - if(!ismetal && reagents) - color = mix_color_from_reagents(reagents.reagent_list) - metal = ismetal +/obj/effect/particle_effect/foam/Initialize(mapload) + . = ..() + create_reagents(25) playsound(src, 'sound/effects/bubbles2.ogg', 80, TRUE, -3) - spawn(3 + metal * 3) - process() - spawn(120) - STOP_PROCESSING(SSobj, src) - sleep(30) + addtimer(CALLBACK(src, PROC_REF(initial_process)), spread_time) - if(metal) - var/turf/T = get_turf(src) - if(isspaceturf(T) && !istype(T, /turf/space/transit)) - T.ChangeTurf(/turf/simulated/floor/plating/metalfoam) - var/turf/simulated/floor/plating/metalfoam/MF = get_turf(src) - MF.metal = metal - MF.update_icon() +/obj/effect/particle_effect/foam/proc/disperse_reagents() + if(!reagents) + return + reagents.handle_reactions() + for(var/atom/A in (spread_at_range ? oview(1, src) : view(0, src))) + if(A == src) + continue + fill_with_reagents(A) - var/obj/structure/foamedmetal/M = new(src.loc) - M.metal = metal - M.update_state() +/obj/effect/particle_effect/foam/proc/fill_with_reagents(atom/A) + if(reagents.total_volume) + var/fraction = 5 / reagents.total_volume + reagents.reaction(A, REAGENT_TOUCH, fraction) - flick("[icon_state]-disolve", src) - sleep(5) - qdel(src) - return + if(ismob(A) && !QDELETED(A)) + var/mob/M = A + for(var/reagent_id in reagents.reagent_list) + var/amount = M.reagents.get_reagent_amount(reagent_id) + if(amount < max_reagent_filling) + M.reagents.add_reagent(reagent_id, min(round(amount / 2), 15)) -// on delete, transfer any reagents to the floor -/obj/effect/particle_effect/foam/Destroy() - if(!metal && reagents) - reagents.handle_reactions() - for(var/atom/A in oview(1, src)) - if(A == src) - continue - if(reagents.total_volume) - var/fraction = 5 / reagents.total_volume - reagents.reaction(A, REAGENT_TOUCH, fraction) - return ..() +/obj/effect/particle_effect/foam/proc/initial_process() + process() + START_PROCESSING(SSobj, src) + addtimer(CALLBACK(src, PROC_REF(stop_processing)), solidify_time) + addtimer(CALLBACK(src, PROC_REF(dissipate)), solidify_time + 3 SECONDS) -/obj/effect/particle_effect/foam/process() - if(--amount < 0) +/obj/effect/particle_effect/foam/proc/stop_processing() + STOP_PROCESSING(SSobj, src) + +/obj/effect/particle_effect/foam/proc/dissipate() + + if(react_mode & FOAM_REACT_ON_DISSIPATE) + addtimer(CALLBACK(src, PROC_REF(disperse_reagents)), 0.3 SECONDS) + flick("[icon_state]-disolve", src) + QDEL_IN(src, 0.5 SECONDS) + +/obj/effect/particle_effect/foam/proc/try_spread_to(turf/target_turf) + if(!target_turf || !target_turf.Enter(src)) return + var/obj/effect/particle_effect/foam/new_foam = locate() in target_turf + + if(new_foam) + return + + new_foam = new type(target_turf) + new_foam.spread_amount = spread_amount + new_foam.spread_time = spread_time + new_foam.solidify_time = solidify_time + new_foam.max_amount_on_spread = max_amount_on_spread + new_foam.spread_at_range = spread_at_range + new_foam.react_mode = react_mode + new_foam.max_reagent_filling = max_reagent_filling + + // add the new amount of foam + if(reagents) + for(var/datum/reagent/R in reagents.reagent_list) + new_foam.reagents.add_reagent(R.id, min(R.volume, 5), R.data, reagents.chem_temp) + new_foam.color = mix_color_from_reagents(reagents.reagent_list) + if(react_mode & FOAM_REACT_BEFORE_SPREAD) + new_foam.disperse_reagents() + +/obj/effect/particle_effect/foam/proc/spread() for(var/direction in GLOB.cardinal) + var/turf/T = get_step(src, direction) + try_spread_to(T) - var/turf/T = get_step(src,direction) - if(!T) - continue +/obj/effect/particle_effect/foam/proc/generate_color() + color = mix_color_from_reagents(reagents.reagent_list) - if(!T.Enter(src)) - continue +/obj/effect/particle_effect/foam/process() + if(react_mode & FOAM_REACT_DURING_SPREAD) + disperse_reagents() - var/obj/effect/particle_effect/foam/F = locate() in T - if(F) - continue + if(--spread_amount < 0) + return - F = new /obj/effect/particle_effect/foam(T, metal) - F.amount = amount - if(!metal) - F.create_reagents(25) - if(reagents) - for(var/datum/reagent/R in reagents.reagent_list) - F.reagents.add_reagent(R.id, min(R.volume, 5), R.data, reagents.chem_temp) - F.color = mix_color_from_reagents(reagents.reagent_list) + spread() // foam disolves when heated // except metal foams @@ -87,79 +117,124 @@ return /obj/effect/particle_effect/foam/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume) // overriden to prevent weird behaviors with heating reagents inside - if(!metal && prob(max(0, exposed_temperature - 475))) + if(prob(max(0, exposed_temperature - 475))) flick("[icon_state]-disolve", src) - - spawn(5) - qdel(src) + QDEL_IN(src, 0.5 SECONDS) /obj/effect/particle_effect/foam/Crossed(atom/movable/AM, oldloc) - if(metal) + if(!iscarbon(AM)) return + var/mob/living/carbon/M = AM + if((M.slip("foam", 10 SECONDS) || IS_HORIZONTAL(M)) && reagents) + fill_with_reagents(M) - if(iscarbon(AM)) - var/mob/living/carbon/M = AM - if(M.slip("foam", 10 SECONDS)) - if(reagents) - for(var/reagent_id in reagents.reagent_list) - var/amount = M.reagents.get_reagent_amount(reagent_id) - if(amount < 25) - M.reagents.add_reagent(reagent_id, min(round(amount / 2), 15)) - if(reagents.total_volume) - var/fraction = 5 / reagents.total_volume - reagents.reaction(M, REAGENT_TOUCH, fraction) +/obj/effect/particle_effect/foam/metal + name = "metal foam" + icon_state = "mfoam" // finally mentor foam + spread_time = 1.2 SECONDS + react_mode = FOAM_REACT_ON_DISSIPATE + /// Represents the icon state that we'll become when we solidify + var/metal_kind = METAL_FOAM_ALUMINUM + +/obj/effect/particle_effect/foam/metal/generate_color() + return // metal foam is boring + +/obj/effect/particle_effect/foam/metal/disperse_reagents() + var/turf/T = get_turf(src) + if(isspaceturf(T) && !istype(T, /turf/space/transit)) + T.ChangeTurf(/turf/simulated/floor/plating/metalfoam) + var/turf/simulated/floor/plating/metalfoam/MF = get_turf(src) + MF.metal_kind = metal_kind + + var/obj/structure/foamedmetal/M = new(loc) + M.metal = metal_kind + M.update_state() + +/obj/effect/particle_effect/foam/metal/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume) + return + +/obj/effect/particle_effect/foam/metal/Crossed(atom/movable/AM, oldloc) + return /datum/effect_system/foam_spread effect_type = /obj/effect/particle_effect/foam - var/amount = 5 // the size of the foam spread. - var/list/carried_reagents // the IDs of reagents present when the foam was mixed - var/metal = 0 // 0=foam, 1=metalfoam, 2=ironfoam + /// the size of the foam spread. + var/spread_size = 5 + /// the IDs of reagents present when the foam was mixed + var/list/carried_reagents + /// the temperature that the reagents in the foam will be set to var/temperature = T0C + /// the reagents that we don't want in foam var/list/banned_reagents = list("smoke_powder", "fluorosurfactant", "stimulants") -/datum/effect_system/foam_spread/set_up(amt=5, loca, datum/reagents/carry = null, metalfoam = 0) - amount = min(round(amt/5, 1), 7) - if(isturf(loca)) - location = loca +/datum/effect_system/foam_spread/set_up(amt = 5, where, datum/reagents/carry) + spread_size = min(round(amt / 5, 1), 7) + if(isturf(where)) + location = where else - location = get_turf(loca) + location = get_turf(where) carried_reagents = list() - metal = metalfoam temperature = carry.chem_temp // bit of a hack here. Foam carries along any reagent also present in the glass it is mixed // with (defaults to water if none is present). Rather than actually transfer the reagents, // this makes a list of the reagent ids and spawns 1 unit of that reagent when the foam disolves. - if(carry && !metal) + if(carry) for(var/datum/reagent/R in carry.reagent_list) carried_reagents[R.id] = R.volume +/datum/effect_system/foam_spread/proc/setup_reagents(obj/effect/particle_effect/foam/working_foam) + if(!carried_reagents) + return + for(var/id in carried_reagents) + if(banned_reagents.Find("[id]")) + continue + var/datum/reagent/reagent_volume = carried_reagents[id] + working_foam.reagents.add_reagent(id, min(reagent_volume, 5), null, temperature) + working_foam.reagents.chem_temp = temperature + working_foam.color = mix_color_from_reagents(working_foam.reagents.reagent_list) + +/datum/effect_system/foam_spread/proc/spread() + var/obj/effect/particle_effect/foam/working_foam = locate() in location + if(working_foam) + working_foam.spread_amount = min(working_foam.spread_amount + working_foam.spread_amount, working_foam.max_amount_on_spread) + return + + working_foam = new effect_type(location) + working_foam.spread_amount = spread_size + setup_reagents(working_foam) + /datum/effect_system/foam_spread/start() - spawn(0) - var/obj/effect/particle_effect/foam/F = locate() in location - if(F) - F.amount += amount - F.amount = min(F.amount, 27) - return + INVOKE_ASYNC(src, PROC_REF(spread)) - F = new /obj/effect/particle_effect/foam(location, metal) - F.amount = amount +/datum/effect_system/foam_spread/cleaner - if(!metal) // don't carry other chemicals if a metal foam - F.create_reagents(25) +/datum/effect_system/foam_spread/cleaner/setup_reagents(obj/effect/particle_effect/foam/F) + F.react_mode = FOAM_REACT_ON_DISSIPATE + F.spread_at_range = TRUE + F.color = mix_color_from_reagents(F.reagents.reagent_list) - if(carried_reagents) - for(var/id in carried_reagents) - if(banned_reagents.Find("[id]")) - continue - var/datum/reagent/reagent_volume = carried_reagents[id] - F.reagents.add_reagent(id, min(reagent_volume, 5), null, temperature) - F.color = mix_color_from_reagents(F.reagents.reagent_list) - else - F.reagents.add_reagent("cleaner", 1) - F.color = mix_color_from_reagents(F.reagents.reagent_list) +/datum/effect_system/foam_spread/metal + /// The type of metal that will be formed from this + var/metal_type = METAL_FOAM_ALUMINUM + effect_type = /obj/effect/particle_effect/foam/metal + +/datum/effect_system/foam_spread/metal/set_up(amt, where, datum/reagents/carry, _metal_type = METAL_FOAM_ALUMINUM) + . = ..() + metal_type = _metal_type + +/datum/effect_system/foam_spread/metal/setup_reagents() + return + +/obj/effect/particle_effect/foam/oil + react_mode = FOAM_REACT_DURING_SPREAD | FOAM_REACT_ON_DISSIPATE + spread_at_range = FALSE + +/datum/effect_system/foam_spread/oil + effect_type = /obj/effect/particle_effect/foam/oil + temperature = 1000 // wall formed by metal foams // dense and opaque, but easy to break @@ -174,7 +249,7 @@ opacity = TRUE // changed in New() anchored = TRUE max_integrity = 20 - var/metal = MFOAM_ALUMINUM + var/metal = METAL_FOAM_ALUMINUM /obj/structure/foamedmetal/Initialize() . = ..() @@ -194,7 +269,7 @@ playsound(src.loc, 'sound/weapons/tap.ogg', 100, TRUE) /obj/structure/foamedmetal/proc/update_state() - if(metal == MFOAM_ALUMINUM) + if(metal == METAL_FOAM_ALUMINUM) max_integrity = 20 obj_integrity = max_integrity else @@ -203,7 +278,7 @@ update_icon(UPDATE_ICON_STATE) /obj/structure/foamedmetal/update_icon_state() - if(metal == MFOAM_ALUMINUM) + if(metal == METAL_FOAM_ALUMINUM) icon_state = "metalfoam" else icon_state = "ironfoam" diff --git a/code/game/objects/items/weapons/tanks/watertank.dm b/code/game/objects/items/weapons/tanks/watertank.dm index 5c2332fcf41..cfbd5e7f904 100644 --- a/code/game/objects/items/weapons/tanks/watertank.dm +++ b/code/game/objects/items/weapons/tanks/watertank.dm @@ -315,7 +315,7 @@ to_chat(user, "Metal foam mix is still being synthesized.") return var/obj/effect/particle_effect/foam/F = new /obj/effect/particle_effect/foam(get_turf(target), TRUE) - F.amount = 0 + F.spread_amount = 0 metal_synthesis_cooldown++ addtimer(CALLBACK(src, PROC_REF(metal_cooldown)), 10 SECONDS) diff --git a/code/game/turfs/simulated/floor/plating.dm b/code/game/turfs/simulated/floor/plating.dm index 89b4b6e48cd..37b500dc366 100644 --- a/code/game/turfs/simulated/floor/plating.dm +++ b/code/game/turfs/simulated/floor/plating.dm @@ -370,17 +370,18 @@ /turf/simulated/floor/plating/metalfoam name = "foamed metal plating" icon_state = "metalfoam" - var/metal = MFOAM_ALUMINUM + /// which kind of metal this will turn into + var/metal_kind = METAL_FOAM_ALUMINUM /turf/simulated/floor/plating/metalfoam/iron icon_state = "ironfoam" - metal = MFOAM_IRON + metal_kind = METAL_FOAM_IRON /turf/simulated/floor/plating/metalfoam/update_icon_state() - switch(metal) - if(MFOAM_ALUMINUM) + switch(metal_kind) + if(METAL_FOAM_ALUMINUM) icon_state = "metalfoam" - if(MFOAM_IRON) + if(METAL_FOAM_IRON) icon_state = "ironfoam" /turf/simulated/floor/plating/metalfoam/attackby(obj/item/C, mob/user, params) @@ -390,7 +391,7 @@ if(istype(C) && C.force) user.changeNext_move(CLICK_CD_MELEE) user.do_attack_animation(src) - var/smash_prob = max(0, C.force*17 - metal*25) // A crowbar will have a 60% chance of a breakthrough on alum, 35% on iron + var/smash_prob = max(0, C.force * 17 - metal_kind * 25) // A crowbar will have a 60% chance of a breakthrough on alum, 35% on iron if(prob(smash_prob)) // YAR BE CAUSIN A HULL BREACH visible_message("[user] smashes through \the [src] with \the [C]!") diff --git a/code/modules/food_and_drinks/kitchen_machinery/deep_fryer.dm b/code/modules/food_and_drinks/kitchen_machinery/deep_fryer.dm index 5bf7ef4f831..f7a1f86c807 100644 --- a/code/modules/food_and_drinks/kitchen_machinery/deep_fryer.dm +++ b/code/modules/food_and_drinks/kitchen_machinery/deep_fryer.dm @@ -118,10 +118,11 @@ create_reagents() // the cooking oil should spread through the foam. // when it gets added, it's at 1000 degrees so it quickly fireflashes and reacts to form inert cooking oil. - reagents.add_reagent("cooking_oil", ice_amount * 2, reagtemp = 1000) + reagents.add_reagent("cooking_oil", ice_amount * 2, reagtemp = 1000, no_react = TRUE) reagents.chem_temp = 1000 - var/datum/effect_system/foam_spread/S = new() + var/datum/effect_system/foam_spread/oil/S = new() S.set_up(ice_amount * 2, loc, reagents, FALSE) + S.temperature = 1000 S.start() diff --git a/code/modules/mod/modules/modules_engineering.dm b/code/modules/mod/modules/modules_engineering.dm index f02d8a9e029..82094de73c8 100644 --- a/code/modules/mod/modules/modules_engineering.dm +++ b/code/modules/mod/modules/modules_engineering.dm @@ -249,7 +249,7 @@ to_chat(user, "You need at least 10 units of water to use the metal foam synthesizer!") return var/obj/effect/particle_effect/foam/F = new/obj/effect/particle_effect/foam(get_turf(target), 1) - F.amount = 0 + F.spread_amount = 0 reagents.remove_any(10) metal_synthesis_charge-- addtimer(CALLBACK(src, PROC_REF(decrease_metal_charge)), 5 SECONDS) diff --git a/code/modules/reagents/chemistry/recipes/others.dm b/code/modules/reagents/chemistry/recipes/others.dm index 7bb6914aa8a..e60da3a4409 100644 --- a/code/modules/reagents/chemistry/recipes/others.dm +++ b/code/modules/reagents/chemistry/recipes/others.dm @@ -24,7 +24,6 @@ s.start() holder.clear_reagents() - /datum/chemical_reaction/metalfoam name = "Metal Foam" id = "metalfoam" @@ -37,11 +36,10 @@ holder.my_atom.visible_message("The solution spews out a metalic foam!") - var/datum/effect_system/foam_spread/s = new() - s.set_up(created_volume, location, holder, MFOAM_ALUMINUM) + var/datum/effect_system/foam_spread/metal/s = new() + s.set_up(created_volume, location, holder, METAL_FOAM_ALUMINUM) s.start() - /datum/chemical_reaction/ironfoam name = "Iron Foam" id = "ironlfoam" @@ -54,11 +52,10 @@ holder.my_atom.visible_message("The solution spews out a metalic foam!") - var/datum/effect_system/foam_spread/s = new() - s.set_up(created_volume, location, holder, MFOAM_IRON) + var/datum/effect_system/foam_spread/metal/s = new() + s.set_up(created_volume, location, holder, METAL_FOAM_IRON) s.start() - // Synthesizing these three chemicals is pretty complex in real life, but fuck it, it's just a game! /datum/chemical_reaction/ammonia name = "Ammonia"