From a54009fd678153599d8dcf9fe7860b5195a454c6 Mon Sep 17 00:00:00 2001 From: Y0SH1M4S73R Date: Mon, 13 Jan 2025 11:16:12 -0500 Subject: [PATCH] Circuit Wirenet Components + Assembly Shell Tweaks (#88593) ## About The Pull Request Assembly shells now use power from whatever machine/borg/mech/modsuit they are attached to the wires of, instead of their own power cell, when appropriate. As for the meat of this PR, circuit wirenet components function like NTnet and NFC components, but their signals are transmitted across whatever cable network the shell (or in the case of assembly shells, the machine or button it's inserted into) is connected to. These components are available with roundstart tech. ## Why It's Good For The Game Provides a somewhat intuitive way to make circuit networks that aren't dependent on external factors to continue functioning. NTnet components require a functional NTnet relay, which usually means they need telecomms to be working. NFC components have a range limit, and you need to provide a specific reference to the circuit being communicated with. Wirenet components, on the other hand, just need the shell to be anchored (or for assembly circuits, the thing whose wire it is attached to), and for the shell to have a cable under it. Also might indirectly provide a reason to use cable layers other than the default one. ## Changelog :cl: add: Adds circuit wirenet components, allowing data to be transmitted and received over cable networks. qol: When attached to a machine, mech, modsuit, or borg, assembly circuit shells will use power from those instead of the circuit's own cell. /:cl: --- code/__DEFINES/dcs/signals/signals_circuit.dm | 3 + code/__DEFINES/dcs/signals/signals_object.dm | 24 +++ .../__DEFINES/dcs/signals/signals_powernet.dm | 4 + code/game/machinery/buttons.dm | 2 + code/modules/assembly/assembly.dm | 4 + code/modules/power/powernet.dm | 6 + .../research/designs/wiremod_designs.dm | 15 ++ .../research/techweb/nodes/circuit_nodes.dm | 3 + .../wiremod/components/wirenet/receive.dm | 76 +++++++ .../wiremod/components/wirenet/send.dm | 68 +++++++ .../components/wirenet/send_literal.dm | 54 +++++ .../wiremod/core/integrated_circuit.dm | 1 + .../component_wirenet_connection.dm | 188 ++++++++++++++++++ code/modules/wiremod/shell/assembly.dm | 50 ++++- tgstation.dme | 5 + 15 files changed, 502 insertions(+), 1 deletion(-) create mode 100644 code/__DEFINES/dcs/signals/signals_powernet.dm create mode 100644 code/modules/wiremod/components/wirenet/receive.dm create mode 100644 code/modules/wiremod/components/wirenet/send.dm create mode 100644 code/modules/wiremod/components/wirenet/send_literal.dm create mode 100644 code/modules/wiremod/dcs_components/component_wirenet_connection.dm diff --git a/code/__DEFINES/dcs/signals/signals_circuit.dm b/code/__DEFINES/dcs/signals/signals_circuit.dm index 08d5f675b28..14be995d6ce 100644 --- a/code/__DEFINES/dcs/signals/signals_circuit.dm +++ b/code/__DEFINES/dcs/signals/signals_circuit.dm @@ -22,6 +22,9 @@ /// Sent when a circuit is removed from its shell #define COMSIG_CIRCUIT_SHELL_REMOVED "circuit_shell_removed" +/// Send to [/obj/item/circuit_component] when it is added to a circuit. (/obj/item/integrated_circuit) +#define COMSIG_CIRCUIT_COMPONENT_ADDED "circuit_component_added" + /// Sent to [/obj/item/circuit_component] when it is removed from a circuit. (/obj/item/integrated_circuit) #define COMSIG_CIRCUIT_COMPONENT_REMOVED "circuit_component_removed" diff --git a/code/__DEFINES/dcs/signals/signals_object.dm b/code/__DEFINES/dcs/signals/signals_object.dm index 132adba02e0..2044aab51e2 100644 --- a/code/__DEFINES/dcs/signals/signals_object.dm +++ b/code/__DEFINES/dcs/signals/signals_object.dm @@ -550,3 +550,27 @@ #define COMSIG_WINGS_OPENED "wings_opened" /// Sent from /obj/item/organ/wings/functional/proc/close_wings(): (mob/living/carbon/owner) #define COMSIG_WINGS_CLOSED "wings_closed" + +/// Sent from /obj/item/assembly/on_attach(): (atom/holder) +#define COMSIG_ASSEMBLY_ATTACHED "assembly_attached" + +/// Sent from /obj/item/assembly/on_detach(): (atom/holder) +#define COMSIG_ASSEMBLY_DETACHED "assembly_detached" + +/* + * The following two signals are separate from the above two because buttons don't set the holder of the inserted assembly. + * This causes subtle behavioral differences that future handlers for these signals may need to account for, + * even if none of the currently implemented handlers do. + */ + +/// Sent from /obj/machinery/button/assembly_act(obj/machinery/button/button, mob/user) +#define COMSIG_ASSEMBLY_ADDED_TO_BUTTON "assembly_added_to_button" + +/// Sent from /obj/machinery/button/remove_assembly(obj/machinery/button/button, mob/user) +#define COMSIG_ASSEMBLY_REMOVED_FROM_BUTTON "assembly_removed_from_button" + +/// Sent from /datum/powernet/add_cable() +#define COMSIG_CABLE_ADDED_TO_POWERNET "cable_added_to_powernet" + +/// Sent from /datum/powernet/remove_cable() +#define COMSIG_CABLE_REMOVED_FROM_POWERNET "cable_removed_from_powernet" diff --git a/code/__DEFINES/dcs/signals/signals_powernet.dm b/code/__DEFINES/dcs/signals/signals_powernet.dm new file mode 100644 index 00000000000..1343e9e1d66 --- /dev/null +++ b/code/__DEFINES/dcs/signals/signals_powernet.dm @@ -0,0 +1,4 @@ +// Powernet signals + +/// Sent when a wirenet circuit component sends a signal (list/data) +#define COMSIG_POWERNET_CIRCUIT_TRANSMISSION "powernet_circuit_transmision" diff --git a/code/game/machinery/buttons.dm b/code/game/machinery/buttons.dm index 70d46576790..c8aba44ef47 100644 --- a/code/game/machinery/buttons.dm +++ b/code/game/machinery/buttons.dm @@ -145,6 +145,7 @@ return ITEM_INTERACT_BLOCKING device = new_device + SEND_SIGNAL(new_device, COMSIG_ASSEMBLY_ADDED_TO_BUTTON, src, user) to_chat(user, span_notice("You add \the [new_device] to the button.")) update_appearance() @@ -273,6 +274,7 @@ return ..() /obj/machinery/button/proc/remove_assembly(mob/user) + SEND_SIGNAL(device, COMSIG_ASSEMBLY_REMOVED_FROM_BUTTON, src, user) user.put_in_hands(device) to_chat(user, span_notice("You remove \the [device] from the button frame.")) device = null diff --git a/code/modules/assembly/assembly.dm b/code/modules/assembly/assembly.dm index add95cdd6db..dbd5a704614 100644 --- a/code/modules/assembly/assembly.dm +++ b/code/modules/assembly/assembly.dm @@ -40,18 +40,22 @@ * Will also be called if the assembly holder is attached to a plasma (internals) tank or welding fuel (dispenser) tank. */ /obj/item/assembly/proc/on_attach() + SHOULD_CALL_PARENT(TRUE) if(!holder && connected) holder = connected.holder + SEND_SIGNAL(src, COMSIG_ASSEMBLY_ATTACHED, holder) /** * on_detach: Called when removed from an assembly holder or wiring datum */ /obj/item/assembly/proc/on_detach() + SHOULD_CALL_PARENT(TRUE) if(connected) connected = null if(!holder) return FALSE forceMove(holder.drop_location()) + SEND_SIGNAL(src, COMSIG_ASSEMBLY_DETACHED, holder) holder = null return TRUE diff --git a/code/modules/power/powernet.dm b/code/modules/power/powernet.dm index 618812351f9..88aa3b7655f 100644 --- a/code/modules/power/powernet.dm +++ b/code/modules/power/powernet.dm @@ -35,6 +35,7 @@ //if the powernet is then empty, delete it //Warning : this proc DON'T check if the cable exists /datum/powernet/proc/remove_cable(obj/structure/cable/C) + SEND_SIGNAL(C, COMSIG_CABLE_REMOVED_FROM_POWERNET) cables -= C C.powernet = null if(is_empty())//the powernet is now empty... @@ -50,6 +51,7 @@ C.powernet.remove_cable(C) //..remove it C.powernet = src cables +=C + SEND_SIGNAL(C, COMSIG_CABLE_ADDED_TO_POWERNET) //remove a power machine from the current powernet //if the powernet is then empty, delete it @@ -90,3 +92,7 @@ /datum/powernet/proc/get_electrocute_damage() return ELECTROCUTE_DAMAGE(energy_to_power(avail)) // Assuming 1 second of contact. + +// Mostly just a wrapper for sending the COMSIG_POWERNET_CIRCUIT_TRANSMISSION signal, but could be retooled in the future to give it other uses +/datum/powernet/proc/data_transmission(list/data, encryption_key, datum/weakref/port) + SEND_SIGNAL(src, COMSIG_POWERNET_CIRCUIT_TRANSMISSION, list("data" = data, "enc_key" = encryption_key, "port" = port)) diff --git a/code/modules/research/designs/wiremod_designs.dm b/code/modules/research/designs/wiremod_designs.dm index 418dec186e9..f8732cc332b 100644 --- a/code/modules/research/designs/wiremod_designs.dm +++ b/code/modules/research/designs/wiremod_designs.dm @@ -477,6 +477,21 @@ id = "comp_assoc_list_pick" build_path = /obj/item/circuit_component/list_pick/assoc +/datum/design/component/wirenet_receive + name = "Wirenet Receiver Component" + id = "comp_wirenet_receive" + build_path = /obj/item/circuit_component/wirenet_receive + +/datum/design/component/wirenet_send + name = "Wirenet Transmitter Component" + id = "comp_wirenet_send" + build_path = /obj/item/circuit_component/wirenet_send + +/datum/design/component/wirenet_send_literal + name = "Wirenet List Literal Transmitter Component" + id = "comp_wirenet_send_literal" + build_path = /obj/item/circuit_component/list_literal/wirenet_send + /datum/design/component/bci/bci_camera name = "BCI Camera" id = "comp_camera_bci" diff --git a/code/modules/research/techweb/nodes/circuit_nodes.dm b/code/modules/research/techweb/nodes/circuit_nodes.dm index 554e9997c04..109873c3851 100644 --- a/code/modules/research/techweb/nodes/circuit_nodes.dm +++ b/code/modules/research/techweb/nodes/circuit_nodes.dm @@ -86,6 +86,9 @@ "comp_typecast", "comp_typecheck", "comp_view_sensor", + "comp_wirenet_receive", + "comp_wirenet_send", + "comp_wirenet_send_literal", ) /datum/techweb_node/circuit_shells diff --git a/code/modules/wiremod/components/wirenet/receive.dm b/code/modules/wiremod/components/wirenet/receive.dm new file mode 100644 index 00000000000..2533573c493 --- /dev/null +++ b/code/modules/wiremod/components/wirenet/receive.dm @@ -0,0 +1,76 @@ +/obj/item/circuit_component/wirenet_receive + display_name = "Wirenet Receiver" + desc = "Receives data packets through the connected cable network. If Encryption Key is set then only signals with the same Encryption Key will be received." + category = "Utility" + + circuit_flags = CIRCUIT_FLAG_OUTPUT_SIGNAL //trigger_output + + ui_buttons = list( + "1" = CABLE_LAYER_1_NAME, + "2" = CABLE_LAYER_2_NAME, + "3" = CABLE_LAYER_3_NAME, + ) + + var/cable_layer = /datum/component/circuit_component_wirenet_connection::cable_layer + + /// The list type + var/datum/port/input/option/list_options + + /// Data being received + var/datum/port/output/data_package + + /// Encryption key + var/datum/port/input/enc_key + +/obj/item/circuit_component/wirenet_receive/Initialize(mapload) + . = ..() + AddComponent(\ + /datum/component/circuit_component_wirenet_connection,\ + connection_callback = CALLBACK(src, PROC_REF(on_powernet_connection)),\ + disconnection_callback = CALLBACK(src, PROC_REF(on_powernet_disconnection)),\ + post_set_cable_layer_callback = CALLBACK(src, PROC_REF(on_set_cable_layer)),\ + ) + +/obj/item/circuit_component/wirenet_receive/proc/on_powernet_connection(datum/powernet/new_powernet) + RegisterSignal(new_powernet, COMSIG_POWERNET_CIRCUIT_TRANSMISSION, PROC_REF(on_circuit_transmission)) + +/obj/item/circuit_component/wirenet_receive/proc/on_powernet_disconnection(datum/powernet/old_powernet) + UnregisterSignal(old_powernet, COMSIG_POWERNET_CIRCUIT_TRANSMISSION) + +/obj/item/circuit_component/wirenet_receive/proc/on_set_cable_layer(new_layer) + cable_layer = new_layer + +/obj/item/circuit_component/wirenet_receive/get_ui_notices() + . = ..() + . += create_ui_notice("Set the cable layer to connect to with the \"1\", \"2\", and \"3\" buttons.", "green", "info") + . += create_ui_notice("Currently connected to: [GLOB.cable_layer_to_name["[cable_layer]"]]", "green", "info") + +/obj/item/circuit_component/wirenet_receive/populate_options() + list_options = add_option_port("List Type", GLOB.wiremod_basic_types) + +/obj/item/circuit_component/wirenet_receive/populate_ports() + data_package = add_output_port("Data Package", PORT_TYPE_LIST(PORT_TYPE_ANY)) + enc_key = add_input_port("Encryption Key", PORT_TYPE_STRING) + +/obj/item/circuit_component/wirenet_receive/pre_input_received(datum/port/input/port) + if(port == list_options) + var/new_datatype = list_options.value + data_package.set_datatype(PORT_TYPE_LIST(new_datatype)) + +/obj/item/circuit_component/wirenet_receive/proc/on_circuit_transmission(_source, list/data) + SIGNAL_HANDLER + + if(data["enc_key"] != enc_key.value) + return + + var/datum/weakref/ref = data["port"] + var/datum/port/input/port = ref?.resolve() + if(!port) + return + + var/datum/circuit_datatype/datatype_handler = data_package.datatype_handler + if(!datatype_handler?.can_receive_from_datatype(port.datatype)) + return + + data_package.set_output(data["data"]) + trigger_output.set_output(COMPONENT_SIGNAL) diff --git a/code/modules/wiremod/components/wirenet/send.dm b/code/modules/wiremod/components/wirenet/send.dm new file mode 100644 index 00000000000..8852b59da4d --- /dev/null +++ b/code/modules/wiremod/components/wirenet/send.dm @@ -0,0 +1,68 @@ +/obj/item/circuit_component/wirenet_send + display_name = "Wirenet Transmitter" + desc = "Sends a data package through the connected cable network. If Encryption Key is set then transmitted data will be only picked up by receivers with the same Encryption Key." + category = "Utility" + + circuit_flags = CIRCUIT_FLAG_INPUT_SIGNAL + + ui_buttons = list( + "1" = CABLE_LAYER_1_NAME, + "2" = CABLE_LAYER_2_NAME, + "3" = CABLE_LAYER_3_NAME, + ) + + var/cable_layer = /datum/component/circuit_component_wirenet_connection::cable_layer + + /// Powernet reference provided by the circuit_component_wirenet_connection component + var/datum/powernet/connected_powernet + + /// The list type + var/datum/port/input/option/list_options + + /// Data being sent + var/datum/port/input/data_package + + /// Encryption key + var/datum/port/input/enc_key + +/obj/item/circuit_component/wirenet_send/Initialize(mapload) + . = ..() + AddComponent(\ + /datum/component/circuit_component_wirenet_connection,\ + connection_callback = CALLBACK(src, PROC_REF(on_powernet_connection)),\ + disconnection_callback = CALLBACK(src, PROC_REF(on_powernet_disconnection)),\ + post_set_cable_layer_callback = CALLBACK(src, PROC_REF(on_set_cable_layer)),\ + ) + +/obj/item/circuit_component/wirenet_send/Destroy() + . = ..() + connected_powernet = null + +/obj/item/circuit_component/wirenet_send/proc/on_powernet_connection(datum/powernet/new_powernet) + connected_powernet = new_powernet + +/obj/item/circuit_component/wirenet_send/proc/on_powernet_disconnection(datum/powernet/old_powernet) + connected_powernet = null + +/obj/item/circuit_component/wirenet_send/proc/on_set_cable_layer(new_layer) + cable_layer = new_layer + +/obj/item/circuit_component/wirenet_send/get_ui_notices() + . = ..() + . += create_ui_notice("Set the cable layer to connect to with the \"1\", \"2\", and \"3\" buttons.", "green", "info") + . += create_ui_notice("Currently connected to: [GLOB.cable_layer_to_name["[cable_layer]"]]", "green", "info") + +/obj/item/circuit_component/wirenet_send/populate_options() + list_options = add_option_port("List Type", GLOB.wiremod_basic_types) + +/obj/item/circuit_component/wirenet_send/populate_ports() + data_package = add_input_port("Data Package", PORT_TYPE_LIST(PORT_TYPE_ANY)) + enc_key = add_input_port("Encryption Key", PORT_TYPE_STRING) + +/obj/item/circuit_component/wirenet_send/pre_input_received(datum/port/input/port) + if(port == list_options) + var/new_datatype = list_options.value + data_package.set_datatype(PORT_TYPE_LIST(new_datatype)) + +/obj/item/circuit_component/wirenet_send/input_received(datum/port/input/port) + connected_powernet?.data_transmission(data_package.value, enc_key.value, WEAKREF(data_package)) diff --git a/code/modules/wiremod/components/wirenet/send_literal.dm b/code/modules/wiremod/components/wirenet/send_literal.dm new file mode 100644 index 00000000000..7d46152d5d9 --- /dev/null +++ b/code/modules/wiremod/components/wirenet/send_literal.dm @@ -0,0 +1,54 @@ +/obj/item/circuit_component/list_literal/wirenet_send + display_name = "Wirenet Transmitter List Literal" + desc = "Creates a list literal data package and sends it through the connected cable network. If Encryption Key is set then transmitted data will be only picked up by receivers with the same Encryption Key." + category = "Utility" + + ui_buttons = list( + "1" = CABLE_LAYER_1_NAME, + "2" = CABLE_LAYER_2_NAME, + "3" = CABLE_LAYER_3_NAME, + "plus" = "add", + "minus" = "remove", + ) + + var/cable_layer = /datum/component/circuit_component_wirenet_connection::cable_layer + + /// Powernet reference provided by the circuit_component_wirenet_connection component + var/datum/powernet/connected_powernet + + /// Encryption key + var/datum/port/input/enc_key + +/obj/item/circuit_component/list_literal/wirenet_send/Initialize(mapload) + . = ..() + AddComponent(\ + /datum/component/circuit_component_wirenet_connection,\ + connection_callback = CALLBACK(src, PROC_REF(on_powernet_connection)),\ + disconnection_callback = CALLBACK(src, PROC_REF(on_powernet_disconnection)),\ + post_set_cable_layer_callback = CALLBACK(src, PROC_REF(on_set_cable_layer)),\ + ) + +/obj/item/circuit_component/list_literal/wirenet_send/Destroy() + . = ..() + connected_powernet = null + +/obj/item/circuit_component/list_literal/wirenet_send/proc/on_powernet_connection(datum/powernet/new_powernet) + connected_powernet = new_powernet + +/obj/item/circuit_component/list_literal/wirenet_send/proc/on_powernet_disconnection(datum/powernet/old_powernet) + connected_powernet = null + +/obj/item/circuit_component/list_literal/wirenet_send/proc/on_set_cable_layer(new_layer) + cable_layer = new_layer + +/obj/item/circuit_component/list_literal/wirenet_send/get_ui_notices() + . = ..() + . += create_ui_notice("Set the cable layer to connect to with the \"1\", \"2\", and \"3\" buttons.", "green", "info") + . += create_ui_notice("Currently connected to: [GLOB.cable_layer_to_name["[cable_layer]"]]", "green", "info") + +/obj/item/circuit_component/list_literal/wirenet_send/populate_ports() + . = ..() + enc_key = add_input_port("Encryption Key", PORT_TYPE_STRING) + +/obj/item/circuit_component/list_literal/wirenet_send/input_received(datum/port/input/port) + connected_powernet?.data_transmission(list_output.value, enc_key.value, WEAKREF(list_output)) diff --git a/code/modules/wiremod/core/integrated_circuit.dm b/code/modules/wiremod/core/integrated_circuit.dm index f3d52653baf..1023a59eb21 100644 --- a/code/modules/wiremod/core/integrated_circuit.dm +++ b/code/modules/wiremod/core/integrated_circuit.dm @@ -276,6 +276,7 @@ GLOBAL_LIST_EMPTY_TYPED(integrated_circuits, /obj/item/integrated_circuit) to_add.rel_x = rand(COMPONENT_MIN_RANDOM_POS, COMPONENT_MAX_RANDOM_POS) - screen_x to_add.rel_y = rand(COMPONENT_MIN_RANDOM_POS, COMPONENT_MAX_RANDOM_POS) - screen_y + SEND_SIGNAL(to_add, COMSIG_CIRCUIT_COMPONENT_ADDED, src) to_add.parent = src attached_components += to_add current_size += to_add.circuit_size diff --git a/code/modules/wiremod/dcs_components/component_wirenet_connection.dm b/code/modules/wiremod/dcs_components/component_wirenet_connection.dm new file mode 100644 index 00000000000..81c7d304ecd --- /dev/null +++ b/code/modules/wiremod/dcs_components/component_wirenet_connection.dm @@ -0,0 +1,188 @@ +/datum/component/circuit_component_wirenet_connection + var/cable_layer = CABLE_LAYER_2 + + var/atom/movable/tracked_shell + + var/atom/movable/tracked_movable + var/obj/structure/cable/tracked_node + var/datum/powernet/tracked_powernet + + var/static/list/turf_connections = list(COMSIG_ATOM_AFTER_SUCCESSFUL_INITIALIZED_ON = PROC_REF(on_atom_initialized_on_turf)) + + /// What action sets the component to link to cable layer 1 + var/layer_1_action + + /// What action sets the component to link to cable layer 2 + var/layer_2_action + + /// What action sets the component to link to cable layer 3 + var/layer_3_action + + /// Callback to invoke when the component is connected to a powernet + var/datum/callback/connection_callback + + /// Callback to invoke when the component is disconnected from a powernet + var/datum/callback/disconnection_callback + + /// Callback to invoke after setting the cable layer to link to + var/datum/callback/post_set_cable_layer_callback + +/datum/component/circuit_component_wirenet_connection/Initialize(layer_1_action = CABLE_LAYER_1_NAME, layer_2_action = CABLE_LAYER_2_NAME, layer_3_action = CABLE_LAYER_3_NAME, datum/callback/connection_callback, datum/callback/disconnection_callback, datum/callback/post_set_cable_layer_callback) + . = ..() + if(!istype(parent, /obj/item/circuit_component)) + return COMPONENT_INCOMPATIBLE + src.layer_1_action = layer_1_action + src.layer_2_action = layer_2_action + src.layer_3_action = layer_3_action + src.connection_callback = connection_callback + src.disconnection_callback = disconnection_callback + src.post_set_cable_layer_callback = post_set_cable_layer_callback + +/datum/component/circuit_component_wirenet_connection/Destroy(force) + . = ..() + connection_callback = null + disconnection_callback = null + post_set_cable_layer_callback = null + +/datum/component/circuit_component_wirenet_connection/RegisterWithParent() + RegisterSignal(parent, COMSIG_CIRCUIT_COMPONENT_PERFORM_ACTION, PROC_REF(on_action)) + RegisterSignal(parent, COMSIG_CIRCUIT_COMPONENT_ADDED, PROC_REF(on_parent_added_to_circuit)) + RegisterSignal(parent, COMSIG_CIRCUIT_COMPONENT_REMOVED, PROC_REF(on_parent_removed_from_circuit)) + +/datum/component/circuit_component_wirenet_connection/UnregisterFromParent() + unset_shell() + UnregisterSignal(parent, list(COMSIG_CIRCUIT_COMPONENT_PERFORM_ACTION, COMSIG_CIRCUIT_COMPONENT_ADDED, COMSIG_CIRCUIT_COMPONENT_REMOVED)) + +/datum/component/circuit_component_wirenet_connection/proc/on_parent_added_to_circuit(_source, obj/item/integrated_circuit/circuit) + SIGNAL_HANDLER + RegisterSignal(circuit, COMSIG_CIRCUIT_SET_SHELL, PROC_REF(on_circuit_set_shell)) + RegisterSignal(circuit, COMSIG_CIRCUIT_SHELL_REMOVED, PROC_REF(unset_shell)) + if(circuit.shell) + set_shell(circuit.shell) + +/datum/component/circuit_component_wirenet_connection/proc/on_parent_removed_from_circuit(_source, obj/item/integrated_circuit/circuit) + SIGNAL_HANDLER + unset_shell() + UnregisterSignal(circuit, list(COMSIG_CIRCUIT_SET_SHELL, COMSIG_CIRCUIT_SHELL_REMOVED)) + +/datum/component/circuit_component_wirenet_connection/proc/on_circuit_set_shell(_source, atom/movable/shell) + SIGNAL_HANDLER + set_shell(shell) + +/datum/component/circuit_component_wirenet_connection/proc/set_shell(atom/movable/new_shell) + tracked_shell = new_shell + if(isassembly(new_shell)) + RegisterSignals(new_shell, list(COMSIG_ASSEMBLY_ATTACHED, COMSIG_ASSEMBLY_ADDED_TO_BUTTON), PROC_REF(on_assembly_shell_attached)) + RegisterSignals(new_shell, list(COMSIG_ASSEMBLY_DETACHED, COMSIG_ASSEMBLY_REMOVED_FROM_BUTTON), PROC_REF(on_assembly_shell_detached)) + else + set_tracked_movable(new_shell) + +/datum/component/circuit_component_wirenet_connection/proc/unset_shell() + SIGNAL_HANDLER + unset_tracked_movable() + if(!tracked_shell) + return + if(isassembly(tracked_shell)) + UnregisterSignal(tracked_shell, list(COMSIG_ASSEMBLY_ATTACHED, COMSIG_ASSEMBLY_DETACHED, COMSIG_ASSEMBLY_ADDED_TO_BUTTON, COMSIG_ASSEMBLY_REMOVED_FROM_BUTTON)) + tracked_shell = null + +/datum/component/circuit_component_wirenet_connection/proc/on_assembly_shell_attached(_source, atom/holder) + SIGNAL_HANDLER + if(ismovable(holder)) + set_tracked_movable(holder) + +/datum/component/circuit_component_wirenet_connection/proc/on_assembly_shell_detached() + SIGNAL_HANDLER + unset_tracked_movable() + +/datum/component/circuit_component_wirenet_connection/proc/set_tracked_movable(atom/movable/new_tracked_movable) + if(tracked_movable == new_tracked_movable) //Should only happen when an assembly holder the assembly was attached to calls on_attach when it itself is attached to something + return + tracked_movable = new_tracked_movable + RegisterSignal(new_tracked_movable, COMSIG_MOVABLE_SET_ANCHORED, PROC_REF(on_tracked_movable_set_anchored)) + RegisterSignal(new_tracked_movable, COMSIG_QDELETING, PROC_REF(unset_tracked_movable)) + if(tracked_movable.anchored) + try_set_tracked_node() + +/datum/component/circuit_component_wirenet_connection/proc/unset_tracked_movable() + SIGNAL_HANDLER + unset_tracked_node() + if(!tracked_movable) + return + UnregisterSignal(tracked_movable, list(COMSIG_MOVABLE_SET_ANCHORED, COMSIG_QDELETING)) + tracked_movable = null + +/datum/component/circuit_component_wirenet_connection/proc/on_tracked_movable_set_anchored(atom/movable/source, now_anchored) + SIGNAL_HANDLER + if(now_anchored) + try_set_tracked_node() + else + unset_tracked_node() + +/datum/component/circuit_component_wirenet_connection/proc/try_set_tracked_node() + SIGNAL_HANDLER + if(tracked_node) + unset_tracked_node() + var/turf/our_turf = get_turf(tracked_movable) + var/obj/structure/cable/node = our_turf.get_cable_node(cable_layer) + if(!node) + AddElement(/datum/element/connect_loc, turf_connections) + return + set_tracked_node(node) + +/datum/component/circuit_component_wirenet_connection/proc/on_atom_initialized_on_turf(_source, obj/structure/cable/initialized) + SIGNAL_HANDLER + if(!istype(initialized)) + return + if(!(initialized.cable_layer & cable_layer)) + return + set_tracked_node(initialized) + +/datum/component/circuit_component_wirenet_connection/proc/set_tracked_node(obj/structure/cable/node) + tracked_node = node + RemoveElement(/datum/element/connect_loc, turf_connections) + RegisterSignal(tracked_movable, COMSIG_MOVABLE_MOVED, PROC_REF(unset_tracked_node)) //Because of wack cases of something pushing an anchored object + RegisterSignal(node, COMSIG_CABLE_ADDED_TO_POWERNET, PROC_REF(set_tracked_powernet)) + RegisterSignal(node, COMSIG_CABLE_REMOVED_FROM_POWERNET, PROC_REF(unset_tracked_powernet)) + RegisterSignal(node, COMSIG_QDELETING, PROC_REF(unset_tracked_node)) + if(node.powernet) + set_tracked_powernet(node.powernet) + +/datum/component/circuit_component_wirenet_connection/proc/unset_tracked_node() + SIGNAL_HANDLER + unset_tracked_powernet() + if(!tracked_node) + return + UnregisterSignal(tracked_movable, COMSIG_MOVABLE_MOVED) + UnregisterSignal(tracked_node, list(COMSIG_CABLE_ADDED_TO_POWERNET, COMSIG_CABLE_REMOVED_FROM_POWERNET, COMSIG_QDELETING)) + tracked_node = null + +/datum/component/circuit_component_wirenet_connection/proc/set_tracked_powernet(datum/powernet/source) + SIGNAL_HANDLER + tracked_powernet = source + connection_callback?.Invoke(source) + +/datum/component/circuit_component_wirenet_connection/proc/unset_tracked_powernet() + SIGNAL_HANDLER + if(!tracked_powernet) + return + disconnection_callback?.Invoke(tracked_powernet) + tracked_powernet = null + +/datum/component/circuit_component_wirenet_connection/proc/on_action(obj/item/circuit_component/component, mob/user, action) + SIGNAL_HANDLER + switch(action) + if(CABLE_LAYER_1_NAME) + set_cable_layer(CABLE_LAYER_1) + if(CABLE_LAYER_2_NAME) + set_cable_layer(CABLE_LAYER_2) + if(CABLE_LAYER_3_NAME) + set_cable_layer(CABLE_LAYER_3) + +/datum/component/circuit_component_wirenet_connection/proc/set_cable_layer(new_layer) + if(cable_layer == new_layer) + return + cable_layer = new_layer + post_set_cable_layer_callback?.Invoke(new_layer) + if(tracked_movable?.anchored) + try_set_tracked_node() diff --git a/code/modules/wiremod/shell/assembly.dm b/code/modules/wiremod/shell/assembly.dm index ea278fb4a64..3e69331c4c8 100644 --- a/code/modules/wiremod/shell/assembly.dm +++ b/code/modules/wiremod/shell/assembly.dm @@ -9,12 +9,60 @@ icon_state = "wiremod" attachable = TRUE + /// A reference to any holder to use power from instead of the circuit's own cell + var/atom/movable/power_use_proxy + + /// Valid types for `power_use_proxy` to be + var/static/list/power_use_override_types = list(/obj/machinery, /obj/vehicle/sealed/mecha, /obj/item/mod/control, /mob/living/silicon/robot) + /obj/item/assembly/wiremod/Initialize(mapload) . = ..() - AddComponent(/datum/component/shell, list( + var/datum/component/shell/shell = AddComponent(/datum/component/shell, list( new /obj/item/circuit_component/assembly_input(), new /obj/item/circuit_component/assembly_output(), ), SHELL_CAPACITY_SMALL) + RegisterSignal(shell, COMSIG_SHELL_CIRCUIT_ATTACHED, PROC_REF(on_circuit_attached)) + RegisterSignal(shell, COMSIG_SHELL_CIRCUIT_REMOVED, PROC_REF(on_circuit_removed)) + RegisterSignals(src, list(COMSIG_ASSEMBLY_ATTACHED, COMSIG_ASSEMBLY_ADDED_TO_BUTTON), PROC_REF(on_attached)) + RegisterSignals(src, list(COMSIG_ASSEMBLY_DETACHED, COMSIG_ASSEMBLY_REMOVED_FROM_BUTTON), PROC_REF(on_detached)) + +/obj/item/assembly/wiremod/proc/on_circuit_attached(_source, obj/item/integrated_circuit/circuit) + SIGNAL_HANDLER + RegisterSignal(circuit, COMSIG_CIRCUIT_PRE_POWER_USAGE, PROC_REF(override_circuit_power_usage)) + +/obj/item/assembly/wiremod/proc/on_circuit_removed(datum/component/shell/source) + SIGNAL_HANDLER + UnregisterSignal(source.attached_circuit, COMSIG_CIRCUIT_PRE_POWER_USAGE) + +/obj/item/assembly/wiremod/proc/on_attached(_source, atom/movable/holder) + SIGNAL_HANDLER + if(is_type_in_list(holder, power_use_override_types)) + power_use_proxy = holder + +/obj/item/assembly/wiremod/proc/on_detached(_source) + SIGNAL_HANDLER + power_use_proxy = null + +/obj/item/assembly/wiremod/proc/override_circuit_power_usage(obj/item/integrated_circuit/source, power_to_use) + SIGNAL_HANDLER + if(ismachinery(power_use_proxy)) + var/obj/machinery/machine = power_use_proxy + if(!(machine.is_operational && machine.anchored)) + return + if(machine.use_energy(power_to_use, AREA_USAGE_EQUIP)) + return COMPONENT_OVERRIDE_POWER_USAGE + if(ismecha(power_use_proxy)) + var/obj/vehicle/sealed/mecha/mech = power_use_proxy + if(mech.use_energy(power_to_use)) + return COMPONENT_OVERRIDE_POWER_USAGE + if(istype(power_use_proxy, /obj/item/mod/control)) + var/obj/item/mod/control/modsuit = power_use_proxy + if(modsuit.subtract_charge(power_to_use)) + return COMPONENT_OVERRIDE_POWER_USAGE + if(iscyborg(power_use_proxy)) + var/mob/living/silicon/robot/borg = power_use_proxy + if(borg.cell?.use(power_to_use, force = TRUE)) + return COMPONENT_OVERRIDE_POWER_USAGE /obj/item/assembly/wiremod/examine(mob/user) . = ..() diff --git a/tgstation.dme b/tgstation.dme index 896fa2f3818..979ceb8a1a7 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -348,6 +348,7 @@ #include "code\__DEFINES\dcs\signals\signals_operatives.dm" #include "code\__DEFINES\dcs\signals\signals_painting.dm" #include "code\__DEFINES\dcs\signals\signals_plane_master_group.dm" +#include "code\__DEFINES\dcs\signals\signals_powernet.dm" #include "code\__DEFINES\dcs\signals\signals_proxmonitor.dm" #include "code\__DEFINES\dcs\signals\signals_radiation.dm" #include "code\__DEFINES\dcs\signals\signals_reagent.dm" @@ -6466,6 +6467,9 @@ #include "code\modules\wiremod\components\utility\typecheck.dm" #include "code\modules\wiremod\components\variables\getter.dm" #include "code\modules\wiremod\components\variables\setter.dm" +#include "code\modules\wiremod\components\wirenet\receive.dm" +#include "code\modules\wiremod\components\wirenet\send.dm" +#include "code\modules\wiremod\components\wirenet\send_literal.dm" #include "code\modules\wiremod\core\admin_panel.dm" #include "code\modules\wiremod\core\assets.dm" #include "code\modules\wiremod\core\component.dm" @@ -6490,6 +6494,7 @@ #include "code\modules\wiremod\datatypes\composite\composite.dm" #include "code\modules\wiremod\datatypes\composite\list.dm" #include "code\modules\wiremod\dcs_components\component_add_port.dm" +#include "code\modules\wiremod\dcs_components\component_wirenet_connection.dm" #include "code\modules\wiremod\preset\hello_world.dm" #include "code\modules\wiremod\preset\speech_relay.dm" #include "code\modules\wiremod\shell\airlock.dm"