mirror of
https://github.com/yogstation13/Yogstation.git
synced 2025-02-26 09:04:50 +00:00
* Ports SSnetworks killings * Update names.dm * Removes my debug message and fixes instances it caught
1864 lines
65 KiB
Plaintext
1864 lines
65 KiB
Plaintext
/*
|
|
New methods:
|
|
pulse - sends a pulse into a wire for hacking purposes
|
|
cut - cuts a wire and makes any necessary state changes
|
|
mend - mends a wire and makes any necessary state changes
|
|
canAIControl - 1 if the AI can control the airlock, 0 if not (then check canAIHack to see if it can hack in)
|
|
canAIHack - 1 if the AI can hack into the airlock to recover control, 0 if not. Also returns 0 if the AI does not *need* to hack it.
|
|
hasPower - 1 if the main or backup power are functioning, 0 if not.
|
|
requiresIDs - 1 if the airlock is requiring IDs, 0 if not
|
|
isAllPowerCut - 1 if the main and backup power both have cut wires.
|
|
regainMainPower - handles the effect of main power coming back on.
|
|
loseMainPower - handles the effect of main power going offline. Usually (if one isn't already running) spawn a thread to count down how long it will be offline - counting down won't happen if main power was completely cut along with backup power, though, the thread will just sleep.
|
|
loseBackupPower - handles the effect of backup power going offline.
|
|
regainBackupPower - handles the effect of main power coming back on.
|
|
shock - has a chance of electrocuting its target.
|
|
*/
|
|
|
|
// Wires for the airlock are located in the datum folder, inside the wires datum folder.
|
|
|
|
#define AIRLOCK_CLOSED 1
|
|
#define AIRLOCK_CLOSING 2
|
|
#define AIRLOCK_OPEN 3
|
|
#define AIRLOCK_OPENING 4
|
|
#define AIRLOCK_DENY 5
|
|
#define AIRLOCK_EMAG 6
|
|
|
|
#define AIRLOCK_FRAME_CLOSED "closed"
|
|
#define AIRLOCK_FRAME_CLOSING "closing"
|
|
#define AIRLOCK_FRAME_OPEN "open"
|
|
#define AIRLOCK_FRAME_OPENING "opening"
|
|
|
|
// Airlock light states, used for generating the light overlays
|
|
#define AIRLOCK_LIGHT_BOLTS "bolts"
|
|
#define AIRLOCK_LIGHT_EMERGENCY "emergency"
|
|
#define AIRLOCK_LIGHT_DENIED "denied"
|
|
#define AIRLOCK_LIGHT_CLOSING "closing"
|
|
#define AIRLOCK_LIGHT_OPENING "opening"
|
|
|
|
#define AIRLOCK_SECURITY_NONE 0 //Normal airlock //Wires are not secured
|
|
#define AIRLOCK_SECURITY_METAL 1 //Medium security airlock //There is a simple metal over wires (use welder)
|
|
#define AIRLOCK_SECURITY_PLASTEEL_I_S 2 //Sliced inner plating (use crowbar), jumps to 0
|
|
#define AIRLOCK_SECURITY_PLASTEEL_I 3 //Removed outer plating, second layer here (use welder)
|
|
#define AIRLOCK_SECURITY_PLASTEEL_O_S 4 //Sliced outer plating (use crowbar)
|
|
#define AIRLOCK_SECURITY_PLASTEEL_O 5 //There is first layer of plasteel (use welder)
|
|
#define AIRLOCK_SECURITY_PLASTEEL 6 //Max security airlock //Fully secured wires (use wirecutters to remove grille, that is electrified)
|
|
|
|
#define AIRLOCK_INTEGRITY_N 300 // Normal airlock integrity
|
|
#define AIRLOCK_INTEGRITY_MULTIPLIER 1.5 // How much reinforced doors health increases
|
|
#define AIRLOCK_DAMAGE_DEFLECTION_N 21 // Normal airlock damage deflection
|
|
#define AIRLOCK_DAMAGE_DEFLECTION_R 30 // Reinforced airlock damage deflection
|
|
|
|
/obj/machinery/door/airlock
|
|
name = "airlock"
|
|
icon = 'icons/obj/doors/airlocks/station/public.dmi'
|
|
icon_state = "closed"
|
|
appearance_flags = TILE_BOUND | LONG_GLIDE | PIXEL_SCALE | KEEP_TOGETHER
|
|
max_integrity = 300
|
|
var/normal_integrity = AIRLOCK_INTEGRITY_N
|
|
integrity_failure = 70
|
|
damage_deflection = AIRLOCK_DAMAGE_DEFLECTION_N
|
|
autoclose = TRUE
|
|
secondsElectrified = MACHINE_NOT_ELECTRIFIED //How many seconds remain until the door is no longer electrified. -1/MACHINE_ELECTRIFIED_PERMANENT = permanently electrified until someone fixes it.
|
|
assemblytype = /obj/structure/door_assembly
|
|
normalspeed = TRUE
|
|
opens_with_door_remote = TRUE
|
|
explosion_block = 1
|
|
hud_possible = list(DIAG_AIRLOCK_HUD)
|
|
smoothing_groups = SMOOTH_GROUP_AIRLOCK
|
|
|
|
FASTDMM_PROP(\
|
|
pinned_vars = list("req_access_txt", "req_one_access_txt", "name")\
|
|
)
|
|
|
|
interaction_flags_machine = INTERACT_MACHINE_WIRES_IF_OPEN | INTERACT_MACHINE_ALLOW_SILICON | INTERACT_MACHINE_OPEN_SILICON | INTERACT_MACHINE_REQUIRES_SILICON | INTERACT_MACHINE_OPEN
|
|
blocks_emissive = EMISSIVE_BLOCK_NONE
|
|
|
|
/// How much are wires secured
|
|
var/security_level = 0
|
|
/// If 1, AI control is disabled until the AI hacks back in and disables the lock. If 2, the AI has bypassed the lock. If -1, the control is enabled but the AI had bypassed it earlier, so if it is disabled again the AI would have no trouble getting back in.
|
|
var/aiControlDisabled = AI_WIRE_NORMAL
|
|
/// Can the AI not hack this door
|
|
var/hackProof = FALSE
|
|
/// The number of seconds until power is restored.
|
|
var/secondsMainPowerLost = 0
|
|
/// The number of seconds until backup power is restored.
|
|
var/secondsBackupPowerLost = 0
|
|
/// Is the door currently restoring power
|
|
var/spawnPowerRestoreRunning = FALSE
|
|
/// Do bolt lights show up
|
|
var/lights = TRUE
|
|
/// Does this airlock scan IDs
|
|
var/aiDisabledIdScanner = FALSE
|
|
/// Is the AI currently hacking this door?
|
|
var/aiHacking = FALSE
|
|
/// Cyclelinking for airlocks that aren't on the same x or y coord as the target.
|
|
var/closeOtherId
|
|
/// Reference to the other airlock to link with
|
|
var/obj/machinery/door/airlock/closeOther
|
|
/// Will it shock someone upon touching it
|
|
var/justzap = FALSE
|
|
/// Cooldowns for shocks
|
|
var/shockCooldown = FALSE
|
|
/// If a charge is on it, explode when the door is opened
|
|
var/obj/item/doorCharge/charge
|
|
/// Type of paper pinned to the airlock
|
|
var/obj/item/note
|
|
/// Has a airlock charge detonated, prevents interaction
|
|
var/detonated = FALSE
|
|
/// Will this airlock go through special effects
|
|
var/abandoned = FALSE
|
|
/// Material of inner filling; if its an airlock with glass, this should be set to "glass"
|
|
var/airlock_material
|
|
|
|
var/obj/item/electronics/airlock/electronics
|
|
var/previous_airlock = /obj/structure/door_assembly //what airlock assembly mineral plating was applied to
|
|
var/obj/machinery/door/airlock/cyclelinkedairlock
|
|
|
|
var/overlays_file = 'icons/obj/doors/airlocks/station/overlays.dmi'
|
|
var/note_overlay_file = 'icons/obj/doors/airlocks/station/overlays.dmi' //Used for papers and photos pinned to the airlock
|
|
var/doorOpen = 'sound/machines/airlock.ogg'
|
|
var/doorClose = 'sound/machines/airlockclose.ogg'
|
|
var/doorDeni = 'sound/machines/deniedbeep.ogg' // i'm thinkin' Deni's
|
|
var/boltUp = 'sound/machines/boltsup.ogg'
|
|
var/boltDown = 'sound/machines/boltsdown.ogg'
|
|
var/noPower = 'sound/machines/doorclick.ogg'
|
|
|
|
/* Note mask_file needed some change due to the change from 513 to 514(the behavior of alpha filters seems to have changed) thats the reason why the mask
|
|
dmi file for normal airlocks is not 32x32 but 64x64 and for the large airlocks instead of 64x32 its now 96x64 due to the fix to this problem*/
|
|
var/mask_file = 'icons/obj/doors/airlocks/mask_32x32_airlocks.dmi' // because filters aren't allowed to have icon_states :(
|
|
var/mask_x = 0
|
|
var/mask_y = 0
|
|
var/anim_parts = "left=-14,0;right=13,0"
|
|
var/list/part_overlays
|
|
var/panel_attachment = "right"
|
|
var/note_attachment = "left"
|
|
var/mask_filter
|
|
|
|
var/cyclelinkeddir = 0 //yogs note im keeping this in order to not break stuff (airlock_helpers and shutle doors)
|
|
/// X-dir to search for a door to link with
|
|
var/cyclelinkedx = 0
|
|
/// Y-dir to search for a door to link with
|
|
var/cyclelinkedy = 0
|
|
var/shuttledocked = 0
|
|
/// Will it close automagically next time it's opened
|
|
var/delayed_close_requested = FALSE
|
|
|
|
/// Is it currently being pried open
|
|
var/prying_so_hard = FALSE
|
|
/// Log of who is bolting this door
|
|
var/list/bolt_log
|
|
/// Log of who is shocking this door
|
|
var/list/shocking_log
|
|
|
|
///Whether wires should all cut themselves when this door is broken.
|
|
var/cut_wires_on_break = TRUE
|
|
|
|
flags_1 = RAD_PROTECT_CONTENTS_1 | RAD_NO_CONTAMINATE_1 | HTML_USE_INITAL_ICON_1
|
|
rad_insulation = RAD_MEDIUM_INSULATION
|
|
|
|
var/static/list/airlock_overlays = list()
|
|
|
|
/obj/machinery/door/airlock/Initialize(mapload)
|
|
. = ..()
|
|
bolt_log = list() //yogs
|
|
shocking_log = list() //yogs
|
|
wires = set_wires()
|
|
|
|
if(frequency)
|
|
set_frequency(frequency)
|
|
|
|
if(closeOtherId != null)
|
|
addtimer(CALLBACK(src, PROC_REF(update_other_id)), 5)
|
|
if(glass)
|
|
airlock_material = "glass"
|
|
if(security_level > AIRLOCK_SECURITY_METAL)
|
|
modify_max_integrity(normal_integrity * AIRLOCK_INTEGRITY_MULTIPLIER)
|
|
if(damage_deflection == AIRLOCK_DAMAGE_DEFLECTION_N && security_level > AIRLOCK_SECURITY_METAL)
|
|
damage_deflection = AIRLOCK_DAMAGE_DEFLECTION_R
|
|
prepare_huds()
|
|
for(var/datum/atom_hud/data/diagnostic/diag_hud in GLOB.huds)
|
|
diag_hud.add_atom_to_hud(src)
|
|
diag_hud_set_electrified()
|
|
|
|
rebuild_parts()
|
|
|
|
return INITIALIZE_HINT_LATELOAD
|
|
|
|
/obj/machinery/door/airlock/connect_to_shuttle(mapload, obj/docking_port/mobile/port, obj/docking_port/stationary/dock)
|
|
if(id_tag)
|
|
id_tag = "[port.shuttle_id]_[id_tag]"
|
|
|
|
/obj/machinery/door/airlock/atom_break(damage_flag)
|
|
. = ..()
|
|
if(!.)
|
|
return FALSE
|
|
if(!panel_open)
|
|
panel_open = TRUE
|
|
if(cut_wires_on_break)
|
|
wires.cut_all()
|
|
|
|
/obj/machinery/door/airlock/LateInitialize()
|
|
. = ..()
|
|
if(cyclelinkedx || cyclelinkedy) //yogs start
|
|
cyclelinkairlock_target()
|
|
else
|
|
if(cyclelinkeddir)
|
|
cyclelinkairlock() //yogs end
|
|
if(abandoned)
|
|
var/outcome = rand(1,100)
|
|
switch(outcome)
|
|
if(1 to 9)
|
|
var/turf/here = get_turf(src)
|
|
for(var/obj/machinery/door/firedoor/FD in here)
|
|
qdel(FD)
|
|
for(var/turf/closed/T in range(2, src))
|
|
here.place_on_top(T.type)
|
|
qdel(src)
|
|
return
|
|
here.place_on_top(/turf/closed/wall)
|
|
qdel(src)
|
|
return
|
|
if(10 to 11)
|
|
lights = FALSE
|
|
locked = TRUE
|
|
if(12 to 15)
|
|
locked = TRUE
|
|
if(16 to 23)
|
|
welded = TRUE
|
|
if(24 to 30)
|
|
panel_open = TRUE
|
|
update_appearance(UPDATE_ICON)
|
|
|
|
/obj/machinery/door/airlock/proc/rebuild_parts()
|
|
if(part_overlays)
|
|
vis_contents -= part_overlays
|
|
QDEL_LIST(part_overlays)
|
|
else
|
|
part_overlays = list()
|
|
var/list/parts_desc = params2list(anim_parts)
|
|
for(var/part_id in parts_desc)
|
|
var/obj/effect/overlay/airlock_part/P = new
|
|
P.side_id = part_id
|
|
var/list/open_offset = splittext(parts_desc[part_id], ",")
|
|
P.open_px = text2num(open_offset[1])
|
|
P.open_py = text2num(open_offset[2])
|
|
if(open_offset.len >= 3)
|
|
P.move_start_time = text2num(open_offset[3])
|
|
if(open_offset.len >= 4)
|
|
P.move_end_time = text2num(open_offset[4])
|
|
if(open_offset.len >= 5)
|
|
P.aperture_angle = text2num(open_offset[5])
|
|
vis_contents += P
|
|
part_overlays += P
|
|
P.icon = icon
|
|
P.icon_state = part_id
|
|
P.parent = src
|
|
P.name = name
|
|
if(mask_filter)
|
|
filters -= mask_filter
|
|
mask_filter = filter(type="alpha",icon=mask_file,x=mask_x,y=mask_y)
|
|
filters += mask_filter
|
|
|
|
/obj/machinery/door/airlock/proc/update_other_id()
|
|
for(var/obj/machinery/door/airlock/A in GLOB.airlocks)
|
|
if(A.closeOtherId == closeOtherId && A != src)
|
|
closeOther = A
|
|
break
|
|
|
|
/obj/machinery/door/airlock/proc/cyclelinkairlock_target() //yogs start
|
|
if (cyclelinkedairlock)
|
|
cyclelinkedairlock.cyclelinkedairlock = null
|
|
cyclelinkedairlock = null
|
|
if(!cyclelinkedx && !cyclelinkedy)
|
|
return
|
|
var/turf/T = get_turf(src)
|
|
var/obj/machinery/door/airlock/FoundDoor
|
|
var/dirlook
|
|
var/targ
|
|
if(cyclelinkedx)
|
|
if(cyclelinkedx > 0)
|
|
targ = cyclelinkedx
|
|
dirlook = 4
|
|
else
|
|
targ = cyclelinkedx * -1
|
|
dirlook = 8
|
|
for(var/i = 0; i < targ; i++)
|
|
T = get_step(T, dirlook)
|
|
|
|
if(cyclelinkedy)
|
|
if(cyclelinkedy > 0)
|
|
targ = cyclelinkedy
|
|
dirlook = 1
|
|
else
|
|
targ = cyclelinkedy * -1
|
|
dirlook = 2
|
|
for(var/i = 0; i < targ; i++)
|
|
T = get_step(T, dirlook)
|
|
|
|
FoundDoor = locate() in T
|
|
if (FoundDoor && (FoundDoor.cyclelinkedy != -1 * cyclelinkedy || FoundDoor.cyclelinkedx != -1 * cyclelinkedx))
|
|
FoundDoor = null
|
|
if (!FoundDoor)
|
|
log_mapping("[src] at [AREACOORD(src)] failed to find a valid airlock to cyclelink_target with! Was targeting [T.x], [T.y], [T.z].")
|
|
return
|
|
FoundDoor.cyclelinkedairlock = src
|
|
cyclelinkedairlock = FoundDoor //yogs end
|
|
|
|
/obj/machinery/door/airlock/proc/cyclelinkairlock()
|
|
if (cyclelinkedairlock)
|
|
cyclelinkedairlock.cyclelinkedairlock = null
|
|
cyclelinkedairlock = null
|
|
if(!cyclelinkeddir)
|
|
return
|
|
var/limit = world.view
|
|
var/turf/T = get_turf(src)
|
|
var/obj/machinery/door/airlock/FoundDoor
|
|
do
|
|
T = get_step(T, cyclelinkeddir)
|
|
FoundDoor = locate() in T
|
|
if (FoundDoor && FoundDoor.cyclelinkeddir != get_dir(FoundDoor, src))
|
|
FoundDoor = null
|
|
limit--
|
|
while(!FoundDoor && limit)
|
|
if (!FoundDoor)
|
|
log_mapping("[src] at [AREACOORD(src)] failed to find a valid airlock to cyclelink with!")
|
|
return
|
|
FoundDoor.cyclelinkedairlock = src
|
|
cyclelinkedairlock = FoundDoor
|
|
|
|
/obj/machinery/door/airlock/vv_edit_var(var_name)
|
|
. = ..()
|
|
switch (var_name)
|
|
if ("cyclelinkedx") //yogs start
|
|
cyclelinkairlock_target()
|
|
if ("cyclelinkedy")
|
|
cyclelinkairlock_target() //yogs end
|
|
if ("cyclelinkeddir")
|
|
cyclelinkairlock()
|
|
|
|
/obj/machinery/door/airlock/lock()
|
|
bolt()
|
|
|
|
/obj/machinery/door/airlock/proc/bolt()
|
|
if(locked)
|
|
return
|
|
locked = TRUE
|
|
playsound(src,boltDown,30,0,3)
|
|
audible_message(span_italics("You hear a click from the bottom of the door."), null, 1)
|
|
update_appearance(UPDATE_ICON)
|
|
|
|
/obj/machinery/door/airlock/unlock()
|
|
unbolt()
|
|
|
|
/obj/machinery/door/airlock/proc/unbolt()
|
|
if(!locked)
|
|
return
|
|
locked = FALSE
|
|
playsound(src,boltUp,30,0,3)
|
|
audible_message(span_italics("You hear a click from the bottom of the door."), null, 1)
|
|
update_appearance(UPDATE_ICON)
|
|
|
|
/obj/machinery/door/airlock/narsie_act()
|
|
var/turf/T = get_turf(src)
|
|
var/obj/machinery/door/airlock/cult/A
|
|
if(GLOB.cult_narsie)
|
|
var/runed = prob(20)
|
|
if(glass)
|
|
if(runed)
|
|
A = new/obj/machinery/door/airlock/cult/glass(T)
|
|
else
|
|
A = new/obj/machinery/door/airlock/cult/unruned/glass(T)
|
|
else
|
|
if(runed)
|
|
A = new/obj/machinery/door/airlock/cult(T)
|
|
else
|
|
A = new/obj/machinery/door/airlock/cult/unruned(T)
|
|
A.name = name
|
|
else
|
|
A = new /obj/machinery/door/airlock/cult/weak(T)
|
|
qdel(src)
|
|
|
|
/obj/machinery/door/airlock/ratvar_act() //Airlocks become pinion airlocks that only allow servants
|
|
var/obj/machinery/door/airlock/clockwork/A
|
|
if(glass)
|
|
A = new/obj/machinery/door/airlock/clockwork/brass(get_turf(src))
|
|
else
|
|
A = new/obj/machinery/door/airlock/clockwork(get_turf(src))
|
|
A.name = name
|
|
qdel(src)
|
|
|
|
/obj/machinery/door/airlock/honk_act()
|
|
var/obj/machinery/door/airlock/bananium/B
|
|
if(glass)
|
|
B = new/obj/machinery/door/airlock/bananium/glass(get_turf(src))
|
|
else
|
|
B = new/obj/machinery/door/airlock/bananium(get_turf(src))
|
|
B.name = name
|
|
qdel(src)
|
|
|
|
/obj/machinery/door/airlock/Destroy()
|
|
QDEL_NULL(wires)
|
|
if(charge)
|
|
qdel(charge)
|
|
charge = null
|
|
QDEL_NULL(electronics)
|
|
if (cyclelinkedairlock)
|
|
if (cyclelinkedairlock.cyclelinkedairlock == src)
|
|
cyclelinkedairlock.cyclelinkedairlock = null
|
|
cyclelinkedairlock = null
|
|
if(id_tag)
|
|
for(var/obj/machinery/doorButtons/D in GLOB.machines)
|
|
D.removeMe(src)
|
|
qdel(note)
|
|
for(var/datum/atom_hud/data/diagnostic/diag_hud in GLOB.huds)
|
|
diag_hud.remove_atom_from_hud(src)
|
|
if(brace) //yogs
|
|
brace.remove() //yogs
|
|
return ..()
|
|
|
|
/obj/machinery/door/airlock/handle_atom_del(atom/A)
|
|
if(A == note)
|
|
note = null
|
|
update_appearance(UPDATE_ICON)
|
|
|
|
/obj/machinery/door/airlock/Bumped(atom/movable/AM)
|
|
if(operating || (obj_flags & EMAGGED))
|
|
return
|
|
if(ismecha(AM))
|
|
var/obj/mecha/mecha = AM
|
|
if(!density) // Somehow bumped into it while it's already open.
|
|
return
|
|
var/has_access = (obj_flags & CMAGGED) ? !check_access_list(mecha.operation_req_access) : check_access_list(mecha.operation_req_access)
|
|
if(mecha.occupant)
|
|
if(world.time - mecha.occupant.last_bumped <= 10)
|
|
return
|
|
mecha.occupant.last_bumped = world.time
|
|
// If there is an occupant, check their access too.
|
|
has_access = (obj_flags & CMAGGED) ? cmag_allowed(mecha.occupant) && has_access : allowed(mecha.occupant) || has_access
|
|
if(aac && locked && has_access)
|
|
aac.request_from_door(src)
|
|
return
|
|
if(has_access)
|
|
open()
|
|
else
|
|
if(obj_flags & CMAGGED)
|
|
try_play_cmagsound()
|
|
do_animate("deny")
|
|
return
|
|
. = ..()
|
|
|
|
/obj/machinery/door/airlock/bumpopen(mob/living/user) //Airlocks now zap you when you 'bump' them open when they're electrified. --NeoFite
|
|
if(!issilicon(usr))
|
|
if(isElectrified())
|
|
if(!justzap)
|
|
if(shock(user, 100))
|
|
justzap = TRUE
|
|
addtimer(VARSET_CALLBACK(src, justzap, FALSE) , 10)
|
|
return
|
|
else
|
|
return
|
|
else if(user.has_status_effect(/datum/status_effect/hallucination) && ishuman(user) && prob(1) && !operating)
|
|
if(user.getarmor(user.held_index_to_hand(user.active_hand_index), ELECTRIC) < 100)
|
|
new /datum/hallucination/shock(user)
|
|
return
|
|
var/allowed = (obj_flags & CMAGGED) ? cmag_allowed(user) : allowed(user)
|
|
if (cyclelinkedairlock)
|
|
if (!shuttledocked && !emergency && !cyclelinkedairlock.shuttledocked && !cyclelinkedairlock.emergency && allowed)
|
|
if(cyclelinkedairlock.operating)
|
|
cyclelinkedairlock.delayed_close_requested = TRUE
|
|
else
|
|
addtimer(CALLBACK(cyclelinkedairlock, PROC_REF(close)), 2)
|
|
if(locked && aac && allowed)
|
|
aac.request_from_door(src)
|
|
return
|
|
..()
|
|
|
|
/obj/machinery/door/airlock/proc/isElectrified()
|
|
if(secondsElectrified != MACHINE_NOT_ELECTRIFIED)
|
|
return TRUE
|
|
return FALSE
|
|
|
|
/obj/machinery/door/airlock/proc/canAIControl(mob/user)
|
|
return ((aiControlDisabled != AI_WIRE_DISABLED) && !isAllPowerCut())
|
|
|
|
/obj/machinery/door/airlock/proc/canAIHack()
|
|
return ((aiControlDisabled==AI_WIRE_DISABLED) && (!hackProof) && (!isAllPowerCut()));
|
|
|
|
/obj/machinery/door/airlock/hasPower()
|
|
return ((!secondsMainPowerLost || !secondsBackupPowerLost) && !(stat & NOPOWER))
|
|
|
|
/obj/machinery/door/airlock/requiresID()
|
|
return !(wires.is_cut(WIRE_IDSCAN) || aiDisabledIdScanner)
|
|
|
|
/obj/machinery/door/airlock/proc/isAllPowerCut()
|
|
if((wires.is_cut(WIRE_POWER1) || wires.is_cut(WIRE_POWER2)) && (wires.is_cut(WIRE_BACKUP1) || wires.is_cut(WIRE_BACKUP2)))
|
|
return TRUE
|
|
|
|
/obj/machinery/door/airlock/proc/regainMainPower()
|
|
if(secondsMainPowerLost > 0)
|
|
secondsMainPowerLost = 0
|
|
update_appearance(UPDATE_ICON)
|
|
|
|
/obj/machinery/door/airlock/proc/handlePowerRestore()
|
|
var/cont = TRUE
|
|
while (cont)
|
|
sleep(1 SECONDS)
|
|
if(QDELETED(src))
|
|
return
|
|
cont = FALSE
|
|
if(secondsMainPowerLost>0)
|
|
if(!wires.is_cut(WIRE_POWER1) && !wires.is_cut(WIRE_POWER2))
|
|
secondsMainPowerLost -= 1
|
|
updateDialog()
|
|
cont = TRUE
|
|
if(secondsBackupPowerLost>0)
|
|
if(!wires.is_cut(WIRE_BACKUP1) && !wires.is_cut(WIRE_BACKUP2))
|
|
secondsBackupPowerLost -= 1
|
|
updateDialog()
|
|
cont = TRUE
|
|
spawnPowerRestoreRunning = FALSE
|
|
updateDialog()
|
|
update_appearance(UPDATE_ICON)
|
|
|
|
/obj/machinery/door/airlock/proc/loseMainPower()
|
|
if(secondsMainPowerLost <= 0)
|
|
secondsMainPowerLost = 60
|
|
if(secondsBackupPowerLost < 10)
|
|
secondsBackupPowerLost = 10
|
|
if(!spawnPowerRestoreRunning)
|
|
spawnPowerRestoreRunning = TRUE
|
|
INVOKE_ASYNC(src, PROC_REF(handlePowerRestore))
|
|
update_appearance(UPDATE_ICON)
|
|
|
|
/obj/machinery/door/airlock/proc/loseBackupPower()
|
|
if(secondsBackupPowerLost < 60)
|
|
secondsBackupPowerLost = 60
|
|
if(!spawnPowerRestoreRunning)
|
|
spawnPowerRestoreRunning = TRUE
|
|
INVOKE_ASYNC(src, PROC_REF(handlePowerRestore))
|
|
update_appearance(UPDATE_ICON)
|
|
|
|
/obj/machinery/door/airlock/proc/regainBackupPower()
|
|
if(secondsBackupPowerLost > 0)
|
|
secondsBackupPowerLost = 0
|
|
update_appearance(UPDATE_ICON)
|
|
|
|
// shock user with probability prb (if all connections & power are working)
|
|
// returns TRUE if shocked, FALSE otherwise
|
|
// The preceding comment was borrowed from the grille's shock script
|
|
/obj/machinery/door/airlock/proc/shock(mob/user, prb)
|
|
if(!hasPower()) // unpowered, no shock
|
|
return FALSE
|
|
if(shockCooldown > world.time)
|
|
return FALSE //Already shocked someone recently?
|
|
if(!prob(prb))
|
|
return FALSE //you lucked out, no shock for you
|
|
do_sparks(5, TRUE, src)
|
|
var/check_range = TRUE
|
|
if(electrocute_mob(user, get_area(src), src, 1, check_range))
|
|
shockCooldown = world.time + 10
|
|
return TRUE
|
|
else
|
|
return FALSE
|
|
|
|
/obj/machinery/door/airlock/update_icon(updates=ALL, state=0, override=0)
|
|
if(operating && !override)
|
|
return
|
|
|
|
if(!state)
|
|
state = density ? AIRLOCK_CLOSED : AIRLOCK_OPEN
|
|
airlock_state = state
|
|
|
|
. = ..()
|
|
|
|
SSdemo.mark_dirty(src)
|
|
|
|
/obj/machinery/door/airlock/update_icon_state()
|
|
. = ..()
|
|
switch(airlock_state)
|
|
if(AIRLOCK_OPEN, AIRLOCK_CLOSED)
|
|
icon_state = ""
|
|
if(AIRLOCK_DENY, AIRLOCK_OPENING, AIRLOCK_CLOSING, AIRLOCK_EMAG)
|
|
icon_state = "nonexistenticonstate" //MADNESS
|
|
|
|
/obj/machinery/door/airlock/proc/set_side_overlays(obj/effect/overlay/airlock_part/base, show_lights = FALSE)
|
|
var/side = base.side_id
|
|
base.icon = icon
|
|
base.cut_overlays()
|
|
if(airlock_material)
|
|
base.add_overlay(get_airlock_overlay("[airlock_material]_[side]", overlays_file))
|
|
else
|
|
base.add_overlay(get_airlock_overlay("fill_[side]", icon))
|
|
if(panel_open && panel_attachment == side)
|
|
if(security_level)
|
|
base.add_overlay(get_airlock_overlay("panel_closed_protected", overlays_file))
|
|
else
|
|
base.add_overlay(get_airlock_overlay("panel_closed", overlays_file))
|
|
if(show_lights && lights && hasPower())
|
|
base.add_overlay(get_airlock_overlay("lights_[side]", overlays_file))
|
|
|
|
if(note && note_attachment == side)
|
|
var/notetype = note_type()
|
|
base.add_overlay(get_airlock_overlay(notetype, note_overlay_file))
|
|
|
|
/obj/machinery/door/airlock/update_overlays()
|
|
. = ..()
|
|
for(var/obj/effect/overlay/airlock_part/part as anything in part_overlays)
|
|
set_side_overlays(part, airlock_state == AIRLOCK_CLOSING || airlock_state == AIRLOCK_OPENING)
|
|
if(part.aperture_angle)
|
|
var/matrix/T
|
|
if(airlock_state == AIRLOCK_OPEN || airlock_state == AIRLOCK_OPENING || airlock_state == AIRLOCK_CLOSING)
|
|
T = matrix()
|
|
T.Translate(-part.open_px,-part.open_py)
|
|
T.Turn(part.aperture_angle)
|
|
T.Translate(part.open_px,part.open_py)
|
|
switch(airlock_state)
|
|
if(AIRLOCK_CLOSED, AIRLOCK_DENY, AIRLOCK_EMAG)
|
|
part.transform = matrix()
|
|
if(AIRLOCK_OPEN)
|
|
part.transform = T
|
|
if(AIRLOCK_CLOSING)
|
|
part.transform = T
|
|
animate(part, transform = T, time = 0.5 SECONDS - part.move_end_time, flags = ANIMATION_LINEAR_TRANSFORM)
|
|
animate(transform = matrix(), time = part.move_end_time - part.move_start_time, flags = ANIMATION_LINEAR_TRANSFORM)
|
|
if(AIRLOCK_OPENING)
|
|
part.transform = matrix()
|
|
animate(part, transform = matrix(), time = part.move_start_time, flags = ANIMATION_LINEAR_TRANSFORM)
|
|
animate(transform = T, time = part.move_end_time - part.move_start_time, flags = ANIMATION_LINEAR_TRANSFORM)
|
|
else
|
|
switch(airlock_state)
|
|
if(AIRLOCK_CLOSED, AIRLOCK_DENY, AIRLOCK_EMAG)
|
|
part.pixel_x = 0
|
|
part.pixel_y = 0
|
|
if(AIRLOCK_OPEN)
|
|
part.pixel_x = part.open_px
|
|
part.pixel_y = part.open_py
|
|
if(AIRLOCK_CLOSING)
|
|
part.pixel_x = part.open_px
|
|
part.pixel_y = part.open_py
|
|
animate(part, pixel_x = part.open_px, pixel_y = part.open_py, time = 0.5 SECONDS - part.move_end_time)
|
|
animate(pixel_x = 0, pixel_y = 0, time = part.move_end_time - part.move_start_time)
|
|
if(AIRLOCK_OPENING)
|
|
part.pixel_x = 0
|
|
part.pixel_y = 0
|
|
animate(part, pixel_x = 0, pixel_y = 0, time = part.move_start_time)
|
|
animate(pixel_x = part.open_px, pixel_y = part.open_py, time = part.move_end_time - part.move_start_time)
|
|
|
|
SSvis_overlays.remove_vis_overlay(src, managed_vis_overlays)
|
|
SSvis_overlays.add_vis_overlay(src, overlays_file, "frame", FLOAT_LAYER, FLOAT_PLANE, dir)
|
|
|
|
switch(airlock_state)
|
|
if(AIRLOCK_CLOSED)
|
|
if(lights && hasPower())
|
|
if(locked)
|
|
SSvis_overlays.add_vis_overlay(src, overlays_file, "lights_bolts", FLOAT_LAYER, FLOAT_PLANE, dir)
|
|
else if(emergency)
|
|
SSvis_overlays.add_vis_overlay(src, overlays_file, "lights_emergency", FLOAT_LAYER, FLOAT_PLANE, dir)
|
|
if(welded)
|
|
SSvis_overlays.add_vis_overlay(src, overlays_file, "welded", FLOAT_LAYER, FLOAT_PLANE, dir)
|
|
if(atom_integrity <integrity_failure)
|
|
SSvis_overlays.add_vis_overlay(src, overlays_file, "sparks_broken", FLOAT_LAYER, FLOAT_PLANE, dir)
|
|
else if(atom_integrity < (0.75 * max_integrity))
|
|
SSvis_overlays.add_vis_overlay(src, overlays_file, "sparks_damaged", FLOAT_LAYER, FLOAT_PLANE, dir)
|
|
|
|
if(AIRLOCK_DENY)
|
|
if(!hasPower())
|
|
return
|
|
SSvis_overlays.add_vis_overlay(src, overlays_file, "lights_denied", FLOAT_LAYER, FLOAT_PLANE, dir)
|
|
if(welded)
|
|
SSvis_overlays.add_vis_overlay(src, overlays_file, "welded", FLOAT_LAYER, FLOAT_PLANE, dir)
|
|
if(atom_integrity <integrity_failure)
|
|
SSvis_overlays.add_vis_overlay(src, overlays_file, "sparks_broken", FLOAT_LAYER, FLOAT_PLANE, dir)
|
|
else if(atom_integrity < (0.75 * max_integrity))
|
|
SSvis_overlays.add_vis_overlay(src, overlays_file, "sparks_damaged", FLOAT_LAYER, FLOAT_PLANE, dir)
|
|
|
|
if(AIRLOCK_EMAG)
|
|
if(welded)
|
|
SSvis_overlays.add_vis_overlay(src, overlays_file, "welded", FLOAT_LAYER, FLOAT_PLANE, dir)
|
|
SSvis_overlays.add_vis_overlay(src, overlays_file, "sparks", FLOAT_LAYER, FLOAT_PLANE, dir)
|
|
if(atom_integrity <integrity_failure)
|
|
SSvis_overlays.add_vis_overlay(src, overlays_file, "sparks_broken", FLOAT_LAYER, FLOAT_PLANE, dir)
|
|
else if(atom_integrity < (0.75 * max_integrity))
|
|
SSvis_overlays.add_vis_overlay(src, overlays_file, "sparks_damaged", FLOAT_LAYER, FLOAT_PLANE, dir)
|
|
|
|
if(AIRLOCK_CLOSING)
|
|
if(lights && hasPower())
|
|
SSvis_overlays.add_vis_overlay(src, overlays_file, "lights_closing", FLOAT_LAYER, FLOAT_PLANE, dir)
|
|
|
|
if(AIRLOCK_OPEN)
|
|
if(atom_integrity < (0.75 * max_integrity))
|
|
SSvis_overlays.add_vis_overlay(src, overlays_file, "sparks_open", FLOAT_LAYER, FLOAT_PLANE, dir)
|
|
|
|
if(AIRLOCK_OPENING)
|
|
if(lights && hasPower())
|
|
SSvis_overlays.add_vis_overlay(src, overlays_file, "lights_opening", FLOAT_LAYER, FLOAT_PLANE, dir)
|
|
|
|
if(hasPower() && unres_sides)
|
|
for(var/heading in list(NORTH,SOUTH,EAST,WEST))
|
|
if(!(unres_sides & heading))
|
|
continue
|
|
var/mutable_appearance/floorlight = mutable_appearance('icons/obj/doors/airlocks/station/overlays.dmi', "unres_[heading]", FLOAT_LAYER, src, ABOVE_LIGHTING_PLANE)
|
|
switch (heading)
|
|
if (NORTH)
|
|
floorlight.pixel_x = 0
|
|
floorlight.pixel_y = 32
|
|
if (SOUTH)
|
|
floorlight.pixel_x = 0
|
|
floorlight.pixel_y = -32
|
|
if (EAST)
|
|
floorlight.pixel_x = 32
|
|
floorlight.pixel_y = 0
|
|
if (WEST)
|
|
floorlight.pixel_x = -32
|
|
floorlight.pixel_y = 0
|
|
. += floorlight
|
|
|
|
/proc/get_airlock_overlay(icon_state, icon_file)
|
|
var/obj/machinery/door/airlock/A
|
|
pass(A) //suppress unused warning
|
|
var/list/airlock_overlays = A.airlock_overlays
|
|
var/iconkey = "[icon_state][icon_file]"
|
|
if((!(. = airlock_overlays[iconkey])))
|
|
. = airlock_overlays[iconkey] = mutable_appearance(icon_file, icon_state)
|
|
|
|
/obj/machinery/door/airlock/do_animate(animation)
|
|
switch(animation)
|
|
if("opening")
|
|
update_icon(state = AIRLOCK_OPENING)
|
|
if("closing")
|
|
update_icon(state = AIRLOCK_CLOSING)
|
|
if("deny")
|
|
if(!stat)
|
|
update_icon(state = AIRLOCK_DENY)
|
|
playsound(src,doorDeni,50,0,3)
|
|
sleep(0.6 SECONDS)
|
|
update_icon(state = AIRLOCK_CLOSED)
|
|
|
|
/obj/machinery/door/airlock/examine(mob/user)
|
|
. = ..()
|
|
if(obj_flags & EMAGGED)
|
|
. += span_warning("The access panel is smoking slightly.")
|
|
if(obj_flags & CMAGGED)
|
|
. += span_warning("The access panel is coated in yellow ooze...")
|
|
if(charge && !panel_open && in_range(user, src))
|
|
. += span_warning("The maintenance panel seems haphazardly fastened.")
|
|
if(charge && panel_open)
|
|
. += span_warning("Something is wired up to the airlock's electronics!")
|
|
if(note)
|
|
if(!in_range(user, src))
|
|
. += "There's a [note.name] pinned to the front. You can't read it from here."
|
|
else
|
|
. += "There's a [note.name] pinned to the front..."
|
|
. += note.examine(user)
|
|
|
|
if(panel_open)
|
|
switch(security_level)
|
|
if(AIRLOCK_SECURITY_NONE)
|
|
. += "Its wires are exposed!"
|
|
if(AIRLOCK_SECURITY_METAL)
|
|
. += "Its wires are hidden behind a welded metal cover."
|
|
if(AIRLOCK_SECURITY_PLASTEEL_I_S)
|
|
. += "There is some shredded plasteel inside."
|
|
if(AIRLOCK_SECURITY_PLASTEEL_I)
|
|
. += "Its wires are behind an inner layer of plasteel."
|
|
if(AIRLOCK_SECURITY_PLASTEEL_O_S)
|
|
. += "There is some shredded plasteel inside."
|
|
if(AIRLOCK_SECURITY_PLASTEEL_O)
|
|
. += "There is a welded plasteel cover hiding its wires."
|
|
if(AIRLOCK_SECURITY_PLASTEEL)
|
|
. += "There is a protective grille over its panel."
|
|
else if(security_level)
|
|
if(security_level == AIRLOCK_SECURITY_METAL)
|
|
. += "It looks a bit stronger."
|
|
else
|
|
. += "It looks very robust."
|
|
|
|
if(issilicon(user) && !(stat & BROKEN))
|
|
. += span_notice("Shift-click [src] to [ density ? "open" : "close"] it.")
|
|
. += span_notice("Ctrl-click [src] to [ locked ? "raise" : "drop"] its bolts.")
|
|
. += span_notice("Alt-click [src] to [ secondsElectrified ? "un-electrify" : "permanently electrify"] it.")
|
|
. += span_notice("Ctrl-Shift-click [src] to [ emergency ? "disable" : "enable"] emergency access.")
|
|
|
|
/obj/machinery/door/airlock/attack_ai(mob/user)
|
|
if(!canAIControl(user))
|
|
if(canAIHack())
|
|
hack(user)
|
|
else
|
|
to_chat(user, span_warning("Airlock AI control has been blocked with a firewall. Unable to hack."))
|
|
return
|
|
if((obj_flags & EMAGGED) || (obj_flags & CMAGGED))
|
|
to_chat(user, span_warning("Unable to interface: Airlock is unresponsive."))
|
|
return
|
|
if(detonated)
|
|
to_chat(user, span_warning("Unable to interface. Airlock control panel damaged."))
|
|
return
|
|
|
|
ui_interact(user)
|
|
|
|
/obj/machinery/door/airlock/attack_robot(mob/user)
|
|
if(!canAIControl(user))
|
|
to_chat(user, span_warning("Airlock AI control has been blocked. Unable to access.")) // Hacking should be AI-exclusive.
|
|
return
|
|
if((obj_flags & EMAGGED) || (obj_flags & CMAGGED))
|
|
to_chat(user, span_warning("Unable to interface: Airlock is unresponsive."))
|
|
return
|
|
if(detonated)
|
|
to_chat(user, span_warning("Unable to interface. Airlock control panel damaged."))
|
|
return
|
|
|
|
var/mob/living/silicon/ai/AI = user
|
|
if(istype(AI) && !AI.has_subcontroller_connection(get_area(src)))
|
|
to_chat(AI, span_warning("No connection to subcontroller detected. Priming servos..."))
|
|
if(!do_after(AI, 1 SECONDS, src, IGNORE_USER_LOC_CHANGE))
|
|
return
|
|
|
|
ui_interact(user)
|
|
|
|
/obj/machinery/door/airlock/proc/hack(mob/user)
|
|
set waitfor = 0
|
|
if(!aiHacking)
|
|
aiHacking = TRUE
|
|
to_chat(user, "Airlock AI control has been blocked. Beginning fault-detection.")
|
|
sleep(5 SECONDS)
|
|
if(canAIControl(user))
|
|
to_chat(user, "Alert cancelled. Airlock control has been restored without our assistance.")
|
|
aiHacking = FALSE
|
|
return
|
|
else if(!canAIHack())
|
|
to_chat(user, "Connection lost! Unable to hack airlock.")
|
|
aiHacking = FALSE
|
|
return
|
|
to_chat(user, "Fault confirmed: airlock control wire disabled or cut.")
|
|
sleep(2 SECONDS)
|
|
to_chat(user, "Attempting to hack into airlock. This may take some time.")
|
|
sleep(20 SECONDS)
|
|
if(canAIControl(user))
|
|
to_chat(user, "Alert cancelled. Airlock control has been restored without our assistance.")
|
|
aiHacking = FALSE
|
|
return
|
|
else if(!canAIHack())
|
|
to_chat(user, "Connection lost! Unable to hack airlock.")
|
|
aiHacking = FALSE
|
|
return
|
|
to_chat(user, "Upload access confirmed. Loading control program into airlock software.")
|
|
sleep(17 SECONDS)
|
|
if(canAIControl(user))
|
|
to_chat(user, "Alert cancelled. Airlock control has been restored without our assistance.")
|
|
aiHacking = FALSE
|
|
return
|
|
else if(!canAIHack())
|
|
to_chat(user, "Connection lost! Unable to hack airlock.")
|
|
aiHacking = FALSE
|
|
return
|
|
to_chat(user, "Transfer complete. Forcing airlock to execute program.")
|
|
sleep(5 SECONDS)
|
|
//disable blocked control
|
|
aiControlDisabled = AI_WIRE_HACKED
|
|
to_chat(user, "Receiving control information from airlock.")
|
|
sleep(1 SECONDS)
|
|
//bring up airlock dialog
|
|
aiHacking = FALSE
|
|
if(user)
|
|
attack_ai(user)
|
|
|
|
/obj/machinery/door/airlock/attack_animal(mob/user)
|
|
. = ..()
|
|
if(isElectrified())
|
|
shock(user, 100)
|
|
|
|
/obj/machinery/door/airlock/attack_paw(mob/user)
|
|
return attack_hand(user)
|
|
|
|
/obj/machinery/door/airlock/attack_hand(mob/user)
|
|
var/allowed = (obj_flags & CMAGGED) ? cmag_allowed(user) : allowed(user)
|
|
if(locked && allowed && aac)
|
|
aac.request_from_door(src)
|
|
. = TRUE
|
|
else
|
|
. = ..()
|
|
if(.)
|
|
return
|
|
if(!(issilicon(user) || IsAdminGhost(user)))
|
|
if(isElectrified())
|
|
if(shock(user, 100))
|
|
return
|
|
|
|
if(ishuman(user) && prob(40) && density)
|
|
var/mob/living/carbon/human/H = user
|
|
if((HAS_TRAIT(H, TRAIT_DUMB)) && Adjacent(user))
|
|
playsound(src, 'sound/effects/bang.ogg', 25, TRUE)
|
|
if(!istype(H.head, /obj/item/clothing/head/helmet))
|
|
H.visible_message(span_danger("[user] headbutts the airlock."), \
|
|
span_userdanger("You headbutt the airlock!"))
|
|
H.Paralyze(100)
|
|
H.apply_damage(10, BRUTE, BODY_ZONE_HEAD)
|
|
else
|
|
visible_message(span_danger("[user] headbutts the airlock. Good thing [user.p_theyre()] wearing a helmet."))
|
|
|
|
/obj/machinery/door/airlock/attempt_wire_interaction(mob/user)
|
|
if(security_level)
|
|
to_chat(user, span_warning("Wires are protected!"))
|
|
return WIRE_INTERACTION_FAIL
|
|
return ..()
|
|
|
|
/obj/machinery/door/airlock/proc/electrified_loop()
|
|
while (secondsElectrified > MACHINE_NOT_ELECTRIFIED)
|
|
sleep(1 SECONDS)
|
|
if(QDELETED(src))
|
|
return
|
|
|
|
secondsElectrified--
|
|
updateDialog()
|
|
// This is to protect against changing to permanent, mid loop.
|
|
if(secondsElectrified == MACHINE_NOT_ELECTRIFIED)
|
|
set_electrified(MACHINE_NOT_ELECTRIFIED)
|
|
else
|
|
set_electrified(MACHINE_ELECTRIFIED_PERMANENT)
|
|
updateDialog()
|
|
|
|
/obj/machinery/door/airlock/Topic(href, href_list, nowindow = 0)
|
|
// If you add an if(..()) check you must first remove the var/nowindow parameter.
|
|
// Otherwise it will runtime with this kind of error: null.Topic()
|
|
if(!nowindow)
|
|
..()
|
|
if(!usr.canUseTopic(src) && !IsAdminGhost(usr))
|
|
return
|
|
add_fingerprint(usr)
|
|
|
|
if((in_range(src, usr) && isturf(loc)) && panel_open)
|
|
usr.set_machine(src)
|
|
|
|
add_fingerprint(usr)
|
|
if(!nowindow)
|
|
updateUsrDialog()
|
|
else
|
|
updateDialog()
|
|
|
|
|
|
/obj/machinery/door/airlock/attackby(obj/item/C, mob/living/user, params)
|
|
if(!issilicon(user) && !IsAdminGhost(user))
|
|
if(isElectrified() && !user.incapacitated())
|
|
if(shock(user, 75))
|
|
return
|
|
add_fingerprint(user)
|
|
|
|
if(panel_open)
|
|
switch(security_level)
|
|
if(AIRLOCK_SECURITY_NONE)
|
|
if(istype(C, /obj/item/stack/sheet/metal))
|
|
var/obj/item/stack/sheet/metal/S = C
|
|
if(S.get_amount() < 2)
|
|
to_chat(user, span_warning("You need at least 2 metal sheets to reinforce [src]."))
|
|
return
|
|
to_chat(user, span_notice("You start reinforcing [src]."))
|
|
if(do_after(user, 2 SECONDS, src))
|
|
if(!panel_open || !S.use(2))
|
|
return
|
|
user.visible_message(span_notice("[user] reinforces \the [src] with metal."),
|
|
span_notice("You reinforce \the [src] with metal."))
|
|
security_level = AIRLOCK_SECURITY_METAL
|
|
update_appearance(UPDATE_ICON)
|
|
return
|
|
else if(istype(C, /obj/item/stack/sheet/plasteel))
|
|
var/obj/item/stack/sheet/plasteel/S = C
|
|
if(S.get_amount() < 2)
|
|
to_chat(user, span_warning("You need at least 2 plasteel sheets to reinforce [src]."))
|
|
return
|
|
to_chat(user, span_notice("You start reinforcing [src]."))
|
|
if(do_after(user, 2 SECONDS, src))
|
|
if(!panel_open || !S.use(2))
|
|
return
|
|
user.visible_message(span_notice("[user] reinforces \the [src] with plasteel."),
|
|
span_notice("You reinforce \the [src] with plasteel."))
|
|
security_level = AIRLOCK_SECURITY_PLASTEEL
|
|
modify_max_integrity(normal_integrity * AIRLOCK_INTEGRITY_MULTIPLIER)
|
|
damage_deflection = AIRLOCK_DAMAGE_DEFLECTION_R
|
|
update_appearance(UPDATE_ICON)
|
|
return
|
|
if(AIRLOCK_SECURITY_METAL)
|
|
if(C.tool_behaviour == TOOL_WELDER)
|
|
if(!C.tool_start_check(user, amount=2))
|
|
return
|
|
to_chat(user, span_notice("You begin cutting the panel's shielding..."))
|
|
if(C.use_tool(src, user, 40, volume=50, amount = 2))
|
|
if(!panel_open)
|
|
return
|
|
user.visible_message(span_notice("[user] cuts through \the [src]'s shielding."),
|
|
span_notice("You cut through \the [src]'s shielding."),
|
|
span_italics("You hear welding."))
|
|
security_level = AIRLOCK_SECURITY_NONE
|
|
spawn_atom_to_turf(/obj/item/stack/sheet/metal, user.loc, 2)
|
|
update_appearance(UPDATE_ICON)
|
|
return
|
|
if(AIRLOCK_SECURITY_PLASTEEL_I_S)
|
|
if(C.tool_behaviour == TOOL_CROWBAR)
|
|
var/obj/item/crowbar/W = C
|
|
to_chat(user, span_notice("You start removing the inner layer of shielding..."))
|
|
if(W.use_tool(src, user, 40, volume=100))
|
|
if(!panel_open)
|
|
return
|
|
if(security_level != AIRLOCK_SECURITY_PLASTEEL_I_S)
|
|
return
|
|
user.visible_message(span_notice("[user] remove \the [src]'s shielding."),
|
|
span_notice("You remove \the [src]'s inner shielding."))
|
|
security_level = AIRLOCK_SECURITY_NONE
|
|
modify_max_integrity(normal_integrity)
|
|
damage_deflection = AIRLOCK_DAMAGE_DEFLECTION_N
|
|
spawn_atom_to_turf(/obj/item/stack/sheet/plasteel, user.loc, 1)
|
|
update_appearance(UPDATE_ICON)
|
|
return
|
|
if(AIRLOCK_SECURITY_PLASTEEL_I)
|
|
if(C.tool_behaviour == TOOL_WELDER)
|
|
if(!C.tool_start_check(user, amount=2))
|
|
return
|
|
to_chat(user, span_notice("You begin cutting the inner layer of shielding..."))
|
|
if(C.use_tool(src, user, 40, volume=50, amount=2))
|
|
if(!panel_open)
|
|
return
|
|
user.visible_message(span_notice("[user] cuts through \the [src]'s shielding."),
|
|
span_notice("You cut through \the [src]'s shielding."),
|
|
span_italics("You hear welding."))
|
|
security_level = AIRLOCK_SECURITY_PLASTEEL_I_S
|
|
return
|
|
if(AIRLOCK_SECURITY_PLASTEEL_O_S)
|
|
if(C.tool_behaviour == TOOL_CROWBAR)
|
|
to_chat(user, span_notice("You start removing outer layer of shielding..."))
|
|
if(C.use_tool(src, user, 40, volume=100))
|
|
if(!panel_open)
|
|
return
|
|
if(security_level != AIRLOCK_SECURITY_PLASTEEL_O_S)
|
|
return
|
|
user.visible_message(span_notice("[user] remove \the [src]'s shielding."),
|
|
span_notice("You remove \the [src]'s shielding."))
|
|
security_level = AIRLOCK_SECURITY_PLASTEEL_I
|
|
spawn_atom_to_turf(/obj/item/stack/sheet/plasteel, user.loc, 1)
|
|
return
|
|
if(AIRLOCK_SECURITY_PLASTEEL_O)
|
|
if(C.tool_behaviour == TOOL_WELDER)
|
|
if(!C.tool_start_check(user, amount=2))
|
|
return
|
|
to_chat(user, span_notice("You begin cutting the outer layer of shielding..."))
|
|
if(C.use_tool(src, user, 40, volume=50, amount=2))
|
|
if(!panel_open)
|
|
return
|
|
user.visible_message(span_notice("[user] cuts through \the [src]'s shielding."),
|
|
span_notice("You cut through \the [src]'s shielding."),
|
|
span_italics("You hear welding."))
|
|
security_level = AIRLOCK_SECURITY_PLASTEEL_O_S
|
|
return
|
|
if(AIRLOCK_SECURITY_PLASTEEL)
|
|
if(C.tool_behaviour == TOOL_WIRECUTTER)
|
|
if(hasPower() && shock(user, 60)) // Protective grille of wiring is electrified
|
|
return
|
|
to_chat(user, span_notice("You start cutting through the outer grille."))
|
|
if(C.use_tool(src, user, 10, volume=100))
|
|
if(!panel_open)
|
|
return
|
|
user.visible_message(span_notice("[user] cut through \the [src]'s outer grille."),
|
|
span_notice("You cut through \the [src]'s outer grille."))
|
|
security_level = AIRLOCK_SECURITY_PLASTEEL_O
|
|
return
|
|
if(C.tool_behaviour == TOOL_SCREWDRIVER)
|
|
if(panel_open && detonated)
|
|
to_chat(user, span_warning("[src] has no maintenance panel!"))
|
|
return
|
|
panel_open = !panel_open
|
|
to_chat(user, span_notice("You [panel_open ? "open":"close"] the maintenance panel of the airlock."))
|
|
C.play_tool_sound(src)
|
|
update_appearance(UPDATE_ICON)
|
|
else if((C.tool_behaviour == TOOL_WIRECUTTER) && note)
|
|
user.visible_message(span_notice("[user] cuts down [note] from [src]."), span_notice("You remove [note] from [src]."))
|
|
C.play_tool_sound(src)
|
|
note.forceMove(get_turf(user))
|
|
note = null
|
|
update_appearance(UPDATE_ICON)
|
|
else if(is_wire_tool(C) && panel_open)
|
|
attempt_wire_interaction(user)
|
|
return
|
|
else if(istype(C, /obj/item/pai_cable))
|
|
var/obj/item/pai_cable/cable = C
|
|
cable.plugin(src, user)
|
|
else if(istype(C, /obj/item/airlock_painter))
|
|
change_paintjob(C, user)
|
|
else if(istype(C, /obj/item/airlock_scanner)) //yogs start
|
|
var/obj/item/airlock_scanner/S = C
|
|
S.show_access(src, user) //yogs end
|
|
else if(istype(C, /obj/item/doorCharge))
|
|
if(!panel_open || security_level)
|
|
to_chat(user, span_warning("The maintenance panel must be open to apply [C]!"))
|
|
return
|
|
if(obj_flags & EMAGGED)
|
|
return
|
|
if(charge && !detonated)
|
|
to_chat(user, span_warning("There's already a charge hooked up to this door!"))
|
|
return
|
|
if(detonated)
|
|
to_chat(user, span_warning("The maintenance panel is destroyed!"))
|
|
return
|
|
to_chat(user, span_warning("You apply [C]. Next time someone opens the door, it will explode."))
|
|
panel_open = FALSE
|
|
update_appearance(UPDATE_ICON)
|
|
user.transferItemToLoc(C, src, TRUE)
|
|
charge = C
|
|
else if(istype(C,/obj/item/electronics/airlock))
|
|
if(!security_level && panel_open)
|
|
var/obj/item/electronics/airlock/ae = C
|
|
if(!electronics)
|
|
if(req_one_access)
|
|
ae.one_access = 1
|
|
ae.accesses = req_one_access
|
|
else
|
|
ae.accesses = req_access
|
|
else
|
|
ae.one_access = electronics.one_access
|
|
ae.accesses = electronics.req_access
|
|
to_chat(user, span_notice("You copy the access of [src] to [ae]."))
|
|
|
|
else if(istype(C, /obj/item/paper) || istype(C, /obj/item/photo))
|
|
if(note)
|
|
to_chat(user, span_warning("There's already something pinned to this airlock! Use wirecutters to remove it."))
|
|
return
|
|
if(!user.transferItemToLoc(C, src))
|
|
to_chat(user, span_warning("For some reason, you can't attach [C]!"))
|
|
return
|
|
user.visible_message(span_notice("[user] pins [C] to [src]."), span_notice("You pin [C] to [src]."))
|
|
note = C
|
|
update_appearance(UPDATE_ICON)
|
|
else if(istype(C, /obj/item/brace)) //yogs
|
|
apply_brace(C, user) //yogs
|
|
else if(istype(C, /obj/item/umbral_tendrils))
|
|
if(!user.combat_mode && !hasPower())
|
|
if(!density)
|
|
return
|
|
if(locked || welded)
|
|
to_chat(user, span_warning("Your [C.name] can't force open locked doors without smashing them down [src]."))
|
|
return
|
|
open(2)
|
|
var/obj/item/umbral_tendrils/T = C
|
|
var/list/modifiers = params2list(params)
|
|
if(!T.darkspawn)
|
|
return ..()
|
|
else if((!user.combat_mode || (modifiers && modifiers[RIGHT_CLICK])) && density)
|
|
// we dont want Duality double-hitting the airlock when we're trying to pry it open
|
|
if(user.get_active_held_item() != C)
|
|
return
|
|
if(!locked && !welded)
|
|
if(!hasPower()) // a crowbar can do this and you're telling me tentacles struggle?
|
|
open(2)
|
|
return
|
|
if(!T.darkspawn.has_psi(15))
|
|
to_chat(user, span_warning("You need at least 15 Psi to force open an airlock!"))
|
|
return
|
|
user.visible_message(span_warning("[user] starts forcing open [src]!"), span_velvet("<b>ueahz</b><br>You begin forcing open [src]..."))
|
|
playsound(src, 'sound/machines/airlock_alien_prying.ogg', 100, TRUE)
|
|
if(!T.twin)
|
|
if(!do_after(user, 7.5 SECONDS, src))
|
|
return
|
|
else
|
|
if(!do_after(user, 5 SECONDS, src))
|
|
return
|
|
open(2)
|
|
if(density && !open(2))
|
|
to_chat(user, span_warning("Despite your attempts, [src] refuses to open!"))
|
|
T.darkspawn.use_psi(15)
|
|
else
|
|
if(!T.darkspawn.has_psi(30))
|
|
to_chat(user, span_warning("You need at least 30 Psi to smash down an airlock!"))
|
|
return
|
|
user.visible_message(span_boldwarning("[user] starts slamming [T] into [src]!"), \
|
|
"<span class='velvet italics'>You loudly begin smashing down [src].</span>")
|
|
while(atom_integrity > max_integrity * 0.25)
|
|
if(T.twin)
|
|
if(!do_after(user, rand(4, 6), src))
|
|
T.darkspawn.use_psi(30)
|
|
return
|
|
else
|
|
if(!do_after(user, rand(8, 10), src))
|
|
T.darkspawn.use_psi(30)
|
|
return
|
|
playsound(src, 'yogstation/sound/magic/pass_smash_door.ogg', 50, TRUE)
|
|
take_damage(max_integrity / rand(8, 15))
|
|
to_chat(user, "<span class='velvet bold'>klaj.</span>")
|
|
ex_act(EXPLODE_DEVASTATE)
|
|
user.visible_message(span_boldwarning("[user] slams down [src]!"), "<span class='velvet bold'>KLAJ.</span>")
|
|
T.darkspawn.use_psi(30)
|
|
else
|
|
return ..()
|
|
else
|
|
return ..()
|
|
|
|
|
|
/obj/machinery/door/airlock/try_to_weld(obj/item/weldingtool/W, mob/living/user, list/modifiers)
|
|
if(!operating && density)
|
|
if(user.combat_mode || (modifiers && modifiers[RIGHT_CLICK]))
|
|
if(!W.tool_start_check(user, amount=0))
|
|
return
|
|
user.visible_message("[user] is [welded ? "unwelding":"welding"] the airlock.", \
|
|
span_notice("You begin [welded ? "unwelding":"welding"] the airlock..."), \
|
|
span_italics("You hear welding."))
|
|
if(W.use_tool(src, user, 40, volume=50, extra_checks = CALLBACK(src, PROC_REF(weld_checks), W, user)))
|
|
welded = !welded
|
|
user.visible_message("[user.name] has [welded? "welded shut":"unwelded"] [src].", \
|
|
span_notice("You [welded ? "weld the airlock shut":"unweld the airlock"]."))
|
|
update_appearance(UPDATE_ICON)
|
|
else
|
|
if(atom_integrity < max_integrity)
|
|
if(!W.tool_start_check(user, amount=0))
|
|
return
|
|
user.visible_message("[user] is welding the airlock.", \
|
|
span_notice("You begin repairing the airlock..."), \
|
|
span_italics("You hear welding."))
|
|
if(W.use_tool(src, user, 40, volume=50, extra_checks = CALLBACK(src, PROC_REF(weld_checks), W, user)))
|
|
update_integrity(max_integrity)
|
|
stat &= ~BROKEN
|
|
user.visible_message("[user.name] has repaired [src].", \
|
|
span_notice("You finish repairing the airlock."))
|
|
update_appearance(UPDATE_ICON)
|
|
else
|
|
to_chat(user, span_notice("The airlock doesn't need repairing."))
|
|
|
|
/obj/machinery/door/airlock/proc/weld_checks(obj/item/weldingtool/W, mob/user)
|
|
return !operating && density
|
|
|
|
/obj/machinery/door/airlock/try_to_crowbar(obj/item/I, mob/living/user)
|
|
var/beingcrowbarred = null
|
|
if(I.tool_behaviour == TOOL_CROWBAR )
|
|
beingcrowbarred = 1
|
|
else
|
|
beingcrowbarred = 0
|
|
if(panel_open && charge)
|
|
to_chat(user, span_notice("You carefully start removing [charge] from [src]..."))
|
|
if(!I.use_tool(src, user, 150, volume=50))
|
|
to_chat(user, span_warning("You slip and [charge] detonates!"))
|
|
user.Paralyze(60)
|
|
return blow_charge()
|
|
user.visible_message(span_notice("[user] removes [charge] from [src]."), \
|
|
span_notice("You gently pry out [charge] from [src] and unhook its wires."))
|
|
charge.forceMove(get_turf(user))
|
|
charge = null
|
|
return
|
|
if(!security_level && (beingcrowbarred && panel_open && ((obj_flags & EMAGGED) || (density && welded && !operating && !hasPower() && !locked))))
|
|
user.visible_message("[user] removes the electronics from the airlock assembly.", \
|
|
span_notice("You start to remove electronics from the airlock assembly..."))
|
|
if(I.use_tool(src, user, 40, volume=100))
|
|
deconstruct(TRUE, user)
|
|
return
|
|
else if(hasPower())
|
|
to_chat(user, span_warning("The airlock's motors resist your efforts to force it!"))
|
|
else if(locked)
|
|
to_chat(user, span_warning("The airlock's bolts prevent it from being forced!"))
|
|
else if(brace)
|
|
to_chat(user, span_warning("The airlock won't budge!"))
|
|
else if(!welded && !operating)
|
|
if(istype(I, /obj/item/fireaxe)) //being fireaxe'd
|
|
var/obj/item/fireaxe/F = I
|
|
if(!HAS_TRAIT(F, TRAIT_WIELDED))
|
|
to_chat(user, span_warning("You need to be wielding the fire axe to do that!"))
|
|
return
|
|
INVOKE_ASYNC(src, (density ? PROC_REF(open) : PROC_REF(close)), 2)
|
|
|
|
if(istype(I, /obj/item/jawsoflife) || istype(I, /obj/item/mantis/blade) || istype(I, /obj/item/mecha_parts/mecha_equipment/hydraulic_clamp))
|
|
if(isElectrified() && shock(user,100))//it's like sticking a fork in a power socket
|
|
return
|
|
|
|
if(istype(I, /obj/item/mantis/blade))
|
|
var/obj/item/mantis/blade/secondsword = user.get_inactive_held_item()
|
|
if(!istype(secondsword, /obj/item/mantis/blade))
|
|
to_chat(user, span_warning("You need a second [I] to pry open doors!"))
|
|
return
|
|
|
|
if(!density)//already open
|
|
return
|
|
|
|
if(locked)
|
|
to_chat(user, span_warning("The bolts are down, it won't budge!"))
|
|
return
|
|
|
|
if(welded)
|
|
to_chat(user, span_warning("It's welded, it won't budge!"))
|
|
return
|
|
|
|
if(brace)
|
|
to_chat(user, span_warning("The airlock won't budge!"))
|
|
return
|
|
|
|
var/time_to_open = 9 SECONDS
|
|
|
|
if(hasPower() && !prying_so_hard)
|
|
if (I.tool_behaviour == TOOL_CROWBAR) //we need another check, futureproofing for if/when bettertools actually completely replaces the old jaws
|
|
if(istype(I,/obj/item/jawsoflife/jimmy))
|
|
var/obj/item/jawsoflife/jimmy/J = I
|
|
if(J.pump_charge >= J.pump_cost)
|
|
J.pump_charge = J.pump_charge - J.pump_cost
|
|
if(J.pump_charge < 0)
|
|
J.pump_charge = 0
|
|
playsound(src, 'sound/items/jimmy_pump.ogg', 100, TRUE)
|
|
if(J.obj_flags & EMAGGED)
|
|
time_to_open /= 2
|
|
else
|
|
if(user)
|
|
to_chat(user, span_warning("You do not have enough charge in the [J] for this. You need at least [J.pump_cost]% "))
|
|
return
|
|
|
|
playsound(src, 'sound/machines/airlock_alien_prying.ogg', 100, TRUE) //is it aliens or just the CE being a dick?
|
|
prying_so_hard = TRUE
|
|
if(I.use_tool(src, user, time_to_open))
|
|
if(!istype(I,/obj/item/jawsoflife/jimmy)) //You get to be special
|
|
take_damage(max_integrity/8, sound_effect = FALSE) //Forcing open a door messes it up a little
|
|
open(2)
|
|
if(density && !open(2))
|
|
to_chat(user, span_warning("Despite your attempts, [src] refuses to open."))
|
|
prying_so_hard = FALSE
|
|
|
|
|
|
if(istype(I, /obj/item/zombie_hand/gamemode))
|
|
var/obj/item/zombie_hand/gamemode/hands = I
|
|
var/door_time_multiplier = hands.door_open_modifier
|
|
var/time_to_open = 50 * door_time_multiplier
|
|
|
|
|
|
|
|
if(!density)//already open
|
|
return
|
|
|
|
if(welded && !locked)
|
|
to_chat(user, span_warning("It's welded, this will take a while..."))
|
|
time_to_open = 100 * door_time_multiplier
|
|
|
|
if(locked && !welded)
|
|
to_chat(user, span_warning("The bolts are down, it won't budge! Forcing the bolts will take a while..."))
|
|
time_to_open = 80 * door_time_multiplier
|
|
|
|
if(locked && welded)
|
|
to_chat(user, span_warning("The bolts are down, and it's welded.Forcing the bolts and breaking the seal will take a long while..."))
|
|
time_to_open = 200 * door_time_multiplier
|
|
|
|
if(brace)
|
|
time_to_open *= 1.5
|
|
|
|
if(hasPower())
|
|
playsound(src, 'sound/machines/airlock_alien_prying.ogg', 100, TRUE) //is it aliens or just the CE being a dick?
|
|
if(do_after(user, time_to_open, src))
|
|
open(2)
|
|
if(density && !open(2))
|
|
to_chat(user, span_warning("Despite your attempts, [src] refuses to open."))
|
|
|
|
|
|
/obj/machinery/door/airlock/open(forced=0)
|
|
if( (operating || welded || locked || brace) && !forced) //yogs - brace
|
|
return FALSE
|
|
if(!forced)
|
|
if(!hasPower() || wires.is_cut(WIRE_OPEN))
|
|
return FALSE
|
|
if(charge && !detonated)
|
|
return blow_charge()
|
|
if(forced < 2)
|
|
if(obj_flags & EMAGGED)
|
|
return FALSE
|
|
use_power(50)
|
|
playsound(src, doorOpen, 30, 1)
|
|
if(closeOther != null && istype(closeOther, /obj/machinery/door/airlock/) && !closeOther.density)
|
|
closeOther.close()
|
|
else
|
|
playsound(src, 'sound/machines/airlockforced.ogg', 30, TRUE)
|
|
|
|
if(autoclose)
|
|
autoclose_in(normalspeed ? 150 : 15)
|
|
|
|
if(!density)
|
|
return TRUE
|
|
if(forced < 2)
|
|
if(locked)
|
|
locked = !locked
|
|
if(welded)
|
|
welded = !welded
|
|
operating = TRUE
|
|
update_icon(state = AIRLOCK_OPENING, override = TRUE)
|
|
sleep(0.1 SECONDS)
|
|
set_opacity(0)
|
|
update_freelook_sight()
|
|
sleep(0.1 SECONDS)
|
|
density = FALSE
|
|
sleep(0.3 SECONDS)
|
|
air_update_turf()
|
|
sleep(0.1 SECONDS)
|
|
layer = OPEN_DOOR_LAYER
|
|
update_icon(state = AIRLOCK_OPEN, override = TRUE)
|
|
operating = FALSE
|
|
if(delayed_close_requested)
|
|
delayed_close_requested = FALSE
|
|
addtimer(CALLBACK(src, PROC_REF(close)), 1)
|
|
return TRUE
|
|
|
|
|
|
/obj/machinery/door/airlock/close(forced=0)
|
|
if(operating || welded || locked)
|
|
return
|
|
if(density)
|
|
return TRUE
|
|
if(!forced)
|
|
if(!hasPower() || wires.is_cut(WIRE_BOLTS))
|
|
return
|
|
if(safe)
|
|
for(var/atom/movable/M in get_turf(src))
|
|
if(M.density && !(M.flags_1 & ON_BORDER_1) && M != src) //something is blocking the door
|
|
autoclose_in(60)
|
|
return
|
|
|
|
if(forced < 2)
|
|
if(obj_flags & EMAGGED)
|
|
return
|
|
use_power(50)
|
|
playsound(src, doorClose, 30, TRUE)
|
|
else
|
|
playsound(src, 'sound/machines/airlockforced.ogg', 30, TRUE)
|
|
|
|
var/obj/structure/window/killthis = (locate(/obj/structure/window) in get_turf(src))
|
|
if(killthis)
|
|
SSexplosions.med_mov_atom += killthis
|
|
|
|
operating = TRUE
|
|
update_icon(state = AIRLOCK_CLOSING, override = TRUE)
|
|
layer = CLOSED_DOOR_LAYER
|
|
if(air_tight)
|
|
density = TRUE
|
|
air_update_turf()
|
|
sleep(0.1 SECONDS)
|
|
density = TRUE
|
|
if(!air_tight)
|
|
air_update_turf()
|
|
sleep(0.4 SECONDS)
|
|
if(!safe)
|
|
crush()
|
|
if(visible && !glass)
|
|
set_opacity(1)
|
|
update_freelook_sight()
|
|
sleep(0.1 SECONDS)
|
|
update_icon(state = AIRLOCK_CLOSED, override = TRUE)
|
|
operating = FALSE
|
|
delayed_close_requested = FALSE
|
|
if(safe)
|
|
CheckForMobs()
|
|
return TRUE
|
|
|
|
/obj/machinery/door/airlock/proc/prison_open()
|
|
if(obj_flags & EMAGGED)
|
|
return
|
|
locked = FALSE
|
|
open()
|
|
locked = TRUE
|
|
return
|
|
|
|
|
|
/obj/machinery/door/airlock/proc/change_paintjob(obj/item/airlock_painter/painter, mob/user)
|
|
|
|
if((!in_range(src, user) && loc != user) || !painter.can_use(user)) // user should be adjacent to the airlock, and the painter should have a toner cartridge that isn't empty
|
|
return
|
|
|
|
// reads from the airlock painter's `available paintjob` list. lets the player choose a paint option, or cancel painting
|
|
var/current_paintjob = tgui_input_list(user, "Paintjob for this airlock", "Customize", sortList(painter.available_paint_jobs))
|
|
if(isnull(current_paintjob)) // if the user clicked cancel on the popup, return
|
|
return
|
|
|
|
var/airlock_type = painter.available_paint_jobs["[current_paintjob]"] // get the airlock type path associated with the airlock name the user just chose
|
|
var/obj/machinery/door/airlock/airlock = airlock_type // we need to create a new instance of the airlock and assembly to read vars from them
|
|
var/obj/structure/door_assembly/assembly = initial(airlock.assemblytype)
|
|
|
|
if(airlock_material == "glass" && initial(assembly.noglass)) // prevents painting glass airlocks with a paint job that doesn't have a glass version, such as the freezer
|
|
to_chat(user, span_warning("This paint job can only be applied to non-glass airlocks."))
|
|
return
|
|
|
|
// applies the user-chosen airlock's icon, overlays and assemblytype to the src airlock
|
|
painter.use_paint(user)
|
|
icon = initial(airlock.icon)
|
|
overlays_file = initial(airlock.overlays_file)
|
|
assemblytype = initial(airlock.assemblytype)
|
|
anim_parts = initial(airlock.anim_parts)
|
|
rebuild_parts()
|
|
update_appearance(UPDATE_ICON)
|
|
|
|
/obj/machinery/door/airlock/CanAStarPass(obj/item/card/id/ID)
|
|
//Airlock is passable if it is open (!density), bot has access, and is not bolted shut or powered off)
|
|
return !density || (check_access(ID) && !locked && hasPower())
|
|
|
|
/obj/machinery/door/airlock/emag_act(mob/user, obj/item/card/emag/emag_card)
|
|
if(operating || !density || !hasPower() || (obj_flags & EMAGGED))
|
|
return FALSE
|
|
operating = TRUE
|
|
update_icon(state = AIRLOCK_EMAG, override = TRUE)
|
|
addtimer(CALLBACK(src, PROC_REF(finish_emag_act), user, emag_card), 0.6 SECONDS)
|
|
return TRUE
|
|
|
|
/obj/machinery/door/airlock/proc/finish_emag_act(mob/user, obj/item/card/emag/emag_card)
|
|
if(QDELETED(src))
|
|
return
|
|
operating = FALSE
|
|
|
|
if(!open()) // Something prevented it from being opened. For example, bolted/welded shut.
|
|
update_icon(state = AIRLOCK_CLOSED, override = TRUE)
|
|
obj_flags |= EMAGGED
|
|
lights = FALSE
|
|
locked = TRUE
|
|
loseMainPower()
|
|
loseBackupPower()
|
|
|
|
/obj/machinery/door/airlock/attack_alien(mob/living/carbon/alien/humanoid/user)
|
|
add_fingerprint(user)
|
|
if(isElectrified())
|
|
shock(user, 100) //Mmm, fried xeno!
|
|
return
|
|
if(!density) //Already open
|
|
return
|
|
if(locked || welded) //Extremely generic, as aliens only understand the basics of how airlocks work.
|
|
to_chat(user, span_warning("[src] refuses to budge!"))
|
|
return
|
|
user.visible_message(span_warning("[user] begins prying open [src]."),\
|
|
span_noticealien("You begin digging your claws into [src] with all your might!"),\
|
|
span_warning("You hear groaning metal..."))
|
|
var/time_to_open = 5
|
|
if(hasPower())
|
|
time_to_open = 50 //Powered airlocks take longer to open, and are loud.
|
|
playsound(src, 'sound/machines/airlock_alien_prying.ogg', 100, 1)
|
|
|
|
|
|
if(do_after(user, time_to_open, src))
|
|
if(density && !open(2)) //The airlock is still closed, but something prevented it opening. (Another player noticed and bolted/welded the airlock in time!)
|
|
to_chat(user, span_warning("Despite your efforts, [src] managed to resist your attempts to open it!"))
|
|
|
|
|
|
/obj/machinery/door/airlock/proc/safe_lockdown()
|
|
// Must be powered and have working AI wire.
|
|
if(canAIControl(src) && !stat)
|
|
locked = FALSE //For airlocks that were bolted open.
|
|
close()
|
|
bolt() //Bolt it!
|
|
|
|
/obj/machinery/door/airlock/hostile_lockdown(mob/origin)
|
|
// Must be powered and have working AI wire.
|
|
if(canAIControl(src) && !stat)
|
|
locked = FALSE //For airlocks that were bolted open.
|
|
safe = FALSE //DOOR CRUSH
|
|
close()
|
|
bolt() //Bolt it!
|
|
set_electrified(MACHINE_ELECTRIFIED_PERMANENT) //Shock it!
|
|
if(origin)
|
|
LAZYADD(shockedby, "\[[time_stamp()]\] [key_name(origin)]")
|
|
|
|
|
|
/obj/machinery/door/airlock/disable_lockdown()
|
|
// Must be powered and have working AI wire.
|
|
if(canAIControl(src) && !stat)
|
|
unbolt()
|
|
set_electrified(MACHINE_NOT_ELECTRIFIED)
|
|
open()
|
|
safe = TRUE
|
|
|
|
/obj/machinery/door/airlock/proc/disable_safe_lockdown()
|
|
// Must be powered and have working AI wire.
|
|
if(canAIControl(src) && !stat)
|
|
unbolt()
|
|
open()
|
|
|
|
|
|
/obj/machinery/door/airlock/proc/set_electrified(seconds, mob/user)
|
|
secondsElectrified = seconds
|
|
diag_hud_set_electrified()
|
|
if(secondsElectrified > MACHINE_NOT_ELECTRIFIED)
|
|
INVOKE_ASYNC(src, PROC_REF(electrified_loop))
|
|
|
|
if(user)
|
|
var/message
|
|
switch(secondsElectrified)
|
|
if(MACHINE_ELECTRIFIED_PERMANENT)
|
|
message = "permanently shocked"
|
|
if(MACHINE_NOT_ELECTRIFIED)
|
|
message = "unshocked"
|
|
else
|
|
message = "temp shocked for [secondsElectrified] seconds"
|
|
LAZYADD(shockedby, text("\[[time_stamp()]\] [key_name(user)] - ([uppertext(message)])"))
|
|
log_combat(user, src, message)
|
|
add_hiddenprint(user)
|
|
|
|
/obj/machinery/door/airlock/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = TRUE, attack_dir, armour_penetration = 0)
|
|
. = ..()
|
|
if(atom_integrity < (0.75 * max_integrity))
|
|
update_appearance(UPDATE_ICON)
|
|
|
|
|
|
/obj/machinery/door/airlock/deconstruct(disassembled = TRUE, mob/user)
|
|
if(!(flags_1 & NODECONSTRUCT_1))
|
|
var/obj/structure/door_assembly/A
|
|
if(assemblytype)
|
|
A = new assemblytype(loc)
|
|
else
|
|
A = new /obj/structure/door_assembly(loc)
|
|
//If you come across a null assemblytype, it will produce the default assembly instead of disintegrating.
|
|
A.heat_proof_finished = heat_proof //tracks whether there's rglass in
|
|
A.setAnchored(TRUE)
|
|
A.glass = glass
|
|
A.state = AIRLOCK_ASSEMBLY_NEEDS_ELECTRONICS
|
|
A.created_name = name
|
|
A.previous_assembly = previous_airlock
|
|
A.update_appearance()
|
|
|
|
if(!disassembled)
|
|
if(A)
|
|
A.update_integrity(A.max_integrity * 0.5)
|
|
else if(obj_flags & EMAGGED)
|
|
if(user)
|
|
to_chat(user, span_warning("You discard the damaged electronics."))
|
|
else
|
|
if(user)
|
|
to_chat(user, span_notice("You remove the airlock electronics."))
|
|
|
|
var/obj/item/electronics/airlock/ae
|
|
if(!electronics)
|
|
ae = new/obj/item/electronics/airlock(loc)
|
|
gen_access()
|
|
if(req_one_access.len)
|
|
ae.one_access = 1
|
|
ae.accesses = req_one_access
|
|
else
|
|
ae.accesses = req_access
|
|
else
|
|
ae = electronics
|
|
electronics = null
|
|
ae.forceMove(drop_location())
|
|
qdel(src)
|
|
|
|
/obj/machinery/door/airlock/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd)
|
|
switch(the_rcd.construction_mode)
|
|
if(RCD_DECONSTRUCT)
|
|
if(security_level != AIRLOCK_SECURITY_NONE)
|
|
to_chat(user, span_notice("[src]'s reinforcement needs to be removed first."))
|
|
return FALSE
|
|
return list("mode" = RCD_DECONSTRUCT, "delay" = 50, "cost" = 32)
|
|
return FALSE
|
|
|
|
/obj/machinery/door/airlock/rcd_act(mob/user, obj/item/construction/rcd/the_rcd, passed_mode)
|
|
switch(passed_mode)
|
|
if(RCD_DECONSTRUCT)
|
|
to_chat(user, span_notice("You deconstruct the airlock."))
|
|
qdel(src)
|
|
return TRUE
|
|
return FALSE
|
|
|
|
/obj/machinery/door/airlock/proc/note_type() //Returns a string representing the type of note pinned to this airlock
|
|
if(!note)
|
|
return
|
|
else if(istype(note, /obj/item/paper))
|
|
return "note"
|
|
else if(istype(note, /obj/item/photo))
|
|
return "photo"
|
|
|
|
/obj/machinery/door/airlock/ui_interact(mob/user, datum/tgui/ui)
|
|
ui = SStgui.try_update_ui(user, src, ui)
|
|
if(!ui)
|
|
ui = new(user, src, "AiAirlock", name)
|
|
ui.open()
|
|
return TRUE
|
|
|
|
/obj/machinery/door/airlock/ui_data()
|
|
var/list/data = list()
|
|
|
|
var/list/power = list()
|
|
power["main"] = secondsMainPowerLost ? 0 : 2 // boolean
|
|
power["main_timeleft"] = secondsMainPowerLost
|
|
power["backup"] = secondsBackupPowerLost ? 0 : 2 // boolean
|
|
power["backup_timeleft"] = secondsBackupPowerLost
|
|
data["power"] = power
|
|
|
|
data["shock"] = secondsElectrified == MACHINE_NOT_ELECTRIFIED ? 2 : 0
|
|
data["shock_timeleft"] = secondsElectrified
|
|
data["id_scanner"] = !aiDisabledIdScanner
|
|
data["emergency"] = emergency // access
|
|
data["locked"] = locked // bolted
|
|
data["lights"] = lights // bolt lights
|
|
data["safe"] = safe // safeties
|
|
data["speed"] = normalspeed // safe speed
|
|
data["welded"] = welded // welded
|
|
data["opened"] = !density // opened
|
|
|
|
var/list/wire = list()
|
|
wire["main_1"] = !wires.is_cut(WIRE_POWER1)
|
|
wire["main_2"] = !wires.is_cut(WIRE_POWER2)
|
|
wire["backup_1"] = !wires.is_cut(WIRE_BACKUP1)
|
|
wire["backup_2"] = !wires.is_cut(WIRE_BACKUP2)
|
|
wire["shock"] = !wires.is_cut(WIRE_SHOCK)
|
|
wire["id_scanner"] = !wires.is_cut(WIRE_IDSCAN)
|
|
wire["bolts"] = !wires.is_cut(WIRE_BOLTS)
|
|
wire["lights"] = !wires.is_cut(WIRE_LIGHT)
|
|
wire["safe"] = !wires.is_cut(WIRE_SAFETY)
|
|
wire["timing"] = !wires.is_cut(WIRE_TIMING)
|
|
|
|
data["wires"] = wire
|
|
return data
|
|
|
|
/obj/machinery/door/airlock/ui_act(action, params)
|
|
if(..())
|
|
return
|
|
if(!user_allowed(usr))
|
|
return
|
|
switch(action)
|
|
if("disrupt-main")
|
|
if(!secondsMainPowerLost)
|
|
loseMainPower()
|
|
update_appearance(UPDATE_ICON)
|
|
else
|
|
to_chat(usr, "Main power is already offline.")
|
|
. = TRUE
|
|
if("disrupt-backup")
|
|
if(!secondsBackupPowerLost)
|
|
loseBackupPower()
|
|
update_appearance(UPDATE_ICON)
|
|
else
|
|
to_chat(usr, "Backup power is already offline.")
|
|
. = TRUE
|
|
if("shock-restore")
|
|
shock_restore(usr)
|
|
shocking_log += "[key_name(usr)] de-electrified [src] at [gameTimestamp("hh:mm:ss", world.time)]" //yogs
|
|
. = TRUE
|
|
if("shock-temp")
|
|
shock_temp(usr)
|
|
shocking_log += "[key_name(usr)] temporarily electrified [src] at [gameTimestamp("hh:mm:ss", world.time)]" //yogs
|
|
. = TRUE
|
|
if("shock-perm")
|
|
shock_perm(usr)
|
|
shocking_log += "[key_name(usr)] permanently electrified [src] at [gameTimestamp("hh:mm:ss", world.time)]" //yogs
|
|
. = TRUE
|
|
if("idscan-toggle")
|
|
aiDisabledIdScanner = !aiDisabledIdScanner
|
|
. = TRUE
|
|
if("emergency-toggle")
|
|
toggle_emergency(usr)
|
|
. = TRUE
|
|
if("bolt-toggle")
|
|
toggle_bolt(usr)
|
|
. = TRUE
|
|
if("light-toggle")
|
|
lights = !lights
|
|
update_appearance(UPDATE_ICON)
|
|
. = TRUE
|
|
if("safe-toggle")
|
|
safe = !safe
|
|
. = TRUE
|
|
if("speed-toggle")
|
|
normalspeed = !normalspeed
|
|
. = TRUE
|
|
if("open-close")
|
|
user_toggle_open(usr)
|
|
. = TRUE
|
|
|
|
/obj/machinery/door/airlock/proc/user_allowed(mob/user)
|
|
return (issilicon(user) && canAIControl(user)) || IsAdminGhost(user)
|
|
|
|
/obj/machinery/door/airlock/proc/shock_restore(mob/user)
|
|
if(!user_allowed(user))
|
|
return
|
|
if(wires.is_cut(WIRE_SHOCK))
|
|
to_chat(user, "Can't un-electrify the airlock - The electrification wire is cut.")
|
|
else if(isElectrified())
|
|
set_electrified(MACHINE_NOT_ELECTRIFIED, user)
|
|
to_chat(user, "Door un-electrified.") //yogs
|
|
|
|
/obj/machinery/door/airlock/proc/shock_temp(mob/user)
|
|
if(!user_allowed(user))
|
|
return
|
|
if(wires.is_cut(WIRE_SHOCK))
|
|
to_chat(user, "The electrification wire has been cut")
|
|
else
|
|
set_electrified(MACHINE_DEFAULT_ELECTRIFY_TIME, user)
|
|
|
|
/obj/machinery/door/airlock/proc/shock_perm(mob/user)
|
|
if(!user_allowed(user))
|
|
return
|
|
if(wires.is_cut(WIRE_SHOCK))
|
|
to_chat(user, "The electrification wire has been cut")
|
|
else
|
|
set_electrified(MACHINE_ELECTRIFIED_PERMANENT, user)
|
|
to_chat(user, "Door electrified") //yogs
|
|
|
|
/obj/machinery/door/airlock/proc/toggle_bolt(mob/user)
|
|
if(!user_allowed(user))
|
|
return
|
|
if(wires.is_cut(WIRE_BOLTS))
|
|
to_chat(user, span_warning("The door bolt drop wire is cut - you can't toggle the door bolts."))
|
|
return
|
|
if(locked)
|
|
if(!hasPower())
|
|
to_chat(user, span_warning("The door has no power - you can't raise the door bolts."))
|
|
else
|
|
unbolt()
|
|
to_chat(user, "Door bolts raised.")
|
|
else
|
|
bolt()
|
|
to_chat(user, "Door bolts dropped.")
|
|
|
|
/obj/machinery/door/airlock/proc/toggle_emergency(mob/user)
|
|
if(!user_allowed(user))
|
|
return
|
|
emergency = !emergency
|
|
update_appearance(UPDATE_ICON)
|
|
|
|
/obj/machinery/door/airlock/proc/user_toggle_open(mob/user)
|
|
if(!user_allowed(user))
|
|
return
|
|
if(welded)
|
|
to_chat(user, text("The airlock has been welded shut!"))
|
|
else if(locked)
|
|
to_chat(user, text("The door bolts are down!"))
|
|
else if(!density)
|
|
close()
|
|
else
|
|
open()
|
|
|
|
/obj/machinery/door/airlock/proc/blow_charge()
|
|
panel_open = TRUE
|
|
update_icon(state = AIRLOCK_OPENING)
|
|
visible_message(span_warning("[src]'s panel is blown off in a spray of deadly shrapnel!"))
|
|
charge.forceMove(drop_location())
|
|
charge.ex_act(EXPLODE_DEVASTATE)
|
|
detonated = TRUE
|
|
charge = null
|
|
for(var/mob/living/carbon/human/H in orange(2,src))
|
|
H.Unconscious(160)
|
|
H.adjust_fire_stacks(20)
|
|
H.ignite_mob() //Guaranteed knockout and ignition for nearby people
|
|
H.apply_damage(40, BRUTE, BODY_ZONE_CHEST)
|
|
|
|
|
|
/**
|
|
* Generates the airlock's wire layout based on the current area the airlock resides in.
|
|
*
|
|
* Returns a new /datum/wires/ with the appropriate wire layout based on the airlock_wires
|
|
* of the area the airlock is in.
|
|
*/
|
|
/obj/machinery/door/airlock/proc/set_wires()
|
|
var/area/source_area = get_area(src)
|
|
return new source_area.airlock_wires(src)
|
|
|
|
/obj/machinery/door/airlock/on_magic_unlock(datum/source, datum/action/cooldown/spell/aoe/knock/spell, mob/living/caster)
|
|
locked = FALSE
|
|
INVOKE_ASYNC(src, PROC_REF(open))
|
|
|
|
#undef AIRLOCK_CLOSED
|
|
#undef AIRLOCK_CLOSING
|
|
#undef AIRLOCK_OPEN
|
|
#undef AIRLOCK_OPENING
|
|
#undef AIRLOCK_DENY
|
|
#undef AIRLOCK_EMAG
|
|
|
|
#undef AIRLOCK_SECURITY_NONE
|
|
#undef AIRLOCK_SECURITY_METAL
|
|
#undef AIRLOCK_SECURITY_PLASTEEL_I_S
|
|
#undef AIRLOCK_SECURITY_PLASTEEL_I
|
|
#undef AIRLOCK_SECURITY_PLASTEEL_O_S
|
|
#undef AIRLOCK_SECURITY_PLASTEEL_O
|
|
#undef AIRLOCK_SECURITY_PLASTEEL
|
|
|
|
#undef AIRLOCK_INTEGRITY_N
|
|
#undef AIRLOCK_INTEGRITY_MULTIPLIER
|
|
#undef AIRLOCK_DAMAGE_DEFLECTION_N
|
|
#undef AIRLOCK_DAMAGE_DEFLECTION_R
|