diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm index 9a72196f8d..a3430383ef 100644 --- a/code/game/area/areas.dm +++ b/code/game/area/areas.dm @@ -43,7 +43,9 @@ var/no_air = null // var/list/lights // list of all lights on this area var/list/all_doors = null //Added by Strumpetplaya - Alarm Change - Contains a list of doors adjacent to this area + var/list/all_arfgs = null //Similar, but a list of all arfgs adjacent to this area var/firedoors_closed = 0 + var/arfgs_active = 0 var/list/ambience = list() var/list/forced_ambience = null var/sound_env = STANDARD_STATION @@ -128,10 +130,11 @@ return 1 return 0 -// Either close or open firedoors depending on current alert statuses +// Either close or open firedoors and arfgs depending on current alert statuses /area/proc/firedoors_update() if(fire || party || atmosalm) firedoors_close() + arfgs_activate() // VOREStation Edit - Make the lights colored! if(fire) for(var/obj/machinery/light/L in src) @@ -142,6 +145,7 @@ // VOREStation Edit End else firedoors_open() + arfgs_deactivate() // VOREStation Edit - Put the lights back! for(var/obj/machinery/light/L in src) L.reset_alert() @@ -175,6 +179,25 @@ spawn(0) E.open() +// Activate all retention fields! +/area/proc/arfgs_activate() + if(!arfgs_active) + arfgs_active = TRUE + if(!all_arfgs) + return + for(var/obj/machinery/atmospheric_field_generator/E in all_arfgs) + E.generate_field() //don't need to check powered state like doors, the arfgs handles it on its end + E.wasactive = TRUE + +// Deactivate retention fields! +/area/proc/arfgs_deactivate() + if(arfgs_active) + arfgs_active = FALSE + if(!all_arfgs) + return + for(var/obj/machinery/atmospheric_field_generator/E in all_arfgs) + E.disable_field() + E.wasactive = FALSE /area/proc/fire_alert() if(!fire) diff --git a/code/game/machinery/atm_ret_field.dm b/code/game/machinery/atm_ret_field.dm new file mode 100644 index 0000000000..9e9a2af168 --- /dev/null +++ b/code/game/machinery/atm_ret_field.dm @@ -0,0 +1,233 @@ +/obj/machinery/atmospheric_field_generator + name = "atmospheric retention field generator" + desc = "A floor-mounted piece of equipment that generates an atmosphere-retaining energy field when powered and activated. Linked to environmental alarm systems and will automatically activate when hazardous conditions are detected.

Note: prolonged immersion in active atmospheric retention fields may have negative long-term health consequences." + icon = 'icons/obj/atm_fieldgen.dmi' + icon_state = "arfg_off" + anchored = TRUE + opacity = FALSE + density = FALSE + power_channel = ENVIRON //so they shut off last + use_power = USE_POWER_IDLE + idle_power_usage = 10 + active_power_usage = 2500 + var/ispowered = TRUE + var/isactive = FALSE + var/wasactive = FALSE //controls automatic reboot after power-loss + var/alwaysactive = FALSE //for a special subtype + + //how long it takes us to reboot if we're shut down by an EMP + var/reboot_delay_min = 50 + var/reboot_delay_max = 75 + + var/hatch_open = FALSE + var/wires_intact = TRUE + var/list/areas_added + var/field_type = /obj/structure/atmospheric_retention_field + circuit = /obj/item/weapon/circuitboard/arf_generator + +/obj/machinery/atmospheric_field_generator/impassable + desc = "An older model of ARF-G that generates an impassable retention field. Works just as well as the modern variety, but is slightly more energy-efficient.

Note: prolonged immersion in active atmospheric retention fields may have negative long-term health consequences." + active_power_usage = 2000 + field_type = /obj/structure/atmospheric_retention_field/impassable + +/obj/machinery/atmospheric_field_generator/perma + name = "static atmospheric retention field generator" + desc = "A floor-mounted piece of equipment that generates an atmosphere-retaining energy field when powered and activated. This model is designed to always be active, though the field will still drop from loss of power or electromagnetic interference.

Note: prolonged immersion in active atmospheric retention fields may have negative long-term health consequences." + alwaysactive = TRUE + active_power_usage = 2000 + +/obj/machinery/atmospheric_field_generator/perma/impassable + active_power_usage = 1500 + field_type = /obj/structure/atmospheric_retention_field/impassable + +/obj/machinery/atmospheric_field_generator/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(W.is_crowbar() && isactive) + if(!src) return + to_chat(user, "You can't open the ARF-G whilst it's running!") + return + if(W.is_crowbar() && !isactive) + if(!src) return + to_chat(user, "You [hatch_open? "close" : "open"] \the [src]'s access hatch.") + hatch_open = !hatch_open + update_icon() + if(alwaysactive && wires_intact) + generate_field() + return + if(hatch_open && W.is_multitool()) + if(!src) return + to_chat(user, "You toggle \the [src]'s activation behavior to [alwaysactive? "emergency" : "always-on"].") + alwaysactive = !alwaysactive + update_icon() + return + if(hatch_open && W.is_wirecutter()) + if(!src) return + to_chat(user, "You [wires_intact? "cut" : "mend"] \the [src]'s wires!") + wires_intact = !wires_intact + update_icon() + return + if(hatch_open && istype(W,/obj/item/weapon/weldingtool)) + if(!src) return + var/obj/item/weapon/weldingtool/WT = W + if(!WT.isOn()) return + if(WT.get_fuel() < 5) // uses up 5 fuel. + to_chat(user, "You need more fuel to complete this task.") + return + user.visible_message("[user] starts to disassemble \the [src].", "You start to disassemble \the [src].") + playsound(src, WT.usesound, 50, 1) + if(do_after(user,15 * W.toolspeed)) + if(!src || !user || !WT.remove_fuel(5, user)) return + to_chat(user, "You fully disassemble \the [src]. There were no salvageable parts.") + qdel(src) + return + +/obj/machinery/atmospheric_field_generator/perma/Initialize() + generate_field() + +/obj/machinery/atmospheric_field_generator/update_icon() + if(stat & BROKEN) + icon_state = "arfg_broken" + else if(hatch_open && wires_intact) + icon_state = "arfg_open_wires" + else if(hatch_open && !wires_intact) + icon_state = "arfg_open_wirescut" + else if(isactive) + icon_state = "arfg_on" + else + icon_state = "arfg_off" + +/obj/machinery/atmospheric_field_generator/power_change() + var/oldstat + ..() + if(!(stat & NOPOWER)) + ispowered = 1 + update_icon() + if(alwaysactive || wasactive) //reboot our field if we were on or are supposed to be always-on + generate_field() + if(stat != oldstat && isactive && (stat & NOPOWER)) + ispowered = 0 + disable_field() + update_icon() + +/obj/machinery/atmospheric_field_generator/emp_act() + . = ..() + disable_field() //shutting dowwwwwwn + if(alwaysactive || wasactive) //reboot after a short delay if we were online before + spawn(rand(reboot_delay_min,reboot_delay_max)) + generate_field() + +/obj/machinery/atmospheric_field_generator/ex_act(severity) + switch(severity) + if(1) + disable_field() + qdel(src) + return + if(2) + stat |= BROKEN + update_icon() + src.visible_message("The ARF-G cracks and shatters!","You hear an uncomfortable metallic crunch.") + disable_field() + if(3) + emp_act() + return + +/obj/machinery/atmospheric_field_generator/proc/generate_field() + if(!ispowered || hatch_open || !wires_intact || isactive) //if it's not powered, the hatch is open, the wires are busted, or it's already on, don't do anything + return + else + isactive = 1 + icon_state = "arfg_on" + new field_type (src.loc) + src.visible_message("The ARF-G crackles to life!","You hear an ARF-G coming online!") + update_use_power(USE_POWER_ACTIVE) + return + +/obj/machinery/atmospheric_field_generator/proc/disable_field() + if(isactive) + icon_state = "arfg_off" + for(var/obj/structure/atmospheric_retention_field/F in loc) + qdel(F) + src.visible_message("The ARF-G shuts down with a low hum.","You hear an ARF-G powering down.") + update_use_power(USE_POWER_IDLE) + isactive = 0 + return + +/obj/machinery/atmospheric_field_generator/Initialize() + . = ..() + //Delete ourselves if we find extra mapped in arfgs + for(var/obj/machinery/atmospheric_field_generator/F in loc) + if(F != src) + log_debug("Duplicate ARFGS at [x],[y],[z]") + return INITIALIZE_HINT_QDEL + + var/area/A = get_area(src) + ASSERT(istype(A)) + + LAZYADD(A.all_arfgs, src) + areas_added = list(A) + + for(var/direction in cardinal) + A = get_area(get_step(src,direction)) + if(istype(A) && !(A in areas_added)) + LAZYADD(A.all_arfgs, src) + areas_added += A + +/obj/structure/atmospheric_retention_field + name = "atmospheric retention field" + desc = "A shimmering forcefield that keeps the good air inside and the bad air outside. This field has been modulated so that it doesn't impede movement or projectiles.

Note: prolonged immersion in active atmospheric retention fields may have negative long-term health consequences." + icon = 'icons/obj/atm_fieldgen.dmi' + icon_state = "arfg_field" + anchored = TRUE + density = FALSE + opacity = 0 + plane = MOB_PLANE + layer = ABOVE_MOB_LAYER + //mouse_opacity = 0 + can_atmos_pass = ATMOS_PASS_NO + var/basestate = "arfg_field" + + light_range = 3 + light_power = 1 + light_color = "#FFFFFF" + light_on = TRUE + +/obj/structure/atmospheric_retention_field/update_icon() + cut_overlays() //overlays.Cut() + var/list/dirs = list() + for(var/obj/structure/atmospheric_retention_field/F in orange(src,1)) + dirs += get_dir(src, F) + + var/list/connections = dirs_to_corner_states(dirs) + + icon_state = "" + for(var/i = 1 to 4) + var/image/I = image(icon, "[basestate][connections[i]]", dir = 1<<(i-1)) + add_overlay(I) + + return + +/obj/structure/atmospheric_retention_field/Initialize() + . = ..() + update_nearby_tiles() //Force ZAS update + update_connections(1) + update_icon() + +/obj/structure/atmospheric_retention_field/Destroy() + for(var/obj/structure/atmospheric_retention_field/W in orange(1, src.loc)) + W.update_connections(1) + update_nearby_tiles() //Force ZAS update + . = ..() + +/obj/structure/atmospheric_retention_field/attack_hand(mob/user as mob) + if(density) + visible_message("You touch the retention field, and it crackles faintly. Tingly!") + else + visible_message("You try to touch the retention field, but pass through it like it isn't even there.") + +/obj/structure/atmospheric_retention_field/ex_act() + return + +/obj/structure/atmospheric_retention_field/impassable + desc = "A shimmering forcefield that keeps the good air inside and the bad air outside. It seems fairly solid, almost like it's made out of some kind of hardened light.

Note: prolonged immersion in active atmospheric retention fields may have negative long-term health consequences." + icon = 'icons/obj/atm_fieldgen.dmi' + icon_state = "arfg_field" + density = TRUE \ No newline at end of file diff --git a/code/game/machinery/frame.dm b/code/game/machinery/frame.dm index ed4b086e73..d651ad2025 100644 --- a/code/game/machinery/frame.dm +++ b/code/game/machinery/frame.dm @@ -221,6 +221,11 @@ frame_style = FRAME_STYLE_WALL x_offset = 28 y_offset = 28 + +/datum/frame/frame_types/arfgs + name = "ARF Generator" + frame_class = FRAME_CLASS_MACHINE + frame_size = 3 ////////////////////////////// // Frame Object (Structure) diff --git a/code/game/objects/items/weapons/circuitboards/frame.dm b/code/game/objects/items/weapons/circuitboards/frame.dm index a3c755a3ac..db3106e635 100644 --- a/code/game/objects/items/weapons/circuitboards/frame.dm +++ b/code/game/objects/items/weapons/circuitboards/frame.dm @@ -261,3 +261,13 @@ /obj/item/weapon/stock_parts/spring = 1, /obj/item/stack/cable_coil = 5) +/obj/item/weapon/circuitboard/arf_generator + name = T_BOARD("atmospheric field generator") + build_path = /obj/machinery/atmospheric_field_generator + board_type = new /datum/frame/frame_types/arfgs + origin_tech = list(TECH_MAGNET = 4, TECH_POWER = 4, TECH_BIO = 3) + req_components = list( + /obj/item/weapon/stock_parts/micro_laser/high = 2, //field emitters + /obj/item/weapon/stock_parts/scanning_module = 1, //atmosphere sensor + /obj/item/weapon/stock_parts/capacitor/adv = 1, //for the JUICE + /obj/item/stack/cable_coil = 10) \ No newline at end of file diff --git a/code/modules/research/designs/circuits/circuits.dm b/code/modules/research/designs/circuits/circuits.dm index 5c77c19e60..9e21b9bc16 100644 --- a/code/modules/research/designs/circuits/circuits.dm +++ b/code/modules/research/designs/circuits/circuits.dm @@ -427,6 +427,13 @@ CIRCUITS BELOW build_path = /obj/item/weapon/circuitboard/skills sort_string = "LAAAC" +/datum/design/circuit/arf_generator + name = "atmospheric field generator" + id = "arf_generator" + req_tech = list(TECH_MAGNET = 4, TECH_POWER = 4, TECH_BIO = 3) + build_path = /obj/item/weapon/circuitboard/arf_generator + sort_string = "LAAAD" + /datum/design/circuit/mecha req_tech = list(TECH_DATA = 3) diff --git a/icons/obj/atm_fieldgen.dmi b/icons/obj/atm_fieldgen.dmi new file mode 100644 index 0000000000..0c30371196 Binary files /dev/null and b/icons/obj/atm_fieldgen.dmi differ diff --git a/icons/obj/stock_parts.dmi b/icons/obj/stock_parts.dmi index 64184432c7..1f203a1e8f 100644 Binary files a/icons/obj/stock_parts.dmi and b/icons/obj/stock_parts.dmi differ diff --git a/vorestation.dme b/vorestation.dme index bea44f2300..71d9cd9ede 100644 --- a/vorestation.dme +++ b/vorestation.dme @@ -831,7 +831,12 @@ #include "code\game\machinery\ai_slipper.dm" #include "code\game\machinery\air_alarm.dm" #include "code\game\machinery\airconditioner_vr.dm" +<<<<<<< HEAD #include "code\game\machinery\airconditioner_yw.dm" +||||||| parent of 3b5fb11bd1... Merge pull request #11663 from KillianKirilenko/kk-arfg +======= +#include "code\game\machinery\atm_ret_field.dm" +>>>>>>> 3b5fb11bd1... Merge pull request #11663 from KillianKirilenko/kk-arfg #include "code\game\machinery\atmo_control.dm" #include "code\game\machinery\autolathe.dm" #include "code\game\machinery\Beacon.dm"