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 && (