Files
aedc5bae7a allowed is now signals based instead of hardcoded slots (#94871)
## About The Pull Request

ID cards/MMI mech access/simple mob access/pAIs now use signals instead
of checking specific slots with mob checks. We do this through mob's
``get_access`` proc that collects all access a mob has with a
collect_access signal.

## Why It's Good For The Game

It looks cleaner and we no longer individually check `check_access` for
every single item that may have access. It's cleaner to put it all
together and check in one go with all the access we've got. This also
makes it easier to add items that hold access that aren't necessarily
IDs but you want to be able to open stuff with.

## Changelog

🆑
refactor: ID checking for access has been reworked, please make a bug
report if anything that's supposed to grant access is not working.
/🆑

---------

Co-authored-by: MrMelbert <51863163+MrMelbert@users.noreply.github.com>
2026-01-16 14:16:22 -07:00

201 lines
6.5 KiB
Plaintext

/datum/wires/airlock/shell
holder_type = /obj/machinery/door/airlock/shell
proper_name = "Circuit Airlock"
/datum/wires/airlock/shell/on_cut(wire, mend, source)
// Don't allow them to re-enable autoclose.
if(wire == WIRE_TIMING)
return
return ..()
/obj/machinery/door/airlock/shell
name = "circuit airlock"
autoclose = FALSE
/obj/machinery/door/airlock/shell/Initialize(mapload)
. = ..()
AddComponent( \
/datum/component/shell, \
unremovable_circuit_components = list(new /obj/item/circuit_component/airlock, new /obj/item/circuit_component/airlock_access_event, new /obj/item/circuit_component/remotecam/airlock), \
capacity = SHELL_CAPACITY_LARGE, \
shell_flags = SHELL_FLAG_ALLOW_FAILURE_ACTION|SHELL_FLAG_REQUIRE_ANCHOR \
)
/obj/machinery/door/airlock/shell/check_access(obj/item/I)
return FALSE
/obj/machinery/door/airlock/shell/canAIControl(mob/user)
return FALSE
/obj/machinery/door/airlock/shell/canAIHack(mob/user)
return FALSE
/obj/machinery/door/airlock/shell/allowed(mob/user)
if(SEND_SIGNAL(src, COMSIG_AIRLOCK_SHELL_ALLOWED, user) & ACCESS_ALLOWED)
return TRUE
return isAdminGhostAI(user)
/obj/machinery/door/airlock/shell/get_wires()
return new /datum/wires/airlock/shell(src)
/obj/item/circuit_component/airlock
display_name = "Airlock"
desc = "The general interface with an airlock. Includes general statuses of the airlock"
/// The shell, if it is an airlock.
var/obj/machinery/door/airlock/attached_airlock
/// Bolts the airlock (if possible)
var/datum/port/input/bolt
/// Unbolts the airlock (if possible)
var/datum/port/input/unbolt
/// Opens the airlock (if possible)
var/datum/port/input/open
/// Closes the airlock (if possible)
var/datum/port/input/close
/// Contains whether the airlock is open or not
var/datum/port/output/is_open
/// Contains whether the airlock is bolted or not
var/datum/port/output/is_bolted
/// Called when the airlock is opened.
var/datum/port/output/opened
/// Called when the airlock is closed
var/datum/port/output/closed
/// Called when the airlock is bolted
var/datum/port/output/bolted
/// Called when the airlock is unbolted
var/datum/port/output/unbolted
/obj/item/circuit_component/airlock/populate_ports()
// Input Signals
bolt = add_input_port("Bolt", PORT_TYPE_SIGNAL)
unbolt = add_input_port("Unbolt", PORT_TYPE_SIGNAL)
open = add_input_port("Open", PORT_TYPE_SIGNAL)
close = add_input_port("Close", PORT_TYPE_SIGNAL)
// States
is_open = add_output_port("Is Open", PORT_TYPE_NUMBER)
is_bolted = add_output_port("Is Bolted", PORT_TYPE_NUMBER)
// Output Signals
opened = add_output_port("Opened", PORT_TYPE_SIGNAL)
closed = add_output_port("Closed", PORT_TYPE_SIGNAL)
bolted = add_output_port("Bolted", PORT_TYPE_SIGNAL)
unbolted = add_output_port("Unbolted", PORT_TYPE_SIGNAL)
/obj/item/circuit_component/airlock/register_shell(atom/movable/shell)
. = ..()
if(istype(shell, /obj/machinery/door/airlock))
attached_airlock = shell
RegisterSignal(shell, COMSIG_AIRLOCK_SET_BOLT, PROC_REF(on_airlock_set_bolted))
RegisterSignal(shell, COMSIG_AIRLOCK_OPEN, PROC_REF(on_airlock_open))
RegisterSignal(shell, COMSIG_AIRLOCK_CLOSE, PROC_REF(on_airlock_closed))
/obj/item/circuit_component/airlock/unregister_shell(atom/movable/shell)
attached_airlock = null
UnregisterSignal(shell, list(
COMSIG_AIRLOCK_SET_BOLT,
COMSIG_AIRLOCK_OPEN,
COMSIG_AIRLOCK_CLOSE,
))
return ..()
/obj/item/circuit_component/airlock/proc/on_airlock_set_bolted(datum/source, should_bolt)
SIGNAL_HANDLER
is_bolted.set_output(should_bolt)
if(should_bolt)
bolted.set_output(COMPONENT_SIGNAL)
else
unbolted.set_output(COMPONENT_SIGNAL)
/obj/item/circuit_component/airlock/proc/on_airlock_open(datum/source, force)
SIGNAL_HANDLER
is_open.set_output(TRUE)
opened.set_output(COMPONENT_SIGNAL)
/obj/item/circuit_component/airlock/proc/on_airlock_closed(datum/source, forced)
SIGNAL_HANDLER
is_open.set_output(FALSE)
closed.set_output(COMPONENT_SIGNAL)
/obj/item/circuit_component/airlock/input_received(datum/port/input/port)
if(!attached_airlock)
return
if(COMPONENT_TRIGGERED_BY(bolt, port))
attached_airlock.bolt()
if(COMPONENT_TRIGGERED_BY(unbolt, port))
attached_airlock.unbolt()
if(COMPONENT_TRIGGERED_BY(open, port) && attached_airlock.density)
INVOKE_ASYNC(attached_airlock, TYPE_PROC_REF(/obj/machinery/door/airlock, open))
if(COMPONENT_TRIGGERED_BY(close, port) && !attached_airlock.density)
INVOKE_ASYNC(attached_airlock, TYPE_PROC_REF(/obj/machinery/door/airlock, close))
/obj/item/circuit_component/airlock_access_event
display_name = "Airlock Access Event"
desc = "An event that can be handled through circuit components to determine if the door should open or not for an entity that might be trying to access it."
circuit_flags = CIRCUIT_FLAG_INSTANT
/// The shell, if it is an airlock.
var/obj/machinery/door/airlock/attached_airlock
/// Tells the event to open the airlock.
var/datum/port/input/open_airlock
/// The person trying to open the airlock.
var/datum/port/output/accessing_entity
/// The signal sent when this event is triggered
var/datum/port/output/event_triggered
/obj/item/circuit_component/airlock_access_event/register_shell(atom/movable/shell)
. = ..()
if(istype(shell, /obj/machinery/door/airlock))
attached_airlock = shell
RegisterSignals(shell, list(
COMSIG_AIRLOCK_SHELL_ALLOWED,
), PROC_REF(handle_allowed))
/obj/item/circuit_component/airlock_access_event/unregister_shell(atom/movable/shell)
attached_airlock = null
UnregisterSignal(shell, list(
COMSIG_AIRLOCK_SHELL_ALLOWED
))
return ..()
/obj/item/circuit_component/airlock_access_event/populate_ports()
open_airlock = add_input_port("Should Open Airlock", PORT_TYPE_RESPONSE_SIGNAL, trigger = PROC_REF(should_open_airlock))
accessing_entity = add_output_port("Accessing Entity", PORT_TYPE_ATOM)
event_triggered = add_output_port("Event Triggered", PORT_TYPE_INSTANT_SIGNAL)
/obj/item/circuit_component/airlock_access_event/proc/should_open_airlock(datum/port/input/port, list/return_values)
CIRCUIT_TRIGGER
if(!return_values)
return
return_values["should_open"] = TRUE
/obj/item/circuit_component/airlock_access_event/proc/handle_allowed(datum/source, mob/accesser)
SIGNAL_HANDLER
if(!attached_airlock)
return
SScircuit_component.queue_instant_run()
accessing_entity.set_output(accesser)
event_triggered.set_output(COMPONENT_SIGNAL)
var/list/result = SScircuit_component.execute_instant_run()
if(!result)
attached_airlock.visible_message(span_warning("[attached_airlock]'s circuitry overheats!"))
return
if(result["should_open"])
return ACCESS_ALLOWED
else
return ACCESS_DISALLOWED