mirror of
https://github.com/yogstation13/Yogstation.git
synced 2025-02-26 09:04:50 +00:00
832 lines
27 KiB
Plaintext
832 lines
27 KiB
Plaintext
// Embedded controller is great and all, but it is really unwieldy to map with. In addition, you can't build it in-game.
|
|
// This serves to make it really easy to make it really easy to make cycling airlocks both in-game and in the map editor.
|
|
// Instead of editing vars, this involves placing a couple of mapping helpers.
|
|
|
|
// also can I say how much I hate the whole radio control thing in this game. It's not even exposed to the player at all.
|
|
// All it does is making coding a massive pain in the rear end.
|
|
|
|
// Anyways for a functioning airlock, you need an interior and an exterior door. Vents are optional.
|
|
// If setup right, you can even make an airlock that cycles between two rooms of different atmospheres!
|
|
// Perfect for the plasmaman atmos tech.
|
|
|
|
// NOTE FOR MAPPERS:
|
|
// PLEASE DON'T PUT THIS ON THE SAME TILE AS A VENT IF THE AIRLOCK IS BIGGER THAN 1X1.
|
|
// (If this is a 1x2 airlock and there is a pressurizing and a depressurizing vent
|
|
// then put the depressurizing vent under the controller)
|
|
|
|
#define AIRLOCK_CYCLESTATE_INOPEN 0
|
|
#define AIRLOCK_CYCLESTATE_INOPENING 1
|
|
#define AIRLOCK_CYCLESTATE_INCLOSING 2
|
|
#define AIRLOCK_CYCLESTATE_CLOSED 3
|
|
#define AIRLOCK_CYCLESTATE_OUTCLOSING 4
|
|
#define AIRLOCK_CYCLESTATE_OUTOPENING 5
|
|
#define AIRLOCK_CYCLESTATE_OUTOPEN 6
|
|
#define AIRLOCK_CYCLESTATE_DOCKED -1
|
|
#define AIRLOCK_CYCLESTATE_ERROR -2
|
|
|
|
#define AIRLOCK_CYCLEROLE_INT_PRESSURIZE 1
|
|
#define AIRLOCK_CYCLEROLE_INT_DEPRESSURIZE 2
|
|
#define AIRLOCK_CYCLEROLE_EXT_PRESSURIZE 4
|
|
#define AIRLOCK_CYCLEROLE_EXT_DEPRESSURIZE 8
|
|
|
|
/obj/item/electronics/advanced_airlock_controller
|
|
name = "airlock controller electronics"
|
|
custom_price = 5
|
|
icon_state = "airalarm_electronics"
|
|
|
|
/obj/item/wallframe/advanced_airlock_controller
|
|
name = "airlock controller frame"
|
|
desc = "Used for building advanced airlock controllers."
|
|
icon = 'icons/obj/monitors.dmi'
|
|
icon_state = "aac_bitem"
|
|
result_path = /obj/machinery/advanced_airlock_controller
|
|
|
|
/obj/machinery/advanced_airlock_controller
|
|
name = "advanced airlock controller"
|
|
desc = "A machine designed to control the operation of cycling airlocks"
|
|
icon = 'icons/obj/monitors.dmi'
|
|
icon_state = "aac"
|
|
use_power = IDLE_POWER_USE
|
|
idle_power_usage = 4
|
|
active_power_usage = 8
|
|
power_channel = ENVIRON
|
|
req_access = list(ACCESS_ATMOSPHERICS)
|
|
max_integrity = 250
|
|
integrity_failure = 80
|
|
armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 100, BOMB = 0, BIO = 100, RAD = 100, FIRE = 90, ACID = 30)
|
|
resistance_flags = FIRE_PROOF
|
|
|
|
FASTDMM_PROP(\
|
|
set_instance_vars(\
|
|
pixel_x = (dir & 3)? INSTANCE_VAR_DEFAULT : (dir == 4 ? -24 : 24),\
|
|
pixel_y = (dir & 3)? (dir == 1 ? -24 : 24) : INSTANCE_VAR_DEFAULT\
|
|
),\
|
|
dir_amount = 4\
|
|
)
|
|
|
|
var/cyclestate = AIRLOCK_CYCLESTATE_INOPEN
|
|
var/interior_pressure = ONE_ATMOSPHERE
|
|
var/exterior_pressure = 0
|
|
|
|
var/locked = TRUE
|
|
var/aidisabled = 0
|
|
var/shorted = 0
|
|
var/buildstage = 2 // 2 = complete, 1 = no wires, 0 = circuit gone
|
|
var/config_error_str = "Needs Scan"
|
|
var/scan_on_late_init = FALSE
|
|
var/depressurization_margin = 10 // use a lower value to reduce cross-contamination
|
|
var/depressurization_target = 0 // What to target - should be lower than the depressurization margin
|
|
var/overlays_hash = null
|
|
var/skip_delay = 100
|
|
var/skip_timer = 0
|
|
var/is_skipping = FALSE
|
|
|
|
var/list/airlocks = list()
|
|
var/list/vents = list()
|
|
var/obj/vis_target = null
|
|
|
|
/obj/machinery/advanced_airlock_controller/lavaland
|
|
exterior_pressure = 36.896 // according to very reliable asay this is the correct pressure.
|
|
// lavaland isn't exactly a contaminant so I'll let it have a high depressurization margin
|
|
// (also miners dont appreciate vacuum)
|
|
depressurization_margin = 36.896
|
|
depressurization_target = 20
|
|
|
|
/obj/machinery/advanced_airlock_controller/mix_chamber
|
|
depressurization_margin = 0.15 // The minimum - We really don't want contamination.
|
|
|
|
/obj/machinery/advanced_airlock_controller/New(loc, ndir, nbuild)
|
|
..()
|
|
wires = new /datum/wires/advanced_airlock_controller(src)
|
|
if(ndir)
|
|
setDir(ndir)
|
|
|
|
if(nbuild)
|
|
buildstage = 0
|
|
panel_open = TRUE
|
|
pixel_x = (dir & 3)? 0 : (dir == 4 ? -24 : 24)
|
|
pixel_y = (dir & 3)? (dir == 1 ? -24 : 24) : 0
|
|
|
|
update_icon()
|
|
|
|
/obj/machinery/advanced_airlock_controller/Destroy()
|
|
qdel(wires)
|
|
wires = null
|
|
cut_links()
|
|
SSair.atmos_machinery -= src
|
|
return ..()
|
|
|
|
/obj/machinery/advanced_airlock_controller/Initialize(mapload)
|
|
. = ..()
|
|
SSair.atmos_machinery += src
|
|
scan_on_late_init = mapload
|
|
if(mapload && (. != INITIALIZE_HINT_QDEL))
|
|
return INITIALIZE_HINT_LATELOAD
|
|
|
|
/obj/machinery/advanced_airlock_controller/LateInitialize(mapload)
|
|
. = ..()
|
|
if(scan_on_late_init)
|
|
scan(TRUE)
|
|
update_error_status()
|
|
update_docked_status(FALSE)
|
|
for(var/A in airlocks)
|
|
var/obj/machinery/door/airlock/airlock = A
|
|
if(airlock.density && (cyclestate == AIRLOCK_CYCLESTATE_CLOSED || (airlocks[A] && cyclestate == AIRLOCK_CYCLESTATE_INOPEN) || (!airlocks[A] && cyclestate == AIRLOCK_CYCLESTATE_OUTOPEN)))
|
|
airlock.bolt()
|
|
|
|
/obj/machinery/advanced_airlock_controller/update_icon(use_hash = FALSE)
|
|
if(!isopenturf(get_turf(src)))
|
|
return
|
|
var/pressure = 0
|
|
var/datum/gas_mixture/environment = return_air()
|
|
if(environment)
|
|
pressure = environment.return_pressure()
|
|
var/maxpressure = (exterior_pressure && (cyclestate == AIRLOCK_CYCLESTATE_OUTCLOSING || cyclestate == AIRLOCK_CYCLESTATE_OUTOPENING || cyclestate == AIRLOCK_CYCLESTATE_OUTOPEN)) ? exterior_pressure : interior_pressure
|
|
var/pressure_bars = round(pressure / maxpressure * 5 + 0.01)
|
|
|
|
var/new_overlays_hash = "[pressure_bars]-[cyclestate]-[buildstage]-[panel_open]-[stat]-[shorted]-[locked]-\ref[vis_target]"
|
|
if(use_hash && new_overlays_hash == overlays_hash)
|
|
return
|
|
overlays_hash = new_overlays_hash
|
|
|
|
cut_overlays()
|
|
if(panel_open)
|
|
switch(buildstage)
|
|
if(2)
|
|
icon_state = "aac_b3"
|
|
if(1)
|
|
icon_state = "aac_b2"
|
|
if(0)
|
|
icon_state = "aac_b1"
|
|
return
|
|
|
|
icon_state = "aac"
|
|
|
|
if((stat & (NOPOWER|BROKEN)) || shorted)
|
|
return
|
|
|
|
var/is_exterior_pressure = (cyclestate == AIRLOCK_CYCLESTATE_OUTCLOSING || cyclestate == AIRLOCK_CYCLESTATE_OUTOPENING || cyclestate == AIRLOCK_CYCLESTATE_OUTOPEN)
|
|
add_overlay("aac_[is_exterior_pressure ? "ext" : "int"]p_[pressure_bars]")
|
|
add_overlay("aac_cyclestate_[cyclestate]")
|
|
if(obj_flags & EMAGGED)
|
|
add_overlay("aac_emagged")
|
|
else if(!locked)
|
|
add_overlay("aac_unlocked")
|
|
|
|
if(vis_target)
|
|
var/f_dx = ((vis_target.pixel_x - pixel_x) / world.icon_size) + (vis_target.x - x)
|
|
var/f_dy = ((vis_target.pixel_y - pixel_y) / world.icon_size) + (vis_target.y - y)
|
|
var/dist = sqrt(f_dx*f_dx+f_dy*f_dy)
|
|
var/s_dx = f_dy/dist
|
|
var/s_dy = -f_dx/dist
|
|
var/matrix/TR = new
|
|
TR.Translate(0, 16)
|
|
TR.Multiply(new /matrix(s_dx, f_dx, 0, s_dy, f_dy, 0))
|
|
var/mutable_appearance/M = mutable_appearance(icon, "hologram-line", ABOVE_LIGHTING_LAYER, ABOVE_LIGHTING_PLANE)
|
|
M.transform = TR
|
|
add_overlay(M)
|
|
|
|
/obj/machinery/advanced_airlock_controller/proc/reset(wire)
|
|
switch(wire)
|
|
if(WIRE_POWER)
|
|
if(!wires.is_cut(WIRE_POWER))
|
|
shorted = FALSE
|
|
update_icon()
|
|
if(WIRE_AI)
|
|
if(!wires.is_cut(WIRE_AI))
|
|
aidisabled = FALSE
|
|
|
|
/obj/machinery/advanced_airlock_controller/proc/shock(mob/user, prb)
|
|
if((stat & (NOPOWER))) // unpowered, no shock
|
|
return 0
|
|
if(!prob(prb))
|
|
return 0 //you lucked out, no shock for you
|
|
var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
|
|
s.set_up(5, 1, src)
|
|
s.start() //sparks always.
|
|
if (electrocute_mob(user, get_area(src), src, 1, TRUE))
|
|
return 1
|
|
else
|
|
return 0
|
|
|
|
/obj/machinery/advanced_airlock_controller/proc/update_docked_status(process_on_changed = FALSE)
|
|
if(cyclestate == AIRLOCK_CYCLESTATE_ERROR)
|
|
return
|
|
var/is_docked = FALSE
|
|
for(var/A in airlocks)
|
|
var/obj/machinery/door/airlock/airlock = A
|
|
if(!airlocks[A]) // only exterior airlocks are checked for docks
|
|
continue
|
|
var/turf/T = get_turf(airlock)
|
|
if(!T)
|
|
continue
|
|
for(var/cdir in GLOB.cardinals)
|
|
var/turf/T2 = get_step(T, cdir)
|
|
if(!T2)
|
|
continue
|
|
if(T2.loc != T.loc && (locate(/obj/machinery/door/airlock) in T2))
|
|
is_docked = TRUE
|
|
break
|
|
if(is_docked)
|
|
break
|
|
if(is_docked && cyclestate != AIRLOCK_CYCLESTATE_DOCKED)
|
|
cyclestate = AIRLOCK_CYCLESTATE_DOCKED
|
|
if(process_on_changed)
|
|
process_atmos()
|
|
if(!is_docked && cyclestate == AIRLOCK_CYCLESTATE_DOCKED)
|
|
cyclestate = AIRLOCK_CYCLESTATE_INOPENING
|
|
reset_skip()
|
|
for(var/airlock in airlocks)
|
|
coerce_door(airlock, TRUE)
|
|
if(process_on_changed)
|
|
process_atmos()
|
|
|
|
/obj/machinery/advanced_airlock_controller/proc/update_error_status()
|
|
if(!airlocks.len)
|
|
cyclestate = AIRLOCK_CYCLESTATE_ERROR
|
|
return
|
|
var/has_interior = FALSE
|
|
var/has_exterior = FALSE
|
|
for(var/A in airlocks)
|
|
if(airlocks[A] == 1)
|
|
has_exterior = TRUE
|
|
if(airlocks[A] == 0)
|
|
has_interior = TRUE
|
|
if(!has_interior || !has_exterior)
|
|
if(!has_interior)
|
|
config_error_str = "No interior door"
|
|
else if(!has_exterior)
|
|
config_error_str = "No exterior door"
|
|
cyclestate = AIRLOCK_CYCLESTATE_ERROR
|
|
return
|
|
if(cyclestate == AIRLOCK_CYCLESTATE_ERROR)
|
|
cyclestate = AIRLOCK_CYCLESTATE_CLOSED
|
|
update_docked_status()
|
|
|
|
/obj/machinery/advanced_airlock_controller/proc/coerce_door(obj/machinery/door/airlock/door, target_density = 0)
|
|
if(door.density == target_density && !door.operating)
|
|
door.bolt()
|
|
return TRUE
|
|
if(door.operating || door.welded || door.brace || !door.hasPower() || door.wires.is_cut(WIRE_BOLTS))
|
|
return FALSE
|
|
door.unbolt()
|
|
if(door.density != target_density)
|
|
if(target_density)
|
|
spawn(0)
|
|
door.close()
|
|
door.bolt()
|
|
else
|
|
spawn(0)
|
|
door.open()
|
|
door.bolt()
|
|
return FALSE
|
|
|
|
/obj/machinery/advanced_airlock_controller/proc/unbolt_door(obj/machinery/door/airlock/door)
|
|
if(!door.wires.is_cut(WIRE_BOLTS))
|
|
door.unbolt()
|
|
|
|
/obj/machinery/advanced_airlock_controller/process()
|
|
process_atmos()
|
|
|
|
/obj/machinery/advanced_airlock_controller/process_atmos()
|
|
if((stat & (NOPOWER|BROKEN)) || shorted)
|
|
update_icon(TRUE)
|
|
return
|
|
|
|
if(!isopenturf(get_turf(src)))
|
|
update_icon(TRUE)
|
|
return
|
|
var/pressure = 0
|
|
var/datum/gas_mixture/environment = return_air()
|
|
if(environment)
|
|
pressure = environment.return_pressure()
|
|
|
|
update_error_status()
|
|
var/doors_valid = TRUE
|
|
var/vents_valid = TRUE
|
|
switch(cyclestate)
|
|
if(AIRLOCK_CYCLESTATE_ERROR)
|
|
return
|
|
if(AIRLOCK_CYCLESTATE_CLOSED)
|
|
return
|
|
if(AIRLOCK_CYCLESTATE_DOCKED)
|
|
for(var/airlock in airlocks)
|
|
unbolt_door(airlock)
|
|
for(var/V in vents)
|
|
var/obj/machinery/atmospherics/components/unary/vent_pump/vent = V
|
|
if(vents[vent] & AIRLOCK_CYCLEROLE_INT_PRESSURIZE)
|
|
vent.pump_direction = 1
|
|
vent.pressure_checks = 1
|
|
vent.external_pressure_bound = interior_pressure
|
|
vent.on = TRUE
|
|
vent.update_icon()
|
|
else
|
|
vent.on = FALSE
|
|
vent.update_icon()
|
|
return
|
|
if(AIRLOCK_CYCLESTATE_INCLOSING)
|
|
for(var/airlock in airlocks)
|
|
doors_valid = doors_valid && coerce_door(airlock, TRUE)
|
|
if(doors_valid || is_skipping)
|
|
for(var/V in vents)
|
|
var/obj/machinery/atmospherics/components/unary/vent_pump/vent = V
|
|
if(vents[vent] & AIRLOCK_CYCLEROLE_INT_DEPRESSURIZE)
|
|
vent.pump_direction = 0
|
|
vent.pressure_checks = 1
|
|
vent.external_pressure_bound = depressurization_target
|
|
vents_valid = FALSE
|
|
vent.on = TRUE
|
|
vent.update_icon()
|
|
else
|
|
vent.on = FALSE
|
|
vent.update_icon()
|
|
if(pressure < depressurization_margin)
|
|
vents_valid = TRUE
|
|
if((doors_valid && vents_valid) || is_skipping)
|
|
cyclestate = AIRLOCK_CYCLESTATE_OUTOPENING
|
|
reset_skip()
|
|
if(AIRLOCK_CYCLESTATE_OUTCLOSING)
|
|
for(var/airlock in airlocks)
|
|
doors_valid = doors_valid && coerce_door(airlock, TRUE)
|
|
if(doors_valid || is_skipping)
|
|
for(var/V in vents)
|
|
var/obj/machinery/atmospherics/components/unary/vent_pump/vent = V
|
|
if(vents[vent] & AIRLOCK_CYCLEROLE_EXT_DEPRESSURIZE)
|
|
vent.pump_direction = 0
|
|
vent.pressure_checks = 1
|
|
vent.external_pressure_bound = depressurization_target
|
|
vents_valid = FALSE
|
|
vent.on = TRUE
|
|
vent.update_icon()
|
|
else
|
|
vent.on = FALSE
|
|
vent.update_icon()
|
|
if(pressure < depressurization_margin)
|
|
vents_valid = TRUE
|
|
if(vents_valid || is_skipping)
|
|
cyclestate = AIRLOCK_CYCLESTATE_INOPENING
|
|
reset_skip()
|
|
if(AIRLOCK_CYCLESTATE_INOPENING)
|
|
for(var/airlock in airlocks)
|
|
if(airlocks[airlock])
|
|
doors_valid = doors_valid && coerce_door(airlock, 1)
|
|
for(var/V in vents)
|
|
var/obj/machinery/atmospherics/components/unary/vent_pump/vent = V
|
|
if(vents[vent] & AIRLOCK_CYCLEROLE_INT_PRESSURIZE)
|
|
vent.pump_direction = 1
|
|
vent.pressure_checks = 1
|
|
vent.external_pressure_bound = interior_pressure
|
|
vents_valid = FALSE
|
|
vent.on = TRUE
|
|
vent.update_icon()
|
|
else
|
|
vent.on = FALSE
|
|
vent.update_icon()
|
|
if(pressure > interior_pressure - 0.5)
|
|
vents_valid = TRUE
|
|
if(vents_valid || is_skipping)
|
|
for(var/airlock in airlocks)
|
|
if(!airlocks[airlock])
|
|
doors_valid = doors_valid && coerce_door(airlock, 0)
|
|
if(doors_valid || is_skipping)
|
|
cyclestate = AIRLOCK_CYCLESTATE_INOPEN
|
|
reset_skip()
|
|
if(AIRLOCK_CYCLESTATE_OUTOPENING)
|
|
for(var/airlock in airlocks)
|
|
if(!airlocks[airlock])
|
|
doors_valid = doors_valid && coerce_door(airlock, 1)
|
|
for(var/V in vents)
|
|
var/obj/machinery/atmospherics/components/unary/vent_pump/vent = V
|
|
if(vents[vent] & AIRLOCK_CYCLEROLE_EXT_PRESSURIZE)
|
|
vent.pump_direction = 1
|
|
vent.pressure_checks = 1
|
|
vent.external_pressure_bound = exterior_pressure
|
|
vents_valid = FALSE
|
|
vent.on = TRUE
|
|
vent.update_icon()
|
|
else
|
|
vent.on = FALSE
|
|
vent.update_icon()
|
|
if(pressure > exterior_pressure - 0.5)
|
|
vents_valid = TRUE
|
|
if(vents_valid || is_skipping)
|
|
for(var/airlock in airlocks)
|
|
if(airlocks[airlock])
|
|
doors_valid = doors_valid && coerce_door(airlock, 0)
|
|
if(doors_valid || is_skipping)
|
|
cyclestate = AIRLOCK_CYCLESTATE_OUTOPEN
|
|
reset_skip()
|
|
if(AIRLOCK_CYCLESTATE_INOPEN)
|
|
for(var/V in vents)
|
|
var/obj/machinery/atmospherics/components/unary/vent_pump/vent = V
|
|
vent.on = FALSE
|
|
vent.update_icon()
|
|
if(AIRLOCK_CYCLESTATE_OUTOPEN)
|
|
for(var/V in vents)
|
|
var/obj/machinery/atmospherics/components/unary/vent_pump/vent = V
|
|
vent.on = FALSE
|
|
vent.update_icon()
|
|
update_icon(TRUE)
|
|
|
|
/obj/machinery/advanced_airlock_controller/attackby(obj/item/W, mob/user, params)
|
|
switch(buildstage)
|
|
if(2)
|
|
if(W.tool_behaviour == TOOL_WIRECUTTER && panel_open && wires.is_all_cut())
|
|
W.play_tool_sound(src)
|
|
to_chat(user, span_notice("You cut the final wires."))
|
|
new /obj/item/stack/cable_coil(loc, 5)
|
|
buildstage = 1
|
|
update_icon()
|
|
return
|
|
else if(W.tool_behaviour == TOOL_SCREWDRIVER) // Opening that up.
|
|
W.play_tool_sound(src)
|
|
panel_open = !panel_open
|
|
to_chat(user, span_notice("The wires have been [panel_open ? "exposed" : "unexposed"]."))
|
|
update_icon()
|
|
return
|
|
else if(istype(W, /obj/item/card/id) || istype(W, /obj/item/pda))// trying to unlock the interface with an ID card
|
|
togglelock(user)
|
|
return
|
|
else if(panel_open && is_wire_tool(W))
|
|
wires.interact(user)
|
|
return
|
|
if(1)
|
|
if(W.tool_behaviour == TOOL_CROWBAR)
|
|
user.visible_message("[user.name] removes the electronics from [src.name].",\
|
|
span_notice("You start prying out the circuit..."))
|
|
W.play_tool_sound(src)
|
|
if (W.use_tool(src, user, 20))
|
|
if (buildstage == 1)
|
|
to_chat(user, span_notice("You remove the airlock controller electronics."))
|
|
new /obj/item/electronics/advanced_airlock_controller( src.loc )
|
|
playsound(src.loc, 'sound/items/deconstruct.ogg', 50, 1)
|
|
buildstage = 0
|
|
update_icon()
|
|
return
|
|
|
|
if(istype(W, /obj/item/stack/cable_coil))
|
|
var/obj/item/stack/cable_coil/cable = W
|
|
if(cable.get_amount() < 5)
|
|
to_chat(user, span_warning("You need five lengths of cable to wire the airlock controller!"))
|
|
return
|
|
user.visible_message("[user.name] wires the airlock controller.", \
|
|
span_notice("You start wiring the airlock controller..."))
|
|
if (do_after(user, 2 SECONDS, src))
|
|
if (cable.get_amount() >= 5 && buildstage == 1)
|
|
cable.use(5)
|
|
to_chat(user, span_notice("You wire the airlock controller."))
|
|
wires.repair()
|
|
aidisabled = 0
|
|
locked = FALSE
|
|
cyclestate = AIRLOCK_CYCLESTATE_ERROR
|
|
cut_links()
|
|
shorted = 0
|
|
buildstage = 2
|
|
update_icon()
|
|
return
|
|
if(0)
|
|
if(istype(W, /obj/item/electronics/advanced_airlock_controller))
|
|
if(user.temporarilyRemoveItemFromInventory(W))
|
|
to_chat(user, span_notice("You insert the circuit."))
|
|
buildstage = 1
|
|
update_icon()
|
|
qdel(W)
|
|
return
|
|
|
|
if(istype(W, /obj/item/electroadaptive_pseudocircuit))
|
|
var/obj/item/electroadaptive_pseudocircuit/P = W
|
|
if(!P.adapt_circuit(user, 25))
|
|
return
|
|
user.visible_message(span_notice("[user] fabricates a circuit and places it into [src]."), \
|
|
span_notice("You adapt an airlock controller circuit and slot it into the assembly."))
|
|
buildstage = 1
|
|
update_icon()
|
|
return
|
|
|
|
if(W.tool_behaviour == TOOL_WRENCH)
|
|
to_chat(user, span_notice("You detach \the [src] from the wall."))
|
|
W.play_tool_sound(src)
|
|
new /obj/item/wallframe/advanced_airlock_controller( user.loc )
|
|
qdel(src)
|
|
return
|
|
|
|
return ..()
|
|
|
|
/obj/machinery/advanced_airlock_controller/proc/cut_links()
|
|
for(var/obj/machinery/door/airlock/A in airlocks)
|
|
if(A.aac == src)
|
|
A.aac = null
|
|
for(var/V in vents)
|
|
var/obj/machinery/atmospherics/components/unary/vent_pump/vent = V
|
|
if(vent.aac == src)
|
|
vent.aac = null
|
|
airlocks.Cut()
|
|
vents.Cut()
|
|
|
|
/obj/machinery/advanced_airlock_controller/proc/scan(assume_roles = FALSE)
|
|
cut_links()
|
|
config_error_str = "Unknown error (bug coders)"
|
|
|
|
var/turf/open/initial_turf = get_turf(src)
|
|
if(!istype(initial_turf))
|
|
config_error_str = "Scan blocked by wall"
|
|
return
|
|
var/list/turfs = list()
|
|
turfs[initial_turf] = 1
|
|
for(var/I = 1; I <= turfs.len; I++)
|
|
var/turf/open/T = turfs[I]
|
|
if(assume_roles)
|
|
T.ImmediateCalculateAdjacentTurfs()
|
|
for(var/turf/open/T2 in T.atmos_adjacent_turfs)
|
|
if(get_dist(initial_turf, T2) > 5)
|
|
config_error_str = "Airlock too big"
|
|
return
|
|
if(locate(/obj/machinery/door/airlock) in T2)
|
|
continue
|
|
turfs[T2] = 1
|
|
if(turfs.len > 16) // I will allow a 4x4 airlock for a shitty poor-man's spacepod bay.
|
|
config_error_str = "Airlock too big"
|
|
for(var/cdir in GLOB.cardinals)
|
|
var/turf/T2 = get_step(T, cdir)
|
|
for(var/obj/machinery/door/airlock/A in T2)
|
|
if(!A.aac || A.aac == src)
|
|
A.aac = src
|
|
airlocks[A] = 0
|
|
if(assume_roles)
|
|
for(var/adir in GLOB.cardinals)
|
|
var/turf/check_turf = get_step(T2, adir)
|
|
if(check_turf.loc != T2.loc)
|
|
airlocks[A] = 1
|
|
break
|
|
for(var/obj/machinery/atmospherics/components/unary/vent_pump/vent in T)
|
|
if(!vent.aac || vent.aac == src)
|
|
vent.aac = src
|
|
vents[vent] = 0
|
|
if(assume_roles)
|
|
if(istype(vent, /obj/machinery/atmospherics/components/unary/vent_pump/siphon))
|
|
vents[vent] = AIRLOCK_CYCLEROLE_INT_DEPRESSURIZE | AIRLOCK_CYCLEROLE_EXT_DEPRESSURIZE
|
|
else
|
|
vents[vent] = AIRLOCK_CYCLEROLE_INT_PRESSURIZE
|
|
for(var/obj/machinery/atmospherics/components/binary/dp_vent_pump/vent in T)
|
|
if(!vent.aac || vent.aac == src)
|
|
vent.aac = src
|
|
vents[vent] = 0
|
|
if(assume_roles)
|
|
vents[vent] = AIRLOCK_CYCLEROLE_INT_DEPRESSURIZE | AIRLOCK_CYCLEROLE_EXT_DEPRESSURIZE | AIRLOCK_CYCLEROLE_INT_PRESSURIZE
|
|
if(!airlocks.len)
|
|
config_error_str = "No airlocks"
|
|
return
|
|
config_error_str = null
|
|
|
|
/obj/machinery/advanced_airlock_controller/ui_status(mob/user)
|
|
if(user.has_unlimited_silicon_privilege && aidisabled)
|
|
to_chat(user, "AI control has been disabled.")
|
|
else if(!shorted)
|
|
return ..()
|
|
return UI_CLOSE
|
|
|
|
/obj/machinery/advanced_airlock_controller/ui_interact(mob/user, datum/tgui/ui)
|
|
ui = SStgui.try_update_ui(user, src, ui)
|
|
if(!ui)
|
|
ui = new(user, src, "AdvancedAirlockController", name)
|
|
ui.open()
|
|
|
|
/obj/machinery/advanced_airlock_controller/ui_data(mob/user)
|
|
var/pressure = 0
|
|
if(isopenturf(get_turf(src)))
|
|
var/datum/gas_mixture/environment = return_air()
|
|
if(environment)
|
|
pressure = environment.return_pressure()
|
|
|
|
var/data = list(
|
|
"locked" = locked,
|
|
"siliconUser" = user.has_unlimited_silicon_privilege,
|
|
"emagged" = (obj_flags & EMAGGED ? 1 : 0),
|
|
"cyclestate" = cyclestate,
|
|
"pressure" = pressure,
|
|
"maxpressure" = (exterior_pressure && (cyclestate == AIRLOCK_CYCLESTATE_OUTCLOSING || cyclestate == AIRLOCK_CYCLESTATE_OUTOPENING || cyclestate == AIRLOCK_CYCLESTATE_OUTOPEN)) ? exterior_pressure : interior_pressure,
|
|
"vents" = list(),
|
|
"airlocks" = list(),
|
|
"skip_timer" = (world.time - skip_timer),
|
|
"skip_delay" = skip_delay,
|
|
"vis_target" = "\ref[vis_target]"
|
|
)
|
|
|
|
if((locked && !user.has_unlimited_silicon_privilege) || (user.has_unlimited_silicon_privilege && aidisabled))
|
|
return data
|
|
|
|
data["config_error_str"] = config_error_str
|
|
data["interior_pressure"] = interior_pressure
|
|
data["exterior_pressure"] = exterior_pressure
|
|
data["depressurization_margin"] = depressurization_margin
|
|
data["depressurization_target"] = depressurization_target
|
|
|
|
for(var/V in vents)
|
|
// it could also be a dpvent.
|
|
var/obj/machinery/atmospherics/components/unary/vent_pump/vent = V
|
|
data["vents"] += list(list(
|
|
"role" = vents[vent],
|
|
"vent_id" = "\ref[vent]",
|
|
"name" = vent.name
|
|
))
|
|
for(var/A in airlocks)
|
|
var/obj/machinery/door/airlock/airlock = A
|
|
var/access_str = "None"
|
|
airlock.gen_access()
|
|
if(islist(airlock.req_access) && airlock.req_access.len)
|
|
access_str = airlock.req_access.len > 1 ? "All of " : ""
|
|
for(var/I in 1 to airlock.req_access.len)
|
|
if(I != 1)
|
|
access_str += ", "
|
|
access_str += get_access_desc(airlock.req_access[I])
|
|
if(islist(airlock.req_one_access) && airlock.req_one_access.len)
|
|
access_str = airlock.req_one_access.len > 1 ? "One of " : ""
|
|
for(var/I in 1 to airlock.req_one_access.len)
|
|
if(I != 1)
|
|
access_str += ", "
|
|
access_str += get_access_desc(airlock.req_one_access[I])
|
|
|
|
data["airlocks"] += list(list(
|
|
"role" = airlocks[airlock],
|
|
"airlock_id" = "\ref[airlock]",
|
|
"name" = airlock.name,
|
|
"access" = access_str
|
|
))
|
|
return data
|
|
|
|
/obj/machinery/advanced_airlock_controller/ui_close()
|
|
. = ..()
|
|
vis_target = null
|
|
|
|
/obj/machinery/advanced_airlock_controller/ui_act(action, params)
|
|
if(..() || buildstage != 2)
|
|
return
|
|
// these actions can be done by anyone
|
|
switch(action)
|
|
if("cycle")
|
|
var/is_allowed = TRUE
|
|
for(var/obj/machinery/door/airlock/A in airlocks)
|
|
if(!A.allowed(usr))
|
|
if(is_allowed)
|
|
is_allowed = FALSE
|
|
to_chat(usr, span_danger("Access denied."))
|
|
if(A.density)
|
|
spawn()
|
|
A.do_animate("deny")
|
|
if(is_allowed)
|
|
cycle_to(text2num(params["exterior"]))
|
|
if("skip")
|
|
if((world.time - skip_timer) >= skip_delay && (cyclestate == AIRLOCK_CYCLESTATE_OUTCLOSING || cyclestate == AIRLOCK_CYCLESTATE_OUTOPENING || cyclestate == AIRLOCK_CYCLESTATE_INOPENING || cyclestate == AIRLOCK_CYCLESTATE_INCLOSING))
|
|
is_skipping = TRUE
|
|
if((locked && !usr.has_unlimited_silicon_privilege) || (usr.has_unlimited_silicon_privilege && aidisabled))
|
|
return
|
|
switch(action)
|
|
if("lock")
|
|
if(usr.has_unlimited_silicon_privilege && !wires.is_cut(WIRE_IDSCAN))
|
|
locked = !locked
|
|
. = TRUE
|
|
vis_target = null
|
|
if("toggle_role")
|
|
var/vent = locate(params["vent_id"])
|
|
if(vent == null || vents[vent] == null)
|
|
return
|
|
var/curr_role = vents[vent]
|
|
var/role_to_toggle = text2num(params["val"]) & 15
|
|
if(curr_role & role_to_toggle)
|
|
vents[vent] = curr_role & ~(role_to_toggle)
|
|
else
|
|
vents[vent] = curr_role | role_to_toggle
|
|
if("set_airlock_role")
|
|
var/airlock = locate(params["airlock_id"])
|
|
if(airlock == null || airlocks[airlock] == null)
|
|
return
|
|
airlocks[airlock] = !!text2num(params["val"])
|
|
if("clear_vis")
|
|
vis_target = null
|
|
if("set_vis_vent")
|
|
var/vent = locate(params["vent_id"])
|
|
if(vent == null || vents[vent] == null)
|
|
return
|
|
vis_target = vent
|
|
if("set_vis_airlock")
|
|
var/airlock = locate(params["airlock_id"])
|
|
if(airlock == null || airlocks[airlock] == null)
|
|
return
|
|
vis_target = airlock
|
|
if("scan")
|
|
scan()
|
|
if("interior_pressure")
|
|
interior_pressure = clamp(text2num(params["pressure"]), 0, ONE_ATMOSPHERE)
|
|
if("exterior_pressure")
|
|
exterior_pressure = clamp(text2num(params["pressure"]), 0, ONE_ATMOSPHERE)
|
|
if("depressurization_margin")
|
|
depressurization_margin = clamp(text2num(params["pressure"]), 0.15, 40)
|
|
if(depressurization_target > depressurization_margin - 0.15)
|
|
depressurization_target = depressurization_margin - 0.15
|
|
if("depressurization_target")
|
|
depressurization_target = clamp(text2num(params["pressure"]), 0, depressurization_target - 0.15)
|
|
if("skip_delay")
|
|
skip_delay = clamp(text2num(params["skip_delay"]), 0, 1200)
|
|
update_icon(TRUE)
|
|
|
|
/obj/machinery/advanced_airlock_controller/proc/request_from_door(airlock)
|
|
var/role = airlocks[airlock]
|
|
if(role == null)
|
|
return
|
|
cycle_to(role)
|
|
|
|
/obj/machinery/advanced_airlock_controller/proc/cycle_to(exterior)
|
|
if(!exterior)
|
|
if(cyclestate == AIRLOCK_CYCLESTATE_OUTOPEN || cyclestate == AIRLOCK_CYCLESTATE_CLOSED || cyclestate == AIRLOCK_CYCLESTATE_OUTOPENING)
|
|
cyclestate = AIRLOCK_CYCLESTATE_OUTCLOSING
|
|
reset_skip()
|
|
process_atmos()
|
|
else if(cyclestate == AIRLOCK_CYCLESTATE_INCLOSING)
|
|
cyclestate = AIRLOCK_CYCLESTATE_INOPENING
|
|
reset_skip()
|
|
process_atmos()
|
|
else
|
|
if(cyclestate == AIRLOCK_CYCLESTATE_INOPEN || cyclestate == AIRLOCK_CYCLESTATE_CLOSED || cyclestate == AIRLOCK_CYCLESTATE_INOPENING)
|
|
cyclestate = AIRLOCK_CYCLESTATE_INCLOSING
|
|
reset_skip()
|
|
else if(cyclestate == AIRLOCK_CYCLESTATE_OUTCLOSING)
|
|
cyclestate = AIRLOCK_CYCLESTATE_OUTOPENING
|
|
reset_skip()
|
|
|
|
/obj/machinery/advanced_airlock_controller/proc/reset_skip()
|
|
is_skipping = FALSE
|
|
skip_timer = world.time
|
|
|
|
/obj/machinery/advanced_airlock_controller/AltClick(mob/user)
|
|
..()
|
|
if(!user.canUseTopic(src, !issilicon(user)) || !isturf(loc))
|
|
return
|
|
else
|
|
togglelock(user)
|
|
|
|
/obj/machinery/advanced_airlock_controller/proc/togglelock(mob/living/user)
|
|
if(stat & (NOPOWER|BROKEN))
|
|
to_chat(user, span_warning("It does nothing!"))
|
|
else
|
|
if(src.allowed(usr) && !wires.is_cut(WIRE_IDSCAN))
|
|
locked = !locked
|
|
update_icon()
|
|
to_chat(user, span_notice("You [ locked ? "lock" : "unlock"] the airlock controller interface."))
|
|
updateUsrDialog()
|
|
else
|
|
to_chat(user, span_danger("Access denied."))
|
|
return
|
|
|
|
/obj/machinery/advanced_airlock_controller/power_change()
|
|
..()
|
|
update_icon()
|
|
|
|
/obj/machinery/advanced_airlock_controller/emag_act(mob/user)
|
|
if(obj_flags & EMAGGED)
|
|
return
|
|
obj_flags |= EMAGGED
|
|
visible_message(span_warning("Sparks fly out of [src]!"), span_notice("You emag [src], disabling its safeties."))
|
|
playsound(src, "sparks", 50, 1)
|
|
|
|
/obj/machinery/advanced_airlock_controller/obj_break(damage_flag)
|
|
..()
|
|
update_icon()
|
|
|
|
/obj/machinery/advanced_airlock_controller/deconstruct(disassembled = TRUE)
|
|
if(!(flags_1 & NODECONSTRUCT_1))
|
|
new /obj/item/stack/sheet/metal(loc, 2)
|
|
var/obj/item/I = new /obj/item/electronics/advanced_airlock_controller(loc)
|
|
if(!disassembled)
|
|
I.obj_integrity = I.max_integrity * 0.5
|
|
new /obj/item/stack/cable_coil(loc, 3)
|
|
qdel(src)
|
|
|
|
/obj/machinery/door/airlock
|
|
var/obj/machinery/advanced_airlock_controller/aac
|
|
|
|
/obj/machinery/door/airlock/Initialize()
|
|
. = ..()
|
|
update_aac_docked()
|
|
/obj/machinery/door/airlock/Destroy()
|
|
var/turf/T = get_turf(src)
|
|
. = ..()
|
|
if(aac)
|
|
aac.airlocks -= src
|
|
aac = null
|
|
if(T)
|
|
update_aac_docked(T)
|
|
|
|
/obj/machinery/door/airlock/proc/update_aac_docked(atom/point = src)
|
|
if(aac)
|
|
aac.update_docked_status(TRUE)
|
|
var/turf/our_turf = get_turf(point)
|
|
if(!our_turf)
|
|
return
|
|
for(var/cdir in GLOB.cardinals)
|
|
var/turf/T = get_step(point, cdir)
|
|
if(!T || (T.loc == our_turf.loc))
|
|
continue
|
|
for(var/obj/machinery/door/airlock/A in T)
|
|
if(A.aac)
|
|
A.aac.update_docked_status(TRUE)
|