[MIRROR] Circuit ID Components [MDB IGNORE] (#10472)

* Circuit ID Components (#63817)

This PR adds several circuit components used for scanning and checking ID cards:

The Get ID component returns the ID the target is wearing or holding
The Read ID Info component returns the name, rank, and age registered on the ID
The Read ID Access component returns a list of all the accesses on the ID
The Access Checker component does comparisons on lists of numbers, specifically tailored for checking ID access
Due to the access checker using a similar UI element to the airlock electronics, that element has been moved to its own file in tgui/interfaces/common. This change is not player-facing.

* Circuit ID Components

Co-authored-by: Y0SH1M4S73R <legoboyo@earthlink.net>
This commit is contained in:
SkyratBot
2022-01-06 14:15:41 +01:00
committed by GitHub
parent aefe93f9be
commit 4b80bb178a
10 changed files with 454 additions and 133 deletions
@@ -0,0 +1,138 @@
/obj/item/circuit_component/compare/access
display_name = "Access Checker"
desc = "Performs a basic comparison between two numerical lists, with additional functions that help in using it to check access on IDs."
category = "ID"
input_port_amount = 0 //Uses custom ports for its comparisons
/// A list of the accesses to check
var/datum/port/input/subject_accesses
/// A list of the accesses required to return true
var/datum/port/input/required_accesses
/// Whether to check for all or any of the required accesses
var/datum/port/input/check_any
ui_buttons = list("id-card" = "access")
/obj/item/circuit_component/compare/access/Initialize(mapload)
. = ..()
gen_access()
/obj/item/circuit_component/compare/access/get_ui_notices()
. = ..()
. += create_ui_notice("When \"Check Any\" is true, returns true if \"Access To Check\" contains ANY value in \"Required Access\".", "orange", "info")
. += create_ui_notice("When \"Check Any\" is false, returns true only if \"Access To Check\" contains ALL values in \"Required Access\".", "orange", "info")
/obj/item/circuit_component/compare/access/populate_custom_ports()
subject_accesses = add_input_port("Access To Check", PORT_TYPE_LIST(PORT_TYPE_NUMBER))
required_accesses = add_input_port("Required Access", PORT_TYPE_LIST(PORT_TYPE_NUMBER))
check_any = add_input_port("Check Any", PORT_TYPE_NUMBER)
/obj/item/circuit_component/compare/access/save_data_to_list(list/component_data)
. = ..()
component_data["input_ports_stored_data"] = list(required_accesses.name = list("stored_data" = required_accesses.value))
/obj/item/circuit_component/compare/access/add_to(obj/item/integrated_circuit/added_to)
. = ..()
RegisterSignal(added_to, COMSIG_CIRCUIT_POST_LOAD, .proc/on_post_load)
/obj/item/circuit_component/compare/access/removed_from(obj/item/integrated_circuit/removed_from)
UnregisterSignal(removed_from, COMSIG_CIRCUIT_POST_LOAD)
return ..()
/obj/item/circuit_component/compare/access/proc/on_post_load(datum/source)
regenerate_access()
/obj/item/circuit_component/compare/access/proc/regenerate_access()
var/check_any_value = check_any.value
var/list/required_accesses_list = required_accesses.value
if(!islist(required_accesses_list))
return
if(check_any_value)
LAZYCLEARLIST(req_access)
req_one_access = required_accesses_list.Copy()
else
LAZYCLEARLIST(req_one_access)
req_access = required_accesses_list.Copy()
/obj/item/circuit_component/compare/access/do_comparisons(list/ports)
return check_access_list(subject_accesses.value)
/obj/item/circuit_component/compare/access/ui_perform_action(mob/user, action)
if(length(required_accesses.connected_ports))
balloon_alert(user, "Disconnect port before manually configuring!")
return
interact(user)
/obj/item/circuit_component/compare/access/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "CircuitAccessChecker", display_name)
ui.open()
/obj/item/circuit_component/compare/access/ui_static_data(mob/user)
var/list/data = list()
var/list/regions = list()
var/list/tgui_region_data = SSid_access.all_region_access_tgui
for(var/region in SSid_access.station_regions)
regions += tgui_region_data[region]
if(parent?.admin_only)
regions += tgui_region_data[REGION_CENTCOM]
regions += tgui_region_data[REGION_ALL_GLOBAL]
data["regions"] = regions
return data
/obj/item/circuit_component/compare/access/ui_data(mob/user)
var/list/data = list()
data["accesses"] = required_accesses.value
data["oneAccess"] = check_any.value
return data
/obj/item/circuit_component/compare/access/ui_act(action, params)
. = ..()
if(.)
return
switch(action)
if("clear_all")
required_accesses.set_value(list())
check_any.set_value(0)
. = TRUE
if("grant_all")
required_accesses.set_value(SSid_access.get_region_access_list(list(REGION_ALL_STATION)))
. = TRUE
if("one_access")
check_any.set_value(!check_any.value)
. = TRUE
if("set")
var/list/required_accesses_list = required_accesses.value
var/list/new_accesses_value = LAZYCOPY(required_accesses_list)
var/access = text2num(params["access"])
if (!(access in new_accesses_value))
new_accesses_value += access
else
new_accesses_value -= access
required_accesses.set_value(new_accesses_value)
. = TRUE
if("grant_region")
var/list/required_accesses_list = required_accesses.value
var/list/required_accesses_value = LAZYCOPY(required_accesses_list)
var/region = params["region"]
if(isnull(region))
return
required_accesses.set_value(required_accesses_value | SSid_access.get_region_access_list(list(region)))
. = TRUE
if("deny_region")
var/list/required_accesses_list = required_accesses.value
var/list/required_accesses_value = LAZYCOPY(required_accesses_list)
var/region = params["region"]
if(isnull(region))
return
required_accesses.set_value(required_accesses_value - SSid_access.get_region_access_list(list(region)))
. = TRUE
if(.)
regenerate_access()
SStgui.update_uis(parent)
@@ -0,0 +1,32 @@
/obj/item/circuit_component/id_access_reader
display_name = "Read ID Access"
desc = "A component that reads the access on an ID."
category = "ID"
/// The input port
var/datum/port/input/target
/// A list of the accesses on the ID
var/datum/port/output/access_port
circuit_flags = CIRCUIT_FLAG_INPUT_SIGNAL|CIRCUIT_FLAG_OUTPUT_SIGNAL
var/max_range = 1
/obj/item/circuit_component/id_access_reader/get_ui_notices()
. = ..()
. += create_ui_notice("Maximum Range: [max_range] tiles.", "orange", "info")
/obj/item/circuit_component/id_access_reader/populate_ports()
target = add_input_port("Target", PORT_TYPE_ATOM)
access_port = add_output_port("Access", PORT_TYPE_LIST(PORT_TYPE_NUMBER))
/obj/item/circuit_component/id_access_reader/input_received(datum/port/input/port)
var/obj/item/card/id/target_item = target.value
var/turf/current_turf = get_location()
var/turf/target_turf = get_turf(target_item)
if(!istype(target_item) || get_dist(current_turf, target_turf) > max_range || current_turf.z != target_turf.z)
access_port.set_output(null)
return
access_port.set_output(target_item.GetAccess())
@@ -0,0 +1,34 @@
/obj/item/circuit_component/id_getter
display_name = "Get ID"
desc = "A component that returns the first available ID card on an organism."
category = "ID"
/// The input port
var/datum/port/input/target
/// Whether to prioritize the target's hands when checking for an ID
var/datum/port/input/prioritize_hands
/// The reference to the ID
var/datum/port/output/id_port
circuit_flags = CIRCUIT_FLAG_INPUT_SIGNAL|CIRCUIT_FLAG_OUTPUT_SIGNAL
var/max_range = 1
/obj/item/circuit_component/id_getter/get_ui_notices()
. = ..()
. += create_ui_notice("Maximum Range: [max_range] tiles.", "orange", "info")
/obj/item/circuit_component/id_getter/populate_ports()
target = add_input_port("Target", PORT_TYPE_ATOM)
prioritize_hands = add_input_port("Prioritize Hands", PORT_TYPE_NUMBER)
id_port = add_output_port("ID", PORT_TYPE_ATOM)
/obj/item/circuit_component/id_getter/input_received(datum/port/input/port)
var/mob/living/target_mob = target.value
var/turf/current_turf = get_location()
if(!istype(target_mob) || get_dist(current_turf, target_mob) > max_range || current_turf.z != target_mob.z)
id_port.set_output(null)
return
id_port.set_output(target_mob.get_idcard(prioritize_hands.value))
@@ -0,0 +1,44 @@
/obj/item/circuit_component/id_info_reader
display_name = "Read ID Info"
desc = "A component that reads the name, job, and age on an ID."
category = "ID"
/// The input port
var/datum/port/input/target
/// The name registered on the ID
var/datum/port/output/name_port
/// The rank registered on the ID
var/datum/port/output/rank_port
/// The age registered on the ID
var/datum/port/output/age_port
circuit_flags = CIRCUIT_FLAG_INPUT_SIGNAL|CIRCUIT_FLAG_OUTPUT_SIGNAL
var/max_range = 1
/obj/item/circuit_component/id_info_reader/get_ui_notices()
. = ..()
. += create_ui_notice("Maximum Range: [max_range] tiles.", "orange", "info")
/obj/item/circuit_component/id_info_reader/populate_ports()
target = add_input_port("Target", PORT_TYPE_ATOM)
name_port = add_output_port("Name", PORT_TYPE_STRING)
rank_port = add_output_port("Rank", PORT_TYPE_STRING)
age_port = add_output_port("Age", PORT_TYPE_NUMBER)
/obj/item/circuit_component/id_info_reader/input_received(datum/port/input/port)
var/obj/item/card/id/target_item = target.value
var/turf/current_turf = get_location()
var/turf/target_turf = get_turf(target_item)
if(!istype(target_item) || get_dist(current_turf, target_turf) > max_range || current_turf.z != target_turf.z)
name_port.set_output(null)
rank_port.set_output(null)
age_port.set_output(null)
return
name_port.set_output(target_item.registered_name)
rank_port.set_output(target_item.assignment)
age_port.set_output(target_item.registered_age)