From 5ab9aba9d4119f01a28745dbf3435e5cdf853bb3 Mon Sep 17 00:00:00 2001
From: SkyratBot <59378654+SkyratBot@users.noreply.github.com>
Date: Wed, 23 Jun 2021 23:50:59 +0200
Subject: [PATCH] [MIRROR] Added circuit component UI details, added
multiplexer and allowed inserting components directly into shells. (#6479)
* Added circuit component UI details, added multiplexer and allowed inserting components directly into shells. (#59635)
Adds the multiplexer circuit component - en.wikipedia.org/wiki/Multiplexer
Circuit components can now be directly inserted into shells rather than having to take the integrated circuit out.
Special information can be accessed from components now through the "Info" button besides the eject button on a component.
* Added circuit component UI details, added multiplexer and allowed inserting components directly into shells.
Co-authored-by: Watermelon914 <37270891+Watermelon914@users.noreply.github.com>
---
code/__DEFINES/wiremod.dm | 6 +-
code/datums/components/shell.dm | 13 +++-
.../research/designs/wiremod_designs.dm | 37 +++-------
code/modules/research/techweb/all_nodes.dm | 1 +
code/modules/wiremod/component.dm | 36 ++++++++++
.../wiremod/components/action/light.dm | 9 +++
.../modules/wiremod/components/action/pull.dm | 1 +
.../wiremod/components/action/radio.dm | 1 +
.../wiremod/components/action/speech.dm | 9 +++
.../wiremod/components/atom/direction.dm | 9 +++
code/modules/wiremod/components/atom/gps.dm | 1 +
.../modules/wiremod/components/atom/health.dm | 9 +++
code/modules/wiremod/components/atom/hear.dm | 1 +
code/modules/wiremod/components/atom/self.dm | 1 +
.../wiremod/components/atom/species.dm | 1 +
.../wiremod/components/math/arithmetic.dm | 20 +++---
.../wiremod/components/math/comparison.dm | 23 +++----
code/modules/wiremod/components/math/index.dm | 1 +
.../modules/wiremod/components/math/length.dm | 1 +
code/modules/wiremod/components/math/logic.dm | 18 +++--
code/modules/wiremod/components/math/not.dm | 1 +
.../modules/wiremod/components/math/random.dm | 1 +
.../wiremod/components/string/concat.dm | 1 +
.../wiremod/components/string/contains.dm | 1 +
.../wiremod/components/string/textcase.dm | 12 ++--
.../wiremod/components/string/tostring.dm | 1 +
.../wiremod/components/utility/clock.dm | 9 +++
.../wiremod/components/utility/combiner.dm | 37 +++++-----
.../wiremod/components/utility/delay.dm | 1 +
.../wiremod/components/utility/multiplexer.dm | 66 ++++++++++++++++++
.../modules/wiremod/components/utility/ram.dm | 1 +
.../wiremod/components/utility/typecheck.dm | 14 +++-
code/modules/wiremod/integrated_circuit.dm | 33 +++++++++
code/modules/wiremod/shell/compact_remote.dm | 1 +
code/modules/wiremod/shell/controller.dm | 1 +
code/modules/wiremod/shell/drone.dm | 3 +-
code/modules/wiremod/shell/moneybot.dm | 2 +
tgstation.dme | 1 +
.../IntegratedCircuit/CircuitInfo.js | 33 +++++++++
.../index.js} | 67 ++++++++++++++++---
.../styles/interfaces/IntegratedCircuit.scss | 9 +++
41 files changed, 398 insertions(+), 95 deletions(-)
create mode 100644 code/modules/wiremod/components/utility/multiplexer.dm
create mode 100644 tgui/packages/tgui/interfaces/IntegratedCircuit/CircuitInfo.js
rename tgui/packages/tgui/interfaces/{IntegratedCircuit.js => IntegratedCircuit/index.js} (90%)
diff --git a/code/__DEFINES/wiremod.dm b/code/__DEFINES/wiremod.dm
index 752d915fc93..f1f29bf6e89 100644
--- a/code/__DEFINES/wiremod.dm
+++ b/code/__DEFINES/wiremod.dm
@@ -25,6 +25,9 @@
// Other datatypes
/// Atom datatype
#define PORT_TYPE_ATOM "entity"
+/// Any datatype (USED ONLY FOR DISPLAY, DO NOT USE)
+#define COMP_TYPE_ANY "any"
+
/// The maximum range between a port and an atom
#define PORT_ATOM_MAX_RANGE 7
@@ -81,9 +84,6 @@
// Clock component
#define COMP_CLOCK_DELAY 0.9 SECONDS
-// Combiner component
-#define COMP_COMBINER_ANY "any"
-
// Shells
/// Whether a circuit is stuck on a shell and cannot be removed (by a user)
diff --git a/code/datums/components/shell.dm b/code/datums/components/shell.dm
index 8d6abd53500..d0e546ae382 100644
--- a/code/datums/components/shell.dm
+++ b/code/datums/components/shell.dm
@@ -105,6 +105,10 @@
source.balloon_alert(attacker, "[locked? "locked" : "unlocked"] [source]")
return COMPONENT_NO_AFTERATTACK
+ if(attached_circuit && istype(item, /obj/item/circuit_component))
+ attached_circuit.add_component(item, attacker)
+ return
+
if(!istype(item, /obj/item/integrated_circuit))
return
var/obj/item/integrated_circuit/logic_board = item
@@ -167,10 +171,15 @@
SIGNAL_HANDLER
remove_circuit()
-/datum/component/shell/proc/on_circuit_add_component_manually(datum/source, obj/item/circuit_component/added_comp)
+/datum/component/shell/proc/on_circuit_add_component_manually(atom/source, obj/item/circuit_component/added_comp, mob/living/user)
SIGNAL_HANDLER
+ if(locked)
+ source.balloon_alert(user, "it's locked!")
+ return COMPONENT_CANCEL_ADD_COMPONENT
- return COMPONENT_CANCEL_ADD_COMPONENT
+ if(length(attached_circuit.attached_components) - length(unremovable_circuit_components) >= capacity)
+ source.balloon_alert(user, "it's at maximum capacity!")
+ return COMPONENT_CANCEL_ADD_COMPONENT
/**
* Attaches a circuit to the parent. Doesn't do any checks to see for any existing circuits so that should be done beforehand.
diff --git a/code/modules/research/designs/wiremod_designs.dm b/code/modules/research/designs/wiremod_designs.dm
index 55e46c3afb3..9c13ffee8a7 100644
--- a/code/modules/research/designs/wiremod_designs.dm
+++ b/code/modules/research/designs/wiremod_designs.dm
@@ -37,162 +37,147 @@
departmental_flags = DEPARTMENTAL_FLAG_SCIENCE
category = list("Circuitry", "Components")
+/datum/design/component/New()
+ . = ..()
+ if(build_path)
+ var/obj/item/circuit_component/component_path = build_path
+ desc = initial(component_path.display_desc)
+
/datum/design/component/arithmetic
name = "Arithmetic Component"
- desc = "General arithmetic component with add/subtract/multiplication/division capabilities."
id = "comp_arithmetic"
build_path = /obj/item/circuit_component/arithmetic
/datum/design/component/clock
name = "Clock Component"
- desc = "A component that repeatedly fires."
id = "comp_clock"
build_path = /obj/item/circuit_component/clock
/datum/design/component/comparison
name = "Comparison Component"
- desc = "A component that compares two objects."
id = "comp_comparison"
build_path = /obj/item/circuit_component/compare/comparison
/datum/design/component/logic
name = "Logic Component"
- desc = "A component with 'and' and 'or' capabilities."
id = "comp_logic"
build_path = /obj/item/circuit_component/compare/logic
/datum/design/component/delay
name = "Delay Component"
- desc = "A component that delays a signal by a specified duration."
id = "comp_delay"
build_path = /obj/item/circuit_component/delay
/datum/design/component/index
name = "Index Component"
- desc = "A component that returns the value of a list at a given index."
id = "comp_index"
build_path = /obj/item/circuit_component/index
/datum/design/component/length
name = "Length Component"
- desc = "A component that returns the length of its input."
id = "comp_length"
build_path = /obj/item/circuit_component/length
/datum/design/component/light
name = "Light Component"
- desc = "A component that emits a light of a specific brightness and colour. Requires a shell."
id = "comp_light"
build_path = /obj/item/circuit_component/light
/datum/design/component/not
name = "Not Component"
- desc = "A component that inverts its input."
id = "comp_not"
build_path = /obj/item/circuit_component/not
/datum/design/component/ram
name = "RAM Component"
- desc = "A component that retains a variable."
id = "comp_ram"
build_path = /obj/item/circuit_component/ram
/datum/design/component/random
name = "Random Component"
- desc = "A component that returns random values."
id = "comp_random"
build_path = /obj/item/circuit_component/random
/datum/design/component/species
name = "Get Species Component"
- desc = "A component that returns the species of its input."
id = "comp_species"
build_path = /obj/item/circuit_component/species
/datum/design/component/speech
name = "Speech Component"
- desc = "A component that sends a message. Requires a shell."
id = "comp_speech"
build_path = /obj/item/circuit_component/speech
/datum/design/component/tostring
name = "To String Component"
- desc = "A component that converts its input to text."
id = "comp_tostring"
build_path = /obj/item/circuit_component/tostring
/datum/design/component/typecheck
name = "Typecheck Component"
- desc = "A component that checks the type of its input."
id = "comp_typecheck"
build_path = /obj/item/circuit_component/compare/typecheck
/datum/design/component/concat
name = "Concatenation Component"
- desc = "A component that combines strings."
id = "comp_concat"
build_path = /obj/item/circuit_component/concat
/datum/design/component/textcase
name = "Textcase Component"
- desc = "A component that makes its input uppercase or lowercase."
id = "comp_textcase"
build_path = /obj/item/circuit_component/textcase
/datum/design/component/hear
name = "Voice Activator Component"
- desc = "A component that listens for messages. Requires a shell."
id = "comp_hear"
build_path = /obj/item/circuit_component/hear
/datum/design/component/contains
name = "String Contains Component"
- desc = "Checks if a string contains a word/letter"
id = "comp_string_contains"
build_path = /obj/item/circuit_component/compare/contains
/datum/design/component/self
name = "Self Component"
- desc = "A component that returns the current shell."
id = "comp_self"
build_path = /obj/item/circuit_component/self
/datum/design/component/radio
name = "Radio Component"
- desc = "A component that can listen and send frequencies."
id = "comp_radio"
build_path = /obj/item/circuit_component/radio
/datum/design/component/gps
name = "GPS Component"
- desc = "A component that returns the xyz co-ordinates of itself."
id = "comp_gps"
build_path = /obj/item/circuit_component/gps
/datum/design/component/direction
name = "Direction Component"
- desc = "A component that returns the direction of itself and an entity."
id = "comp_direction"
build_path = /obj/item/circuit_component/direction
/datum/design/component/health
name = "Health Component"
- desc = "A component that returns the health of an organism."
id = "comp_health"
build_path = /obj/item/circuit_component/health
/datum/design/component/combiner
name = "Combiner Component"
- desc = "A component that combines multiple inputs to provide 1 output."
id = "comp_combiner"
build_path = /obj/item/circuit_component/combiner
/datum/design/component/pull
name = "Pull Component"
- desc = "A component that can force the shell to pull entities. Only works for drone shells."
id = "comp_pull"
build_path = /obj/item/circuit_component/pull
+/datum/design/component/multiplexer
+ name = "Multiplexer Component"
+ id = "comp_multiplexer"
+ build_path = /obj/item/circuit_component/multiplexer
+
/datum/design/compact_remote_shell
name = "Compact Remote Shell"
desc = "A handheld shell with one big button."
diff --git a/code/modules/research/techweb/all_nodes.dm b/code/modules/research/techweb/all_nodes.dm
index 8a15c5430c5..06677146d9b 100644
--- a/code/modules/research/techweb/all_nodes.dm
+++ b/code/modules/research/techweb/all_nodes.dm
@@ -223,6 +223,7 @@
"comp_length",
"comp_light",
"comp_logic",
+ "comp_multiplexer",
"comp_not",
"comp_radio",
"comp_ram",
diff --git a/code/modules/wiremod/component.dm b/code/modules/wiremod/component.dm
index 3a12593c1bb..5e743169729 100644
--- a/code/modules/wiremod/component.dm
+++ b/code/modules/wiremod/component.dm
@@ -16,6 +16,9 @@
/// The name of the component shown on the UI
var/display_name = "Generic"
+ /// The description of the component shown on the UI
+ var/display_desc = "A generic component"
+
/// The integrated_circuit that this component is attached to.
var/obj/item/integrated_circuit/parent
@@ -54,11 +57,16 @@
. = ..()
if(name == COMPONENT_DEFAULT_NAME)
name = "[lowertext(display_name)] [COMPONENT_DEFAULT_NAME]"
+ populate_options()
if(length(options))
current_option = options[1]
return INITIALIZE_HINT_LATELOAD
+/// Called when the options variable should be set.
+/obj/item/circuit_component/proc/populate_options()
+ return
+
/obj/item/circuit_component/LateInitialize()
. = ..()
if(circuit_flags & CIRCUIT_FLAG_INPUT_SIGNAL)
@@ -187,3 +195,31 @@
if((circuit_flags & CIRCUIT_FLAG_INPUT_SIGNAL) && !COMPONENT_TRIGGERED_BY(trigger_input, port))
return TRUE
+
+/**
+ * Gets the UI notices to be displayed on the CircuitInfo panel.
+ *
+ * Returns a list of buttons in the following format
+ * list(
+ * "icon" = ICON(string)
+ * "content" = CONTENT(string)
+ * "color" = COLOR(string, not a hex)
+ * )
+ */
+/obj/item/circuit_component/proc/get_ui_notices()
+ . = list()
+
+ if(!removable)
+ . += list(list(
+ "icon" = "lock",
+ "content" = "Unremovable",
+ "color" = "red"
+ ))
+
+
+ if(length(input_ports))
+ . += list(list(
+ "icon" = "bolt",
+ "content" = "Power Usage Per Input: [power_usage_per_input]",
+ "color" = "orange",
+ ))
diff --git a/code/modules/wiremod/components/action/light.dm b/code/modules/wiremod/components/action/light.dm
index d4137a4173f..f398ac9dafd 100644
--- a/code/modules/wiremod/components/action/light.dm
+++ b/code/modules/wiremod/components/action/light.dm
@@ -5,6 +5,7 @@
*/
/obj/item/circuit_component/light
display_name = "Light"
+ display_desc = "A component that emits a light of a specific brightness and colour. Requires a shell."
/// The colours of the light
var/datum/port/input/red
@@ -21,6 +22,14 @@
var/min_lightness = 0.4
var/shell_light_color
+/obj/item/circuit_component/light/get_ui_notices()
+ . = ..()
+ . += list(list(
+ "icon" = "lightbulb",
+ "content" = "Maximum Brightness: [max_power]",
+ "color" = "orange"
+ ))
+
/obj/item/circuit_component/light/Initialize()
. = ..()
red = add_input_port("Red", PORT_TYPE_NUMBER)
diff --git a/code/modules/wiremod/components/action/pull.dm b/code/modules/wiremod/components/action/pull.dm
index e1a0b9d34b3..e10c71dc57e 100644
--- a/code/modules/wiremod/components/action/pull.dm
+++ b/code/modules/wiremod/components/action/pull.dm
@@ -5,6 +5,7 @@
*/
/obj/item/circuit_component/pull
display_name = "Start Pulling"
+ display_desc = "A component that can force the shell to pull entities. Only works for drone shells."
/// Frequency input
var/datum/port/input/target
diff --git a/code/modules/wiremod/components/action/radio.dm b/code/modules/wiremod/components/action/radio.dm
index ab8b0c9f782..b0b5fa58fa9 100644
--- a/code/modules/wiremod/components/action/radio.dm
+++ b/code/modules/wiremod/components/action/radio.dm
@@ -5,6 +5,7 @@
*/
/obj/item/circuit_component/radio
display_name = "Radio"
+ display_desc = "A component that can listen and send frequencies."
/// Frequency input
var/datum/port/input/freq
diff --git a/code/modules/wiremod/components/action/speech.dm b/code/modules/wiremod/components/action/speech.dm
index aafbbfdd1e0..8b0084fa522 100644
--- a/code/modules/wiremod/components/action/speech.dm
+++ b/code/modules/wiremod/components/action/speech.dm
@@ -5,6 +5,7 @@
*/
/obj/item/circuit_component/speech
display_name = "Speech"
+ display_desc = "A component that sends a message. Requires a shell."
/// The message to send
var/datum/port/input/message
@@ -16,6 +17,14 @@
COOLDOWN_DECLARE(next_speech)
+/obj/item/circuit_component/speech/get_ui_notices()
+ . = ..()
+ . += list(list(
+ "icon" = "stopwatch",
+ "content" = "Speech Cooldown: [DisplayTimeText(speech_cooldown)]",
+ "color" = "orange",
+ ))
+
/obj/item/circuit_component/speech/Initialize()
. = ..()
message = add_input_port("Message", PORT_TYPE_STRING, FALSE)
diff --git a/code/modules/wiremod/components/atom/direction.dm b/code/modules/wiremod/components/atom/direction.dm
index 62a6806d0b7..872076af7f2 100644
--- a/code/modules/wiremod/components/atom/direction.dm
+++ b/code/modules/wiremod/components/atom/direction.dm
@@ -5,6 +5,7 @@
*/
/obj/item/circuit_component/direction
display_name = "Get Direction"
+ display_desc = "A component that returns the direction of itself and an entity."
/// The input port
var/datum/port/input/input_port
@@ -23,6 +24,14 @@
/// Maximum range for a valid direction to be returned
var/max_range = 7
+/obj/item/circuit_component/direction/get_ui_notices()
+ . = ..()
+ . += list(list(
+ "icon" = "info",
+ "content" = "Maximum Range: [max_range] tiles",
+ "color" = "orange",
+ ))
+
/obj/item/circuit_component/direction/Initialize()
. = ..()
input_port = add_input_port("Organism", PORT_TYPE_ATOM)
diff --git a/code/modules/wiremod/components/atom/gps.dm b/code/modules/wiremod/components/atom/gps.dm
index 9dc4ba72755..3c0b70b4188 100644
--- a/code/modules/wiremod/components/atom/gps.dm
+++ b/code/modules/wiremod/components/atom/gps.dm
@@ -5,6 +5,7 @@
*/
/obj/item/circuit_component/gps
display_name = "Internal GPS"
+ display_desc = "A component that returns the xyz co-ordinates of itself."
/// The result from the output
var/datum/port/output/x_pos
diff --git a/code/modules/wiremod/components/atom/health.dm b/code/modules/wiremod/components/atom/health.dm
index 7a9dcaba61b..af8afcb3167 100644
--- a/code/modules/wiremod/components/atom/health.dm
+++ b/code/modules/wiremod/components/atom/health.dm
@@ -5,6 +5,7 @@
*/
/obj/item/circuit_component/health
display_name = "Get Health"
+ display_desc = "A component that returns the health of an organism."
/// The input port
var/datum/port/input/input_port
@@ -24,6 +25,14 @@
var/max_range = 5
+/obj/item/circuit_component/health/get_ui_notices()
+ . = ..()
+ . += list(list(
+ "icon" = "info",
+ "content" = "Maximum Range: [max_range] tiles",
+ "color" = "orange",
+ ))
+
/obj/item/circuit_component/health/Initialize()
. = ..()
input_port = add_input_port("Organism", PORT_TYPE_ATOM)
diff --git a/code/modules/wiremod/components/atom/hear.dm b/code/modules/wiremod/components/atom/hear.dm
index 92dad54c4ce..322253001e3 100644
--- a/code/modules/wiremod/components/atom/hear.dm
+++ b/code/modules/wiremod/components/atom/hear.dm
@@ -5,6 +5,7 @@
*/
/obj/item/circuit_component/hear
display_name = "Voice Activator"
+ display_desc = "A component that listens for messages. Requires a shell."
flags_1 = HEAR_1
diff --git a/code/modules/wiremod/components/atom/self.dm b/code/modules/wiremod/components/atom/self.dm
index fdd69567da7..364d51cd6d6 100644
--- a/code/modules/wiremod/components/atom/self.dm
+++ b/code/modules/wiremod/components/atom/self.dm
@@ -5,6 +5,7 @@
*/
/obj/item/circuit_component/self
display_name = "Self"
+ display_desc = "A component that returns the current shell."
/// The shell this component is attached to.
var/datum/port/output/output
diff --git a/code/modules/wiremod/components/atom/species.dm b/code/modules/wiremod/components/atom/species.dm
index cf774ae3640..7c3735f852c 100644
--- a/code/modules/wiremod/components/atom/species.dm
+++ b/code/modules/wiremod/components/atom/species.dm
@@ -5,6 +5,7 @@
*/
/obj/item/circuit_component/species
display_name = "Get Species"
+ display_desc = "A component that returns the species of its input."
/// The input port
var/datum/port/input/input_port
diff --git a/code/modules/wiremod/components/math/arithmetic.dm b/code/modules/wiremod/components/math/arithmetic.dm
index 2b6db052fc6..6b010b08e0e 100644
--- a/code/modules/wiremod/components/math/arithmetic.dm
+++ b/code/modules/wiremod/components/math/arithmetic.dm
@@ -6,6 +6,7 @@
*/
/obj/item/circuit_component/arithmetic
display_name = "Arithmetic"
+ display_desc = "General arithmetic component with arithmetic capabilities."
/// The amount of input ports to have
var/input_port_amount = 4
@@ -15,17 +16,18 @@
circuit_flags = CIRCUIT_FLAG_INPUT_SIGNAL|CIRCUIT_FLAG_OUTPUT_SIGNAL
-GLOBAL_LIST_INIT(comp_arithmetic_options, list(
- COMP_ARITHMETIC_ADD,
- COMP_ARITHMETIC_SUBTRACT,
- COMP_ARITHMETIC_MULTIPLY,
- COMP_ARITHMETIC_DIVIDE,
- COMP_ARITHMETIC_MIN,
- COMP_ARITHMETIC_MAX,
-))
+/obj/item/circuit_component/arithmetic/populate_options()
+ var/static/component_options = list(
+ COMP_ARITHMETIC_ADD,
+ COMP_ARITHMETIC_SUBTRACT,
+ COMP_ARITHMETIC_MULTIPLY,
+ COMP_ARITHMETIC_DIVIDE,
+ COMP_ARITHMETIC_MIN,
+ COMP_ARITHMETIC_MAX,
+ )
+ options = component_options
/obj/item/circuit_component/arithmetic/Initialize()
- options = GLOB.comp_arithmetic_options
. = ..()
for(var/port_id in 1 to input_port_amount)
var/letter = ascii2text(text2ascii("A") + (port_id-1))
diff --git a/code/modules/wiremod/components/math/comparison.dm b/code/modules/wiremod/components/math/comparison.dm
index 46e7910ab2c..af90d612179 100644
--- a/code/modules/wiremod/components/math/comparison.dm
+++ b/code/modules/wiremod/components/math/comparison.dm
@@ -5,22 +5,21 @@
*/
/obj/item/circuit_component/compare/comparison
display_name = "Comparison"
+ display_desc = "A component that compares two objects."
input_port_amount = 2
var/current_type = PORT_TYPE_ANY
-GLOBAL_LIST_INIT(comp_comparison_options, list(
- COMP_COMPARISON_EQUAL,
- COMP_COMPARISON_NOT_EQUAL,
- COMP_COMPARISON_GREATER_THAN,
- COMP_COMPARISON_LESS_THAN,
- COMP_COMPARISON_GREATER_THAN_OR_EQUAL,
- COMP_COMPARISON_LESS_THAN_OR_EQUAL
-))
-
-/obj/item/circuit_component/compare/comparison/Initialize()
- options = GLOB.comp_comparison_options
- return ..()
+/obj/item/circuit_component/compare/comparison/populate_options()
+ var/static/component_options = list(
+ COMP_COMPARISON_EQUAL,
+ COMP_COMPARISON_NOT_EQUAL,
+ COMP_COMPARISON_GREATER_THAN,
+ COMP_COMPARISON_LESS_THAN,
+ COMP_COMPARISON_GREATER_THAN_OR_EQUAL,
+ COMP_COMPARISON_LESS_THAN_OR_EQUAL,
+ )
+ options = component_options
/obj/item/circuit_component/compare/comparison/input_received(datum/port/input/port)
switch(current_option)
diff --git a/code/modules/wiremod/components/math/index.dm b/code/modules/wiremod/components/math/index.dm
index 9c3f34c28c3..b327f814b8f 100644
--- a/code/modules/wiremod/components/math/index.dm
+++ b/code/modules/wiremod/components/math/index.dm
@@ -5,6 +5,7 @@
*/
/obj/item/circuit_component/index
display_name = "Index List"
+ display_desc = "A component that returns the value of a list at a given index."
/// The input port
var/datum/port/input/list_port
diff --git a/code/modules/wiremod/components/math/length.dm b/code/modules/wiremod/components/math/length.dm
index 4382d17873c..4ebe782a4b7 100644
--- a/code/modules/wiremod/components/math/length.dm
+++ b/code/modules/wiremod/components/math/length.dm
@@ -5,6 +5,7 @@
*/
/obj/item/circuit_component/length
display_name = "Length"
+ display_desc = "A component that returns the length of its input."
/// The input port
var/datum/port/input/input_port
diff --git a/code/modules/wiremod/components/math/logic.dm b/code/modules/wiremod/components/math/logic.dm
index acedb79613c..efb6b410b0e 100644
--- a/code/modules/wiremod/components/math/logic.dm
+++ b/code/modules/wiremod/components/math/logic.dm
@@ -5,17 +5,15 @@
*/
/obj/item/circuit_component/compare/logic
display_name = "Logic"
+ display_desc = "A component with 'and' and 'or' capabilities."
-
-GLOBAL_LIST_INIT(comp_logic_options, list(
- COMP_LOGIC_AND,
- COMP_LOGIC_OR,
- COMP_LOGIC_XOR
-))
-
-/obj/item/circuit_component/compare/logic/Initialize()
- options = GLOB.comp_logic_options
- return ..()
+/obj/item/circuit_component/compare/logic/populate_options()
+ var/static/component_options = list(
+ COMP_LOGIC_AND,
+ COMP_LOGIC_OR,
+ COMP_LOGIC_XOR,
+ )
+ options = component_options
/obj/item/circuit_component/compare/logic/do_comparisons(list/ports)
. = FALSE
diff --git a/code/modules/wiremod/components/math/not.dm b/code/modules/wiremod/components/math/not.dm
index a147224d6dc..dd60c593ecb 100644
--- a/code/modules/wiremod/components/math/not.dm
+++ b/code/modules/wiremod/components/math/not.dm
@@ -5,6 +5,7 @@
*/
/obj/item/circuit_component/not
display_name = "Not"
+ display_desc = "A component that inverts its input."
/// The input port
var/datum/port/input/input_port
diff --git a/code/modules/wiremod/components/math/random.dm b/code/modules/wiremod/components/math/random.dm
index 47b2e765d17..dce8296efac 100644
--- a/code/modules/wiremod/components/math/random.dm
+++ b/code/modules/wiremod/components/math/random.dm
@@ -5,6 +5,7 @@
*/
/obj/item/circuit_component/random
display_name = "Random"
+ display_desc = "A component that returns random values."
/// The minimum value that the random number can be
var/datum/port/input/minimum
diff --git a/code/modules/wiremod/components/string/concat.dm b/code/modules/wiremod/components/string/concat.dm
index 16691f88920..ac4ba9d0665 100644
--- a/code/modules/wiremod/components/string/concat.dm
+++ b/code/modules/wiremod/components/string/concat.dm
@@ -5,6 +5,7 @@
*/
/obj/item/circuit_component/concat
display_name = "Concatenate"
+ display_desc = "A component that combines strings."
/// The amount of input ports to have
var/input_port_amount = 4
diff --git a/code/modules/wiremod/components/string/contains.dm b/code/modules/wiremod/components/string/contains.dm
index 3f5c34e595a..61c48a476b2 100644
--- a/code/modules/wiremod/components/string/contains.dm
+++ b/code/modules/wiremod/components/string/contains.dm
@@ -5,6 +5,7 @@
*/
/obj/item/circuit_component/compare/contains
display_name = "String Contains"
+ display_desc = "Checks if a string contains a word/letter"
input_port_amount = 0
diff --git a/code/modules/wiremod/components/string/textcase.dm b/code/modules/wiremod/components/string/textcase.dm
index b2d6c926356..809f36bb0ab 100644
--- a/code/modules/wiremod/components/string/textcase.dm
+++ b/code/modules/wiremod/components/string/textcase.dm
@@ -5,6 +5,7 @@
*/
/obj/item/circuit_component/textcase
display_name = "Text Case"
+ display_desc = "A component that makes its input uppercase or lowercase."
/// The input port
var/datum/port/input/input_port
@@ -14,13 +15,14 @@
circuit_flags = CIRCUIT_FLAG_INPUT_SIGNAL|CIRCUIT_FLAG_OUTPUT_SIGNAL
-GLOBAL_LIST_INIT(comp_text_operations, list(
- COMP_TEXT_LOWER,
- COMP_TEXT_UPPER
-))
+/obj/item/circuit_component/textcase/populate_options()
+ var/static/component_options = list(
+ COMP_TEXT_LOWER,
+ COMP_TEXT_UPPER,
+ )
+ options = component_options
/obj/item/circuit_component/textcase/Initialize()
- options = GLOB.comp_text_operations
. = ..()
input_port = add_input_port("Input", PORT_TYPE_STRING)
output = add_output_port("Output", PORT_TYPE_STRING)
diff --git a/code/modules/wiremod/components/string/tostring.dm b/code/modules/wiremod/components/string/tostring.dm
index e447501e418..642594bb08c 100644
--- a/code/modules/wiremod/components/string/tostring.dm
+++ b/code/modules/wiremod/components/string/tostring.dm
@@ -5,6 +5,7 @@
*/
/obj/item/circuit_component/tostring
display_name = "To String"
+ display_desc = "A component that converts its input to text."
/// The input port
var/datum/port/input/input_port
diff --git a/code/modules/wiremod/components/utility/clock.dm b/code/modules/wiremod/components/utility/clock.dm
index 9fe6c5699e7..91b3a0db4b3 100644
--- a/code/modules/wiremod/components/utility/clock.dm
+++ b/code/modules/wiremod/components/utility/clock.dm
@@ -5,6 +5,7 @@
*/
/obj/item/circuit_component/clock
display_name = "Clock"
+ display_desc = "A component that repeatedly fires."
/// Whether the clock is on or not
var/datum/port/input/on
@@ -12,6 +13,14 @@
/// The signal from this clock component
var/datum/port/output/signal
+/obj/item/circuit_component/clock/get_ui_notices()
+ . = ..()
+ . += list(list(
+ "icon" = "clock",
+ "content" = "Clock Interval: [DisplayTimeText(COMP_CLOCK_DELAY)]",
+ "color" = "orange",
+ ))
+
/obj/item/circuit_component/clock/Initialize()
. = ..()
on = add_input_port("On", PORT_TYPE_NUMBER)
diff --git a/code/modules/wiremod/components/utility/combiner.dm b/code/modules/wiremod/components/utility/combiner.dm
index 56bd664367d..7857f0f260a 100644
--- a/code/modules/wiremod/components/utility/combiner.dm
+++ b/code/modules/wiremod/components/utility/combiner.dm
@@ -5,6 +5,7 @@
*/
/obj/item/circuit_component/combiner
display_name = "Combiner"
+ display_desc = "A component that combines multiple inputs to provide 1 output."
/// The amount of input ports to have
var/input_port_amount = 4
@@ -13,34 +14,40 @@
var/current_type
-GLOBAL_LIST_INIT(comp_combiner_options, list(
- COMP_COMBINER_ANY,
- PORT_TYPE_STRING,
- PORT_TYPE_NUMBER,
- PORT_TYPE_LIST,
- PORT_TYPE_ATOM,
- PORT_TYPE_SIGNAL,
-))
+/obj/item/circuit_component/combiner/populate_options()
+ var/static/component_options = list(
+ COMP_TYPE_ANY,
+ PORT_TYPE_STRING,
+ PORT_TYPE_NUMBER,
+ PORT_TYPE_LIST,
+ PORT_TYPE_ATOM,
+ PORT_TYPE_SIGNAL,
+ )
+ options = component_options
/obj/item/circuit_component/combiner/Initialize()
- options = GLOB.comp_combiner_options
. = ..()
- current_type = current_option
+ current_option = COMP_TYPE_ANY
+ current_type = COMP_TYPE_ANY
for(var/port_id in 1 to input_port_amount)
var/letter = ascii2text(text2ascii("A") + (port_id-1))
- add_input_port(letter, current_type)
- output_port = add_output_port("Output", current_type)
+ add_input_port(letter, PORT_TYPE_ANY)
+ output_port = add_output_port("Output", PORT_TYPE_ANY)
+
+/obj/item/circuit_component/combiner/Destroy()
+ output_port = null
+ return ..()
/obj/item/circuit_component/combiner/input_received(datum/port/input/port)
. = ..()
- if(current_type != current_option && (current_option != COMP_COMBINER_ANY || current_type != PORT_TYPE_ANY))
+ if(current_type != current_option && (current_option != COMP_TYPE_ANY || current_type != PORT_TYPE_ANY))
current_type = current_option
- if(current_type == COMP_COMBINER_ANY)
+ if(current_type == COMP_TYPE_ANY)
current_type = PORT_TYPE_ANY
for(var/datum/port/input/input_port as anything in input_ports)
input_port.set_datatype(current_type)
output_port.set_datatype(current_type)
- output_port.set_output(port?.input_value)
if(. || !port)
return TRUE
+ output_port.set_output(port.input_value)
diff --git a/code/modules/wiremod/components/utility/delay.dm b/code/modules/wiremod/components/utility/delay.dm
index ff659162d2a..7403bb41321 100644
--- a/code/modules/wiremod/components/utility/delay.dm
+++ b/code/modules/wiremod/components/utility/delay.dm
@@ -5,6 +5,7 @@
*/
/obj/item/circuit_component/delay
display_name = "Delay"
+ display_desc = "A component that delays a signal by a specified duration."
/// Amount to delay by
var/datum/port/input/delay_amount
diff --git a/code/modules/wiremod/components/utility/multiplexer.dm b/code/modules/wiremod/components/utility/multiplexer.dm
new file mode 100644
index 00000000000..9ea48e70a0d
--- /dev/null
+++ b/code/modules/wiremod/components/utility/multiplexer.dm
@@ -0,0 +1,66 @@
+/**
+ * # Combiner Component
+ *
+ * Combines multiple inputs into 1 output port.
+ */
+/obj/item/circuit_component/multiplexer
+ display_name = "Multiplexer"
+ display_desc = "A component that allows you to selectively choose which input port provides an output. The first port is the selector and takes a number between 1 and the maximum port amount."
+ circuit_flags = CIRCUIT_FLAG_INPUT_SIGNAL|CIRCUIT_FLAG_OUTPUT_SIGNAL
+
+ /// The port to select from, goes from 1 to input_port_amount
+ var/datum/port/input/input_port
+
+ /// The amount of input ports to have
+ var/input_port_amount = 4
+
+ var/datum/port/output/output_port
+
+ /// Current type of the ports
+ var/current_type
+
+ /// The multiplexer inputs. These are what get selected for the output by the input_port.
+ var/list/datum/port/input/multiplexer_inputs
+
+/obj/item/circuit_component/multiplexer/populate_options()
+ var/static/component_options = list(
+ COMP_TYPE_ANY,
+ PORT_TYPE_STRING,
+ PORT_TYPE_NUMBER,
+ PORT_TYPE_LIST,
+ PORT_TYPE_ATOM,
+ )
+ options = component_options
+
+/obj/item/circuit_component/multiplexer/Initialize()
+ . = ..()
+ current_option = COMP_TYPE_ANY
+ current_type = COMP_TYPE_ANY
+ input_port = add_input_port("Selector", PORT_TYPE_NUMBER, default = 1)
+ multiplexer_inputs = list()
+ for(var/port_id in 1 to input_port_amount)
+ multiplexer_inputs += add_input_port("Port [port_id]", PORT_TYPE_ANY)
+ output_port = add_output_port("Output", PORT_TYPE_ANY)
+
+/obj/item/circuit_component/multiplexer/Destroy()
+ output_port = null
+ multiplexer_inputs.Cut()
+ multiplexer_inputs = null
+ return ..()
+
+
+/obj/item/circuit_component/multiplexer/input_received(datum/port/input/port)
+ . = ..()
+ if(current_type != current_option && (current_option != COMP_TYPE_ANY || current_type != PORT_TYPE_ANY))
+ current_type = current_option
+ if(current_type == COMP_TYPE_ANY)
+ current_type = PORT_TYPE_ANY
+ for(var/datum/port/input/input_port as anything in multiplexer_inputs)
+ input_port.set_datatype(current_type)
+ output_port.set_datatype(current_type)
+
+ input_port.set_input(clamp(input_port.input_value || 1, 1, input_port_amount), FALSE)
+ if(.)
+ return TRUE
+ output_port.set_output(multiplexer_inputs[input_port.input_value].input_value)
+
diff --git a/code/modules/wiremod/components/utility/ram.dm b/code/modules/wiremod/components/utility/ram.dm
index 194f4474e54..9c8e120cd81 100644
--- a/code/modules/wiremod/components/utility/ram.dm
+++ b/code/modules/wiremod/components/utility/ram.dm
@@ -7,6 +7,7 @@
*/
/obj/item/circuit_component/ram
display_name = "RAM"
+ display_desc = "A component that retains a variable."
/// The input to store
var/datum/port/input/input_port
diff --git a/code/modules/wiremod/components/utility/typecheck.dm b/code/modules/wiremod/components/utility/typecheck.dm
index f939f116836..faef753aca5 100644
--- a/code/modules/wiremod/components/utility/typecheck.dm
+++ b/code/modules/wiremod/components/utility/typecheck.dm
@@ -5,6 +5,7 @@
*/
/obj/item/circuit_component/compare/typecheck
display_name = "Typecheck"
+ display_desc = "A component that checks the type of its input."
input_port_amount = 1
@@ -17,9 +18,16 @@ GLOBAL_LIST_INIT(comp_typecheck_options, list(
COMP_TYPECHECK_HUMAN,
))
-/obj/item/circuit_component/compare/typecheck/Initialize()
- options = GLOB.comp_typecheck_options
- return ..()
+/obj/item/circuit_component/compare/typecheck/populate_options()
+ var/static/component_options = list(
+ PORT_TYPE_STRING,
+ PORT_TYPE_NUMBER,
+ PORT_TYPE_LIST,
+ PORT_TYPE_ATOM,
+ COMP_TYPECHECK_MOB,
+ COMP_TYPECHECK_HUMAN,
+ )
+ options = component_options
/obj/item/circuit_component/compare/typecheck/do_comparisons(list/ports)
if(!length(ports))
diff --git a/code/modules/wiremod/integrated_circuit.dm b/code/modules/wiremod/integrated_circuit.dm
index 35e486adbaf..b04c85acafe 100644
--- a/code/modules/wiremod/integrated_circuit.dm
+++ b/code/modules/wiremod/integrated_circuit.dm
@@ -32,6 +32,15 @@
/// The ID that is authorized to unlock/lock the shell so that the circuit can/cannot be removed.
var/datum/weakref/owner_id
+ /// The current examined component. Used in IntegratedCircuit UI
+ var/datum/weakref/examined_component
+
+ /// X position of the examined_component
+ var/examined_rel_x = 0
+
+ /// Y position of the examined component
+ var/examined_rel_y = 0
+
/obj/item/integrated_circuit/Initialize()
. = ..()
RegisterSignal(src, COMSIG_ATOM_USB_CABLE_TRY_ATTACH, .proc/on_atom_usb_cable_try_attach)
@@ -44,7 +53,10 @@
for(var/obj/item/circuit_component/to_delete in attached_components)
remove_component(to_delete)
qdel(to_delete)
+ attached_components.Cut()
shell = null
+ examined_component = null
+ owner_id = null
QDEL_NULL(cell)
return ..()
@@ -228,6 +240,16 @@
.["display_name"] = display_name
+ var/obj/item/circuit_component/examined
+ if(examined_component)
+ examined = examined_component.resolve()
+
+ .["examined_name"] = examined?.display_name
+ .["examined_desc"] = examined?.display_desc
+ .["examined_notices"] = examined?.get_ui_notices()
+ .["examined_rel_x"] = examined_rel_x
+ .["examined_rel_y"] = examined_rel_y
+
/obj/item/integrated_circuit/ui_host(mob/user)
if(shell)
return shell
@@ -396,6 +418,17 @@
shell.name = initial(shell.name)
. = TRUE
+ if("set_examined_component")
+ var/component_id = text2num(params["component_id"])
+ if(!WITHIN_RANGE(component_id, attached_components))
+ return
+ examined_component = WEAKREF(attached_components[component_id])
+ examined_rel_x = text2num(params["x"])
+ examined_rel_y = text2num(params["y"])
+ . = TRUE
+ if("remove_examined_component")
+ examined_component = null
+ . = TRUE
/obj/item/integrated_circuit/proc/on_atom_usb_cable_try_attach(datum/source, obj/item/usb_cable/usb_cable, mob/user)
usb_cable.balloon_alert(user, "circuit needs to be in a compatible shell")
diff --git a/code/modules/wiremod/shell/compact_remote.dm b/code/modules/wiremod/shell/compact_remote.dm
index cc3b5327243..d1877771e40 100644
--- a/code/modules/wiremod/shell/compact_remote.dm
+++ b/code/modules/wiremod/shell/compact_remote.dm
@@ -22,6 +22,7 @@
/obj/item/circuit_component/compact_remote
display_name = "Compact Remote"
+ display_desc = "Used to receive inputs from the compact remote shell. Use the shell in hand to trigger the output signal."
/// Called when attack_self is called on the shell.
var/datum/port/output/signal
diff --git a/code/modules/wiremod/shell/controller.dm b/code/modules/wiremod/shell/controller.dm
index 84564986579..8df6782822b 100644
--- a/code/modules/wiremod/shell/controller.dm
+++ b/code/modules/wiremod/shell/controller.dm
@@ -23,6 +23,7 @@
/obj/item/circuit_component/controller
display_name = "Controller"
+ display_desc = "Used to receive inputs from the controller shell. Use the shell in hand to trigger the output signal. Alt-click for the alternate signal. Right click for the extra signal."
/// The three separate buttons that are called in attack_hand on the shell.
var/datum/port/output/signal
diff --git a/code/modules/wiremod/shell/drone.dm b/code/modules/wiremod/shell/drone.dm
index c523c19d018..5944b662302 100644
--- a/code/modules/wiremod/shell/drone.dm
+++ b/code/modules/wiremod/shell/drone.dm
@@ -27,6 +27,7 @@
/obj/item/circuit_component/bot_circuit
display_name = "Drone"
+ display_desc = "Used to send movement output signals to the drone shell."
/// The inputs to allow for the drone to move
var/datum/port/input/north
@@ -41,7 +42,7 @@
COOLDOWN_DECLARE(west_delay)
/// Delay between each movement
- var/move_delay = COMP_CLOCK_DELAY
+ var/move_delay = PORT_INPUT_RECEIVE_DELAY
/obj/item/circuit_component/bot_circuit/Initialize()
. = ..()
diff --git a/code/modules/wiremod/shell/moneybot.dm b/code/modules/wiremod/shell/moneybot.dm
index 06af6971898..cceef55b0bc 100644
--- a/code/modules/wiremod/shell/moneybot.dm
+++ b/code/modules/wiremod/shell/moneybot.dm
@@ -38,6 +38,7 @@
/obj/item/circuit_component/money_dispenser
display_name = "Money Dispenser"
+ display_desc = "Used to dispense money from the money bot. Money is taken from the internal storage of money."
circuit_flags = CIRCUIT_FLAG_INPUT_SIGNAL|CIRCUIT_FLAG_OUTPUT_SIGNAL
/// The amount of money to dispense
@@ -86,6 +87,7 @@
/obj/item/circuit_component/money_bot
display_name = "Money Bot"
var/obj/structure/money_bot/attached_bot
+ display_desc = "Used to receive input signals when money is inserted into the money bot shell and also keep track of the total money in the shell."
/// Total money in the shell
var/datum/port/output/total_money
diff --git a/tgstation.dme b/tgstation.dme
index a5de9f732ee..396512a40d2 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -3631,6 +3631,7 @@
#include "code\modules\wiremod\components\utility\clock.dm"
#include "code\modules\wiremod\components\utility\combiner.dm"
#include "code\modules\wiremod\components\utility\delay.dm"
+#include "code\modules\wiremod\components\utility\multiplexer.dm"
#include "code\modules\wiremod\components\utility\ram.dm"
#include "code\modules\wiremod\components\utility\typecheck.dm"
#include "code\modules\wiremod\preset\hello_world.dm"
diff --git a/tgui/packages/tgui/interfaces/IntegratedCircuit/CircuitInfo.js b/tgui/packages/tgui/interfaces/IntegratedCircuit/CircuitInfo.js
new file mode 100644
index 00000000000..8fd1263b7aa
--- /dev/null
+++ b/tgui/packages/tgui/interfaces/IntegratedCircuit/CircuitInfo.js
@@ -0,0 +1,33 @@
+import { Button, Section, Stack, Box } from '../../components';
+
+export const CircuitInfo = (props, context) => {
+ const {
+ name,
+ desc,
+ notices,
+ ...rest
+ } = props;
+ return (
+
+
+
+ {desc}
+
+
+
+ {notices.map((val, index) => (
+
+
+
+ ))}
+
+
+
+
+ );
+};
diff --git a/tgui/packages/tgui/interfaces/IntegratedCircuit.js b/tgui/packages/tgui/interfaces/IntegratedCircuit/index.js
similarity index 90%
rename from tgui/packages/tgui/interfaces/IntegratedCircuit.js
rename to tgui/packages/tgui/interfaces/IntegratedCircuit/index.js
index ab19e831f46..f5928b09189 100644
--- a/tgui/packages/tgui/interfaces/IntegratedCircuit.js
+++ b/tgui/packages/tgui/interfaces/IntegratedCircuit/index.js
@@ -1,13 +1,14 @@
-import { useBackend, useLocalState } from '../backend';
-import { Box, Stack, Icon, Button, Input, Flex, NumberInput, Dropdown, InfinitePlane, Tooltip } from '../components';
+import { useBackend, useLocalState } from '../../backend';
+import { Box, Stack, Icon, Button, Input, Flex, NumberInput, Dropdown, InfinitePlane, Tooltip } from '../../components';
import { Component, createRef } from 'inferno';
-import { Window } from '../layouts';
-import { CSS_COLORS } from '../constants';
-import { classes, shallowDiffers } from '../../common/react';
-import { resolveAsset } from '../assets';
+import { Window } from '../../layouts';
+import { CSS_COLORS } from '../../constants';
+import { classes, shallowDiffers } from '../../../common/react';
+import { resolveAsset } from '../../assets';
+import { CircuitInfo } from './CircuitInfo';
const NULL_REF = "[0x0]";
-const SVG_Y_OFFSET = -32;
+const ABSOLUTE_Y_OFFSET = -32;
const SVG_CURVE_INTENSITY = 64;
const BasicInput = (props, context) => {
@@ -127,6 +128,7 @@ export class IntegratedCircuit extends Component {
locations: {},
};
this.handlePortLocation = this.handlePortLocation.bind(this);
+ this.handleMouseDown = this.handleMouseDown.bind(this);
}
// Helper function to get an element's exact position
@@ -141,7 +143,7 @@ export class IntegratedCircuit extends Component {
}
return {
x: xPos,
- y: yPos + SVG_Y_OFFSET,
+ y: yPos + ABSOLUTE_Y_OFFSET,
};
}
@@ -166,9 +168,33 @@ export class IntegratedCircuit extends Component {
this.setState({ locations: locations });
}
+ componentDidMount() {
+ window.addEventListener("mousedown", this.handleMouseDown);
+ }
+
+ componentWillUnmount() {
+ window.removeEventListener("mousedown", this.handleMouseDown);
+ }
+
+ handleMouseDown(event) {
+ const { act, data } = useBackend(this.context);
+ const { examined_name } = data;
+ if (examined_name) {
+ act("remove_examined_component");
+ }
+ }
+
render() {
const { act, data } = useBackend(this.context);
- const { components, display_name } = data;
+ const {
+ components,
+ display_name,
+ examined_name,
+ examined_desc,
+ examined_notices,
+ examined_rel_x,
+ examined_rel_y,
+ } = data;
const { locations } = this.state;
return (
@@ -206,6 +232,17 @@ export class IntegratedCircuit extends Component {
))}
+ {!!examined_name && (
+
+ )}
);
@@ -414,6 +451,18 @@ export class ObjectComponent extends Component {
/>
)}
+
+
{!!removable && (