diff --git a/code/__DEFINES/dcs/signals/signals_object.dm b/code/__DEFINES/dcs/signals/signals_object.dm index 2044aab51e2..4d9c6e9c00b 100644 --- a/code/__DEFINES/dcs/signals/signals_object.dm +++ b/code/__DEFINES/dcs/signals/signals_object.dm @@ -558,19 +558,29 @@ #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. + * The following four signals are separate from the above two because buttons and pressure plates 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) +/// Sent when an assembly is added to a button : (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) +/// Sent when an assembly is removed from a button : (obj/machinery/button/button, mob/user) #define COMSIG_ASSEMBLY_REMOVED_FROM_BUTTON "assembly_removed_from_button" +/// Sent when an assembly is added to a pressure plate : (obj/item/pressureplate/pressure_plate, mob/user) +#define COMSIG_ASSEMBLY_ADDED_TO_PRESSURE_PLATE "assembly_added_to_pressure_plate" + +/// Sent when an assembly is removed from a pressure plate : (obj/item/pressureplate/pressure_plate, mob/user) +#define COMSIG_ASSEMBLY_REMOVED_FROM_PRESSURE_PLATE "assembly_removed_from_pressure_playe" + /// 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" + +/// Sent from /datum/wires/attach_assembly() : (atom/holder) +#define COMSIG_ASSEMBLY_PRE_ATTACH "assembly_pre_attach" + #define COMPONENT_CANCEL_ATTACH (1<<0) diff --git a/code/__DEFINES/traits/declarations.dm b/code/__DEFINES/traits/declarations.dm index dc3d6fa0c1d..5d35a7fcb87 100644 --- a/code/__DEFINES/traits/declarations.dm +++ b/code/__DEFINES/traits/declarations.dm @@ -1424,4 +1424,7 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai /// Mob doesn't get closed eyelids overlay when it gets knocked out cold or dies #define TRAIT_NO_EYELIDS "no_eyelids" +/// Trait applied when the wire bundle component is added to an [/obj/item/integrated_circuit] +#define TRAIT_COMPONENT_WIRE_BUNDLE "component_wire_bundle" + // END TRAIT DEFINES diff --git a/code/__DEFINES/wires.dm b/code/__DEFINES/wires.dm index 4926996f26b..034bb8897e6 100644 --- a/code/__DEFINES/wires.dm +++ b/code/__DEFINES/wires.dm @@ -2,6 +2,30 @@ #define COMSIG_CUT_WIRE(wire) "cut_wire [wire]" #define COMSIG_MEND_WIRE(wire) "mend_wire [wire]" +/// from base of /datum/wires/proc/on_pulse : (wire, mob/user) +#define COMSIG_PULSE_WIRE "pulse_wire" + +// Directionality of wire pulses + +/// The wires interact with their holder when pulsed +#define WIRES_INPUT (1<<0) +/// The wires have a reason to toggle whether attached assemblies are armed +#define WIRES_TOGGLE_ARMED (1<<1) +/// The wires only want to activate assemblies that do something other than (dis)arming themselves +#define WIRES_FUNCTIONAL_OUTPUT (1<<2) +/// The holder can both pulse its wires and be affected by its wires getting pulsed +#define WIRES_ALL (WIRES_INPUT | WIRES_TOGGLE_ARMED | WIRES_FUNCTIONAL_OUTPUT) + +/// The assembly can pulse a wire it is attached to +#define ASSEMBLY_INPUT (1<<0) +/// The assembly toggles whether it will pulse the attached wire when it is pulsed by the attached wire +#define ASSEMBLY_TOGGLE_ARMED (1<<1) +/// The assembly does something other than just (dis)arming itself when it is pulsed by the wire it is attached to +#define ASSEMBLY_FUNCTIONAL_OUTPUT (1<<2) +/// The assembly can both pulse the wire it is attached to, and (dis)arms itself when pulsed by the wire +#define ASSEMBLY_TOGGLEABLE_INPUT (ASSEMBLY_INPUT | ASSEMBLY_TOGGLE_ARMED) +#define ASSEMBLY_ALL (ASSEMBLY_TOGGLEABLE_INPUT | ASSEMBLY_FUNCTIONAL_OUTPUT) + //retvals for attempt_wires_interaction #define WIRE_INTERACTION_FAIL 0 #define WIRE_INTERACTION_SUCCESSFUL 1 @@ -72,3 +96,5 @@ #define AI_WIRE_DISABLED 1 #define AI_WIRE_HACKED 2 #define AI_WIRE_DISABLED_HACKED -1 + +#define MAX_WIRE_COUNT 17 diff --git a/code/_globalvars/traits/_traits.dm b/code/_globalvars/traits/_traits.dm index 4edc46bb503..e351e155dc1 100644 --- a/code/_globalvars/traits/_traits.dm +++ b/code/_globalvars/traits/_traits.dm @@ -687,6 +687,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_CIRCUIT_UI_OPEN" = TRAIT_CIRCUIT_UI_OPEN, "TRAIT_CIRCUIT_UNDUPABLE" = TRAIT_CIRCUIT_UNDUPABLE, "TRAIT_COMPONENT_MMI" = TRAIT_COMPONENT_MMI, + "TRAIT_COMPONENT_WIRE_BUNDLE" = TRAIT_COMPONENT_WIRE_BUNDLE, ), /obj/item/modular_computer = list( "TRAIT_MODPC_HALVED_DOWNLOAD_SPEED" = TRAIT_MODPC_HALVED_DOWNLOAD_SPEED, diff --git a/code/datums/wires/_wires.dm b/code/datums/wires/_wires.dm index 73bdc511ee4..13b9420d836 100644 --- a/code/datums/wires/_wires.dm +++ b/code/datums/wires/_wires.dm @@ -7,16 +7,14 @@ if(I.tool_behaviour == TOOL_WIRECUTTER || I.tool_behaviour == TOOL_MULTITOOL) return TRUE if(isassembly(I)) - var/obj/item/assembly/A = I - if(A.attachable) - return TRUE + return TRUE /atom/proc/attempt_wire_interaction(mob/user) if(!wires) return WIRE_INTERACTION_FAIL if(!user.CanReach(src)) return WIRE_INTERACTION_FAIL - wires.interact(user) + INVOKE_ASYNC(wires, TYPE_PROC_REF(/datum/wires, interact), user) return WIRE_INTERACTION_BLOCK /datum/wires @@ -29,6 +27,9 @@ /// The display name for the wire set shown in station blueprints. Not shown in blueprints if randomize is TRUE or it's an item NT wouldn't know about (Explosives/Nuke). Also used in the hacking interface. var/proper_name = "Unknown" + /// Whether pulsed wires affect the holder, and/or the holder pulses its wires + var/wire_behavior = WIRES_INPUT + /// List of all wires. var/list/wires = list() /// List of cut wires. @@ -179,6 +180,7 @@ /datum/wires/proc/pulse(wire, user, force=FALSE) if(!force && is_cut(wire)) return + SEND_SIGNAL(src, COMSIG_PULSE_WIRE, wire, user) on_pulse(wire, user) /datum/wires/proc/pulse_color(color, mob/living/user, force=FALSE) @@ -191,7 +193,7 @@ return TRUE /datum/wires/proc/attach_assembly(color, obj/item/assembly/S) - if(S && istype(S) && S.attachable && !is_attached(color)) + if(S && istype(S) && S.assembly_behavior && !is_attached(color) && !(SEND_SIGNAL(S, COMSIG_ASSEMBLY_PRE_ATTACH, holder) & COMPONENT_CANCEL_ATTACH)) assemblies[color] = S S.forceMove(holder) S.connected = src @@ -384,13 +386,13 @@ I = L.get_active_held_item() if(isassembly(I)) var/obj/item/assembly/A = I - if(A.attachable) + if(A.assembly_behavior & wire_behavior) if(!L.temporarilyRemoveItemFromInventory(A)) return if(!attach_assembly(target_wire, A)) A.forceMove(L.drop_location()) . = TRUE else - to_chat(L, span_warning("You need an attachable assembly!")) + to_chat(L, span_warning("You cannot attach this assembly to these wires!")) #undef MAXIMUM_EMP_WIRES diff --git a/code/datums/wires/scanner_gate.dm b/code/datums/wires/scanner_gate.dm index 14752ec6795..cb363d68f95 100644 --- a/code/datums/wires/scanner_gate.dm +++ b/code/datums/wires/scanner_gate.dm @@ -2,6 +2,7 @@ holder_type = /obj/machinery/scanner_gate proper_name = "Scanner Gate" wires = list(WIRE_ACCEPT, WIRE_DENY, WIRE_DISABLE) + wire_behavior = WIRES_FUNCTIONAL_OUTPUT /datum/wires/scanner_gate/on_pulse(wire, user) . = ..() diff --git a/code/datums/wires/wire_bundle_component.dm b/code/datums/wires/wire_bundle_component.dm new file mode 100644 index 00000000000..5cd4ffa2af6 --- /dev/null +++ b/code/datums/wires/wire_bundle_component.dm @@ -0,0 +1,24 @@ +#define CAPACITY_PER_WIRE 10 + +/datum/wires/wire_bundle_component + holder_type = /atom //Anything that can have a shell component, really. + randomize = TRUE + wire_behavior = WIRES_ALL + +/datum/wires/wire_bundle_component/New(atom/holder) + var/datum/component/shell/shell_comp = holder.GetComponent(/datum/component/shell) + if(!istype(shell_comp)) + CRASH("Holder does not have a shell component!") + var/wire_count = clamp(round(shell_comp.capacity / CAPACITY_PER_WIRE, 1), 1, MAX_WIRE_COUNT) + for(var/index in 1 to wire_count) + wires += "Port [index]" + ..() + +/datum/wires/wire_bundle_component/always_reveal_wire(color) + return TRUE // Let's not make wiring up this stuff confusing - just give them what wires correspond to what ports. + +/datum/wires/wire_bundle_component/ui_data(mob/user) + proper_name = holder.name + . = ..() + +#undef CAPACITY_PER_WIRE diff --git a/code/game/machinery/buttons.dm b/code/game/machinery/buttons.dm index c8aba44ef47..66f1b64795a 100644 --- a/code/game/machinery/buttons.dm +++ b/code/game/machinery/buttons.dm @@ -140,6 +140,9 @@ if(device) to_chat(user, span_warning("The button already contains a device!")) return ITEM_INTERACT_BLOCKING + if(!(new_device.assembly_behavior & ASSEMBLY_FUNCTIONAL_OUTPUT)) + to_chat(user, span_warning("\The [new_device] won't really do anything meaningful inside of the button...")) + return ITEM_INTERACT_BLOCKING if(!user.transferItemToLoc(new_device, src, silent = FALSE)) to_chat(user, span_warning("\The [new_device] is stuck to you!")) return ITEM_INTERACT_BLOCKING diff --git a/code/game/objects/items/devices/pressureplates.dm b/code/game/objects/items/devices/pressureplates.dm index 17f324d109f..ea27894d829 100644 --- a/code/game/objects/items/devices/pressureplates.dm +++ b/code/game/objects/items/devices/pressureplates.dm @@ -14,12 +14,12 @@ var/specific_item = null var/trigger_silent = FALSE var/sound/trigger_sound = 'sound/effects/pressureplate.ogg' - var/obj/item/assembly/signaler/sigdev = null + var/obj/item/assembly/assembly = null var/roundstart_signaller = FALSE var/roundstart_signaller_freq = FREQ_PRESSURE_PLATE var/roundstart_signaller_code = 30 var/roundstart_hide = FALSE - var/removable_signaller = TRUE + var/removable_assembly = TRUE var/active = FALSE var/image/tile_overlay = null var/can_trigger = TRUE @@ -31,9 +31,10 @@ . = ..() tile_overlay = image(icon = 'icons/turf/floors.dmi', icon_state = "pp_overlay") if(roundstart_signaller) - sigdev = new - sigdev.code = roundstart_signaller_code - sigdev.set_frequency(roundstart_signaller_freq) + var/obj/item/assembly/signaler/signaller = new(src) + signaller.code = roundstart_signaller_code + signaller.set_frequency(roundstart_signaller_freq) + assembly = signaller if(undertile_pressureplate) AddElement(/datum/element/undertile, tile_overlay = tile_overlay, use_anchor = TRUE) @@ -59,21 +60,28 @@ /obj/item/pressure_plate/proc/trigger() can_trigger = TRUE - if(istype(sigdev)) - sigdev.signal() + if(istype(assembly)) + assembly.activate() -/obj/item/pressure_plate/attackby(obj/item/I, mob/living/L) - if(issignaler(I) && !istype(sigdev) && removable_signaller && L.transferItemToLoc(I, src)) - sigdev = I - to_chat(L, span_notice("You attach [I] to [src]!")) +/obj/item/pressure_plate/attackby(obj/item/item, mob/living/L) + if(isassembly(item) && !istype(assembly) && removable_assembly) + var/obj/item/assembly/new_assembly = item + if(!(new_assembly.assembly_behavior & ASSEMBLY_FUNCTIONAL_OUTPUT)) + to_chat(L, span_warning("\The [item] doesn't seem like it would do much of anything inside of [src]...")) + return + if(L.transferItemToLoc(item, src)) + assembly = item + SEND_SIGNAL(item, COMSIG_ASSEMBLY_ADDED_TO_PRESSURE_PLATE, src, L) + to_chat(L, span_notice("You attach [item] to [src]!")) return ..() /obj/item/pressure_plate/attack_self(mob/living/L) - if(removable_signaller && istype(sigdev)) - to_chat(L, span_notice("You remove [sigdev] from [src].")) - if(!L.put_in_hands(sigdev)) - sigdev.forceMove(get_turf(src)) - sigdev = null + if(removable_assembly && istype(assembly)) + to_chat(L, span_notice("You remove [assembly] from [src].")) + SEND_SIGNAL(assembly, COMSIG_ASSEMBLY_REMOVED_FROM_PRESSURE_PLATE, src, L) + if(!L.put_in_hands(assembly)) + assembly.forceMove(get_turf(src)) + assembly = null return ..() /obj/item/pressure_plate/item_ctrl_click(mob/user) @@ -97,7 +105,7 @@ protected = TRUE anchored = TRUE //this prevents us from being picked up active = TRUE - removable_signaller = FALSE + removable_assembly = FALSE /// puzzle id we send if stepped on var/puzzle_id /// queue size must match diff --git a/code/game/objects/items/puzzle_pieces.dm b/code/game/objects/items/puzzle_pieces.dm index a7bd4da85ae..f5e3cf6da68 100644 --- a/code/game/objects/items/puzzle_pieces.dm +++ b/code/game/objects/items/puzzle_pieces.dm @@ -168,7 +168,7 @@ trigger_mob = FALSE trigger_item = TRUE specific_item = /obj/structure/holobox - removable_signaller = FALSE //Being a pressure plate subtype, this can also use signals. + removable_assembly = FALSE //Being a pressure plate subtype, this can also use signals. roundstart_signaller_freq = FREQ_HOLOGRID_SOLUTION //Frequency is kept on its own default channel however. active = TRUE trigger_delay = 10 diff --git a/code/modules/assembly/assembly.dm b/code/modules/assembly/assembly.dm index dbd5a704614..0ac5993aecc 100644 --- a/code/modules/assembly/assembly.dm +++ b/code/modules/assembly/assembly.dm @@ -23,7 +23,7 @@ var/secured = TRUE var/list/attached_overlays = null var/obj/item/assembly_holder/holder = null - var/attachable = FALSE // can this be attached to wires + var/assembly_behavior = ASSEMBLY_FUNCTIONAL_OUTPUT // how does the assembly behave with respect to what it's connected to var/datum/wires/connected = null var/next_activate = 0 //When we're next allowed to activate - for spam control @@ -126,7 +126,7 @@ balloon_alert(user, "can't attach another of that!") return if(new_assembly.secured || secured) - balloon_alert(user, "both devices not attachable!") + balloon_alert(user, "both devices not assembly_behavior!") return holder = new /obj/item/assembly_holder(drop_location()) diff --git a/code/modules/assembly/doorcontrol.dm b/code/modules/assembly/doorcontrol.dm index 31584976ced..33610283502 100644 --- a/code/modules/assembly/doorcontrol.dm +++ b/code/modules/assembly/doorcontrol.dm @@ -2,7 +2,6 @@ name = "blast door controller" desc = "A small electronic device able to control a blast door remotely." icon_state = "control" - attachable = TRUE /// The ID of the blast door electronics to match to the ID of the blast door being used. var/id = null /// Cooldown of the door's controller. Updates when pressed (activate()) diff --git a/code/modules/assembly/health.dm b/code/modules/assembly/health.dm index ad2c6ac1764..d4635ac159f 100644 --- a/code/modules/assembly/health.dm +++ b/code/modules/assembly/health.dm @@ -3,7 +3,7 @@ desc = "Used for scanning and monitoring health." icon_state = "health" custom_materials = list(/datum/material/iron=SMALL_MATERIAL_AMOUNT*8, /datum/material/glass=SMALL_MATERIAL_AMOUNT * 2) - attachable = TRUE + assembly_behavior = ASSEMBLY_TOGGLEABLE_INPUT var/scanning = FALSE var/health_scan diff --git a/code/modules/assembly/mousetrap.dm b/code/modules/assembly/mousetrap.dm index 187a161df80..2b2065a67a0 100644 --- a/code/modules/assembly/mousetrap.dm +++ b/code/modules/assembly/mousetrap.dm @@ -4,7 +4,7 @@ icon_state = "mousetrap" inhand_icon_state = "mousetrap" custom_materials = list(/datum/material/iron=SMALL_MATERIAL_AMOUNT) - attachable = TRUE + assembly_behavior = ASSEMBLY_TOGGLEABLE_INPUT var/armed = FALSE drop_sound = 'sound/items/handling/component_drop.ogg' pickup_sound = 'sound/items/handling/component_pickup.ogg' diff --git a/code/modules/assembly/proximity.dm b/code/modules/assembly/proximity.dm index 6ba2a7a6342..9b7ccad9aef 100644 --- a/code/modules/assembly/proximity.dm +++ b/code/modules/assembly/proximity.dm @@ -3,7 +3,7 @@ desc = "Used for scanning and alerting when someone enters a certain proximity." icon_state = "prox" custom_materials = list(/datum/material/iron=SMALL_MATERIAL_AMOUNT*8, /datum/material/glass=SMALL_MATERIAL_AMOUNT * 2) - attachable = TRUE + assembly_behavior = ASSEMBLY_TOGGLEABLE_INPUT drop_sound = 'sound/items/handling/component_drop.ogg' pickup_sound = 'sound/items/handling/component_pickup.ogg' var/scanning = FALSE diff --git a/code/modules/assembly/signaler.dm b/code/modules/assembly/signaler.dm index 4e265384ace..b5346386d7d 100644 --- a/code/modules/assembly/signaler.dm +++ b/code/modules/assembly/signaler.dm @@ -6,7 +6,7 @@ lefthand_file = 'icons/mob/inhands/items/devices_lefthand.dmi' righthand_file = 'icons/mob/inhands/items/devices_righthand.dmi' custom_materials = list(/datum/material/iron=SMALL_MATERIAL_AMOUNT * 4, /datum/material/glass=SMALL_MATERIAL_AMOUNT*1.2) - attachable = TRUE + assembly_behavior = ASSEMBLY_ALL drop_sound = 'sound/items/handling/component_drop.ogg' pickup_sound = 'sound/items/handling/component_pickup.ogg' diff --git a/code/modules/assembly/timer.dm b/code/modules/assembly/timer.dm index 09cbfd9b0dc..b25d30e1b4b 100644 --- a/code/modules/assembly/timer.dm +++ b/code/modules/assembly/timer.dm @@ -3,7 +3,7 @@ desc = "Used to time things. Works well with contraptions which has to count down. Tick tock." icon_state = "timer" custom_materials = list(/datum/material/iron=SMALL_MATERIAL_AMOUNT*5, /datum/material/glass=SMALL_MATERIAL_AMOUNT*0.5) - attachable = TRUE + assembly_behavior = ASSEMBLY_TOGGLEABLE_INPUT drop_sound = 'sound/items/handling/component_drop.ogg' pickup_sound = 'sound/items/handling/component_pickup.ogg' diff --git a/code/modules/assembly/voice.dm b/code/modules/assembly/voice.dm index de0954c960e..106b8127307 100644 --- a/code/modules/assembly/voice.dm +++ b/code/modules/assembly/voice.dm @@ -8,7 +8,7 @@ desc = "A small electronic device able to record a voice sample, and send a signal when that sample is repeated." icon_state = "voice" custom_materials = list(/datum/material/iron=SMALL_MATERIAL_AMOUNT*5, /datum/material/glass=SMALL_MATERIAL_AMOUNT*0.5) - attachable = TRUE + assembly_behavior = ASSEMBLY_TOGGLEABLE_INPUT verb_say = "beeps" verb_ask = "beeps" verb_exclaim = "beeps" diff --git a/code/modules/research/designs/wiremod_designs.dm b/code/modules/research/designs/wiremod_designs.dm index f8732cc332b..526e8d2a54a 100644 --- a/code/modules/research/designs/wiremod_designs.dm +++ b/code/modules/research/designs/wiremod_designs.dm @@ -477,6 +477,11 @@ id = "comp_assoc_list_pick" build_path = /obj/item/circuit_component/list_pick/assoc +/datum/design/component/wire_bundle + name = "Wire Bundle" + id = "comp_wire_bundle" + build_path = /obj/item/circuit_component/wire_bundle + /datum/design/component/wirenet_receive name = "Wirenet Receiver Component" id = "comp_wirenet_receive" @@ -691,3 +696,32 @@ category = list( RND_CATEGORY_CIRCUITRY + RND_SUBCATEGORY_CIRCUITRY_SHELLS ) + +/datum/design/undertile_shell + name = "Under-tile Shell" + desc = "A small shell that can fit under the floor." + id = "undertile_shell" + materials = list( + /datum/material/glass=HALF_SHEET_MATERIAL_AMOUNT, + /datum/material/iron=SHEET_MATERIAL_AMOUNT*2.5, + ) + build_path = /obj/item/undertile_circuit + build_type = COMPONENT_PRINTER + category = list( + RND_CATEGORY_CIRCUITRY + RND_SUBCATEGORY_CIRCUITRY_SHELLS + ) + + +/datum/design/wallmount_shell + name = "Wall-mounted Shell" + desc = "A large shell that can be mounted on a wall." + id = "wallmount_shell" + materials = list( + /datum/material/glass=SHEET_MATERIAL_AMOUNT, + /datum/material/iron=SHEET_MATERIAL_AMOUNT*5, + ) + build_path = /obj/item/wallframe/circuit + build_type = COMPONENT_PRINTER + category = list( + RND_CATEGORY_CIRCUITRY + RND_SUBCATEGORY_CIRCUITRY_SHELLS + ) diff --git a/code/modules/research/techweb/nodes/circuit_nodes.dm b/code/modules/research/techweb/nodes/circuit_nodes.dm index 109873c3851..9ef3b929ac4 100644 --- a/code/modules/research/techweb/nodes/circuit_nodes.dm +++ b/code/modules/research/techweb/nodes/circuit_nodes.dm @@ -86,6 +86,7 @@ "comp_typecast", "comp_typecheck", "comp_view_sensor", + "comp_wire_bundle", "comp_wirenet_receive", "comp_wirenet_send", "comp_wirenet_send_literal", @@ -108,6 +109,8 @@ "money_bot_shell", "scanner_gate_shell", "scanner_shell", + "undertile_shell", + "wallmount_shell", "comp_equip_action", ) research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_1_POINTS) diff --git a/code/modules/wiremod/components/utility/wire_bundle.dm b/code/modules/wiremod/components/utility/wire_bundle.dm new file mode 100644 index 00000000000..7e0355e8948 --- /dev/null +++ b/code/modules/wiremod/components/utility/wire_bundle.dm @@ -0,0 +1,115 @@ +/obj/item/circuit_component/wire_bundle + display_name = "Wire Bundle" + desc = "A bundle of exposed wires that assemblies can be attached to. Ports will only show up once the circuit is inserted into a shell." + category = "Utility" + circuit_flags = CIRCUIT_FLAG_REFUSE_MODULE + + var/datum/wires/wire_bundle_component/tracked_wires + + var/list/wire_input_ports = list() + var/list/wire_output_ports = list() + +/obj/item/circuit_component/wire_bundle/get_ui_notices() + . = ..() + . += create_ui_notice("Port count is proportional to shell capacity.", "orange", "plug") + . += create_ui_notice("Max port count: [MAX_WIRE_COUNT]", "orange", "plug") + . += create_ui_notice("Incompatible with assembly shell.", "red", "plug-circle-xmark") + +/obj/item/circuit_component/wire_bundle/register_shell(atom/movable/shell) + . = ..() + if(isassembly(shell) && !parent.admin_only) + return + if(shell.wires) // Don't add wires to shells that already have some. + return + tracked_wires = new(shell) + shell.set_wires(tracked_wires) + for(var/wire in tracked_wires.wires) + wire_input_ports[add_input_port("Pulse [wire]", PORT_TYPE_SIGNAL)] = wire + wire_output_ports[wire] = add_output_port("[wire] Pulsed", PORT_TYPE_SIGNAL) + RegisterSignal(tracked_wires, COMSIG_PULSE_WIRE, PROC_REF(on_pulse_wire)) + RegisterSignal(shell, COMSIG_ATOM_REQUESTING_CONTEXT_FROM_ITEM, PROC_REF(on_shell_requesting_context)) + RegisterSignal(shell, COMSIG_ATOM_ITEM_INTERACTION_SECONDARY, PROC_REF(on_shell_secondary_interaction)) + +/obj/item/circuit_component/wire_bundle/unregister_shell(atom/movable/shell) + . = ..() + if(shell.wires != tracked_wires) + return + UnregisterSignal(shell, list(COMSIG_ATOM_ITEM_INTERACTION_SECONDARY, COMSIG_ATOM_REQUESTING_CONTEXT_FROM_ITEM)) + for(var/color in tracked_wires.colors) + var/obj/item/assembly/assembly = tracked_wires.detach_assembly(color) + if(assembly) + assembly.forceMove(drop_location()) + shell.set_wires(null) + QDEL_NULL(tracked_wires) + for(var/datum/port/input/in_port in wire_input_ports) + remove_input_port(in_port) + for(var/wire in wire_output_ports) + var/datum/port/output/out_port = wire_output_ports[wire] + remove_output_port(out_port) + wire_input_ports.Cut() + wire_output_ports.Cut() + +/obj/item/circuit_component/wire_bundle/add_to(obj/item/integrated_circuit/added_to) + . = ..() + if(HAS_TRAIT(added_to, TRAIT_COMPONENT_WIRE_BUNDLE)) + return FALSE + ADD_TRAIT(added_to, TRAIT_COMPONENT_WIRE_BUNDLE, REF(src)) + +/obj/item/circuit_component/wire_bundle/removed_from(obj/item/integrated_circuit/removed_from) + . = ..() + REMOVE_TRAIT(removed_from, TRAIT_COMPONENT_WIRE_BUNDLE, REF(src)) + return ..() + +/obj/item/circuit_component/wire_bundle/input_received(datum/port/input/port) + . = ..() + if(!port) + return + var/wire = wire_input_ports[port] + if(!wire) + return + if(tracked_wires.is_cut(wire)) + return + var/color = tracked_wires.get_color_of_wire(wire) + var/obj/item/assembly/attached = tracked_wires.get_attached(color) + attached?.activate() + +/obj/item/circuit_component/wire_bundle/proc/on_pulse_wire(source, wire) + SIGNAL_HANDLER + if(tracked_wires.is_cut(wire)) + return + var/datum/port/output/port = wire_output_ports[wire] + if(!istype(port)) + return + port.set_output(COMPONENT_SIGNAL) + +/obj/item/circuit_component/wire_bundle/proc/can_access_wires(atom/source) + if(ismachinery(source)) + var/obj/machinery/machine = source + return machine.panel_open + return TRUE + +/obj/item/circuit_component/wire_bundle/proc/on_shell_requesting_context(atom/source, list/context, obj/item/item, mob/user) + SIGNAL_HANDLER + . = NONE + + if(!is_wire_tool(item)) + return + if(!can_access_wires(source)) + return + context[SCREENTIP_CONTEXT_RMB] = "Interact with wires" + return CONTEXTUAL_SCREENTIP_SET + +/obj/item/circuit_component/wire_bundle/proc/on_shell_secondary_interaction(atom/source, mob/user, obj/item/tool) + SIGNAL_HANDLER + if(!is_wire_tool(tool)) + return + if(!can_access_wires(source)) + return + var/datum/component/shell/shell_comp = source.GetComponent(/datum/component/shell) + if(shell_comp.locked) + source.balloon_alert(user, "locked!") + return ITEM_INTERACT_FAILURE + if(source.attempt_wire_interaction(user) == WIRE_INTERACTION_BLOCK) + return ITEM_INTERACT_BLOCKING + + diff --git a/code/modules/wiremod/shell/assembly.dm b/code/modules/wiremod/shell/assembly.dm index 3e69331c4c8..033808c8454 100644 --- a/code/modules/wiremod/shell/assembly.dm +++ b/code/modules/wiremod/shell/assembly.dm @@ -7,13 +7,13 @@ name = "circuit assembly" desc = "A small electronic device that can house an integrated circuit." icon_state = "wiremod" - attachable = TRUE + assembly_behavior = ASSEMBLY_ALL /// 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) + var/static/list/power_use_override_types = list(/obj/machinery, /obj/vehicle/sealed/mecha, /obj/item/mod/control, /obj/item/pressure_plate, /mob/living/silicon/robot) /obj/item/assembly/wiremod/Initialize(mapload) . = ..() @@ -23,10 +23,11 @@ ), 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)) + RegisterSignal(src, COMSIG_ASSEMBLY_PRE_ATTACH, PROC_REF(on_pre_attach)) + RegisterSignals(src, list(COMSIG_ASSEMBLY_ATTACHED, COMSIG_ASSEMBLY_ADDED_TO_BUTTON, COMSIG_ASSEMBLY_ADDED_TO_PRESSURE_PLATE), PROC_REF(on_attached)) + RegisterSignals(src, list(COMSIG_ASSEMBLY_DETACHED, COMSIG_ASSEMBLY_REMOVED_FROM_BUTTON, COMSIG_ASSEMBLY_REMOVED_FROM_PRESSURE_PLATE), PROC_REF(on_detached)) -/obj/item/assembly/wiremod/proc/on_circuit_attached(_source, obj/item/integrated_circuit/circuit) +/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)) @@ -34,12 +35,24 @@ SIGNAL_HANDLER UnregisterSignal(source.attached_circuit, COMSIG_CIRCUIT_PRE_POWER_USAGE) -/obj/item/assembly/wiremod/proc/on_attached(_source, atom/movable/holder) +/obj/item/assembly/wiremod/proc/on_pre_attach(obj/item/circuit_component/wire_bundle/source, atom/holder) + SIGNAL_HANDLER + if(!istype(source)) + return + if(source.parent.admin_only) + return + if(istype(holder.wires, /datum/wires/wire_bundle_component)) + var/datum/component/shell/shell_comp = GetComponent(/datum/component/shell) + if(shell_comp.attached_circuit.admin_only) + return + return COMPONENT_CANCEL_ATTACH + +/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) +/obj/item/assembly/wiremod/proc/on_detached(source) SIGNAL_HANDLER power_use_proxy = null @@ -59,6 +72,12 @@ var/obj/item/mod/control/modsuit = power_use_proxy if(modsuit.subtract_charge(power_to_use)) return COMPONENT_OVERRIDE_POWER_USAGE + if(istype(power_use_proxy, /obj/item/pressure_plate)) + if(!power_use_proxy.anchored) + return + var/area/our_area = get_area(power_use_proxy) + if(our_area.apc?.use_energy(power_to_use, AREA_USAGE_EQUIP)) + 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)) diff --git a/code/modules/wiremod/shell/undertile.dm b/code/modules/wiremod/shell/undertile.dm new file mode 100644 index 00000000000..69ef66b61c0 --- /dev/null +++ b/code/modules/wiremod/shell/undertile.dm @@ -0,0 +1,13 @@ +/obj/item/undertile_circuit + name = "circuit panel" + desc = "A panel for an integrated circuit. It needs to be fit under a floor tile to operate." + icon = 'icons/obj/science/circuits.dmi' + inhand_icon_state = "flashtool" + lefthand_file = 'icons/mob/inhands/equipment/security_lefthand.dmi' + righthand_file = 'icons/mob/inhands/equipment/security_righthand.dmi' + icon_state = "undertile" + +/obj/item/undertile_circuit/Initialize(mapload) + . = ..() + AddElement(/datum/element/undertile, TRAIT_T_RAY_VISIBLE, INVISIBILITY_OBSERVER, use_anchor = TRUE) + AddComponent(/datum/component/shell, null, SHELL_CAPACITY_SMALL, SHELL_FLAG_REQUIRE_ANCHOR|SHELL_FLAG_USB_PORT) diff --git a/code/modules/wiremod/shell/wallmount.dm b/code/modules/wiremod/shell/wallmount.dm new file mode 100644 index 00000000000..d461f696da1 --- /dev/null +++ b/code/modules/wiremod/shell/wallmount.dm @@ -0,0 +1,33 @@ +/obj/structure/wallmount_circuit + name = "circuit box" + desc = "A wall-mounted box suitable for the installation of integrated circuits." + icon = 'icons/obj/science/circuits.dmi' + icon_state = "wallmount" + layer = BELOW_OBJ_LAYER + anchored = TRUE + + resistance_flags = LAVA_PROOF | FIRE_PROOF + +/obj/structure/wallmount_circuit/Initialize(mapload) + . = ..() + AddComponent(/datum/component/shell, null, SHELL_CAPACITY_LARGE, SHELL_FLAG_REQUIRE_ANCHOR|SHELL_FLAG_USB_PORT) + +/obj/structure/wallmount_circuit/wrench_act(mob/living/user, obj/item/tool) + var/datum/component/shell/shell_comp = GetComponent(/datum/component/shell) + if(shell_comp.locked) + balloon_alert(user, "locked!") + return ITEM_INTERACT_FAILURE + to_chat(user, span_notice("You start unsecuring the circuit box...")) + if(tool.use_tool(src, user, 40, volume=50)) + to_chat(user, span_notice("You unsecure the circuit box.")) + playsound(loc, 'sound/items/deconstruct.ogg', 50, TRUE) + deconstruct(TRUE) + return ITEM_INTERACT_SUCCESS + +/obj/item/wallframe/circuit + name = "circuit box frame" + desc = "A box that can be mounted on a wall and have circuits installed." + icon = 'icons/obj/science/circuits.dmi' + icon_state = "wallmount_assembly" + result_path = /obj/structure/wallmount_circuit + pixel_shift = 32 diff --git a/icons/obj/science/circuits.dmi b/icons/obj/science/circuits.dmi index 1d50c67823b..e91025ae613 100644 Binary files a/icons/obj/science/circuits.dmi and b/icons/obj/science/circuits.dmi differ diff --git a/tgstation.dme b/tgstation.dme index 31035ae171a..255baf3b398 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -2003,6 +2003,7 @@ #include "code\datums\wires\syndicatebomb.dm" #include "code\datums\wires\tesla_coil.dm" #include "code\datums\wires\vending.dm" +#include "code\datums\wires\wire_bundle_component.dm" #include "code\datums\wounds\_wound_static_data.dm" #include "code\datums\wounds\_wounds.dm" #include "code\datums\wounds\blunt.dm" @@ -6470,6 +6471,7 @@ #include "code\modules\wiremod\components\utility\timepiece.dm" #include "code\modules\wiremod\components\utility\typecast.dm" #include "code\modules\wiremod\components\utility\typecheck.dm" +#include "code\modules\wiremod\components\utility\wire_bundle.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" @@ -6518,6 +6520,8 @@ #include "code\modules\wiremod\shell\scanner_gate.dm" #include "code\modules\wiremod\shell\server.dm" #include "code\modules\wiremod\shell\shell_items.dm" +#include "code\modules\wiremod\shell\undertile.dm" +#include "code\modules\wiremod\shell\wallmount.dm" #include "code\modules\zombie\items.dm" #include "code\modules\zombie\organs.dm" #include "code\ze_genesis_call\genesis_call.dm"