mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-25 14:08:31 +01:00
Fix telekinesis / ai / mecha door usage + Adds more airlock access unit tests (#91799)
## About The Pull Request Fixes #91795 Fixes #91790 Checking for `MOBILITY_USE` in `allowed` has too broad of an effect, catching mobs which don't have `MOBILITY_USE` but should otherwise be able to use doors. I checked with JFW and this was done to prevent spirits from accessing doors on click. So I just moved it to attack hand. Telekinesis interactions was also fixed by adding a `check_access(null)` check back to `allowed` as it used to have. Not sure why it was ever removed. ## Changelog 🆑 Melbert fix: AIs can open windoors fix: Mechas can open airlocks fix: Handcuffed people can open public airlocks fix: Telekinesis can open public airlocks /🆑
This commit is contained in:
@@ -303,6 +303,12 @@
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
// Stops people without +USE from being able to click-open airlocks
|
||||
// Explicitly not a generic check - if you make this generic, AIs (and more) won't be able to open doors
|
||||
if(isliving(user))
|
||||
var/mob/living/living_user = user
|
||||
if(!(living_user.mobility_flags & MOBILITY_USE))
|
||||
return
|
||||
if(try_remove_seal(user))
|
||||
return
|
||||
if(try_safety_unlock(user))
|
||||
@@ -328,10 +334,6 @@
|
||||
run_animation(DOOR_DENY_ANIMATION)
|
||||
|
||||
/obj/machinery/door/allowed(mob/M)
|
||||
if(isliving(M))
|
||||
var/mob/living/living_user = M
|
||||
if(!(living_user.mobility_flags & MOBILITY_USE))
|
||||
return FALSE
|
||||
if(emergency)
|
||||
return TRUE
|
||||
if(unrestricted_side(M))
|
||||
|
||||
@@ -525,3 +525,38 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/door/window/brigdoor/security/holding
|
||||
/obj/machinery/door/window/brigdoor/security/holding/right
|
||||
icon_state = "rightsecure"
|
||||
base_state = "rightsecure"
|
||||
|
||||
/*
|
||||
* Subtype used in unit tests to ensure instant windoor open/close
|
||||
*/
|
||||
/obj/machinery/door/window/instant
|
||||
|
||||
/obj/machinery/door/window/instant/open(forced = DEFAULT_DOOR_CHECKS)
|
||||
if(!density || operating || !try_to_force_door_open(forced))
|
||||
return FALSE
|
||||
|
||||
operating = TRUE
|
||||
|
||||
set_density(FALSE)
|
||||
air_update_turf(TRUE, FALSE)
|
||||
update_freelook_sight()
|
||||
|
||||
operating = FALSE
|
||||
update_appearance()
|
||||
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/door/window/instant/close(forced = DEFAULT_DOOR_CHECKS)
|
||||
if(density || operating || !try_to_force_door_shut(forced))
|
||||
return FALSE
|
||||
|
||||
operating = TRUE
|
||||
|
||||
set_density(TRUE)
|
||||
air_update_turf(TRUE, TRUE)
|
||||
update_freelook_sight()
|
||||
|
||||
operating = FALSE
|
||||
update_appearance()
|
||||
|
||||
return TRUE
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
if(result_bitflags & COMPONENT_OBJ_DISALLOW) // override all other checks
|
||||
return FALSE
|
||||
if(isnull(accessor)) //likely a TK user.
|
||||
return FALSE
|
||||
return check_access(null)
|
||||
if(isAdminGhostAI(accessor))
|
||||
//Access can't stop the abuse
|
||||
return TRUE
|
||||
|
||||
@@ -4,11 +4,13 @@
|
||||
/datum/unit_test/door_access_check/Run()
|
||||
var/mob/living/carbon/human/subject = allocate(/mob/living/carbon/human/consistent, run_loc_floor_bottom_left)
|
||||
var/obj/machinery/door/airlock/instant/door = allocate(/obj/machinery/door/airlock/instant, run_loc_floor_bottom_left, EAST) //special subtype that just flips the density var on open() and close(), akin to a real airlock.
|
||||
door.interaction_flags_machine |= INTERACT_MACHINE_OFFLINE
|
||||
|
||||
// First, test that someone without any access can open a door that doesn't have any access requirements. Let's test it via using the bumpopen() proc, called when someone bumps into the door.
|
||||
door.bumpopen(subject)
|
||||
subject.Bump(door)
|
||||
TEST_ASSERT_EQUAL(door.density, FALSE, "Subject failed to open access-free airlock!")
|
||||
door.close() // close it here as well
|
||||
subject.last_bumped = 0
|
||||
|
||||
// Alright, now let's test that someone with access can open a door that requires access when only req_access is set.
|
||||
subject.equipOutfit(/datum/outfit/job/assistant/consistent) // set up the outfit here to ensure the last check is pure.
|
||||
@@ -17,26 +19,140 @@
|
||||
// Test two accesses at once just to make sure the script hasn't changed on us.
|
||||
keycard.access = list(ACCESS_ENGINEERING, ACCESS_MAINT_TUNNELS)
|
||||
door.req_access = list(ACCESS_ENGINEERING, ACCESS_MAINT_TUNNELS)
|
||||
door.bumpopen(subject)
|
||||
subject.Bump(door)
|
||||
TEST_ASSERT_EQUAL(door.density, FALSE, "Subject with valid access failed to open airlock access-locked behind req_access!")
|
||||
door.close()
|
||||
subject.last_bumped = 0
|
||||
|
||||
// Okay, now let's edit the req_access on the door to make sure the subject can't open it with the requirements of req_access (must have all accesses required on keycard to open door).
|
||||
door.req_access = list(ACCESS_ENGINEERING, ACCESS_MAINT_TUNNELS, ACCESS_CARGO)
|
||||
door.bumpopen(subject)
|
||||
subject.Bump(door)
|
||||
TEST_ASSERT_EQUAL(door.density, TRUE, "Subject with invalid access succeeded in opening airlock access-locked behind req_access!")
|
||||
door.close() // included for completeness, will early return if the door is already closed.
|
||||
subject.last_bumped = 0
|
||||
|
||||
// Alright, now to test req_one_access. The two systems should be mutually exclusive, so we'll reset the access on the keycard and the door before we continue..
|
||||
door.req_access = null
|
||||
door.req_one_access = list(ACCESS_ENGINEERING, ACCESS_MAINT_TUNNELS)
|
||||
keycard.access = list(ACCESS_MAINT_TUNNELS)
|
||||
door.bumpopen(subject)
|
||||
subject.Bump(door)
|
||||
TEST_ASSERT_EQUAL(door.density, FALSE, "Subject with valid access failed to open airlock access-locked behind req_one_access!")
|
||||
door.close()
|
||||
subject.last_bumped = 0
|
||||
|
||||
// Now, let's test req_one_access with an invalid access. The keycard is still on ACCESS_MAINT_TUNNELS from last step.
|
||||
door.req_one_access = list(ACCESS_ENGINEERING, ACCESS_CARGO)
|
||||
door.bumpopen(subject)
|
||||
subject.Bump(door)
|
||||
TEST_ASSERT_EQUAL(door.density, TRUE, "Subject with invalid access succeeded in opening airlock access-locked behind req_one_access!")
|
||||
|
||||
/// Tests that the AI can open doors
|
||||
/datum/unit_test/door_access_ai
|
||||
|
||||
/datum/unit_test/door_access_ai/Run()
|
||||
var/mob/dead/observer/fake_ghost = allocate(__IMPLIED_TYPE__) // ai must be passed a mob in /new, cringe
|
||||
var/mob/living/silicon/ai/subject = allocate(__IMPLIED_TYPE__, run_loc_floor_top_right, null, fake_ghost)
|
||||
var/obj/machinery/door/airlock/instant/door = allocate(__IMPLIED_TYPE__)
|
||||
door.interaction_flags_machine |= INTERACT_MACHINE_OFFLINE
|
||||
|
||||
door.AIShiftClick(subject)
|
||||
TEST_ASSERT_EQUAL(door.density, FALSE, "AI failed to open access-free airlock!")
|
||||
|
||||
/// Tests that the AI can open windoors
|
||||
/datum/unit_test/windoor_access_ai
|
||||
|
||||
/datum/unit_test/windoor_access_ai/Run()
|
||||
var/mob/dead/observer/fake_ghost = allocate(__IMPLIED_TYPE__) // ai must be passed a mob in /new, cringe
|
||||
var/mob/living/silicon/ai/subject = allocate(__IMPLIED_TYPE__, run_loc_floor_top_right, null, fake_ghost)
|
||||
var/obj/machinery/door/window/instant/door = allocate(__IMPLIED_TYPE__)
|
||||
door.interaction_flags_machine |= INTERACT_MACHINE_OFFLINE
|
||||
|
||||
door.attack_ai(subject)
|
||||
TEST_ASSERT_EQUAL(door.density, FALSE, "AI failed to open access-free window door!")
|
||||
|
||||
/// Tests that telekinesis can open airlocks without access set (and cannot open airlocks that have an access set)
|
||||
/datum/unit_test/door_access_telekinesis
|
||||
|
||||
/datum/unit_test/door_access_telekinesis/Run()
|
||||
var/mob/living/carbon/human/consistent/subject = allocate(__IMPLIED_TYPE__, run_loc_floor_top_right)
|
||||
var/obj/machinery/door/airlock/instant/door = allocate(__IMPLIED_TYPE__, run_loc_floor_bottom_left)
|
||||
door.interaction_flags_machine |= INTERACT_MACHINE_OFFLINE
|
||||
subject.dna.add_mutation(/datum/mutation/telekinesis, list(INNATE_TRAIT))
|
||||
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)
|
||||
|
||||
// Test TK on an access-free airlock
|
||||
door.attack_tk(subject)
|
||||
TEST_ASSERT_EQUAL(door.density, FALSE, "Subject with telekinesis failed to open access-free airlock at range!")
|
||||
door.close()
|
||||
|
||||
// Test TK on an access-locked airlock while having valid access - this should fail
|
||||
door.req_access = list(ACCESS_ENGINEERING, ACCESS_MAINT_TUNNELS)
|
||||
door.attack_tk(subject)
|
||||
TEST_ASSERT_EQUAL(door.density, TRUE, "Subject with telekinesis managed to open access-locked airlock at range (with access)!")
|
||||
|
||||
// Test TK on an access-locked airlock without having valid access - this should also fail
|
||||
keycard.access = list()
|
||||
door.attack_tk(subject)
|
||||
TEST_ASSERT_EQUAL(door.density, TRUE, "Subject with telekinesis managed to open access-locked airlock at range (with no access)!")
|
||||
|
||||
/// Tests that mechas can bump open airlocks
|
||||
/datum/unit_test/door_access_mecha
|
||||
|
||||
/datum/unit_test/door_access_mecha/Run()
|
||||
var/obj/vehicle/sealed/mecha/ripley/subject_mech = allocate(__IMPLIED_TYPE__)
|
||||
var/mob/living/carbon/human/consistent/subject_pilot = allocate(__IMPLIED_TYPE__, run_loc_floor_top_right)
|
||||
var/obj/machinery/door/airlock/instant/door = allocate(__IMPLIED_TYPE__)
|
||||
door.interaction_flags_machine |= INTERACT_MACHINE_OFFLINE
|
||||
subject_pilot.equipOutfit(/datum/outfit/job/assistant/consistent)
|
||||
subject_mech.accesses = list()
|
||||
subject_mech.mob_enter(subject_pilot)
|
||||
|
||||
var/obj/item/card/id/advanced/keycard = subject_pilot.wear_id
|
||||
keycard.access = list(ACCESS_ENGINEERING, ACCESS_MAINT_TUNNELS)
|
||||
|
||||
// Test bumping an access-free airlock - this should open
|
||||
subject_mech.Bump(door)
|
||||
TEST_ASSERT_EQUAL(door.density, FALSE, "Mecha failed to open access-free airlock!")
|
||||
door.close()
|
||||
|
||||
// Setting an access on the door, this should open
|
||||
door.req_access = list(ACCESS_ENGINEERING, ACCESS_MAINT_TUNNELS)
|
||||
subject_mech.Bump(door)
|
||||
TEST_ASSERT_EQUAL(door.density, FALSE, "Mecha failed to open access-locked airlock with valid access!")
|
||||
door.close()
|
||||
|
||||
// Now setting a different access on the door, this should not open
|
||||
door.req_access = list(ACCESS_CARGO)
|
||||
subject_mech.Bump(door)
|
||||
TEST_ASSERT_EQUAL(door.density, TRUE, "Mecha opened access-locked airlock with invalid access!")
|
||||
|
||||
/// Checks that hands_blocked mobs cannot open doors unless it's an access-free door.
|
||||
/datum/unit_test/door_access_handcuffs
|
||||
|
||||
/datum/unit_test/door_access_handcuffs/Run()
|
||||
var/mob/living/carbon/human/subject = allocate(__IMPLIED_TYPE__, run_loc_floor_bottom_left)
|
||||
var/obj/machinery/door/airlock/instant/door = allocate(__IMPLIED_TYPE__)
|
||||
door.interaction_flags_machine |= INTERACT_MACHINE_OFFLINE
|
||||
subject.equipOutfit(/datum/outfit/job/assistant/consistent)
|
||||
ADD_TRAIT(subject, TRAIT_HANDS_BLOCKED, INNATE_TRAIT)
|
||||
|
||||
var/obj/item/card/id/advanced/keycard = subject.wear_id
|
||||
keycard.access = list(ACCESS_ENGINEERING, ACCESS_MAINT_TUNNELS)
|
||||
|
||||
// Test that you can bump open an access-free airlock with hands blocked.
|
||||
subject.Bump(door)
|
||||
TEST_ASSERT_EQUAL(door.density, FALSE, "Subject failed to bump open access-free airlock while hands blocked!")
|
||||
door.close()
|
||||
subject.last_bumped = 0
|
||||
|
||||
// Attack handing should fail though - because unarmed attack fails while hands are blocked.
|
||||
subject.UnarmedAttack(door)
|
||||
TEST_ASSERT_EQUAL(door.density, TRUE, "Subject opened attack-handed open access-free airlock while hands blocked!")
|
||||
door.close()
|
||||
|
||||
// Now adding an access, this should not open even though we have access.
|
||||
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!")
|
||||
|
||||
Reference in New Issue
Block a user