diff --git a/_maps/RandomRuins/SpaceRuins/caravanambush.dmm b/_maps/RandomRuins/SpaceRuins/caravanambush.dmm
index ca3ea5c31d9..27dcfe96808 100644
--- a/_maps/RandomRuins/SpaceRuins/caravanambush.dmm
+++ b/_maps/RandomRuins/SpaceRuins/caravanambush.dmm
@@ -364,9 +364,7 @@
/turf/open/floor/plating/airless,
/area/shuttle/caravan/freighter3)
"gc" = (
-/obj/machinery/door/airlock/external{
- req_access_txt = "13"
- },
+/obj/machinery/door/airlock/external,
/obj/effect/mapping_helpers/airlock/cyclelink_helper,
/turf/open/floor/plating/airless,
/area/shuttle/caravan/freighter3)
@@ -560,9 +558,7 @@
/area/shuttle/caravan/freighter2)
"hs" = (
/obj/effect/decal/cleanable/dirt,
-/obj/machinery/door/airlock/external{
- req_access_txt = "13"
- },
+/obj/machinery/door/airlock/external,
/obj/effect/mapping_helpers/airlock/cyclelink_helper,
/turf/open/floor/plating/airless,
/area/shuttle/caravan/freighter2)
@@ -1239,9 +1235,7 @@
/turf/closed/wall/mineral/plastitanium,
/area/ruin/unpowered)
"vE" = (
-/obj/machinery/door/airlock/external{
- req_access_txt = "13"
- },
+/obj/machinery/door/airlock/external,
/obj/effect/mapping_helpers/airlock/cyclelink_helper{
dir = 1
},
@@ -1249,9 +1243,7 @@
/area/shuttle/caravan/freighter3)
"GL" = (
/obj/effect/decal/cleanable/dirt,
-/obj/machinery/door/airlock/external{
- req_access_txt = "13"
- },
+/obj/machinery/door/airlock/external,
/obj/effect/mapping_helpers/airlock/cyclelink_helper{
dir = 1
},
diff --git a/_maps/RandomZLevels/research.dmm b/_maps/RandomZLevels/research.dmm
index 953c5a1d491..e7f037d652a 100644
--- a/_maps/RandomZLevels/research.dmm
+++ b/_maps/RandomZLevels/research.dmm
@@ -528,9 +528,7 @@
/turf/open/floor/iron/white,
/area/awaymission/research/interior/engineering)
"bx" = (
-/obj/machinery/door/airlock/external{
- req_access_txt = "13"
- },
+/obj/machinery/door/airlock/external,
/turf/open/floor/plating,
/area/awaymission/research/interior/maint)
"by" = (
diff --git a/_maps/map_files/IceBoxStation/IcemoonUnderground_Above.dmm b/_maps/map_files/IceBoxStation/IcemoonUnderground_Above.dmm
index 53acd67ae5a..3f6ac242431 100644
--- a/_maps/map_files/IceBoxStation/IcemoonUnderground_Above.dmm
+++ b/_maps/map_files/IceBoxStation/IcemoonUnderground_Above.dmm
@@ -2917,8 +2917,7 @@
dir = 8
},
/obj/machinery/door/airlock/external{
- name = "External Access";
- req_access_txt = "13"
+ name = "External Access"
},
/turf/open/floor/plating,
/area/maintenance/aft)
@@ -3591,8 +3590,7 @@
/area/service/chapel)
"py" = (
/obj/machinery/door/airlock/external{
- name = "External Access";
- req_access_txt = "13"
+ name = "External Access"
},
/obj/effect/mapping_helpers/airlock/cyclelink_helper{
dir = 4
@@ -7480,8 +7478,7 @@
/area/maintenance/fore)
"EW" = (
/obj/machinery/door/airlock/external{
- name = "External Access";
- req_access_txt = "13"
+ name = "External Access"
},
/obj/effect/mapping_helpers/airlock/cyclelink_helper{
dir = 4
@@ -8781,8 +8778,7 @@
dir = 8
},
/obj/machinery/door/airlock/external{
- name = "External Access";
- req_access_txt = "13"
+ name = "External Access"
},
/turf/open/floor/plating/snowed/icemoon,
/area/maintenance/fore)
diff --git a/_maps/shuttles/emergency_supermatter.dmm b/_maps/shuttles/emergency_supermatter.dmm
index 4ae5e8e04c6..3c97c0818d9 100644
--- a/_maps/shuttles/emergency_supermatter.dmm
+++ b/_maps/shuttles/emergency_supermatter.dmm
@@ -137,7 +137,7 @@
"aL" = (
/obj/machinery/door/airlock/external{
name = "Emergency Launch Catwalk";
- req_access_txt = "10;13"
+ req_access_txt = "10"
},
/turf/open/floor/plating,
/area/shuttle/escape)
diff --git a/code/datums/helper_datums/teleport.dm b/code/datums/helper_datums/teleport.dm
index 3d0afa13b54..a0761a2bc72 100644
--- a/code/datums/helper_datums/teleport.dm
+++ b/code/datums/helper_datums/teleport.dm
@@ -115,60 +115,67 @@
var/z = pick(zlevels)
var/random_location = locate(x,y,z)
- if(!isfloorturf(random_location))
- continue
- var/turf/open/floor/F = random_location
- var/area/destination_area = F.loc
+ if(is_safe_turf(random_location, extended_safety_checks, dense_atoms, cycle < 300))//if the area is mostly NOTELEPORT (centcom) we gotta give up on this fantasy at some point.
+ return random_location
- if(cycle < 300 && destination_area.area_flags & NOTELEPORT)//if the area is mostly NOTELEPORT (centcom) we gotta give up on this fantasy at some point.
- continue
- if(!F.air)
- continue
+/// Checks if a given turf is a "safe" location
+/proc/is_safe_turf(turf/random_location, extended_safety_checks = FALSE, dense_atoms = TRUE, no_teleport = FALSE)
+ . = FALSE
+ if(!isfloorturf(random_location))
+ return
+ var/turf/open/floor/floor_turf = random_location
+ var/area/destination_area = floor_turf.loc
- var/datum/gas_mixture/A = F.air
- var/list/A_gases = A.gases
- var/trace_gases
- for(var/id in A_gases)
- if(id in GLOB.hardcoded_gases)
- continue
- trace_gases = TRUE
- break
+ if(no_teleport && (destination_area.area_flags & NOTELEPORT))
+ return
- // Can most things breathe?
- if(trace_gases)
- continue
- if(!(A_gases[/datum/gas/oxygen] && A_gases[/datum/gas/oxygen][MOLES] >= 16))
- continue
- if(A_gases[/datum/gas/plasma])
- continue
- if(A_gases[/datum/gas/carbon_dioxide] && A_gases[/datum/gas/carbon_dioxide][MOLES] >= 10)
- continue
+ var/datum/gas_mixture/floor_gas_mixture = floor_turf.air
+ if(!floor_gas_mixture)
+ return
- // Aim for goldilocks temperatures and pressure
- if((A.temperature <= 270) || (A.temperature >= 360))
- continue
- var/pressure = A.return_pressure()
- if((pressure <= 20) || (pressure >= 550))
+ var/list/floor_gases = floor_gas_mixture.gases
+ var/trace_gases
+ for(var/id in floor_gases)
+ if(id in GLOB.hardcoded_gases)
continue
+ trace_gases = TRUE
+ break
- if(extended_safety_checks)
- if(islava(F)) //chasms aren't /floor, and so are pre-filtered
- var/turf/open/lava/L = F
- if(!L.is_safe())
- continue
+ // Can most things breathe?
+ if(trace_gases)
+ return
+ if(!(floor_gases[/datum/gas/oxygen] && floor_gases[/datum/gas/oxygen][MOLES] >= 16))
+ return
+ if(floor_gases[/datum/gas/plasma])
+ return
+ if(floor_gases[/datum/gas/carbon_dioxide] && floor_gases[/datum/gas/carbon_dioxide][MOLES] >= 10)
+ return
- // Check that we're not warping onto a table or window
- if(!dense_atoms)
- var/density_found = FALSE
- for(var/atom/movable/found_movable in F)
- if(found_movable.density)
- density_found = TRUE
- break
- if(density_found)
- continue
+ // Aim for goldilocks temperatures and pressure
+ if((floor_gas_mixture.temperature <= 270) || (floor_gas_mixture.temperature >= 360))
+ return
+ var/pressure = floor_gas_mixture.return_pressure()
+ if((pressure <= 20) || (pressure >= 550))
+ return
- // DING! You have passed the gauntlet, and are "probably" safe.
- return F
+ if(extended_safety_checks)
+ if(islava(floor_turf)) //chasms aren't /floor, and so are pre-filtered
+ var/turf/open/lava/lava_turf = floor_turf // Cyberboss: okay, this makes no sense and I don't understand the above comment, but I'm too lazy to check history to see what it's supposed to do right now
+ if(!lava_turf.is_safe())
+ return
+
+ // Check that we're not warping onto a table or window
+ if(!dense_atoms)
+ var/density_found = FALSE
+ for(var/atom/movable/found_movable in floor_turf)
+ if(found_movable.density)
+ density_found = TRUE
+ break
+ if(density_found)
+ return
+
+ // DING! You have passed the gauntlet, and are "probably" safe.
+ return TRUE
/proc/get_teleport_turfs(turf/center, precision = 0)
if(!precision)
diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm
index 72e53f4a170..6406667640d 100644
--- a/code/game/machinery/doors/airlock.dm
+++ b/code/game/machinery/doors/airlock.dm
@@ -401,19 +401,6 @@
if(!C.wearing_shock_proof_gloves())
new /datum/hallucination/shock(C)
return
- if(close_others)
- for(var/obj/machinery/door/airlock/otherlock as anything in close_others)
- if(!shuttledocked && !emergency && !otherlock.shuttledocked && !otherlock.emergency && allowed(user))
- if(otherlock.operating)
- otherlock.delayed_close_requested = TRUE
- else
- addtimer(CALLBACK(otherlock, .proc/close), 2)
- if(cyclelinkedairlock)
- if(!shuttledocked && !emergency && !cyclelinkedairlock.shuttledocked && !cyclelinkedairlock.emergency && allowed(user))
- if(cyclelinkedairlock.operating)
- cyclelinkedairlock.delayed_close_requested = TRUE
- else
- addtimer(CALLBACK(cyclelinkedairlock, .proc/close), 2)
..()
/obj/machinery/door/airlock/proc/isElectrified()
@@ -1115,9 +1102,6 @@
return FALSE
use_power(50)
playsound(src, doorOpen, 30, TRUE)
-
- if(closeOther != null && istype(closeOther, /obj/machinery/door/airlock/) && !closeOther.density)
- closeOther.close()
else
//playsound(src, 'sound/machines/airlockforced.ogg', 30, TRUE) - ORIGINAL
playsound(src, forcedOpen, 30, TRUE) //SKYRAT EDIT CHANGE - AESTHETICS
@@ -1127,6 +1111,25 @@
if(!density)
return TRUE
+
+ if(closeOther != null && istype(closeOther, /obj/machinery/door/airlock))
+ addtimer(CALLBACK(closeOther, .proc/close), 2)
+
+ if(close_others)
+ for(var/obj/machinery/door/airlock/otherlock as anything in close_others)
+ if(!shuttledocked && !emergency && !otherlock.shuttledocked && !otherlock.emergency)
+ if(otherlock.operating)
+ otherlock.delayed_close_requested = TRUE
+ else
+ addtimer(CALLBACK(otherlock, .proc/close), 2)
+
+ if(cyclelinkedairlock)
+ if(!shuttledocked && !emergency && !cyclelinkedairlock.shuttledocked && !cyclelinkedairlock.emergency)
+ if(cyclelinkedairlock.operating)
+ cyclelinkedairlock.delayed_close_requested = TRUE
+ else
+ addtimer(CALLBACK(cyclelinkedairlock, .proc/close), 2)
+
SEND_SIGNAL(src, COMSIG_AIRLOCK_OPEN, forced)
operating = TRUE
update_icon(ALL, AIRLOCK_OPENING, TRUE)
diff --git a/code/game/machinery/doors/airlock_types.dm b/code/game/machinery/doors/airlock_types.dm
index 65b1af06731..e69e2a73b16 100644
--- a/code/game/machinery/doors/airlock_types.dm
+++ b/code/game/machinery/doors/airlock_types.dm
@@ -342,6 +342,42 @@
overlays_file = 'icons/obj/doors/airlocks/external/overlays.dmi'
note_overlay_file = 'icons/obj/doors/airlocks/external/overlays.dmi'
assemblytype = /obj/structure/door_assembly/door_assembly_ext
+ req_access = list(ACCESS_EXTERNAL_AIRLOCKS)
+
+ /// Whether or not the airlock can be opened without access from a certain direction while powered, or with bare hands from any direction while unpowered OR pressurized.
+ var/space_dir = null
+
+/obj/machinery/door/airlock/external/LateInitialize()
+ . = ..()
+ if(space_dir)
+ unres_sides |= space_dir
+
+/obj/machinery/door/airlock/external/examine(mob/user)
+ . = ..()
+ if(space_dir)
+ . += span_notice("It has labels indicating that it has an emergency mechanism to open from the [dir2text(space_dir)] side with just your hands even if there's no power.")
+
+/obj/machinery/door/airlock/external/cyclelinkairlock()
+ . = ..()
+ var/obj/machinery/door/airlock/external/cycle_linked_external_airlock = cyclelinkedairlock
+ if(istype(cycle_linked_external_airlock))
+ cycle_linked_external_airlock.space_dir |= space_dir
+ space_dir |= cycle_linked_external_airlock.space_dir
+
+/obj/machinery/door/airlock/external/try_safety_unlock(mob/user)
+ if(space_dir && density)
+ if(!hasPower())
+ to_chat(user, span_notice("You begin unlocking the airlock safety mechanism..."))
+ if(do_after(user, 15 SECONDS, target = src))
+ try_to_crowbar(null, user, TRUE)
+ return TRUE
+ else
+ // always open from the space side
+ // get_dir(src, user) & space_dir, checked in unresricted_sides
+ var/should_safety_open = shuttledocked || cyclelinkedairlock?.shuttledocked || is_safe_turf(get_step(src, space_dir), TRUE, FALSE)
+ return try_to_activate_door(user, should_safety_open)
+
+ return ..()
/obj/machinery/door/airlock/external/glass
opacity = FALSE
diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm
index 59ee8f19f13..c78d3b2106d 100644
--- a/code/game/machinery/doors/door.dm
+++ b/code/game/machinery/doors/door.dm
@@ -40,7 +40,6 @@
var/real_explosion_block //ignore this, just use explosion_block
var/red_alert_access = FALSE //if TRUE, this door will always open on red alert
var/unres_sides = 0 //Unrestricted sides. A bitflag for which direction (if any) can open the door with no access
- var/safety_mode = FALSE ///Whether or not the airlock can be opened with bare hands while unpowered
var/can_crush = TRUE /// Whether or not the door can crush mobs.
@@ -52,8 +51,6 @@
else
. += span_notice("In the event of a red alert, its access requirements will automatically lift.")
. += span_notice("Its maintenance panel is screwed in place.")
- if(safety_mode)
- . += span_notice("It has labels indicating that it has an emergency mechanism to open it with just your hands if there's no power.")
/obj/machinery/door/check_access_list(list/access_list)
if(red_alert_access && SSsecurity_level.current_level >= SEC_LEVEL_RED)
@@ -111,11 +108,6 @@
playsound(src, 'sound/machines/boltsup.ogg', 50, TRUE)
/obj/machinery/door/proc/try_safety_unlock(mob/user)
- if(safety_mode && !hasPower() && density)
- to_chat(user, span_notice("You begin unlocking the airlock safety mechanism..."))
- if(do_after(user, 15 SECONDS, target = src))
- try_to_crowbar(null, user)
- return TRUE
return FALSE
/**
@@ -204,13 +196,12 @@
return ..()
-/obj/machinery/door/proc/try_to_activate_door(mob/user)
+/obj/machinery/door/proc/try_to_activate_door(mob/user, access_bypass = FALSE)
add_fingerprint(user)
if(operating || (obj_flags & EMAGGED))
return
- if(!requiresID())
- user = null //so allowed(user) always succeeds
- if(allowed(user))
+ access_bypass |= !requiresID()
+ if(access_bypass || allowed(user))
if(density)
open()
else
diff --git a/code/game/machinery/doors/firedoor.dm b/code/game/machinery/doors/firedoor.dm
index f80741c278c..0d92e5ca0b8 100644
--- a/code/game/machinery/doors/firedoor.dm
+++ b/code/game/machinery/doors/firedoor.dm
@@ -124,7 +124,7 @@
return
return ..()
-/obj/machinery/door/firedoor/try_to_activate_door(mob/user)
+/obj/machinery/door/firedoor/try_to_activate_door(mob/user, access_bypass = FALSE)
return
/obj/machinery/door/firedoor/try_to_weld(obj/item/weldingtool/W, mob/user)
diff --git a/code/game/machinery/doors/passworddoor.dm b/code/game/machinery/doors/passworddoor.dm
index 4537484ad8b..543ddbc4768 100644
--- a/code/game/machinery/doors/passworddoor.dm
+++ b/code/game/machinery/doors/passworddoor.dm
@@ -32,12 +32,12 @@
/obj/machinery/door/password/Bumped(atom/movable/AM)
return !density && ..()
-/obj/machinery/door/password/try_to_activate_door(mob/user)
+/obj/machinery/door/password/try_to_activate_door(mob/user, access_bypass = FALSE)
add_fingerprint(user)
if(operating)
return
if(density)
- if(ask_for_pass(user))
+ if(access_bypass || ask_for_pass(user))
open()
else
do_animate("deny")
diff --git a/code/game/machinery/doors/windowdoor.dm b/code/game/machinery/doors/windowdoor.dm
index 36acb2e9947..f6e0c8c3331 100644
--- a/code/game/machinery/doors/windowdoor.dm
+++ b/code/game/machinery/doors/windowdoor.dm
@@ -302,7 +302,7 @@
/obj/machinery/door/window/interact(mob/user) //for sillycones
try_to_activate_door(user)
-/obj/machinery/door/window/try_to_activate_door(mob/user)
+/obj/machinery/door/window/try_to_activate_door(mob/user, access_bypass = FALSE)
if (..())
autoclose = FALSE
diff --git a/code/game/objects/items/puzzle_pieces.dm b/code/game/objects/items/puzzle_pieces.dm
index 174a1c34c61..6f7e8af9e07 100644
--- a/code/game/objects/items/puzzle_pieces.dm
+++ b/code/game/objects/items/puzzle_pieces.dm
@@ -57,7 +57,7 @@
/obj/machinery/door/keycard/ex_act(severity, target)
return FALSE
-/obj/machinery/door/keycard/try_to_activate_door(mob/user)
+/obj/machinery/door/keycard/try_to_activate_door(mob/user, access_bypass = FALSE)
add_fingerprint(user)
if(operating)
return
diff --git a/code/modules/shuttle/on_move.dm b/code/modules/shuttle/on_move.dm
index 8ad3b489b42..8d4ec34450d 100644
--- a/code/modules/shuttle/on_move.dm
+++ b/code/modules/shuttle/on_move.dm
@@ -197,19 +197,19 @@ All ShuttleMove procs go here
/obj/machinery/door/airlock/beforeShuttleMove(turf/newT, rotation, move_mode, obj/docking_port/mobile/moving_dock)
. = ..()
- for(var/obj/machinery/door/airlock/A in range(1, src)) // includes src
- A.shuttledocked = FALSE
- A.air_tight = TRUE
- INVOKE_ASYNC(A, /obj/machinery/door/.proc/close)
+ for(var/obj/machinery/door/airlock/other_airlock in range(2, src)) // includes src, extended because some escape pods have 1 plating turf exposed to space
+ other_airlock.shuttledocked = FALSE
+ other_airlock.air_tight = TRUE
+ INVOKE_ASYNC(other_airlock, /obj/machinery/door/.proc/close, FALSE, TRUE) // force crush
/obj/machinery/door/airlock/afterShuttleMove(turf/oldT, list/movement_force, shuttle_dir, shuttle_preferred_direction, move_dir, rotation)
. = ..()
var/current_area = get_area(src)
- for(var/obj/machinery/door/airlock/A in orange(1, src)) // does not include src
- if(get_area(A) != current_area) // does not include double-wide airlocks unless actually docked
+ for(var/obj/machinery/door/airlock/other_airlock in orange(2, src)) // does not include src, extended because some escape pods have 1 plating turf exposed to space
+ if(get_area(other_airlock) != current_area) // does not include double-wide airlocks unless actually docked
// Cycle linking is only disabled if we are actually adjacent to another airlock
shuttledocked = TRUE
- A.shuttledocked = TRUE
+ other_airlock.shuttledocked = TRUE
/obj/machinery/camera/beforeShuttleMove(turf/newT, rotation, move_mode, obj/docking_port/mobile/moving_dock)
. = ..()