From e05b5c0bfb50e39569ea413435a5bf8f4f962054 Mon Sep 17 00:00:00 2001 From: Loganbacca Date: Mon, 14 Jul 2014 19:12:22 +1200 Subject: [PATCH] Pipe rendering rewrite - Complete rewrite of pipe rendering code. It now selects icons from a shared cache. - Manifolds and other devices (pumps, filters, etc.) now match the color of the connected pipes. - Updated omni devices to use the shared cache. - Set separate pipe color definitions. - Cleaned up a lot of pipe code, converting it to absolute paths and removing old commented out code. - Tweaked t-ray rendering code. - Tweaked pipe painter. - Enhanced pipe checking debug command. - Expanded tank capacity and resprited them. --- baystation12.dme | 1 + code/ATMOSPHERICS/_atmos_setup.dm | 200 ++++ code/ATMOSPHERICS/atmospherics.dm | 70 +- .../binary_devices/binary_atmos_base.dm | 4 + .../components/binary_devices/dp_vent_pump.dm | 296 +++--- .../components/binary_devices/passive_gate.dm | 275 +++--- .../components/binary_devices/pump.dm | 293 +++--- .../components/binary_devices/volume_pump.dm | 284 +++--- .../components/omni_devices/_omni_extras.dm | 37 - .../components/omni_devices/omni_base.dm | 55 +- .../components/portables_connector.dm | 231 +++-- .../components/trinary_devices/filter.dm | 280 +++--- .../components/trinary_devices/mixer.dm | 306 +++--- .../trinary_devices/trinary_base.dm | 5 + code/ATMOSPHERICS/components/tvalve.dm | 846 +++++++++-------- .../components/unary/outlet_injector.dm | 242 +++-- .../components/unary/unary_base.dm | 4 + .../components/unary/vent_pump.dm | 555 +++++------ .../components/unary/vent_scrubber.dm | 428 +++++---- code/ATMOSPHERICS/components/valve.dm | 566 ++++++----- code/ATMOSPHERICS/mapdebugging.dm | 16 - code/ATMOSPHERICS/pipes.dm | 884 +++++++++--------- code/game/machinery/pipe/construction.dm | 20 +- .../objects/items/devices/pipe_painter.dm | 17 +- code/game/objects/items/devices/scanners.dm | 2 + code/game/turfs/simulated/floor_types.dm | 3 +- code/modules/admin/verbs/atmosdebug.dm | 20 +- code/modules/recycling/disposal.dm | 4 +- icons/atmos/connector.dmi | Bin 0 -> 653 bytes icons/atmos/digital_tvalve.dmi | Bin 0 -> 2486 bytes icons/atmos/digital_valve.dmi | Bin 0 -> 3435 bytes icons/atmos/filter.dmi | Bin 0 -> 17954 bytes icons/atmos/injector.dmi | Bin 0 -> 939 bytes icons/atmos/manifold.dmi | Bin 0 -> 1097 bytes icons/atmos/mixer.dmi | Bin 0 -> 27952 bytes icons/atmos/omni_devices.dmi | Bin 0 -> 12175 bytes icons/atmos/passive_gate.dmi | Bin 0 -> 1052 bytes icons/atmos/pipe_underlays.dmi | Bin 0 -> 1070 bytes icons/atmos/pipes.dmi | Bin 0 -> 1433 bytes icons/atmos/pump.dmi | Bin 0 -> 1561 bytes icons/atmos/tank.dmi | Bin 0 -> 3062 bytes icons/atmos/tvalve.dmi | Bin 0 -> 2974 bytes icons/atmos/valve.dmi | Bin 0 -> 1544 bytes icons/atmos/vent_pump.dmi | Bin 0 -> 36930 bytes icons/atmos/vent_scrubber.dmi | Bin 0 -> 1328 bytes icons/atmos/volume_pump.dmi | Bin 0 -> 4062 bytes icons/obj/atmospherics/omni_devices.dmi | Bin 12990 -> 13197 bytes 47 files changed, 3137 insertions(+), 2807 deletions(-) create mode 100644 code/ATMOSPHERICS/_atmos_setup.dm delete mode 100644 code/ATMOSPHERICS/mapdebugging.dm create mode 100644 icons/atmos/connector.dmi create mode 100644 icons/atmos/digital_tvalve.dmi create mode 100644 icons/atmos/digital_valve.dmi create mode 100644 icons/atmos/filter.dmi create mode 100644 icons/atmos/injector.dmi create mode 100644 icons/atmos/manifold.dmi create mode 100644 icons/atmos/mixer.dmi create mode 100644 icons/atmos/omni_devices.dmi create mode 100644 icons/atmos/passive_gate.dmi create mode 100644 icons/atmos/pipe_underlays.dmi create mode 100644 icons/atmos/pipes.dmi create mode 100644 icons/atmos/pump.dmi create mode 100644 icons/atmos/tank.dmi create mode 100644 icons/atmos/tvalve.dmi create mode 100644 icons/atmos/valve.dmi create mode 100644 icons/atmos/vent_pump.dmi create mode 100644 icons/atmos/vent_scrubber.dmi create mode 100644 icons/atmos/volume_pump.dmi diff --git a/baystation12.dme b/baystation12.dme index 47496fac7b..a0495f8487 100644 --- a/baystation12.dme +++ b/baystation12.dme @@ -48,6 +48,7 @@ #include "code\_onclick\hud\other_mobs.dm" #include "code\_onclick\hud\robot.dm" #include "code\_onclick\hud\screen_objects.dm" +#include "code\ATMOSPHERICS\_atmos_setup.dm" #include "code\ATMOSPHERICS\atmospherics.dm" #include "code\ATMOSPHERICS\datum_pipe_network.dm" #include "code\ATMOSPHERICS\datum_pipeline.dm" diff --git a/code/ATMOSPHERICS/_atmos_setup.dm b/code/ATMOSPHERICS/_atmos_setup.dm new file mode 100644 index 0000000000..a34d372c59 --- /dev/null +++ b/code/ATMOSPHERICS/_atmos_setup.dm @@ -0,0 +1,200 @@ +//-------------------------------------------- +// Pipe colors +// +// Add them here and to the pipe_colors list +// to automatically add them to all relevant +// atmospherics devices. +//-------------------------------------------- + +#define PIPE_COLOR_GREY "#ffffff" //yes white is grey +#define PIPE_COLOR_RED "#ff0000" +#define PIPE_COLOR_BLUE "#0000ff" +#define PIPE_COLOR_CYAN "#00ffff" +#define PIPE_COLOR_GREEN "#00ff00" +#define PIPE_COLOR_YELLOW "#ffcc00" +#define PIPE_COLOR_PURPLE "#5c1ec0" + +var/global/list/pipe_colors = list("grey" = PIPE_COLOR_GREY, "red" = PIPE_COLOR_RED, "blue" = PIPE_COLOR_BLUE, "cyan" = PIPE_COLOR_CYAN, "green" = PIPE_COLOR_GREEN, "yellow" = PIPE_COLOR_YELLOW, "purple" = PIPE_COLOR_PURPLE) + +/proc/pipe_color_lookup(var/color) + for(var/C in pipe_colors) + if(color == pipe_colors[C]) + return "[C]" + +/proc/pipe_color_check(var/color) + for(var/C in pipe_colors) + if(color == pipe_colors[C]) + return 1 + return 0 + +//-------------------------------------------- +// Icon cache generation +//-------------------------------------------- + +/datum/pipe_icon_manager + var/list/pipe_icons[] + var/list/manifold_icons[] + var/list/device_icons[] + var/list/underlays_down[] + var/list/underlays_exposed[] + var/list/underlays_intact[] + var/list/pipe_underlays_exposed[] + var/list/pipe_underlays_intact[] + var/list/omni_icons[] + +/datum/pipe_icon_manager/New() + check_icons() + +/datum/pipe_icon_manager/proc/get_atmos_icon(var/device, var/dir, var/color, var/state) + check_icons() + + device = "[device]" + state = "[state]" + color = "[color]" + dir = "[dir]" + + switch(device) + if("pipe") + return pipe_icons[state + color] + if("manifold") + return manifold_icons[state + color] + if("device") + return device_icons[state] + if("omni") + return omni_icons[state] + if("underlay_intact") + return underlays_intact[dir + color] + if("underlay_exposed") + return underlays_exposed[dir + color] + if("underlay_down") + return underlays_down[dir + color] + if("pipe_underlay_exposed") + return pipe_underlays_exposed[dir + color] + if("pipe_underlay_intact") + return pipe_underlays_intact[dir + color] + +/datum/pipe_icon_manager/proc/check_icons() + if(!pipe_icons) + gen_pipe_icons() + if(!manifold_icons) + gen_manifold_icons() + if(!device_icons) + gen_device_icons() + if(!omni_icons) + gen_omni_icons() + if(!underlays_intact || !underlays_down || !underlays_exposed || !pipe_underlays_exposed || !pipe_underlays_intact) + gen_underlay_icons() + +/datum/pipe_icon_manager/proc/gen_pipe_icons() + if(!pipe_icons) + pipe_icons = new() + + var/icon/pipe = new('icons/atmos/pipes.dmi') + + for(var/state in pipe.IconStates()) + if(!state || findtext(state, "map")) + continue + + var/cache_name = state + var/image/I = image('icons/atmos/pipes.dmi', icon_state = state) + pipe_icons[cache_name] = I + + for(var/pipe_color in pipe_colors) + I = image('icons/atmos/pipes.dmi', icon_state = state) + I.color = pipe_colors[pipe_color] + pipe_icons[state + "[pipe_colors[pipe_color]]"] = I + +/datum/pipe_icon_manager/proc/gen_manifold_icons() + if(!manifold_icons) + manifold_icons = new() + + var/icon/pipe = new('icons/atmos/manifold.dmi') + + for(var/state in pipe.IconStates()) + if(findtext(state, "clamps")) + var/image/I = image('icons/atmos/manifold.dmi', icon_state = state) + manifold_icons[state] = I + continue + + if(state == "core" || state == "4way") + var/image/I = image('icons/atmos/manifold.dmi', icon_state = state) + manifold_icons[state] = I + for(var/pipe_color in pipe_colors) + I = image('icons/atmos/manifold.dmi', icon_state = state) + I.color = pipe_colors[pipe_color] + manifold_icons[state + pipe_colors[pipe_color]] = I + +/datum/pipe_icon_manager/proc/gen_device_icons() + if(!device_icons) + device_icons = new() + + var/icon/device + + device = new('icons/atmos/vent_pump.dmi') + for(var/state in device.IconStates()) + if(!state || findtext(state, "map")) + continue + device_icons["vent" + state] = image('icons/atmos/vent_pump.dmi', icon_state = state) + + device = new('icons/atmos/vent_scrubber.dmi') + for(var/state in device.IconStates()) + if(!state || findtext(state, "map")) + continue + device_icons["scrubber" + state] = image('icons/atmos/vent_scrubber.dmi', icon_state = state) + +/datum/pipe_icon_manager/proc/gen_omni_icons() + if(!omni_icons) + omni_icons = new() + + var/icon/omni = new('icons/atmos/omni_devices.dmi') + + for(var/state in omni.IconStates()) + if(!state || findtext(state, "map")) + continue + omni_icons[state] = image('icons/atmos/omni_devices.dmi', icon_state = state) + +/datum/pipe_icon_manager/proc/gen_underlay_icons() + if(!underlays_intact) + underlays_intact = new() + if(!underlays_exposed) + underlays_exposed = new() + if(!underlays_down) + underlays_down = new() + if(!pipe_underlays_exposed) + pipe_underlays_exposed = new() + if(!pipe_underlays_intact) + pipe_underlays_intact = new() + + var/icon/pipe = new('icons/atmos/pipe_underlays.dmi') + + for(var/state in pipe.IconStates()) + if(state == "") + continue + + for(var/D in cardinal) + var/image/I = image('icons/atmos/pipe_underlays.dmi', icon_state = state, dir = D) + switch(state) + if("intact") + underlays_intact["[D]"] = I + if("exposed") + underlays_exposed["[D]"] = I + if("down") + underlays_down["[D]"] = I + if("pipe_exposed") + pipe_underlays_exposed["[D]"] = I + if("pipe_intact") + pipe_underlays_intact["[D]"] = I + for(var/pipe_color in pipe_colors) + I = image('icons/atmos/pipe_underlays.dmi', icon_state = state, dir = D) + I.color = pipe_colors[pipe_color] + switch(state) + if("intact") + underlays_intact["[D]" + pipe_colors[pipe_color]] = I + if("exposed") + underlays_exposed["[D]" + pipe_colors[pipe_color]] = I + if("down") + underlays_down["[D]" + pipe_colors[pipe_color]] = I + if("pipe_exposed") + pipe_underlays_exposed["[D]" + pipe_colors[pipe_color]] = I + if("pipe_intact") + pipe_underlays_intact["[D]" + pipe_colors[pipe_color]] = I \ No newline at end of file diff --git a/code/ATMOSPHERICS/atmospherics.dm b/code/ATMOSPHERICS/atmospherics.dm index 1b89db43be..d652aed9d9 100644 --- a/code/ATMOSPHERICS/atmospherics.dm +++ b/code/ATMOSPHERICS/atmospherics.dm @@ -10,48 +10,96 @@ Pipelines + Other Objects -> Pipe network */ -obj/machinery/atmospherics +/obj/machinery/atmospherics anchored = 1 idle_power_usage = 0 active_power_usage = 0 power_channel = ENVIRON var/nodealert = 0 + var/initialize_directions = 0 + var/pipe_color + + var/global/datum/pipe_icon_manager/icon_manager +/obj/machinery/atmospherics/New() + if(!icon_manager) + icon_manager = new() + + if(!pipe_color) + pipe_color = color + color = null + + if(!pipe_color_check(pipe_color)) + pipe_color = null + ..() -obj/machinery/atmospherics/var/initialize_directions = 0 -obj/machinery/atmospherics/var/pipe_color +/obj/machinery/atmospherics/attackby(atom/A, mob/user as mob) + if(istype(A, /obj/item/device/pipe_painter)) + return + ..() -obj/machinery/atmospherics/process() +/obj/machinery/atmospherics/proc/add_underlay(var/turf/T, var/obj/machinery/atmospherics/node, var/direction) + if(node) + if(T.intact && node.level == 1 && istype(node, /obj/machinery/atmospherics/pipe)) + underlays += icon_manager.get_atmos_icon("underlay_down", direction, color_cache_name(node)) + else + underlays += icon_manager.get_atmos_icon("underlay_intact", direction, color_cache_name(node)) + else + underlays += icon_manager.get_atmos_icon("underlay_exposed", direction, pipe_color) + +/obj/machinery/atmospherics/proc/update_underlays() + if(check_icon_cache()) + return 1 + else + return 0 + +/obj/machinery/atmospherics/proc/check_icon_cache(var/safety = 0) + if(!istype(icon_manager)) + if(!safety) //to prevent infinite loops + icon_manager = new() + check_icon_cache(1) + return 0 + + return 1 + +/obj/machinery/atmospherics/proc/color_cache_name(var/obj/machinery/atmospherics/node) + //Don't use this for standard pipes + if(!istype(node)) + return null + + return node.pipe_color + +/obj/machinery/atmospherics/process() build_network() -obj/machinery/atmospherics/proc/network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference) +/obj/machinery/atmospherics/proc/network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference) // Check to see if should be added to network. Add self if so and adjust variables appropriately. // Note don't forget to have neighbors look as well! return null -obj/machinery/atmospherics/proc/build_network() +/obj/machinery/atmospherics/proc/build_network() // Called to build a network from this node return null -obj/machinery/atmospherics/proc/return_network(obj/machinery/atmospherics/reference) +/obj/machinery/atmospherics/proc/return_network(obj/machinery/atmospherics/reference) // Returns pipe_network associated with connection to reference // Notes: should create network if necessary // Should never return null return null -obj/machinery/atmospherics/proc/reassign_network(datum/pipe_network/old_network, datum/pipe_network/new_network) +/obj/machinery/atmospherics/proc/reassign_network(datum/pipe_network/old_network, datum/pipe_network/new_network) // Used when two pipe_networks are combining -obj/machinery/atmospherics/proc/return_network_air(datum/network/reference) +/obj/machinery/atmospherics/proc/return_network_air(datum/network/reference) // Return a list of gas_mixture(s) in the object // associated with reference pipe_network for use in rebuilding the networks gases list // Is permitted to return null -obj/machinery/atmospherics/proc/disconnect(obj/machinery/atmospherics/reference) +/obj/machinery/atmospherics/proc/disconnect(obj/machinery/atmospherics/reference) -obj/machinery/atmospherics/update_icon() +/obj/machinery/atmospherics/update_icon() return null \ No newline at end of file diff --git a/code/ATMOSPHERICS/components/binary_devices/binary_atmos_base.dm b/code/ATMOSPHERICS/components/binary_devices/binary_atmos_base.dm index 9d2a8e32e8..52f57b2958 100644 --- a/code/ATMOSPHERICS/components/binary_devices/binary_atmos_base.dm +++ b/code/ATMOSPHERICS/components/binary_devices/binary_atmos_base.dm @@ -76,6 +76,7 @@ obj/machinery/atmospherics/binary break update_icon() + update_underlays() build_network() if(!network1 && node1) @@ -127,4 +128,7 @@ obj/machinery/atmospherics/binary del(network2) node2 = null + update_icon() + update_underlays() + return null \ No newline at end of file diff --git a/code/ATMOSPHERICS/components/binary_devices/dp_vent_pump.dm b/code/ATMOSPHERICS/components/binary_devices/dp_vent_pump.dm index ac451871dc..6a21d08245 100644 --- a/code/ATMOSPHERICS/components/binary_devices/dp_vent_pump.dm +++ b/code/ATMOSPHERICS/components/binary_devices/dp_vent_pump.dm @@ -1,6 +1,6 @@ /obj/machinery/atmospherics/binary/dp_vent_pump - icon = 'icons/obj/atmospherics/dp_vent_pump.dmi' - icon_state = "off" + icon = 'icons/atmos/vent_pump.dmi' + icon_state = "map_dp_vent" //node2 is output port //node1 is input port @@ -10,15 +10,6 @@ level = 1 - high_volume - name = "Large Dual Port Air Vent" - - New() - ..() - - air1.volume = 1000 - air2.volume = 1000 - var/on = 0 var/pump_direction = 1 //0 = siphoning, 1 = releasing @@ -26,174 +17,199 @@ var/input_pressure_min = 0 var/output_pressure_max = 0 + var/frequency = 0 + var/id = null + var/datum/radio_frequency/radio_connection + var/pressure_checks = 1 //1: Do not pass external_pressure_bound //2: Do not pass input_pressure_min //4: Do not pass output_pressure_max +/obj/machinery/atmospherics/binary/dp_vent_pump/New() + ..() + icon = null + +/obj/machinery/atmospherics/binary/dp_vent_pump/high_volume + name = "Large Dual Port Air Vent" + +/obj/machinery/atmospherics/binary/dp_vent_pump/high_volume/New() + ..() + air1.volume = 1000 + air2.volume = 1000 + +/obj/machinery/atmospherics/binary/dp_vent_pump/update_icon(var/safety = 0) + if(!check_icon_cache()) + return + + overlays.Cut() + + var/vent_icon = "vent" + + var/turf/T = get_turf(src) + if(!istype(T)) + return + + if(T.intact && node1 && node2 && node1.level == 1 && node2.level == 1 && istype(node1, /obj/machinery/atmospherics/pipe) && istype(node2, /obj/machinery/atmospherics/pipe)) + vent_icon += "h" + + if(!powered()) + vent_icon += "off" + else + vent_icon += "[on ? "[pump_direction ? "out" : "in"]" : "off"]" + + overlays += icon_manager.get_atmos_icon("device", , , vent_icon) + +/obj/machinery/atmospherics/binary/dp_vent_pump/update_underlays() + if(..()) + underlays.Cut() + var/turf/T = get_turf(src) + if(!istype(T)) + return + if(T.intact && node1 && node2 && node1.level == 1 && node2.level == 1 && istype(node1, /obj/machinery/atmospherics/pipe) && istype(node2, /obj/machinery/atmospherics/pipe)) + return + else + add_underlay(T, node1, turn(dir, -180)) + add_underlay(T, node2, dir) + +/obj/machinery/atmospherics/binary/dp_vent_pump/hide(var/i) update_icon() - if(on) - if(pump_direction) - icon_state = "[level == 1 && istype(loc, /turf/simulated) ? "h" : "" ]out" - else - icon_state = "[level == 1 && istype(loc, /turf/simulated) ? "h" : "" ]in" - else - icon_state = "[level == 1 && istype(loc, /turf/simulated) ? "h" : "" ]off" - on = 0 + update_underlays() - return +/obj/machinery/atmospherics/binary/dp_vent_pump/process() + ..() - hide(var/i) //to make the little pipe section invisible, the icon changes. - if(on) - if(pump_direction) - icon_state = "[i == 1 && istype(loc, /turf/simulated) ? "h" : "" ]out" - else - icon_state = "[i == 1 && istype(loc, /turf/simulated) ? "h" : "" ]in" - else - icon_state = "[i == 1 && istype(loc, /turf/simulated) ? "h" : "" ]off" - on = 0 - return + if(!on) + return 0 - process() - ..() + var/datum/gas_mixture/environment = loc.return_air() + var/environment_pressure = environment.return_pressure() - if(!on) - return 0 + if(pump_direction) //input -> external + var/pressure_delta = 10000 - var/datum/gas_mixture/environment = loc.return_air() - var/environment_pressure = environment.return_pressure() + if(pressure_checks&1) + pressure_delta = min(pressure_delta, (external_pressure_bound - environment_pressure)) + if(pressure_checks&2) + pressure_delta = min(pressure_delta, (air1.return_pressure() - input_pressure_min)) - if(pump_direction) //input -> external - var/pressure_delta = 10000 + if(pressure_delta > 0) + if(air1.temperature > 0) + var/transfer_moles = pressure_delta*environment.volume/(air1.temperature * R_IDEAL_GAS_EQUATION) - if(pressure_checks&1) - pressure_delta = min(pressure_delta, (external_pressure_bound - environment_pressure)) - if(pressure_checks&2) - pressure_delta = min(pressure_delta, (air1.return_pressure() - input_pressure_min)) + var/datum/gas_mixture/removed = air1.remove(transfer_moles) - if(pressure_delta > 0) - if(air1.temperature > 0) - var/transfer_moles = pressure_delta*environment.volume/(air1.temperature * R_IDEAL_GAS_EQUATION) + loc.assume_air(removed) - var/datum/gas_mixture/removed = air1.remove(transfer_moles) + if(network1) + network1.update = 1 - loc.assume_air(removed) + else //external -> output + var/pressure_delta = 10000 - if(network1) - network1.update = 1 + if(pressure_checks&1) + pressure_delta = min(pressure_delta, (environment_pressure - external_pressure_bound)) + if(pressure_checks&4) + pressure_delta = min(pressure_delta, (output_pressure_max - air2.return_pressure())) - else //external -> output - var/pressure_delta = 10000 + if(pressure_delta > 0) + if(environment.temperature > 0) + var/transfer_moles = pressure_delta*air2.volume/(environment.temperature * R_IDEAL_GAS_EQUATION) - if(pressure_checks&1) - pressure_delta = min(pressure_delta, (environment_pressure - external_pressure_bound)) - if(pressure_checks&4) - pressure_delta = min(pressure_delta, (output_pressure_max - air2.return_pressure())) + var/datum/gas_mixture/removed = loc.remove_air(transfer_moles) - if(pressure_delta > 0) - if(environment.temperature > 0) - var/transfer_moles = pressure_delta*air2.volume/(environment.temperature * R_IDEAL_GAS_EQUATION) + air2.merge(removed) - var/datum/gas_mixture/removed = loc.remove_air(transfer_moles) + if(network2) + network2.update = 1 - air2.merge(removed) - - if(network2) - network2.update = 1 - - return 1 + return 1 //Radio remote control - proc - set_frequency(new_frequency) - radio_controller.remove_object(src, frequency) - frequency = new_frequency - if(frequency) - radio_connection = radio_controller.add_object(src, frequency, filter = RADIO_ATMOSIA) +/obj/machinery/atmospherics/binary/dp_vent_pump/proc/set_frequency(new_frequency) + radio_controller.remove_object(src, frequency) + frequency = new_frequency + if(frequency) + radio_connection = radio_controller.add_object(src, frequency, filter = RADIO_ATMOSIA) - broadcast_status() - if(!radio_connection) - return 0 +/obj/machinery/atmospherics/binary/dp_vent_pump/proc/broadcast_status() + if(!radio_connection) + return 0 - var/datum/signal/signal = new - signal.transmission_method = 1 //radio signal - signal.source = src + var/datum/signal/signal = new + signal.transmission_method = 1 //radio signal + signal.source = src - signal.data = list( - "tag" = id, - "device" = "ADVP", - "power" = on, - "direction" = pump_direction?("release"):("siphon"), - "checks" = pressure_checks, - "input" = input_pressure_min, - "output" = output_pressure_max, - "external" = external_pressure_bound, - "sigtype" = "status" - ) - radio_connection.post_signal(src, signal, filter = RADIO_ATMOSIA) + signal.data = list( + "tag" = id, + "device" = "ADVP", + "power" = on, + "direction" = pump_direction?("release"):("siphon"), + "checks" = pressure_checks, + "input" = input_pressure_min, + "output" = output_pressure_max, + "external" = external_pressure_bound, + "sigtype" = "status" + ) + radio_connection.post_signal(src, signal, filter = RADIO_ATMOSIA) - return 1 + return 1 - var/frequency = 0 - var/id = null - var/datum/radio_frequency/radio_connection +/obj/machinery/atmospherics/binary/dp_vent_pump/initialize() + ..() + if(frequency) + set_frequency(frequency) - initialize() - ..() - if(frequency) - set_frequency(frequency) +/obj/machinery/atmospherics/binary/dp_vent_pump/receive_signal(datum/signal/signal) + if(!signal.data["tag"] || (signal.data["tag"] != id) || (signal.data["sigtype"]!="command")) + return 0 + if(signal.data["power"]) + on = text2num(signal.data["power"]) - receive_signal(datum/signal/signal) + if(signal.data["power_toggle"]) + on = !on - if(!signal.data["tag"] || (signal.data["tag"] != id) || (signal.data["sigtype"]!="command")) - return 0 - if("power" in signal.data) - on = text2num(signal.data["power"]) + if(signal.data["direction"]) + pump_direction = text2num(signal.data["direction"]) - if("power_toggle" in signal.data) - on = !on + if(signal.data["checks"]) + pressure_checks = text2num(signal.data["checks"]) - if("direction" in signal.data) - pump_direction = text2num(signal.data["direction"]) + if(signal.data["purge"]) + pressure_checks &= ~1 + pump_direction = 0 - if("checks" in signal.data) - pressure_checks = text2num(signal.data["checks"]) + if(signal.data["stabalize"]) + pressure_checks |= 1 + pump_direction = 1 - if("purge" in signal.data) - pressure_checks &= ~1 - pump_direction = 0 + if(signal.data["set_input_pressure"]) + input_pressure_min = between( + 0, + text2num(signal.data["set_input_pressure"]), + ONE_ATMOSPHERE*50 + ) - if("stabalize" in signal.data) - pressure_checks |= 1 - pump_direction = 1 + if(signal.data["set_output_pressure"]) + output_pressure_max = between( + 0, + text2num(signal.data["set_output_pressure"]), + ONE_ATMOSPHERE*50 + ) - if("set_input_pressure" in signal.data) - input_pressure_min = between( - 0, - text2num(signal.data["set_input_pressure"]), - ONE_ATMOSPHERE*50 - ) + if(signal.data["set_external_pressure"]) + external_pressure_bound = between( + 0, + text2num(signal.data["set_external_pressure"]), + ONE_ATMOSPHERE*50 + ) - if("set_output_pressure" in signal.data) - output_pressure_max = between( - 0, - text2num(signal.data["set_output_pressure"]), - ONE_ATMOSPHERE*50 - ) - - if("set_external_pressure" in signal.data) - external_pressure_bound = between( - 0, - text2num(signal.data["set_external_pressure"]), - ONE_ATMOSPHERE*50 - ) - - if("status" in signal.data) - spawn(2) - broadcast_status() - return //do not update_icon - //if(signal.data["tag"]) + if(signal.data["status"]) spawn(2) broadcast_status() - update_icon() \ No newline at end of file + return //do not update_icon + + spawn(2) + broadcast_status() + update_icon() \ No newline at end of file diff --git a/code/ATMOSPHERICS/components/binary_devices/passive_gate.dm b/code/ATMOSPHERICS/components/binary_devices/passive_gate.dm index a126928e2d..4766883a64 100644 --- a/code/ATMOSPHERICS/components/binary_devices/passive_gate.dm +++ b/code/ATMOSPHERICS/components/binary_devices/passive_gate.dm @@ -1,8 +1,9 @@ -obj/machinery/atmospherics/binary/passive_gate +/obj/machinery/atmospherics/binary/passive_gate //Tries to achieve target pressure at output (like a normal pump) except // Uses no power but can not transfer gases from a low pressure area to a high pressure area - icon = 'icons/obj/atmospherics/passive_gate.dmi' - icon_state = "intact_off" + icon = 'icons/atmos/passive_gate.dmi' + icon_state = "map" + level = 1 name = "Passive gate" desc = "A one-way air valve that does not require power" @@ -14,175 +15,161 @@ obj/machinery/atmospherics/binary/passive_gate var/id = null var/datum/radio_frequency/radio_connection - update_icon() - if(stat & NOPOWER) - icon_state = "intact_off" - else if(node1 && node2) - icon_state = "intact_[on?("on"):("off")]" - else - if(node1) - icon_state = "exposed_1_off" - else if(node2) - icon_state = "exposed_2_off" - else - icon_state = "exposed_3_off" - return +/obj/machinery/atmospherics/binary/passive_gate/update_icon() + icon_state = "[on ? "on" : "off"]" - process() - ..() - if(!on) - return 0 +/obj/machinery/atmospherics/binary/passive_gate/update_underlays() + if(..()) + underlays.Cut() + var/turf/T = get_turf(src) + if(!istype(T)) + return + add_underlay(T, node1, turn(dir, 180)) + add_underlay(T, node2, dir) - var/output_starting_pressure = air2.return_pressure() - var/input_starting_pressure = air1.return_pressure() +/obj/machinery/atmospherics/binary/passive_gate/hide(var/i) + update_underlays() - if(output_starting_pressure >= min(target_pressure,input_starting_pressure-10)) - //No need to pump gas if target is already reached or input pressure is too low - //Need at least 10 KPa difference to overcome friction in the mechanism - return 1 +/obj/machinery/atmospherics/binary/passive_gate/process() + ..() + if(!on) + return 0 - //Calculate necessary moles to transfer using PV = nRT - if((air1.total_moles() > 0) && (air1.temperature>0)) - var/pressure_delta = min(target_pressure - output_starting_pressure, (input_starting_pressure - output_starting_pressure)/2) - //Can not have a pressure delta that would cause output_pressure > input_pressure + var/output_starting_pressure = air2.return_pressure() + var/input_starting_pressure = air1.return_pressure() - var/transfer_moles = pressure_delta*air2.volume/(air1.temperature * R_IDEAL_GAS_EQUATION) + if(output_starting_pressure >= min(target_pressure,input_starting_pressure-10)) + //No need to pump gas if target is already reached or input pressure is too low + //Need at least 10 KPa difference to overcome friction in the mechanism + return 1 - //Actually transfer the gas - var/datum/gas_mixture/removed = air1.remove(transfer_moles) - air2.merge(removed) + //Calculate necessary moles to transfer using PV = nRT + if((air1.total_moles() > 0) && (air1.temperature>0)) + var/pressure_delta = min(target_pressure - output_starting_pressure, (input_starting_pressure - output_starting_pressure)/2) + //Can not have a pressure delta that would cause output_pressure > input_pressure - if(network1) - network1.update = 1 + var/transfer_moles = pressure_delta*air2.volume/(air1.temperature * R_IDEAL_GAS_EQUATION) - if(network2) - network2.update = 1 + //Actually transfer the gas + var/datum/gas_mixture/removed = air1.remove(transfer_moles) + air2.merge(removed) + if(network1) + network1.update = 1 - //Radio remote control + if(network2) + network2.update = 1 - proc - set_frequency(new_frequency) - radio_controller.remove_object(src, frequency) - frequency = new_frequency - if(frequency) - radio_connection = radio_controller.add_object(src, frequency, filter = RADIO_ATMOSIA) +//Radio remote control - broadcast_status() - if(!radio_connection) - return 0 +/obj/machinery/atmospherics/binary/passive_gate/proc/set_frequency(new_frequency) + radio_controller.remove_object(src, frequency) + frequency = new_frequency + if(frequency) + radio_connection = radio_controller.add_object(src, frequency, filter = RADIO_ATMOSIA) - var/datum/signal/signal = new - signal.transmission_method = 1 //radio signal - signal.source = src +/obj/machinery/atmospherics/binary/passive_gate/proc/broadcast_status() + if(!radio_connection) + return 0 - signal.data = list( - "tag" = id, - "device" = "AGP", - "power" = on, - "target_output" = target_pressure, - "sigtype" = "status" - ) + var/datum/signal/signal = new + signal.transmission_method = 1 //radio signal + signal.source = src - radio_connection.post_signal(src, signal, filter = RADIO_ATMOSIA) + signal.data = list( + "tag" = id, + "device" = "AGP", + "power" = on, + "target_output" = target_pressure, + "sigtype" = "status" + ) - return 1 + radio_connection.post_signal(src, signal, filter = RADIO_ATMOSIA) - interact(mob/user as mob) - var/dat = {"Power: [on?"On":"Off"]
- Desirable output pressure: - [round(target_pressure,0.1)]kPa | Change - "} + return 1 - user << browse("[src.name] control[dat]", "window=atmo_pump") - onclose(user, "atmo_pump") +/obj/machinery/atmospherics/binary/passive_gate/interact(mob/user as mob) + var/dat = {"Power: [on?"On":"Off"]
+ Desirable output pressure: + [round(target_pressure,0.1)]kPa | Change + "} - initialize() - ..() - if(frequency) - set_frequency(frequency) + user << browse("[src.name] control[dat]", "window=atmo_pump") + onclose(user, "atmo_pump") - receive_signal(datum/signal/signal) - if(!signal.data["tag"] || (signal.data["tag"] != id) || (signal.data["sigtype"]!="command")) - return 0 +/obj/machinery/atmospherics/binary/passive_gate/initialize() + ..() + if(frequency) + set_frequency(frequency) - if("power" in signal.data) - on = text2num(signal.data["power"]) +/obj/machinery/atmospherics/binary/passive_gate/receive_signal(datum/signal/signal) + if(!signal.data["tag"] || (signal.data["tag"] != id) || (signal.data["sigtype"]!="command")) + return 0 - if("power_toggle" in signal.data) - on = !on + if("power" in signal.data) + on = text2num(signal.data["power"]) - if("set_output_pressure" in signal.data) - target_pressure = between( - 0, - text2num(signal.data["set_output_pressure"]), - ONE_ATMOSPHERE*50 - ) + if("power_toggle" in signal.data) + on = !on - if("status" in signal.data) - spawn(2) - broadcast_status() - return //do not update_icon + if("set_output_pressure" in signal.data) + target_pressure = between( + 0, + text2num(signal.data["set_output_pressure"]), + ONE_ATMOSPHERE*50 + ) + if("status" in signal.data) spawn(2) broadcast_status() - update_icon() + return //do not update_icon + + spawn(2) + broadcast_status() + update_icon() + return + +/obj/machinery/atmospherics/binary/passive_gate/attack_hand(user as mob) + if(..()) return - - - - attack_hand(user as mob) - if(..()) - return - src.add_fingerprint(usr) - if(!src.allowed(user)) - user << "\red Access denied." - return - usr.set_machine(src) - interact(user) + src.add_fingerprint(usr) + if(!src.allowed(user)) + user << "\red Access denied." return + usr.set_machine(src) + interact(user) + return - Topic(href,href_list) - if(..()) return - if(href_list["power"]) - on = !on - if(href_list["set_press"]) - var/new_pressure = input(usr,"Enter new output pressure (0-4500kPa)","Pressure control",src.target_pressure) as num - src.target_pressure = max(0, min(4500, new_pressure)) - usr.set_machine(src) - src.update_icon() - src.updateUsrDialog() - return - - power_change() - ..() - update_icon() - - - - attackby(var/obj/item/weapon/W as obj, var/mob/user as mob) - if (!istype(W, /obj/item/weapon/wrench)) - return ..() - if (on) - user << "\red You cannot unwrench this [src], turn it off first." - return 1 - var/turf/T = src.loc - if (level==1 && isturf(T) && T.intact) - user << "\red You must remove the plating first." - return 1 - var/datum/gas_mixture/int_air = return_air() - var/datum/gas_mixture/env_air = loc.return_air() - if ((int_air.return_pressure()-env_air.return_pressure()) > 2*ONE_ATMOSPHERE) - user << "\red You cannot unwrench this [src], it too exerted due to internal pressure." - add_fingerprint(user) - return 1 - playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) - user << "\blue You begin to unfasten \the [src]..." - if (do_after(user, 40)) - user.visible_message( \ - "[user] unfastens \the [src].", \ - "\blue You have unfastened \the [src].", \ - "You hear ratchet.") - new /obj/item/pipe(loc, make_from=src) - del(src) +/obj/machinery/atmospherics/binary/passive_gate/Topic(href,href_list) + if(..()) return + if(href_list["power"]) + on = !on + if(href_list["set_press"]) + var/new_pressure = input(usr,"Enter new output pressure (0-4500kPa)","Pressure control",src.target_pressure) as num + src.target_pressure = max(0, min(4500, new_pressure)) + usr.set_machine(src) + src.update_icon() + src.updateUsrDialog() + return +/obj/machinery/atmospherics/binary/passive_gate/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob) + if (!istype(W, /obj/item/weapon/wrench)) + return ..() + if (on) + user << "\red You cannot unwrench this [src], turn it off first." + return 1 + var/datum/gas_mixture/int_air = return_air() + var/datum/gas_mixture/env_air = loc.return_air() + if ((int_air.return_pressure()-env_air.return_pressure()) > 2*ONE_ATMOSPHERE) + user << "\red You cannot unwrench this [src], it too exerted due to internal pressure." + add_fingerprint(user) + return 1 + playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) + user << "\blue You begin to unfasten \the [src]..." + if (do_after(user, 40)) + user.visible_message( \ + "[user] unfastens \the [src].", \ + "\blue You have unfastened \the [src].", \ + "You hear ratchet.") + new /obj/item/pipe(loc, make_from=src) + del(src) \ No newline at end of file diff --git a/code/ATMOSPHERICS/components/binary_devices/pump.dm b/code/ATMOSPHERICS/components/binary_devices/pump.dm index 0a0a56fb74..b8e54e5bc8 100644 --- a/code/ATMOSPHERICS/components/binary_devices/pump.dm +++ b/code/ATMOSPHERICS/components/binary_devices/pump.dm @@ -12,9 +12,10 @@ Thus, the two variables affect pump operation are set in New(): but overall network volume is also increased as this increases... */ -obj/machinery/atmospherics/binary/pump - icon = 'icons/obj/atmospherics/pump.dmi' - icon_state = "intact_off" +/obj/machinery/atmospherics/binary/pump + icon = 'icons/atmos/pump.dmi' + icon_state = "map" + level = 1 name = "Gas pump" desc = "A pump" @@ -26,180 +27,180 @@ obj/machinery/atmospherics/binary/pump var/id = null var/datum/radio_frequency/radio_connection - highcap - name = "High capacity gas pump" - desc = "A high capacity pump" +/obj/machinery/atmospherics/binary/pump/highcap + name = "High capacity gas pump" + desc = "A high capacity pump" - target_pressure = 15000000 + target_pressure = 15000000 - on - on = 1 - icon_state = "intact_on" +/obj/machinery/atmospherics/binary/pump/on + on = 1 - update_icon() - if(stat & NOPOWER) - icon_state = "intact_off" - else if(node1 && node2) - icon_state = "intact_[on?("on"):("off")]" - else - if(node1) - icon_state = "exposed_1_off" - else if(node2) - icon_state = "exposed_2_off" - else - icon_state = "exposed_3_off" - return +/obj/machinery/atmospherics/binary/pump/update_icon() + if(!powered()) + icon_state = "off" + else + icon_state = "[on ? "on" : "off"]" - process() -// ..() - if(stat & (NOPOWER|BROKEN)) +/obj/machinery/atmospherics/binary/pump/update_underlays() + if(..()) + underlays.Cut() + var/turf/T = get_turf(src) + if(!istype(T)) return - if(!on) - return 0 + add_underlay(T, node1, turn(dir, -180)) + add_underlay(T, node2, dir) - var/output_starting_pressure = air2.return_pressure() +/obj/machinery/atmospherics/binary/pump/hide(var/i) + update_underlays() - if( (target_pressure - output_starting_pressure) < 0.01) - //No need to pump gas if target is already reached! - return 1 +/obj/machinery/atmospherics/binary/pump/process() +// ..() + if(stat & (NOPOWER|BROKEN)) + return + if(!on) + return 0 - //Calculate necessary moles to transfer using PV=nRT - if((air1.total_moles() > 0) && (air1.temperature>0)) - var/pressure_delta = target_pressure - output_starting_pressure - var/transfer_moles = pressure_delta*air2.volume/(air1.temperature * R_IDEAL_GAS_EQUATION) - - //Actually transfer the gas - var/datum/gas_mixture/removed = air1.remove(transfer_moles) - air2.merge(removed) - - if(network1) - network1.update = 1 - - if(network2) - network2.update = 1 + var/output_starting_pressure = air2.return_pressure() + if( (target_pressure - output_starting_pressure) < 0.01) + //No need to pump gas if target is already reached! return 1 - //Radio remote control + //Calculate necessary moles to transfer using PV=nRT + if((air1.total_moles() > 0) && (air1.temperature>0)) + var/pressure_delta = target_pressure - output_starting_pressure + var/transfer_moles = pressure_delta*air2.volume/(air1.temperature * R_IDEAL_GAS_EQUATION) - proc - set_frequency(new_frequency) - radio_controller.remove_object(src, frequency) - frequency = new_frequency - if(frequency) - radio_connection = radio_controller.add_object(src, frequency, filter = RADIO_ATMOSIA) + //Actually transfer the gas + var/datum/gas_mixture/removed = air1.remove(transfer_moles) + air2.merge(removed) - broadcast_status() - if(!radio_connection) - return 0 + if(network1) + network1.update = 1 - var/datum/signal/signal = new - signal.transmission_method = 1 //radio signal - signal.source = src + if(network2) + network2.update = 1 - signal.data = list( - "tag" = id, - "device" = "AGP", - "power" = on, - "target_output" = target_pressure, - "sigtype" = "status" - ) + return 1 - radio_connection.post_signal(src, signal, filter = RADIO_ATMOSIA) +//Radio remote control - return 1 +/obj/machinery/atmospherics/binary/pump/proc/set_frequency(new_frequency) + radio_controller.remove_object(src, frequency) + frequency = new_frequency + if(frequency) + radio_connection = radio_controller.add_object(src, frequency, filter = RADIO_ATMOSIA) - interact(mob/user as mob) - var/dat = {"Power: [on?"On":"Off"]
- Desirable output pressure: - [round(target_pressure,0.1)]kPa | Change - "} +/obj/machinery/atmospherics/binary/pump/proc/broadcast_status() + if(!radio_connection) + return 0 - user << browse("[src.name] control[dat]", "window=atmo_pump") - onclose(user, "atmo_pump") + var/datum/signal/signal = new + signal.transmission_method = 1 //radio signal + signal.source = src - initialize() - ..() - if(frequency) - set_frequency(frequency) + signal.data = list( + "tag" = id, + "device" = "AGP", + "power" = on, + "target_output" = target_pressure, + "sigtype" = "status" + ) - receive_signal(datum/signal/signal) - if(!signal.data["tag"] || (signal.data["tag"] != id) || (signal.data["sigtype"]!="command")) - return 0 + radio_connection.post_signal(src, signal, filter = RADIO_ATMOSIA) - if("power" in signal.data) - on = text2num(signal.data["power"]) + return 1 - if("power_toggle" in signal.data) - on = !on +/obj/machinery/atmospherics/binary/pump/interact(mob/user as mob) + var/dat = {"Power: [on?"On":"Off"]
+ Desirable output pressure: + [round(target_pressure,0.1)]kPa | Change + "} - if("set_output_pressure" in signal.data) - target_pressure = between( - 0, - text2num(signal.data["set_output_pressure"]), - ONE_ATMOSPHERE*50 - ) + user << browse("[src.name] control[dat]", "window=atmo_pump") + onclose(user, "atmo_pump") - if("status" in signal.data) - spawn(2) - broadcast_status() - return //do not update_icon +/obj/machinery/atmospherics/binary/pump/initialize() + ..() + if(frequency) + set_frequency(frequency) +/obj/machinery/atmospherics/binary/pump/receive_signal(datum/signal/signal) + if(!signal.data["tag"] || (signal.data["tag"] != id) || (signal.data["sigtype"]!="command")) + return 0 + + if(signal.data["power"]) + on = text2num(signal.data["power"]) + + if(signal.data["power_toggle"]) + on = !on + + if(signal.data["set_output_pressure"]) + target_pressure = between( + 0, + text2num(signal.data["set_output_pressure"]), + ONE_ATMOSPHERE*50 + ) + + if(signal.data["status"]) spawn(2) broadcast_status() - update_icon() + return //do not update_icon + + spawn(2) + broadcast_status() + update_icon() + return + + +/obj/machinery/atmospherics/binary/pump/attack_hand(user as mob) + if(..()) return - - - attack_hand(user as mob) - if(..()) - return - src.add_fingerprint(usr) - if(!src.allowed(user)) - user << "\red Access denied." - return - usr.set_machine(src) - interact(user) + src.add_fingerprint(usr) + if(!src.allowed(user)) + user << "\red Access denied." return + usr.set_machine(src) + interact(user) + return - Topic(href,href_list) - if(..()) return - if(href_list["power"]) - on = !on - if(href_list["set_press"]) - var/new_pressure = input(usr,"Enter new output pressure (0-4500kPa)","Pressure control",src.target_pressure) as num - src.target_pressure = max(0, min(4500, new_pressure)) - usr.set_machine(src) - src.update_icon() - src.updateUsrDialog() - return +/obj/machinery/atmospherics/binary/pump/Topic(href,href_list) + if(..()) return + if(href_list["power"]) + on = !on + if(href_list["set_press"]) + var/new_pressure = input(usr,"Enter new output pressure (0-4500kPa)","Pressure control",src.target_pressure) as num + src.target_pressure = max(0, min(4500, new_pressure)) + usr.set_machine(src) + src.update_icon() + src.updateUsrDialog() + return - power_change() - ..() +/obj/machinery/atmospherics/binary/pump/power_change() + var/old_stat = stat + ..() + if(old_stat != stat) update_icon() - attackby(var/obj/item/weapon/W as obj, var/mob/user as mob) - if (!istype(W, /obj/item/weapon/wrench)) - return ..() - if (!(stat & NOPOWER) && on) - user << "\red You cannot unwrench this [src], turn it off first." - return 1 - var/turf/T = src.loc - if (level==1 && isturf(T) && T.intact) - user << "\red You must remove the plating first." - return 1 - var/datum/gas_mixture/int_air = return_air() - var/datum/gas_mixture/env_air = loc.return_air() - if ((int_air.return_pressure()-env_air.return_pressure()) > 2*ONE_ATMOSPHERE) - user << "\red You cannot unwrench this [src], it too exerted due to internal pressure." - add_fingerprint(user) - return 1 - playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) - user << "\blue You begin to unfasten \the [src]..." - if (do_after(user, 40)) - user.visible_message( \ - "[user] unfastens \the [src].", \ - "\blue You have unfastened \the [src].", \ - "You hear ratchet.") - new /obj/item/pipe(loc, make_from=src) - del(src) +/obj/machinery/atmospherics/binary/pump/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob) + if (!istype(W, /obj/item/weapon/wrench)) + return ..() + if (!(stat & NOPOWER) && on) + user << "\red You cannot unwrench this [src], turn it off first." + return 1 + var/datum/gas_mixture/int_air = return_air() + var/datum/gas_mixture/env_air = loc.return_air() + if ((int_air.return_pressure()-env_air.return_pressure()) > 2*ONE_ATMOSPHERE) + user << "\red You cannot unwrench this [src], it too exerted due to internal pressure." + add_fingerprint(user) + return 1 + playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) + user << "\blue You begin to unfasten \the [src]..." + if (do_after(user, 40)) + user.visible_message( \ + "[user] unfastens \the [src].", \ + "\blue You have unfastened \the [src].", \ + "You hear ratchet.") + new /obj/item/pipe(loc, make_from=src) + del(src) \ No newline at end of file diff --git a/code/ATMOSPHERICS/components/binary_devices/volume_pump.dm b/code/ATMOSPHERICS/components/binary_devices/volume_pump.dm index e2dddfa97c..2f9d775bd5 100644 --- a/code/ATMOSPHERICS/components/binary_devices/volume_pump.dm +++ b/code/ATMOSPHERICS/components/binary_devices/volume_pump.dm @@ -12,9 +12,10 @@ Thus, the two variables affect pump operation are set in New(): but overall network volume is also increased as this increases... */ -obj/machinery/atmospherics/binary/volume_pump - icon = 'icons/obj/atmospherics/volume_pump.dmi' - icon_state = "intact_off" +/obj/machinery/atmospherics/binary/volume_pump + icon = 'icons/atmos/volume_pump.dmi' + icon_state = "map" + level = 1 name = "Volumetric gas pump" desc = "A volumetric pump" @@ -26,174 +27,167 @@ obj/machinery/atmospherics/binary/volume_pump var/id = null var/datum/radio_frequency/radio_connection - on - on = 1 - icon_state = "intact_on" +/obj/machinery/atmospherics/binary/volume_pump/on + on = 1 - update_icon() - if(stat & NOPOWER) - icon_state = "intact_off" - else if(node1 && node2) - icon_state = "intact_[on?("on"):("off")]" - else - if(node1) - icon_state = "exposed_1_off" - else if(node2) - icon_state = "exposed_2_off" - else - icon_state = "exposed_3_off" - return +/obj/machinery/atmospherics/binary/volume_pump/update_icon() + if(!powered()) + icon_state = "off" + else + icon_state = "[on ? "on" : "off"]" - process() -// ..() - if(stat & (NOPOWER|BROKEN)) +/obj/machinery/atmospherics/binary/volume_pump/update_underlays() + if(..()) + underlays.Cut() + var/turf/T = get_turf(src) + if(!istype(T)) return - if(!on) - return 0 + add_underlay(T, node1, turn(dir, -180)) + add_underlay(T, node2, dir) + +/obj/machinery/atmospherics/binary/volume_pump/hide(var/i) + update_underlays() + +/obj/machinery/atmospherics/binary/volume_pump/process() +// ..() + if(stat & (NOPOWER|BROKEN)) + return + if(!on) + return 0 // Pump mechanism just won't do anything if the pressure is too high/too low - var/input_starting_pressure = air1.return_pressure() - var/output_starting_pressure = air2.return_pressure() - - if((input_starting_pressure < 0.01) || (output_starting_pressure > 9000)) - return 1 - - var/transfer_ratio = max(1, transfer_rate/air1.volume) - - var/datum/gas_mixture/removed = air1.remove_ratio(transfer_ratio) - - air2.merge(removed) - - if(network1) - network1.update = 1 - - if(network2) - network2.update = 1 + var/input_starting_pressure = air1.return_pressure() + var/output_starting_pressure = air2.return_pressure() + if((input_starting_pressure < 0.01) || (output_starting_pressure > 9000)) return 1 - proc - set_frequency(new_frequency) - radio_controller.remove_object(src, frequency) - frequency = new_frequency - if(frequency) - radio_connection = radio_controller.add_object(src, frequency) + var/transfer_ratio = max(1, transfer_rate/air1.volume) - broadcast_status() - if(!radio_connection) - return 0 + var/datum/gas_mixture/removed = air1.remove_ratio(transfer_ratio) - var/datum/signal/signal = new - signal.transmission_method = 1 //radio signal - signal.source = src + air2.merge(removed) - signal.data = list( - "tag" = id, - "device" = "APV", - "power" = on, - "transfer_rate" = transfer_rate, - "sigtype" = "status" - ) - radio_connection.post_signal(src, signal) + if(network1) + network1.update = 1 - return 1 + if(network2) + network2.update = 1 - interact(mob/user as mob) - var/dat = {"Power: [on?"On":"Off"]
- Desirable output flow: - [round(transfer_rate,1)]l/s | Change - "} + return 1 - user << browse("[src.name] control[dat]", "window=atmo_pump") - onclose(user, "atmo_pump") +/obj/machinery/atmospherics/binary/volume_pump/proc/set_frequency(new_frequency) + radio_controller.remove_object(src, frequency) + frequency = new_frequency + if(frequency) + radio_connection = radio_controller.add_object(src, frequency) +/obj/machinery/atmospherics/binary/volume_pump/proc/broadcast_status() + if(!radio_connection) + return 0 + var/datum/signal/signal = new + signal.transmission_method = 1 //radio signal + signal.source = src - initialize() - ..() + signal.data = list( + "tag" = id, + "device" = "APV", + "power" = on, + "transfer_rate" = transfer_rate, + "sigtype" = "status" + ) + radio_connection.post_signal(src, signal) - set_frequency(frequency) + return 1 - receive_signal(datum/signal/signal) - if(!signal.data["tag"] || (signal.data["tag"] != id) || (signal.data["sigtype"]!="command")) - return 0 +/obj/machinery/atmospherics/binary/volume_pump/interact(mob/user as mob) + var/dat = {"Power: [on?"On":"Off"]
+ Desirable output flow: + [round(transfer_rate,1)]l/s | Change + "} - if("power" in signal.data) - on = text2num(signal.data["power"]) + user << browse("[src.name] control[dat]", "window=atmo_pump") + onclose(user, "atmo_pump") - if("power_toggle" in signal.data) - on = !on +/obj/machinery/atmospherics/binary/volume_pump/initialize() + ..() + set_frequency(frequency) - if("set_transfer_rate" in signal.data) - transfer_rate = between( - 0, - text2num(signal.data["set_transfer_rate"]), - air1.volume - ) +/obj/machinery/atmospherics/binary/volume_pump/receive_signal(datum/signal/signal) + if(!signal.data["tag"] || (signal.data["tag"] != id) || (signal.data["sigtype"]!="command")) + return 0 - if("status" in signal.data) - spawn(2) - broadcast_status() - return //do not update_icon + if(signal.data["power"]) + on = text2num(signal.data["power"]) + if(signal.data["power_toggle"]) + on = !on + + if(signal.data["set_transfer_rate"]) + transfer_rate = between( + 0, + text2num(signal.data["set_transfer_rate"]), + air1.volume + ) + + if(signal.data["status"]) spawn(2) broadcast_status() + return //do not update_icon + + spawn(2) + broadcast_status() + update_icon() + +/obj/machinery/atmospherics/binary/volume_pump/attack_hand(user as mob) + if(..()) + return + src.add_fingerprint(usr) + if(!src.allowed(user)) + user << "\red Access denied." + return + usr.set_machine(src) + interact(user) + return + +/obj/machinery/atmospherics/binary/volume_pump/Topic(href,href_list) + if(..()) return + if(href_list["power"]) + on = !on + if(href_list["set_transfer_rate"]) + var/new_transfer_rate = input(usr,"Enter new output volume (0-200l/s)","Flow control",src.transfer_rate) as num + src.transfer_rate = max(0, min(200, new_transfer_rate)) + usr.set_machine(src) + src.update_icon() + src.updateUsrDialog() + return + +/obj/machinery/atmospherics/binary/volume_pump/power_change() + var/old_stat = stat + ..() + if(old_stat != stat) update_icon() - - attack_hand(user as mob) - if(..()) - return - src.add_fingerprint(usr) - if(!src.allowed(user)) - user << "\red Access denied." - return - usr.set_machine(src) - interact(user) - return - - Topic(href,href_list) - if(..()) return - if(href_list["power"]) - on = !on - if(href_list["set_transfer_rate"]) - var/new_transfer_rate = input(usr,"Enter new output volume (0-200l/s)","Flow control",src.transfer_rate) as num - src.transfer_rate = max(0, min(200, new_transfer_rate)) - usr.set_machine(src) - src.update_icon() - src.updateUsrDialog() - return - - power_change() - ..() - update_icon() - - - - attackby(var/obj/item/weapon/W as obj, var/mob/user as mob) - if (!istype(W, /obj/item/weapon/wrench)) - return ..() - if (!(stat & NOPOWER) && on) - user << "\red You cannot unwrench this [src], turn it off first." - return 1 - var/turf/T = src.loc - if (level==1 && isturf(T) && T.intact) - user << "\red You must remove the plating first." - return 1 - var/datum/gas_mixture/int_air = return_air() - var/datum/gas_mixture/env_air = loc.return_air() - if ((int_air.return_pressure()-env_air.return_pressure()) > 2*ONE_ATMOSPHERE) - user << "\red You cannot unwrench this [src], it too exerted due to internal pressure." - add_fingerprint(user) - return 1 - playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) - user << "\blue You begin to unfasten \the [src]..." - if (do_after(user, 40)) - user.visible_message( \ - "[user] unfastens \the [src].", \ - "\blue You have unfastened \the [src].", \ - "You hear ratchet.") - new /obj/item/pipe(loc, make_from=src) - del(src) - +/obj/machinery/atmospherics/binary/volume_pump/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob) + if (!istype(W, /obj/item/weapon/wrench)) + return ..() + if (!(stat & NOPOWER) && on) + user << "\red You cannot unwrench this [src], turn it off first." + return 1 + var/datum/gas_mixture/int_air = return_air() + var/datum/gas_mixture/env_air = loc.return_air() + if ((int_air.return_pressure()-env_air.return_pressure()) > 2*ONE_ATMOSPHERE) + user << "\red You cannot unwrench this [src], it too exerted due to internal pressure." + add_fingerprint(user) + return 1 + playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) + user << "\blue You begin to unfasten \the [src]..." + if (do_after(user, 40)) + user.visible_message( \ + "[user] unfastens \the [src].", \ + "\blue You have unfastened \the [src].", \ + "You hear ratchet.") + new /obj/item/pipe(loc, make_from=src) + del(src) \ No newline at end of file diff --git a/code/ATMOSPHERICS/components/omni_devices/_omni_extras.dm b/code/ATMOSPHERICS/components/omni_devices/_omni_extras.dm index ae827881ad..b48c2f4033 100644 --- a/code/ATMOSPHERICS/components/omni_devices/_omni_extras.dm +++ b/code/ATMOSPHERICS/components/omni_devices/_omni_extras.dm @@ -11,33 +11,6 @@ #define ATM_P 6 //Phoron #define ATM_N2O 7 -//-------------------------------------------- -// Omni device cached icon list -//-------------------------------------------- -var/global/list/omni_icons[] - -/proc/gen_omni_icons() - omni_icons = new() - var/icon/omni = new('icons/obj/atmospherics/omni_devices.dmi') - - for(var/state in omni.IconStates()) - if(!state || findtext(state, "map")) - continue - - var/image/I = image('icons/obj/atmospherics/omni_devices.dmi', icon_state = state) - - if(findtext(state, "pipe")) - for(var/pipe_color in pipe_colors) - I = image('icons/obj/atmospherics/omni_devices.dmi', icon_state = state) - I.color = pipe_colors[pipe_color] - var/cache_name = state - if(I.color) - cache_name += "_[pipe_colors[pipe_color]]" - omni_icons[cache_name] = I - else - omni_icons[state] = I - - //-------------------------------------------- // Omni port datum // @@ -83,16 +56,6 @@ var/global/list/omni_icons[] // Need to find somewhere else for these //-------------------------------------------- -#define PIPE_COLOR_RED "#ff0000" -#define PIPE_COLOR_BLUE "#0000ff" -#define PIPE_COLOR_CYAN "#00ffff" -#define PIPE_COLOR_GREEN "#00ff00" -#define PIPE_COLOR_YELLOW "#ffcc00" -#define PIPE_COLOR_PURPLE "#5c1ec0" - -var/global/list/pipe_colors = list("grey" = null, "red" = PIPE_COLOR_RED, "blue" = PIPE_COLOR_BLUE, "cyan" = PIPE_COLOR_CYAN, "green" = PIPE_COLOR_GREEN, "yellow" = PIPE_COLOR_YELLOW, "purple" = PIPE_COLOR_PURPLE) - - //returns a text string based on the direction flag input // if capitalize is true, it will return the string capitalized // otherwise it will return the direction string in lower case diff --git a/code/ATMOSPHERICS/components/omni_devices/omni_base.dm b/code/ATMOSPHERICS/components/omni_devices/omni_base.dm index 0e46546a20..24c771f94d 100644 --- a/code/ATMOSPHERICS/components/omni_devices/omni_base.dm +++ b/code/ATMOSPHERICS/components/omni_devices/omni_base.dm @@ -3,10 +3,11 @@ //-------------------------------------------- /obj/machinery/atmospherics/omni name = "omni device" - icon = 'icons/obj/atmospherics/omni_devices.dmi' + icon = 'icons/atmos/omni_devices.dmi' icon_state = "base" use_power = 1 initialize_directions = 0 + level = 1 var/on = 0 var/configuring = 0 @@ -70,12 +71,6 @@ update_icon() /obj/machinery/atmospherics/omni/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob) - if(istype(W, /obj/item/device/pipe_painter)) //for updating the color of connected pipe ends - for(var/datum/omni_port/P in ports) - P.update = 1 - update_ports() - return - if(!istype(W, /obj/item/weapon/wrench)) return ..() @@ -106,8 +101,8 @@ return /obj/machinery/atmospherics/omni/proc/build_icons() - if(!omni_icons) - gen_omni_icons() + if(!check_icon_cache()) + return var/core_icon = null if(istype(src, /obj/machinery/atmospherics/omni/mixer)) @@ -119,13 +114,16 @@ //directional icons are layers 1-4, with the core icon on layer 5 if(core_icon) - overlays_off[5] = omni_icons[core_icon] - overlays_on[5] = omni_icons[core_icon + "_glow"] + overlays_off[5] = icon_manager.get_atmos_icon("omni", , , core_icon) + overlays_on[5] = icon_manager.get_atmos_icon("omni", , , core_icon + "_glow") - overlays_error[1] = omni_icons[core_icon] - overlays_error[2] = omni_icons["error"] + overlays_error[1] = icon_manager.get_atmos_icon("omni", , , core_icon) + overlays_error[2] = icon_manager.get_atmos_icon("omni", , , "error") /obj/machinery/atmospherics/omni/proc/update_port_icons() + if(!check_icon_cache()) + return + for(var/datum/omni_port/P in ports) if(P.update) var/ref_layer = 0 @@ -145,11 +143,11 @@ var/list/port_icons = select_port_icons(P) if(port_icons) if(P.node) - underlays_current[ref_layer] = omni_icons[port_icons["pipe_icon"]] + underlays_current[ref_layer] = port_icons["pipe_icon"] else underlays_current[ref_layer] = null - overlays_off[ref_layer] = omni_icons[port_icons["off_icon"]] - overlays_on[ref_layer] = omni_icons[port_icons["on_icon"]] + overlays_off[ref_layer] = port_icons["off_icon"] + overlays_on[ref_layer] = port_icons["on_icon"] else underlays_current[ref_layer] = null overlays_off[ref_layer] = null @@ -175,14 +173,29 @@ if(ATM_O2 to ATM_N2O) ic_on += "_filter" ic_off += "_out" - - var/pipe_state = ic_dir + "_pipe" - if(P.node) - if(P.node.color) - pipe_state += "_[P.node.color]" + ic_on = icon_manager.get_atmos_icon("omni", , , ic_on) + ic_off = icon_manager.get_atmos_icon("omni", , , ic_off) + + var/pipe_state + var/turf/T = get_turf(src) + if(!istype(T)) + return + if(T.intact && istype(P.node, /obj/machinery/atmospherics/pipe) && P.node.level == 1 ) + pipe_state = icon_manager.get_atmos_icon("underlay_down", P.dir, color_cache_name(P.node)) + else + pipe_state = icon_manager.get_atmos_icon("underlay_intact", P.dir, color_cache_name(P.node)) + return list("on_icon" = ic_on, "off_icon" = ic_off, "pipe_icon" = pipe_state) +/obj/machinery/atmospherics/omni/update_underlays() + for(var/datum/omni_port/P in ports) + P.update = 1 + update_ports() + +/obj/machinery/atmospherics/omni/hide(var/i) + update_underlays() + /obj/machinery/atmospherics/omni/proc/update_ports() sort_ports() update_port_icons() diff --git a/code/ATMOSPHERICS/components/portables_connector.dm b/code/ATMOSPHERICS/components/portables_connector.dm index 9ecc82b324..75d32718fa 100644 --- a/code/ATMOSPHERICS/components/portables_connector.dm +++ b/code/ATMOSPHERICS/components/portables_connector.dm @@ -1,6 +1,6 @@ /obj/machinery/atmospherics/portables_connector - icon = 'icons/obj/atmospherics/portables_connector.dmi' - icon_state = "intact" + icon = 'icons/atmos/connector.dmi' + icon_state = "map_connector" name = "Connector Port" desc = "For connecting portables devices related to atmospherics control." @@ -16,142 +16,139 @@ var/on = 0 use_power = 0 - level = 0 + level = 1 - New() - initialize_directions = dir - ..() +/obj/machinery/atmospherics/portables_connector/New() + initialize_directions = dir + ..() - update_icon() - if(node) - icon_state = "[level == 1 && istype(loc, /turf/simulated) ? "h" : "" ]intact" - dir = get_dir(src, node) - else - icon_state = "exposed" +/obj/machinery/atmospherics/portables_connector/update_icon() + icon_state = "connector" +/obj/machinery/atmospherics/portables_connector/update_underlays() + if(..()) + underlays.Cut() + var/turf/T = get_turf(src) + if(!istype(T)) + return + add_underlay(T, node, dir) + +/obj/machinery/atmospherics/portables_connector/hide(var/i) + update_underlays() + +/obj/machinery/atmospherics/portables_connector/process() + ..() + if(!on) return - - hide(var/i) //to make the little pipe section invisible, the icon changes. - if(node) - icon_state = "[i == 1 && istype(loc, /turf/simulated) ? "h" : "" ]intact" - dir = get_dir(src, node) - else - icon_state = "exposed" - - process() - ..() - if(!on) - return - if(!connected_device) - on = 0 - return - if(network) - network.update = 1 - return 1 + if(!connected_device) + on = 0 + return + if(network) + network.update = 1 + return 1 // Housekeeping and pipe network stuff below - network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference) - if(reference == node) - network = new_network +/obj/machinery/atmospherics/portables_connector/network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference) + if(reference == node) + network = new_network - if(new_network.normal_members.Find(src)) - return 0 + if(new_network.normal_members.Find(src)) + return 0 - new_network.normal_members += src + new_network.normal_members += src - return null + return null - Del() - loc = null +/obj/machinery/atmospherics/portables_connector/Del() + loc = null - if(connected_device) - connected_device.disconnect() + if(connected_device) + connected_device.disconnect() - if(node) - node.disconnect(src) - del(network) + if(node) + node.disconnect(src) + del(network) - node = null + node = null - ..() + ..() - initialize() - if(node) return +/obj/machinery/atmospherics/portables_connector/initialize() + if(node) return - var/node_connect = dir + var/node_connect = dir - for(var/obj/machinery/atmospherics/target in get_step(src,node_connect)) - if(target.initialize_directions & get_dir(target,src)) - node = target - break + for(var/obj/machinery/atmospherics/target in get_step(src,node_connect)) + if(target.initialize_directions & get_dir(target,src)) + node = target + break - update_icon() + update_icon() + update_underlays() +/obj/machinery/atmospherics/portables_connector/build_network() + if(!network && node) + network = new /datum/pipe_network() + network.normal_members += src + network.build_network(node, src) + + +/obj/machinery/atmospherics/portables_connector/return_network(obj/machinery/atmospherics/reference) build_network() - if(!network && node) - network = new /datum/pipe_network() - network.normal_members += src - network.build_network(node, src) + + if(reference==node) + return network + + if(reference==connected_device) + return network + + return null + +/obj/machinery/atmospherics/portables_connector/reassign_network(datum/pipe_network/old_network, datum/pipe_network/new_network) + if(network == old_network) + network = new_network + + return 1 + +/obj/machinery/atmospherics/portables_connector/return_network_air(datum/pipe_network/reference) + var/list/results = list() + + if(connected_device) + results += connected_device.air_contents + + return results + +/obj/machinery/atmospherics/portables_connector/disconnect(obj/machinery/atmospherics/reference) + if(reference==node) + del(network) + node = null + + update_underlays() + + return null - return_network(obj/machinery/atmospherics/reference) - build_network() - - if(reference==node) - return network - - if(reference==connected_device) - return network - - return null - - reassign_network(datum/pipe_network/old_network, datum/pipe_network/new_network) - if(network == old_network) - network = new_network - +/obj/machinery/atmospherics/portables_connector/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob) + if (!istype(W, /obj/item/weapon/wrench)) + return ..() + if (connected_device) + user << "\red You cannot unwrench this [src], dettach [connected_device] first." return 1 - - return_network_air(datum/pipe_network/reference) - var/list/results = list() - - if(connected_device) - results += connected_device.air_contents - - return results - - disconnect(obj/machinery/atmospherics/reference) - if(reference==node) - del(network) - node = null - - return null - - - attackby(var/obj/item/weapon/W as obj, var/mob/user as mob) - if (!istype(W, /obj/item/weapon/wrench)) - return ..() - if (connected_device) - user << "\red You cannot unwrench this [src], dettach [connected_device] first." - return 1 - if (locate(/obj/machinery/portable_atmospherics, src.loc)) - return 1 - var/turf/T = src.loc - if (level==1 && isturf(T) && T.intact) - user << "\red You must remove the plating first." - return 1 - var/datum/gas_mixture/int_air = return_air() - var/datum/gas_mixture/env_air = loc.return_air() - if ((int_air.return_pressure()-env_air.return_pressure()) > 2*ONE_ATMOSPHERE) - user << "\red You cannot unwrench this [src], it too exerted due to internal pressure." - add_fingerprint(user) - return 1 - playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) - user << "\blue You begin to unfasten \the [src]..." - if (do_after(user, 40)) - user.visible_message( \ - "[user] unfastens \the [src].", \ - "\blue You have unfastened \the [src].", \ - "You hear ratchet.") - new /obj/item/pipe(loc, make_from=src) - del(src) + if (locate(/obj/machinery/portable_atmospherics, src.loc)) + return 1 + var/datum/gas_mixture/int_air = return_air() + var/datum/gas_mixture/env_air = loc.return_air() + if ((int_air.return_pressure()-env_air.return_pressure()) > 2*ONE_ATMOSPHERE) + user << "\red You cannot unwrench this [src], it too exerted due to internal pressure." + add_fingerprint(user) + return 1 + playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) + user << "\blue You begin to unfasten \the [src]..." + if (do_after(user, 40)) + user.visible_message( \ + "[user] unfastens \the [src].", \ + "\blue You have unfastened \the [src].", \ + "You hear ratchet.") + new /obj/item/pipe(loc, make_from=src) + del(src) diff --git a/code/ATMOSPHERICS/components/trinary_devices/filter.dm b/code/ATMOSPHERICS/components/trinary_devices/filter.dm index 16a863a2e1..594190bdb8 100755 --- a/code/ATMOSPHERICS/components/trinary_devices/filter.dm +++ b/code/ATMOSPHERICS/components/trinary_devices/filter.dm @@ -1,11 +1,11 @@ -obj/machinery/atmospherics/trinary/filter - icon = 'icons/obj/atmospherics/filter.dmi' - icon_state = "intact_off" +/obj/machinery/atmospherics/trinary/filter + icon = 'icons/atmos/filter.dmi' + icon_state = "map" density = 0 + level = 1 name = "Gas filter" - var/on = 0 var/temp = null // -- TLE var/target_pressure = ONE_ATMOSPHERE @@ -24,141 +24,159 @@ Filter types: var/frequency = 0 var/datum/radio_frequency/radio_connection - proc - set_frequency(new_frequency) - radio_controller.remove_object(src, frequency) - frequency = new_frequency - if(frequency) - radio_connection = radio_controller.add_object(src, frequency, RADIO_ATMOSIA) +/obj/machinery/atmospherics/trinary/filter/proc/set_frequency(new_frequency) + radio_controller.remove_object(src, frequency) + frequency = new_frequency + if(frequency) + radio_connection = radio_controller.add_object(src, frequency, RADIO_ATMOSIA) - New() - if(radio_controller) - initialize() - ..() +/* I don't know why this is here, but it's ugly, so I'm disabling it +/obj/machinery/atmospherics/trinary/filter/New() + ..() + if(radio_controller) + initialize() +*/ +/obj/machinery/atmospherics/trinary/filter/update_icon() + if(istype(src, /obj/machinery/atmospherics/trinary/filter/m_filter)) + icon_state = "m" + else + icon_state = "" + + if(!powered()) + icon_state += "off" + else if(node2 && node3 && node1) + icon_state += on ? "on" : "off" + else + icon_state += "off" + on = 0 - update_icon() - if(stat & NOPOWER) - icon_state = "intact_off" - else if(node2 && node3 && node1) - icon_state = "intact_[on?("on"):("off")]" +/obj/machinery/atmospherics/trinary/filter/update_underlays() + if(..()) + underlays.Cut() + var/turf/T = get_turf(src) + if(!istype(T)) + return + + add_underlay(T, node1, turn(dir, -180)) + + if(istype(src, /obj/machinery/atmospherics/trinary/filter/m_filter)) + add_underlay(T, node2, turn(dir, 90)) else - icon_state = "intact_off" - on = 0 + add_underlay(T, node2, turn(dir, -90)) - return + add_underlay(T, node3, dir) - power_change() - var/old_stat = stat - ..() - if(old_stat != stat) - update_icon() +/obj/machinery/atmospherics/trinary/filter/hide(var/i) + update_underlays() - process() - ..() - if(!on) - return 0 +/obj/machinery/atmospherics/trinary/filter/power_change() + var/old_stat = stat + ..() + if(old_stat != stat) + update_icon() - var/output_starting_pressure = air3.return_pressure() +/obj/machinery/atmospherics/trinary/filter/process() + ..() + if(!on) + return 0 - if(output_starting_pressure >= target_pressure || air2.return_pressure() >= target_pressure ) - //No need to mix if target is already full! - return 1 - - //Calculate necessary moles to transfer using PV=nRT - - var/pressure_delta = target_pressure - output_starting_pressure - var/transfer_moles - - if(air1.temperature > 0) - transfer_moles = pressure_delta*air3.volume/(air1.temperature * R_IDEAL_GAS_EQUATION) - - //Actually transfer the gas - - if(transfer_moles > 0) - var/datum/gas_mixture/removed = air1.remove(transfer_moles) - - if(!removed) - return - var/datum/gas_mixture/filtered_out = new - filtered_out.temperature = removed.temperature - - switch(filter_type) - if(0) //removing hydrocarbons - filtered_out.phoron = removed.phoron - removed.phoron = 0 - - if(removed.trace_gases.len>0) - for(var/datum/gas/trace_gas in removed.trace_gases) - if(istype(trace_gas, /datum/gas/oxygen_agent_b)) - removed.trace_gases -= trace_gas - filtered_out.trace_gases += trace_gas - - if(1) //removing O2 - filtered_out.oxygen = removed.oxygen - removed.oxygen = 0 - - if(2) //removing N2 - filtered_out.nitrogen = removed.nitrogen - removed.nitrogen = 0 - - if(3) //removing CO2 - filtered_out.carbon_dioxide = removed.carbon_dioxide - removed.carbon_dioxide = 0 - - if(4)//removing N2O - if(removed.trace_gases.len>0) - for(var/datum/gas/trace_gas in removed.trace_gases) - if(istype(trace_gas, /datum/gas/sleeping_agent)) - removed.trace_gases -= trace_gas - filtered_out.trace_gases += trace_gas - - else - filtered_out = null - - - air2.merge(filtered_out) - air3.merge(removed) - - if(network2) - network2.update = 1 - - if(network3) - network3.update = 1 - - if(network1) - network1.update = 1 + var/output_starting_pressure = air3.return_pressure() + if(output_starting_pressure >= target_pressure || air2.return_pressure() >= target_pressure ) + //No need to mix if target is already full! return 1 - initialize() - set_frequency(frequency) - ..() + //Calculate necessary moles to transfer using PV=nRT - attackby(var/obj/item/weapon/W as obj, var/mob/user as mob) - if (!istype(W, /obj/item/weapon/wrench)) - return ..() - var/turf/T = src.loc - if (level==1 && isturf(T) && T.intact) - user << "\red You must remove the plating first." - return 1 - var/datum/gas_mixture/int_air = return_air() - var/datum/gas_mixture/env_air = loc.return_air() - if ((int_air.return_pressure()-env_air.return_pressure()) > 2*ONE_ATMOSPHERE) - user << "\red You cannot unwrench this [src], it too exerted due to internal pressure." - add_fingerprint(user) - return 1 - playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) - user << "\blue You begin to unfasten \the [src]..." - if (do_after(user, 40)) - user.visible_message( \ - "[user] unfastens \the [src].", \ - "\blue You have unfastened \the [src].", \ - "You hear ratchet.") - new /obj/item/pipe(loc, make_from=src) - del(src) + var/pressure_delta = target_pressure - output_starting_pressure + var/transfer_moles + + if(air1.temperature > 0) + transfer_moles = pressure_delta*air3.volume/(air1.temperature * R_IDEAL_GAS_EQUATION) + + //Actually transfer the gas + + if(transfer_moles > 0) + var/datum/gas_mixture/removed = air1.remove(transfer_moles) + + if(!removed) + return + var/datum/gas_mixture/filtered_out = new + filtered_out.temperature = removed.temperature + + switch(filter_type) + if(0) //removing hydrocarbons + filtered_out.phoron = removed.phoron + removed.phoron = 0 + + if(removed.trace_gases.len>0) + for(var/datum/gas/trace_gas in removed.trace_gases) + if(istype(trace_gas, /datum/gas/oxygen_agent_b)) + removed.trace_gases -= trace_gas + filtered_out.trace_gases += trace_gas + + if(1) //removing O2 + filtered_out.oxygen = removed.oxygen + removed.oxygen = 0 + + if(2) //removing N2 + filtered_out.nitrogen = removed.nitrogen + removed.nitrogen = 0 + + if(3) //removing CO2 + filtered_out.carbon_dioxide = removed.carbon_dioxide + removed.carbon_dioxide = 0 + + if(4)//removing N2O + if(removed.trace_gases.len>0) + for(var/datum/gas/trace_gas in removed.trace_gases) + if(istype(trace_gas, /datum/gas/sleeping_agent)) + removed.trace_gases -= trace_gas + filtered_out.trace_gases += trace_gas + + else + filtered_out = null -obj/machinery/atmospherics/trinary/filter/attack_hand(user as mob) // -- TLE + air2.merge(filtered_out) + air3.merge(removed) + + if(network2) + network2.update = 1 + + if(network3) + network3.update = 1 + + if(network1) + network1.update = 1 + + return 1 + +/obj/machinery/atmospherics/trinary/filter/initialize() + set_frequency(frequency) + ..() + +/obj/machinery/atmospherics/trinary/filter/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob) + if (!istype(W, /obj/item/weapon/wrench)) + return ..() + var/datum/gas_mixture/int_air = return_air() + var/datum/gas_mixture/env_air = loc.return_air() + if ((int_air.return_pressure()-env_air.return_pressure()) > 2*ONE_ATMOSPHERE) + user << "\red You cannot unwrench this [src], it too exerted due to internal pressure." + add_fingerprint(user) + return 1 + playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) + user << "\blue You begin to unfasten \the [src]..." + if (do_after(user, 40)) + user.visible_message( \ + "[user] unfastens \the [src].", \ + "\blue You have unfastened \the [src].", \ + "You hear ratchet.") + new /obj/item/pipe(loc, make_from=src) + del(src) + + +/obj/machinery/atmospherics/trinary/filter/attack_hand(user as mob) // -- TLE if(..()) return @@ -211,7 +229,7 @@ obj/machinery/atmospherics/trinary/filter/attack_hand(user as mob) // -- TLE onclose(user, "atmo_filter") return -obj/machinery/atmospherics/trinary/filter/Topic(href, href_list) // -- TLE +/obj/machinery/atmospherics/trinary/filter/Topic(href, href_list) // -- TLE if(..()) return usr.set_machine(src) @@ -234,9 +252,8 @@ obj/machinery/atmospherics/trinary/filter/Topic(href, href_list) // -- TLE */ return -obj/machinery/atmospherics/trinary/filter/m_filter - icon = 'icons/obj/atmospherics/m_filter.dmi' - icon_state = "intact_off" +/obj/machinery/atmospherics/trinary/filter/m_filter + icon_state = "mmap" dir = SOUTH initialize_directions = SOUTH|NORTH|EAST @@ -253,7 +270,9 @@ obj/machinery/atmospherics/trinary/filter/m_filter/New() if(WEST) initialize_directions = WEST|SOUTH|EAST -obj/machinery/atmospherics/trinary/filter/m_filter/initialize() +/obj/machinery/atmospherics/trinary/filter/m_filter/initialize() + set_frequency(frequency) + if(node1 && node2 && node3) return var/node1_connect = turn(dir, -180) @@ -276,3 +295,4 @@ obj/machinery/atmospherics/trinary/filter/m_filter/initialize() break update_icon() + update_underlays() \ No newline at end of file diff --git a/code/ATMOSPHERICS/components/trinary_devices/mixer.dm b/code/ATMOSPHERICS/components/trinary_devices/mixer.dm index 4d94acbfba..228be72020 100644 --- a/code/ATMOSPHERICS/components/trinary_devices/mixer.dm +++ b/code/ATMOSPHERICS/components/trinary_devices/mixer.dm @@ -1,169 +1,190 @@ -obj/machinery/atmospherics/trinary/mixer - icon = 'icons/obj/atmospherics/mixer.dmi' - icon_state = "intact_off" +/obj/machinery/atmospherics/trinary/mixer + icon = 'icons/atmos/mixer.dmi' + icon_state = "map" density = 0 + level = 1 name = "Gas mixer" - var/on = 0 - var/target_pressure = ONE_ATMOSPHERE var/node1_concentration = 0.5 var/node2_concentration = 0.5 //node 3 is the outlet, nodes 1 & 2 are intakes - update_icon() - if(stat & NOPOWER) - icon_state = "intact_off" - else if(node2 && node3 && node1) - icon_state = "intact_[on?("on"):("off")]" +/obj/machinery/atmospherics/trinary/mixer/update_icon(var/safety = 0) + if(istype(src, /obj/machinery/atmospherics/trinary/mixer/m_mixer)) + icon_state = "m" + else if(istype(src, /obj/machinery/atmospherics/trinary/mixer/t_mixer)) + icon_state = "t" + else + icon_state = "" + + if(!powered()) + icon_state += "off" + else if(node2 && node3 && node1) + icon_state += on ? "on" : "off" + else + icon_state += "off" + on = 0 + +/obj/machinery/atmospherics/trinary/mixer/update_underlays() + if(..()) + underlays.Cut() + var/turf/T = get_turf(src) + if(!istype(T)) + return + + if(istype(src, /obj/machinery/atmospherics/trinary/mixer/t_mixer)) + add_underlay(T, node1, turn(dir, -90)) else - icon_state = "intact_off" - on = 0 + add_underlay(T, node1, turn(dir, -180)) - return + if(istype(src, /obj/machinery/atmospherics/trinary/mixer/m_mixer) || istype(src, /obj/machinery/atmospherics/trinary/mixer/t_mixer)) + add_underlay(T, node2, turn(dir, 90)) + else + add_underlay(T, node2, turn(dir, -90)) - power_change() - var/old_stat = stat - ..() - if(old_stat != stat) - update_icon() + add_underlay(T, node3, dir) - New() - ..() - air3.volume = 300 +/obj/machinery/atmospherics/trinary/mixer/hide(var/i) + update_underlays() - process() - ..() - if(!on) - return 0 +/obj/machinery/atmospherics/trinary/mixer/power_change() + var/old_stat = stat + ..() + if(old_stat != stat) + update_icon() - var/output_starting_pressure = air3.return_pressure() +/obj/machinery/atmospherics/trinary/mixer/New() + ..() + air3.volume = 300 - if(output_starting_pressure >= target_pressure) - //No need to mix if target is already full! - return 1 +/obj/machinery/atmospherics/trinary/mixer/process() + ..() + if(!on) + return 0 - //Calculate necessary moles to transfer using PV=nRT - - var/pressure_delta = target_pressure - output_starting_pressure - var/transfer_moles1 = 0 - var/transfer_moles2 = 0 - - if(air1.temperature > 0) - transfer_moles1 = (node1_concentration*pressure_delta)*air3.volume/(air1.temperature * R_IDEAL_GAS_EQUATION) - - if(air2.temperature > 0) - transfer_moles2 = (node2_concentration*pressure_delta)*air3.volume/(air2.temperature * R_IDEAL_GAS_EQUATION) - - var/air1_moles = air1.total_moles() - var/air2_moles = air2.total_moles() - - if((air1_moles < transfer_moles1) || (air2_moles < transfer_moles2)) - if(!transfer_moles1 || !transfer_moles2) return - var/ratio = min(air1_moles/transfer_moles1, air2_moles/transfer_moles2) - - transfer_moles1 *= ratio - transfer_moles2 *= ratio - - //Actually transfer the gas - - if(transfer_moles1 > 0) - var/datum/gas_mixture/removed1 = air1.remove(transfer_moles1) - air3.merge(removed1) - - if(transfer_moles2 > 0) - var/datum/gas_mixture/removed2 = air2.remove(transfer_moles2) - air3.merge(removed2) - - if(network1 && transfer_moles1) - network1.update = 1 - - if(network2 && transfer_moles2) - network2.update = 1 - - if(network3) - network3.update = 1 + var/output_starting_pressure = air3.return_pressure() + if(output_starting_pressure >= target_pressure) + //No need to mix if target is already full! return 1 - attackby(var/obj/item/weapon/W as obj, var/mob/user as mob) - if (!istype(W, /obj/item/weapon/wrench)) - return ..() - var/turf/T = src.loc - if (level==1 && isturf(T) && T.intact) - user << "\red You must remove the plating first." - return 1 - var/datum/gas_mixture/int_air = return_air() - var/datum/gas_mixture/env_air = loc.return_air() - if ((int_air.return_pressure()-env_air.return_pressure()) > 2*ONE_ATMOSPHERE) - user << "\red You cannot unwrench this [src], it too exerted due to internal pressure." - add_fingerprint(user) - return 1 - playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) - user << "\blue You begin to unfasten \the [src]..." - if (do_after(user, 40)) - user.visible_message( \ - "[user] unfastens \the [src].", \ - "\blue You have unfastened \the [src].", \ - "You hear ratchet.") - new /obj/item/pipe(loc, make_from=src) - del(src) + //Calculate necessary moles to transfer using PV=nRT - attack_hand(user as mob) - if(..()) - return - src.add_fingerprint(usr) - if(!src.allowed(user)) - user << "\red Access denied." - return - usr.set_machine(src) - var/dat = {"Power: [on?"On":"Off"]
- Desirable output pressure: - [target_pressure]kPa | Change -
- Node 1 Concentration: - - - - - [node1_concentration]([node1_concentration*100]%) - + - + -
- Node 2 Concentration: - - - - - [node2_concentration]([node2_concentration*100]%) - + - + - "} + var/pressure_delta = target_pressure - output_starting_pressure + var/transfer_moles1 = 0 + var/transfer_moles2 = 0 - user << browse("[src.name] control[dat]", "window=atmo_mixer") - onclose(user, "atmo_mixer") + if(air1.temperature > 0) + transfer_moles1 = (node1_concentration*pressure_delta)*air3.volume/(air1.temperature * R_IDEAL_GAS_EQUATION) + + if(air2.temperature > 0) + transfer_moles2 = (node2_concentration*pressure_delta)*air3.volume/(air2.temperature * R_IDEAL_GAS_EQUATION) + + var/air1_moles = air1.total_moles() + var/air2_moles = air2.total_moles() + + if((air1_moles < transfer_moles1) || (air2_moles < transfer_moles2)) + if(!transfer_moles1 || !transfer_moles2) return + var/ratio = min(air1_moles/transfer_moles1, air2_moles/transfer_moles2) + + transfer_moles1 *= ratio + transfer_moles2 *= ratio + + //Actually transfer the gas + + if(transfer_moles1 > 0) + var/datum/gas_mixture/removed1 = air1.remove(transfer_moles1) + air3.merge(removed1) + + if(transfer_moles2 > 0) + var/datum/gas_mixture/removed2 = air2.remove(transfer_moles2) + air3.merge(removed2) + + if(network1 && transfer_moles1) + network1.update = 1 + + if(network2 && transfer_moles2) + network2.update = 1 + + if(network3) + network3.update = 1 + + return 1 + +/obj/machinery/atmospherics/trinary/mixer/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob) + if (!istype(W, /obj/item/weapon/wrench)) + return ..() + var/datum/gas_mixture/int_air = return_air() + var/datum/gas_mixture/env_air = loc.return_air() + if ((int_air.return_pressure()-env_air.return_pressure()) > 2*ONE_ATMOSPHERE) + user << "\red You cannot unwrench this [src], it too exerted due to internal pressure." + add_fingerprint(user) + return 1 + playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) + user << "\blue You begin to unfasten \the [src]..." + if (do_after(user, 40)) + user.visible_message( \ + "[user] unfastens \the [src].", \ + "\blue You have unfastened \the [src].", \ + "You hear ratchet.") + new /obj/item/pipe(loc, make_from=src) + del(src) + +/obj/machinery/atmospherics/trinary/mixer/attack_hand(user as mob) + if(..()) return - - Topic(href,href_list) - if(..()) return - if(href_list["power"]) - on = !on - if(href_list["set_press"]) - var/new_pressure = input(usr,"Enter new output pressure (0-4500kPa)","Pressure control",src.target_pressure) as num - src.target_pressure = max(0, min(4500, new_pressure)) - if(href_list["node1_c"]) - var/value = text2num(href_list["node1_c"]) - src.node1_concentration = max(0, min(1, src.node1_concentration + value)) - src.node2_concentration = max(0, min(1, src.node2_concentration - value)) - if(href_list["node2_c"]) - var/value = text2num(href_list["node2_c"]) - src.node2_concentration = max(0, min(1, src.node2_concentration + value)) - src.node1_concentration = max(0, min(1, src.node1_concentration - value)) - src.update_icon() - src.updateUsrDialog() + src.add_fingerprint(usr) + if(!src.allowed(user)) + user << "\red Access denied." return + usr.set_machine(src) + var/dat = {"Power: [on?"On":"Off"]
+ Desirable output pressure: + [target_pressure]kPa | Change +
+ Node 1 Concentration: + - + - + [node1_concentration]([node1_concentration*100]%) + + + + +
+ Node 2 Concentration: + - + - + [node2_concentration]([node2_concentration*100]%) + + + + + "} + + user << browse("[src.name] control[dat]", "window=atmo_mixer") + onclose(user, "atmo_mixer") + return + +/obj/machinery/atmospherics/trinary/mixer/Topic(href,href_list) + if(..()) return + if(href_list["power"]) + on = !on + if(href_list["set_press"]) + var/new_pressure = input(usr,"Enter new output pressure (0-4500kPa)","Pressure control",src.target_pressure) as num + src.target_pressure = max(0, min(4500, new_pressure)) + if(href_list["node1_c"]) + var/value = text2num(href_list["node1_c"]) + src.node1_concentration = max(0, min(1, src.node1_concentration + value)) + src.node2_concentration = max(0, min(1, src.node2_concentration - value)) + if(href_list["node2_c"]) + var/value = text2num(href_list["node2_c"]) + src.node2_concentration = max(0, min(1, src.node2_concentration + value)) + src.node1_concentration = max(0, min(1, src.node1_concentration - value)) + src.update_icon() + src.updateUsrDialog() + return obj/machinery/atmospherics/trinary/mixer/t_mixer - icon = 'icons/obj/atmospherics/t_mixer.dmi' - icon_state = "intact_off" + icon_state = "tmap" dir = SOUTH initialize_directions = SOUTH|EAST|WEST @@ -205,10 +226,10 @@ obj/machinery/atmospherics/trinary/mixer/t_mixer/initialize() break update_icon() + update_underlays() obj/machinery/atmospherics/trinary/mixer/m_mixer - icon = 'icons/obj/atmospherics/m_mixer.dmi' - icon_state = "intact_off" + icon_state = "mmap" dir = SOUTH initialize_directions = SOUTH|NORTH|EAST @@ -249,4 +270,5 @@ obj/machinery/atmospherics/trinary/mixer/m_mixer/initialize() node3 = target break - update_icon() \ No newline at end of file + update_icon() + update_underlays() \ No newline at end of file diff --git a/code/ATMOSPHERICS/components/trinary_devices/trinary_base.dm b/code/ATMOSPHERICS/components/trinary_devices/trinary_base.dm index d3f1116a43..655e58ea38 100644 --- a/code/ATMOSPHERICS/components/trinary_devices/trinary_base.dm +++ b/code/ATMOSPHERICS/components/trinary_devices/trinary_base.dm @@ -2,6 +2,8 @@ obj/machinery/atmospherics/trinary dir = SOUTH initialize_directions = SOUTH|NORTH|WEST use_power = 1 + + var/on = 0 var/datum/gas_mixture/air1 var/datum/gas_mixture/air2 @@ -94,6 +96,7 @@ obj/machinery/atmospherics/trinary break update_icon() + update_underlays() build_network() if(!network1 && node1) @@ -160,5 +163,7 @@ obj/machinery/atmospherics/trinary else if(reference==node3) del(network3) node3 = null + + update_underlays() return null \ No newline at end of file diff --git a/code/ATMOSPHERICS/components/tvalve.dm b/code/ATMOSPHERICS/components/tvalve.dm index 83f592c315..603feb0294 100644 --- a/code/ATMOSPHERICS/components/tvalve.dm +++ b/code/ATMOSPHERICS/components/tvalve.dm @@ -1,10 +1,11 @@ -obj/machinery/atmospherics/tvalve - icon = 'icons/obj/atmospherics/valve.dmi' - icon_state = "tvalve0" +/obj/machinery/atmospherics/tvalve + icon = 'icons/atmos/tvalve.dmi' + icon_state = "map_tvalve0" name = "manual switching valve" desc = "A pipe valve" + level = 1 dir = SOUTH initialize_directions = SOUTH|NORTH|WEST @@ -19,415 +20,466 @@ obj/machinery/atmospherics/tvalve var/datum/pipe_network/network_node2 var/datum/pipe_network/network_node3 - update_icon(animation) - if(animation) - flick("tvalve[src.state][!src.state]",src) +/obj/machinery/atmospherics/tvalve/bypass + icon_state = "map_tvalve1" + state = 1 + +/obj/machinery/atmospherics/tvalve/update_icon(animation) + if(animation) + flick("tvalve[src.state][!src.state]",src) + else + icon_state = "tvalve[state]" + +/obj/machinery/atmospherics/tvalve/update_underlays() + if(..()) + underlays.Cut() + var/turf/T = get_turf(src) + if(!istype(T)) + return + add_underlay(T, node1, turn(dir, -180)) + + if(istype(src, /obj/machinery/atmospherics/tvalve/mirrored)) + add_underlay(T, node2, turn(dir, 90)) else - icon_state = "tvalve[state]" + add_underlay(T, node2, turn(dir, -90)) + + add_underlay(T, node3, dir) - New() - initialize_directions() - ..() - - proc/initialize_directions() - switch(dir) - if(NORTH) - initialize_directions = SOUTH|NORTH|EAST - if(SOUTH) - initialize_directions = NORTH|SOUTH|WEST - if(EAST) - initialize_directions = WEST|EAST|SOUTH - if(WEST) - initialize_directions = EAST|WEST|NORTH - - network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference) - if(reference == node1) - network_node1 = new_network - if(state) - network_node2 = new_network - else - network_node3 = new_network - else if(reference == node2) - network_node2 = new_network - if(state) - network_node1 = new_network - else if(reference == node3) - network_node3 = new_network - if(!state) - network_node1 = new_network - - if(new_network.normal_members.Find(src)) - return 0 - - new_network.normal_members += src - - if(state) - if(reference == node1) - if(node2) - return node2.network_expand(new_network, src) - else if(reference == node2) - if(node1) - return node1.network_expand(new_network, src) - else - if(reference == node1) - if(node3) - return node3.network_expand(new_network, src) - else if(reference == node3) - if(node1) - return node1.network_expand(new_network, src) - - return null - - Del() - loc = null - - if(node1) - node1.disconnect(src) - del(network_node1) - if(node2) - node2.disconnect(src) - del(network_node2) - if(node3) - node3.disconnect(src) - del(network_node3) - - node1 = null - node2 = null - node3 = null - - ..() - - proc/go_to_side() - - if(state) return 0 - - state = 1 - update_icon() - - if(network_node1) - del(network_node1) - if(network_node3) - del(network_node3) - build_network() - - if(network_node1&&network_node2) - network_node1.merge(network_node2) - network_node2 = network_node1 - - if(network_node1) - network_node1.update = 1 - else if(network_node2) - network_node2.update = 1 - - return 1 - - proc/go_straight() - - if(!state) - return 0 - - state = 0 - update_icon() - - if(network_node1) - del(network_node1) - if(network_node2) - del(network_node2) - build_network() - - if(network_node1&&network_node3) - network_node1.merge(network_node3) - network_node3 = network_node1 - - if(network_node1) - network_node1.update = 1 - else if(network_node3) - network_node3.update = 1 - - return 1 - - attack_ai(mob/user as mob) - return - - attack_paw(mob/user as mob) - return attack_hand(user) - - attack_hand(mob/user as mob) - src.add_fingerprint(usr) - update_icon(1) - sleep(10) - if (src.state) - src.go_straight() - else - src.go_to_side() - - process() - ..() - machines.Remove(src) - -/* if(open && (!node1 || !node2)) - close() - if(!node1) - if(!nodealert) - //world << "Missing node from [src] at [src.x],[src.y],[src.z]" - nodealert = 1 - else if (!node2) - if(!nodealert) - //world << "Missing node from [src] at [src.x],[src.y],[src.z]" - nodealert = 1 - else if (nodealert) - nodealert = 0 -*/ - - return - - initialize() - var/node1_dir - var/node2_dir - var/node3_dir - - node1_dir = turn(dir, 180) - node2_dir = turn(dir, -90) - node3_dir = dir - - for(var/obj/machinery/atmospherics/target in get_step(src,node1_dir)) - if(target.initialize_directions & get_dir(target,src)) - node1 = target - break - for(var/obj/machinery/atmospherics/target in get_step(src,node2_dir)) - if(target.initialize_directions & get_dir(target,src)) - node2 = target - break - for(var/obj/machinery/atmospherics/target in get_step(src,node3_dir)) - if(target.initialize_directions & get_dir(target,src)) - node3 = target - break - - build_network() - if(!network_node1 && node1) - network_node1 = new /datum/pipe_network() - network_node1.normal_members += src - network_node1.build_network(node1, src) - - if(!network_node2 && node2) - network_node2 = new /datum/pipe_network() - network_node2.normal_members += src - network_node2.build_network(node2, src) - - if(!network_node3 && node3) - network_node3 = new /datum/pipe_network() - network_node3.normal_members += src - network_node3.build_network(node3, src) - - - return_network(obj/machinery/atmospherics/reference) - build_network() - - if(reference==node1) - return network_node1 - - if(reference==node2) - return network_node2 - - if(reference==node3) - return network_node3 - - return null - - reassign_network(datum/pipe_network/old_network, datum/pipe_network/new_network) - if(network_node1 == old_network) - network_node1 = new_network - if(network_node2 == old_network) - network_node2 = new_network - if(network_node3 == old_network) - network_node3 = new_network - - return 1 - - return_network_air(datum/network/reference) - return null - - disconnect(obj/machinery/atmospherics/reference) - if(reference==node1) - del(network_node1) - node1 = null - - else if(reference==node2) - del(network_node2) - node2 = null - - else if(reference==node3) - del(network_node3) - node2 = null - - return null - - digital // can be controlled by AI - name = "digital switching valve" - desc = "A digitally controlled valve." - icon = 'icons/obj/atmospherics/digital_valve.dmi' - - attack_ai(mob/user as mob) - return src.attack_hand(user) - - attack_hand(mob/user as mob) - if(!src.allowed(user)) - user << "\red Access denied." - return - ..() - - //Radio remote control - - proc - set_frequency(new_frequency) - radio_controller.remove_object(src, frequency) - frequency = new_frequency - if(frequency) - radio_connection = radio_controller.add_object(src, frequency, RADIO_ATMOSIA) - - var/frequency = 0 - var/id = null - var/datum/radio_frequency/radio_connection - - initialize() - ..() - if(frequency) - set_frequency(frequency) - - receive_signal(datum/signal/signal) - if(!signal.data["tag"] || (signal.data["tag"] != id)) - return 0 - - switch(signal.data["command"]) - if("valve_open") - if(!state) - go_to_side() - - if("valve_close") - if(state) - go_straight() - - if("valve_toggle") - if(state) - go_straight() - else - go_to_side() - - attackby(var/obj/item/weapon/W as obj, var/mob/user as mob) - if (!istype(W, /obj/item/weapon/wrench)) - return ..() - if (istype(src, /obj/machinery/atmospherics/tvalve/digital)) - user << "\red You cannot unwrench this [src], it's too complicated." - return 1 - var/turf/T = src.loc - if (level==1 && isturf(T) && T.intact) - user << "\red You must remove the plating first." - return 1 - var/datum/gas_mixture/int_air = return_air() - var/datum/gas_mixture/env_air = loc.return_air() - if ((int_air.return_pressure()-env_air.return_pressure()) > 2*ONE_ATMOSPHERE) - user << "\red You cannot unwrench this [src], it too exerted due to internal pressure." - add_fingerprint(user) - return 1 - playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) - user << "\blue You begin to unfasten \the [src]..." - if (do_after(user, 40)) - user.visible_message( \ - "[user] unfastens \the [src].", \ - "\blue You have unfastened \the [src].", \ - "You hear ratchet.") - new /obj/item/pipe(loc, make_from=src) - del(src) - -obj/machinery/atmospherics/tvalve/mirrored - icon_state = "tvalvem0" +/obj/machinery/atmospherics/tvalve/hide(var/i) + update_underlays() +/obj/machinery/atmospherics/tvalve/New() initialize_directions() - switch(dir) - if(NORTH) - initialize_directions = SOUTH|NORTH|WEST - if(SOUTH) - initialize_directions = NORTH|SOUTH|EAST - if(EAST) - initialize_directions = WEST|EAST|NORTH - if(WEST) - initialize_directions = EAST|WEST|SOUTH + ..() - initialize() - var/node1_dir - var/node2_dir - var/node3_dir +/obj/machinery/atmospherics/tvalve/proc/initialize_directions() + switch(dir) + if(NORTH) + initialize_directions = SOUTH|NORTH|EAST + if(SOUTH) + initialize_directions = NORTH|SOUTH|WEST + if(EAST) + initialize_directions = WEST|EAST|SOUTH + if(WEST) + initialize_directions = EAST|WEST|NORTH - node1_dir = turn(dir, 180) - node2_dir = turn(dir, 90) - node3_dir = dir - - for(var/obj/machinery/atmospherics/target in get_step(src,node1_dir)) - if(target.initialize_directions & get_dir(target,src)) - node1 = target - break - for(var/obj/machinery/atmospherics/target in get_step(src,node2_dir)) - if(target.initialize_directions & get_dir(target,src)) - node2 = target - break - for(var/obj/machinery/atmospherics/target in get_step(src,node3_dir)) - if(target.initialize_directions & get_dir(target,src)) - node3 = target - break - - update_icon(animation) - if(animation) - flick("tvalvem[src.state][!src.state]",src) +/obj/machinery/atmospherics/tvalve/network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference) + if(reference == node1) + network_node1 = new_network + if(state) + network_node2 = new_network else - icon_state = "tvalvem[state]" + network_node3 = new_network + else if(reference == node2) + network_node2 = new_network + if(state) + network_node1 = new_network + else if(reference == node3) + network_node3 = new_network + if(!state) + network_node1 = new_network - digital // can be controlled by AI - name = "digital switching valve" - desc = "A digitally controlled valve." - icon = 'icons/obj/atmospherics/digital_valve.dmi' + if(new_network.normal_members.Find(src)) + return 0 - attack_ai(mob/user as mob) - return src.attack_hand(user) + new_network.normal_members += src - attack_hand(mob/user as mob) - if(!src.allowed(user)) - user << "\red Access denied." - return - ..() + if(state) + if(reference == node1) + if(node2) + return node2.network_expand(new_network, src) + else if(reference == node2) + if(node1) + return node1.network_expand(new_network, src) + else + if(reference == node1) + if(node3) + return node3.network_expand(new_network, src) + else if(reference == node3) + if(node1) + return node1.network_expand(new_network, src) - //Radio remote control -eh? + return null - proc - set_frequency(new_frequency) - radio_controller.remove_object(src, frequency) - frequency = new_frequency - if(frequency) - radio_connection = radio_controller.add_object(src, frequency, RADIO_ATMOSIA) +/obj/machinery/atmospherics/tvalve/Del() + loc = null - var/frequency = 0 - var/id = null - var/datum/radio_frequency/radio_connection + if(node1) + node1.disconnect(src) + del(network_node1) + if(node2) + node2.disconnect(src) + del(network_node2) + if(node3) + node3.disconnect(src) + del(network_node3) - initialize() - ..() - if(frequency) - set_frequency(frequency) + node1 = null + node2 = null + node3 = null - receive_signal(datum/signal/signal) - if(!signal.data["tag"] || (signal.data["tag"] != id)) - return 0 + ..() - switch(signal.data["command"]) - if("valve_open") - if(!state) - go_to_side() +/obj/machinery/atmospherics/tvalve/proc/go_to_side() - if("valve_close") - if(state) - go_straight() + if(state) return 0 - if("valve_toggle") - if(state) - go_straight() - else - go_to_side() \ No newline at end of file + state = 1 + update_icon() + + if(network_node1) + del(network_node1) + if(network_node3) + del(network_node3) + build_network() + + if(network_node1&&network_node2) + network_node1.merge(network_node2) + network_node2 = network_node1 + + if(network_node1) + network_node1.update = 1 + else if(network_node2) + network_node2.update = 1 + + return 1 + +/obj/machinery/atmospherics/tvalve/proc/go_straight() + + if(!state) + return 0 + + state = 0 + update_icon() + + if(network_node1) + del(network_node1) + if(network_node2) + del(network_node2) + build_network() + + if(network_node1&&network_node3) + network_node1.merge(network_node3) + network_node3 = network_node1 + + if(network_node1) + network_node1.update = 1 + else if(network_node3) + network_node3.update = 1 + + return 1 + +/obj/machinery/atmospherics/tvalve/attack_ai(mob/user as mob) + return + +/obj/machinery/atmospherics/tvalve/attack_paw(mob/user as mob) + return attack_hand(user) + +/obj/machinery/atmospherics/tvalve/attack_hand(mob/user as mob) + src.add_fingerprint(usr) + update_icon(1) + sleep(10) + if (src.state) + src.go_straight() + else + src.go_to_side() + +/obj/machinery/atmospherics/tvalve/process() + ..() + . = PROCESS_KILL + //machines.Remove(src) + + return + +/obj/machinery/atmospherics/tvalve/initialize() + var/node1_dir + var/node2_dir + var/node3_dir + + node1_dir = turn(dir, 180) + node2_dir = turn(dir, -90) + node3_dir = dir + + for(var/obj/machinery/atmospherics/target in get_step(src,node1_dir)) + if(target.initialize_directions & get_dir(target,src)) + node1 = target + break + for(var/obj/machinery/atmospherics/target in get_step(src,node2_dir)) + if(target.initialize_directions & get_dir(target,src)) + node2 = target + break + for(var/obj/machinery/atmospherics/target in get_step(src,node3_dir)) + if(target.initialize_directions & get_dir(target,src)) + node3 = target + break + + update_icon() + update_underlays() + +/obj/machinery/atmospherics/tvalve/build_network() + if(!network_node1 && node1) + network_node1 = new /datum/pipe_network() + network_node1.normal_members += src + network_node1.build_network(node1, src) + + if(!network_node2 && node2) + network_node2 = new /datum/pipe_network() + network_node2.normal_members += src + network_node2.build_network(node2, src) + + if(!network_node3 && node3) + network_node3 = new /datum/pipe_network() + network_node3.normal_members += src + network_node3.build_network(node3, src) + + +/obj/machinery/atmospherics/tvalve/return_network(obj/machinery/atmospherics/reference) + build_network() + + if(reference==node1) + return network_node1 + + if(reference==node2) + return network_node2 + + if(reference==node3) + return network_node3 + + return null + +/obj/machinery/atmospherics/tvalve/reassign_network(datum/pipe_network/old_network, datum/pipe_network/new_network) + if(network_node1 == old_network) + network_node1 = new_network + if(network_node2 == old_network) + network_node2 = new_network + if(network_node3 == old_network) + network_node3 = new_network + + return 1 + +/obj/machinery/atmospherics/tvalve/return_network_air(datum/network/reference) + return null + +/obj/machinery/atmospherics/tvalve/disconnect(obj/machinery/atmospherics/reference) + if(reference==node1) + del(network_node1) + node1 = null + + else if(reference==node2) + del(network_node2) + node2 = null + + else if(reference==node3) + del(network_node3) + node2 = null + + update_underlays() + + return null + +/obj/machinery/atmospherics/tvalve/digital // can be controlled by AI + name = "digital switching valve" + desc = "A digitally controlled valve." + icon = 'icons/atmos/digital_tvalve.dmi' + + var/frequency = 0 + var/id = null + var/datum/radio_frequency/radio_connection + +/obj/machinery/atmospherics/tvalve/digital/bypass + icon_state = "map_tvalve1" + state = 1 + +/obj/machinery/atmospherics/tvalve/digital/power_change() + var/old_stat = stat + ..() + if(old_stat != stat) + update_icon() + +/obj/machinery/atmospherics/tvalve/digital/update_icon() + ..() + if(!powered()) + icon_state = "tvalvenopower" + +/obj/machinery/atmospherics/tvalve/digital/attack_ai(mob/user as mob) + return src.attack_hand(user) + +/obj/machinery/atmospherics/tvalve/digital/attack_hand(mob/user as mob) + if(!powered()) + return + if(!src.allowed(user)) + user << "\red Access denied." + return + ..() + +//Radio remote control + +/obj/machinery/atmospherics/tvalve/digital/proc/set_frequency(new_frequency) + radio_controller.remove_object(src, frequency) + frequency = new_frequency + if(frequency) + radio_connection = radio_controller.add_object(src, frequency, RADIO_ATMOSIA) + + + +/obj/machinery/atmospherics/tvalve/digital/initialize() + ..() + if(frequency) + set_frequency(frequency) + +/obj/machinery/atmospherics/tvalve/digital/receive_signal(datum/signal/signal) + if(!signal.data["tag"] || (signal.data["tag"] != id)) + return 0 + + switch(signal.data["command"]) + if("valve_open") + if(!state) + go_to_side() + + if("valve_close") + if(state) + go_straight() + + if("valve_toggle") + if(state) + go_straight() + else + go_to_side() + +/obj/machinery/atmospherics/tvalve/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob) + if (!istype(W, /obj/item/weapon/wrench)) + return ..() + if (istype(src, /obj/machinery/atmospherics/tvalve/digital)) + user << "\red You cannot unwrench this [src], it's too complicated." + return 1 + var/datum/gas_mixture/int_air = return_air() + var/datum/gas_mixture/env_air = loc.return_air() + if ((int_air.return_pressure()-env_air.return_pressure()) > 2*ONE_ATMOSPHERE) + user << "\red You cannot unwrench this [src], it too exerted due to internal pressure." + add_fingerprint(user) + return 1 + playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) + user << "\blue You begin to unfasten \the [src]..." + if (do_after(user, 40)) + user.visible_message( \ + "[user] unfastens \the [src].", \ + "\blue You have unfastened \the [src].", \ + "You hear ratchet.") + new /obj/item/pipe(loc, make_from=src) + del(src) + +/obj/machinery/atmospherics/tvalve/mirrored + icon_state = "map_tvalvem0" + +/obj/machinery/atmospherics/tvalve/mirrored/bypass + icon_state = "map_tvalvem1" + state = 1 + +/obj/machinery/atmospherics/tvalve/mirrored/initialize_directions() + switch(dir) + if(NORTH) + initialize_directions = SOUTH|NORTH|WEST + if(SOUTH) + initialize_directions = NORTH|SOUTH|EAST + if(EAST) + initialize_directions = WEST|EAST|NORTH + if(WEST) + initialize_directions = EAST|WEST|SOUTH + +/obj/machinery/atmospherics/tvalve/mirrored/initialize() + var/node1_dir + var/node2_dir + var/node3_dir + + node1_dir = turn(dir, 180) + node2_dir = turn(dir, 90) + node3_dir = dir + + for(var/obj/machinery/atmospherics/target in get_step(src,node1_dir)) + if(target.initialize_directions & get_dir(target,src)) + node1 = target + break + for(var/obj/machinery/atmospherics/target in get_step(src,node2_dir)) + if(target.initialize_directions & get_dir(target,src)) + node2 = target + break + for(var/obj/machinery/atmospherics/target in get_step(src,node3_dir)) + if(target.initialize_directions & get_dir(target,src)) + node3 = target + break + + update_icon() + update_underlays() + +/obj/machinery/atmospherics/tvalve/mirrored/update_icon(animation) + if(animation) + flick("tvalvem[src.state][!src.state]",src) + else + icon_state = "tvalvem[state]" + +/obj/machinery/atmospherics/tvalve/mirrored/digital // can be controlled by AI + name = "digital switching valve" + desc = "A digitally controlled valve." + icon = 'icons/atmos/digital_tvalve.dmi' + + var/frequency = 0 + var/id = null + var/datum/radio_frequency/radio_connection + +/obj/machinery/atmospherics/tvalve/mirrored/digital/bypass + icon_state = "map_tvalvem1" + state = 1 + +/obj/machinery/atmospherics/tvalve/mirrored/digital/power_change() + var/old_stat = stat + ..() + if(old_stat != stat) + update_icon() + +/obj/machinery/atmospherics/tvalve/mirrored/digital/update_icon() + ..() + if(!powered()) + icon_state = "tvalvemnopower" + +/obj/machinery/atmospherics/tvalve/mirrored/digital/attack_ai(mob/user as mob) + return src.attack_hand(user) + +/obj/machinery/atmospherics/tvalve/mirrored/digital/attack_hand(mob/user as mob) + if(!powered()) + return + if(!src.allowed(user)) + user << "\red Access denied." + return + ..() + +//Radio remote control -eh? + +/obj/machinery/atmospherics/tvalve/mirrored/digital/proc/set_frequency(new_frequency) + radio_controller.remove_object(src, frequency) + frequency = new_frequency + if(frequency) + radio_connection = radio_controller.add_object(src, frequency, RADIO_ATMOSIA) + +/obj/machinery/atmospherics/tvalve/mirrored/digital/initialize() + ..() + if(frequency) + set_frequency(frequency) + +/obj/machinery/atmospherics/tvalve/mirrored/digital/receive_signal(datum/signal/signal) + if(!signal.data["tag"] || (signal.data["tag"] != id)) + return 0 + + switch(signal.data["command"]) + if("valve_open") + if(!state) + go_to_side() + + if("valve_close") + if(state) + go_straight() + + if("valve_toggle") + if(state) + go_straight() + else + go_to_side() \ No newline at end of file diff --git a/code/ATMOSPHERICS/components/unary/outlet_injector.dm b/code/ATMOSPHERICS/components/unary/outlet_injector.dm index f070882ba8..c821b629e0 100644 --- a/code/ATMOSPHERICS/components/unary/outlet_injector.dm +++ b/code/ATMOSPHERICS/components/unary/outlet_injector.dm @@ -1,7 +1,8 @@ /obj/machinery/atmospherics/unary/outlet_injector - icon = 'icons/obj/atmospherics/outlet_injector.dmi' - icon_state = "off" + icon = 'icons/atmos/injector.dmi' + icon_state = "map_injector" use_power = 1 + layer = 3 name = "Air Injector" desc = "Has a valve and pump attached to it" @@ -17,131 +18,122 @@ level = 1 - update_icon() - if(node) - if(on && !(stat & NOPOWER)) - icon_state = "[level == 1 && istype(loc, /turf/simulated) ? "h" : "" ]on" - else - icon_state = "[level == 1 && istype(loc, /turf/simulated) ? "h" : "" ]off" - else - icon_state = "exposed" - on = 0 +/obj/machinery/atmospherics/unary/outlet_injector/update_icon() + if(!powered()) + icon_state = "off" + else + icon_state = "[on ? "on" : "off"]" - return - - power_change() - var/old_stat = stat - ..() - if(old_stat != stat) - update_icon() - - - process() - ..() - injecting = 0 - - if(!on || stat & NOPOWER) - return 0 - - if(air_contents.temperature > 0) - var/transfer_moles = (air_contents.return_pressure())*volume_rate/(air_contents.temperature * R_IDEAL_GAS_EQUATION) - - var/datum/gas_mixture/removed = air_contents.remove(transfer_moles) - - loc.assume_air(removed) - - if(network) - network.update = 1 - - return 1 - - proc/inject() - if(on || injecting) - return 0 - - injecting = 1 - - if(air_contents.temperature > 0) - var/transfer_moles = (air_contents.return_pressure())*volume_rate/(air_contents.temperature * R_IDEAL_GAS_EQUATION) - - var/datum/gas_mixture/removed = air_contents.remove(transfer_moles) - - loc.assume_air(removed) - - if(network) - network.update = 1 - - flick("inject", src) - - proc - set_frequency(new_frequency) - radio_controller.remove_object(src, frequency) - frequency = new_frequency - if(frequency) - radio_connection = radio_controller.add_object(src, frequency) - - broadcast_status() - if(!radio_connection) - return 0 - - var/datum/signal/signal = new - signal.transmission_method = 1 //radio signal - signal.source = src - - signal.data = list( - "tag" = id, - "device" = "AO", - "power" = on, - "volume_rate" = volume_rate, - //"timestamp" = world.time, - "sigtype" = "status" - ) - - radio_connection.post_signal(src, signal) - - return 1 - - initialize() - ..() - - set_frequency(frequency) - - receive_signal(datum/signal/signal) - if(!signal.data["tag"] || (signal.data["tag"] != id) || (signal.data["sigtype"]!="command")) - return 0 - - if("power" in signal.data) - on = text2num(signal.data["power"]) - - if("power_toggle" in signal.data) - on = !on - - if("inject" in signal.data) - spawn inject() +/obj/machinery/atmospherics/unary/outlet_injector/update_underlays() + if(..()) + underlays.Cut() + var/turf/T = get_turf(src) + if(!istype(T)) return + add_underlay(T, node, dir) - if("set_volume_rate" in signal.data) - var/number = text2num(signal.data["set_volume_rate"]) - volume_rate = between(0, number, air_contents.volume) - - if("status" in signal.data) - spawn(2) - broadcast_status() - return //do not update_icon - - //log_admin("DEBUG \[[world.timeofday]\]: outlet_injector/receive_signal: unknown command \"[signal.data["command"]]\"\n[signal.debug_print()]") - //return - spawn(2) - broadcast_status() +/obj/machinery/atmospherics/unary/outlet_injector/power_change() + var/old_stat = stat + ..() + if(old_stat != stat) update_icon() - hide(var/i) //to make the little pipe section invisible, the icon changes. - if(node) - if(on) - icon_state = "[i == 1 && istype(loc, /turf/simulated) ? "h" : "" ]on" - else - icon_state = "[i == 1 && istype(loc, /turf/simulated) ? "h" : "" ]off" - else - icon_state = "[i == 1 && istype(loc, /turf/simulated) ? "h" : "" ]exposed" - on = 0 - return \ No newline at end of file +/obj/machinery/atmospherics/unary/outlet_injector/process() + ..() + injecting = 0 + + if(!on || stat & NOPOWER) + return 0 + + if(air_contents.temperature > 0) + var/transfer_moles = (air_contents.return_pressure())*volume_rate/(air_contents.temperature * R_IDEAL_GAS_EQUATION) + + var/datum/gas_mixture/removed = air_contents.remove(transfer_moles) + + loc.assume_air(removed) + + if(network) + network.update = 1 + + return 1 + +/obj/machinery/atmospherics/unary/outlet_injector/proc/inject() + if(on || injecting) + return 0 + + injecting = 1 + + if(air_contents.temperature > 0) + var/transfer_moles = (air_contents.return_pressure())*volume_rate/(air_contents.temperature * R_IDEAL_GAS_EQUATION) + + var/datum/gas_mixture/removed = air_contents.remove(transfer_moles) + + loc.assume_air(removed) + + if(network) + network.update = 1 + + flick("inject", src) + +/obj/machinery/atmospherics/unary/outlet_injector/proc/set_frequency(new_frequency) + radio_controller.remove_object(src, frequency) + frequency = new_frequency + if(frequency) + radio_connection = radio_controller.add_object(src, frequency) + +/obj/machinery/atmospherics/unary/outlet_injector/proc/broadcast_status() + if(!radio_connection) + return 0 + + var/datum/signal/signal = new + signal.transmission_method = 1 //radio signal + signal.source = src + + signal.data = list( + "tag" = id, + "device" = "AO", + "power" = on, + "volume_rate" = volume_rate, + "sigtype" = "status" + ) + + radio_connection.post_signal(src, signal) + + return 1 + +/obj/machinery/atmospherics/unary/outlet_injector/initialize() + ..() + + set_frequency(frequency) + +/obj/machinery/atmospherics/unary/outlet_injector/receive_signal(datum/signal/signal) + if(!signal.data["tag"] || (signal.data["tag"] != id) || (signal.data["sigtype"]!="command")) + return 0 + + if(signal.data["power"]) + on = text2num(signal.data["power"]) + + if(signal.data["power_toggle"]) + on = !on + + if(signal.data["inject"]) + spawn inject() + return + + if(signal.data["set_volume_rate"]) + var/number = text2num(signal.data["set_volume_rate"]) + volume_rate = between(0, number, air_contents.volume) + + if(signal.data["status"]) + spawn(2) + broadcast_status() + return //do not update_icon + + //log_admin("DEBUG \[[world.timeofday]\]: outlet_injector/receive_signal: unknown command \"[signal.data["command"]]\"\n[signal.debug_print()]") + //return + spawn(2) + broadcast_status() + update_icon() + +/obj/machinery/atmospherics/unary/outlet_injector/hide(var/i) + update_underlays() \ No newline at end of file diff --git a/code/ATMOSPHERICS/components/unary/unary_base.dm b/code/ATMOSPHERICS/components/unary/unary_base.dm index b755071487..2c5f63f607 100644 --- a/code/ATMOSPHERICS/components/unary/unary_base.dm +++ b/code/ATMOSPHERICS/components/unary/unary_base.dm @@ -50,6 +50,7 @@ break update_icon() + update_underlays() build_network() if(!network && node) @@ -85,4 +86,7 @@ del(network) node = null + update_icon() + update_underlays() + return null \ No newline at end of file diff --git a/code/ATMOSPHERICS/components/unary/vent_pump.dm b/code/ATMOSPHERICS/components/unary/vent_pump.dm index f4e9cb9750..e2cd25cfba 100644 --- a/code/ATMOSPHERICS/components/unary/vent_pump.dm +++ b/code/ATMOSPHERICS/components/unary/vent_pump.dm @@ -4,8 +4,8 @@ #undefine /obj/machinery/atmospherics/unary/vent_pump - icon = 'icons/obj/atmospherics/vent_pump.dmi' - icon_state = "off" + icon = 'icons/atmos/vent_pump.dmi' + icon_state = "map_vent" name = "Air Vent" desc = "Has a valve and pump attached to it" @@ -40,316 +40,329 @@ var/radio_filter_out var/radio_filter_in - on - on = 1 - icon_state = "out" +/obj/machinery/atmospherics/unary/vent_pump/on + on = 1 + icon_state = "map_vent_out" - siphon - pump_direction = 0 - icon_state = "off" +/obj/machinery/atmospherics/unary/vent_pump/siphon + pump_direction = 0 - on - on = 1 - icon_state = "in" +/obj/machinery/atmospherics/unary/vent_pump/siphon/on + on = 1 + icon_state = "map_vent_in" - New() - initial_loc = get_area(loc) - if (initial_loc.master) - initial_loc = initial_loc.master - area_uid = initial_loc.uid - if (!id_tag) - assign_uid() - id_tag = num2text(uid) - if(ticker && ticker.current_state == 3)//if the game is running - src.initialize() - src.broadcast_status() - ..() +/obj/machinery/atmospherics/unary/vent_pump/New() + icon = null + initial_loc = get_area(loc) + if (initial_loc.master) + initial_loc = initial_loc.master + area_uid = initial_loc.uid + if (!id_tag) + assign_uid() + id_tag = num2text(uid) + if(ticker && ticker.current_state == 3)//if the game is running + src.initialize() + src.broadcast_status() + ..() - high_volume - name = "Large Air Vent" - power_channel = EQUIP - New() - ..() - air_contents.volume = 1000 +/obj/machinery/atmospherics/unary/vent_pump/high_volume + name = "Large Air Vent" + power_channel = EQUIP - update_icon() - if(welded) - icon_state = "[level == 1 && istype(loc, /turf/simulated) ? "h" : "" ]weld" - return - if(on && !(stat & (NOPOWER|BROKEN))) - if(pump_direction) - icon_state = "[level == 1 && istype(loc, /turf/simulated) ? "h" : "" ]out" - else - icon_state = "[level == 1 && istype(loc, /turf/simulated) ? "h" : "" ]in" - else - icon_state = "[level == 1 && istype(loc, /turf/simulated) ? "h" : "" ]off" +/obj/machinery/atmospherics/unary/vent_pump/high_volume/New() + ..() + air_contents.volume = 1000 +/obj/machinery/atmospherics/unary/vent_pump/update_icon(var/safety = 0) + if(!check_icon_cache()) return - process() - ..() - if(stat & (NOPOWER|BROKEN)) + overlays.Cut() + + var/vent_icon = "vent" + + var/turf/T = get_turf(src) + if(!istype(T)) + return + + if(T.intact && node && node.level == 1 && istype(node, /obj/machinery/atmospherics/pipe)) + vent_icon += "h" + + if(welded) + vent_icon += "weld" + else if(!powered()) + vent_icon += "off" + else + vent_icon += "[on ? "[pump_direction ? "out" : "in"]" : "off"]" + + overlays += icon_manager.get_atmos_icon("device", , , vent_icon) + +/obj/machinery/atmospherics/unary/vent_pump/update_underlays() + if(..()) + underlays.Cut() + var/turf/T = get_turf(src) + if(!istype(T)) return - if (!node) - on = 0 - //broadcast_status() // from now air alarm/control computer should request update purposely --rastaf0 - if(!on) - return 0 - - if(welded) - return 0 - - var/datum/gas_mixture/environment = loc.return_air() - var/environment_pressure = environment.return_pressure() - - if(pump_direction) //internal -> external - var/pressure_delta = 10000 - - if(pressure_checks&1) - pressure_delta = min(pressure_delta, (external_pressure_bound - environment_pressure)) - if(pressure_checks&2) - pressure_delta = min(pressure_delta, (air_contents.return_pressure() - internal_pressure_bound)) - - if(pressure_delta > 0.5) - if(air_contents.temperature > 0) - var/transfer_moles = pressure_delta*environment.volume/(air_contents.temperature * R_IDEAL_GAS_EQUATION) - - var/datum/gas_mixture/removed = air_contents.remove(transfer_moles) - - loc.assume_air(removed) - - if(network) - network.update = 1 - - else //external -> internal - var/pressure_delta = 10000 - if(pressure_checks&1) - pressure_delta = min(pressure_delta, (environment_pressure - external_pressure_bound)) - if(pressure_checks&2) - pressure_delta = min(pressure_delta, (internal_pressure_bound - air_contents.return_pressure())) - - if(pressure_delta > 0.5) - if(environment.temperature > 0) - var/transfer_moles = pressure_delta*air_contents.volume/(environment.temperature * R_IDEAL_GAS_EQUATION) - - var/datum/gas_mixture/removed = loc.remove_air(transfer_moles) - if (isnull(removed)) //in space - return - - air_contents.merge(removed) - - if(network) - network.update = 1 - - return 1 - - //Radio remote control - - proc - set_frequency(new_frequency) - radio_controller.remove_object(src, frequency) - frequency = new_frequency - if(frequency) - radio_connection = radio_controller.add_object(src, frequency,radio_filter_in) - - broadcast_status() - if(!radio_connection) - return 0 - - var/datum/signal/signal = new - signal.transmission_method = 1 //radio signal - signal.source = src - - signal.data = list( - "area" = src.area_uid, - "tag" = src.id_tag, - "device" = "AVP", - "power" = on, - "direction" = pump_direction?("release"):("siphon"), - "checks" = pressure_checks, - "internal" = internal_pressure_bound, - "external" = external_pressure_bound, - "timestamp" = world.time, - "sigtype" = "status" - ) - - if(!initial_loc.air_vent_names[id_tag]) - var/new_name = "[initial_loc.name] Vent Pump #[initial_loc.air_vent_names.len+1]" - initial_loc.air_vent_names[id_tag] = new_name - src.name = new_name - initial_loc.air_vent_info[id_tag] = signal.data - - radio_connection.post_signal(src, signal, radio_filter_out) - - return 1 - - - initialize() - ..() - - //some vents work his own spesial way - radio_filter_in = frequency==1439?(RADIO_FROM_AIRALARM):null - radio_filter_out = frequency==1439?(RADIO_TO_AIRALARM):null - if(frequency) - set_frequency(frequency) - - receive_signal(datum/signal/signal) - if(stat & (NOPOWER|BROKEN)) + if(T.intact && node && node.level == 1 && istype(node, /obj/machinery/atmospherics/pipe)) return - //log_admin("DEBUG \[[world.timeofday]\]: /obj/machinery/atmospherics/unary/vent_pump/receive_signal([signal.debug_print()])") - if(!signal.data["tag"] || (signal.data["tag"] != id_tag) || (signal.data["sigtype"]!="command")) - return 0 + else + add_underlay(T, node, dir) - if(signal.data["purge"] != null) - pressure_checks &= ~1 - pump_direction = 0 +/obj/machinery/atmospherics/unary/vent_pump/hide() + update_icon() + update_underlays() - if(signal.data["stabalize"] != null) - pressure_checks |= 1 - pump_direction = 1 +/obj/machinery/atmospherics/unary/vent_pump/process() + ..() + if(stat & (NOPOWER|BROKEN)) + return + if (!node) + on = 0 + //broadcast_status() // from now air alarm/control computer should request update purposely --rastaf0 + if(!on) + return 0 - if(signal.data["power"] != null) - on = text2num(signal.data["power"]) + if(welded) + return 0 - if(signal.data["power_toggle"] != null) - on = !on + var/datum/gas_mixture/environment = loc.return_air() + var/environment_pressure = environment.return_pressure() - if(signal.data["checks"] != null) - if (signal.data["checks"] == "default") - pressure_checks = pressure_checks_default - else - pressure_checks = text2num(signal.data["checks"]) + if(pump_direction) //internal -> external + var/pressure_delta = 10000 - if(signal.data["checks_toggle"] != null) - pressure_checks = (pressure_checks?0:3) + if(pressure_checks&1) + pressure_delta = min(pressure_delta, (external_pressure_bound - environment_pressure)) + if(pressure_checks&2) + pressure_delta = min(pressure_delta, (air_contents.return_pressure() - internal_pressure_bound)) - if(signal.data["direction"] != null) - pump_direction = text2num(signal.data["direction"]) + if(pressure_delta > 0.5) + if(air_contents.temperature > 0) + var/transfer_moles = pressure_delta*environment.volume/(air_contents.temperature * R_IDEAL_GAS_EQUATION) - if(signal.data["set_internal_pressure"] != null) - if (signal.data["set_internal_pressure"] == "default") - internal_pressure_bound = internal_pressure_bound_default - else - internal_pressure_bound = between( - 0, - text2num(signal.data["set_internal_pressure"]), - ONE_ATMOSPHERE*50 - ) + var/datum/gas_mixture/removed = air_contents.remove(transfer_moles) - if(signal.data["set_external_pressure"] != null) - if (signal.data["set_external_pressure"] == "default") - external_pressure_bound = external_pressure_bound_default - else - external_pressure_bound = between( - 0, - text2num(signal.data["set_external_pressure"]), - ONE_ATMOSPHERE*50 - ) + loc.assume_air(removed) - if(signal.data["adjust_internal_pressure"] != null) + if(network) + network.update = 1 + + else //external -> internal + var/pressure_delta = 10000 + if(pressure_checks&1) + pressure_delta = min(pressure_delta, (environment_pressure - external_pressure_bound)) + if(pressure_checks&2) + pressure_delta = min(pressure_delta, (internal_pressure_bound - air_contents.return_pressure())) + + if(pressure_delta > 0.5) + if(environment.temperature > 0) + var/transfer_moles = pressure_delta*air_contents.volume/(environment.temperature * R_IDEAL_GAS_EQUATION) + + var/datum/gas_mixture/removed = loc.remove_air(transfer_moles) + if (isnull(removed)) //in space + return + + air_contents.merge(removed) + + if(network) + network.update = 1 + + return 1 + +//Radio remote control + +/obj/machinery/atmospherics/unary/vent_pump/proc/set_frequency(new_frequency) + radio_controller.remove_object(src, frequency) + frequency = new_frequency + if(frequency) + radio_connection = radio_controller.add_object(src, frequency,radio_filter_in) + +/obj/machinery/atmospherics/unary/vent_pump/proc/broadcast_status() + if(!radio_connection) + return 0 + + var/datum/signal/signal = new + signal.transmission_method = 1 //radio signal + signal.source = src + + signal.data = list( + "area" = src.area_uid, + "tag" = src.id_tag, + "device" = "AVP", + "power" = on, + "direction" = pump_direction?("release"):("siphon"), + "checks" = pressure_checks, + "internal" = internal_pressure_bound, + "external" = external_pressure_bound, + "timestamp" = world.time, + "sigtype" = "status" + ) + + if(!initial_loc.air_vent_names[id_tag]) + var/new_name = "[initial_loc.name] Vent Pump #[initial_loc.air_vent_names.len+1]" + initial_loc.air_vent_names[id_tag] = new_name + src.name = new_name + initial_loc.air_vent_info[id_tag] = signal.data + + radio_connection.post_signal(src, signal, radio_filter_out) + + return 1 + + +/obj/machinery/atmospherics/unary/vent_pump/initialize() + ..() + + //some vents work his own spesial way + radio_filter_in = frequency==1439?(RADIO_FROM_AIRALARM):null + radio_filter_out = frequency==1439?(RADIO_TO_AIRALARM):null + if(frequency) + set_frequency(frequency) + +/obj/machinery/atmospherics/unary/vent_pump/receive_signal(datum/signal/signal) + if(stat & (NOPOWER|BROKEN)) + return + //log_admin("DEBUG \[[world.timeofday]\]: /obj/machinery/atmospherics/unary/vent_pump/receive_signal([signal.debug_print()])") + if(!signal.data["tag"] || (signal.data["tag"] != id_tag) || (signal.data["sigtype"]!="command")) + return 0 + + if(signal.data["purge"] != null) + pressure_checks &= ~1 + pump_direction = 0 + + if(signal.data["stabalize"] != null) + pressure_checks |= 1 + pump_direction = 1 + + if(signal.data["power"] != null) + on = text2num(signal.data["power"]) + + if(signal.data["power_toggle"] != null) + on = !on + + if(signal.data["checks"] != null) + if (signal.data["checks"] == "default") + pressure_checks = pressure_checks_default + else + pressure_checks = text2num(signal.data["checks"]) + + if(signal.data["checks_toggle"] != null) + pressure_checks = (pressure_checks?0:3) + + if(signal.data["direction"] != null) + pump_direction = text2num(signal.data["direction"]) + + if(signal.data["set_internal_pressure"] != null) + if (signal.data["set_internal_pressure"] == "default") + internal_pressure_bound = internal_pressure_bound_default + else internal_pressure_bound = between( 0, - internal_pressure_bound + text2num(signal.data["adjust_internal_pressure"]), + text2num(signal.data["set_internal_pressure"]), ONE_ATMOSPHERE*50 ) - if(signal.data["adjust_external_pressure"] != null) - - + if(signal.data["set_external_pressure"] != null) + if (signal.data["set_external_pressure"] == "default") + external_pressure_bound = external_pressure_bound_default + else external_pressure_bound = between( 0, - external_pressure_bound + text2num(signal.data["adjust_external_pressure"]), + text2num(signal.data["set_external_pressure"]), ONE_ATMOSPHERE*50 ) - if(signal.data["init"] != null) - name = signal.data["init"] - return + if(signal.data["adjust_internal_pressure"] != null) + internal_pressure_bound = between( + 0, + internal_pressure_bound + text2num(signal.data["adjust_internal_pressure"]), + ONE_ATMOSPHERE*50 + ) - if(signal.data["status"] != null) - spawn(2) - broadcast_status() - return //do not update_icon + if(signal.data["adjust_external_pressure"] != null) - //log_admin("DEBUG \[[world.timeofday]\]: vent_pump/receive_signal: unknown command \"[signal.data["command"]]\"\n[signal.debug_print()]") + + external_pressure_bound = between( + 0, + external_pressure_bound + text2num(signal.data["adjust_external_pressure"]), + ONE_ATMOSPHERE*50 + ) + + if(signal.data["init"] != null) + name = signal.data["init"] + return + + if(signal.data["status"] != null) spawn(2) broadcast_status() - update_icon() - return + return //do not update_icon - hide(var/i) //to make the little pipe section invisible, the icon changes. - if(welded) - icon_state = "[i == 1 && istype(loc, /turf/simulated) ? "h" : "" ]weld" - return - if(on&&node) - if(pump_direction) - icon_state = "[i == 1 && istype(loc, /turf/simulated) ? "h" : "" ]out" - else - icon_state = "[i == 1 && istype(loc, /turf/simulated) ? "h" : "" ]in" - else - icon_state = "[i == 1 && istype(loc, /turf/simulated) ? "h" : "" ]off" - on = 0 - return + //log_admin("DEBUG \[[world.timeofday]\]: vent_pump/receive_signal: unknown command \"[signal.data["command"]]\"\n[signal.debug_print()]") + spawn(2) + broadcast_status() + update_icon() + return - attackby(obj/item/W, mob/user) - if(istype(W, /obj/item/weapon/weldingtool)) - var/obj/item/weapon/weldingtool/WT = W - if (WT.remove_fuel(0,user)) - user << "\blue Now welding the vent." - if(do_after(user, 20)) - if(!src || !WT.isOn()) return - playsound(src.loc, 'sound/items/Welder2.ogg', 50, 1) - if(!welded) - user.visible_message("[user] welds the vent shut.", "You weld the vent shut.", "You hear welding.") - welded = 1 - update_icon() - else - user.visible_message("[user] unwelds the vent.", "You unweld the vent.", "You hear welding.") - welded = 0 - update_icon() +/obj/machinery/atmospherics/unary/vent_pump/attackby(obj/item/W, mob/user) + if(istype(W, /obj/item/weapon/weldingtool)) + var/obj/item/weapon/weldingtool/WT = W + if (WT.remove_fuel(0,user)) + user << "\blue Now welding the vent." + if(do_after(user, 20)) + if(!src || !WT.isOn()) return + playsound(src.loc, 'sound/items/Welder2.ogg', 50, 1) + if(!welded) + user.visible_message("[user] welds the vent shut.", "You weld the vent shut.", "You hear welding.") + welded = 1 + update_icon() else - user << "\blue The welding tool needs to be on to start this task." + user.visible_message("[user] unwelds the vent.", "You unweld the vent.", "You hear welding.") + welded = 0 + update_icon() else - user << "\blue You need more welding fuel to complete this task." - return 1 - examine() - set src in oview(1) - ..() - if(welded) - usr << "It seems welded shut." - - power_change() - if(powered(power_channel)) - stat &= ~NOPOWER + user << "\blue The welding tool needs to be on to start this task." else - stat |= NOPOWER + user << "\blue You need more welding fuel to complete this task." + return 1 + else + ..() + +/obj/machinery/atmospherics/unary/vent_pump/examine() + set src in oview(1) + ..() + if(welded) + usr << "It seems welded shut." + +/obj/machinery/atmospherics/unary/vent_pump/power_change() + var/old_stat = stat + ..() + if(old_stat != stat) update_icon() - attackby(var/obj/item/weapon/W as obj, var/mob/user as mob) - if (!istype(W, /obj/item/weapon/wrench)) - return ..() - if (!(stat & NOPOWER) && on) - user << "\red You cannot unwrench this [src], turn it off first." - return 1 - var/turf/T = src.loc - if (level==1 && isturf(T) && T.intact) - user << "\red You must remove the plating first." - return 1 - var/datum/gas_mixture/int_air = return_air() - var/datum/gas_mixture/env_air = loc.return_air() - if ((int_air.return_pressure()-env_air.return_pressure()) > 2*ONE_ATMOSPHERE) - user << "\red You cannot unwrench this [src], it too exerted due to internal pressure." - add_fingerprint(user) - return 1 - playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) - user << "\blue You begin to unfasten \the [src]..." - if (do_after(user, 40)) - user.visible_message( \ - "[user] unfastens \the [src].", \ - "\blue You have unfastened \the [src].", \ - "You hear ratchet.") - new /obj/item/pipe(loc, make_from=src) - del(src) +/obj/machinery/atmospherics/unary/vent_pump/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob) + if (!istype(W, /obj/item/weapon/wrench)) + return ..() + if (!(stat & NOPOWER) && on) + user << "\red You cannot unwrench this [src], turn it off first." + return 1 + var/turf/T = src.loc + if (node && node.level==1 && isturf(T) && T.intact) + user << "\red You must remove the plating first." + return 1 + var/datum/gas_mixture/int_air = return_air() + var/datum/gas_mixture/env_air = loc.return_air() + if ((int_air.return_pressure()-env_air.return_pressure()) > 2*ONE_ATMOSPHERE) + user << "\red You cannot unwrench this [src], it too exerted due to internal pressure." + add_fingerprint(user) + return 1 + playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) + user << "\blue You begin to unfasten \the [src]..." + if (do_after(user, 40)) + user.visible_message( \ + "[user] unfastens \the [src].", \ + "\blue You have unfastened \the [src].", \ + "You hear ratchet.") + new /obj/item/pipe(loc, make_from=src) + del(src) /obj/machinery/atmospherics/unary/vent_pump/Del() if(initial_loc) diff --git a/code/ATMOSPHERICS/components/unary/vent_scrubber.dm b/code/ATMOSPHERICS/components/unary/vent_scrubber.dm index 3845b9ad61..05acdd1603 100644 --- a/code/ATMOSPHERICS/components/unary/vent_scrubber.dm +++ b/code/ATMOSPHERICS/components/unary/vent_scrubber.dm @@ -1,6 +1,6 @@ /obj/machinery/atmospherics/unary/vent_scrubber - icon = 'icons/obj/atmospherics/vent_scrubber.dmi' - icon_state = "off" + icon = 'icons/atmos/vent_scrubber.dmi' + icon_state = "map_scrubber" name = "Air Scrubber" desc = "Has a valve and pump attached to it" @@ -25,245 +25,259 @@ var/area_uid var/radio_filter_out var/radio_filter_in - New() - initial_loc = get_area(loc) - if (initial_loc.master) - initial_loc = initial_loc.master - area_uid = initial_loc.uid - if (!id_tag) - assign_uid() - id_tag = num2text(uid) - if(ticker && ticker.current_state == 3)//if the game is running - src.initialize() - src.broadcast_status() - ..() - update_icon() - if(node && on && !(stat & (NOPOWER|BROKEN))) - if(scrubbing) - icon_state = "[level == 1 && istype(loc, /turf/simulated) ? "h" : "" ]on" - else - icon_state = "[level == 1 && istype(loc, /turf/simulated) ? "h" : "" ]in" - else - icon_state = "[level == 1 && istype(loc, /turf/simulated) ? "h" : "" ]off" +/obj/machinery/atmospherics/unary/vent_scrubber/New() + icon = null + initial_loc = get_area(loc) + if (initial_loc.master) + initial_loc = initial_loc.master + area_uid = initial_loc.uid + if (!id_tag) + assign_uid() + id_tag = num2text(uid) + if(ticker && ticker.current_state == 3)//if the game is running + src.initialize() + src.broadcast_status() + ..() + +/obj/machinery/atmospherics/unary/vent_scrubber/update_icon(var/safety = 0) + if(!check_icon_cache()) return - proc - set_frequency(new_frequency) - radio_controller.remove_object(src, frequency) - frequency = new_frequency - radio_connection = radio_controller.add_object(src, frequency, radio_filter_in) + overlays.Cut() + + var/scrubber_icon = "scrubber" - broadcast_status() - if(!radio_connection) - return 0 + var/turf/T = get_turf(src) + if(!istype(T)) + return - var/datum/signal/signal = new - signal.transmission_method = 1 //radio signal - signal.source = src - signal.data = list( - "area" = area_uid, - "tag" = id_tag, - "device" = "AScr", - "timestamp" = world.time, - "power" = on, - "scrubbing" = scrubbing, - "panic" = panic, - "filter_co2" = scrub_CO2, - "filter_phoron" = scrub_Toxins, - "filter_n2o" = scrub_N2O, - "sigtype" = "status" - ) - if(!initial_loc.air_scrub_names[id_tag]) - var/new_name = "[initial_loc.name] Air Scrubber #[initial_loc.air_scrub_names.len+1]" - initial_loc.air_scrub_names[id_tag] = new_name - src.name = new_name - initial_loc.air_scrub_info[id_tag] = signal.data - radio_connection.post_signal(src, signal, radio_filter_out) + if(T.intact && node && node.level == 1 && istype(node, /obj/machinery/atmospherics/pipe)) + scrubber_icon += "h" + + if(!powered()) + scrubber_icon += "off" + else + scrubber_icon += "[on ? "[scrubbing ? "on" : "in"]" : "off"]" - return 1 + overlays += icon_manager.get_atmos_icon("device", , , scrubber_icon) - initialize() - ..() - radio_filter_in = frequency==initial(frequency)?(RADIO_FROM_AIRALARM):null - radio_filter_out = frequency==initial(frequency)?(RADIO_TO_AIRALARM):null - if (frequency) - set_frequency(frequency) - - process() - ..() - if(stat & (NOPOWER|BROKEN)) +/obj/machinery/atmospherics/unary/vent_scrubber/update_underlays() + if(..()) + underlays.Cut() + var/turf/T = get_turf(src) + if(!istype(T)) return - if (!node) - on = 0 - //broadcast_status() - if(!on) - return 0 + if(T.intact && node && node.level == 1 && istype(node, /obj/machinery/atmospherics/pipe)) + return + else + add_underlay(T, node, dir) + +/obj/machinery/atmospherics/unary/vent_scrubber/proc/set_frequency(new_frequency) + radio_controller.remove_object(src, frequency) + frequency = new_frequency + radio_connection = radio_controller.add_object(src, frequency, radio_filter_in) + +/obj/machinery/atmospherics/unary/vent_scrubber/proc/broadcast_status() + if(!radio_connection) + return 0 + + var/datum/signal/signal = new + signal.transmission_method = 1 //radio signal + signal.source = src + signal.data = list( + "area" = area_uid, + "tag" = id_tag, + "device" = "AScr", + "timestamp" = world.time, + "power" = on, + "scrubbing" = scrubbing, + "panic" = panic, + "filter_co2" = scrub_CO2, + "filter_phoron" = scrub_Toxins, + "filter_n2o" = scrub_N2O, + "sigtype" = "status" + ) + if(!initial_loc.air_scrub_names[id_tag]) + var/new_name = "[initial_loc.name] Air Scrubber #[initial_loc.air_scrub_names.len+1]" + initial_loc.air_scrub_names[id_tag] = new_name + src.name = new_name + initial_loc.air_scrub_info[id_tag] = signal.data + radio_connection.post_signal(src, signal, radio_filter_out) + + return 1 + +/obj/machinery/atmospherics/unary/vent_scrubber/initialize() + ..() + radio_filter_in = frequency==initial(frequency)?(RADIO_FROM_AIRALARM):null + radio_filter_out = frequency==initial(frequency)?(RADIO_TO_AIRALARM):null + if (frequency) + set_frequency(frequency) + +/obj/machinery/atmospherics/unary/vent_scrubber/process() + ..() + if(stat & (NOPOWER|BROKEN)) + return + if (!node) + on = 0 + //broadcast_status() + if(!on) + return 0 - var/datum/gas_mixture/environment = loc.return_air() + var/datum/gas_mixture/environment = loc.return_air() - if(scrubbing) - if((environment.phoron>0.001) || (environment.carbon_dioxide>0.001) || (environment.trace_gases.len>0)) - var/transfer_moles = min(1, volume_rate/environment.volume)*environment.total_moles() + if(scrubbing) + if((environment.phoron>0.001) || (environment.carbon_dioxide>0.001) || (environment.trace_gases.len>0)) + var/transfer_moles = min(1, volume_rate/environment.volume)*environment.total_moles() - //Take a gas sample - var/datum/gas_mixture/removed = loc.remove_air(transfer_moles) - if (isnull(removed)) //in space - return - - //Filter it - var/datum/gas_mixture/filtered_out = new - filtered_out.temperature = removed.temperature - if(scrub_Toxins) - filtered_out.phoron = removed.phoron - removed.phoron = 0 - if(scrub_CO2) - filtered_out.carbon_dioxide = removed.carbon_dioxide - removed.carbon_dioxide = 0 - - if(removed.trace_gases.len>0) - for(var/datum/gas/trace_gas in removed.trace_gases) - if(istype(trace_gas, /datum/gas/oxygen_agent_b)) - removed.trace_gases -= trace_gas - filtered_out.trace_gases += trace_gas - else if(istype(trace_gas, /datum/gas/sleeping_agent) && scrub_N2O) - removed.trace_gases -= trace_gas - filtered_out.trace_gases += trace_gas - - - //Remix the resulting gases - air_contents.merge(filtered_out) - - loc.assume_air(removed) - - if(network) - network.update = 1 - - else //Just siphoning all air - if (air_contents.return_pressure()>=50*ONE_ATMOSPHERE) + //Take a gas sample + var/datum/gas_mixture/removed = loc.remove_air(transfer_moles) + if (isnull(removed)) //in space return - var/transfer_moles = environment.total_moles()*(volume_rate/environment.volume) + //Filter it + var/datum/gas_mixture/filtered_out = new + filtered_out.temperature = removed.temperature + if(scrub_Toxins) + filtered_out.phoron = removed.phoron + removed.phoron = 0 + if(scrub_CO2) + filtered_out.carbon_dioxide = removed.carbon_dioxide + removed.carbon_dioxide = 0 - var/datum/gas_mixture/removed = loc.remove_air(transfer_moles) + if(removed.trace_gases.len>0) + for(var/datum/gas/trace_gas in removed.trace_gases) + if(istype(trace_gas, /datum/gas/oxygen_agent_b)) + removed.trace_gases -= trace_gas + filtered_out.trace_gases += trace_gas + else if(istype(trace_gas, /datum/gas/sleeping_agent) && scrub_N2O) + removed.trace_gases -= trace_gas + filtered_out.trace_gases += trace_gas - air_contents.merge(removed) + + //Remix the resulting gases + air_contents.merge(filtered_out) + + loc.assume_air(removed) if(network) network.update = 1 - return 1 -/* //unused piece of code - hide(var/i) //to make the little pipe section invisible, the icon changes. - if(on&&node) - if(scrubbing) - icon_state = "[i == 1 && istype(loc, /turf/simulated) ? "h" : "" ]on" - else - icon_state = "[i == 1 && istype(loc, /turf/simulated) ? "h" : "" ]in" - else - icon_state = "[i == 1 && istype(loc, /turf/simulated) ? "h" : "" ]off" - on = 0 + else //Just siphoning all air + if (air_contents.return_pressure()>=50*ONE_ATMOSPHERE) + return + + var/transfer_moles = environment.total_moles()*(volume_rate/environment.volume) + + var/datum/gas_mixture/removed = loc.remove_air(transfer_moles) + + air_contents.merge(removed) + + if(network) + network.update = 1 + + return 1 + +/obj/machinery/atmospherics/unary/vent_scrubber/hide(var/i) //to make the little pipe section invisible, the icon changes. + update_icon() + +/obj/machinery/atmospherics/unary/vent_scrubber/receive_signal(datum/signal/signal) + if(stat & (NOPOWER|BROKEN)) return -*/ + if(!signal.data["tag"] || (signal.data["tag"] != id_tag) || (signal.data["sigtype"]!="command")) + return 0 - receive_signal(datum/signal/signal) - if(stat & (NOPOWER|BROKEN)) - return - if(!signal.data["tag"] || (signal.data["tag"] != id_tag) || (signal.data["sigtype"]!="command")) - return 0 + if(signal.data["power"] != null) + on = text2num(signal.data["power"]) + if(signal.data["power_toggle"] != null) + on = !on - if(signal.data["power"] != null) - on = text2num(signal.data["power"]) - if(signal.data["power_toggle"] != null) - on = !on + if(signal.data["panic_siphon"]) //must be before if("scrubbing" thing + panic = text2num(signal.data["panic_siphon"] != null) + if(panic) + on = 1 + scrubbing = 0 + volume_rate = 2000 + else + scrubbing = 1 + volume_rate = initial(volume_rate) + if(signal.data["toggle_panic_siphon"] != null) + panic = !panic + if(panic) + on = 1 + scrubbing = 0 + volume_rate = 2000 + else + scrubbing = 1 + volume_rate = initial(volume_rate) - if(signal.data["panic_siphon"]) //must be before if("scrubbing" thing - panic = text2num(signal.data["panic_siphon"] != null) - if(panic) - on = 1 - scrubbing = 0 - volume_rate = 2000 - else - scrubbing = 1 - volume_rate = initial(volume_rate) - if(signal.data["toggle_panic_siphon"] != null) - panic = !panic - if(panic) - on = 1 - scrubbing = 0 - volume_rate = 2000 - else - scrubbing = 1 - volume_rate = initial(volume_rate) + if(signal.data["scrubbing"] != null) + scrubbing = text2num(signal.data["scrubbing"]) + if(signal.data["toggle_scrubbing"]) + scrubbing = !scrubbing - if(signal.data["scrubbing"] != null) - scrubbing = text2num(signal.data["scrubbing"]) - if(signal.data["toggle_scrubbing"]) - scrubbing = !scrubbing + if(signal.data["co2_scrub"] != null) + scrub_CO2 = text2num(signal.data["co2_scrub"]) + if(signal.data["toggle_co2_scrub"]) + scrub_CO2 = !scrub_CO2 - if(signal.data["co2_scrub"] != null) - scrub_CO2 = text2num(signal.data["co2_scrub"]) - if(signal.data["toggle_co2_scrub"]) - scrub_CO2 = !scrub_CO2 + if(signal.data["tox_scrub"] != null) + scrub_Toxins = text2num(signal.data["tox_scrub"]) + if(signal.data["toggle_tox_scrub"]) + scrub_Toxins = !scrub_Toxins - if(signal.data["tox_scrub"] != null) - scrub_Toxins = text2num(signal.data["tox_scrub"]) - if(signal.data["toggle_tox_scrub"]) - scrub_Toxins = !scrub_Toxins + if(signal.data["n2o_scrub"] != null) + scrub_N2O = text2num(signal.data["n2o_scrub"]) + if(signal.data["toggle_n2o_scrub"]) + scrub_N2O = !scrub_N2O - if(signal.data["n2o_scrub"] != null) - scrub_N2O = text2num(signal.data["n2o_scrub"]) - if(signal.data["toggle_n2o_scrub"]) - scrub_N2O = !scrub_N2O + if(signal.data["init"] != null) + name = signal.data["init"] + return - if(signal.data["init"] != null) - name = signal.data["init"] - return - - if(signal.data["status"] != null) - spawn(2) - broadcast_status() - return //do not update_icon - -// log_admin("DEBUG \[[world.timeofday]\]: vent_scrubber/receive_signal: unknown command \"[signal.data["command"]]\"\n[signal.debug_print()]") + if(signal.data["status"] != null) spawn(2) broadcast_status() - update_icon() - return + return //do not update_icon - power_change() - if(powered(power_channel)) - stat &= ~NOPOWER - else - stat |= NOPOWER +// log_admin("DEBUG \[[world.timeofday]\]: vent_scrubber/receive_signal: unknown command \"[signal.data["command"]]\"\n[signal.debug_print()]") + spawn(2) + broadcast_status() + update_icon() + return + +/obj/machinery/atmospherics/unary/vent_scrubber/power_change() + var/old_stat = stat + ..() + if(old_stat != stat) update_icon() - attackby(var/obj/item/weapon/W as obj, var/mob/user as mob) - if (!istype(W, /obj/item/weapon/wrench)) - return ..() - if (!(stat & NOPOWER) && on) - user << "\red You cannot unwrench this [src], turn it off first." - return 1 - var/turf/T = src.loc - if (level==1 && isturf(T) && T.intact) - user << "\red You must remove the plating first." - return 1 - var/datum/gas_mixture/int_air = return_air() - var/datum/gas_mixture/env_air = loc.return_air() - if ((int_air.return_pressure()-env_air.return_pressure()) > 2*ONE_ATMOSPHERE) - user << "\red You cannot unwrench this [src], it too exerted due to internal pressure." - add_fingerprint(user) - return 1 - playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) - user << "\blue You begin to unfasten \the [src]..." - if (do_after(user, 40)) - user.visible_message( \ - "[user] unfastens \the [src].", \ - "\blue You have unfastened \the [src].", \ - "You hear ratchet.") - new /obj/item/pipe(loc, make_from=src) - del(src) +/obj/machinery/atmospherics/unary/vent_scrubber/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob) + if (!istype(W, /obj/item/weapon/wrench)) + return ..() + if (!(stat & NOPOWER) && on) + user << "\red You cannot unwrench this [src], turn it off first." + return 1 + var/turf/T = src.loc + if (node && node.level==1 && isturf(T) && T.intact) + user << "\red You must remove the plating first." + return 1 + var/datum/gas_mixture/int_air = return_air() + var/datum/gas_mixture/env_air = loc.return_air() + if ((int_air.return_pressure()-env_air.return_pressure()) > 2*ONE_ATMOSPHERE) + user << "\red You cannot unwrench this [src], it too exerted due to internal pressure." + add_fingerprint(user) + return 1 + playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) + user << "\blue You begin to unfasten \the [src]..." + if (do_after(user, 40)) + user.visible_message( \ + "[user] unfastens \the [src].", \ + "\blue You have unfastened \the [src].", \ + "You hear ratchet.") + new /obj/item/pipe(loc, make_from=src) + del(src) /obj/machinery/atmospherics/unary/vent_scrubber/Del() if(initial_loc) diff --git a/code/ATMOSPHERICS/components/valve.dm b/code/ATMOSPHERICS/components/valve.dm index 09d0b64f86..75282275eb 100644 --- a/code/ATMOSPHERICS/components/valve.dm +++ b/code/ATMOSPHERICS/components/valve.dm @@ -1,10 +1,11 @@ -obj/machinery/atmospherics/valve - icon = 'icons/obj/atmospherics/valve.dmi' - icon_state = "valve0" +/obj/machinery/atmospherics/valve + icon = 'icons/atmos/valve.dmi' + icon_state = "map_valve0" name = "manual valve" desc = "A pipe valve" + level = 1 dir = SOUTH initialize_directions = SOUTH|NORTH @@ -17,322 +18,297 @@ obj/machinery/atmospherics/valve var/datum/pipe_network/network_node1 var/datum/pipe_network/network_node2 - open - open = 1 - icon_state = "valve1" +/obj/machinery/atmospherics/valve/open + open = 1 + icon_state = "map_valve1" - update_icon(animation) - if(animation) - flick("valve[src.open][!src.open]",src) - else - icon_state = "valve[open]" +/obj/machinery/atmospherics/valve/update_icon(animation) + if(animation) + flick("valve[src.open][!src.open]",src) + else + icon_state = "valve[open]" - New() - switch(dir) - if(NORTH || SOUTH) - initialize_directions = NORTH|SOUTH - if(EAST || WEST) - initialize_directions = EAST|WEST - ..() +/obj/machinery/atmospherics/valve/update_underlays() + if(..()) + underlays.Cut() + var/turf/T = get_turf(src) + if(!istype(T)) + return + add_underlay(T, node1, get_dir(src, node1)) + add_underlay(T, node2, get_dir(src, node2)) - network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference) +/obj/machinery/atmospherics/valve/hide(var/i) + update_underlays() +/obj/machinery/atmospherics/valve/New() + switch(dir) + if(NORTH || SOUTH) + initialize_directions = NORTH|SOUTH + if(EAST || WEST) + initialize_directions = EAST|WEST + ..() - if(reference == node1) - network_node1 = new_network - if(open) - network_node2 = new_network - else if(reference == node2) - network_node2 = new_network - if(open) - network_node1 = new_network - - if(new_network.normal_members.Find(src)) - return 0 - - new_network.normal_members += src - +/obj/machinery/atmospherics/valve/network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference) + if(reference == node1) + network_node1 = new_network if(open) - if(reference == node1) - if(node2) - return node2.network_expand(new_network, src) - else if(reference == node2) - if(node1) - return node1.network_expand(new_network, src) + network_node2 = new_network + else if(reference == node2) + network_node2 = new_network + if(open) + network_node1 = new_network - return null + if(new_network.normal_members.Find(src)) + return 0 - Del() - loc = null + new_network.normal_members += src - if(node1) - node1.disconnect(src) - del(network_node1) - if(node2) - node2.disconnect(src) - del(network_node2) + if(open) + if(reference == node1) + if(node2) + return node2.network_expand(new_network, src) + else if(reference == node2) + if(node1) + return node1.network_expand(new_network, src) + return null + +/obj/machinery/atmospherics/valve/Del() + loc = null + + if(node1) + node1.disconnect(src) + del(network_node1) + if(node2) + node2.disconnect(src) + del(network_node2) + + node1 = null + node2 = null + + ..() + +/obj/machinery/atmospherics/valve/proc/open() + if(open) return 0 + + open = 1 + update_icon() + + if(network_node1&&network_node2) + network_node1.merge(network_node2) + network_node2 = network_node1 + + if(network_node1) + network_node1.update = 1 + else if(network_node2) + network_node2.update = 1 + + return 1 + +/obj/machinery/atmospherics/valve/proc/close() + if(!open) + return 0 + + open = 0 + update_icon() + + if(network_node1) + del(network_node1) + if(network_node2) + del(network_node2) + + build_network() + + return 1 + +/obj/machinery/atmospherics/valve/proc/normalize_dir() + if(dir==3) + dir = 1 + else if(dir==12) + dir = 4 + +/obj/machinery/atmospherics/valve/attack_ai(mob/user as mob) + return + +/obj/machinery/atmospherics/valve/attack_paw(mob/user as mob) + return attack_hand(user) + +/obj/machinery/atmospherics/valve/attack_hand(mob/user as mob) + src.add_fingerprint(usr) + update_icon(1) + sleep(10) + if (src.open) + src.close() + else + src.open() + +/obj/machinery/atmospherics/valve/process() + ..() + . = PROCESS_KILL + + return + +/obj/machinery/atmospherics/valve/initialize() + normalize_dir() + + var/node1_dir + var/node2_dir + + for(var/direction in cardinal) + if(direction&initialize_directions) + if (!node1_dir) + node1_dir = direction + else if (!node2_dir) + node2_dir = direction + + for(var/obj/machinery/atmospherics/target in get_step(src,node1_dir)) + if(target.initialize_directions & get_dir(target,src)) + node1 = target + break + for(var/obj/machinery/atmospherics/target in get_step(src,node2_dir)) + if(target.initialize_directions & get_dir(target,src)) + node2 = target + break + + build_network() + + update_icon() + update_underlays() + + if(openDuringInit) + close() + open() + openDuringInit = 0 + +/obj/machinery/atmospherics/valve/build_network() + if(!network_node1 && node1) + network_node1 = new /datum/pipe_network() + network_node1.normal_members += src + network_node1.build_network(node1, src) + + if(!network_node2 && node2) + network_node2 = new /datum/pipe_network() + network_node2.normal_members += src + network_node2.build_network(node2, src) + +/obj/machinery/atmospherics/valve/return_network(obj/machinery/atmospherics/reference) + build_network() + + if(reference==node1) + return network_node1 + + if(reference==node2) + return network_node2 + + return null + +/obj/machinery/atmospherics/valve/reassign_network(datum/pipe_network/old_network, datum/pipe_network/new_network) + if(network_node1 == old_network) + network_node1 = new_network + if(network_node2 == old_network) + network_node2 = new_network + + return 1 + +/obj/machinery/atmospherics/valve/return_network_air(datum/network/reference) + return null + +/obj/machinery/atmospherics/valve/disconnect(obj/machinery/atmospherics/reference) + if(reference==node1) + del(network_node1) node1 = null + + else if(reference==node2) + del(network_node2) node2 = null - ..() + update_underlays() - proc/open() + return null - if(open) return 0 +/obj/machinery/atmospherics/valve/digital // can be controlled by AI + name = "digital valve" + desc = "A digitally controlled valve." + icon = 'icons/atmos/digital_valve.dmi' + + var/frequency = 0 + var/id = null + var/datum/radio_frequency/radio_connection - open = 1 +/obj/machinery/atmospherics/valve/digital/attack_ai(mob/user as mob) + return src.attack_hand(user) + +/obj/machinery/atmospherics/valve/digital/attack_hand(mob/user as mob) + if(!powered()) + return + if(!src.allowed(user)) + user << "\red Access denied." + return + ..() + +/obj/machinery/atmospherics/valve/digital/open + open = 1 + icon_state = "map_valve1" + +/obj/machinery/atmospherics/valve/digital/power_change() + var/old_stat = stat + ..() + if(old_stat != stat) update_icon() - if(network_node1&&network_node2) - network_node1.merge(network_node2) - network_node2 = network_node1 +/obj/machinery/atmospherics/valve/digital/update_icon() + ..() + if(!powered()) + icon_state = "valve[open]nopower" - if(network_node1) - network_node1.update = 1 - else if(network_node2) - network_node2.update = 1 +/obj/machinery/atmospherics/valve/digital/proc/set_frequency(new_frequency) + radio_controller.remove_object(src, frequency) + frequency = new_frequency + if(frequency) + radio_connection = radio_controller.add_object(src, frequency, RADIO_ATMOSIA) - return 1 +/obj/machinery/atmospherics/valve/digital/initialize() + ..() + if(frequency) + set_frequency(frequency) - proc/close() +/obj/machinery/atmospherics/valve/digital/receive_signal(datum/signal/signal) + if(!signal.data["tag"] || (signal.data["tag"] != id)) + return 0 - if(!open) - return 0 + switch(signal.data["command"]) + if("valve_open") + if(!open) + open() - open = 0 - update_icon() + if("valve_close") + if(open) + close() - if(network_node1) - del(network_node1) - if(network_node2) - del(network_node2) - - build_network() - - return 1 - - proc/normalize_dir() - if(dir==3) - dir = 1 - else if(dir==12) - dir = 4 - - attack_ai(mob/user as mob) - return - - attack_paw(mob/user as mob) - return attack_hand(user) - - attack_hand(mob/user as mob) - src.add_fingerprint(usr) - update_icon(1) - sleep(10) - if (src.open) - src.close() - else - src.open() - - process() - ..() - . = PROCESS_KILL - -/* if(open && (!node1 || !node2)) - close() - if(!node1) - if(!nodealert) - //world << "Missing node from [src] at [src.x],[src.y],[src.z]" - nodealert = 1 - else if (!node2) - if(!nodealert) - //world << "Missing node from [src] at [src.x],[src.y],[src.z]" - nodealert = 1 - else if (nodealert) - nodealert = 0 -*/ - - return - - initialize() - normalize_dir() - - var/node1_dir - var/node2_dir - - for(var/direction in cardinal) - if(direction&initialize_directions) - if (!node1_dir) - node1_dir = direction - else if (!node2_dir) - node2_dir = direction - - for(var/obj/machinery/atmospherics/target in get_step(src,node1_dir)) - if(target.initialize_directions & get_dir(target,src)) - node1 = target - break - for(var/obj/machinery/atmospherics/target in get_step(src,node2_dir)) - if(target.initialize_directions & get_dir(target,src)) - node2 = target - break - - build_network() - - if(openDuringInit) - close() - open() - openDuringInit = 0 - -/* - var/connect_directions - switch(dir) - if(NORTH) - connect_directions = NORTH|SOUTH - if(SOUTH) - connect_directions = NORTH|SOUTH - if(EAST) - connect_directions = EAST|WEST - if(WEST) - connect_directions = EAST|WEST + if("valve_toggle") + if(open) + close() else - connect_directions = dir - - for(var/direction in cardinal) - if(direction&connect_directions) - for(var/obj/machinery/atmospherics/target in get_step(src,direction)) - if(target.initialize_directions & get_dir(target,src)) - connect_directions &= ~direction - node1 = target - break - if(node1) - break - - for(var/direction in cardinal) - if(direction&connect_directions) - for(var/obj/machinery/atmospherics/target in get_step(src,direction)) - if(target.initialize_directions & get_dir(target,src)) - node2 = target - break - if(node1) - break -*/ - build_network() - if(!network_node1 && node1) - network_node1 = new /datum/pipe_network() - network_node1.normal_members += src - network_node1.build_network(node1, src) - - if(!network_node2 && node2) - network_node2 = new /datum/pipe_network() - network_node2.normal_members += src - network_node2.build_network(node2, src) - - - return_network(obj/machinery/atmospherics/reference) - build_network() - - if(reference==node1) - return network_node1 - - if(reference==node2) - return network_node2 - - return null - - reassign_network(datum/pipe_network/old_network, datum/pipe_network/new_network) - if(network_node1 == old_network) - network_node1 = new_network - if(network_node2 == old_network) - network_node2 = new_network + open() +/obj/machinery/atmospherics/valve/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob) + if (!istype(W, /obj/item/weapon/wrench)) + return ..() + if (istype(src, /obj/machinery/atmospherics/valve/digital)) + user << "\red You cannot unwrench this [src], it's too complicated." return 1 - - return_network_air(datum/network/reference) - return null - - disconnect(obj/machinery/atmospherics/reference) - if(reference==node1) - del(network_node1) - node1 = null - - else if(reference==node2) - del(network_node2) - node2 = null - - return null - - digital // can be controlled by AI - name = "digital valve" - desc = "A digitally controlled valve." - icon = 'icons/obj/atmospherics/digital_valve.dmi' - - attack_ai(mob/user as mob) - return src.attack_hand(user) - - attack_hand(mob/user as mob) - if(!src.allowed(user)) - user << "\red Access denied." - return - ..() - - //Radio remote control - - proc - set_frequency(new_frequency) - radio_controller.remove_object(src, frequency) - frequency = new_frequency - if(frequency) - radio_connection = radio_controller.add_object(src, frequency, RADIO_ATMOSIA) - - var/frequency = 0 - var/id = null - var/datum/radio_frequency/radio_connection - - initialize() - ..() - if(frequency) - set_frequency(frequency) - - receive_signal(datum/signal/signal) - if(!signal.data["tag"] || (signal.data["tag"] != id)) - return 0 - - switch(signal.data["command"]) - if("valve_open") - if(!open) - open() - - if("valve_close") - if(open) - close() - - if("valve_toggle") - if(open) - close() - else - open() - - attackby(var/obj/item/weapon/W as obj, var/mob/user as mob) - if (!istype(W, /obj/item/weapon/wrench)) - return ..() - if (istype(src, /obj/machinery/atmospherics/valve/digital)) - user << "\red You cannot unwrench this [src], it's too complicated." - return 1 - var/turf/T = src.loc - if (level==1 && isturf(T) && T.intact) - user << "\red You must remove the plating first." - return 1 - var/datum/gas_mixture/int_air = return_air() - var/datum/gas_mixture/env_air = loc.return_air() - if ((int_air.return_pressure()-env_air.return_pressure()) > 2*ONE_ATMOSPHERE) - user << "\red You cannot unwrench this [src], it too exerted due to internal pressure." - add_fingerprint(user) - return 1 - playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) - user << "\blue You begin to unfasten \the [src]..." - if (do_after(user, 40)) - user.visible_message( \ - "[user] unfastens \the [src].", \ - "\blue You have unfastened \the [src].", \ - "You hear ratchet.") - new /obj/item/pipe(loc, make_from=src) - del(src) + var/datum/gas_mixture/int_air = return_air() + var/datum/gas_mixture/env_air = loc.return_air() + if ((int_air.return_pressure()-env_air.return_pressure()) > 2*ONE_ATMOSPHERE) + user << "\red You cannot unwrench this [src], it too exerted due to internal pressure." + add_fingerprint(user) + return 1 + playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) + user << "\blue You begin to unfasten \the [src]..." + if (do_after(user, 40)) + user.visible_message( \ + "[user] unfastens \the [src].", \ + "\blue You have unfastened \the [src].", \ + "You hear ratchet.") + new /obj/item/pipe(loc, make_from=src) + del(src) \ No newline at end of file diff --git a/code/ATMOSPHERICS/mapdebugging.dm b/code/ATMOSPHERICS/mapdebugging.dm deleted file mode 100644 index 2dc3949713..0000000000 --- a/code/ATMOSPHERICS/mapdebugging.dm +++ /dev/null @@ -1,16 +0,0 @@ -client/verb/discon_pipes() - set name = "Show Disconnected Pipes" - set category = "Debug" - - for(var/obj/machinery/atmospherics/pipe/simple/P in world) - if(!P.node1 || !P.node2) - usr << "[P], [P.x], [P.y], [P.z], [P.loc.loc]" - - for(var/obj/machinery/atmospherics/pipe/manifold/P in world) - if(!P.node1 || !P.node2 || !P.node3) - usr << "[P], [P.x], [P.y], [P.z], [P.loc.loc]" - - for(var/obj/machinery/atmospherics/pipe/manifold4w/P in world) - if(!P.node1 || !P.node2 || !P.node3 || !P.node4) - usr << "[P], [P.x], [P.y], [P.z], [P.loc.loc]" -//With thanks to mini. Check before use, uncheck after. Do Not Use on a live server. \ No newline at end of file diff --git a/code/ATMOSPHERICS/pipes.dm b/code/ATMOSPHERICS/pipes.dm index 11daee64c3..875c5a67ee 100644 --- a/code/ATMOSPHERICS/pipes.dm +++ b/code/ATMOSPHERICS/pipes.dm @@ -1,4 +1,4 @@ -obj/machinery/atmospherics/pipe +/obj/machinery/atmospherics/pipe var/datum/gas_mixture/air_temporary //used when reconstructing a pipeline that broke var/datum/pipeline/parent @@ -12,51 +12,57 @@ obj/machinery/atmospherics/pipe var/alert_pressure = 80*ONE_ATMOSPHERE //minimum pressure before check_pressure(...) should be called -obj/machinery/atmospherics/pipe/proc/pipeline_expansion() +/obj/machinery/atmospherics/pipe/New() + ..() + //so pipes under walls are hidden + if(!istype(get_turf(src), /turf/simulated/floor)) + level = 1 + +/obj/machinery/atmospherics/pipe/proc/pipeline_expansion() return null -obj/machinery/atmospherics/pipe/proc/check_pressure(pressure) +/obj/machinery/atmospherics/pipe/proc/check_pressure(pressure) //Return 1 if parent should continue checking other pipes //Return null if parent should stop checking other pipes. Recall: del(src) will by default return null return 1 -obj/machinery/atmospherics/pipe/return_air() +/obj/machinery/atmospherics/pipe/return_air() if(!parent) parent = new /datum/pipeline() parent.build_pipeline(src) return parent.air -obj/machinery/atmospherics/pipe/build_network() +/obj/machinery/atmospherics/pipe/build_network() if(!parent) parent = new /datum/pipeline() parent.build_pipeline(src) return parent.return_network() -obj/machinery/atmospherics/pipe/network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference) +/obj/machinery/atmospherics/pipe/network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference) if(!parent) parent = new /datum/pipeline() parent.build_pipeline(src) return parent.network_expand(new_network, reference) -obj/machinery/atmospherics/pipe/return_network(obj/machinery/atmospherics/reference) +/obj/machinery/atmospherics/pipe/return_network(obj/machinery/atmospherics/reference) if(!parent) parent = new /datum/pipeline() parent.build_pipeline(src) return parent.return_network(reference) -obj/machinery/atmospherics/pipe/Del() +/obj/machinery/atmospherics/pipe/Del() del(parent) if(air_temporary) loc.assume_air(air_temporary) ..() -obj/machinery/atmospherics/pipe/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob) +/obj/machinery/atmospherics/pipe/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob) if (istype(src, /obj/machinery/atmospherics/pipe/tank)) return ..() if (istype(src, /obj/machinery/atmospherics/pipe/vent)) @@ -91,10 +97,44 @@ obj/machinery/atmospherics/pipe/attackby(var/obj/item/weapon/W as obj, var/mob/u del(meter) del(src) +/obj/machinery/atmospherics/proc/change_color(var/new_color) + //only pass valid pipe colors please ~otherwise your pipe will turn invisible + if(!pipe_color_check(new_color)) + return -obj/machinery/atmospherics/pipe/simple - icon = 'icons/obj/pipes.dmi' + pipe_color = new_color + update_icon() +/obj/machinery/atmospherics/pipe/add_underlay(var/obj/machinery/atmospherics/node, var/direction) + if(istype(src, /obj/machinery/atmospherics/pipe/tank)) //todo: move tanks to unary devices + return ..() + + if(node) + var/temp_dir = get_dir(src, node) + underlays += icon_manager.get_atmos_icon("pipe_underlay_intact", temp_dir, color_cache_name(node)) + return temp_dir + else if(direction) + underlays += icon_manager.get_atmos_icon("pipe_underlay_exposed", direction, pipe_color) + else + return null + +/obj/machinery/atmospherics/pipe/color_cache_name(var/obj/machinery/atmospherics/node) + if(istype(src, /obj/machinery/atmospherics/pipe/tank)) + return ..() + + if(istype(node, /obj/machinery/atmospherics/pipe/manifold) || istype(node, /obj/machinery/atmospherics/pipe/manifold4w)) + if(pipe_color == node.pipe_color) + return node.pipe_color + else + return null + else if(istype(node, /obj/machinery/atmospherics/pipe/simple)) + return node.pipe_color + else + return pipe_color + +/obj/machinery/atmospherics/pipe/simple + icon = 'icons/atmos/pipes.dmi' + icon_state = "intact" name = "pipe" desc = "A one meter section of regular pipe" @@ -113,12 +153,16 @@ obj/machinery/atmospherics/pipe/simple var/fatigue_pressure = 55*ONE_ATMOSPHERE alert_pressure = 55*ONE_ATMOSPHERE - level = 1 -obj/machinery/atmospherics/pipe/simple/New() +/obj/machinery/atmospherics/pipe/simple/New() ..() + + // Pipe colors and icon states are handled by an image cache - so color and icon should + // be null. For mapping purposes color is defined in the object definitions. + icon = null alpha = 255 + switch(dir) if(SOUTH || NORTH) initialize_directions = SOUTH|NORTH @@ -133,53 +177,18 @@ obj/machinery/atmospherics/pipe/simple/New() if(SOUTHWEST) initialize_directions = SOUTH|WEST - -obj/machinery/atmospherics/pipe/simple/hide(var/i) +/obj/machinery/atmospherics/pipe/simple/hide(var/i) if(level == 1 && istype(loc, /turf/simulated)) invisibility = i ? 101 : 0 update_icon() -obj/machinery/atmospherics/pipe/simple/process() +/obj/machinery/atmospherics/pipe/simple/process() if(!parent) //This should cut back on the overhead calling build_network thousands of times per cycle ..() else . = PROCESS_KILL - /*if(!node1) - parent.mingle_with_turf(loc, volume) - if(!nodealert) - //world << "Missing node from [src] at [src.x],[src.y],[src.z]" - nodealert = 1 - - else if(!node2) - parent.mingle_with_turf(loc, volume) - if(!nodealert) - //world << "Missing node from [src] at [src.x],[src.y],[src.z]" - nodealert = 1 - else if (nodealert) - nodealert = 0 - - - else if(parent) - var/environment_temperature = 0 - - if(istype(loc, /turf/simulated/)) - if(loc:blocks_air) - environment_temperature = loc:temperature - else - var/datum/gas_mixture/environment = loc.return_air() - environment_temperature = environment.temperature - - else - environment_temperature = loc:temperature - - var/datum/gas_mixture/pipe_air = return_air() - - if(abs(environment_temperature-pipe_air.temperature) > minimum_temperature_difference) - parent.temperature_interact(loc, volume, thermal_conductivity) - */ //Screw you heat lag - -obj/machinery/atmospherics/pipe/simple/check_pressure(pressure) +/obj/machinery/atmospherics/pipe/simple/check_pressure(pressure) var/datum/gas_mixture/environment = loc.return_air() var/pressure_difference = pressure - environment.return_pressure() @@ -194,7 +203,7 @@ obj/machinery/atmospherics/pipe/simple/check_pressure(pressure) else return 1 -obj/machinery/atmospherics/pipe/simple/proc/burst() +/obj/machinery/atmospherics/pipe/simple/proc/burst() src.visible_message("\red \bold [src] bursts!"); playsound(src.loc, 'sound/effects/bang.ogg', 25, 1) var/datum/effect/effect/system/smoke_spread/smoke = new @@ -202,13 +211,13 @@ obj/machinery/atmospherics/pipe/simple/proc/burst() smoke.start() del(src) -obj/machinery/atmospherics/pipe/simple/proc/normalize_dir() +/obj/machinery/atmospherics/pipe/simple/proc/normalize_dir() if(dir==3) dir = 1 else if(dir==12) dir = 4 -obj/machinery/atmospherics/pipe/simple/Del() +/obj/machinery/atmospherics/pipe/simple/Del() if(node1) node1.disconnect(src) if(node2) @@ -216,42 +225,42 @@ obj/machinery/atmospherics/pipe/simple/Del() ..() -obj/machinery/atmospherics/pipe/simple/pipeline_expansion() +/obj/machinery/atmospherics/pipe/simple/pipeline_expansion() return list(node1, node2) -obj/machinery/atmospherics/pipe/simple/update_icon() - switch(pipe_color) - if ("red") color = COLOR_RED - if ("blue") color = COLOR_BLUE - if ("cyan") color = COLOR_CYAN - if ("green") color = COLOR_GREEN - if ("yellow") color = "#FFCC00" - if ("purple") color = "#5C1EC0" - if ("grey") color = null +/obj/machinery/atmospherics/pipe/simple/change_color(var/new_color) + ..() + //for updating connected atmos device pipes (i.e. vents, manifolds, etc) + if(node1) + node1.update_underlays() + if(node2) + node2.update_underlays() - if(node1 && node2) - icon_state = "intact[invisibility ? "-f" : "" ]" +/obj/machinery/atmospherics/pipe/simple/update_icon(var/safety = 0) + if(!check_icon_cache()) + return - //var/node1_direction = get_dir(src, node1) - //var/node2_direction = get_dir(src, node2) + alpha = 255 - //dir = node1_direction|node2_direction + overlays.Cut() + if(!node1 && !node2) + var/turf/T = get_turf(src) + new /obj/item/pipe(loc, make_from=src) + for (var/obj/machinery/meter/meter in T) + if (meter.target == src) + new /obj/item/pipe_meter(T) + del(meter) + del(src) + else if(node1 && node2) + overlays += icon_manager.get_atmos_icon("pipe", , pipe_color, "intact") else - if(!node1 && !node2) - var/turf/T = get_turf(src) - new /obj/item/pipe(loc, make_from=src) - for (var/obj/machinery/meter/meter in T) - if (meter.target == src) - new /obj/item/pipe_meter(T) - del(meter) - del(src) - var/have_node1 = node1?1:0 - var/have_node2 = node2?1:0 - icon_state = "exposed[have_node1][have_node2][invisibility ? "-f" : "" ]" + overlays += icon_manager.get_atmos_icon("pipe", , pipe_color, "exposed[node1?1:0][node2?1:0]") +/obj/machinery/atmospherics/pipe/simple/update_underlays() + return -obj/machinery/atmospherics/pipe/simple/initialize() +/obj/machinery/atmospherics/pipe/simple/initialize() normalize_dir() var/node1_dir var/node2_dir @@ -276,12 +285,12 @@ obj/machinery/atmospherics/pipe/simple/initialize() del(src) return - var/turf/T = src.loc // hide if turf is not intact - hide(T.intact) + var/turf/T = get_turf(src) + if(istype(T)) + hide(T.intact) update_icon() - //update_icon() -obj/machinery/atmospherics/pipe/simple/disconnect(obj/machinery/atmospherics/reference) +/obj/machinery/atmospherics/pipe/simple/disconnect(obj/machinery/atmospherics/reference) if(reference == node1) if(istype(node1, /obj/machinery/atmospherics/pipe)) del(parent) @@ -296,55 +305,54 @@ obj/machinery/atmospherics/pipe/simple/disconnect(obj/machinery/atmospherics/ref return null - - - -obj/machinery/atmospherics/pipe/simple/visible +/obj/machinery/atmospherics/pipe/simple/visible level = 2 - icon_state = "intact" -obj/machinery/atmospherics/pipe/simple/visible/scrubbers - name="Scrubbers pipe" - color=COLOR_RED +/obj/machinery/atmospherics/pipe/simple/visible/scrubbers + name = "Scrubbers pipe" + color = PIPE_COLOR_RED -obj/machinery/atmospherics/pipe/simple/visible/supply - name="Air supply pipe" - color=COLOR_BLUE +/obj/machinery/atmospherics/pipe/simple/visible/supply + name = "Air supply pipe" + color = PIPE_COLOR_BLUE -obj/machinery/atmospherics/pipe/simple/visible/yellow - color="#FFCC00" +/obj/machinery/atmospherics/pipe/simple/visible/yellow + color = PIPE_COLOR_YELLOW -obj/machinery/atmospherics/pipe/simple/visible/cyan - color=COLOR_CYAN +/obj/machinery/atmospherics/pipe/simple/visible/cyan + color = PIPE_COLOR_CYAN -obj/machinery/atmospherics/pipe/simple/visible/green - color=COLOR_GREEN +/obj/machinery/atmospherics/pipe/simple/visible/green + color = PIPE_COLOR_GREEN +/obj/machinery/atmospherics/pipe/simple/visible/purple + color = PIPE_COLOR_PURPLE -obj/machinery/atmospherics/pipe/simple/hidden +/obj/machinery/atmospherics/pipe/simple/hidden level = 1 - icon_state = "intact-f" - alpha = 192 //set for the benefit of mapping - this is reset to opaque when the pipe is spawned in game + alpha = 128 //set for the benefit of mapping - this is reset to opaque when the pipe is spawned in game -obj/machinery/atmospherics/pipe/simple/hidden/scrubbers - name="Scrubbers pipe" - color=COLOR_RED +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers + name = "Scrubbers pipe" + color = PIPE_COLOR_RED -obj/machinery/atmospherics/pipe/simple/hidden/supply - name="Air supply pipe" - color=COLOR_BLUE +/obj/machinery/atmospherics/pipe/simple/hidden/supply + name = "Air supply pipe" + color = PIPE_COLOR_BLUE -obj/machinery/atmospherics/pipe/simple/hidden/yellow - color="#FFCC00" +/obj/machinery/atmospherics/pipe/simple/hidden/yellow + color = PIPE_COLOR_YELLOW -obj/machinery/atmospherics/pipe/simple/hidden/cyan - color=COLOR_CYAN +/obj/machinery/atmospherics/pipe/simple/hidden/cyan + color = PIPE_COLOR_CYAN -obj/machinery/atmospherics/pipe/simple/hidden/green - color=COLOR_GREEN +/obj/machinery/atmospherics/pipe/simple/hidden/green + color = PIPE_COLOR_GREEN +/obj/machinery/atmospherics/pipe/simple/hidden/purple + color = PIPE_COLOR_PURPLE -obj/machinery/atmospherics/pipe/simple/insulated +/obj/machinery/atmospherics/pipe/simple/insulated icon = 'icons/obj/atmospherics/red_pipe.dmi' icon_state = "intact" @@ -357,9 +365,9 @@ obj/machinery/atmospherics/pipe/simple/insulated level = 2 -obj/machinery/atmospherics/pipe/manifold - icon = 'icons/obj/atmospherics/pipe_manifold.dmi' - +/obj/machinery/atmospherics/pipe/manifold + icon = 'icons/atmos/manifold.dmi' + icon_state = "map" name = "pipe manifold" desc = "A manifold composed of regular pipes" @@ -375,8 +383,11 @@ obj/machinery/atmospherics/pipe/manifold level = 1 layer = 2.4 //under wires with their 2.44 -obj/machinery/atmospherics/pipe/manifold/New() +/obj/machinery/atmospherics/pipe/manifold/New() + ..() alpha = 255 + icon = null + switch(dir) if(NORTH) initialize_directions = EAST|SOUTH|WEST @@ -387,43 +398,21 @@ obj/machinery/atmospherics/pipe/manifold/New() if(WEST) initialize_directions = NORTH|EAST|SOUTH - ..() - - - -obj/machinery/atmospherics/pipe/manifold/hide(var/i) +/obj/machinery/atmospherics/pipe/manifold/hide(var/i) if(level == 1 && istype(loc, /turf/simulated)) invisibility = i ? 101 : 0 update_icon() -obj/machinery/atmospherics/pipe/manifold/pipeline_expansion() +/obj/machinery/atmospherics/pipe/manifold/pipeline_expansion() return list(node1, node2, node3) -obj/machinery/atmospherics/pipe/manifold/process() +/obj/machinery/atmospherics/pipe/manifold/process() if(!parent) ..() else . = PROCESS_KILL -/* - if(!node1) - parent.mingle_with_turf(loc, 70) - if(!nodealert) - //world << "Missing node from [src] at [src.x],[src.y],[src.z]" - nodealert = 1 - else if(!node2) - parent.mingle_with_turf(loc, 70) - if(!nodealert) - //world << "Missing node from [src] at [src.x],[src.y],[src.z]" - nodealert = 1 - else if(!node3) - parent.mingle_with_turf(loc, 70) - if(!nodealert) - //world << "Missing node from [src] at [src.x],[src.y],[src.z]" - nodealert = 1 - else if (nodealert) - nodealert = 0 -*/ -obj/machinery/atmospherics/pipe/manifold/Del() + +/obj/machinery/atmospherics/pipe/manifold/Del() if(node1) node1.disconnect(src) if(node2) @@ -433,7 +422,7 @@ obj/machinery/atmospherics/pipe/manifold/Del() ..() -obj/machinery/atmospherics/pipe/manifold/disconnect(obj/machinery/atmospherics/reference) +/obj/machinery/atmospherics/pipe/manifold/disconnect(obj/machinery/atmospherics/reference) if(reference == node1) if(istype(node1, /obj/machinery/atmospherics/pipe)) del(parent) @@ -453,40 +442,51 @@ obj/machinery/atmospherics/pipe/manifold/disconnect(obj/machinery/atmospherics/r ..() -obj/machinery/atmospherics/pipe/manifold/update_icon() - if(node1&&node2&&node3) - switch(pipe_color) - if ("red") color = COLOR_RED - if ("blue") color = COLOR_BLUE - if ("cyan") color = COLOR_CYAN - if ("green") color = COLOR_GREEN - if ("yellow") color = "#FFCC00" - if ("purple") color = "#5C1EC0" - if ("grey") color = null - icon_state = "manifold[invisibility ? "-f" : "" ]" +/obj/machinery/atmospherics/pipe/manifold/change_color(var/new_color) + ..() + //for updating connected atmos device pipes (i.e. vents, manifolds, etc) + if(node1) + node1.update_underlays() + if(node2) + node2.update_underlays() + if(node3) + node3.update_underlays() +/obj/machinery/atmospherics/pipe/manifold/update_icon(var/safety = 0) + if(!check_icon_cache()) + return + + alpha = 255 + + if(!node1 && !node2 && !node3) + var/turf/T = get_turf(src) + new /obj/item/pipe(loc, make_from=src) + for (var/obj/machinery/meter/meter in T) + if (meter.target == src) + new /obj/item/pipe_meter(T) + del(meter) + del(src) else - var/connected = 0 - var/unconnected = 0 - var/connect_directions = (NORTH|SOUTH|EAST|WEST)&(~dir) + overlays.Cut() + overlays += icon_manager.get_atmos_icon("manifold", , pipe_color, "core") + overlays += icon_manager.get_atmos_icon("manifold", , , "clamps") + underlays.Cut() + + var/list/directions = list(NORTH, SOUTH, EAST, WEST) + directions -= dir - if(node1) - connected |= get_dir(src, node1) - if(node2) - connected |= get_dir(src, node2) - if(node3) - connected |= get_dir(src, node3) + directions -= add_underlay(node1) + directions -= add_underlay(node2) + directions -= add_underlay(node3) - unconnected = (~connected)&(connect_directions) + for(var/D in directions) + add_underlay(,D) - icon_state = "manifold_[connected]_[unconnected]" +/obj/machinery/atmospherics/pipe/manifold/update_underlays() + ..() + update_icon() - if(!connected) - del(src) - - return - -obj/machinery/atmospherics/pipe/manifold/initialize() +/obj/machinery/atmospherics/pipe/manifold/initialize() var/connect_directions = (NORTH|SOUTH|EAST|WEST)&(~dir) for(var/direction in cardinal) @@ -521,61 +521,61 @@ obj/machinery/atmospherics/pipe/manifold/initialize() if (node3) break - var/turf/T = src.loc // hide if turf is not intact - hide(T.intact) - //update_icon() + var/turf/T = get_turf(src) + if(istype(T)) + hide(T.intact) update_icon() - -obj/machinery/atmospherics/pipe/manifold/visible +/obj/machinery/atmospherics/pipe/manifold/visible level = 2 - icon_state = "manifold" -obj/machinery/atmospherics/pipe/manifold/visible/supply - name="Air supply pipe" - color=COLOR_BLUE +/obj/machinery/atmospherics/pipe/manifold/visible/scrubbers + name = "Scrubbers pipe" + color = PIPE_COLOR_RED -obj/machinery/atmospherics/pipe/manifold/visible/scrubbers - name="Scrubbers pipe" - color=COLOR_RED +/obj/machinery/atmospherics/pipe/manifold/visible/supply + name = "Air supply pipe" + color = PIPE_COLOR_BLUE -obj/machinery/atmospherics/pipe/manifold/visible/yellow - color="#FFCC00" +/obj/machinery/atmospherics/pipe/manifold/visible/yellow + color = PIPE_COLOR_YELLOW -obj/machinery/atmospherics/pipe/manifold/visible/cyan - color=COLOR_CYAN +/obj/machinery/atmospherics/pipe/manifold/visible/cyan + color = PIPE_COLOR_CYAN -obj/machinery/atmospherics/pipe/manifold/visible/green - color=COLOR_GREEN +/obj/machinery/atmospherics/pipe/manifold/visible/green + color = PIPE_COLOR_GREEN +/obj/machinery/atmospherics/pipe/manifold/visible/purple + color = PIPE_COLOR_PURPLE -obj/machinery/atmospherics/pipe/manifold/hidden +/obj/machinery/atmospherics/pipe/manifold/hidden level = 1 - icon_state = "manifold-f" - alpha = 192 //set for the benefit of mapping - this is reset to opaque when the pipe is spawned in game + alpha = 128 //set for the benefit of mapping - this is reset to opaque when the pipe is spawned in game -obj/machinery/atmospherics/pipe/manifold/hidden/supply - name="Air supply pipe" - color=COLOR_BLUE +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers + name = "Scrubbers pipe" + color = PIPE_COLOR_RED -obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers - name="Scrubbers pipe" - color = COLOR_RED +/obj/machinery/atmospherics/pipe/manifold/hidden/supply + name = "Air supply pipe" + color = PIPE_COLOR_BLUE -obj/machinery/atmospherics/pipe/manifold/hidden/yellow - color="#FFCC00" +/obj/machinery/atmospherics/pipe/manifold/hidden/yellow + color = PIPE_COLOR_YELLOW -obj/machinery/atmospherics/pipe/manifold/hidden/cyan - color=COLOR_CYAN +/obj/machinery/atmospherics/pipe/manifold/hidden/cyan + color = PIPE_COLOR_CYAN -obj/machinery/atmospherics/pipe/manifold/hidden/green - color=COLOR_GREEN +/obj/machinery/atmospherics/pipe/manifold/hidden/green + color = PIPE_COLOR_GREEN +/obj/machinery/atmospherics/pipe/manifold/hidden/purple + color = PIPE_COLOR_PURPLE - -obj/machinery/atmospherics/pipe/manifold4w - icon = 'icons/obj/atmospherics/pipe_manifold.dmi' - +/obj/machinery/atmospherics/pipe/manifold4w + icon = 'icons/atmos/manifold.dmi' + icon_state = "map_4way" name = "4-way pipe manifold" desc = "A manifold composed of regular pipes" @@ -592,43 +592,21 @@ obj/machinery/atmospherics/pipe/manifold4w level = 1 layer = 2.4 //under wires with their 2.44 -obj/machinery/atmospherics/pipe/manifold4w/New() +/obj/machinery/atmospherics/pipe/manifold4w/New() ..() alpha = 255 + icon = null -obj/machinery/atmospherics/pipe/manifold4w/hide(var/i) - if(level == 1 && istype(loc, /turf/simulated)) - invisibility = i ? 101 : 0 - update_icon() - -obj/machinery/atmospherics/pipe/manifold4w/pipeline_expansion() +/obj/machinery/atmospherics/pipe/manifold4w/pipeline_expansion() return list(node1, node2, node3, node4) -obj/machinery/atmospherics/pipe/manifold4w/process() +/obj/machinery/atmospherics/pipe/manifold4w/process() if(!parent) ..() else . = PROCESS_KILL -/* - if(!node1) - parent.mingle_with_turf(loc, 70) - if(!nodealert) - //world << "Missing node from [src] at [src.x],[src.y],[src.z]" - nodealert = 1 - else if(!node2) - parent.mingle_with_turf(loc, 70) - if(!nodealert) - //world << "Missing node from [src] at [src.x],[src.y],[src.z]" - nodealert = 1 - else if(!node3) - parent.mingle_with_turf(loc, 70) - if(!nodealert) - //world << "Missing node from [src] at [src.x],[src.y],[src.z]" - nodealert = 1 - else if (nodealert) - nodealert = 0 -*/ -obj/machinery/atmospherics/pipe/manifold4w/Del() + +/obj/machinery/atmospherics/pipe/manifold4w/Del() if(node1) node1.disconnect(src) if(node2) @@ -640,7 +618,7 @@ obj/machinery/atmospherics/pipe/manifold4w/Del() ..() -obj/machinery/atmospherics/pipe/manifold4w/disconnect(obj/machinery/atmospherics/reference) +/obj/machinery/atmospherics/pipe/manifold4w/disconnect(obj/machinery/atmospherics/reference) if(reference == node1) if(istype(node1, /obj/machinery/atmospherics/pipe)) del(parent) @@ -665,37 +643,58 @@ obj/machinery/atmospherics/pipe/manifold4w/disconnect(obj/machinery/atmospherics ..() -obj/machinery/atmospherics/pipe/manifold4w/update_icon() - overlays.Cut() - if(node1&&node2&&node3&&node4) - switch(pipe_color) - if ("red") color = COLOR_RED - if ("blue") color = COLOR_BLUE - if ("cyan") color = COLOR_CYAN - if ("green") color = COLOR_GREEN - if ("yellow") color = "#FFCC00" - if ("purple") color = "#5C1EC0" - if ("grey") color = null - icon_state = "manifold4w[invisibility ? "-f" : "" ]" +/obj/machinery/atmospherics/pipe/manifold4w/change_color(var/new_color) + ..() + //for updating connected atmos device pipes (i.e. vents, manifolds, etc) + if(node1) + node1.update_underlays() + if(node2) + node2.update_underlays() + if(node3) + node3.update_underlays() + if(node4) + node4.update_underlays() +/obj/machinery/atmospherics/pipe/manifold4w/update_icon(var/safety = 0) + if(!check_icon_cache()) + return + + alpha = 255 + + if(!node1 && !node2 && !node3 && !node4) + var/turf/T = get_turf(src) + new /obj/item/pipe(loc, make_from=src) + for (var/obj/machinery/meter/meter in T) + if (meter.target == src) + new /obj/item/pipe_meter(T) + del(meter) + del(src) else - icon_state = "manifold4w_ex" - var/icon/con = new/icon('icons/obj/atmospherics/pipe_manifold.dmi',"manifold4w_con") //Since 4-ways are supposed to be directionless, they need an overlay instead it seems. + overlays.Cut() + overlays += icon_manager.get_atmos_icon("manifold", , pipe_color, "4way") + overlays += icon_manager.get_atmos_icon("manifold", , , "clamps_4way") + underlays.Cut() + + var/list/directions = list(NORTH, SOUTH, EAST, WEST) - if(node1) - overlays += new/image(con,dir=1) - if(node2) - overlays += new/image(con,dir=2) - if(node3) - overlays += new/image(con,dir=4) - if(node4) - overlays += new/image(con,dir=8) + directions -= add_underlay(node1) + directions -= add_underlay(node2) + directions -= add_underlay(node3) + directions -= add_underlay(node4) - if(!node1 && !node2 && !node3 && !node4) - del(src) - return + for(var/D in directions) + add_underlay(,D) -obj/machinery/atmospherics/pipe/manifold4w/initialize() +/obj/machinery/atmospherics/pipe/manifold4w/update_underlays() + ..() + update_icon() + +/obj/machinery/atmospherics/pipe/manifold4w/hide(var/i) + if(level == 1 && istype(loc, /turf/simulated)) + invisibility = i ? 101 : 0 + update_icon() + +/obj/machinery/atmospherics/pipe/manifold4w/initialize() for(var/obj/machinery/atmospherics/target in get_step(src,1)) if(target.initialize_directions & 2) @@ -717,58 +716,59 @@ obj/machinery/atmospherics/pipe/manifold4w/initialize() node4 = target break - var/turf/T = src.loc // hide if turf is not intact - hide(T.intact) - //update_icon() + var/turf/T = get_turf(src) + if(istype(T)) + hide(T.intact) update_icon() - -obj/machinery/atmospherics/pipe/manifold4w/visible +/obj/machinery/atmospherics/pipe/manifold4w/visible level = 2 - icon_state = "manifold4w" -obj/machinery/atmospherics/pipe/manifold4w/visible/supply - name="Air supply pipe" - color=COLOR_BLUE +/obj/machinery/atmospherics/pipe/manifold4w/visible/scrubbers + name = "Scrubbers pipe" + color = PIPE_COLOR_RED -obj/machinery/atmospherics/pipe/manifold4w/visible/scrubbers - name="Scrubbers pipe" - color=COLOR_RED +/obj/machinery/atmospherics/pipe/manifold4w/visible/supply + name = "Air supply pipe" + color = PIPE_COLOR_BLUE -obj/machinery/atmospherics/pipe/manifold4w/visible/yellow - color="#FFCC00" +/obj/machinery/atmospherics/pipe/manifold4w/visible/yellow + color = PIPE_COLOR_YELLOW -obj/machinery/atmospherics/pipe/manifold4w/visible/cyan - color=COLOR_CYAN +/obj/machinery/atmospherics/pipe/manifold4w/visible/cyan + color = PIPE_COLOR_CYAN -obj/machinery/atmospherics/pipe/manifold4w/visible/green - color=COLOR_GREEN +/obj/machinery/atmospherics/pipe/manifold4w/visible/green + color = PIPE_COLOR_GREEN +/obj/machinery/atmospherics/pipe/manifold4w/visible/purple + color = PIPE_COLOR_PURPLE -obj/machinery/atmospherics/pipe/manifold4w/hidden +/obj/machinery/atmospherics/pipe/manifold4w/hidden level = 1 - icon_state = "manifold4w-f" - alpha = 192 //set for the benefit of mapping - this is reset to opaque when the pipe is spawned in game + alpha = 128 //set for the benefit of mapping - this is reset to opaque when the pipe is spawned in game -obj/machinery/atmospherics/pipe/manifold4w/hidden/supply - name="Air supply pipe" - color=COLOR_BLUE +/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers + name = "Scrubbers pipe" + color = PIPE_COLOR_RED -obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers - name="Scrubbers pipe" - color=COLOR_RED +/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply + name = "Air supply pipe" + color = PIPE_COLOR_BLUE -obj/machinery/atmospherics/pipe/manifold4w/hidden/yellow - color="#FFCC00" +/obj/machinery/atmospherics/pipe/manifold4w/hidden/yellow + color = PIPE_COLOR_YELLOW -obj/machinery/atmospherics/pipe/manifold4w/hidden/cyan - color=COLOR_CYAN +/obj/machinery/atmospherics/pipe/manifold4w/hidden/cyan + color = PIPE_COLOR_CYAN -obj/machinery/atmospherics/pipe/manifold4w/hidden/green - color=COLOR_GREEN +/obj/machinery/atmospherics/pipe/manifold4w/hidden/green + color = PIPE_COLOR_GREEN +/obj/machinery/atmospherics/pipe/manifold4w/hidden/purple + color = PIPE_COLOR_PURPLE -obj/machinery/atmospherics/pipe/cap +/obj/machinery/atmospherics/pipe/cap name = "pipe endcap" desc = "An endcap for pipes" icon = 'icons/obj/pipes.dmi' @@ -783,7 +783,7 @@ obj/machinery/atmospherics/pipe/cap var/obj/machinery/atmospherics/node -obj/machinery/atmospherics/pipe/cap/New() +/obj/machinery/atmospherics/pipe/cap/New() ..() switch(dir) if(SOUTH) @@ -795,26 +795,26 @@ obj/machinery/atmospherics/pipe/cap/New() if(EAST) initialize_directions = WEST -obj/machinery/atmospherics/pipe/cap/hide(var/i) +/obj/machinery/atmospherics/pipe/cap/hide(var/i) if(level == 1 && istype(loc, /turf/simulated)) invisibility = i ? 101 : 0 update_icon() -obj/machinery/atmospherics/pipe/cap/pipeline_expansion() +/obj/machinery/atmospherics/pipe/cap/pipeline_expansion() return list(node) -obj/machinery/atmospherics/pipe/cap/process() +/obj/machinery/atmospherics/pipe/cap/process() if(!parent) ..() else . = PROCESS_KILL -obj/machinery/atmospherics/pipe/cap/Del() +/obj/machinery/atmospherics/pipe/cap/Del() if(node) node.disconnect(src) ..() -obj/machinery/atmospherics/pipe/cap/disconnect(obj/machinery/atmospherics/reference) +/obj/machinery/atmospherics/pipe/cap/disconnect(obj/machinery/atmospherics/reference) if(reference == node) if(istype(node, /obj/machinery/atmospherics/pipe)) del(parent) @@ -824,13 +824,13 @@ obj/machinery/atmospherics/pipe/cap/disconnect(obj/machinery/atmospherics/refere ..() -obj/machinery/atmospherics/pipe/cap/update_icon() +/obj/machinery/atmospherics/pipe/cap/update_icon() overlays = new() icon_state = "cap[invisibility ? "-f" : ""]" return -obj/machinery/atmospherics/pipe/cap/initialize() +/obj/machinery/atmospherics/pipe/cap/initialize() for(var/obj/machinery/atmospherics/target in get_step(src, dir)) if(target.initialize_directions & get_dir(target,src)) node = target @@ -838,151 +838,65 @@ obj/machinery/atmospherics/pipe/cap/initialize() var/turf/T = src.loc // hide if turf is not intact hide(T.intact) - //update_icon() update_icon() -obj/machinery/atmospherics/pipe/cap/visible +/obj/machinery/atmospherics/pipe/cap/visible level = 2 icon_state = "cap" -obj/machinery/atmospherics/pipe/cap/hidden +/obj/machinery/atmospherics/pipe/cap/hidden level = 1 icon_state = "cap-f" -obj/machinery/atmospherics/pipe/tank - icon = 'icons/obj/atmospherics/pipe_tank.dmi' - icon_state = "intact" +/obj/machinery/atmospherics/pipe/tank + icon = 'icons/atmos/tank.dmi' + icon_state = "air_map" name = "Pressure Tank" desc = "A large vessel containing pressurized gas." - volume = 2000 //in liters, 1 meters by 1 meters by 2 meters + volume = 10000 //in liters, 1 meters by 1 meters by 2 meters ~tweaked it a little to simulate a pressure tank without needing to recode them yet + level = 1 dir = SOUTH initialize_directions = SOUTH density = 1 var/obj/machinery/atmospherics/node1 -obj/machinery/atmospherics/pipe/tank/New() +/obj/machinery/atmospherics/pipe/tank/New() + icon_state = "air" initialize_directions = dir ..() -obj/machinery/atmospherics/pipe/tank/process() +/obj/machinery/atmospherics/pipe/tank/process() if(!parent) ..() else . = PROCESS_KILL -/* if(!node1) - parent.mingle_with_turf(loc, 200) - if(!nodealert) - //world << "Missing node from [src] at [src.x],[src.y],[src.z]" - nodealert = 1 - else if (nodealert) - nodealert = 0 -*/ -obj/machinery/atmospherics/pipe/tank/carbon_dioxide - name = "Pressure Tank (Carbon Dioxide)" - New() - air_temporary = new - air_temporary.volume = volume - air_temporary.temperature = T20C - - air_temporary.carbon_dioxide = (25*ONE_ATMOSPHERE)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature) - - ..() - -obj/machinery/atmospherics/pipe/tank/phoron - icon = 'icons/obj/atmospherics/orange_pipe_tank.dmi' - name = "Pressure Tank (Phoron)" - - New() - air_temporary = new - air_temporary.volume = volume - air_temporary.temperature = T20C - - air_temporary.phoron = (25*ONE_ATMOSPHERE)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature) - - ..() - -obj/machinery/atmospherics/pipe/tank/oxygen_agent_b - icon = 'icons/obj/atmospherics/red_orange_pipe_tank.dmi' - name = "Pressure Tank (Oxygen + Phoron)" - - New() - air_temporary = new - air_temporary.volume = volume - air_temporary.temperature = T0C - - var/datum/gas/oxygen_agent_b/trace_gas = new - trace_gas.moles = (25*ONE_ATMOSPHERE)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature) - - air_temporary.trace_gases += trace_gas - - ..() - -obj/machinery/atmospherics/pipe/tank/oxygen - icon = 'icons/obj/atmospherics/blue_pipe_tank.dmi' - name = "Pressure Tank (Oxygen)" - - New() - air_temporary = new - air_temporary.volume = volume - air_temporary.temperature = T20C - - air_temporary.oxygen = (25*ONE_ATMOSPHERE)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature) - - ..() - -obj/machinery/atmospherics/pipe/tank/nitrogen - icon = 'icons/obj/atmospherics/red_pipe_tank.dmi' - name = "Pressure Tank (Nitrogen)" - - New() - air_temporary = new - air_temporary.volume = volume - air_temporary.temperature = T20C - - air_temporary.nitrogen = (25*ONE_ATMOSPHERE)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature) - - ..() - -obj/machinery/atmospherics/pipe/tank/air - icon = 'icons/obj/atmospherics/red_pipe_tank.dmi' - name = "Pressure Tank (Air)" - - New() - air_temporary = new - air_temporary.volume = volume - air_temporary.temperature = T20C - - air_temporary.oxygen = (25*ONE_ATMOSPHERE*O2STANDARD)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature) - air_temporary.nitrogen = (25*ONE_ATMOSPHERE*N2STANDARD)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature) - - ..() - -obj/machinery/atmospherics/pipe/tank/Del() +/obj/machinery/atmospherics/pipe/tank/Del() if(node1) node1.disconnect(src) ..() -obj/machinery/atmospherics/pipe/tank/pipeline_expansion() +/obj/machinery/atmospherics/pipe/tank/pipeline_expansion() return list(node1) -obj/machinery/atmospherics/pipe/tank/update_icon() - if(node1) - icon_state = "intact" +/obj/machinery/atmospherics/pipe/tank/update_underlays() + if(..()) + underlays.Cut() + var/turf/T = get_turf(src) + if(!istype(T)) + return + add_underlay(T, node1, dir) - dir = get_dir(src, node1) - - else - icon_state = "exposed" - -obj/machinery/atmospherics/pipe/tank/initialize() +/obj/machinery/atmospherics/pipe/tank/hide() + update_underlays() +/obj/machinery/atmospherics/pipe/tank/initialize() var/connect_direction = dir for(var/obj/machinery/atmospherics/target in get_step(src,connect_direction)) @@ -990,20 +904,23 @@ obj/machinery/atmospherics/pipe/tank/initialize() node1 = target break - update_icon() + update_underlays() -obj/machinery/atmospherics/pipe/tank/disconnect(obj/machinery/atmospherics/reference) +/obj/machinery/atmospherics/pipe/tank/disconnect(obj/machinery/atmospherics/reference) if(reference == node1) if(istype(node1, /obj/machinery/atmospherics/pipe)) del(parent) node1 = null - update_icon() + update_underlays() return null -obj/machinery/atmospherics/pipe/tank/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob) - if (istype(W, /obj/item/device/analyzer) && get_dist(user, src) <= 1) +/obj/machinery/atmospherics/pipe/tank/attackby(var/obj/item/W as obj, var/mob/user as mob) + if(istype(W, /obj/item/device/pipe_painter)) + return + + if(istype(W, /obj/item/device/analyzer) && in_range(user, src)) for (var/mob/O in viewers(user, null)) O << "\red [user] has used the analyzer on \icon[icon]" @@ -1030,7 +947,95 @@ obj/machinery/atmospherics/pipe/tank/attackby(var/obj/item/weapon/W as obj, var/ else user << "\blue Tank is empty!" -obj/machinery/atmospherics/pipe/vent +/obj/machinery/atmospherics/pipe/tank/air + name = "Pressure Tank (Air)" + icon_state = "air_map" + +/obj/machinery/atmospherics/pipe/tank/air/New() + air_temporary = new + air_temporary.volume = volume + air_temporary.temperature = T20C + + air_temporary.oxygen = (25*ONE_ATMOSPHERE*O2STANDARD)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature) + air_temporary.nitrogen = (25*ONE_ATMOSPHERE*N2STANDARD)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature) + + ..() + icon_state = "air" + +/obj/machinery/atmospherics/pipe/tank/oxygen + name = "Pressure Tank (Oxygen)" + icon_state = "o2_map" + +/obj/machinery/atmospherics/pipe/tank/oxygen/New() + air_temporary = new + air_temporary.volume = volume + air_temporary.temperature = T20C + + air_temporary.oxygen = (25*ONE_ATMOSPHERE)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature) + + ..() + icon_state = "o2" + +/obj/machinery/atmospherics/pipe/tank/nitrogen + name = "Pressure Tank (Nitrogen)" + icon_state = "n2_map" + +/obj/machinery/atmospherics/pipe/tank/nitrogen/New() + air_temporary = new + air_temporary.volume = volume + air_temporary.temperature = T20C + + air_temporary.nitrogen = (25*ONE_ATMOSPHERE)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature) + + ..() + icon_state = "n2" + +/obj/machinery/atmospherics/pipe/tank/carbon_dioxide + name = "Pressure Tank (Carbon Dioxide)" + icon_state = "co2_map" + +/obj/machinery/atmospherics/pipe/tank/carbon_dioxide/New() + air_temporary = new + air_temporary.volume = volume + air_temporary.temperature = T20C + + air_temporary.carbon_dioxide = (25*ONE_ATMOSPHERE)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature) + + ..() + icon_state = "co2" + +/obj/machinery/atmospherics/pipe/tank/phoron + name = "Pressure Tank (Phoron)" + icon_state = "phoron_map" + +/obj/machinery/atmospherics/pipe/tank/phoron/New() + air_temporary = new + air_temporary.volume = volume + air_temporary.temperature = T20C + + air_temporary.phoron = (25*ONE_ATMOSPHERE)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature) + + ..() + icon_state = "phoron" + +/obj/machinery/atmospherics/pipe/tank/nitrous_oxide + name = "Pressure Tank (Nitrous Oxide)" + icon_state = "n2o_map" + +/obj/machinery/atmospherics/pipe/tank/nitrous_oxide/New() + air_temporary = new + air_temporary.volume = volume + air_temporary.temperature = T0C + + var/datum/gas/sleeping_agent/trace_gas = new + trace_gas.moles = (25*ONE_ATMOSPHERE)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature) + + air_temporary.trace_gases += trace_gas + + ..() + icon_state = "n2o" + +/obj/machinery/atmospherics/pipe/vent icon = 'icons/obj/atmospherics/pipe_vent.dmi' icon_state = "intact" @@ -1048,15 +1053,15 @@ obj/machinery/atmospherics/pipe/vent var/obj/machinery/atmospherics/node1 -obj/machinery/atmospherics/pipe/vent/New() +/obj/machinery/atmospherics/pipe/vent/New() initialize_directions = dir ..() -obj/machinery/atmospherics/pipe/vent/high_volume +/obj/machinery/atmospherics/pipe/vent/high_volume name = "Larger vent" volume = 1000 -obj/machinery/atmospherics/pipe/vent/process() +/obj/machinery/atmospherics/pipe/vent/process() if(!parent) if(build_killswitch <= 0) . = PROCESS_KILL @@ -1066,24 +1071,17 @@ obj/machinery/atmospherics/pipe/vent/process() return else parent.mingle_with_turf(loc, volume) -/* - if(!node1) - if(!nodealert) - //world << "Missing node from [src] at [src.x],[src.y],[src.z]" - nodealert = 1 - else if (nodealert) - nodealert = 0 -*/ -obj/machinery/atmospherics/pipe/vent/Del() + +/obj/machinery/atmospherics/pipe/vent/Del() if(node1) node1.disconnect(src) ..() -obj/machinery/atmospherics/pipe/vent/pipeline_expansion() +/obj/machinery/atmospherics/pipe/vent/pipeline_expansion() return list(node1) -obj/machinery/atmospherics/pipe/vent/update_icon() +/obj/machinery/atmospherics/pipe/vent/update_icon() if(node1) icon_state = "intact" @@ -1092,7 +1090,7 @@ obj/machinery/atmospherics/pipe/vent/update_icon() else icon_state = "exposed" -obj/machinery/atmospherics/pipe/vent/initialize() +/obj/machinery/atmospherics/pipe/vent/initialize() var/connect_direction = dir for(var/obj/machinery/atmospherics/target in get_step(src,connect_direction)) @@ -1102,7 +1100,7 @@ obj/machinery/atmospherics/pipe/vent/initialize() update_icon() -obj/machinery/atmospherics/pipe/vent/disconnect(obj/machinery/atmospherics/reference) +/obj/machinery/atmospherics/pipe/vent/disconnect(obj/machinery/atmospherics/reference) if(reference == node1) if(istype(node1, /obj/machinery/atmospherics/pipe)) del(parent) @@ -1112,7 +1110,7 @@ obj/machinery/atmospherics/pipe/vent/disconnect(obj/machinery/atmospherics/refer return null -obj/machinery/atmospherics/pipe/vent/hide(var/i) //to make the little pipe section invisible, the icon changes. +/obj/machinery/atmospherics/pipe/vent/hide(var/i) //to make the little pipe section invisible, the icon changes. if(node1) icon_state = "[i == 1 && istype(loc, /turf/simulated) ? "h" : "" ]intact" dir = get_dir(src, node1) diff --git a/code/game/machinery/pipe/construction.dm b/code/game/machinery/pipe/construction.dm index 864e893dc9..e8ec749a31 100644 --- a/code/game/machinery/pipe/construction.dm +++ b/code/game/machinery/pipe/construction.dm @@ -52,7 +52,7 @@ Buildable meters if (make_from) src.dir = make_from.dir src.pipename = make_from.name - color = make_from.color + color = make_from.pipe_color var/is_bent if (make_from.initialize_directions in list(NORTH|SOUTH, WEST|EAST)) is_bent = 0 @@ -324,12 +324,12 @@ Buildable meters return 1 // no conflicts found - var/pipefailtext = "\red There's nothing to connect this pipe section to! (with how the pipe code works, at least one end needs to be connected to something, otherwise the game deletes the segment)" + var/pipefailtext = "\red There's nothing to connect this pipe section to!" //(with how the pipe code works, at least one end needs to be connected to something, otherwise the game deletes the segment)" switch(pipe_type) if(PIPE_SIMPLE_STRAIGHT, PIPE_SIMPLE_BENT) var/obj/machinery/atmospherics/pipe/simple/P = new( src.loc ) - P.color = color + P.pipe_color = color P.dir = src.dir P.initialize_directions = pipe_dir var/turf/T = P.loc @@ -382,7 +382,7 @@ Buildable meters if(PIPE_MANIFOLD) //manifold var/obj/machinery/atmospherics/pipe/manifold/M = new( src.loc ) - M.color = color + M.pipe_color = color M.dir = dir M.initialize_directions = pipe_dir //M.New() @@ -390,7 +390,7 @@ Buildable meters M.level = T.intact ? 2 : 1 M.initialize() if (!M) - usr << "There's nothing to connect this manifold to! (with how the pipe code works, at least one end needs to be connected to something, otherwise the game deletes the segment)" + usr << "There's nothing to connect this manifold to!" //(with how the pipe code works, at least one end needs to be connected to something, otherwise the game deletes the segment)" return 1 M.build_network() if (M.node1) @@ -405,7 +405,7 @@ Buildable meters if(PIPE_MANIFOLD4W) //4-way manifold var/obj/machinery/atmospherics/pipe/manifold4w/M = new( src.loc ) - M.color = color + M.pipe_color = color M.dir = dir M.initialize_directions = pipe_dir //M.New() @@ -413,7 +413,7 @@ Buildable meters M.level = T.intact ? 2 : 1 M.initialize() if (!M) - usr << "There's nothing to connect this manifold to! (with how the pipe code works, at least one end needs to be connected to something, otherwise the game deletes the segment)" + usr << "There's nothing to connect this manifold to!" //(with how the pipe code works, at least one end needs to be connected to something, otherwise the game deletes the segment)" return 1 M.build_network() if (M.node1) @@ -438,7 +438,7 @@ Buildable meters //P.level = T.intact ? 2 : 1 P.initialize() if (!P) - usr << "There's nothing to connect this pipe to!" //(with how the pipe code works, at least one end needs to be connected to something, otherwise the game deletes the segment)" + usr << pipefailtext //"There's nothing to connect this pipe to! (with how the pipe code works, at least one end needs to be connected to something, otherwise the game deletes the segment)" return 1 P.build_network() if (P.node1) @@ -709,7 +709,7 @@ Buildable meters C.node.initialize() C.node.build_network() ///// Z-Level stuff - if(PIPE_UP) //volume pump + if(PIPE_UP) var/obj/machinery/atmospherics/pipe/zpipe/up/P = new(src.loc) P.dir = dir P.initialize_directions = pipe_dir @@ -725,7 +725,7 @@ Buildable meters if (P.node2) P.node2.initialize() P.node2.build_network() - if(PIPE_DOWN) //volume pump + if(PIPE_DOWN) var/obj/machinery/atmospherics/pipe/zpipe/down/P = new(src.loc) P.dir = dir P.initialize_directions = pipe_dir diff --git a/code/game/objects/items/devices/pipe_painter.dm b/code/game/objects/items/devices/pipe_painter.dm index 3a062adca4..74374297cc 100644 --- a/code/game/objects/items/devices/pipe_painter.dm +++ b/code/game/objects/items/devices/pipe_painter.dm @@ -3,8 +3,15 @@ icon = 'icons/obj/bureaucracy.dmi' icon_state = "labeler1" item_state = "flight" - var/list/modes = list("grey","red","blue","cyan","green","yellow","purple") - var/mode = "grey" + var/list/modes + var/mode + +/obj/item/device/pipe_painter/New() + ..() + modes = new() + for(var/C in pipe_colors) + modes += "[C]" + mode = pick(modes) /obj/item/device/pipe_painter/afterattack(atom/A, mob/user as mob) if(!istype(A,/obj/machinery/atmospherics/pipe) || istype(A,/obj/machinery/atmospherics/pipe/tank) || istype(A,/obj/machinery/atmospherics/pipe/vent) || istype(A,/obj/machinery/atmospherics/pipe/simple/heat_exchanging) || istype(A,/obj/machinery/atmospherics/pipe/simple/insulated) || !in_range(user, A)) @@ -16,12 +23,10 @@ user << "\red You must remove the plating first." return - P.pipe_color = mode - user.visible_message("[user] paints \the [P] [mode].","You paint \the [P] [mode].") - P.update_icon() + P.change_color(pipe_colors[mode]) /obj/item/device/pipe_painter/attack_self(mob/user as mob) - mode = input("Which colour do you want to use?","Pipe painter") in modes + mode = input("Which colour do you want to use?", "Pipe painter", mode) in modes /obj/item/device/pipe_painter/examine() ..() diff --git a/code/game/objects/items/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm index 6bc605a9c9..2a8ec10569 100644 --- a/code/game/objects/items/devices/scanners.dm +++ b/code/game/objects/items/devices/scanners.dm @@ -48,11 +48,13 @@ REAGENT SCANNER if(O.invisibility == 101) O.invisibility = 0 + O.alpha = 128 spawn(10) if(O) var/turf/U = O.loc if(U.intact) O.invisibility = 101 + O.alpha = 255 var/mob/living/M = locate() in T if(M && M.invisibility == 2) diff --git a/code/game/turfs/simulated/floor_types.dm b/code/game/turfs/simulated/floor_types.dm index dec999f0fc..932e40e8c5 100644 --- a/code/game/turfs/simulated/floor_types.dm +++ b/code/game/turfs/simulated/floor_types.dm @@ -53,6 +53,7 @@ icon_state = "engine" thermal_conductivity = 0.025 heat_capacity = 325000 + intact = 0 /turf/simulated/floor/engine/attackby(obj/item/weapon/C as obj, mob/user as mob) if(!C) @@ -154,7 +155,7 @@ name = "skipjack floor" oxygen = 0 nitrogen = MOLES_N2STANDARD + MOLES_O2STANDARD - + /turf/simulated/floor/beach name = "Beach" icon = 'icons/misc/beach.dmi' diff --git a/code/modules/admin/verbs/atmosdebug.dm b/code/modules/admin/verbs/atmosdebug.dm index dd5fee98f6..f4e163394c 100644 --- a/code/modules/admin/verbs/atmosdebug.dm +++ b/code/modules/admin/verbs/atmosdebug.dm @@ -1,11 +1,16 @@ /client/proc/atmosscan() set category = "Mapping" - set name = "Check Plumbing" + set name = "Check Piping" + set background = 1 if(!src.holder) src << "Only administrators may use this command." return feedback_add_details("admin_verb","CP") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + + if(alert("WARNING: This command should not be run on a live server. Do you want to continue?", "Check Piping", "No", "Yes") == "No") + return + usr << "Checking for disconnected pipes..." //all plumbing - yes, some things might get stated twice, doesn't matter. for (var/obj/machinery/atmospherics/plumbing in world) if (plumbing.nodealert) @@ -21,6 +26,19 @@ if (!pipe.node1 || !pipe.node2) usr << "Unconnected [pipe.name] located at [pipe.x],[pipe.y],[pipe.z] ([get_area(pipe.loc)])" + usr << "Checking for overlapping pipes..." + next_turf: + for(var/turf/T in world) + for(var/dir in cardinal) + var/check = 0 + for(var/obj/machinery/atmospherics/pipe in T) + if(dir & pipe.initialize_directions) + check++ + if(check > 1) + usr << "Overlapping pipe ([pipe.name]) located at [T.x],[T.y],[T.z] ([get_area(T)])" + continue next_turf + usr << "Done" + /client/proc/powerdebug() set category = "Mapping" set name = "Check Power" diff --git a/code/modules/recycling/disposal.dm b/code/modules/recycling/disposal.dm index 38e1ff3bfb..0280599d5e 100644 --- a/code/modules/recycling/disposal.dm +++ b/code/modules/recycling/disposal.dm @@ -736,10 +736,10 @@ // this will be revealed if a T-scanner is used // if visible, use regular icon_state proc/updateicon() - if(invisibility) +/* if(invisibility) //we hide things with alpha now, no need for transparent icons icon_state = "[base_icon_state]f" else - icon_state = base_icon_state + icon_state = base_icon_state*/ return diff --git a/icons/atmos/connector.dmi b/icons/atmos/connector.dmi new file mode 100644 index 0000000000000000000000000000000000000000..cf4ea7a3c84ee95aff76e501af86f1261828582e GIT binary patch literal 653 zcmV;80&@L{P)P)t-sz`(#0 z6BC1jgC-^>V`F1pUS2aZGebi|xVX3+92{9$S+cUSiHV6HA0M@~wY0RfhK7b38XC8^ zx4F5w85tQJ9UWp~VjCM9z`(%9WsV=-0C=2JR&a84_w-Y6@%7{?OD!tS%+FJ>RWQ*r;NmRLOex6#a*U0*I5Sc+(=$pS zoZ^zil2jm5DLFqcFEzO&zetITGbOXA7^IPlGp#5wHx&jsud z08#ZR;u2G_=>Px$Z%IT!RA_CwMiD2+ew>>|a$wkiC z;O;`34MC(Lvq>G#ZL*noQBI%ExcmNb0DI(Vg6V2yScp6CHv=C0GZUE0wP7Ldynh*)%0K39~AJ$tEx%x zW<_LW&MMHSEjEeIi#}z4a9|C#El~{I_Y6mkeu4(uSe=;03I;CGy(hSP zCWs}_*)sk-$Sa6E(FzcR)MR(f4G~0j4MBp1zQ)`4tQJ@&x4zDAt-u^^@9yz6$FB&4 z5PdGjZ+$;5N`OG`wd}T1O5NxVAz<7vE&3x%FDSEvQf=FwM%18u`-imx_$mUu2k1BX n9z-reXH%QR^??2#ApV*&yDum{zh~AM00000NkvXXu0mjfvKt(3 literal 0 HcmV?d00001 diff --git a/icons/atmos/digital_tvalve.dmi b/icons/atmos/digital_tvalve.dmi new file mode 100644 index 0000000000000000000000000000000000000000..b34d2903b5cffcd485944d8f02723f4755690583 GIT binary patch literal 2486 zcmZWp3p`Z$9v^i{VzpOp8y79NOR1!}*W-$#O;U(r48@F9OhPlrqvml!Y2A|avYVJ5 zYGW`(n(@dOi5{3D2BR74nH^)iW`;A)IXi0aZlBLRpU?T7^FROp`ThRC@8h54zkiQ` zo{1g?gE83a<#7;$(F$L>b(d?tRPX{AnuoW)PvGu`h6W1@i?0m~%*@OH0Pq!IL>SC< z5hf!eBN&f2G&D?LR$RV(S+o_?shNt!h}ak`24iAkLLd;hTyAD&W<*2;hr`k2!QQ}X zrZ8G35AF}ZxR3TkX$IWWfx#y|A`_1!L{m;ilTTnUskZ`xC<#fbxd6(vVtAAHmQC%g zf`CW3ZSSxHgPR3D8((1(E@pF`um`c7*nR774PI%w61YB~xM;Ke&zrm4vo2saR6hKs zDEk7o%*Ni)xXHl-Px31I&+@b7&SI`|@?DPkg)dOj zf$0GZMi;l&V`pIMEm=XTlT|QVfh!@I3ePP4F2lH&;6R|-=^kUd*iJ1SaS2I7r?VKx zn9PeTbo6FKj1 zfHMnXfk_<`mr4dc_4j*dY7qgZZp8Ng>OmvV>`}Ho%6A5Mu(&>LYPz|=9-G7Lm1 z#K`9@rd&ULbK$mwm2tc#5#XYteOVu~dlnHj&u&nLM6yusOo@M$!c=A4>L%u5qbB3Y zXlyEdDZm-(ZR7F}3mMjMW!?*`A(c6+4%@T$RNi zy7+zqY6K=^Ojx$?Wy#eRn$`0(b%}p>NVFVx|JU-85t*s31-XA6R>iFa9iB4A!l<(gio0W8FpEEh$`i7IZ$Qd>E(h#BOgz=OuP)A6ezR6H;Qb42nQZ+4akY`& zVW{RF_Qz0W3a4IP1gahfqX#}(57jCYjqBpTf>z>M{M07;8SokCh^~ChSf+tn43*^A zReKJXYZa(*4z#*7b<;q+=keo3QO*Ac_nAH$w5*F6)5Ufj3!uY0pdL>>pwJDgrKGe?{NdMsu zuW@K6U`pT(n`H(pkbZ^+635Xwv#;{&RsY-8^p)ITw-dX0d!uLVGzGl`H3$VxiPtUz zyc+=hKj7261l<*!Iwi%U-8e;AMK`&i3tE7&0ux)fnXX-#<2ZToCu+Y&xuLv7l|V-* z_asfZZKMz<+-P2-z#6>21J50(g|(p&l&sk#*k7$CWk^#Hq_+nuKyePIKZBHQzOu_a zt2j4YmisXEYA5v1VpTB0k$y>K!{T&dq8^)#51Szy-sz1IYS4kIsw+wrHJc@6&Zc=wy_+>0my7Q+~tPc+9!FjY7P&78@J{}Cy$z> z*uJPwlN!ww&g62?$Yb9cqaDam^#J)- z3;6s~cB4jVOCA>+(~K^}{o}z~EB>OFuR&y&m-n5SkxE@MT8bmO>6a{)MkxI{OLL5# zS&$rZ6!CXeL#?BC(rtHX<2`YgcQjnLO+{ApI7J53rjJ{Gw49;jvh{_R+0YxEB)yb;|FtHE2k!R6%V`)WQR+&o(4TqYn6xb zySFwT;lf%QqvQT0WIr-|AX88vQucgds*h;r?Jo*4y5t@-=Qwmwv>FljzHzwx9)XA;J%!NIYYiq1r z?XPvoSW731(DBk->5=$_(w+K|Z8ChfBfxTcaWQ=){y{8nAU+xg_jS%}C%RsG5=7w- zb(BEeV=n?9y)`8AwG-2MwdpY_UsoyGR&bNGg_D-YrRP5*`^M2-drU#{=l3pOFX9k} c+lhP>vjIyW>^V03Zplo0cklNo|1LcJH_wzR4gdfE literal 0 HcmV?d00001 diff --git a/icons/atmos/digital_valve.dmi b/icons/atmos/digital_valve.dmi new file mode 100644 index 0000000000000000000000000000000000000000..b1adc8b65192d4a843b8eb5d9232ab9cf8c224b6 GIT binary patch literal 3435 zcmb_fc~lek8l4mhh+u4?K&3QVv@U>1sh}bRc@*?jA_$0p3QuHFR1_gVVlq5vrFAJ* z>dF$7B8W;rM3j&ODhetZm0$=Vi5m?`NCJ{YGEVX)80u2(Iq$UjXD0J~^E-3zcklhp z{1}Q0wziyR2>^igisgZ;0RV-Zq5ums(Yw4Q<{hZs5Y<-*3OLJt~Q5 z3JnSQxzrn<7nswv-1YQi-j$w)ef#>&&e#{l^14^2q_G7VUmU`p-a-(^>AOWLh0BIx!y?)@WICM*LxsU(Q#b zt)pWAz$$M=;IfG95*dG4N@UdM9V7Z%w}>ZF4&x(DzHnk6*!;8Wo-=k|4E`2kx6I)q zd;X^AlU=8}PTh+BWJ$zeQ0FQ9$pzErTju$6hXkJttHLK7$?Gl+O<=dQ^hak1DmE7X zURFXR&lc(7)_5^{H%5fhj|y%t)IT^M+jOqhGx<)$Y+Om*la4|jpOz)Ne!vkg>uX#i zbGKd2*WgGx33)|O0J*!j_gE%vy-)UVc?b^IC+E`=n6>91!5LN@-+jehz#*lHcd5B~ znzV5%jgci8jnaHuSBVOZJlx2Wt)(XNRP=BPvpFuW9973)Y)@jYjKB6_sOIIxLvC~v zhflfp(}Z7T3Vl>#XQ5dZOWJB`&UK5eX7Ai0F|POV(f}g8tTDz-s)0P>SeL}aDnBrj zX&XBYxY-mx(d9AiS+SY-hM=IJnKoz_y%|ZM4 z-Mjl^+-_fulIVuIR;mQ-U-&s%wxIX~VPIqSprH{{qBq~yC&g3@ zkaDPKy@1gq^zw8hf4TV?XzBq~;Yu%DEkL8wT(@O}izyV6x&UT^TJi9hvW@dX)x8BK z3$-u<85eO_zoJ&oxu$YQ5L@RGHFEB~ir~1hOrf|tDangj7Y~x3960FiBF6aOyVMF{ znhej2Ie#QFGEpj(KG@!LzGfb;KA`|1ov0q-p4Jvjak@Y!YNjynXtm8qm$S3;C1jp3 z8GH^)aa9S(?>>2GROrc!_o}4nG9dvKybCNMCmc7F_I|*4NwH zI~=#?-o3Ec*jVBKMXVxFU);J7rhj~GAO2x0DmFUW!?OWdv=rAtpbJuEJw1`g=>Zho(;7fXz0J|d$q9E8Puqr&Q6o88d>%oz zr1U3x_Q=L?xUzCqY)lM6Mr7xwMZ?-hhea$(Y!mOW+I`*SI&MW@1VzfE*Mc(Cj!o(5 z&pG*njP5E~=hI*LEjuel_F-tCO41XeA8qjT?7^t0>#p1%Tpyn(+%JvmQ;8M>TBVaF z6%BYcjEY!MvsaZ}Y)EGH!H`CFzw%rB*t3C6g^6d3&be`fJbig&ie}ZX2)msC!%x$%9vEytq|7 zdtS9}QPOFzL?AUa^}&|Lnb@Q2Cps@F zKl0DCUo-JH&#bkx^9L1y{)pm+3wiD8&6|6DL0$jnzJyI^jNiq9fq`DCi*&-a%48Jq z%YS**xd~Q4tA`oz(7^=Qu^$C2x()!JB>=!r9stmhr~aV41Rl1i@YAm)2~egEL&?n1 z2pVQXk7oN09maJF72NMfL=ARl^;11^tbo<{+G-qzd1xQ`c`tl= zKoEt5obX~Vsm!E&m2fA8GRb1m^@`TNK%N_N?AS2}_j(opcs&|<(%~ZE+%+`=>a4$B znCk%i#f?CRv0Pu?6F(;zyY#ne7IqCK3qYAcTt!O-A5E1Iy_f3I*ErY!3LQ|2edHXi zMd)L4hF0mTNd-+iNmv^4u>FuBt&8nwNa!pO!9x*-;=E^(t#Ij{QP zEvz;9C*Kg3JXs&pg4w_}=t?;My}CLGA*h*~uZ&aS?S{t=ei?t~O=MUt{^3~RHR#bb z16*)1)u<6aHk!4zx3_19yPNtG zkaOhqCF%rW25|q0^ScA)J=9E&vEGxezUsUmAwZR5J~h6M0>_S!vm=GHwlU#Y3=vLH z{taHhxkds&U4qOQKGwMh)J5RTiGqBxu@DTJm%l|8(4kP{Ct(_!J}S>L?hz8+QIXOt6?P z0<^n9HlXgu=h}VaIc%M4t!dCtpD4&fMpX8i@E^E^x+(tjHwBd{G@13BV{ s@Xp3K6~T)hOEkLdAG6LowqXcE>uk5ns&@Sy`Fa9Ye1i+D4T#VCA3ebHTL1t6 literal 0 HcmV?d00001 diff --git a/icons/atmos/filter.dmi b/icons/atmos/filter.dmi new file mode 100644 index 0000000000000000000000000000000000000000..8b5cd81c70776c602c94baf2249677e7b564aa4a GIT binary patch literal 17954 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 N002ovPDHLkV1i_fwNL;6 literal 0 HcmV?d00001 diff --git a/icons/atmos/manifold.dmi b/icons/atmos/manifold.dmi new file mode 100644 index 0000000000000000000000000000000000000000..f6b24341c9a04ce1762668022902385e95dace35 GIT binary patch literal 1097 zcmV-P1h)H$P)C0001lP)t-sz`(#9 z92{9$S+cUSiHV6HA0M@~wS$9$w6wH_hK3p%8n?H%xw*L+85v$)UbwipR8&;Dy1Kl) zyf`>Getv$&#>T0ssXsqIK|w)`jEox_8>XhFnVFfZtE+&3fWE%IzrVlB%gdLSm(9)1 zy}i9+VqzT~9U&nhIXO8zJUpbNq`<(y`1uOj00001bW%=J06^y0W&i*Hi+WU8bVOxy zV{&P5bZKvH004NLQ&wGQ37AE4cc(fP)4A4vSHohLiKh0008qNkl{EGVl(zc)5ivaPdPiX6J)+bxiM~mVx*TK= z{eOS}CYB38wuk-`olUs_WP9j8*9G+vAbaRP*CiQ%Y!Cfcj@tob5B*oVroIEn9{R6l zw_E_g9{Nvacid$N?4f_Ng$MxIL;s&XfB8Bm0zmfAe~2A0znGhaEAAKFI?nuL9qL=Ow)8~Q`^_=V=C%x4FVYWS6Non#iTBtp3TbC<+r*v zYx8nVN^)#V$J9@s0_@w)w^jWyj1?Yh;?X4>g3uCKRcE9tf^ALTpYz+N>? zlW+2>O5V)7sXCf&&6Dm$o+nAt^z?--?E>f^fKz+n=n>fKoW07_cf0-}UB|2r3BCiB z%fM&M>5w=5EIMFyNaCL4UprEVbWb#3i#gpRfEt{D(;>N&pX*s2vU!!akkui%lOHNs z9n$@tiw;;FveEL5gw-Kz_RD79kw_#G`40$PAvx3sWP8DbXMI2jU|$~)^j&>GwD+hF z2m$Q#e@geL4+sJ5>jUR?yQ>d~x<`FL2w-0yIIr*P1G0|m1Hu7_;Ms8`5{X12!3kbq z_y7Trbv`}-ZoYtqoiF$U0dVsLH0*o<9{@RDzz0Ci7tpZt1vJ5*`|0@rMCi32_DV_0CY8;|D*YVBkR@S1nV;a09}pe|EKc-gZ}@K zwdt)x@3O9T-+@8?-k%SU`v2Ygy>;Ln=sWG&-|}nE4_wYqI?f~i2acDX z0bHK{1IH`R04~q}fn(2y9U}h+j)lD4=QyAIANme`ABg`y5Q#)0kpTPzrD;e#P{e4b P00000NkvXXu0mjf2esKwuf*9|JZf@Rb4U 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

6XS=6$Dn@OePhLn#fN8jjxD{adoD{mJF<2E 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 literal 0 HcmV?d00001 diff --git a/icons/atmos/pipes.dmi b/icons/atmos/pipes.dmi new file mode 100644 index 0000000000000000000000000000000000000000..019be28ffd8a7a70de8e4cffc0ecfd4c89a1c55b GIT binary patch literal 1433 zcmZ8heKeGL6dr0Cl1MfmgV#qN*r`!=H@j!nYtSNAY9^Z{M9Ai28Wnb0uW3j!HIntQ zjUp9N!x<(+!w_wyjzLcLh$Re_#>lrB@B7>7>|eWo-22@7-1FS${&lkh{Jr$oo3F>= zaQZ&po`*D8`Z;vgXtHEeA*6xC06+S^*49=F3yYwjAfZs0ot+IqkVqura5(k#^%pK& zFgG`EXlQ6`Y&0`73k?kwi^X(0y{V~5B9SyVHwy#;B9X}Da?{h(TUuJAQfXmfVMIhk zadEMwrKOFH4V6j_4i3)B%F4*d@b>oBcqwIfiZs?*rw{qlaBdTSMQfUKztWGK_KZr3 zWX3X1$0jD=a4CFRAcJ{kX`aUTv@q`IyVJ4jrHod4*r~^PWRxWHb9jzpaxaTroDVs_ za^7#vAIHNoj~JplZv~hrbgAh z-MGU2QTU%=liFadeb-Jkb&lr*}Zn#xFXW2f4f*iW|k^a}Iz^5;hS zV(nZr><#=&x~OcXl|`hSr6X_KUA6gUq`kqFpurdT^Awloqg2`O^F{L-|K4Z6bMFCu^>zWALWKglx9>cy6$)NnK!- zcsuKQ&c0t>ZOoa)R*4SEZww9WOlBX(PsPXk%|;JA_;gxYxfy9k4&-f-b5@ewU7b(v zFwtRdaRIM8iKTpe*YH3HrT>@^~OUF%9i)wxp7Z}s?LZxVXu zP6Dl5Rr6|z&WgTq5%LW0sP;e{?{Rah)gJWHCb$FNiFJRBVZ~B9Z7SW~ndCG_F?C3W zD^DJ?wdEGtdRtLj1@yMMXg;SN$sil`l6$dDFadIqdaJ$Y)>9^Ad27GE-k`29aqkfM zu|%ot7`sho&@A^-HY`_mp;E%;rf$3P5$OG))-I#`0M0+(nU?A+q z4!!|BX}Ot;ya9~2$RX7ueTzsvbi52Le+bG^Ydr-dLLmhq=me-#fD`aD=A3GmQFd;3 zn$uS$kmQs0bt2hN44sK!lVD-%lu*X)^g6KgBS;Ye*#LTMLnn)sj&f+|*a9Y%q2;UR z2<;gB8V*%}7s5!qy;2e04W6pJ%7Ah?yi^hvE(N>=-stOVJ=1W;i6zLrUTt7AfMyvg zFprC8fz54Jy8{xwbFxhry9)cx+|Bmh>du_go+TKY_CraPHSiA=whIeSXO7o2W2TEs zu{Cg@5_nWD0h>NGF#Lcb7Y$K_)TRdCZJ5bCWF-MLk%k+{QsDWmNg+A~B#^9 literal 0 HcmV?d00001 diff --git a/icons/atmos/pump.dmi b/icons/atmos/pump.dmi new file mode 100644 index 0000000000000000000000000000000000000000..6350782a2f19321014781667ae10ee020b6a2e77 GIT binary patch literal 1561 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 literal 0 HcmV?d00001 diff --git a/icons/atmos/valve.dmi b/icons/atmos/valve.dmi new file mode 100644 index 0000000000000000000000000000000000000000..04351917b65418a7b61e6e7ee5d68419bceb288c GIT binary patch literal 1544 zcmYk6do+}39LJwAq?@KqH-m;Y>7r=a#^o3zBy_ROlsX$DB3d=A)P&bN6U!b;8cNiP zJvCF=iiiv`@09Mz8@63#nMt^ZcI6_xt;t^W=ta4Yry| zo(TZ33fUC69RPxH2xQZV#@JJ_DaM%2hHqvDNhA_$YikCBQBY7285wD3XSaLz?%LYg z+}vCWg;HN%pOuwWS67#llS3wx8yXrK8yjtGY@(u~L?RKB$!uzBYHn_JUAqmErWdQoS?s(&*AdR^zB{1$tY;xk^ltlI+0FIY2b{P6Z)V z%)i*fYjxUHziPEe*T~D72M*qi^vg)K6#!tK6B6jpJYF_b_5-7zJ~wFpnZSWWvtPVj zWU&h>-sAWYpYUgguAgtq&aZ5j`R;(;2y~bCyh!3Whc4&{ezfMsQ-9k04^Xkdd8i9e z(#2NqQw+{BO^v*V7bWGI!Nw)BAV3j38|zjbl-PI@kW;>_xJKML9~#6~g$4I17AtGy z*OH)NKZ0!hJaD~GT{N1FqjN{nlD$UD!N?md!a*t@=fZ*rU0PVk38F>~VlQ{G9-dj~ znS{`y55%jF4o&h!8ONH0vTZn$3nhrBjThqc+^Bi4?zL6dtEkyM4NV4^6L6O^^y|>E zJJN#+pV&9qxB0HqN-+qIWo=}6ZJC3R?kx6_kLkBY3a8K>(z;sg*Z7n{?@q~OV56iw1;^6%mU9OSJ-L!&|mvf(exW9 zp%tCjN3RymGzVk1LzO-_{*ZUdm)rXzf#Pp$w{%**WQI0l5Iexv>xUmdDz85K5dSKG zriS#^YN~yq5s2?U0c>F65cd&zK{r-}6t>}QqAV75{%P)p>6Q7&o7=4rO*tVm@J66v zOY@X$pW_@@vs}$8|9G_hMSd;pp>U!Ox3N%cQ zs8lOUtHbnZ8e(65O|=r!S1oy2eV&EGlAiwOK3r+XC0()VQy#ZC#=@n?@4{9xMP%cfTkgeC=vsYTx~w%KS4%S z`b_enqtpR`s<<5DVa?K?<=jlDqGb4KX!GZ z05x#{vQ`rVRkk%0hjYj?gWjaK5VPtg@t?Er!Mp^q7K)nM+@dWmt(yY&*}vCG+~a2aD?v!m*1)O_(V71OQN{&& literal 0 HcmV?d00001 diff --git a/icons/atmos/vent_pump.dmi b/icons/atmos/vent_pump.dmi new file mode 100644 index 0000000000000000000000000000000000000000..8846103633c08ac8a9fa0432e769c5e920506d26 GIT binary patch literal 36930 zcmdSBc_376A3uD?UY1cpmQWO>LiQ{}S(0oiq(b(6N%mz1g(yT($dbywg(!Q-7P3>a z%f9c-%=ukM_kBP2{p`>0ecwOcKN>TdGtQiIUEk~T{Vdl*O?743{jB>T2%=TFq;M62 zP)W!?DhlwMIkAEp;76tBHNATZX3i#etsL)JIoLyxd;FV-^8EpVhaOChpQQU3ef4J0 z*&88O+1D6(B5WAG>RriLo0qybg${XtHYNGm2&H(-=o$ip2CNvw$q&+zA5g;Z_`^n;c65n zLbwO@93HnXSwRpNq@o~y%{_ju-0%v!?#Bf}?Ydei$+cjok0w{#OseJ~TB?2_QwMfq zHnw`9M~@HRP|0fNi;6pw_#yZh`GJ$WrrswyxNh!F` z?c2AxsQkHt6JuRGEpXuJB{e?i0GT}fM>$k5c=?rlzZ`gV|Ewl-47~5&2z+C{=JV&z z*joOji5Np!hFQ0Z(-x+tM)vmVDr__qr_Y`xn(nk8wBhLSm)+JN*6-Y2!ECSBSOw9@ zJ%0Qcc3&*t9PL&%F&V=cOQN1ksYa6J_GZTUic~V%arA^BheW~S*t9lX9}*HA>@ix& zkFC7wc3AgjWrze}NS4UiKIzU#=#bg{ik-etYc;r2EppI@Zd4MMUc*SPdrd3`c-gcM z_8)NCNkPj#QkBxI{P=EvOzt`a`AUd}6AZgX1uFG=sIS1StNU~bRnpKy3?*#6b7_0` zlGnv+lZipZ&S4mx`V*D4Ca$MHPrJB6iC-huI}_J?!WE=!Arc&Rd&*>Dab@Lhi$!t= zJR8OE1b z9Lk-uvA4gV+Pvbo-ygTOc8?w78(&({IbB=6o6@Hr5$?6Ad`D=~$lLf}o#KPT?5sNP zOARxXCf}SDVVC@J9bTL6%+vpJ*yVAx!L9pJZpubQ&zFs6j_zMsb;Nc(uzR0he&#pG;krV?{ZuXD_55nB@v{hk82G&fL!LT}IPXObIITDdhx7lRb+=<@$+tVimYYk3`m_ zc7%k4P`I`hW+>;q?*n9r-1Bi}kxg_^q@C()ldZ=&(?faoKh6igO7nK03}XA*-IJ?n zU=SATBU<9L%5=H;a{Gphlr_5RRq>+OsZ;!4J<_Sc#lZVw9({g%nPXSrwwy~mc^=$B zt_MDQi{PsmI+1Lx%b0U-lkeNcK`C&hs|}1NUFr0WhV@`M#0??K#W`d!YV8gU_E*=z z8?9l_365=w{PnUNCOZX08dfb)0Z7{hx>=UY#d6fI!;pj!JXH|2$q&n-8P za&tjyWaCb&*R^k5ql#;xu*qS3ck}bsmV{~XBVD)a)yDZ%u{Mg8DTe8&<-nI~A3l&n zavE;o=9P2NqBliZSXi`XS!eDyEqnI?TyQiA$=v(7kwC;d0(4D?43~Qs|q0u_qC*s>0Y_0chhL$52MLV=1;d zV}nV*60~|lNHlc~QxDsN{y7oekwuej)d`*=|O|2WKNgTu37#l@4M-4Z$ zxrK%3(AXORm4mTyaa^SnjNd=*d`#L^-JA>HQ4z9HjeIR)7T94tT}7BFTa^=lZ!pLe z5?2>UgX>^0sxF+r$7gP*68Tg%Ne@5SPbmk=V*6IxDZ`QA611iB#)-brP|c#u%M2*h zxw?kt=793ru-V=meo@Fk9MeN7A|XPP*cQ~Pdb`PDjx0~iNS;38#fx_B(;I zJB80ebLqn#o2c4RY?%+V_r~BlY=RF2<}v4E_z4|JND2B9M`G32r6aed4Se^h-iEqT zxWL>ihN|+OJ4ZxE2Yw?hy1Z*+M0?4#`7jI1$lDLBW@cuG9qCTp46S?BpL;^j%U;62 zh^-*?(nd z^kZ-A#GYR{@ih8b;2hZ%Q`F(a=l9ztFFFj_nHdiA9o8YuP{CDr-f#TSBc|t^4bk7t zJkce6J@Y`;4++hHi3g7Z8yhZZZ>;W(FziZVF?@iMYjT+0etjc(e%95@Fi%~M3FT3} zBln(Zyv9~6r7-J|vorN`kF_JF#aYt!??(JOJ3FDRO_U^MJUy9wKbY|TTuGBE-z_Rr zIA?pZYu0Ugk5c)cSX{31y+}`XMFZ1eDV!a)dgL+(nS50pHM3TM1EyD&s~m4pBbl#bd?t|ZJSk*E%5zy6uB!2MHs30 zVH!(`yU)EizxMchAEu$`n#*i|RF2LlIMP{7mOm51srzNh4NpFKv3M7n|2L9+5_k`vLjRgmO~JzVX(BCBNX^How;ZSwQ%nJR!wtFrvDrelp2?8l-&W4d>KZr#6>N5_k63lwku;{^ddg;G$?{a{`EjiEMPjNL<^h~Z!R3!& zyF;^Ut&luD*^}7c;G7=`J$RW+eFz7@9o6k5NCAx6DH3wz?H8E;EfW0w(9E;-^w#G- zRy9tN@TO{~Y?|I*9=~&Digy$r1vjQ3a4z3>Gj$1L3XO^$aYKOLT6~yHk8~CzK_LOV z0#ElM)jYKy&ZF)iWKMHWEQ0bEcst_KOS<>ZwF|xP&TPgO>W>9!uS#?b<`t4mFpzXs zhB`Y57Wtm0Hm>uc8*QKTA#&e{IHg5|9j!U4niRkKZ?~MtMavvZn7ap5Iz|>lhBxU^6~pTk z7q?qFPFI$#EM42dxRCG(C~tSI++Chob11<4d__C82s@;zpEiW67vvvTciPm!L+1c~ zyQ#w4zYc~K2~OCe^3&+(F}!c(yW9^S_MJJ?OnHimq@%Ob3BR>`2`gqCug<&hgR>6I zoPkoz{!mHEF@`91jh8Qdv z#Ru?B5`u{WC-dFf>}{I{X;PfHO^a!Ad#U@+q|_QbdiU-eD6}QM^XH{G(6~4CS{!*p zLWgOVw!H=8T0qS|cIFJNY$7_6r+RX=+Pokc;21G82c7e^8(1ys+7C*eE@q67k*_ZY zz-Iv$YXo0hnVK(sOv@%_WVsdg%1(sUY3%120BkK+S_8Ct4-*%r>OpNcOZ*7M+t>wg zQPC?tu|b*EM?4}5FOK@*dwUTGC+8u#U8zJsv*B7fq!F}Dd3)$qVB6%)11Jn(&Y4Dn z5(R-`9l#d?;Wk?7=KAuvKc>)L@Uoz6YHrpl$fXdsAG~07-vM&Dk@D40THS?u1_<(pd zBQxVC^8(}q=AwmUW$F6QjCJ3>o~L&@@27tI;*{<&E{8sq#JHOfw03XPa--S)M#1%{ zCr=I(B~%;f+4ZmQ+aah z&(|;Q6U+HA;%Hf@7i-6$BJZ2<7Ls76djmmo;G*1%U#$A{>B5DzMzHGQ!&|Wlggl#W zICvKq61xAW%0Yl_hr!8B+|9Nmots{$o|`)j5q+RYo@6jX-rY3F&(6%H{)n`Ckvw%- zXH+6r_}DIoz9HSrTx|{5P03*-Ps*uKKMCo6^m@wrbz}bfhv`T-eI6r40ajWcxyC8@ z$p!`PqA*XMDJEYJ{uQTa0FrjCqobqJa;5HrAE5sj z12|pxeeOa=$Lk^A*_IN{i{%En9TZtTbX~^N#Y3Lj+ZcmM9LonuFNV1~#k6nN-=w3S z^@To(iJ|m*c%(P?wyrgB9xyWkz%1rdZXhzPJ; zxeDgx`*#A4hsZ*4qFQE0&vkKML3)Q+8**I4P0{3^C-om2&42b|JuP4>az#lg_Fba5 zfL%eg>AB>>ED=*)qhqAdug)IhfV4zC6d#MYIL!-K-k8049(NOgs+Rm_;f7joIMk%QbzteyfpqNgH|Uv)`K!!F;e%>dF{PD|w=rY1;*QQBIE z*I;rfp*PXh?`_BTEm{eZe8-VWp-6{F!3XTYFE+tH?h5yQxt@VDO{U(e#?^-J-o-q< z>xEK%>}g!CXa4#zvsk)STE8WLGuOuU$J0hL{|Q}9DZC>F+|wI!xNHUY*M@*bIp;iE zzUNzeofGa!sW5aKwuW^(Gjg&zzI3&Q7R_N5P{E9l%onuS8#g0UbW9j!%hL@hS4+Uc)Gmx}2M#CrH6y4*%6kh42x=|qXSl9jk=RoN< zjHTxy8F($>adeFDu@j^;@!o=tcRwl2DpPNBvW;U`W~1QD$)kH%NqjfkQlnPCJzP=h zD&f*w6OGq^B~v6S!!ih?)(Cg6(!0uk)KDiFMA6+^;~RKoTFvw{gaUy@uj(@4+_&LR zE5i%L72a^>iY3VqEty}BW^-P-C;($6L@Q_f^&Sn?eUQ_Wo(RWJ{%Ux$Dj-(X)e2&w z4(y}&Ce3F-@}4(bzT#oD6ZP?Y&W@i4G>V}-kR7};va1#=+7tdF+*%gXb6C1XXC*Yo zKf%3rXU6RQn4*ubZu~C2mBA#3`(;An`TTLp zRrBeKYO&elECLALio8Sz!-Qw>@YM|zfdH>}yG7&CV{XIijm-h6?XVk44=M{~pAdH0 z8KMX(nda?)gGuNiiI?gC1%-fFQR0R@#N_Mwhi-uN=cC zK8cDV1yveQ5YRk#9%!*cna>(KIUR5>d zGDqseIVW>|F_{Oq+k_z0!&QtebiSmRsp_h7Oxt8YzwKwh?SNVifKUX_KCsq^#nB@C z(@C#_j-xuaZ!p#$y|~J@y1EJw51`lrL8k|rSlhll)WsUNLv|_c!EE9VM|myMnH*o2 zqlOD*@c`vv-PXo#*~GomxDA2o41j&`tA--z-D>53#%AF^y~@@a;qjHk-hAEyxGV?7 zwT*XZXr%~`Otge+=xWUEvP5^Shc|b%^mX=E4uyjz9$=cZv@9F|JfgkeSLhU{l!I@& z?H=TR@(r*eY>kCq=E!ipZiRpyv&>d6X?80I2s%_zNbA7veFR)EWD(u@croI~xk2Aq zHT+NUN_l5z1_O*{D7c%@)-7-7=|)$M!`ZQLES_6mUwssz#C~<|pj;!blmUZ*FlOME zwrsjj^QOSkt*BBcss+noW|*x(5PF;oEKS4Xt(@{VHr&eHOOf|~{yfoO?@{+Yr{e4sai;0irN~3gP9%CW<0j$n zk_+|DJ61-zsrx{i%D4IV%iZ>Qc@;wVLD8i7@5RpTWYKZR7ydg8w(vI$);I;0CkUW6 zjS~nlR6mNHcWxWeJPdO$kgj-^TUtq`+a93{GMAE-%~2s$wZn}VJk_TKq<@S0$V~!}4q-_z&(&Qk81>(5(u8 z0Kg=AzXhTuheO1MD~a=`z+@%^*nx|MFxgJ0PE36df2lWJ1@wUCX`-7q?4t*#*!!D2 zefI25m1LUj8KzM4%2=cM4N4wMPd z_hiqR*j0UT+~e{d#*$5?X23My!t=u0yPQs(5nuqz(?89gi#|$4;+atBvmv#U56I(N zm99tpxuD@)4xsNmPw;)+Zmxf1QtGKRl|K&DvsdOrzJM=jtv)(1Gk@`W?|f5*(Mwzw zMJ=@}{wDRx9kDnt<3j*R`$c+(?%ho#pC3mdO@oNIUpNi9*1y=v#&N*>0J1U{tQ+^) zC=ZK4`6q%K8&$vnoSwEaH8(dlH6;U-)AN@v6+JzXc2Gg%W~SS`VImmom# zXMNBCeA=g)bjsMpI%+8*kST5?a0Q<$e$9{ztP_`LS25C8_FJLlp$K&9#Sezci zwTzv_tX{Zt7+b$N#656?Z}f!3dKXja<{UYWG2C-z1UvH~z`g3Ns|0@46VkM1v29jL zSW2Ma&Z8|^y&AJ}8GyC`2!d)UVzNkTBNr7FH6YUcIs@=i za)6TA#+qC2=bhTocn;qo{knthNKQbDMzf@kJy5e|R_Awot7FixAk=llle>ZVMm(9} zv8Y?g5mRxKt&Xbc-~WhX@**JqmB96vHzQMbQh{v{Kybpf$wV8p)(K zUILs-Gwiqt3u|j1fL;5bL$>GVs~R}Y9zpxFjVMPd49DnE=jGK#qeTiz7}NI`}97p6le+ ztPjxBEYfMnG=Ya9B3aAF)rf3nYCseP$2ePUfN<#xnL1G~42{QCN4f?fXCW(qy!PZ{i3lQ5TGUXu)- z1fS71hRvQC#tLs`_dNMRXV^bQ&5|410&s+j+jthnu*5 z&12~ow0jX4X-|_tEUr#Y)8VD51AugYKJYj!mXefXmO%-5mC@egkXbNg#LPFSBeYkV4+xeFW6a=-) zX_3fx`X~D%jVrH8(&zzw)a1Hp(>+zz^&pTt=)(*mG@sjEyDV1-He*l)oiSW$@G?fUD0Ydtgx9sy4bI{a3iH@cKdZtPw5Hb&; z_sB5?n?x_V<+Jp+Zr>p1av=biro;poqIJxRT8{uN3 zS`l)K3uc(dHbAC=hjr$neyn8N)Des)Rqs>1oFdbcBuKgtHc<08uJ}R^4zjeClUA>Y z9es5HEYbjp0ayvxr=z82Wgj#5Glh}^U3BLN;WBNo_}oBi%NYpr{OBdJOIohE$AWQe z=RVjYL9SJF?F|J}X#XBx1tA=k=zoFDl0>;EY)EtZi!nz%AlwV(A*+tFG1OJ>c&h^+ zWDMO1J_OLfUbl@W7#8hQkK}oSPTM1|ly3U~^{DLFkrK|~?-btHuA)~^S9kA8^5M&F z;a5q&RrpAW-*%+|T07_zz=G#UCoyvOgH9o8^WLVBtEh9`{`VUn zCLJ$D8uzH1!yYad3S^T^*AQOpYCN&v?H7QCn8&fk1Vfio8~}nnl60_=-1m#p0!S8t z(}0sx1CR{Td9*K_+?77AKzt+-o@Nvg7ay4~9#nW(u6Ggw>+RQpf&0A~hKf#F$v?f8 zKZPL@`d=^^7g&zL=tacEls6MR#GT?ycfoZ{g78E~pUowY5 zT^#G7NGdaV@`z|y(Zf&-&y_PFsPaC1G!ds)nk>;3ZlW<5VAS4aoDV@OD=SawB%lUF z8l+^Q>!COut^p`vx}19gl~Z-ra-^;DEqsULT0UnpL;$k_7oeGoD6OAu^j5J(0D|<~ zxld}&qD@Urg2U|B-hW|;*7=<@i)utx%v%XKy=`7tyA!CtiHG5f6iG(&fjze}&6|~E z^4jUad}#6={5Lp_nw^}RisYQIuvQf0vrZM|oNdQnMm3PJPgJAZIs(>jKxod%MQq=l zzAReJJs}V%E?~$46>v`?Bst&eCPz;OECK+`{myH>M@ju7uhqBgaHb)s-&P3_(m#JP zA>1pdGvF3Max5I@Wn^e^Shl=h(D2MEB1O9Wk|MRGQCl>MW(X!(0dk2<#I^OrXV?{t z5Yju?vX@jFRRJhPuXuo)n;SfW!u5*J_|6>^cm#Fe72l}?F_T^p@NpQOdjYiXWEOI5 zLpLfwLR~5Gw4EvshPmZi4Bqj*7euE`Cl%vp+_|_f?b?X zn6@i7@RZTKqO_u`@3&riXDPyU$-dt1OGcN$q6z1Ut$qYtnb4<)nl%FT^nx#4jk1pk zwye%OQ%Iq@pIyHbbJ1uTO$1?YSTV~NQl8j%^BLuKtrTgc=dlHCjN75rgJ+?ez9@u!ZfA2>|qJX zJFnJLjspRa+y_je@byxJHVf*cW5KbqvBArOUW;{^;d>UfyClcjV|ex%bl;`H6#b*c ztmf>c&BpX0erzW5trf;+fwzuoZJ!Mi_2}AZKYNMMRw&hSJFVz?R1SaykCjRk(??q_ zrmb?S#Ku(QT3S7;ck~rEwQ!bkecSf623zDS__%1H@*|#dCvM7wvH^BqsFcHR4!buQ z^3-#*M-Cti7yh<^0UacPN@A~i$ZJLR8e{JeKAy@wsyEg?QQ4wgl=$EheDc%rJKQ6+ z)d5Ycv(ZMeKp`w!am-pyd&lGWVa7X1H8W=AaS#I~`Yb{0!fs2)mBbjaq)Hh1^exV7 zt0&jtu?^R=)NAR4@N1xWX2By1l~ARZW8N;d9nw; zp2~n&3vA?Nfe!hgEQ4p9wc!N~qEqdYuE$xka|afpfM?H@IR!U%)Vic%W$b{;ku? zC_VRn{mk6_%Oes!?uUNU9JNSy)(YA{r%DE8-7Ka9g>`5wUv~FJ`pI}89k*1lB3KjX zB$m4$kANkt{kt0*0098Rl7p}6TgeG<tmbaN8BNx*ufqr;O5Pu!yo5)dicD5P>*jUiIUN7qFMHimTu>n4QwHwQX16m&j zNbmz>x)F(~Cn36^izgunn40zjb|Nn?kG^GD@yqa6L15aW%ti_6u{pL>5cV~aLV$=+ zk8=HR3&JfgJ3&7i09`e^{t95InOVAI z@B{E-TVTXIo6juG5J4nH;RSQRlVld6G7&y)2f(yz#PA83L4B_6#Bam`DBhO1D&hLp zFyS@0`4k7|v9&&OD_dlNfs4bJH&;~kW=N7a$N{5S@&h^y2z20?)bvWyvBJ`3A%Zkm z{s%-*a_lqpK>&VfYU}6##x3bxk>2T8g0+9qWFWU*sZgexP3>_`DzR;pw#0qpwQc*pFKFjC8F=>Wz00PZg;`OS%A5ZuYcI^-5s@b8JVwTMG zKm>CZ?LAPOzL*OGhoq2rF@nbBU7MT6POx!EAczR|f&iyaCa?Ma-OWHQswt0-jsC@{ z`j0NNj-Uyn@=t2?lFl0f6{oW^T;$u8%rWnvNJ@En$K_9oU31^tiqKrw2^MPfCP;PG^hwD z;^kUW&M^|>){*1lul6t_7pz1wcfMDukMEEw|?wmDrmHH~9M|}WwrnZQ?Z)%6> z#R=Co4B2NW19zUSbuLtTzBM;^{SL;tUTxD9)(q8XqT1#>0xZq0B(Gl5y=2aUrtbLW zovb6}_9_w4AUNtjbl+BYfNziwgVsE+Sw64O^&p{71%SF%*(&!~JenC#8p9nNQ#C>3 zD(Ce$e@!_9zNt#gpswh3?h8i=gyz7#&uNZF2d7XDufZ&)&sm?*FLISB;t+_Z;5&eJY);^%|M)3 zfc;z5-m0|Tv(g7E_=SPJG{Et(a}N zbBdu>pVt(!wzb9Ado7k1&&2GJRkzo%2y!~mOn&&`?g~9kLb5wbYuW?4&BbbiK@DYrJc5 z1R=GYipakLkwL!9eOnzKEI#txf%6zYKee#1u={eI8lZft`<|<+z`fWr z#^&Y}H*VZ;pLm81QH`5+`2L=@yu3K#$pf@7sNUf2Z@Un$xT>EyeDsj3csqpuDnEUL!+&_;QbZ=H#>W)qLz}JVofRy@| zOaX(h%iCZb1(_cAd)p4HTJsi1J76)1T05sS^pHbGR({2W0wH&xcpes5WMZz4EhV3T z)St%i?*_bSzHYUCbuj;&%zX6|ZrV&@c)R7T{6+jWraqhYGbCg#We|A$WZbIdn@Dg?>KS|B zq4!0y$=7Cq$({q>tjq~eZ*#BpG`!xp@9Z~d>9YX#4c<1=-dfj4l%)mkHDK`qE}9Z&H!>jPqTh17;=-VTZq;Z0J!C}6?FkSCiYN^x zU+vBnw2?se10`XF7KsmjF^N?x+Q=<>yy*7XDG;6SSh> zI4pPOyi_Td3d`jk{5IVoMkeb7{n2hpoP!Lgwv6Fbc#i{zP4>#T-~)Z+mgAoX7&aO?jxP z;X!?tW{`+Wyps;Yj$wV}DIHw7ibeJvgt?iM- zG4S=TTv0ckYizMMHxIOdcKX|BprirQ$Dbd&mkFXFaHa+#EI<=F(Tq~HAbMA?f_u(;e2KCvV4 zqd)+`>-o3fvQ|`5BAh=61Fr)l^+_2AxX)isxmUAs&EVqj9~=HFLwNvlG`9{>Ww`Y} z8~U7bwSMzCe_Gt+*FTL0kpss!rONH^WBQzOifA_umPT$?iO!}x_|Z`C?%h+~B;dzh z^4_HfoUhiMqkqeNJku8sj}yonsIB#Hd(0*-I=wn674huZ1B=cM(9>^*(smn z%b$Ex$2~BgA#nL#mG0(-^!Sk$l{k&PJ?O2M;EqAP#0({q9R&zO+PKM=4BXt(U@!kHC6Lab?HaBVFaBnx66CEs=! zkvaaVf|&c>m(i`?qLN{DeF#LX270mZ8|pm#imuRYL|vzbKnNpcg|^lg4qqE&c4D~Y zq;(Xy$Ur9mXs5BUF=TA~xK18gM*>cZ5axTFWaVFmJos&L{aF2OMl%DZetUcfLL0dnEo z!1g&XZ}NqhIRw6NgGEIk_R8g!V2c8Vya6)tr9={Qb8|s}1J`G1r=}O=b#$UX!(dh) z*MOF`mQA4L?KWRAMZmPY)gCG;_Z`l*72H+h8O1<*4hn65D@bbj`-4751E)qn4 zPcLcb<+DrsHVi^*M!s6+i+n#p;>utmz7sh~aJM~o5@oa;#0f#AuGddiPuKA#t{x_f zcw_y|M1$>gx$|W6VO9=`ye{RM4)9F}NDkPvuH?yOtr-4T{Iv3PW3FJyb8_ib7%%|4E6dfWmy!UC&lq)4dU$wCMBazOx$g3t`&7qRx8 zc`M(;`-*5#1_1FV%Ud%RS2x!i>~Bnm1CK;eOy9Gzx><}=Lb;b4Xhe^$7-`wl%sEH9 zaXf>d63mRg6KPszuD1Ozujdlt^|T~uR>QR$z-7BQ;}1lTzzO}1?Rm=5yxvxTz9ayf zl*7uNi=qF{_R00%**+;>|H<|l?UvvpS4~n?3{ZQ550ezS%bEnrm4{|d$Ze1vQh~;Q zP>!#AE@LZqD*5>MssLw-jP>ul;ky@WYA$2Cz;S_rL0Z@Jf#a8Hs^c5R;}a7n86nrQGJD@FG~c(`Jp)89w(PfH zPsqd$kn9g-!(|k5b)N9#Af@SF2y!Yu(BwaQq~Po=^monP`s96Xy-L*IHGB0~Lhn`W zuNi7aH*UnLF9UQk;kEqAp5*C|b2ClZCCf%0huCexjE=1NfjATznpHgTmRbB{%cHip zZ}-oub7nD~~NtTGlUlM5?5t9Dnfr4h3jb z%|N3{4k?{8gv-8;?N~4_SrR6-wyy&(I_L%eWR(CEeDyISwQDzmX?_v#fWAO+jq9kT zc{J&OuOXjA(M-)o3)G*tbCcvYmz$fKE`Us$)eb5;uF62<#Z!``g@Tdvw)dn~9$P(Q zS`_kmytsvhN^1)Fr5V`hBk10lI52_jB?qcH(n@;1pGAsL#kxCKwolz;I@ISjwwx%_ zo*u57?K1XRt?SuMp@{cu9-#D$Vg%68@UNhf*+0+If}!?sm)V{XfEPeV5w+=V zR0(tgP(!T>U+C0t(;Y|qa}9&IXIg)8VzY^0oF7-0prshqaDU-FAeA+7K?Y=Wq!y^E z)%lBNN+j!onj814OqfWDDx9kxrc!Gf6Y++1E{ zFaJwh?&La0#DA19MC~~yjm$SNcUo>+?)kw$qQ2^ zz;Gxj3rOiPbjKf_Rn%&yjNbLtgK5~v8-}+z==0|M7K1nssksa>BNH=Yl>#&S31)2Uq~+V~g2LXbo~ z<6D)-tG@-KG-U7^{}_y780<7k+r@$PF3)F|&P+cRsks&w%wVW~{<BGDz}rHrOy|5v`fAoNaTcDd7UoMlf1n7dt_KmVq#?Fc@x>ztmD5{)N?T>QIXc+& zv83PF(THE`fBkmEJdrj&J&qDA_8=sESv%hIm^!etgHaFhS#4m;C{TIKLft5?=k-G* zf~+wPtyxwPloo9XT7&ib#JDBmXiL-b=!Fa5^w+}Yc+N&WX>IXX&aMwgBz(bT(YEnx z7|itNkyf!PC>zSf9?HvOPh= zH`h0?r>$9FIP2Z{If}#ccd5#ZP;%jM*t`jvPqzc4ZHRt5nDuq^>9*5HthWQ!IZum9 zo?ru%%I{u)S0pq%8$|euuCDG^wELNc^&kxXsFm*PF73o#f5&`~momf>it@N_N$;eq zpW5O)2cdQZ_Pw0Be;)QzHKIKGBwK0mczz?+pX);Y|A#cgZ+ingxZX=TDs)7ge)s9H zjXdT_XEJZiy}7;k7vinR8d4*Ne-l}3I{ZR89^8D&*XMt?ed!Nxayi%4vYnZ+a98=a z?nN(%Nbdf=LB!>kI$kxZhAkTNSZRb~;g~eMO(Z4It{oG6X^GgE!$F7#xHKOj-ek7~ z4SIC?LZvF9|`n zkWHRfxIgtj_>gr)97Nx;{03(ZGzJT7<-bknZb8FWpH22>n`w4pZAz1MYFp0#-@?T7!K{7i= zHLK&;ke$RYy;z=2I4@;b&&vSNmmum6IwsJhrEJKZ0daUFKLqS9Ek)p0U;}|P1uGXX z)2zG=rMK&2;h0k%NG=Cy;+|zAfND?18I;&M50cxOK-5P3g}_Hb=!x5Eaqta5{HVT3 zOrSoamiARttq36&WGsG+v%TZ)LEz7o{1uG>%NITJ3OJXMP83`KtBQKy5rez!>hi&O zDcD#yT}uROzAtw__+sRVP+kuqylme>qsipJ011?oTB=-N=-M1>cZ{lwYT#X&1Z8|4 z$Yr$KF3!n$cu4-$`vMdo5XS$O_}>^{fI$@<0YBNj)WN%>EW$em{On*T0muR&Cv#N;+H&yrqNf;0Iuxm2!x`37t;YA-;HMxf^- zl4bHJHz+KOzxEy|O$A3dIeTCGz1i4xw^rDTv1=lE_re{x3uKGTtA5U@ZB1f5$$?GX zeK%WN%UD2XzZ~H65g$y^j4ntRq#^DG6X4DNEFP1a1auj2*MYCNWcDa@ie3Rz1YL1q|*bRym(F zCMsi1SCD18uXlUhV-pm< zMNbBJidQF4f7-^Q1l{m&vs)05FMzYZk!@^u3EOO-p1E?+{DMmn^laJ&9 za2j~5?+0n4MTSC|UGcwX@JRrU1*R_q$KGTxk|wSm4#9&^<#4a=kjnWz?us37^oU+J zW|)bHqN)E3>e2lv0}r5H64`r{o59Rg+04w`o68(HpxuD1%fK!U*`5G6U(5|3o6q?e z(Spo>WZYZU70mfRds_|=>=jU#WbzGogg+&KFnvSVCCstD*RCUlq!wT^ggK6jKa$1$ z=L|g=&bNcDYxtssNT{|WUzWdq`kmU{`qg@3FBQ8{Is;MTfb|pDrVVT4akW!Z*dZ4- zO8;EWL@)$t`K(3p>>Ef(*r?NrQfY(HDonIej^OxBdPvqH57GlU7gtHLXoEH{8wrB-wxGtk>TR#^drsJ z*q5_;Z`|h2`3?7#JSHT*is@O5gdg^zOSyjVruydMk2L#Vs%8=i3Dn%d#K)pPTsSu7 z#?JIv8?o$OFRQ16kllx(24Tf)CGL32hv(rZuRW%bAiLZYqfob10??6JJhyUt&~Nj5 z2)Z$_9G1an4%+5yBQR58(P5S<3xA1T0X)Ns;F-de%~W-0Vgg|EWG3B?$`<1DP_evw z_@<$sDc{;IyoPI?6uXAhU+Ni{{D?2OipUbW9BUhJ@t3jdc%2T7H4iJ&on09Cft!hx zo!*xT@Ls0ta?)p*3WU$db~%3%sTEw&VSK=9Jl&akr|7xR3~NAn36ebPqNEJFL=i-(2p-o0xikY6J?OqS$BhVZ9ATm`#FeX=hm z?Y}kQ^m9%Z*_&u+QFlXBTs--W*@q}HkRK*5@OJGT^$tkFAz)Bul)I=KeqmXRKsn{{uOXxl5?f; z+MN6RcCJN`RUB~Jph^Jl6R7ii{QN+|4guS-fTXBp1+&1fBo5f-;$NG3KZC?S&g@r2 z9lIg*E0AndA6BvoMZkz!fFPTcp+#jt^7`VJm48DwU@sqlZUFZR01q&DG%;0$Yz*re zQT*2_tLUA}?p0yQ0H17)al*mT(NT!E0O7Jhw+hxJq%*w}13Ltg zNZn_=L|o}4?g*TG{4@1p$6&u7aHtO)`49vmZ4a_gsIOhPvxc+sE-s=m(vaMLpqJlJ z)UvtSPyS?rAekRBu>?N@9ujc74ejEn;5Lx%UrA>ehgsJ#8PK?+#2)t=3#isef4sCB z3J{-{Q4lWU_Vp==A-@L?9^9Wo?=iO@&>!IFwAVp^GTU_dB#%-T~w#?$2Hm_)?DF^<7*U5YSXs4)hCJaH0|l4q0idfA-z}*un7y+dKYX{ z6A4my^*KEnO7MqGRKBHkz8(a5czA&5-l;?jJMW{hiJ??Ilw5!KcHOe_S-;|(HHG(o z1``oTI8qYb6;PFNtGvEGE7;@e)O@a=DA!)*{eIjDDC@VNI+$%W;Hds{8hYmsM8KGG zIQbGI$k5Yo=bB}2abAbs{nQt|2~wOuRYJ@~U<-hVJWP2#STmkkE5LZf5!O2SX+Okb44vT@0AFuS>)du@88SUY>(M=pM>;mQ% z$W;Ajz=l4*vQ|leMkkY(13ufov2HdXpXEqZ?791O!=?0{fF3VbCTiLL2n=@d06zbx z(FAz@CHBfSUE=1Dqe}_Rt#lKMLw5oVFFZh9C^W7#%*r%QK9wbEYny5HB?lIfjca)u zCmOpY9VZ*Eq7vuOVY~9&{%WE{oI}t1M%M4Suc$MlGv>4v+sP^D4?RaISR4|kqvJlm zf)`2{E3c`-pRXbRSw{TeynuI4lw9;$m>hI&l}V*aNjdvSx&$599XOL=2g!j`mSBha zFqB4C#Q?H>JkB9fZn8(lD@xQI<$~D=(LW4f+IFmogK5AKonXYPX+$ehuZ#c|VG0ADfuH zaSxeXY*JugAV`6+(@|c%di85(XTZ~^hrsqM^eQSUdEe&&a&s*`0-i%vrhL{sL~QW{ znU1o=!Ao{vBMaSTYzLVrGa(VZj=2TjVBf96Z(^oSNSrIG*+|qSh02?_Zk}7YzbEu${jq0VozbHoKHZ%q*rO0ppyj$1jHN>BkoP5+g_U^d$P20Yb zeb9*?GtEJ8(`1-2YBO;c?FfH>Z3*a8&=ZyU_qG|&T{k+5iTZw(@F%I2qa&LtN6k#n z+xGZgv->_{QMsuyWogpX@H%Q4^?c`XwY*Ak-!av$V>} zJy#=A?k8pi8Zw+XV=?U2dfe)ThI1oa0z9{Q=foJk1d%5n19Wr=oKL%nB?@Pf(g)Ry zIQ|qsS=9Ulb%>6abqT5+0ne@vqk_TzNMuy~ddoFGN-jF^-ZT=l9N3VpMvI&S2i_l) zvR@i<0#B3~-Jwx%T-d4q^Z}m=XHn@gN4CA6hsi`rf1&hQz-(d$7VpB76~0{aIO>ig z#JLI2N69&#ryPW`HJ{7|edJ=a@xijTpAD!<^zr9Sl%WtLkXZ7}mvV7X`+Txp8G31W zKSVL~>(bN#pCNIdl8lh_3I`6{R7`cUcIwpZk@WPVxq;_7@otk|x-7KgZgsB|SKkpS zGr_PzTdOPtaL%XZs$RZ)Xi@E1v;g;!lchGU72Yo^w6_NjO~b37Ve-S-tsYA$gb>jl zUaOuhji_hr+!MMOLPsf&qsqR^ff(QIz{bi;8c= zMc~{z$<1(_ssit~Jq8c@dqbVOY8|y~I%eqmi*S3GdY%O7d``bg%>U`_%fq4U+rO_d zBI_t5r3T4TSwa*sgs3EKNQyS3L=wW7k)kM+N=U{|NU}%P+(<%5NGP%|*~gf<-t(&a zex9ED`5nLKIo{(v-un-Cgs$a#eb3K!o)>$J6N^(AV!*L1CoDry*vPxDXc={C)h8?a zKMJ!4lwf#FcDvYU14sSsiIQp<+Xu0;F87`?pO%j$OYzX)E+@yum>WCu+$qb#dBjc8 ztnci%k7FlSH#aLOZNG7S>EYnuXj~^B>3GOAN%b`Ld<+wJxUfr~(ePv}o>Hi(t{-3j z_|8y)inqv)_G1NIodLz4g$G}?-yKaiK60d_{s`qgy+H}VeMWZ-kj@mKO+QG3NK0p1 z2qiDCw=Y%W)d3&m$u4IgDyMQ8;D zt6>v)ZdJlo)Wu)cDYlH`LcAdP?rwa3=Utd=nR8r&*6PsfRs>Oo&zIC)u3TwyVRAf5 zRKQLfnHcj-2<`R&2^sjHhDMQ%(&|R|>s5*;@4SB=b>w(vTReSu8?bJ$L3IDTO*2PY@)MXERA{M{Sx);6mDEkvZptw`nsZXIKBEgUL>{P^($HZo+g>ye;E zJ&kMp9i8LBg9kM4D?1`HPwE}KykgiSMi&sG<@0WABYlF#u7J~r`v=!WHAF-~{SNV5Q{^N6}+T?o*l$i`}s1 z=OphkNSsV3j~Qr>EufE6%8(g23RzLs>MpJPM(^2<2P*`ql58(iyj{4b%q7*;Mc`k) zXttJvgTp4fWAgheWoVmwtZZz5!7<)kCtc#Ew#G0UqI$yN&}cpks&Q1EY@O`7Uu@AK zuOzZ+Ym=04D5HTnz`BASV-Q^htxVh=eMRgY9TPbbiX5P?rKZ4w%$B_gk5Sy zsBi+|tbvIdBxw&GvAWT8P-OS|&jIxg@%d3_J!qA^NLdM?=EEgl@#U@;vO8d^P~^!R za$atpgtqp2a|LVodSJ038=X&ApvQTqsl8x^{~|{u77iXC-SNQ5C+PgzNvr9Yt3;jc ztZZ-o8w_F;D@>b4AEq>tb=r?bU?+Cs_%nNa`tuHsJ@;+iDwX$oP>U+vkr$eX5wRwt z^R<1xtMMkJn=@8wPlf;8sK@y@0v{hpOHct55)x?1$((X>avlql68G=lx5@962$URk z(}X|Ue>tYbnb2hK?7qOSe^CFx0j$HmdFY00pmU)W>>GZ5elQMAdwKOszQ+vWD|E|K zd@rlv1bR%HQ>|?&#F7~5Btx6n?tFK*-@1v5cF@T#DYF*fTYprY@RYN1lI|F5h!UxC#FxtO)O#WOg1t|_mXF%R_TGpI+l$Vo z&@%g7`pQ|SY3+7oyWw-o=BH~&8ZK$pEZVa)dUqS6kwEg1Tn#LFZjmFKuxw~a{=3ko01`w0-lGcz(?KsbY&)98mguzTd{kJ4>AdPq zU=FWjlidkctb$R^q3-C36GI=|SEy20*<1YDhf!lOM#-YXf+7h;!Wwj&p5x&{xr}m7 zMa^a%nBi)gB&BRDoL|+4NA4hQ$rDG4)sHSJ-gy+yK?USvo}Oi*I>*+C`&6_b44`Gd z+0>l}UE4H=?w4)cxG``(XQCMM1 zFW**PoI%eZ8xieCL$%G6?N|J7tIk<#ufrgza9?;q$l`QycD`xt z0@3&VdtCn_-b7)Kl|LW*Sbn zUI0{hxG#DcoaBPtg|#M6pT#r!ILm4eU;WvFrL2Y2QXU7f1SceY8JW*f%|nL|vW=tO zvm_ftW9!a4uY;_0|3oeZWoN7@es23X5pmc&<7C;Ob>FFMxHV0Wk?*tpN(m0`zHGNu z@b|PfQ`m}MHQPZWsqdo^b<=4WSd2%srMyyr!k5kR4%_V-lVcZb2!tHL#QbnGP{2!`dL92HnS zPZ_)dEb}wkxMbH((6nX}UJ+8nDI2Bs>;hZ}AZu`BB&vnulWQs$MB~|^cB($1Rh$`@%GdlqYn4dofBICuB#6rDbJqAah6r>+dso?-}>z6 zJJ&)qYYa?92l|0U>i0NoO{}=KAtC%%)ms;R!nvqxJF2&V93q6A#|yFJpnxHt=5YW= zFr)%(KP7`Hbn`o#7$DtOmUM8T;d5o%x`!c$!}fgQN~EE>KOWmRRjA97J#T_THMHelG$D z9{Q=>zYFZ7-+{|+42(a0`qY_aS0f}M65sVfHy>soWRcc{rpd)UeE2Z2@q_%ehlSER zaGe|+P3>0&MHF9qH}3O6Y7EQaK~vtb(C>^6JVMji5M6n+>b;tn_Ybi-&n-drqq@*!iQRByegsQA`!|Cva&O*99E*p6w!-Zg*J|3WGYv53eY94< zRK3&IG5m|aAd?UMMp3DWj?1z)fk1t2*yl-R%z;^wH+pOiS8tBuImAD3c*2g^A-^t+ zyKG(;>tq6C@STk4>0yB<{s27O=)s{O-MxFc*K2#o`{zBO zv4zTQ2s8O(KzJGreOUP7Ry*FprB86=rpgA#gwQ?vlOyk%jb6knT~o6#`;^X1>Bwts z@RU)H0nyhDMu!R92r-4%8d2CU@FHvB*1LJ`0 zM}Ak_DjpW+htoTz9?nKhn zL31g><-A04^95D7F~5ut*N1|PH$h`HYu5XtJhuKmE0_$qQXOB&Y;*2 zW@T-al9v839~QO|GP$SPU!GerBFM)^cch@A)VMp!D%ot`B~pYB5`1#3v;J5dpNS5f zcW+xbfZl9+`33}{4;xSYl8nMxl@Th&X0l5jb*m(@*jO*YEj2=5Div zi37)3miY_9h>p9vdK66efx#;Im*!6cpSsjFesil9A2jyJ)>z+$lJ=@=GJ6)=_1%iI zwLZo02W~J7E<0;%=wwZL2h$qcyYPUd-2EpcWi)y6y%?e4MQkV3i|$1~ydC&9KVn$D z1?7VQi9mjVb0el-*rIsqx4X}Y!8jI}NfzONFZ*|SD*fzl@>Bye<_yc-Rk=0fCDQkoi$JPrLAl2!m;zagJKIYYv;nc?laR{d?~On{@A7&c1>QaxQ|v z9s|2Q42Oj}g3B=D$?xQY={;^m04Rb0++aEtoCMCpscpl}r9WV15zM7%Y-(QyZJ5|! zd;B=<>eiLe;rV)fy?G|K@~HEVp0o~6{tFaRAig2do65 z3kU)5k-L7Gtb&5ST;+|;;hANZ@;8@M?}gf!zhpPtJ@67uA4Ym!3$Au6>Rq$85^nI* zg02PnTugjP3C>SXZ;*01ZoR1JsWsG93N7HR{TP|ur}W*E7lBe^;m`;eGyT}K29yws zr;*%cokD*cBEiZ>#HFQZrKKTBGEYg^WrU-s$8;(9|NXE;YAMlKNbLL>`EDyf<9=~p zC1KtX)^Gjo2hG({4)iDhSMa65*?ogYBa1V(Th%xTWDGRKH17n>=deAj0N2e8UQ(kT zrv~4)O})5U*SX!hg zP|@7nn6IDOx_dxK#MG#K*BQ*^w)C~E(p++!@+ZLtpTa;x=Hfk1xmxE zPZ5N6@r3A_;k7+3g>iA+P3E zbzcWUbxbA)P}k>4lI5F7wD0U*lNq?iO14Ukh!U%h3mZ|TyynTH5|5ZFaU?qZeCErS zY_Khy_k`Qp)ZV(RtkY2M!#+L^Ti;u%x$S$zAJG*jcqFfVke03(6017o=Q|g(->?kH z*|1G`wMkoJe5~;AQx3@9?Lvim6Frej(o@u7gYp=o)UVcX3q$L-nY;4pb z9a~yTn4RTQ46s|v`;G%w!=S=X#$G%T@%8d*5<{C=p$>X zrQMw~1lADAQ?Kgey9A`5X2>-T7XK?p;1d@)IXHyQmv#EAtrfo4Je1&A=Hh5AfBzB1 z1e`u`vQFLM@ZN58j1S`p0LBS`ygk`co_F};Ip@CFjdbhlmbe#4rG*jCSC0>lR)F4& z{c2F@0^IghCumbCOQkW+cAvZwD_#+76c!ue2vi2KlU4Wg&`-hn3Hu?73XiFJp>QN2soH~bCP+wc8dkR&5{zPhmMzNy-$sA*O!>|B(nx0QPn zsMvPz)oo@S%;v4BP~0ptR>ACz9A?)%_b1!j*yQAZi0`hLotM>vHYa~sL2g#_9dfn5 zR1)|hH!&sCsSH+(kK&=e{ZwF)M>k5Vc3%@k_FMtJvJ7_4FxZcY$V&Yc{)u(=Dre%< zZgZUZFe*#Ltu|IU+lZ?HN(21B^}<^vT-k$8`<^u2sY7|sc|{brN&M6~ca2`GESEn% zX?aos42pH92Qvk?N6JutBOCX$kwaX|baeoJzm2B>G!_I?ZirME-v~zuLVUe(S)KHY zL=OC{^%uL!LopXSbC0l4CVlrS9SHjcCWGHUYuHPTgIi{M{~rz>>tS>(Dt226q{(sjYrE*w0KDiAK(D z+t)*=a}5-KUI$svGDJU8{J%1ozo_k9rFT%#>QV*3IUozz9vLSa2cj+TnITtTG6hx& zFy0h|h+A<+#2aUtcz5xC{U@)vbN$&*VR&%+0*Jyw-9bWAs8iRtK~dtF4_uA&x<-Qkie10Ye_5nqL(xTt5YkG~? zc!W^F_O{7oAD=(%X*ricH=Hv2!GuMs`>g_#kOi zhBO@YQT#5A*I+AJWTKb7D3A!pl!U?JtyQ{wX75uV3R zWzWSsbefSEuMbohu06b4I{J=a*#km*1W(XoEvk&6cIv7i1k59ZA%%$^0FmLq4Py&@T$0Tt^|Rk~Q3F4A|(P>@wM>1~RQ~-wQzFhWgIRP3bOYC8^B6e#!G7nBAJGW4R?pTPBoSVAypb zU0jB0bDfmdo6p|e&ufMcOwziqEyeikJ!S2KQxjRTTerk)rBGOmeZ)X#IbO=5${5Av zlsM|%S<9Fd~{297pKj?^|h;lZ@yBzSW=!o@V@QYTF7 zT8~YcA1D2cADl$(^3mq!oNrERIExp{m0xghkoIA8cJEF<0srWVU|jhir^-4n)mc4y zhUv7D^-QY*C3m*6zS6sCV3y*>AUf;5f_V;`R_&DBS3m5kvBfGSmPhKGt!->k(eW&P zczP?>IxQX7k3hSLC}DB&?z6Flp_X}F7-d0Z+39zbEE=p;j~@%j)=fS(!f3wbCaQmk z@Ih^$e;MU9qa^dki?-&GlJI79BvnK&JMZ2Z@b^Vs_44#8FK7I+z{}(Mb2r{^;G|nR?q1r0sl<|Rh#(vR=luYzE zErt+CATWJP6y)R%V$MKNB~hh`gPK7cjm^CKvaLDs06Jj)ZicjTh7+Eh`Sgz!*0``np&W;(>VOb zL#O_IEpS;MD=SCH^Y9>ivlKlDoq?PTN*eMYzwG-i6-*xkAsxb6wy$moc9TQkld6<( zz&`PLbLS+$g#|@xv@<`Xu%zmAIoNm>_rmT%RtYXdB^a1sipRxg2VGKMx~TOYZM=m! zY|kitH7g(rF*r670D7i+k(Z5f(zo}MC;HCX^}0C`r(DcwBev=!0XxZPdS`~U5tnhwwgFTXidXr~c zFM0-o`-?vsKB@sEGn}s_{Kg=Wl7s!*T$=yjvv~AM%#*qDQ@R>}DflQ9$zy6|#S1(E z^FF&SnR|ykEZH6J+c|~_kRbduI^=@53t}Ib5QT+>_Juz9xBJiejh%p-l=;9Az6)3}kl^$n=&c9M3Pl zi`_Edi$EL8fB6HwZKbSj{9>O%@;7gO0iGuk6{d)EBy}x(Ted`RpzL-WOWr;=tG@l( zGkzduaMIXkm|}gGbW+F3y7a48`b?dAIHY}PDFw^dhj0Q&ob=d<;d-zy;M&2L;G%jy zl%CkkeNI1UDZ5Yo*2n3AhV$z&pFgMmrtPbT16nJg6!9_bACz{m0yN_SpS;;6Pgx~n zjpQ8I(6TtuDY7!vXFC8jbD`&G!hy|VsGpo4)m`VznKMW+o*OtFP|Vd=v^Wr0vlza6 z)pFy;4fZ?1uP`ZUj&e>nlQT@ZAjX6oa{vBH*ZI%8!0I`C5{EOj!sUYhH`10FVi98+ zTDlT$BV12NZ73-zA;9g_+a8wNs{(!81tFE!Y^V9oyMfk)!>EefTxYskl^K6TnnS}= ztw6s}-i@=-b(?nVXrFj-=r=dy;BxemL(3egV-YJT0HYgXNY$`6gFL-!7aO_bq={62 zOlT;TpuJ#I@$HAWf&xEeU7QPxtM5lH`tG)i-q9^!Mz=2b{AL8@vAx11tfsESBps6h z*__+Afn?&4iAQ&QirV|T=6ke}GM@>B8BZ<8z%#o4LvSSHNczy==&riiwP7995Qs?Z zhg1bf-v%2AWp&EZGk+N^WfLzNo0<-WN<2I}z6taS*yj+PlP8~^CL!J|`aqaZa&GR? zSc4B|*Y1Z?vs`p4p-aP2WjXim@}6yVdf`5?VyD*}@71eU!?f4#p*wvk7R5?Zwp{~^ zQz|Wgegf51Q~+h_^600D7j_NAA-lLl%FLklX#2F`PV(Y|VNSmeRzua|#CyexQ}4zX zNsjQstJ`0yE_USL00%z=CIWVPt}bW_Tf^_IU)@JWRx#^*eW>N{SNp`uvh{J#7)3Rtp9EV!GkQZ=Zkjn(KItG19AEC zWmoQd=GJ6*FPrKbuo1{1JA38#taRKPxi=_*JfFP!dkIoQ9odi(+}(#=`zz1iV~9;I~Z{I z&!o%FGkUk&A&wrjXE@xOc|PAA zA9Lm?hXaG?$i!L(3n-{IAd_-G;lRQ%i$|1w`*x2^P^>9$@{zuwb^dw`s$u zfu#kD^DqZ4st2ew)MzR|1z@E~IFNU#`i?9AunKAF?hbhOZVS9Hw`t<#DE=iMZ(R0> zw8BZx_AF@<(id+7xwwdB$o1a{aO*tgt^P@Xe`nU#!C>UHXWPNLxITo3P0*)pyM+5; z{mn35B{mW0*EE`%hcp4crAzlqq%{%WGjoh%vKu_DPbrbPWTp4!|EGQaa^)1_0gFv+mwtd(FVe1;q zE2M9Fw%6Fc&9l30$kkPdeMs?i`L9%w>*|71lQR4D2nf|sxS(G7jc;%)D>2vUKiH`L z%SP^sR5nJG`px)bckb+I<3 zfc@Z&5ra<2I&IoN$?U(Ibb%8F+~@J7khU0m6ud_mOvCMenuhyz{(I9f?mn9NpK?wo zFK3P757hyT{)we)|9oZ?elc^2Hp)k`PHzk9Zy4gdeHVEOt^5(Qhu8=Pz}D}cclNfo zaC^SiPI(trlx#HV=r=#cK12RT-g_RG@wdFU#4+OPeSfFT5cmE&ZHAE=fZ<|jX7sd- zpQ(d@gRFE0)q@!ljOy;+t)VgeMyqHYkB9^9_|m3q$w34m@bA&rJ;J>XClkZh>7F+V zp3>l~f2gvGu-XOEvpmPy>~4mXYtGhlXFt@g#u?N9^dBF)^o42ot8BQ8`H%SX^!F|G z+`q#|^CDKA%q*|%?n%MQO5@quge2b_2w3s^LrUCQ(8SEm#7Oequ1z{AbrLVGvm@I~ zSgfS%pKR7Pm1q>y-#ow$zwYo)G)nZ?kv(&yj(98D@#L723AJ2@4Sr7dMOn8Chwsi? zIqi-byxOg3na@aF%K2i`v=t&Qe%PGI&#~C-bMPyCXL~p&zia z5{o`a@6lBwi1}9l@R=K>Z$Ns&4txss{L1d%hSDpa@ah2M@mQPzA0*`T+)0y*0z_iS zi6Ryr5z01f5K7=$j*wVKsDFMhyjuW}-|E$?J$}&A(G^Nh=v+V0AjQa|Kf3#;o-d_6 z@=328L6;!IMp!H~)aQY2o3e9Koq3HgrmTLj$28q0D>3M`p|cc)ghJ zQRa?ooC&QC_Z~l94sRKQp{}JD!kyzd;i*GC^U zjIFAw`f<=+<=s?&U2b1)N4!8GIvub>lv*R30N<)pSd-K^~wZ>20D3)ieDe|Nv z?8pAZ2~9d}qVGo2N5VtrX(i$>vi&nd_jCD$ND)+GGv{Or z*-DDxuVWL%O_Hy4H0U2DJ?Q4%MwmAEMf5-Kd?!N2E(+6mnwG~hUNO0Y2E7Ektf99c zthDOEE`#Ta*3QGVb|F7LT5q15w=Qm(-j6DJ_3cxsoh45r`lY{q*)H}2hMyuGcq4)=rEmXblfM&tVbMS&gB){j5$ z)UVsM3L;crN_>{GbNOTrv^J5a5NF7OvFk$rwlRS!A648SdaCQ!oc;G6)Y+)wQnA--h1LWJB zY>o}PXo#O?cD%eb+r4;US?E)LsIOSNb$m7t49CH~<;T~m!O>THa%VlYuw=faWu)Z9 z7So@_Xb$cv8^lJLA*-MtK#uw_vtKu}ZS!-TKmAMBeJ2fEUakV|e6^Sud)atH%#Lm< zge9ARjTUr`?{U|uE@5$uJ>o~c4B+(-CUl>{riD-Q$;!!L{YT&c`h&3wd1pTuLJW~3 zU$7!D7ycjCs{MLUr{gZP1bkQ_OJq*XTdVd!pUKMgAps8eFrT#&a$QF{f0+;9zDGRt z?O>(FDk@T7!`HLM60ghqc^W&wJPo$h~h8u@Q+>!T6Z&1#3V z{lm_5sj)ihH8*;YH%&^fmOSusuZhW=X8PyfJWipC(x^4L%#b`E*w=5ErBwlU#$E@e zD)d`rI}u2hPkM3cgT)0dV&LBOh)rKP+2B=XCIP`HFcNsG_kgw+?;T;Hb!XH0o5-mT8o5+hbMm`AecfbHTLnN+09jZ!W>l(cB1w}PF=5rffH8(n*D*% zJrEyZ!ef8_l5Zn~PDFZ@beIz(BbC3i!8RdJs4T(2jIi7wKcxSqL++_rf|2Q6#xV@qwWoy;zRhA zKeL20UR(ZS_rn78558bkWgB4}4X&+@-3lKlwxF6L$nD#=UER*p?I1TXhQEK|-?acupwHc<-(l4&nH_+)+YOrtL^IZcSxfc*BV}9aWW32o_Ul@nS z&ZjBEbyuICDDq!g@;+Ke61dV%>0Tr?vlz|uv(}E7YxWPiMHhIm69R>?SfG#xVL#)! zCdX19W=q&Jk|)-M);k=2EV3VVENFhD9f#M2e^NAzZ|WIs&jzWxJO}5sbA899s7Z!Y zPgQ}>P*v-eCYT|6$bRTi@!KWJvoT7}tm4VyTcGmb5!OsH35P@vx@c7VK&y$ABZHxC zEclym@B+7ln2@9rE5k3UJB2?}(03wetMs6BLEDrI_VSb?R;vBtRC|u!Jw^yLZg9uQ zQ+SAy<}ZZ|F)nnfrTfm`vCl!y&Xdw8^=)*78-%HlV)pWXjWpD8HbaXm#*9 zo@+u6)-1AmSPchIyD=;05(^ED%NhL|!zQIqe7d^D5tn5Z+{#Z}{->6W`u%4;l76;q zaFzY7WkW0fA1xcPc9{*)_mo@X!7}0R}kig

P{fqhhmvKqN zG^gC3hmQWoj#^N5eCF%LJ?|o zKW;)hyKtt1V?=X#nY$S1yXC>|c`6fl%X?vb&~!VYbJ zp?vcoT4c{}eXf02pX-dtAN1>~>tCw=YzH|E?I4vlwtdV?bzI^PqqQTBD23)t7#F7h zgz$Q^&@ePv{EIUHp-Iai?!V5hbJlh!^%2Qv;r09@MN1i-(>f{5S=nXXuHQ?{&B8wL zKJtCMmlUd2*DkZ%P*Vfv!4O)rUMr5V$8z-Iw1Z(SW!o$;!Dz&CsqVLSDo;NFc3uSjlwI>s_Q9MdQ9WP+|N@{4fpSzkea zs+fJudhDR{Df!y5BKEw}!l302inle_%Jf8SerJZ-?InFYh!LKUW&aCl*{Y%OwmujK z;;O2@ChK6#k#$832DG z@ggt8><7okp9*I`bFt#wM(x#fVh+Qd`_q6BrH9MORiM_B~^+hbs& K|9qFt_5TA2Vq!G_ literal 0 HcmV?d00001 diff --git a/icons/atmos/vent_scrubber.dmi b/icons/atmos/vent_scrubber.dmi new file mode 100644 index 0000000000000000000000000000000000000000..a116f6ab67f07a3068a5815ef5e4cf6e66a75efd GIT binary patch literal 1328 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 S?7r>CcWn(lROw~w2mb>*+Pp>p literal 0 HcmV?d00001 diff --git a/icons/obj/atmospherics/omni_devices.dmi b/icons/obj/atmospherics/omni_devices.dmi index 642e90a0f1d5115a3fa463293c25cea2342bc6ca..398fd5f159e80909b4a9c05ae0a08e21cc0bc229 100644 GIT binary patch literal 13197 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 VEetT206((cQ**cFS9JU$Ei(*Lt|vn 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