Skip to content

Commit

Permalink
fix: keycard auth
Browse files Browse the repository at this point in the history
  • Loading branch information
DeltaEpsilon7787 authored Sep 10, 2024
1 parent c17b052 commit 99326e1
Show file tree
Hide file tree
Showing 2 changed files with 134 additions and 102 deletions.
2 changes: 1 addition & 1 deletion baystation12.dme
Original file line number Diff line number Diff line change
Expand Up @@ -2847,7 +2847,7 @@
#include "code\modules\research\designs\protolathe\dp-stock_parts.dm"
#include "code\modules\research\designs\protolathe\dp-surgery.dm"
#include "code\modules\research\designs\protolathe\dp-weapons.dm"
#include "code\modules\security levels\keycard authentication.dm"
#include "code\modules\security_levels\keycard_auth.dm"
#include "code\modules\shield_generators\floor_diffuser.dm"
#include "code\modules\shield_generators\handheld_diffuser.dm"
#include "code\modules\shield_generators\modes.dm"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,25 +1,37 @@
#define INACTIVE 0
#define CALL_ERT 1
#define GRANT_MAINT 2
#define REVOKE_MAINT 3
#define GRANT_NUCLEAR_CODE 4

/obj/machinery/keycard_auth
name = "Keycard Authentication Device"
desc = "This device is used to trigger functions which require more than one ID card to authenticate."
icon = 'icons/obj/monitors.dmi'
icon_state = "auth_off"
var/active = 0 //This gets set to 1 on all devices except the one where the initial request was made.
var/event = ""
var/event_additional_info = ""
var/screen = 1
var/confirmed = 0 //This variable is set by the device that confirms the request.

// 3 vars here as booleans produce 4 relevant state:
// (!!auth_proxy)<<2 | (!!trigger_id)<<1 | (active_event != INACTIVE)
// 000 -- Standby, waiting for an event to be selected
// 001 -- Event selected, waiting for causer to swipe ID
// 011 -- Causer waits for confirmation
// 100 -- Wait for confirmer's ID
var/active_event = INACTIVE
var/event_reason = ""

var/obj/machinery/keycard_auth/auth_proxy
var/obj/item/card/id/trigger_id

var/confirm_delay = 3 SECONDS
var/busy = 0 //Busy when waiting for authentication or an event request has been sent from this device.
var/obj/machinery/keycard_auth/event_source
var/obj/item/card/id/initial_card
var/mob/event_triggered_by
var/mob/event_confirmed_by
//1 = select event
//2 = authenticate

var/mob/triggered_by = null
var/mob/confirmed_by = null

anchored = 1.0
idle_power_usage = 2 WATTS
active_power_usage = 6 WATTS
power_channel = STATIC_ENVIRON

/// Whether we have active thinking to call ert or not
var/ert_context_thinking = FALSE

Expand All @@ -35,33 +47,81 @@
if(stat & (NOPOWER|BROKEN))
to_chat(user, SPAN_WARNING("This device is not powered."))
return
if(istype(W,/obj/item/card/id))
visible_message(SPAN_NOTICE("\The [user] swipes \the [W] through \the [src]."))
var/obj/item/card/id/ID = W
if(access_keycard_auth in ID.access)
if(active)
if(event_source && initial_card != ID)
event_source.confirmed = 1
event_source.event_confirmed_by = user
else
visible_message(SPAN_WARNING("\The [src] blinks and displays a message: Unable to confirm the event with the same card."), range=2)
else if(screen == 2)
event_triggered_by = user
initial_card = ID
broadcast_request() //This is the device making the initial event request. It needs to broadcast to other devices

if(istype(W, /obj/item/card/id))
var/obj/item/card/id/id = W

if (src.auth_proxy)
if (src.auth_proxy.try_confirm(id, user))
visible_message(SPAN_INFO("\The [src] blinks and displays a message: Confirmed."), range=2)
src.reset()
else
visible_message(SPAN_WARNING("\The [src] blinks and displays a message: Unable to confirm the event with the same card."), range=2)
else if (src.active_event == INACTIVE || src.trigger_id)
visible_message(SPAN_NOTICE("\The [user] swipes \the [id] through \the [src], but nothing happens."))
else if (!(access_keycard_auth in id.access))
visible_message(SPAN_NOTICE("\The [user] swipes \the [id] through \the [src], but it's declined."))
else
visible_message(SPAN_NOTICE("\The [user] swipes \the [id] through \the [src] and it's accepted."))
src.do_proxy(id, user)

/obj/machinery/keycard_auth/proc/do_proxy(obj/item/card/id/trigger_id, mob/triggerer)
src.icon_state = "auth_on"
src.trigger_id = trigger_id
src.triggered_by = triggerer

for(var/obj/machinery/keycard_auth/KA in world)
if(KA == src)
continue

if (!KA.auth_proxy)
KA.auth_proxy = src
KA.icon_state = "auth_on"
spawn(src.confirm_delay)
if (KA.auth_proxy == src)
KA.reset()

sleep(src.confirm_delay)

if (src.trigger_id)
visible_message(SPAN_INFO("\The [src] blinks and displays a message: Confirmation failure."), range=2)

src.reset()

/obj/machinery/keycard_auth/proc/try_confirm(obj/item/card/id/second_id, mob/confirmer)
if (!src.trigger_id || src.trigger_id == second_id)
return FALSE

visible_message(SPAN_INFO("\The [src] blinks and displays a message: Confirmed."), range=2)
log_game("[key_name(src.triggered_by)] triggered and [key_name(confirmer)] confirmed event [src.active_event]")
message_admins("[key_name(src.triggered_by)] triggered and [key_name(confirmer)] confirmed event [src.active_event]", 1)

src.cause_event()
src.reset()

return TRUE

//icon_state gets set everwhere besides here, that needs to be fixed sometime
/obj/machinery/keycard_auth/on_update_icon()
if(stat &NOPOWER)
if(stat & NOPOWER)
icon_state = "auth_off"

/obj/machinery/keycard_auth/proc/reset()
src.active_event = INACTIVE
src.event_reason = ""
src.icon_state = "auth_off"
src.auth_proxy = null
src.trigger_id = null
src.triggered_by = null
src.confirmed_by = null

/obj/machinery/keycard_auth/attack_hand(mob/user as mob)
if(stat & (NOPOWER|BROKEN))
to_chat(user, "This device is not powered.")
return
if(!user.IsAdvancedToolUser())
return 0
if(busy)
if(src.trigger_id)
to_chat(user, "This device is busy.")
return

Expand All @@ -72,28 +132,38 @@
dat += "This device is used to trigger some high security events. It requires the simultaneous swipe of two high-level ID cards."
dat += "<br><hr><br>"

if(screen == 1)
if(src.active_event == INACTIVE)
dat += "Select an event to trigger:<ul>"

var/decl/security_state/security_state = decls_repository.get_decl(GLOB.using_map.security_state)
dat += "<li><A href='?src=\ref[src];triggerevent=Red alert'>Engage [security_state.high_security_level.name]</A></li>"
if(!config.gamemode.ert_admin_only)
dat += "<li><A href='?src=\ref[src];triggerevent=Emergency Response Team'>Emergency Response Team</A></li>"
dat += "<li><A href='?src=\ref[src];triggerevent=[CALL_ERT]'>Emergency Response Team</A></li>"

dat += "<li><A href='?src=\ref[src];triggerevent=Grant Emergency Maintenance Access'>Grant Emergency Maintenance Access</A></li>"
dat += "<li><A href='?src=\ref[src];triggerevent=Revoke Emergency Maintenance Access'>Revoke Emergency Maintenance Access</A></li>"
dat += "<li><A href='?src=\ref[src];triggerevent=Grant Nuclear Authorization Code'>Grant Nuclear Authorization Code</A></li>"
dat += "<li><A href='?src=\ref[src];triggerevent=[GRANT_MAINT]'>Grant Emergency Maintenance Access</A></li>"
dat += "<li><A href='?src=\ref[src];triggerevent=[REVOKE_MAINT]'>Revoke Emergency Maintenance Access</A></li>"
dat += "<li><A href='?src=\ref[src];triggerevent=[GRANT_NUCLEAR_CODE]'>Grant Nuclear Authorization Code</A></li>"
dat += "</ul>"
show_browser(user, dat, "window=keycard_auth;size=500x250")
if(screen == 2)
else
var/event = "Standby"
switch (src.active_event)
if (CALL_ERT)
event = "Call Emergency Response Team"
if (GRANT_MAINT)
event = "Grant Emergency Maintenance Access"
if (REVOKE_MAINT)
event = "Revoke Emergency Maintenance Access"
if (GRANT_NUCLEAR_CODE)
event = "Grant Nuclear Authorization Code"

dat += "Please swipe your card to authorize the following event: <b>[event]</b>"
dat += "[event_additional_info ? "<p>Additional info: [event_additional_info]" : ""]"
if (src.event_reason)
dat += "<br>Reason: [src.event_reason]<br>"
dat += "<p><A href='?src=\ref[src];reset=1'>Back</A>"
show_browser(user, dat, "window=keycard_auth;size=500x250")
return

/obj/machinery/keycard_auth/CanUseTopic(mob/user, href_list)
if(busy)
if(src.auth_proxy)
to_chat(user, "This device is busy.")
return STATUS_CLOSE
if(!user.IsAdvancedToolUser())
Expand All @@ -103,21 +173,25 @@

/obj/machinery/keycard_auth/OnTopic(user, href_list)
if(href_list["triggerevent"])
event = href_list["triggerevent"]
event_additional_info = ""
if(event == "Emergency Response Team")
event_additional_info = sanitize(input(user, "Enter call reason", "Call reason") as message, extra=FALSE)
event = "Emergency Response Team"
screen = 2
src.active_event = text2num(href_list["triggerevent"])
src.event_reason = ""

if(src.active_event == CALL_ERT)
event_reason = sanitize(input(user, "Enter call reason", "Call reason") as message, extra=FALSE)

. = TOPIC_REFRESH

if(href_list["reset"])
reset()
src.active_event = INACTIVE
src.event_reason = ""

. = TOPIC_REFRESH

if(is_admin(user) && href_list["approve_ert"])
set_next_think_ctx("call_ert_context", 0)
ert_context_thinking = FALSE
call_ert()

if(is_admin(user) && href_list["prohibit_ert"])
set_next_think_ctx("call_ert_context", 0)
ert_context_thinking = FALSE
Expand All @@ -127,74 +201,26 @@
if(. == TOPIC_REFRESH)
attack_hand(user)

/obj/machinery/keycard_auth/proc/reset()
active = 0
event = ""
screen = 1
confirmed = 0
event_source = null
icon_state = "auth_off"
event_triggered_by = null
event_confirmed_by = null
initial_card = null

/obj/machinery/keycard_auth/proc/broadcast_request()
icon_state = "auth_on"
for(var/obj/machinery/keycard_auth/KA in world)
if(KA == src)
continue
KA.reset()
KA.receive_request(src, initial_card)

if(confirm_delay)
set_next_think(world.time + confirm_delay)

/obj/machinery/keycard_auth/think()
if(confirmed)
confirmed = 0
trigger_event(event)
log_game("[key_name(event_triggered_by)] triggered and [key_name(event_confirmed_by)] confirmed event [event]")
message_admins("[key_name(event_triggered_by)] triggered and [key_name(event_confirmed_by)] confirmed event [event]", 1)
reset()

/obj/machinery/keycard_auth/proc/receive_request(obj/machinery/keycard_auth/source, obj/item/card/id/ID)
if(stat & (BROKEN|NOPOWER))
return
event_source = source
initial_card = ID
busy = 1
active = 1
icon_state = "auth_on"

sleep(confirm_delay)

event_source = null
initial_card = null
icon_state = "auth_off"
active = 0
busy = 0

/obj/machinery/keycard_auth/proc/trigger_event()
switch(event)
if("Red alert")
var/decl/security_state/security_state = decls_repository.get_decl(GLOB.using_map.security_state)
security_state.set_security_level(security_state.high_security_level)
feedback_inc("alert_keycard_auth_red",1)
if("Grant Emergency Maintenance Access")
/obj/machinery/keycard_auth/proc/cause_event()
switch(src.active_event)
if(GRANT_MAINT)
make_maint_all_access()
feedback_inc("alert_keycard_auth_maintGrant",1)
if("Revoke Emergency Maintenance Access")
if(REVOKE_MAINT)
revoke_maint_all_access()
feedback_inc("alert_keycard_auth_maintRevoke",1)
if("Emergency Response Team")
if(CALL_ERT)
if(ert_call_failure())
return
if(!ert_context_thinking)
visible_message(SPAN_NOTICE("\The [src] displays the message: The request has been created and the process of transferring the request to the emergency response service has been started, the approximate waiting time for processing is 2 minutes."), range=2)
set_next_think_ctx("call_ert_context", world.time + 2 MINUTES)
ert_context_thinking = TRUE
message_admins("An ERT call request was created with the reason:\n[event_additional_info].\nThis call will automatically be approved after 2 minutes. <A href='?src=\ref[src];approve_ert=1'>Approve</a>. <A href='?src=\ref[src];prohibit_ert=1'>Reject</a>.")
if("Grant Nuclear Authorization Code")
message_admins("An ERT call request was created with the reason:\n[src.event_reason].\nThis call will automatically be approved after 2 minutes. <A href='?src=\ref[src];approve_ert=1'>Approve</a>. <A href='?src=\ref[src];prohibit_ert=1'>Reject</a>.")
if(GRANT_NUCLEAR_CODE)
var/obj/machinery/nuclearbomb/nuke = locate(/obj/machinery/nuclearbomb/station) in world
if(nuke)
visible_message(SPAN_WARNING("\The [src] blinks and displays a message: The nuclear authorization code is [nuke.r_code]"), range=2)
Expand All @@ -218,7 +244,7 @@
return

visible_message(SPAN_NOTICE("\The [src] displays the message: The request has been approved, the response team will be on facility shortly."), range=2)
trigger_armed_response_team(TRUE, event_additional_info)
trigger_armed_response_team(TRUE, src.event_reason)
feedback_inc("alert_keycard_auth_ert",1)

/obj/machinery/keycard_auth/proc/is_ert_blocked()
Expand All @@ -241,3 +267,9 @@ var/global/maint_all_access = 0
if(maint_all_access && src.check_access_list(list(access_maint_tunnels)))
return 1
return ..(M)

#undef INACTIVE
#undef CALL_ERT
#undef GRANT_MAINT
#undef REVOKE_MAINT
#undef GRANT_NUCLEAR_CODE

0 comments on commit 99326e1

Please sign in to comment.