From d5e6af13504b0adbd81a1fa49c81a2f8f0943181 Mon Sep 17 00:00:00 2001 From: Aura Dusklight <46622484+NovaDusklight@users.noreply.github.com> Date: Fri, 25 Jul 2025 15:29:11 +0200 Subject: [PATCH] Circuity improvements and minor additions (#18046) * Implement circuitry bug assembly * Add distant ref grabbing support to circuits * Set circuitry clothing wearer var for some functionality * Add silent, built-in speaker to circuitry ear piece. * Communicator support and reference grabber circuit * Add toggler circuit to easily toggle functionality * Allow reagent using circuits to use reagent storage. * update .dme --- code/controllers/subsystems/circuits.dm | 3 +- .../integrated_electronics/core/assemblies.dm | 9 ++- .../core/assemblies/circuit_bug.dm | 16 ++++++ .../core/assemblies/clothing.dm | 56 +++++++++++++++++++ .../subtypes/built_in.dm | 21 +++++++ .../integrated_electronics/subtypes/input.dm | 46 ++++++++++++++- .../integrated_electronics/subtypes/logic.dm | 27 +++++++++ .../subtypes/reagents.dm | 42 ++++++++++++-- .../research/designs/circuit_assembly.dm | 9 +++ vorestation.dme | 1 + 10 files changed, 218 insertions(+), 12 deletions(-) create mode 100644 code/modules/integrated_electronics/core/assemblies/circuit_bug.dm diff --git a/code/controllers/subsystems/circuits.dm b/code/controllers/subsystems/circuits.dm index 2e555b293d1..777b74f4d7f 100644 --- a/code/controllers/subsystems/circuits.dm +++ b/code/controllers/subsystems/circuits.dm @@ -84,7 +84,8 @@ SUBSYSTEM_DEF(circuit) /obj/item/clothing/shoes/circuitry, /obj/item/clothing/head/circuitry, /obj/item/clothing/ears/circuitry, - /obj/item/clothing/suit/circuitry + /obj/item/clothing/suit/circuitry, + /obj/item/electronic_assembly/circuit_bug ) circuit_fabricator_recipe_list["Tools"] = list( diff --git a/code/modules/integrated_electronics/core/assemblies.dm b/code/modules/integrated_electronics/core/assemblies.dm index b6766f602b8..108831a926c 100644 --- a/code/modules/integrated_electronics/core/assemblies.dm +++ b/code/modules/integrated_electronics/core/assemblies.dm @@ -264,16 +264,19 @@ IC.assembly = src /obj/item/electronic_assembly/afterattack(atom/target, mob/user, proximity) + var/scanned = FALSE if(proximity) - var/scanned = FALSE + // Existing sensor support for(var/obj/item/integrated_circuit/input/sensor/S in contents) -// S.set_pin_data(IC_OUTPUT, 1, WEAKREF(target)) -// S.check_then_do_work() if(S.scan(target)) scanned = TRUE if(scanned) visible_message(span_infoplain(span_bold("\The [user]") + " waves \the [src] around [target].")) + // Support for reference grabber + future ranged circuitry. + for(var/obj/item/integrated_circuit/input/reference_grabber/G in contents) + G.afterattack(target, user, proximity, null) + /obj/item/electronic_assembly/attackby(var/obj/item/I, var/mob/user) if(can_anchor && I.has_tool_quality(TOOL_WRENCH)) anchored = !anchored diff --git a/code/modules/integrated_electronics/core/assemblies/circuit_bug.dm b/code/modules/integrated_electronics/core/assemblies/circuit_bug.dm new file mode 100644 index 00000000000..b33cac9dd39 --- /dev/null +++ b/code/modules/integrated_electronics/core/assemblies/circuit_bug.dm @@ -0,0 +1,16 @@ +/obj/item/electronic_assembly/circuit_bug // A nerfed, circuitry version of the spy bug. + name = "electronic bug" + desc = "A tiny circuit assembly that looks perfect for hiding." + icon = 'icons/obj/integrated_electronics/electronic_setups.dmi' + icon_state = "setup_device_cylinder" + layer = TURF_LAYER+0.2 // Appears under many things, but with alt+click, unlike spy bug. + w_class = ITEMSIZE_TINY + slot_flags = SLOT_EARS + max_components = IC_COMPONENTS_BASE + max_complexity = 20 // Incredibly low complexity to prevent shenanigans. + origin_tech = list(TECH_DATA = 1, TECH_ENGINEERING = 1) + +/obj/item/electronic_assembly/circuit_bug/examine(mob/user) + . = ..() + if(get_dist(user, src) == 0) + . += "It looks like it could be hidden easily..." diff --git a/code/modules/integrated_electronics/core/assemblies/clothing.dm b/code/modules/integrated_electronics/core/assemblies/clothing.dm index ca202a9ff4f..58ef7b23bb5 100644 --- a/code/modules/integrated_electronics/core/assemblies/clothing.dm +++ b/code/modules/integrated_electronics/core/assemblies/clothing.dm @@ -100,6 +100,13 @@ setup_integrated_circuit(/obj/item/electronic_assembly/clothing) return ..() +/obj/item/clothing/under/circuitry/equipped(mob/user, slot) // Set wearer var when equiped. + wearer = WEAKREF(user) + ..() + +/obj/item/clothing/under/circuitry/dropped(mob/user) // Remove wearer var. + wearer = null + ..() // Gloves. /obj/item/clothing/gloves/circuitry @@ -114,6 +121,13 @@ setup_integrated_circuit(/obj/item/electronic_assembly/clothing/small) return ..() +/obj/item/clothing/gloves/circuitry/equipped(mob/user, slot) + wearer = WEAKREF(user) + ..() + +/obj/item/clothing/gloves/circuitry/dropped(mob/user) + wearer = null + ..() // Glasses. /obj/item/clothing/glasses/circuitry @@ -128,6 +142,14 @@ setup_integrated_circuit(/obj/item/electronic_assembly/clothing/small) return ..() +/obj/item/clothing/glasses/circuitry/equipped(mob/user, slot) + wearer = WEAKREF(user) + ..() + +/obj/item/clothing/glasses/circuitry/dropped(mob/user) + wearer = null + ..() + // Shoes /obj/item/clothing/shoes/circuitry name = "electronic boots" @@ -141,6 +163,14 @@ setup_integrated_circuit(/obj/item/electronic_assembly/clothing/small) return ..() +/obj/item/clothing/shoes/circuitry/equipped(mob/user, slot) + wearer = WEAKREF(user) + ..() + +/obj/item/clothing/shoes/circuitry/dropped(mob/user) + wearer = null + ..() + // Head /obj/item/clothing/head/circuitry name = "electronic headwear" @@ -154,6 +184,14 @@ setup_integrated_circuit(/obj/item/electronic_assembly/clothing/small) return ..() +/obj/item/clothing/head/circuitry/equipped(mob/user, slot) + wearer = WEAKREF(user) + ..() + +/obj/item/clothing/head/circuitry/dropped(mob/user) + wearer = null + ..() + // Ear /obj/item/clothing/ears/circuitry name = "electronic earwear" @@ -165,8 +203,18 @@ /obj/item/clothing/ears/circuitry/Initialize(mapload) setup_integrated_circuit(/obj/item/electronic_assembly/clothing/small) + var/obj/item/integrated_circuit/built_in/earpiece_speaker/built_in_speaker = new(IC) + IC.force_add_circuit(built_in_speaker) return ..() +/obj/item/clothing/ears/circuitry/equipped(mob/user, slot) + wearer = WEAKREF(user) + ..() + +/obj/item/clothing/ears/circuitry/dropped(mob/user) + wearer = null + ..() + // Exo-slot /obj/item/clothing/suit/circuitry name = "electronic chestpiece" @@ -179,3 +227,11 @@ /obj/item/clothing/suit/circuitry/Initialize(mapload) setup_integrated_circuit(/obj/item/electronic_assembly/clothing/large) return ..() + +/obj/item/clothing/suit/circuitry/equipped(mob/user, slot) + wearer = WEAKREF(user) + ..() + +/obj/item/clothing/suit/circuitry/dropped(mob/user) + wearer = null + ..() diff --git a/code/modules/integrated_electronics/subtypes/built_in.dm b/code/modules/integrated_electronics/subtypes/built_in.dm index 8bfdda0d36e..e945dd56648 100644 --- a/code/modules/integrated_electronics/subtypes/built_in.dm +++ b/code/modules/integrated_electronics/subtypes/built_in.dm @@ -37,3 +37,24 @@ /obj/item/integrated_circuit/built_in/action_button/do_work() activate_pin(1) + +/obj/item/integrated_circuit/built_in/earpiece_speaker + name = "earpiece speaker" + desc = "This small speaker can be used to output sound to a person wearing an earpiece." + extended_desc = "This speaker can only be heard by the one wearing the earpiece." + inputs = list("displayed data" = IC_PINTYPE_STRING) + activators = list("load data" = IC_PINTYPE_PULSE_IN) + var/speaker_output = null + +/obj/item/integrated_circuit/built_in/earpiece_speaker/disconnect_all() + ..() + speaker_output = null + +/obj/item/integrated_circuit/built_in/earpiece_speaker/do_work() + var/datum/integrated_io/I = inputs[1] + speaker_output = I.data + + var/obj/item/clothing/ears/circuitry/ep = assembly.loc + var/mob/wearer = ep.wearer?.resolve() + if(wearer && ismob(wearer)) // Only allow the wearer to hear the earpiece exclusive speaker + to_chat(wearer, span_notice("[icon2html(ep, wearer.client)] [speaker_output]")) diff --git a/code/modules/integrated_electronics/subtypes/input.dm b/code/modules/integrated_electronics/subtypes/input.dm index e6142e99751..f144a05cb9a 100644 --- a/code/modules/integrated_electronics/subtypes/input.dm +++ b/code/modules/integrated_electronics/subtypes/input.dm @@ -6,6 +6,39 @@ /obj/item/integrated_circuit/input/proc/ask_for_input(mob/user) return +/obj/item/integrated_circuit/input/reference_grabber // Allows grabbing non-adjacet refs, and their coords. (relative) + name = "reference grabber" + desc = "A handheld mechanism that can be aimed to attain distant references." + extended_desc = "When used, it will capture the reference of the target, and output coordinates relative to the user." + icon_state = "video_camera" + complexity = 4 + inputs = list() + outputs = list( + "clicked ref" = IC_PINTYPE_REF, + "X" = IC_PINTYPE_NUMBER, + "Y" = IC_PINTYPE_NUMBER + ) + activators = list( + "on success" = IC_PINTYPE_PULSE_OUT, + "on failure" = IC_PINTYPE_PULSE_OUT + ) + spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + +/obj/item/integrated_circuit/input/reference_grabber/afterattack(atom/target, mob/user, proximity_flag, click_parameters) + if(!assembly || user.get_active_hand() != assembly) + activate_pin(2) // Failure pin, not in assembly, or not held. + return + + if(!target || get_dist(user, target) > 7 || !(target in view(user))) + activate_pin(2) // Failure pin, out of range or not visible. + return + + set_pin_data(IC_OUTPUT, 1, WEAKREF(target)) + set_pin_data(IC_OUTPUT, 2, target.x - user.x) + set_pin_data(IC_OUTPUT, 3, target.y - user.y) + push_data() + activate_pin(1) // Success pin + /obj/item/integrated_circuit/input/button name = "button" desc = "This tiny button must do something, right?" @@ -17,8 +50,6 @@ activators = list("on pressed" = IC_PINTYPE_PULSE_OUT) spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH - - /obj/item/integrated_circuit/input/button/ask_for_input(mob/user) //Bit misleading name for this specific use. to_chat(user, span_notice("You press the button labeled '[src.displayed_name]'.")) activate_pin(1) @@ -72,7 +103,7 @@ power_draw_per_use = 4 /obj/item/integrated_circuit/input/textpad/ask_for_input(mob/user) - var/new_input = tgui_input_text(user, "Enter some words, please.","Number pad", get_pin_data(IC_OUTPUT, 1),MAX_NAME_LEN, encode=FALSE) + var/new_input = tgui_input_text(user, "Enter some words, please.","Number pad", get_pin_data(IC_OUTPUT, 1),MAX_KEYPAD_INPUT_LEN, encode=FALSE) new_input = sanitize(new_input,MAX_KEYPAD_INPUT_LEN) // Slightly increase the size of the character limit. if(istext(new_input) && CanInteract(user, GLOB.tgui_physical_state)) set_pin_data(IC_OUTPUT, 1, new_input) @@ -500,6 +531,12 @@ var/message = get_pin_data(IC_INPUT, 2) var/text = get_pin_data(IC_INPUT, 3) + var/is_communicator = FALSE // improved communicator support + for(var/obj/item/communicator/comm in all_communicators) + if(comm.exonet && comm.exonet.address == target_address) + is_communicator = TRUE + break + if(target_address && istext(target_address)) if(!get_connection_to_tcomms()) set_pin_data(IC_OUTPUT, 1, null) @@ -509,6 +546,9 @@ push_data() activate_pin(2) else + if(is_communicator) + text = message // For communicators, we need to set the text to the message. + message = "text" exonet.send_message(target_address, message, text) /obj/item/integrated_circuit/input/receive_exonet_message(var/atom/origin_atom, var/origin_address, var/message, var/text) diff --git a/code/modules/integrated_electronics/subtypes/logic.dm b/code/modules/integrated_electronics/subtypes/logic.dm index f996ddf24c8..21055118eac 100644 --- a/code/modules/integrated_electronics/subtypes/logic.dm +++ b/code/modules/integrated_electronics/subtypes/logic.dm @@ -223,3 +223,30 @@ /obj/item/integrated_circuit/logic/unary/not/do_check(var/datum/integrated_io/A) return !A.data + +/obj/item/integrated_circuit/logic/toggler // Allows parts of circuits to be toggled on/off. + name = "circuit toggler" + desc = "Outputs its input data if enabled, otherwise does nothing. Used for enable/disabling parts of your circuit boards" + icon_state = "toggle_button" + inputs = list( + "input" = IC_PINTYPE_ANY, + "enabled" = IC_PINTYPE_BOOLEAN, + "toggle enable" = IC_PINTYPE_PULSE_IN, + ) + inputs_default = list("2" = TRUE) + outputs = list("output" = IC_PINTYPE_ANY) + activators = list( + "pulse in" = IC_PINTYPE_PULSE_IN, + "pulse out" = IC_PINTYPE_PULSE_OUT + ) + spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + +/obj/item/integrated_circuit/logic/toggler/do_work() + pull_data() + var/enabled_input = get_pin_data(IC_INPUT, 2) + if(!enabled_input) + return + else + set_pin_data(IC_OUTPUT, 1, get_pin_data(IC_INPUT, 1)) + push_data() + activate_pin(2) diff --git a/code/modules/integrated_electronics/subtypes/reagents.dm b/code/modules/integrated_electronics/subtypes/reagents.dm index 3d7c43be78f..61a3ef3c5bd 100644 --- a/code/modules/integrated_electronics/subtypes/reagents.dm +++ b/code/modules/integrated_electronics/subtypes/reagents.dm @@ -18,8 +18,12 @@ flags = OPENCONTAINER complexity = 20 cooldown_per_use = 30 SECONDS - inputs = list() - outputs = list("volume used" = IC_PINTYPE_NUMBER,"self reference" = IC_PINTYPE_REF) + inputs = list( + "reagent storage" = IC_PINTYPE_REF) + outputs = list( + "volume held" = IC_PINTYPE_NUMBER, + "self reference" = IC_PINTYPE_REF + ) activators = list("create smoke" = IC_PINTYPE_PULSE_IN,"on smoked" = IC_PINTYPE_PULSE_OUT) spawn_flags = IC_SPAWN_RESEARCH origin_tech = list(TECH_ENGINEERING = 3, TECH_DATA = 3, TECH_BIO = 3) @@ -37,6 +41,15 @@ ..() /obj/item/integrated_circuit/reagent/smoke/do_work() + // Attempt to fill self from input storage before acting + var/input_storage = get_pin_data(IC_INPUT, 1) + if(input_storage && istype(input_storage, /obj/item/integrated_circuit/reagent/storage)) + var/obj/item/integrated_circuit/reagent/storage/storage = input_storage + if(storage.reagents && storage.reagents.total_volume > 0) + var/amount_to_transfer = min(storage.reagents.total_volume, reagents.get_free_space()) + if(amount_to_transfer > 0) + storage.reagents.trans_to(src, amount_to_transfer) + playsound(src, 'sound/effects/smoke.ogg', 50, 1, -3) var/datum/effect/effect/system/smoke_spread/chem/smoke_system = new() smoke_system.set_up(reagents, 10, 0, get_turf(src)) @@ -55,10 +68,19 @@ flags = OPENCONTAINER complexity = 20 cooldown_per_use = 6 SECONDS - inputs = list("target" = IC_PINTYPE_REF, "injection amount" = IC_PINTYPE_NUMBER) + inputs = list("target" = IC_PINTYPE_REF, + "injection amount" = IC_PINTYPE_NUMBER, + "reagent storage" = IC_PINTYPE_REF) inputs_default = list("2" = 5) - outputs = list("volume used" = IC_PINTYPE_NUMBER,"self reference" = IC_PINTYPE_REF) - activators = list("inject" = IC_PINTYPE_PULSE_IN, "on injected" = IC_PINTYPE_PULSE_OUT, "on fail" = IC_PINTYPE_PULSE_OUT) + outputs = list( + "volume contained" = IC_PINTYPE_NUMBER, + "self reference" = IC_PINTYPE_REF, + ) + activators = list( + "inject" = IC_PINTYPE_PULSE_IN, + "on injected" = IC_PINTYPE_PULSE_OUT, + "on fail" = IC_PINTYPE_PULSE_OUT + ) spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH volume = 30 power_draw_per_use = 15 @@ -89,6 +111,16 @@ /obj/item/integrated_circuit/reagent/injector/do_work() set waitfor = 0 // Don't sleep in a proc that is called by a processor without this set, otherwise it'll delay the entire thing + + // Attempt to fill self from input storage before acting + var/input_storage = get_pin_data(IC_INPUT, 3) + if(input_storage && istype(input_storage, /obj/item/integrated_circuit/reagent/storage)) + var/obj/item/integrated_circuit/reagent/storage/storage = input_storage + if(storage.reagents && storage.reagents.total_volume > 0) + var/amount_to_transfer = min(storage.reagents.total_volume, transfer_amount) + if(amount_to_transfer > 0) + storage.reagents.trans_to(src, amount_to_transfer) + var/atom/movable/AM = get_pin_data_as_type(IC_INPUT, 1, /atom/movable) if(!istype(AM)) //Invalid input activate_pin(3) diff --git a/code/modules/research/designs/circuit_assembly.dm b/code/modules/research/designs/circuit_assembly.dm index 48641d04201..76867b492da 100644 --- a/code/modules/research/designs/circuit_assembly.dm +++ b/code/modules/research/designs/circuit_assembly.dm @@ -97,3 +97,12 @@ materials = list(MAT_STEEL = 2000) build_path = /obj/item/implant/integrated_circuit sort_string = "UDAAF" + +/datum/design/item/integrated_circuitry/assembly/circuit_bug + name = "Circuitry Bug" + desc = "A tiny circuit assembly that can easily be hidden." + id = "circuit-bug" + req_tech = list(TECH_MATERIAL = 3, TECH_ENGINEERING = 3, TECH_POWER = 2) + materials = list(MAT_STEEL = 2000) + build_path = /obj/item/electronic_assembly/circuit_bug + sort_string = "UDAAG" diff --git a/vorestation.dme b/vorestation.dme index 6d3db0ca093..0182a078430 100644 --- a/vorestation.dme +++ b/vorestation.dme @@ -2839,6 +2839,7 @@ #include "code\modules\integrated_electronics\core\pins.dm" #include "code\modules\integrated_electronics\core\printer.dm" #include "code\modules\integrated_electronics\core\tools.dm" +#include "code\modules\integrated_electronics\core\assemblies\circuit_bug.dm" #include "code\modules\integrated_electronics\core\assemblies\clothing.dm" #include "code\modules\integrated_electronics\core\assemblies\device.dm" #include "code\modules\integrated_electronics\core\assemblies\generic.dm"