[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>
This commit is contained in:
SkyratBot
2021-06-23 22:50:59 +01:00
committed by GitHub
co-authored by Watermelon914
parent 1a2f4f5d69
commit 5ab9aba9d4
41 changed files with 398 additions and 95 deletions
+3 -3
View File
@@ -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)
+11 -2
View File
@@ -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.
@@ -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."
@@ -223,6 +223,7 @@
"comp_length",
"comp_light",
"comp_logic",
"comp_multiplexer",
"comp_not",
"comp_radio",
"comp_ram",
+36
View File
@@ -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",
))
@@ -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)
@@ -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
@@ -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
@@ -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)
@@ -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)
@@ -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
@@ -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)
@@ -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
@@ -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
@@ -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
@@ -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))
@@ -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)
@@ -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
@@ -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
+8 -10
View File
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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)
@@ -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
@@ -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)
@@ -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)
@@ -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
@@ -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)
@@ -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
@@ -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))
@@ -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")
@@ -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
+1
View File
@@ -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
+2 -1
View File
@@ -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()
. = ..()
+2
View File
@@ -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
+1
View File
@@ -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"
@@ -0,0 +1,33 @@
import { Button, Section, Stack, Box } from '../../components';
export const CircuitInfo = (props, context) => {
const {
name,
desc,
notices,
...rest
} = props;
return (
<Box {...rest}>
<Stack fill vertical justify="space-around">
<Stack.Item maxWidth="200px">
{desc}
</Stack.Item>
<Stack.Item>
<Stack vertical>
{notices.map((val, index) => (
<Stack.Item key={index}>
<Button
content={val.content}
color={val.color}
icon={val.icon}
fluid
/>
</Stack.Item>
))}
</Stack>
</Stack.Item>
</Stack>
</Box>
);
};
@@ -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 {
))}
<Connections locations={locations} />
</InfinitePlane>
{!!examined_name && (
<CircuitInfo
position="absolute"
className="CircuitInfo__Examined"
top={`${examined_rel_y}px`}
left={`${examined_rel_x}px`}
name={examined_name}
desc={examined_desc}
notices={examined_notices}
/>
)}
</Window.Content>
</Window>
);
@@ -414,6 +451,18 @@ export class ObjectComponent extends Component {
/>
</Stack.Item>
)}
<Stack.Item>
<Button
color="transparent"
icon="info"
compact
onClick={(e) => act("set_examined_component", {
component_id: index,
x: e.pageX,
y: e.pageY + ABSOLUTE_Y_OFFSET,
})}
/>
</Stack.Item>
{!!removable && (
<Stack.Item>
<Button
@@ -3,6 +3,15 @@
$bg-map: colors.$bg-map !default;
.CircuitInfo__Examined {
background-color:rgba(0, 0, 0, 1);
padding: 8px;
border-radius: 5px;
user-select: none;
pointer-events: none;
}
.ObjectComponent__Titlebar {
border-top-left-radius: 12px;
border-top-right-radius: 12px;