mirror of
https://github.com/yogstation13/Yogstation.git
synced 2025-02-26 09:04:50 +00:00
Moves integrity to the atom level (ported from tgstation/tgstation#61183), and allows turfs to be destroyed in the same way objects can. Many things which destroy walls have been reworked to use the integrity system instead, and walls can now be destroyed through conventional means like hitting them with something strong. They can also be repaired with welding tools while not on harm intent. Reinforced walls are still very strong and require powerful tools or weapons to damage. Also changes some demolition modifiers slightly to fit the new system: emitters have 2.4x, overcharged emitters have 4x, and pulse rifles have 6x. Standard wall - 300 integrity, 20 damage deflection, 60 melee/bullet/laser armor Reinforced wall - 400 integrity, 75 damage deflection, 80 melee/bullet armor, 60 laser armor
833 lines
28 KiB
Plaintext
833 lines
28 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 = AREA_USAGE_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_cycle_icon()
|
|
|
|
/obj/machinery/advanced_airlock_controller/Destroy()
|
|
qdel(wires)
|
|
wires = null
|
|
cut_links()
|
|
SSair.stop_processing_machine(src)
|
|
return ..()
|
|
|
|
/obj/machinery/advanced_airlock_controller/Initialize(mapload)
|
|
. = ..()
|
|
SSair.start_processing_machine(src)
|
|
scan_on_late_init = mapload
|
|
if(mapload && (. != INITIALIZE_HINT_QDEL))
|
|
return INITIALIZE_HINT_LATELOAD
|
|
|
|
/obj/machinery/advanced_airlock_controller/LateInitialize()
|
|
. = ..()
|
|
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/proc/update_cycle_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_UP(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_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_cycle_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_cycle_icon(TRUE)
|
|
return
|
|
|
|
if(!isopenturf(get_turf(src)))
|
|
update_cycle_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_appearance(UPDATE_ICON)
|
|
else
|
|
vent.on = FALSE
|
|
vent.update_appearance(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_appearance(UPDATE_ICON)
|
|
else
|
|
vent.on = FALSE
|
|
vent.update_appearance(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_appearance(UPDATE_ICON)
|
|
else
|
|
vent.on = FALSE
|
|
vent.update_appearance(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_appearance(UPDATE_ICON)
|
|
else
|
|
vent.on = FALSE
|
|
vent.update_appearance(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_appearance(UPDATE_ICON)
|
|
else
|
|
vent.on = FALSE
|
|
vent.update_appearance(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_appearance(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_appearance(UPDATE_ICON)
|
|
update_cycle_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_cycle_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_cycle_icon()
|
|
return
|
|
else if(W.GetID())// 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_cycle_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_cycle_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_cycle_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_cycle_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.immediate_calculate_adjacent_turfs()
|
|
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 | AIRLOCK_CYCLEROLE_EXT_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 | AIRLOCK_CYCLEROLE_EXT_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_margin - 0.15)
|
|
if("skip_delay")
|
|
skip_delay = clamp(text2num(params["skip_delay"]), 0, 1200)
|
|
update_cycle_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_cycle_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_cycle_icon()
|
|
|
|
/obj/machinery/advanced_airlock_controller/emag_act(mob/user, obj/item/card/emag/emag_card)
|
|
if(obj_flags & EMAGGED)
|
|
return FALSE
|
|
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)
|
|
return TRUE
|
|
|
|
/obj/machinery/advanced_airlock_controller/atom_break(damage_flag)
|
|
..()
|
|
update_cycle_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.update_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(mapload)
|
|
. = ..()
|
|
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)
|