/* 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 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("ueahz
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]!"), \ "You loudly begin smashing down [src].") 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, "klaj.") ex_act(EXPLODE_DEVASTATE) user.visible_message(span_boldwarning("[user] slams down [src]!"), "KLAJ.") 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