Adds the Janitor access keyring (#73768)

## About The Pull Request

HackMD for this can be found here:
https://hackmd.io/VEbjO1kaQJarao4KqGfzgw?view

Basically, this gives the first Janitor an access key that they can use
to enter departments. This requires a Head of Staff to approve it
through the keycard authenticator, and only holds one department at a
time, and will clear itself out after 10 minutes.
This gives departmental AA, including the head of staff's office, adding
a tradeoff.

The Janitor is alerted when access is given to their key (as their
keyring will say such) and everyone can see janitors trying to open a
door when they use it (with a cool sound, too).
You can't bump open airlocks with it, I limited it to directly using it
on the door, because I thought it made it feel more realistic to a
keyring.

I had an earlier version of this that gave the key it's own access,
which allowed bumping open, but it also allowed things like locking RD
consoles, and I dunno how strong I want this key to be.

I also wanted to limit how easy this is to greytide/steal, currently
only the first Janitor spawns with the key. I thought it would be too
easy to exploit otherwise, or essentially stolen roundstart if there
were no Janitors. Maybe this can also fit as a Traitor objective after
melon's new objective PR is done?

### Minor detail

While adding icons, I realized inhands don't actually set its icon state
to the default if it's null, so I removed that LYING comment.

## Why It's Good For The Game


![geromekey](https://user-images.githubusercontent.com/53777086/222824948-4d42d801-fea5-423b-9050-2a23d02f8ea4.gif)

![gerome](https://user-images.githubusercontent.com/53777086/222824598-1225aeb0-4aa8-4826-bf29-5674e9cda7ad.gif)

Alternatively, https://youtu.be/dlkSbQ-IkRM?t=182 (timestamp)

## Changelog

🆑 JohnFulpWillard, sprites by BalkyGoat
add: The Janitor Access key: Janitors can now be given departmental AA
(one at a time) using the Keycard authentication device in Command
offices. Use it if you need cleaning!
fix: HoP's trim is no longer set to edit Supply access.
/🆑

---------

Co-authored-by: Fikou <23585223+Fikou@users.noreply.github.com>
Co-authored-by: tattle <66640614+dragomagol@users.noreply.github.com>
Co-authored-by: Zephyr <12817816+ZephyrTFA@users.noreply.github.com>
This commit is contained in:
John Willard
2023-03-20 15:05:48 +00:00
committed by GitHub
parent 21bc477071
commit 70ed01ed72
15 changed files with 137 additions and 13 deletions
@@ -0,0 +1,2 @@
///Called when a keycard is sending a department's access. (obj/machinery/keycard_auth/source, list/region_access)
#define COMSIG_ON_DEPARTMENT_ACCESS "on_department_access"
+1 -1
View File
@@ -159,7 +159,7 @@ SUBSYSTEM_DEF(id_access)
"pdas" = list(),
),
"[ACCESS_HOP]" = list(
"regions" = list(REGION_GENERAL, REGION_SUPPLY),
"regions" = list(REGION_GENERAL),
"head" = JOB_HEAD_OF_PERSONNEL,
"templates" = list(),
"pdas" = list(),
+8 -5
View File
@@ -283,13 +283,16 @@
try_to_crowbar(tool, user, forced_open)
return TOOL_ACT_TOOLTYPE_SUCCESS
/obj/machinery/door/attackby(obj/item/I, mob/living/user, params)
if(!user.combat_mode && istype(I, /obj/item/fireaxe))
try_to_crowbar(I, user, FALSE)
/obj/machinery/door/attackby(obj/item/weapon, mob/living/user, params)
if(istype(weapon, /obj/item/access_key))
var/obj/item/access_key/key = weapon
return key.attempt_open_door(user, src)
else if(!user.combat_mode && istype(weapon, /obj/item/fireaxe))
try_to_crowbar(weapon, user, FALSE)
return TRUE
else if(I.item_flags & NOBLUDGEON || user.combat_mode)
else if(weapon.item_flags & NOBLUDGEON || user.combat_mode)
return ..()
else if(!user.combat_mode && istype(I, /obj/item/stack/sheet/mineral/wood))
else if(!user.combat_mode && istype(weapon, /obj/item/stack/sheet/mineral/wood))
return ..() // we need this so our can_barricade element can be called using COMSIG_PARENT_ATTACKBY
else if(try_to_activate_door(user))
return TRUE
+1 -1
View File
@@ -16,7 +16,7 @@ GLOBAL_DATUM_INIT(fire_overlay, /mutable_appearance, mutable_appearance('icons/e
!!!!!!!!!!!!!!! IMPORTANT !!!!!!!!!!!!!! */
///icon state for inhand overlays, if null the normal icon_state will be used.
///icon state for inhand overlays.
var/inhand_icon_state = null
///Icon file for left hand inhand overlays
var/lefthand_file = 'icons/mob/inhands/items_lefthand.dmi'
+82
View File
@@ -0,0 +1,82 @@
///The time limit on the keys before the access it's been given clears itself.
#define ACCESS_TIMER_LIMIT (10 MINUTES)
/obj/item/access_key
name = "access key ring"
desc = "A key ring with a beeper, allowing the keys to change shape depending on which department it has access to."
icon_state = "access_key"
inhand_icon_state = "access_key"
icon = 'icons/obj/janitor.dmi'
lefthand_file = 'icons/mob/inhands/items/keys_lefthand.dmi'
righthand_file = 'icons/mob/inhands/items/keys_righthand.dmi'
hitsound = 'sound/items/rattling_keys_attack.ogg'
force = 2
verb_say = "beeps" //it has a beeper
verb_ask = "questionably beeps"
verb_exclaim = "beeps loudly"
w_class = WEIGHT_CLASS_TINY
///The departmental access given to the key.
var/list/department_access
/obj/item/access_key/Initialize(mapload)
. = ..()
RegisterSignal(SSdcs, COMSIG_ON_DEPARTMENT_ACCESS, PROC_REF(department_access_given))
/obj/item/access_key/examine(mob/user)
. = ..()
if(department_access)
. += "It currently holds access to the [department_access] region."
/obj/item/access_key/examine_more(mob/user)
. = ..()
. += span_notice("Access can be granted through a Keycard Authentication Device.")
. += span_notice("This access is limited to one department at a time.")
/**
* Called when attempting to open an airlock.
* Checks if the keys have access, returns try_to_activate_door if it does, returns FALSE otherwise.
* Args:
* user - The person attempting to open the door
* airlock - The door we're attempting to open
*/
/obj/item/access_key/proc/attempt_open_door(mob/living/user, obj/machinery/door/airlock)
if(DOING_INTERACTION_WITH_TARGET(user, airlock))
return
user.balloon_alert_to_viewers("fumbles with keys...", "finding key...")
user.playsound_local(src, 'sound/items/rattling_keys.ogg', 25, TRUE)
if(!do_after(user, 3 SECONDS, airlock))
return FALSE
if(!department_access || !airlock.check_access_list(SSid_access.accesses_by_region[department_access]))
airlock.balloon_alert(user, "no access!")
return FALSE
return airlock.try_to_activate_door(user, access_bypass = TRUE)
/**
* Called when a keycard authenticator sends region access
* Stores it on the key to use for access, then sets a timer to clear it.
* Args:
* source - the keycard authenticator giving us the access
* region_access - the list of access we're being sent, we only take the first entry in the list as there should only have one department at a time.
*/
/obj/item/access_key/proc/department_access_given(obj/machinery/keycard_auth/source, list/region_access)
SIGNAL_HANDLER
department_access = region_access[1]
say("Access granted to [department_access] area.")
playsound(src, 'sound/machines/ding.ogg', 25, TRUE)
addtimer(CALLBACK(src, PROC_REF(clear_access)), ACCESS_TIMER_LIMIT, TIMER_UNIQUE|TIMER_OVERRIDE)
log_game("Access to the [department_access] department was given to [src] [(ismob(loc)) ? "held by [loc]" : "which is not being held"]")
investigate_log("Access to the [department_access] department was given to [src] [(ismob(loc)) ? "held by [loc]" : "which is not being held"]", INVESTIGATE_ACCESSCHANGES)
/**
* Called when a keycard authenticator runs out of time
* Clears the department access and alerts nearby people of such.
*/
/obj/item/access_key/proc/clear_access()
log_game("Access to the [department_access] department on [src] has expired.")
investigate_log("Access to the [department_access] department on [src] has expired.]", INVESTIGATE_ACCESSCHANGES)
department_access = null
say("Access revoked, time ran out.")
playsound(src, 'sound/machines/scanbuzz.ogg', 25, TRUE)
#undef ACCESS_TIMER_LIMIT
+6 -2
View File
@@ -32,7 +32,6 @@
job_tone = "slip"
/datum/outfit/job/janitor
name = "Janitor"
jobtype = /datum/job/janitor
@@ -42,12 +41,17 @@
belt = /obj/item/modular_computer/pda/janitor
ears = /obj/item/radio/headset/headset_srv
/datum/outfit/job/janitor/pre_equip(mob/living/carbon/human/H, visualsOnly)
/datum/outfit/job/janitor/pre_equip(mob/living/carbon/human/human_equipper, visuals_only)
. = ..()
if(check_holidays(GARBAGEDAY))
backpack_contents += list(/obj/item/gun/ballistic/revolver)
r_pocket = /obj/item/ammo_box/a357
var/static/access_key_given = FALSE
if(!access_key_given && !visuals_only)
access_key_given = TRUE
backpack_contents += list(/obj/item/access_key)
/datum/outfit/job/janitor/get_types_to_preload()
. = ..()
if(check_holidays(GARBAGEDAY))
@@ -4,9 +4,11 @@ GLOBAL_DATUM_INIT(keycard_events, /datum/events, new)
#define KEYCARD_EMERGENCY_MAINTENANCE_ACCESS "Emergency Maintenance Access"
#define KEYCARD_BSA_UNLOCK "Bluespace Artillery Unlock"
#define ACCESS_GRANTING_COOLDOWN (30 SECONDS)
/obj/machinery/keycard_auth
name = "Keycard Authentication Device"
desc = "This device is used to trigger station functions, which require more than one ID card to authenticate."
desc = "This device is used to trigger station functions, which require more than one ID card to authenticate, or to give the Janitor access to a department."
icon = 'icons/obj/monitors.dmi'
icon_state = "auth_off"
power_channel = AREA_USAGE_ENVIRON
@@ -19,6 +21,8 @@ GLOBAL_DATUM_INIT(keycard_events, /datum/events, new)
var/mob/triggerer = null
var/waiting = FALSE
COOLDOWN_DECLARE(access_grant_cooldown)
MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/keycard_auth, 26)
/obj/machinery/keycard_auth/Initialize(mapload)
@@ -61,9 +65,9 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/keycard_auth, 26)
/obj/machinery/keycard_auth/ui_act(action, params)
. = ..()
if(. || waiting || !allowed(usr))
return
switch(action)
if("red_alert")
if(!event_source)
@@ -83,6 +87,24 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/keycard_auth, 26)
if(!event_source)
sendEvent(KEYCARD_BSA_UNLOCK)
. = TRUE
if("give_janitor_access")
var/mob/living/living_user = usr
if(!living_user || !istype(living_user))
return TRUE
if(!COOLDOWN_FINISHED(src, access_grant_cooldown))
balloon_alert(usr, "on cooldown!")
return TRUE
var/obj/item/card/id/advanced/card = living_user.get_idcard(hand_first = TRUE)
if(!card)
return TRUE
for(var/access_as_text in SSid_access.sub_department_managers_tgui)
var/list/info = SSid_access.sub_department_managers_tgui[access_as_text]
if(card.trim.assignment != info["head"])
continue
COOLDOWN_START(src, access_grant_cooldown, ACCESS_GRANTING_COOLDOWN)
SEND_GLOBAL_SIGNAL(COMSIG_ON_DEPARTMENT_ACCESS, info["regions"])
balloon_alert(usr, "key access sent")
return
/obj/machinery/keycard_auth/update_appearance(updates)
. = ..()
@@ -163,6 +185,7 @@ GLOBAL_VAR_INIT(emergency_access, FALSE)
minor_announce("Bluespace Artillery firing protocols have been [GLOB.bsa_unlock? "unlocked" : "locked"]", "Weapons Systems Update:")
SSblackbox.record_feedback("nested tally", "keycard_auths", 1, list("bluespace artillery", GLOB.bsa_unlock? "unlocked" : "locked"))
#undef ACCESS_GRANTING_COOLDOWN
#undef KEYCARD_RED_ALERT
#undef KEYCARD_EMERGENCY_MAINTENANCE_ACCESS
#undef KEYCARD_BSA_UNLOCK
Binary file not shown.

After

Width:  |  Height:  |  Size: 344 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 336 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 34 KiB

+3 -1
View File
@@ -38,6 +38,9 @@ alien_organ_cut.ogg is adapted from some CC 0 flesh sound, lesaucisson's swoosh
standard_stamp.ogg is adapted from tom_woysky's "Stamp.wav" https://freesound.org/people/tom_woysky/sounds/348316/
rattling_keys.ogg and rattling_keys_attack.ogg is adapted from Desibloke's "Keys rattling [Key rattle]" https://freesound.org/people/Desibloke/sounds/523671/
chainsaw_loop.ogg is adapted from Audionautics "Chainsaw Idle Loops", which is licensed under CC Attribution 3.0
https://freesound.org/people/Audionautics/sounds/171652/
chainsaw_start.ogg is adapted from 8 Chainsaw Pulls.wav by Stefan021
@@ -45,4 +48,3 @@ https://freesound.org/s/431740/ (CC 0)
chainsaw_stop.ogg is adapted from kyles "chainsaw sawing short cuts +stop.flac" (CC 0)
https://freesound.org/people/kyles/sounds/453256/
Binary file not shown.
Binary file not shown.
+2
View File
@@ -268,6 +268,7 @@
#include "code\__DEFINES\dcs\signals\signals_hud.dm"
#include "code\__DEFINES\dcs\signals\signals_hydroponic.dm"
#include "code\__DEFINES\dcs\signals\signals_janitor.dm"
#include "code\__DEFINES\dcs\signals\signals_key.dm"
#include "code\__DEFINES\dcs\signals\signals_ladder.dm"
#include "code\__DEFINES\dcs\signals\signals_lift.dm"
#include "code\__DEFINES\dcs\signals\signals_light_eater.dm"
@@ -1791,6 +1792,7 @@
#include "code\game\objects\items\hourglass.dm"
#include "code\game\objects\items\inducer.dm"
#include "code\game\objects\items\inspector.dm"
#include "code\game\objects\items\janitor_key.dm"
#include "code\game\objects\items\kirbyplants.dm"
#include "code\game\objects\items\kitchen.dm"
#include "code\game\objects\items\knives.dm"
+7 -1
View File
@@ -5,7 +5,7 @@ import { Window } from '../layouts';
export const KeycardAuth = (props, context) => {
const { act, data } = useBackend(context);
return (
<Window width={375} height={125}>
<Window width={375} height={145}>
<Window.Content>
<Section>
<Box>
@@ -49,6 +49,12 @@ export const KeycardAuth = (props, context) => {
onClick={() => act('bsa_unlock')}
content="Bluespace Artillery Unlock"
/>
<Button
icon="key"
fluid
onClick={() => act('give_janitor_access')}
content="Grant Janitor Access"
/>
</>
)}
</>