From 00be4978ae421983c96f0fd67c7cb3a65c24ec2d Mon Sep 17 00:00:00 2001 From: Watermelon914 <37270891+Watermelon914@users.noreply.github.com> Date: Mon, 6 Nov 2023 22:10:04 +0000 Subject: [PATCH] Adds a user type to integrated circuits, refactors the list pick component. (#79412) ## About The Pull Request Added a user type to integrated circuits that can't be stored as a user type but can be typecasted to entity. Useful for components that directly ask for an input from the user, like the list pick component. Refactored the list pick component to use this user port and to also send failure signals whenever a success signal is not sent. Removed the triggered port for the list pick component. Also fixes a runtime that occurs with the list pick component if the list passed in only contains null values. ## Why It's Good For The Game Can't force a prompt onto people who haven't interacted with your circuit. ## Changelog :cl: add: Added a user type to integrated circuits /:cl: --------- Co-authored-by: Watermelon914 <3052169-Watermelon914@users.noreply.gitlab.com> --- code/__DEFINES/traits.dm | 3 ++ code/__DEFINES/wiremod.dm | 2 + .../subsystem/circuit_component.dm | 4 +- code/modules/tgui_input/list.dm | 8 ++++ .../components/list/assoc_list_pick.dm | 1 - .../wiremod/components/list/assoc_literal.dm | 18 ++++---- .../wiremod/components/list/list_pick.dm | 42 ++++++++----------- code/modules/wiremod/datatypes/datum.dm | 1 + code/modules/wiremod/datatypes/entity.dm | 3 ++ code/modules/wiremod/datatypes/user.dm | 9 ++++ code/modules/wiremod/shell/bot.dm | 3 +- .../wiremod/shell/brain_computer_interface.dm | 2 +- code/modules/wiremod/shell/controller.dm | 24 +++++------ code/modules/wiremod/shell/keyboard.dm | 3 +- code/modules/wiremod/shell/module.dm | 2 +- code/modules/wiremod/shell/moneybot.dm | 2 +- tgstation.dme | 1 + 17 files changed, 71 insertions(+), 57 deletions(-) create mode 100644 code/modules/wiremod/datatypes/user.dm diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm index f8bd12fa5b9..ffcb72b92ae 100644 --- a/code/__DEFINES/traits.dm +++ b/code/__DEFINES/traits.dm @@ -873,6 +873,9 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai /// Trait applied when an integrated circuit/module becomes undupable #define TRAIT_CIRCUIT_UNDUPABLE "circuit_undupable" +/// Trait applied when an integrated circuit opens a UI on a player (see list pick component) +#define TRAIT_CIRCUIT_UI_OPEN "circuit_ui_open" + /// Hearing trait that is from the hearing component #define CIRCUIT_HEAR_TRAIT "circuit_hear" diff --git a/code/__DEFINES/wiremod.dm b/code/__DEFINES/wiremod.dm index 14a03d780ce..421650e3bf1 100644 --- a/code/__DEFINES/wiremod.dm +++ b/code/__DEFINES/wiremod.dm @@ -45,6 +45,8 @@ #define PORT_TYPE_ATOM "entity" /// Datum datatype #define PORT_TYPE_DATUM "datum" +/// User datatype +#define PORT_TYPE_USER "user" /// The maximum range between a port and an atom diff --git a/code/controllers/subsystem/circuit_component.dm b/code/controllers/subsystem/circuit_component.dm index 3ef1be5a3aa..bae302ed9d0 100644 --- a/code/controllers/subsystem/circuit_component.dm +++ b/code/controllers/subsystem/circuit_component.dm @@ -39,7 +39,7 @@ SUBSYSTEM_DEF(circuit_component) * Those that registered first will be executed first and those registered last will be executed last. */ /datum/controller/subsystem/circuit_component/proc/add_callback(datum/port/input, datum/callback/to_call) - if(instant_run_tick == world.time && (TICK_USAGE - instant_run_start_cpu_usage) < instant_run_max_cpu_usage) + if(instant_run_tick == world.time && (TICK_USAGE - instant_run_start_cpu_usage) <= instant_run_max_cpu_usage) instant_run_callbacks_to_run += to_call return @@ -80,7 +80,7 @@ SUBSYSTEM_DEF(circuit_component) else instant_run_tick = 0 - if((TICK_USAGE - instant_run_start_cpu_usage) < instant_run_max_cpu_usage) + if((TICK_USAGE - instant_run_start_cpu_usage) <= instant_run_max_cpu_usage) return received_inputs else return null diff --git a/code/modules/tgui_input/list.dm b/code/modules/tgui_input/list.dm index a58b96b06e3..18525e6b10a 100644 --- a/code/modules/tgui_input/list.dm +++ b/code/modules/tgui_input/list.dm @@ -29,6 +29,9 @@ if(!user.client.prefs.read_preference(/datum/preference/toggle/tgui_input)) return input(user, message, title, default) as null|anything in items var/datum/tgui_list_input/input = new(user, message, title, items, default, timeout, ui_state) + if(input.invalid) + qdel(input) + return input.ui_interact(user) input.wait() if (input) @@ -62,6 +65,8 @@ var/closed /// The TGUI UI state that will be returned in ui_state(). Default: always_state var/datum/ui_state/state + /// Whether the tgui list input is invalid or not (i.e. due to all list entries being null) + var/invalid = FALSE /datum/tgui_list_input/New(mob/user, message, title, list/items, default, timeout, ui_state) src.title = title @@ -81,6 +86,9 @@ string_key = avoid_assoc_duplicate_keys(string_key, repeat_items) src.items += string_key src.items_map[string_key] = i + + if(length(src.items) == 0) + invalid = TRUE if (timeout) src.timeout = timeout start_time = world.time diff --git a/code/modules/wiremod/components/list/assoc_list_pick.dm b/code/modules/wiremod/components/list/assoc_list_pick.dm index 9c8e94c074a..64dbe6a0a0b 100644 --- a/code/modules/wiremod/components/list/assoc_list_pick.dm +++ b/code/modules/wiremod/components/list/assoc_list_pick.dm @@ -15,7 +15,6 @@ /obj/item/circuit_component/list_pick/assoc/make_list_port() input_list = add_input_port("List", PORT_TYPE_ASSOC_LIST(PORT_TYPE_STRING, PORT_TYPE_ANY)) - /obj/item/circuit_component/list_pick/assoc/pre_input_received(datum/port/input/port) if(port == list_options) var/new_type = list_options.value diff --git a/code/modules/wiremod/components/list/assoc_literal.dm b/code/modules/wiremod/components/list/assoc_literal.dm index a3f97cae745..f829ad08f25 100644 --- a/code/modules/wiremod/components/list/assoc_literal.dm +++ b/code/modules/wiremod/components/list/assoc_literal.dm @@ -38,15 +38,6 @@ list_options = add_option_port("List Type", GLOB.wiremod_basic_types) /obj/item/circuit_component/assoc_literal/populate_ports() - AddComponent(/datum/component/circuit_component_add_port, \ - port_list = entry_ports, \ - add_action = "add", \ - remove_action = "remove", \ - port_type = PORT_TYPE_ANY, \ - prefix = "Index", \ - minimum_amount = 1, \ - maximum_amount = 20 \ - ) AddComponent(/datum/component/circuit_component_add_port, \ port_list = key_ports, \ add_action = "add", \ @@ -56,6 +47,15 @@ minimum_amount = 1, \ maximum_amount = 20 \ ) + AddComponent(/datum/component/circuit_component_add_port, \ + port_list = entry_ports, \ + add_action = "add", \ + remove_action = "remove", \ + port_type = PORT_TYPE_ANY, \ + prefix = "Value", \ + minimum_amount = 1, \ + maximum_amount = 20 \ + ) list_output = add_output_port("Value", PORT_TYPE_ASSOC_LIST(PORT_TYPE_STRING, PORT_TYPE_ANY), order = 1.1) /obj/item/circuit_component/assoc_literal/input_received(datum/port/input/port) diff --git a/code/modules/wiremod/components/list/list_pick.dm b/code/modules/wiremod/components/list/list_pick.dm index bce3e82688f..a1e8141f3c3 100644 --- a/code/modules/wiremod/components/list/list_pick.dm +++ b/code/modules/wiremod/components/list/list_pick.dm @@ -27,39 +27,24 @@ circuit_flags = CIRCUIT_FLAG_INPUT_SIGNAL - var/index_type = PORT_TYPE_NUMBER - -/obj/item/circuit_component/list_pick/populate_options() - list_options = add_option_port("List Type", GLOB.wiremod_basic_types) - /obj/item/circuit_component/list_pick/proc/make_list_port() - input_list = add_input_port("List", PORT_TYPE_LIST(PORT_TYPE_ANY)) + input_list = add_input_port("List", PORT_TYPE_LIST(PORT_TYPE_STRING)) /obj/item/circuit_component/list_pick/populate_ports() input_name = add_input_port("Input Name", PORT_TYPE_STRING) - user = add_input_port("User", PORT_TYPE_ATOM) + user = add_input_port("User", PORT_TYPE_USER) make_list_port() - output = add_output_port("Picked Item", PORT_TYPE_NUMBER) - trigger_output = add_output_port("Triggered", PORT_TYPE_SIGNAL) + output = add_output_port("Picked Item", PORT_TYPE_STRING) failure = add_output_port("On Failure", PORT_TYPE_SIGNAL) - success = add_output_port("On Succes", PORT_TYPE_SIGNAL) - - -/obj/item/circuit_component/list_pick/pre_input_received(datum/port/input/port) - if(port == list_options) - var/new_type = list_options.value - input_list.set_datatype(PORT_TYPE_LIST(new_type)) - output.set_datatype(new_type) - + success = add_output_port("On Success", PORT_TYPE_SIGNAL) /obj/item/circuit_component/list_pick/input_received(datum/port/input/port) - if(parent.Adjacent(user.value)) + var/mob/mob_user = user.value + if(!ismob(mob_user) || HAS_TRAIT_FROM(parent, TRAIT_CIRCUIT_UI_OPEN, REF(mob_user))) + failure.set_output(COMPONENT_SIGNAL) return - - if(ismob(user.value)) - trigger_output.set_output(COMPONENT_SIGNAL) - INVOKE_ASYNC(src, PROC_REF(show_list), user.value, input_name.value, input_list.value) + INVOKE_ASYNC(src, PROC_REF(show_list), mob_user, input_name.value, input_list.value) /// Show a list of options to the user using standed TGUI input list /obj/item/circuit_component/list_pick/proc/show_list(mob/user, message, list/showed_list) @@ -68,10 +53,17 @@ return if(!message) message = "circuit input" - if(!(user.can_perform_action(src, FORBID_TELEKINESIS_REACH))) + if(!(user.can_perform_action(parent.shell, FORBID_TELEKINESIS_REACH|ALLOW_SILICON_REACH|ALLOW_RESTING))) + failure.set_output(COMPONENT_SIGNAL) return + var/user_ref = REF(user) + ADD_TRAIT(parent, TRAIT_CIRCUIT_UI_OPEN, user_ref) var/picked = tgui_input_list(user, message = message, items = showed_list) - if(!(user.can_perform_action(src, FORBID_TELEKINESIS_REACH))) + REMOVE_TRAIT(parent, TRAIT_CIRCUIT_UI_OPEN, user_ref) + if(QDELETED(src)) + return + if(!(user.can_perform_action(parent.shell, FORBID_TELEKINESIS_REACH|ALLOW_SILICON_REACH|ALLOW_RESTING))) + failure.set_output(COMPONENT_SIGNAL) return choose_item(picked, showed_list) diff --git a/code/modules/wiremod/datatypes/datum.dm b/code/modules/wiremod/datatypes/datum.dm index f3faa8f5d8e..4045ee3793e 100644 --- a/code/modules/wiremod/datatypes/datum.dm +++ b/code/modules/wiremod/datatypes/datum.dm @@ -4,6 +4,7 @@ datatype_flags = DATATYPE_FLAG_ALLOW_MANUAL_INPUT|DATATYPE_FLAG_ALLOW_ATOM_INPUT can_receive_from = list( PORT_TYPE_ATOM, + PORT_TYPE_USER ) /datum/circuit_datatype/datum/convert_value(datum/port/port, value_to_convert) diff --git a/code/modules/wiremod/datatypes/entity.dm b/code/modules/wiremod/datatypes/entity.dm index e3a76892f97..437b3d7adb4 100644 --- a/code/modules/wiremod/datatypes/entity.dm +++ b/code/modules/wiremod/datatypes/entity.dm @@ -2,6 +2,9 @@ datatype = PORT_TYPE_ATOM color = "purple" datatype_flags = DATATYPE_FLAG_ALLOW_MANUAL_INPUT|DATATYPE_FLAG_ALLOW_ATOM_INPUT + can_receive_from = list( + PORT_TYPE_USER, + ) /datum/circuit_datatype/entity/convert_value(datum/port/port, value_to_convert) var/atom/object = value_to_convert diff --git a/code/modules/wiremod/datatypes/user.dm b/code/modules/wiremod/datatypes/user.dm new file mode 100644 index 00000000000..693941dcd74 --- /dev/null +++ b/code/modules/wiremod/datatypes/user.dm @@ -0,0 +1,9 @@ +/datum/circuit_datatype/user + datatype = PORT_TYPE_USER + color = "label" + +/datum/circuit_datatype/user/convert_value(datum/port/port, value_to_convert) + var/datum/object = value_to_convert + if(QDELETED(object)) + return null + return object diff --git a/code/modules/wiremod/shell/bot.dm b/code/modules/wiremod/shell/bot.dm index 36fd6c5b369..dfd9845bc05 100644 --- a/code/modules/wiremod/shell/bot.dm +++ b/code/modules/wiremod/shell/bot.dm @@ -31,7 +31,7 @@ var/datum/port/output/entity /obj/item/circuit_component/bot/populate_ports() - entity = add_output_port("User", PORT_TYPE_ATOM) + entity = add_output_port("User", PORT_TYPE_USER) signal = add_output_port("Signal", PORT_TYPE_SIGNAL) /obj/item/circuit_component/bot/register_shell(atom/movable/shell) @@ -46,4 +46,3 @@ playsound(source, get_sfx(SFX_TERMINAL_TYPE), 25, FALSE) entity.set_output(user) signal.set_output(COMPONENT_SIGNAL) - diff --git a/code/modules/wiremod/shell/brain_computer_interface.dm b/code/modules/wiremod/shell/brain_computer_interface.dm index 89aac209c83..c3ac3154d2d 100644 --- a/code/modules/wiremod/shell/brain_computer_interface.dm +++ b/code/modules/wiremod/shell/brain_computer_interface.dm @@ -114,7 +114,7 @@ send_message_signal = add_input_port("Send Message", PORT_TYPE_SIGNAL) show_charge_meter = add_input_port("Show Charge Meter", PORT_TYPE_NUMBER, trigger = PROC_REF(update_charge_action)) - user_port = add_output_port("User", PORT_TYPE_ATOM) + user_port = add_output_port("User", PORT_TYPE_USER) /obj/item/circuit_component/bci_core/Destroy() QDEL_NULL(charge_action) diff --git a/code/modules/wiremod/shell/controller.dm b/code/modules/wiremod/shell/controller.dm index 7040e554a0a..3092d3315f1 100644 --- a/code/modules/wiremod/shell/controller.dm +++ b/code/modules/wiremod/shell/controller.dm @@ -34,7 +34,7 @@ var/datum/port/output/entity /obj/item/circuit_component/controller/populate_ports() - entity = add_output_port("User", PORT_TYPE_ATOM) + entity = add_output_port("User", PORT_TYPE_USER) signal = add_output_port("Signal", PORT_TYPE_SIGNAL) alt = add_output_port("Alternate Signal", PORT_TYPE_SIGNAL) right = add_output_port("Extra Signal", PORT_TYPE_SIGNAL) @@ -51,6 +51,12 @@ COMSIG_CLICK_ALT, )) +/obj/item/circuit_component/controller/proc/handle_trigger(atom/source, user, port_name, datum/port/output/port_signal) + source.balloon_alert(user, "clicked [port_name] button") + playsound(source, get_sfx(SFX_TERMINAL_TYPE), 25, FALSE) + entity.set_output(user) + port_signal.set_output(COMPONENT_SIGNAL) + /** * Called when the shell item is used in hand */ @@ -58,10 +64,7 @@ SIGNAL_HANDLER if(!user.Adjacent(source)) return - source.balloon_alert(user, "clicked primary button") - playsound(source, get_sfx(SFX_TERMINAL_TYPE), 25, FALSE) - entity.set_output(user) - signal.set_output(COMPONENT_SIGNAL) + handle_trigger(source, user, "primary", signal) /** * Called when the shell item is alt-clicked @@ -70,10 +73,8 @@ SIGNAL_HANDLER if(!user.Adjacent(source)) return - source.balloon_alert(user, "clicked alternate button") - playsound(source, get_sfx(SFX_TERMINAL_TYPE), 25, FALSE) - entity.set_output(user) - alt.set_output(COMPONENT_SIGNAL) + handle_trigger(source, user, "alternate", alt) + /** * Called when the shell item is right-clicked in active hand @@ -82,7 +83,4 @@ SIGNAL_HANDLER if(!user.Adjacent(source)) return - source.balloon_alert(user, "clicked extra button") - playsound(source, get_sfx(SFX_TERMINAL_TYPE), 25, FALSE) - entity.set_output(user) - right.set_output(COMPONENT_SIGNAL) + handle_trigger(source, user, "extra", right) diff --git a/code/modules/wiremod/shell/keyboard.dm b/code/modules/wiremod/shell/keyboard.dm index 4231a6dc814..05b9ded074b 100644 --- a/code/modules/wiremod/shell/keyboard.dm +++ b/code/modules/wiremod/shell/keyboard.dm @@ -27,7 +27,7 @@ var/datum/port/output/output /obj/item/circuit_component/keyboard_shell/populate_ports() - entity = add_output_port("User", PORT_TYPE_ATOM) + entity = add_output_port("User", PORT_TYPE_USER) output = add_output_port("Message", PORT_TYPE_STRING) signal = add_output_port("Signal", PORT_TYPE_SIGNAL) @@ -53,4 +53,3 @@ output.set_output(message) signal.set_output(COMPONENT_SIGNAL) - diff --git a/code/modules/wiremod/shell/module.dm b/code/modules/wiremod/shell/module.dm index bffff02e5fb..4201c6afb17 100644 --- a/code/modules/wiremod/shell/module.dm +++ b/code/modules/wiremod/shell/module.dm @@ -123,7 +123,7 @@ toggle_suit = add_input_port("Toggle Suit", PORT_TYPE_SIGNAL) select_module = add_input_port("Select Module", PORT_TYPE_SIGNAL) // States - wearer = add_output_port("Wearer", PORT_TYPE_ATOM) + wearer = add_output_port("Wearer", PORT_TYPE_USER) deployed = add_output_port("Deployed", PORT_TYPE_NUMBER) activated = add_output_port("Activated", PORT_TYPE_NUMBER) selected_module = add_output_port("Selected Module", PORT_TYPE_STRING) diff --git a/code/modules/wiremod/shell/moneybot.dm b/code/modules/wiremod/shell/moneybot.dm index 46a834e2d60..20eb596eb72 100644 --- a/code/modules/wiremod/shell/moneybot.dm +++ b/code/modules/wiremod/shell/moneybot.dm @@ -95,7 +95,7 @@ /obj/item/circuit_component/money_bot/populate_ports() total_money = add_output_port("Total Money", PORT_TYPE_NUMBER) money_input = add_output_port("Last Input Money", PORT_TYPE_NUMBER) - entity = add_output_port("User", PORT_TYPE_ATOM) + entity = add_output_port("User", PORT_TYPE_USER) money_trigger = add_output_port("Money Input", PORT_TYPE_SIGNAL) /obj/item/circuit_component/money_bot/register_shell(atom/movable/shell) diff --git a/tgstation.dme b/tgstation.dme index bb2b7f4a3b0..e8b7d9ff89a 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -5879,6 +5879,7 @@ #include "code\modules\wiremod\datatypes\option.dm" #include "code\modules\wiremod\datatypes\signal.dm" #include "code\modules\wiremod\datatypes\string.dm" +#include "code\modules\wiremod\datatypes\user.dm" #include "code\modules\wiremod\datatypes\composite\assoc_list.dm" #include "code\modules\wiremod\datatypes\composite\composite.dm" #include "code\modules\wiremod\datatypes\composite\list.dm"