diff --git a/_maps/map_files/Deltastation/DeltaStation2.dmm b/_maps/map_files/Deltastation/DeltaStation2.dmm index 4c7bee23e7f..827a50f10f3 100644 --- a/_maps/map_files/Deltastation/DeltaStation2.dmm +++ b/_maps/map_files/Deltastation/DeltaStation2.dmm @@ -24186,8 +24186,8 @@ /area/station/maintenance/department/crew_quarters/bar) "fOV" = ( /obj/effect/turf_decal/tile/neutral/fourcorners, -/obj/item/kirbyplants/random, /obj/structure/sign/warning/firing_range/directional/west, +/obj/machinery/bci_implanter, /turf/open/floor/iron/dark, /area/station/science/circuits) "fPf" = ( @@ -57785,6 +57785,7 @@ "nZn" = ( /obj/effect/turf_decal/tile/neutral/fourcorners, /obj/structure/disposalpipe/segment, +/obj/item/kirbyplants/random, /turf/open/floor/iron/dark, /area/station/science/circuits) "nZt" = ( diff --git a/_maps/map_files/IceBoxStation/IceBoxStation.dmm b/_maps/map_files/IceBoxStation/IceBoxStation.dmm index 201b26190b2..d5a2a09e148 100644 --- a/_maps/map_files/IceBoxStation/IceBoxStation.dmm +++ b/_maps/map_files/IceBoxStation/IceBoxStation.dmm @@ -13953,9 +13953,21 @@ "egT" = ( /obj/machinery/airalarm/directional/north, /obj/structure/rack, -/obj/item/controller, -/obj/item/compact_remote, -/obj/item/compact_remote, +/obj/item/controller{ + pixel_x = -7 + }, +/obj/item/compact_remote{ + pixel_x = -7 + }, +/obj/item/compact_remote{ + pixel_x = -7 + }, +/obj/item/integrated_circuit/loaded/speech_relay{ + pixel_x = 7 + }, +/obj/item/integrated_circuit/loaded/hello_world{ + pixel_x = 7 + }, /turf/open/floor/iron/white/corner, /area/station/science/explab) "egV" = ( @@ -40279,9 +40291,7 @@ /turf/open/floor/iron/dark/textured, /area/station/security/prison) "msi" = ( -/obj/structure/rack, -/obj/item/integrated_circuit/loaded/speech_relay, -/obj/item/integrated_circuit/loaded/hello_world, +/obj/machinery/bci_implanter, /turf/open/floor/iron/white/side{ dir = 4 }, diff --git a/_maps/map_files/KiloStation/KiloStation.dmm b/_maps/map_files/KiloStation/KiloStation.dmm index c0fc35b5407..992675343c5 100644 --- a/_maps/map_files/KiloStation/KiloStation.dmm +++ b/_maps/map_files/KiloStation/KiloStation.dmm @@ -6231,13 +6231,11 @@ /turf/open/floor/iron, /area/station/hallway/primary/central) "bWv" = ( -/obj/structure/rack, -/obj/item/integrated_circuit/loaded/speech_relay, -/obj/item/integrated_circuit/loaded/hello_world, /obj/effect/turf_decal/tile/purple/anticorner/contrasted{ dir = 1 }, /obj/machinery/light_switch/directional/north, +/obj/machinery/bci_implanter, /turf/open/floor/iron/showroomfloor, /area/station/science/ordnance/office) "bWE" = ( @@ -71144,13 +71142,25 @@ /area/station/engineering/atmos) "ujZ" = ( /obj/structure/rack, -/obj/item/controller, -/obj/item/compact_remote, -/obj/item/compact_remote, +/obj/item/controller{ + pixel_x = -7 + }, +/obj/item/compact_remote{ + pixel_x = -7 + }, +/obj/item/compact_remote{ + pixel_x = -7 + }, /obj/effect/turf_decal/tile/purple/half/contrasted{ dir = 1 }, /obj/machinery/airalarm/directional/north, +/obj/item/integrated_circuit/loaded/speech_relay{ + pixel_x = 7 + }, +/obj/item/integrated_circuit/loaded/hello_world{ + pixel_x = 7 + }, /turf/open/floor/iron/showroomfloor, /area/station/science/ordnance/office) "ukc" = ( diff --git a/_maps/map_files/MetaStation/MetaStation.dmm b/_maps/map_files/MetaStation/MetaStation.dmm index 1cfb99fa695..c9b01a050eb 100644 --- a/_maps/map_files/MetaStation/MetaStation.dmm +++ b/_maps/map_files/MetaStation/MetaStation.dmm @@ -34770,11 +34770,7 @@ /turf/closed/wall/r_wall, /area/station/science/lab) "mvS" = ( -/obj/structure/table, -/obj/machinery/airalarm/directional/south, -/obj/item/storage/toolbox/electrical{ - pixel_y = 5 - }, +/obj/machinery/bci_implanter, /turf/open/floor/iron, /area/station/science/explab) "mvY" = ( @@ -65294,7 +65290,9 @@ "wVC" = ( /obj/structure/rack, /obj/item/integrated_circuit/loaded/hello_world, +/obj/item/storage/toolbox/electrical, /obj/item/integrated_circuit/loaded/speech_relay, +/obj/machinery/airalarm/directional/north, /turf/open/floor/iron/white, /area/station/science/explab) "wVO" = ( diff --git a/_maps/map_files/tramstation/tramstation.dmm b/_maps/map_files/tramstation/tramstation.dmm index be399891809..4c01777f0a2 100644 --- a/_maps/map_files/tramstation/tramstation.dmm +++ b/_maps/map_files/tramstation/tramstation.dmm @@ -18347,6 +18347,7 @@ /obj/effect/turf_decal/trimline/purple/filled/corner{ dir = 1 }, +/obj/machinery/bci_implanter, /turf/open/floor/iron/white, /area/station/science/explab) "gCH" = ( @@ -30737,11 +30738,7 @@ /area/station/science/lower) "kXw" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/door/window/right/directional/north{ - dir = 2; - name = "Research Test Chamber"; - req_access = list("science") - }, +/obj/structure/window/reinforced, /turf/open/floor/engine, /area/station/science/explab) "kXI" = ( diff --git a/code/__DEFINES/wiremod.dm b/code/__DEFINES/wiremod.dm index dcfb2c3ce0b..befbcdb8c74 100644 --- a/code/__DEFINES/wiremod.dm +++ b/code/__DEFINES/wiremod.dm @@ -119,6 +119,8 @@ #define CIRCUIT_FLAG_INSTANT (1<<4) /// This circuit component can't be loaded in module component. Saves us some headaches. #define CIRCUIT_FLAG_REFUSE_MODULE (1<<5) +/// This circuit component cannot be inserted into the same circuit multiple times. Only use this for major headaches. +#define CIRCUIT_NO_DUPLICATES (1<<6) // Datatype flags /// The datatype supports manual inputs diff --git a/code/modules/research/designs/wiremod_designs.dm b/code/modules/research/designs/wiremod_designs.dm index edf04e0d6eb..1873fa8162a 100644 --- a/code/modules/research/designs/wiremod_designs.dm +++ b/code/modules/research/designs/wiremod_designs.dm @@ -381,6 +381,16 @@ id = "comp_counter_overlay" build_path = /obj/item/circuit_component/counter_overlay +/datum/design/component/bci/reagent_injector + name = "Reagent Injector Component" + id = "comp_reagent_injector" + build_path = /obj/item/circuit_component/reagent_injector + +/datum/design/component/bci/install_detector + name = "Install Detector Component" + id = "comp_install_detector" + build_path = /obj/item/circuit_component/install_detector + /datum/design/component/foreach name = "For Each Component" id = "comp_foreach" diff --git a/code/modules/research/techweb/all_nodes.dm b/code/modules/research/techweb/all_nodes.dm index dad1a92ecd0..5b4216134d6 100644 --- a/code/modules/research/techweb/all_nodes.dm +++ b/code/modules/research/techweb/all_nodes.dm @@ -826,7 +826,9 @@ "comp_bar_overlay", "comp_bci_action", "comp_counter_overlay", + "comp_install_detector", "comp_object_overlay", + "comp_reagent_injector", "comp_target_intercept", "comp_thought_listener", "comp_vox", diff --git a/code/modules/wiremod/components/bci/install_detector.dm b/code/modules/wiremod/components/bci/install_detector.dm new file mode 100644 index 00000000000..0d39e01214e --- /dev/null +++ b/code/modules/wiremod/components/bci/install_detector.dm @@ -0,0 +1,50 @@ +/** + * # Install Detector Component + * + * Detects when a BCI is installed/removed. + * Requires a BCI shell. + */ + +/obj/item/circuit_component/install_detector + display_name = "Install Detector" + desc = "A component that detects when a BCI is installed or removed from its user." + category = "BCI" + + required_shells = list(/obj/item/organ/internal/cyberimp/bci) + + var/datum/port/output/implanted + var/datum/port/output/removed + var/datum/port/output/current_state + + var/obj/item/organ/internal/cyberimp/bci/bci + +/obj/item/circuit_component/install_detector/populate_ports() + . = ..() + current_state = add_output_port("Current State", PORT_TYPE_NUMBER) + implanted = add_output_port("Implanted", PORT_TYPE_SIGNAL) + removed = add_output_port("Removed", PORT_TYPE_SIGNAL) + +/obj/item/circuit_component/install_detector/register_shell(atom/movable/shell) + . = ..() + if(istype(shell, /obj/item/organ/internal/cyberimp/bci)) + bci = shell + RegisterSignal(shell, COMSIG_ORGAN_IMPLANTED, PROC_REF(on_organ_implanted)) + RegisterSignal(shell, COMSIG_ORGAN_REMOVED, PROC_REF(on_organ_removed)) + +/obj/item/circuit_component/install_detector/unregister_shell(atom/movable/shell) + . = ..() + bci = null + UnregisterSignal(shell, list( + COMSIG_ORGAN_IMPLANTED, + COMSIG_ORGAN_REMOVED, + )) + +/obj/item/circuit_component/install_detector/proc/on_organ_implanted(datum/source, mob/living/carbon/owner) + SIGNAL_HANDLER + current_state.set_output(TRUE) + implanted.set_output(COMPONENT_SIGNAL) + +/obj/item/circuit_component/install_detector/proc/on_organ_removed(datum/source, mob/living/carbon/owner) + SIGNAL_HANDLER + current_state.set_output(FALSE) + removed.set_output(COMPONENT_SIGNAL) diff --git a/code/modules/wiremod/components/bci/reagent_injector.dm b/code/modules/wiremod/components/bci/reagent_injector.dm new file mode 100644 index 00000000000..ef9188d7bdc --- /dev/null +++ b/code/modules/wiremod/components/bci/reagent_injector.dm @@ -0,0 +1,56 @@ +/** + * # Reagent Injector Component + * + * Injects reagents into the user. + * Requires a BCI shell. + */ + +/obj/item/circuit_component/reagent_injector + display_name = "Reagent Injector" + desc = "A component that can inject reagents from a BCI's reagent storage." + category = "BCI" + circuit_flags = CIRCUIT_NO_DUPLICATES + + required_shells = list(/obj/item/organ/internal/cyberimp/bci) + + var/datum/port/input/inject + var/datum/port/output/injected + + var/obj/item/organ/internal/cyberimp/bci/bci + +/obj/item/circuit_component/reagent_injector/Initialize(mapload) + . = ..() + create_reagents(15, OPENCONTAINER) //This is mostly used in the case of a BCI still having reagents in it when the component is removed. + +/obj/item/circuit_component/reagent_injector/populate_ports() + . = ..() + inject = add_input_port("Inject", PORT_TYPE_SIGNAL, trigger = PROC_REF(trigger_inject)) + injected = add_output_port("Injected", PORT_TYPE_SIGNAL) + +/obj/item/circuit_component/reagent_injector/proc/trigger_inject() + CIRCUIT_TRIGGER + if(!bci.owner) + return + if(bci.owner.reagents.total_volume + bci.reagents.total_volume > bci.owner.reagents.maximum_volume) + return + var/contained = bci.reagents.get_reagent_log_string() + var/units = bci.reagents.trans_to(bci.owner.reagents, bci.reagents.total_volume, methods = INJECT) + if(units) + injected.set_output(COMPONENT_SIGNAL) + log_combat(bci.owner, bci.owner, "injected", bci, "which had [contained]") + +/obj/item/circuit_component/reagent_injector/register_shell(atom/movable/shell) + . = ..() + if(istype(shell, /obj/item/organ/internal/cyberimp/bci)) + bci = shell + bci.create_reagents(15, OPENCONTAINER) + if(reagents.total_volume) + reagents.trans_to(bci, reagents.total_volume) + +/obj/item/circuit_component/reagent_injector/unregister_shell(atom/movable/shell) + . = ..() + if(bci?.reagents) + if(bci.reagents.total_volume) + bci.reagents.trans_to(src, bci.reagents.total_volume) + QDEL_NULL(bci.reagents) + bci = null diff --git a/code/modules/wiremod/core/integrated_circuit.dm b/code/modules/wiremod/core/integrated_circuit.dm index 4b3beee4296..9d4a42e5ff6 100644 --- a/code/modules/wiremod/core/integrated_circuit.dm +++ b/code/modules/wiremod/core/integrated_circuit.dm @@ -216,6 +216,28 @@ GLOBAL_LIST_EMPTY_TYPED(integrated_circuits, /obj/item/integrated_circuit) SEND_SIGNAL(src, COMSIG_CIRCUIT_SET_ON, new_value) on = new_value +/** + * Used for checking if another component of to_check's type exists in the circuit. + * Introspects through modules. + * + * Arguments: + * * to_check - The component to check. + **/ +/obj/item/integrated_circuit/proc/is_duplicate(obj/item/circuit_component/to_check) + for(var/component as anything in attached_components) + if(component == to_check) + continue + if(istype(component, to_check.type)) + return TRUE + if(istype(component, /obj/item/circuit_component/module)) + var/obj/item/circuit_component/module/module = component + for(var/module_component as anything in module.internal_circuit.attached_components) + if(module_component == to_check) + continue + if(istype(module_component, to_check.type)) + return TRUE + return FALSE + /** * Adds a component to the circuitboard * @@ -231,6 +253,11 @@ GLOBAL_LIST_EMPTY_TYPED(integrated_circuits, /obj/item/integrated_circuit) if(!to_add.add_to(src)) return FALSE + if(to_add.circuit_flags & CIRCUIT_NO_DUPLICATES) + if(is_duplicate(to_add)) + to_chat(user, span_danger("You can't insert multiple instances of this component into the same circuit!")) + return FALSE + var/success = FALSE if(user) success = user.transferItemToLoc(to_add, src) diff --git a/code/modules/wiremod/shell/brain_computer_interface.dm b/code/modules/wiremod/shell/brain_computer_interface.dm index e0e9d6639a1..c221dc00ffe 100644 --- a/code/modules/wiremod/shell/brain_computer_interface.dm +++ b/code/modules/wiremod/shell/brain_computer_interface.dm @@ -101,15 +101,19 @@ var/datum/port/input/message var/datum/port/input/send_message_signal + var/datum/port/input/show_charge_meter var/datum/port/output/user_port var/datum/weakref/user + var/obj/item/organ/internal/cyberimp/bci/bci + /obj/item/circuit_component/bci_core/populate_ports() - message = add_input_port("Message", PORT_TYPE_STRING) + message = add_input_port("Message", PORT_TYPE_STRING, trigger = null) 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) @@ -117,31 +121,47 @@ QDEL_NULL(charge_action) return ..() -/obj/item/circuit_component/bci_core/register_shell(atom/movable/shell) - var/obj/item/organ/internal/cyberimp/bci/bci = shell +/obj/item/circuit_component/bci_core/proc/update_charge_action() + CIRCUIT_TRIGGER + var/mob/living/carbon/resolved_owner = user?.resolve() + if (show_charge_meter.value) + if (charge_action) + return + charge_action = new(src) + if (resolved_owner) + charge_action.Grant(resolved_owner) + bci.actions += charge_action + else + if (!charge_action) + return + if (resolved_owner) + charge_action.Remove(resolved_owner) + bci.actions -= charge_action + QDEL_NULL(charge_action) - charge_action = new(src) - bci.actions += list(charge_action) +/obj/item/circuit_component/bci_core/register_shell(atom/movable/shell) + bci = shell + + show_charge_meter.set_value(TRUE) RegisterSignal(shell, COMSIG_ORGAN_IMPLANTED, PROC_REF(on_organ_implanted)) RegisterSignal(shell, COMSIG_ORGAN_REMOVED, PROC_REF(on_organ_removed)) /obj/item/circuit_component/bci_core/unregister_shell(atom/movable/shell) - var/obj/item/organ/internal/cyberimp/bci/bci = shell + bci = shell - bci.actions -= charge_action - QDEL_NULL(charge_action) + if (charge_action) + var/mob/living/carbon/resolved_owner = user?.resolve() + if (resolved_owner) + charge_action.Remove(resolved_owner) + bci.actions -= charge_action + QDEL_NULL(charge_action) UnregisterSignal(shell, list( COMSIG_ORGAN_IMPLANTED, COMSIG_ORGAN_REMOVED, )) -/obj/item/circuit_component/bci_core/should_receive_input(datum/port/input/port) - if (!COMPONENT_TRIGGERED_BY(send_message_signal, port)) - return FALSE - return ..() - /obj/item/circuit_component/bci_core/input_received(datum/port/input/port) var/sent_message = trim(message.value) if (!sent_message) @@ -159,6 +179,8 @@ /obj/item/circuit_component/bci_core/proc/on_organ_implanted(datum/source, mob/living/carbon/owner) SIGNAL_HANDLER + update_charge_action() + user_port.set_output(owner) user = WEAKREF(owner) diff --git a/tgstation.dme b/tgstation.dme index a8d638a602a..dc15adbc9e8 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -4731,6 +4731,8 @@ #include "code\modules\wiremod\components\atom\reagentscanner.dm" #include "code\modules\wiremod\components\atom\self.dm" #include "code\modules\wiremod\components\atom\species.dm" +#include "code\modules\wiremod\components\bci\install_detector.dm" +#include "code\modules\wiremod\components\bci\reagent_injector.dm" #include "code\modules\wiremod\components\bci\thought_listener.dm" #include "code\modules\wiremod\components\bci\vox.dm" #include "code\modules\wiremod\components\bci\hud\bar_overlay.dm"