mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-01-29 02:21:44 +00:00
* Refactors firestacks into status effects (#66573) This PR refactors firestacks into two status effects: fire_stacks, which behave like normal firestacks you have right now, and wet_stacks, which are your negative fire stacks right now. This allows for custom fires with custom behaviors and icons to be made. Some fire related is moved away from species(what the fuck was it even doing there) into these as well. Oh and I fixed the bug where monkeys on fire had a human fire overlay, why wasn't this fixed already, it's like ancient. Also changed some related proc names to be snake_case like everything should be. This allows for custom fire types with custom behaviours, like freezing freon fire or radioactive tritium fire. Removing vars from living and moving them to status effects for modularity is also good. Nothing to argue about since there's nothing player-facing * Hud Image Culling By Z Level: Theft edition (#65189) * makes hud images only apply by z level * makes some of the atom_hud procs have better names * fixes warning with the hud_user list and adds better documentation * better docs for hud_images * removes TODOs * docs for hud_list * adds support for linked z levels so mobs can see lower ones * fixes merge conflict and shittily makes only shocked airlocks get added * adds support for setting images in the hud as active and inactive * gets rid of unatomic spatial grid change * maybe i should actually try COMPILING my changes * fixes merge skew and makes it compile again * fixes huds refusing to remove from users who changed z level * improves z level and registration logic * fixes antag huds not appearing * Fixes antag huds not properly setting. We now use hud_list in init, so it needs to be set before the new call, not after. Not sure why the use of appearance key was split like this, but none else knows either so none can stop me * Ensures that hiding a basic appearance also hides the atom's active list too * Fixes antag huds going poof Ensures that remove_atom_from_hud will return false if the passed atom isn't managed by it This fixes antag huds disappearing randomly, since they assumed that if the parent call of remove_atom_from_hud returned true, we should delete ourselves. This is a safe assumption for them to make, since they should only ever have one atom. Does kinda bork if we call remove_atom_from_hud in a way that is unsure if the passed atom is actually in that list. We were forced into doing this by how atom huds use the qdeleting signal. * makes basic alternate_appearance's only update themselves when setting their hud image to active and makes them not add themselves to the global huds_by_category list * fixes mistake with hud_users list being set non associatively (bad) * as anything in bot path loops * Fixes merge skew problems * Makes bot paths non global This way they can show themselves to only the bot that "owns" them, ya feel me? * Fixes huds not showing up sometimes, cleans up some code Post Kapu's limb refactor, we were calling prepare_huds twice in a human init call chain. What was happening was this: call prepare_huds() // Human I gained a new hud image I set active hud icons to mirror it call prepare_huds() // Living I overwrote the new hud image I attempted to set active hud icons, which failed because it assumes this can never happen *cries* * Renames add_hud_to_atom to show_to My hope is this will make understanding hud code a bit easier, by tying the behavior to a "verb" more closely. Also renamed a few vars * remove_hud_from_mob -> hide_from * Nitpicks a few comments * Whoops/fuck/shit/damn it all/hhhhhhhhhhhh * Moves check down, improves stack trace a bit Co-authored-by: KylerAce <kylerlumpkin1@gmail.com> * small touch-up * this should do it Co-authored-by: SmArtKar <44720187+SmArtKar@users.noreply.github.com> Co-authored-by: LemonInTheDark <58055496+LemonInTheDark@users.noreply.github.com> Co-authored-by: KylerAce <kylerlumpkin1@gmail.com>
387 lines
11 KiB
Plaintext
387 lines
11 KiB
Plaintext
// 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
|