diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm index 31ea8791848..57dffa377e5 100644 --- a/code/game/machinery/doors/door.dm +++ b/code/game/machinery/doors/door.dm @@ -322,6 +322,10 @@ return return ..() +/obj/machinery/door/allowed(mob/accessor) + return ..() || emergency + +/// A mob is trying to open or close the door /obj/machinery/door/proc/try_to_activate_door(mob/user, access_bypass = FALSE, bumped = FALSE) add_fingerprint(user) if(operating || (obj_flags & EMAGGED)) @@ -333,24 +337,8 @@ if(elevator_mode && elevator_status != LIFT_PLATFORM_UNLOCKED) return - var/access_check = access_bypass - if(emergency) - access_check = TRUE - else if(unrestricted_side(user) && !delayed_unres_open) - access_check = TRUE - else if(!requiresID()) - access_check = TRUE - else if(allowed(user)) // You - access_check = TRUE - else for(var/mob/living/human_backpack in user.buckled_mobs) - if(allowed(human_backpack)) // Your partner in crime - access_check = TRUE - break - - if(!access_check && unrestricted_side(user) && attempt_delayed_unres_open(user)) - access_check = TRUE - - if(access_check) + // note: if the ID wire is cut no ID cards are checked at all! (This is intentional!) + if(access_bypass || (requiresID() && user_can_activate_door(user))) if(density) open() else @@ -360,6 +348,18 @@ else if(!operating && density) run_animation(DOOR_DENY_ANIMATION) +/// Used in try_to_activate_door +/obj/machinery/door/proc/user_can_activate_door(mob/user) + PRIVATE_PROC(TRUE) + if(allowed(user)) + return TRUE + for(var/mob/living/human_backpack in user.buckled_mobs) + if(allowed(human_backpack)) + return TRUE + if(unrestricted_side(user)) + return !delayed_unres_open || attempt_delayed_unres_open(user) + return FALSE + /// Allows for specific side of airlocks to be unrestricted (IE, can exit maint freely, but need access to enter) /obj/machinery/door/proc/unrestricted_side(mob/opener) return get_dir(src, opener) & unres_sides diff --git a/code/modules/unit_tests/door_access.dm b/code/modules/unit_tests/door_access.dm index 595e68297ad..78e663bb310 100644 --- a/code/modules/unit_tests/door_access.dm +++ b/code/modules/unit_tests/door_access.dm @@ -173,3 +173,55 @@ door.req_access = list(ACCESS_ENGINEERING, ACCESS_MAINT_TUNNELS) subject.Bump(door) TEST_ASSERT_EQUAL(door.density, TRUE, "Subject opened access-locked airlock while hands blocked!") + +/// Checks that doors with the id wire cut are inaccessible +/datum/unit_test/door_require_id_wire_cut + +/datum/unit_test/door_require_id_wire_cut/Run() + var/obj/machinery/door/airlock/instant/door = EASY_ALLOCATE() + door.interaction_flags_machine |= INTERACT_MACHINE_OFFLINE + door.req_access = list(ACCESS_ENGINEERING) + + var/mob/living/carbon/human/subject = EASY_ALLOCATE() + subject.equipOutfit(/datum/outfit/job/assistant/consistent) + var/obj/item/card/id/advanced/keycard = subject.wear_id + keycard.access = list(ACCESS_ENGINEERING, ACCESS_MAINT_TUNNELS) + + subject.Bump(door) + TEST_ASSERT_EQUAL(door.density, FALSE, "Subject failed to open access-locked airlock before id wire cut!") + door.close() + door.wires.pulse(WIRE_OPEN, subject) + TEST_ASSERT_EQUAL(door.density, TRUE, "Pulsing the door's open wire allowed the subject to open the access-locked airlock without cutting the id wire!") + door.wires.cut(WIRE_IDSCAN, subject) + subject.last_bumped = 0 + subject.Bump(door) + TEST_ASSERT_EQUAL(door.density, TRUE, "Subject opened access-locked airlock with id wire cut!") + door.wires.pulse(WIRE_OPEN, subject) + TEST_ASSERT_EQUAL(door.density, FALSE, "Subject failed to open access-locked airlock with id wire cut and open wire pulsed!") + door.close() + door.wires.cut(WIRE_IDSCAN, subject) // mend + subject.last_bumped = 0 + subject.Bump(door) + TEST_ASSERT_EQUAL(door.density, FALSE, "Subject failed to open access-locked airlock after mending id wire!") + +/// Same as above but testing throwing the item at the door +/datum/unit_test/door_require_id_wire_cut/item_only + +/datum/unit_test/door_require_id_wire_cut/item_only/Run() + var/obj/machinery/door/airlock/instant/door = EASY_ALLOCATE() + door.interaction_flags_machine |= INTERACT_MACHINE_OFFLINE + door.req_access = list(ACCESS_ENGINEERING) + + var/obj/item/card/id/advanced/keycard = EASY_ALLOCATE() + keycard.access = list(ACCESS_ENGINEERING, ACCESS_MAINT_TUNNELS) + + keycard.Bump(door) + TEST_ASSERT_EQUAL(door.density, FALSE, "Throwing an ID at an access-locked airlock failed to open it before id wire cut!") + door.close() + door.wires.cut(WIRE_IDSCAN) + keycard.Bump(door) + TEST_ASSERT_EQUAL(door.density, TRUE, "Throwing an ID at an access-locked airlock succeeded in opening it after id wire cut!") + door.close() + door.wires.cut(WIRE_IDSCAN) // mend + keycard.Bump(door) + TEST_ASSERT_EQUAL(door.density, FALSE, "Throwing an ID at an access-locked airlock failed to open it after mending the id wire!")