diff --git a/code/__DEFINES/wiremod.dm b/code/__DEFINES/wiremod.dm
index c65a58e50ed..90bc8f308f0 100644
--- a/code/__DEFINES/wiremod.dm
+++ b/code/__DEFINES/wiremod.dm
@@ -26,6 +26,8 @@
#define PORT_TYPE_LIST "list"
/// Table datatype. Derivative of list, contains other lists with matching columns.
#define PORT_TYPE_TABLE "table"
+/// Options datatype. Derivative of string.
+#define PORT_TYPE_OPTION "option"
// Other datatypes
/// Atom datatype
@@ -114,6 +116,10 @@
#define COMP_PROC_GLOBAL "Global"
#define COMP_PROC_OBJECT "Object"
+// Bar overlay component
+#define COMP_BAR_OVERLAY_VERTICAL "Vertical"
+#define COMP_BAR_OVERLAY_HORIZONTAL "Horizontal"
+
// Shells
/// Whether a circuit is stuck on a shell and cannot be removed (by a user)
@@ -148,3 +154,9 @@
#define CIRCUIT_FLAG_ADMIN (1<<3)
/// This circuit component does not show in the menu.
#define CIRCUIT_FLAG_HIDDEN (1<<4)
+
+// Datatype flags
+/// The datatype supports manual inputs
+#define DATATYPE_FLAG_ALLOW_MANUAL_INPUT (1<<0)
+/// The datatype won't update the value when it is connected to the port
+#define DATATYPE_FLAG_AVOID_VALUE_UPDATE (1<<1)
diff --git a/code/game/machinery/computer/security.dm b/code/game/machinery/computer/security.dm
index 5ea01dcb094..d80cceb85ee 100644
--- a/code/game/machinery/computer/security.dm
+++ b/code/game/machinery/computer/security.dm
@@ -107,8 +107,8 @@
/// The targets to set the status of.
var/datum/port/input/targets
- /// Sets the new status of the targets. If set to null, the status is taken from the options.
- var/datum/port/input/new_status
+ /// Sets the new status of the targets.
+ var/datum/port/input/option/new_status
/// Returns the new status set once the setting is complete. Good for locating errors.
var/datum/port/output/new_status_set
@@ -135,12 +135,11 @@
COMP_STATE_DISCHARGED,
COMP_STATE_NONE,
)
- options = component_options
+ new_status = add_option_port("Arrest Options", component_options)
/obj/item/circuit_component/arrest_console_arrest/Initialize()
. = ..()
targets = add_input_port("Targets", PORT_TYPE_TABLE)
- new_status = add_input_port("New Status", PORT_TYPE_STRING)
new_status_set = add_output_port("Set Status", PORT_TYPE_STRING)
on_fail = add_output_port("Failed", PORT_TYPE_SIGNAL)
@@ -154,8 +153,6 @@
return
var/status_to_set = new_status.input_value
- if(!status_to_set || !(status_to_set in options))
- status_to_set = current_option
new_status_set.set_output(status_to_set)
var/list/target_table = targets.input_value
diff --git a/code/modules/atmospherics/machinery/airalarm.dm b/code/modules/atmospherics/machinery/airalarm.dm
index d02b4fc28d4..ea6ea75b0b4 100644
--- a/code/modules/atmospherics/machinery/airalarm.dm
+++ b/code/modules/atmospherics/machinery/airalarm.dm
@@ -891,6 +891,8 @@
display_name = "Air Alarm"
desc = "Controls levels of gases and their temperature as well as all vents and scrubbers in the room."
+ var/datum/port/input/option/air_alarm_options
+
var/datum/port/input/min_2
var/datum/port/input/min_1
var/datum/port/input/max_1
@@ -919,24 +921,18 @@
/obj/item/circuit_component/air_alarm/populate_options()
var/static/list/component_options
- var/static/list/options_to_key
if(!component_options)
component_options = list(
- "Pressure",
- "Temperature"
- )
- options_to_key = list(
"Pressure" = "pressure",
"Temperature" = "temperature"
)
for(var/gas_id in GLOB.meta_gas_info)
- component_options.Add(GLOB.meta_gas_info[gas_id][META_GAS_NAME])
- options_to_key[GLOB.meta_gas_info[gas_id][META_GAS_NAME]] = gas_id2path(gas_id)
+ component_options[GLOB.meta_gas_info[gas_id][META_GAS_NAME]] = gas_id2path(gas_id)
- options = component_options
- options_map = options_to_key
+ air_alarm_options = add_option_port("Air Alarm Options", component_options)
+ options_map = component_options
/obj/item/circuit_component/air_alarm/register_usb_parent(atom/movable/parent)
. = ..()
@@ -953,6 +949,8 @@
if(. || !connected_alarm || connected_alarm.locked)
return
+ var/current_option = air_alarm_options.input_value
+
if(COMPONENT_TRIGGERED_BY(request_data, port))
var/turf/alarm_turf = get_turf(connected_alarm)
var/datum/gas_mixture/environment = alarm_turf.return_air()
diff --git a/code/modules/wiremod/component.dm b/code/modules/wiremod/component.dm
index ffb5a897772..d7bab2838f9 100644
--- a/code/modules/wiremod/component.dm
+++ b/code/modules/wiremod/component.dm
@@ -42,31 +42,28 @@
/// The power usage whenever this component receives an input
var/power_usage_per_input = 1
- /// The current selected option
- var/current_option
- /// The options that this component can take on. Limited to strings
- var/list/options
-
// Whether the component is removable or not. Only affects user UI
var/removable = TRUE
// Defines which shells support this component. Only used as an informational guide, does not restrict placing these components in circuits.
var/required_shells = null
+/// Called when the option ports should be set up
+/obj/item/circuit_component/proc/populate_options()
+ return
+
+/// Extension of add_input_port. Simplifies the code to make an option port to reduce boilerplate
+/obj/item/circuit_component/proc/add_option_port(name, list/list_to_use)
+ return add_input_port(name, PORT_TYPE_OPTION, port_type = /datum/port/input/option, extra_args = list("possible_options" = list_to_use))
+
/obj/item/circuit_component/Initialize()
. = ..()
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)
@@ -120,17 +117,6 @@
for(var/datum/port/input/port_to_disconnect as anything in input_ports)
port_to_disconnect.disconnect()
-/**
- * Sets the option on this component
- *
- * Can only be a value from the options variable
- * Arguments:
- * * option - The option that has been switched to.
- */
-/obj/item/circuit_component/proc/set_option(option)
- current_option = option
- TRIGGER_CIRCUIT_COMPONENT(src, null)
-
/**
* Adds an input port and returns it
*
@@ -139,8 +125,12 @@
* * type - The datatype it handles
* * trigger - Whether this input port triggers an update on the component when updated.
*/
-/obj/item/circuit_component/proc/add_input_port(name, type, trigger = TRUE, default = null, index = null)
- var/datum/port/input/input_port = new(src, name, type, trigger, default)
+/obj/item/circuit_component/proc/add_input_port(name, type, trigger = TRUE, default = null, index = null, port_type = /datum/port/input, extra_args = null)
+ var/list/arguments = list(src)
+ arguments += args
+ if(extra_args)
+ arguments += extra_args
+ var/datum/port/input/input_port = new port_type(arglist(arguments))
if(index)
input_ports.Insert(index, input_port)
else
@@ -169,7 +159,9 @@
* * type - The datatype it handles.
*/
/obj/item/circuit_component/proc/add_output_port(name, type)
- var/datum/port/output/output_port = new(src, name, type)
+ var/list/arguments = list(src)
+ arguments += args
+ var/datum/port/output/output_port = new(arglist(arguments))
output_ports += output_port
return output_port
diff --git a/code/modules/wiremod/components/abstract/compare.dm b/code/modules/wiremod/components/abstract/compare.dm
index 6d10ac7b56c..ef6ba171b74 100644
--- a/code/modules/wiremod/components/abstract/compare.dm
+++ b/code/modules/wiremod/components/abstract/compare.dm
@@ -19,11 +19,13 @@
/// The result from the output
var/datum/port/output/result
+ var/list/datum/port/input/compare_ports = list()
+
/obj/item/circuit_component/compare/Initialize()
. = ..()
for(var/port_id in 1 to input_port_amount)
var/letter = ascii2text(text2ascii("A") + (port_id-1))
- add_input_port(letter, PORT_TYPE_ANY)
+ compare_ports += add_input_port(letter, PORT_TYPE_ANY)
load_custom_ports()
compare = add_input_port("Compare", PORT_TYPE_SIGNAL)
@@ -43,11 +45,7 @@
if(.)
return
- var/list/ports = input_ports.Copy()
- if(input_port_amount)
- ports.Cut(input_port_amount+1)
-
- var/logic_result = do_comparisons(ports)
+ var/logic_result = do_comparisons(compare_ports)
if(COMPONENT_TRIGGERED_BY(compare, port))
if(logic_result)
true.set_output(COMPONENT_SIGNAL)
diff --git a/code/modules/wiremod/components/action/radio.dm b/code/modules/wiremod/components/action/radio.dm
index 0347d414b58..7e96f9284c3 100644
--- a/code/modules/wiremod/components/action/radio.dm
+++ b/code/modules/wiremod/components/action/radio.dm
@@ -7,6 +7,9 @@
display_name = "Radio"
desc = "A component that can listen and send frequencies. If set to private, the component will only receive signals from other components attached to circuitboards with the same owner id."
+ /// The publicity options. Controls whether it's public or private.
+ var/datum/port/input/option/public_options
+
/// Frequency input
var/datum/port/input/freq
/// Signal input
@@ -22,7 +25,7 @@
COMP_RADIO_PUBLIC,
COMP_RADIO_PRIVATE,
)
- options = component_options
+ public_options = add_option_port("Encryption Options", component_options)
/obj/item/circuit_component/radio/Initialize()
. = ..()
@@ -59,7 +62,7 @@
if(signal.data["code"] != round(code.input_value || 0))
return
- if(current_option == COMP_RADIO_PRIVATE && parent?.owner_id != signal.data["key"])
+ if(public_options.input_value == COMP_RADIO_PRIVATE && parent?.owner_id != signal.data["key"])
return
trigger_output.set_output(COMPONENT_SIGNAL)
diff --git a/code/modules/wiremod/components/action/soundemitter.dm b/code/modules/wiremod/components/action/soundemitter.dm
index ac644e15de6..08730bb3f18 100644
--- a/code/modules/wiremod/components/action/soundemitter.dm
+++ b/code/modules/wiremod/components/action/soundemitter.dm
@@ -8,6 +8,9 @@
desc = "A component that emits a sound when it receives an input. The frequency is a multiplier which determines the speed at which the sound is played"
circuit_flags = CIRCUIT_FLAG_INPUT_SIGNAL|CIRCUIT_FLAG_OUTPUT_SIGNAL
+ /// Sound to play
+ var/datum/port/input/option/sound_file
+
/// Volume of the sound when played
var/datum/port/input/volume
@@ -40,7 +43,7 @@
COMP_SOUND_WARN,
COMP_SOUND_SLOWCLAP,
)
- options = component_options
+ sound_file = add_option_port("Sound Option", component_options)
var/static/options_to_sound = list(
COMP_SOUND_BUZZ = 'sound/machines/buzz-sigh.ogg',
@@ -65,7 +68,7 @@
if(TIMER_COOLDOWN_CHECK(parent, COOLDOWN_CIRCUIT_SOUNDEMITTER))
return
- var/sound_to_play = options_map[current_option]
+ var/sound_to_play = options_map[sound_file.input_value]
if(!sound_to_play)
return
diff --git a/code/modules/wiremod/components/admin/proccall.dm b/code/modules/wiremod/components/admin/proccall.dm
index 9af6d0571c7..42b9f0d7f8d 100644
--- a/code/modules/wiremod/components/admin/proccall.dm
+++ b/code/modules/wiremod/components/admin/proccall.dm
@@ -5,9 +5,11 @@
*/
/obj/item/circuit_component/proccall
display_name = "Proc Call"
- desc = "A component that gets a variable on an object."
+ desc = "A component that calls a proc on an object."
circuit_flags = CIRCUIT_FLAG_INPUT_SIGNAL|CIRCUIT_FLAG_OUTPUT_SIGNAL|CIRCUIT_FLAG_ADMIN
+ var/datum/port/input/option/proccall_options
+
/// Entity to proccall on
var/datum/port/input/entity
@@ -26,7 +28,7 @@
COMP_PROC_GLOBAL,
)
- options = component_options
+ proccall_options = add_option_port("Proccall Options", component_options)
/obj/item/circuit_component/proccall/Initialize()
. = ..()
@@ -42,7 +44,7 @@
return
var/called_on
- if(current_option == COMP_PROC_OBJECT)
+ if(proccall_options.input_value == COMP_PROC_OBJECT)
called_on = entity.input_value
else
called_on = GLOBAL_PROC
diff --git a/code/modules/wiremod/components/admin/spawn.dm b/code/modules/wiremod/components/admin/spawn.dm
index 555b5b5151e..fbf9ccea5ff 100644
--- a/code/modules/wiremod/components/admin/spawn.dm
+++ b/code/modules/wiremod/components/admin/spawn.dm
@@ -5,7 +5,7 @@
*/
/obj/item/circuit_component/spawn_atom
display_name = "Spawn Atom"
- desc = "A component that returns the value of a list at a given index."
+ desc = "Spawns an atom at a desired location"
circuit_flags = CIRCUIT_FLAG_INPUT_SIGNAL|CIRCUIT_FLAG_OUTPUT_SIGNAL|CIRCUIT_FLAG_ADMIN
/// The input path to convert into a typepath
diff --git a/code/modules/wiremod/components/admin/to_type.dm b/code/modules/wiremod/components/admin/to_type.dm
index 3dc23e21293..266763fba8d 100644
--- a/code/modules/wiremod/components/admin/to_type.dm
+++ b/code/modules/wiremod/components/admin/to_type.dm
@@ -5,7 +5,7 @@
*/
/obj/item/circuit_component/to_type
display_name = "String To Type"
- desc = "A component that returns the value of a list at a given index."
+ desc = "Converts a string into a typepath. Useful for adding components."
circuit_flags = CIRCUIT_FLAG_INPUT_SIGNAL|CIRCUIT_FLAG_OUTPUT_SIGNAL|CIRCUIT_FLAG_ADMIN
/// The input path to convert into a typepath
diff --git a/code/modules/wiremod/components/hud/bar_overlay.dm b/code/modules/wiremod/components/hud/bar_overlay.dm
index 004d7b38e34..52245767a32 100644
--- a/code/modules/wiremod/components/hud/bar_overlay.dm
+++ b/code/modules/wiremod/components/hud/bar_overlay.dm
@@ -5,42 +5,40 @@
* Requires a BCI shell.
*/
-#define BAR_OVERLAY_LIMIT 10
-
/obj/item/circuit_component/object_overlay/bar
display_name = "Bar Overlay"
desc = "Requires a BCI shell. A component that shows a bar overlay ontop of an object from a range of 0 to 100."
+ var/datum/port/input/option/bar_overlay_options
var/datum/port/input/bar_number
+ var/overlay_limit = 10
+
/obj/item/circuit_component/object_overlay/bar/Initialize()
. = ..()
bar_number = add_input_port("Number", PORT_TYPE_NUMBER)
/obj/item/circuit_component/object_overlay/bar/populate_options()
var/static/component_options_bar = list(
- "Vertical",
- "Horizontal"
+ COMP_BAR_OVERLAY_VERTICAL = "barvert",
+ COMP_BAR_OVERLAY_HORIZONTAL = "barhoriz"
)
- options = component_options_bar
-
- var/static/options_to_icons_bar = list(
- "Vertical" = "barvert",
- "Horizontal" = "barhoriz"
- )
- options_map = options_to_icons_bar
+ bar_overlay_options = add_option_port("Bar Overlay Options", component_options_bar)
+ options_map = component_options_bar
/obj/item/circuit_component/object_overlay/bar/show_to_owner(atom/target_atom, mob/living/owner)
- if(LAZYLEN(active_overlays) >= BAR_OVERLAY_LIMIT)
+ if(LAZYLEN(active_overlays) >= overlay_limit)
return
+ var/current_option = bar_overlay_options.input_value
+
if(active_overlays[target_atom])
QDEL_NULL(active_overlays[target_atom])
var/number_clear = clamp(bar_number.input_value, 0, 100)
- if(current_option == "Horizontal")
+ if(current_option == COMP_BAR_OVERLAY_HORIZONTAL)
number_clear = round(number_clear / 6.25) * 6.25
- else if(current_option == "Vertical")
+ else if(current_option == COMP_BAR_OVERLAY_VERTICAL)
number_clear = round(number_clear / 10) * 10
var/image/cool_overlay = image(icon = 'icons/hud/screen_bci.dmi', loc = target_atom, icon_state = "[options_map[current_option]][number_clear]", layer = RIPPLE_LAYER)
@@ -56,5 +54,3 @@
cool_overlay,
owner,
))
-
-#undef BAR_OVERLAY_LIMIT
diff --git a/code/modules/wiremod/components/hud/object_overlay.dm b/code/modules/wiremod/components/hud/object_overlay.dm
index 7b5c0477831..7d1fb63463f 100644
--- a/code/modules/wiremod/components/hud/object_overlay.dm
+++ b/code/modules/wiremod/components/hud/object_overlay.dm
@@ -13,6 +13,8 @@
required_shells = list(/obj/item/organ/cyberimp/bci)
+ var/datum/port/input/option/object_overlay_options
+
/// Target atom
var/datum/port/input/target
@@ -44,20 +46,6 @@
/obj/item/circuit_component/object_overlay/populate_options()
var/static/component_options = list(
- "Corners (Blue)",
- "Corners (Red)",
- "Circle (Blue)",
- "Circle (Red)",
- "Small Corners (Blue)",
- "Small Corners (Red)",
- "Triangle (Blue)",
- "Triangle (Red)",
- "HUD mark (Blue)",
- "HUD mark (Red)"
- )
- options = component_options
-
- var/static/options_to_icons = list(
"Corners (Blue)" = "hud_corners",
"Corners (Red)" = "hud_corners_red",
"Circle (Blue)" = "hud_circle",
@@ -69,7 +57,8 @@
"HUD mark (Blue)" = "hud_mark",
"HUD mark (Red)" = "hud_mark_red"
)
- options_map = options_to_icons
+ object_overlay_options = add_option_port("Object", component_options)
+ options_map = component_options
/obj/item/circuit_component/object_overlay/register_shell(atom/movable/shell)
if(istype(shell, /obj/item/organ/cyberimp/bci))
@@ -106,7 +95,7 @@
if(active_overlays[target_atom])
QDEL_NULL(active_overlays[target_atom])
- var/image/cool_overlay = image(icon = 'icons/hud/screen_bci.dmi', loc = target_atom, icon_state = options_map[current_option], layer = RIPPLE_LAYER)
+ var/image/cool_overlay = image(icon = 'icons/hud/screen_bci.dmi', loc = target_atom, icon_state = options_map[object_overlay_options.input_value], layer = RIPPLE_LAYER)
if(image_pixel_x.input_value)
cool_overlay.pixel_x = image_pixel_x.input_value
diff --git a/code/modules/wiremod/components/list/select.dm b/code/modules/wiremod/components/list/select.dm
index 34bd15e2553..510d9d73b38 100644
--- a/code/modules/wiremod/components/list/select.dm
+++ b/code/modules/wiremod/components/list/select.dm
@@ -8,6 +8,8 @@
desc = "A component used with USB cables that can perform select queries on a list based on the column name selected. The values are then compared with the comparison input."
circuit_flags = CIRCUIT_FLAG_INPUT_SIGNAL|CIRCUIT_FLAG_OUTPUT_SIGNAL
+ var/datum/port/input/option/comparison_options
+
/// The list to perform the filter on
var/datum/port/input/received_table
@@ -31,7 +33,7 @@
COMP_COMPARISON_GREATER_THAN_OR_EQUAL,
COMP_COMPARISON_LESS_THAN_OR_EQUAL,
)
- options = component_options
+ comparison_options = add_option_port("Comparison Options", component_options)
/obj/item/circuit_component/select/Initialize()
. = ..()
@@ -43,6 +45,8 @@
/obj/item/circuit_component/select/input_received(datum/port/input/port)
. = ..()
+ var/current_option = comparison_options.input_value
+
switch(current_option)
if(COMP_COMPARISON_EQUAL, COMP_COMPARISON_NOT_EQUAL)
if(current_type != PORT_TYPE_ANY)
diff --git a/code/modules/wiremod/components/math/arithmetic.dm b/code/modules/wiremod/components/math/arithmetic.dm
index dd8ceb1ae7d..61a04a52474 100644
--- a/code/modules/wiremod/components/math/arithmetic.dm
+++ b/code/modules/wiremod/components/math/arithmetic.dm
@@ -11,9 +11,12 @@
/// The amount of input ports to have
var/input_port_amount = 4
+ var/datum/port/input/option/arithmetic_option
+
/// The result from the output
var/datum/port/output/output
+ var/list/arithmetic_ports
circuit_flags = CIRCUIT_FLAG_INPUT_SIGNAL|CIRCUIT_FLAG_OUTPUT_SIGNAL
/obj/item/circuit_component/arithmetic/populate_options()
@@ -25,13 +28,14 @@
COMP_ARITHMETIC_MIN,
COMP_ARITHMETIC_MAX,
)
- options = component_options
+ arithmetic_option = add_option_port("Arithmetic Option", component_options)
/obj/item/circuit_component/arithmetic/Initialize()
. = ..()
+ arithmetic_ports = list()
for(var/port_id in 1 to input_port_amount)
var/letter = ascii2text(text2ascii("A") + (port_id-1))
- add_input_port(letter, PORT_TYPE_NUMBER)
+ arithmetic_ports += add_input_port(letter, PORT_TYPE_NUMBER)
output = add_output_port("Output", PORT_TYPE_NUMBER)
@@ -40,10 +44,8 @@
if(.)
return
- var/list/ports = input_ports.Copy()
- var/datum/port/input/first_port = ports[1]
- ports -= first_port
- ports -= trigger_input
+ var/list/ports = arithmetic_ports.Copy()
+ var/datum/port/input/first_port = popleft(ports)
var/result = first_port.input_value
for(var/datum/port/input/input_port as anything in ports)
@@ -51,7 +53,7 @@
if(isnull(value))
continue
- switch(current_option)
+ switch(arithmetic_option.input_value)
if(COMP_ARITHMETIC_ADD)
result += value
if(COMP_ARITHMETIC_SUBTRACT)
diff --git a/code/modules/wiremod/components/math/comparison.dm b/code/modules/wiremod/components/math/comparison.dm
index 6437d73135d..2e1a4c0ba2b 100644
--- a/code/modules/wiremod/components/math/comparison.dm
+++ b/code/modules/wiremod/components/math/comparison.dm
@@ -7,6 +7,8 @@
display_name = "Comparison"
desc = "A component that compares two objects."
+ var/datum/port/input/option/comparison_option
+
input_port_amount = 2
var/current_type = PORT_TYPE_ANY
@@ -19,20 +21,20 @@
COMP_COMPARISON_GREATER_THAN_OR_EQUAL,
COMP_COMPARISON_LESS_THAN_OR_EQUAL,
)
- options = component_options
+ comparison_option = add_option_port("Comparison Option", component_options)
/obj/item/circuit_component/compare/comparison/input_received(datum/port/input/port)
- switch(current_option)
+ switch(comparison_option.input_value)
if(COMP_COMPARISON_EQUAL, COMP_COMPARISON_NOT_EQUAL)
if(current_type != PORT_TYPE_ANY)
current_type = PORT_TYPE_ANY
- input_ports[1].set_datatype(PORT_TYPE_ANY)
- input_ports[2].set_datatype(PORT_TYPE_ANY)
+ compare_ports[1].set_datatype(PORT_TYPE_ANY)
+ compare_ports[2].set_datatype(PORT_TYPE_ANY)
else
if(current_type != PORT_TYPE_NUMBER)
current_type = PORT_TYPE_NUMBER
- input_ports[1].set_datatype(PORT_TYPE_NUMBER)
- input_ports[2].set_datatype(PORT_TYPE_NUMBER)
+ compare_ports[1].set_datatype(PORT_TYPE_NUMBER)
+ compare_ports[2].set_datatype(PORT_TYPE_NUMBER)
return ..()
@@ -41,8 +43,9 @@
return FALSE
// Comparison component only compares the first two ports
- var/input1 = input_ports[1].input_value
- var/input2 = input_ports[2].input_value
+ var/input1 = compare_ports[1].input_value
+ var/input2 = compare_ports[2].input_value
+ var/current_option = comparison_option.input_value
switch(current_option)
if(COMP_COMPARISON_EQUAL)
diff --git a/code/modules/wiremod/components/math/logic.dm b/code/modules/wiremod/components/math/logic.dm
index e87669b8da9..5b4e8e9b49e 100644
--- a/code/modules/wiremod/components/math/logic.dm
+++ b/code/modules/wiremod/components/math/logic.dm
@@ -7,16 +7,20 @@
display_name = "Logic"
desc = "A component with 'and' and 'or' capabilities."
+ var/datum/port/input/option/logic_options
+
/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
+ logic_options = add_option_port("Logic Options", component_options)
/obj/item/circuit_component/compare/logic/do_comparisons(list/ports)
. = FALSE
+ var/current_option = logic_options.input_value
+
// Used by XOR
var/total_ports = 0
var/total_true_ports = 0
diff --git a/code/modules/wiremod/components/string/textcase.dm b/code/modules/wiremod/components/string/textcase.dm
index 346d6f7dc74..9af54497af9 100644
--- a/code/modules/wiremod/components/string/textcase.dm
+++ b/code/modules/wiremod/components/string/textcase.dm
@@ -7,6 +7,8 @@
display_name = "Text Case"
desc = "A component that makes its input uppercase or lowercase."
+ var/datum/port/input/option/textcase_options
+
/// The input port
var/datum/port/input/input_port
@@ -20,7 +22,7 @@
COMP_TEXT_LOWER,
COMP_TEXT_UPPER,
)
- options = component_options
+ textcase_options = add_option_port("Textcase Options", component_options)
/obj/item/circuit_component/textcase/Initialize()
. = ..()
@@ -37,7 +39,7 @@
return
var/result
- switch(current_option)
+ switch(textcase_options.input_value)
if(COMP_TEXT_LOWER)
result = lowertext(value)
if(COMP_TEXT_UPPER)
diff --git a/code/modules/wiremod/components/utility/combiner.dm b/code/modules/wiremod/components/utility/combiner.dm
index d803dc3632d..1954da7eb6d 100644
--- a/code/modules/wiremod/components/utility/combiner.dm
+++ b/code/modules/wiremod/components/utility/combiner.dm
@@ -9,9 +9,11 @@
/// The amount of input ports to have
var/input_port_amount = 4
+ var/datum/port/input/option/combiner_options
var/datum/port/output/output_port
+ var/list/combiner_ports = list()
var/current_type
/obj/item/circuit_component/combiner/populate_options()
@@ -23,21 +25,21 @@
PORT_TYPE_ATOM,
PORT_TYPE_SIGNAL,
)
- options = component_options
+ combiner_options = add_option_port("Combiner Options", component_options)
/obj/item/circuit_component/combiner/Initialize()
. = ..()
- current_type = current_option
+ current_type = combiner_options.input_value
for(var/port_id in 1 to input_port_amount)
var/letter = ascii2text(text2ascii("A") + (port_id-1))
- add_input_port(letter, current_option)
- output_port = add_output_port("Output", current_option)
+ combiner_ports += add_input_port(letter, current_type)
+ output_port = add_output_port("Output", current_type)
/obj/item/circuit_component/combiner/input_received(datum/port/input/port)
. = ..()
- if(current_type != current_option)
- current_type = current_option
- for(var/datum/port/input/input_port as anything in input_ports)
+ if(current_type != combiner_options.input_value)
+ current_type = combiner_options.input_value
+ for(var/datum/port/input/input_port as anything in combiner_ports)
input_port.set_datatype(current_type)
output_port.set_datatype(current_type)
diff --git a/code/modules/wiremod/components/utility/ram.dm b/code/modules/wiremod/components/utility/ram.dm
index ce92154dad1..90e25cac48e 100644
--- a/code/modules/wiremod/components/utility/ram.dm
+++ b/code/modules/wiremod/components/utility/ram.dm
@@ -10,6 +10,8 @@
desc = "A component that retains a variable."
circuit_flags = CIRCUIT_FLAG_OUTPUT_SIGNAL
+ var/datum/port/input/option/ram_options
+
/// The input to store
var/datum/port/input/input_port
/// The trigger to store the current value of the input
@@ -31,16 +33,15 @@
PORT_TYPE_ATOM,
PORT_TYPE_SIGNAL,
)
- options = component_options
+ ram_options = add_option_port("RAM Options", component_options)
/obj/item/circuit_component/ram/Initialize()
. = ..()
- current_type = current_option
- input_port = add_input_port("Input", current_type)
+ input_port = add_input_port("Input", PORT_TYPE_ANY)
trigger = add_input_port("Store", PORT_TYPE_SIGNAL)
clear = add_input_port("Clear", PORT_TYPE_SIGNAL)
- output = add_output_port("Stored Value", current_type)
+ output = add_output_port("Stored Value", PORT_TYPE_ANY)
/obj/item/circuit_component/ram/Destroy()
input_port = null
@@ -51,8 +52,8 @@
/obj/item/circuit_component/ram/input_received(datum/port/input/port)
. = ..()
- if(current_type != current_option)
- current_type = current_option
+ if(current_type != ram_options.input_value)
+ current_type = ram_options.input_value
input_port.set_datatype(current_type)
output.set_datatype(current_type)
diff --git a/code/modules/wiremod/components/utility/router.dm b/code/modules/wiremod/components/utility/router.dm
index 06cc9a5dc23..36fb9895051 100644
--- a/code/modules/wiremod/components/utility/router.dm
+++ b/code/modules/wiremod/components/utility/router.dm
@@ -8,6 +8,8 @@
desc = "Copies the input chosen by \"Input Selector\" to the output chosen by \"Output Selector\"."
circuit_flags = CIRCUIT_FLAG_INPUT_SIGNAL|CIRCUIT_FLAG_OUTPUT_SIGNAL
+ var/datum/port/input/option/router_options
+
/// Which ports to connect.
var/datum/port/input/input_selector
var/datum/port/input/output_selector
@@ -31,11 +33,11 @@
PORT_TYPE_LIST,
PORT_TYPE_ATOM,
)
- options = component_options
+ router_options = add_option_port("Router Options", component_options)
/obj/item/circuit_component/router/Initialize()
. = ..()
- current_type = current_option
+ current_type = router_options.input_value
if(input_port_amount > 1)
input_selector = add_input_port("Input Selector", PORT_TYPE_NUMBER, default = 1)
if(output_port_amount > 1)
@@ -61,6 +63,7 @@
#define WRAPACCESS(L, I) L[(((I||1)-1)%length(L)+length(L))%length(L)+1]
/obj/item/circuit_component/router/input_received(datum/port/input/port)
. = ..()
+ var/current_option = router_options.input_value
if(current_type != current_option)
current_type = current_option
for(var/datum/port/input/input as anything in ins)
diff --git a/code/modules/wiremod/components/utility/typecast.dm b/code/modules/wiremod/components/utility/typecast.dm
index 9375970d5be..f7ecb9ed4cd 100644
--- a/code/modules/wiremod/components/utility/typecast.dm
+++ b/code/modules/wiremod/components/utility/typecast.dm
@@ -8,6 +8,8 @@
desc = "A component that casts a value to a type if it matches or outputs null."
circuit_flags = CIRCUIT_FLAG_INPUT_SIGNAL|CIRCUIT_FLAG_OUTPUT_SIGNAL
+ var/datum/port/input/option/typecast_options
+
var/datum/port/input/input_value
var/datum/port/output/output_value
@@ -16,21 +18,22 @@
/obj/item/circuit_component/typecast/Initialize()
. = ..()
- current_type = current_option
+ current_type = typecast_options.input_value
input_value = add_input_port("Input", PORT_TYPE_ANY)
- output_value = add_output_port("Output", current_option)
+ output_value = add_output_port("Output", current_type)
/obj/item/circuit_component/typecast/populate_options()
- var/static/component_options = list(
+ var/static/list/component_options = list(
PORT_TYPE_STRING,
PORT_TYPE_NUMBER,
PORT_TYPE_LIST,
PORT_TYPE_ATOM,
)
- options = component_options
+ typecast_options = add_option_port("Typecast Options", component_options)
/obj/item/circuit_component/typecast/input_received(datum/port/input/port)
. = ..()
+ var/current_option = typecast_options.input_value
if(current_type != current_option)
current_type = current_option
output_value.set_datatype(current_type)
diff --git a/code/modules/wiremod/components/utility/typecheck.dm b/code/modules/wiremod/components/utility/typecheck.dm
index e92313e5a78..58b06e537cf 100644
--- a/code/modules/wiremod/components/utility/typecheck.dm
+++ b/code/modules/wiremod/components/utility/typecheck.dm
@@ -8,6 +8,7 @@
desc = "A component that checks the type of its input."
input_port_amount = 1
+ var/datum/port/input/option/typecheck_options
/obj/item/circuit_component/compare/typecheck/populate_options()
var/static/component_options = list(
@@ -18,7 +19,7 @@
COMP_TYPECHECK_MOB,
COMP_TYPECHECK_HUMAN,
)
- options = component_options
+ typecheck_options = add_option_port("Typecheck Options", component_options)
/obj/item/circuit_component/compare/typecheck/do_comparisons(list/ports)
if(!length(ports))
@@ -28,7 +29,7 @@
// We're only comparing the first port/value. There shouldn't be any more.
var/datum/port/input/input_port = ports[1]
var/input_val = input_port.input_value
- switch(current_option)
+ switch(typecheck_options.input_value)
if(PORT_TYPE_STRING)
return istext(input_val)
if(PORT_TYPE_NUMBER)
diff --git a/code/modules/wiremod/datatypes.dm b/code/modules/wiremod/datatypes.dm
new file mode 100644
index 00000000000..03d6a344591
--- /dev/null
+++ b/code/modules/wiremod/datatypes.dm
@@ -0,0 +1,91 @@
+// An assoc list of all the possible datatypes.
+GLOBAL_LIST_INIT(circuit_datatypes, generate_circuit_datatypes())
+
+/proc/generate_circuit_datatypes()
+ var/list/datatypes_by_key = list()
+ for(var/datum/circuit_datatype/type as anything in subtypesof(/datum/circuit_datatype))
+ if(!initial(type.datatype))
+ continue
+ datatypes_by_key[initial(type.datatype)] = new type()
+ return datatypes_by_key
+
+/**
+ * A circuit datatype. Used to determine the datatype of a port and also handle any additional behaviour.
+ */
+/datum/circuit_datatype
+ /// The key. Used to identify the datatype. Should be a define.
+ var/datatype
+
+ /// The color of the port in the UI. Doesn't work with hex colours.
+ var/color = "blue"
+
+ /// The flags of the circuit datatype
+ var/datatype_flags = 0
+
+/**
+ * Returns the value to be set for the port
+ *
+ * Used for implicit conversions between outputs and inputs (e.g. number -> string)
+ * and applying/removing signals on inputs
+ */
+/datum/circuit_datatype/proc/convert_value(datum/port/port, value_to_convert)
+ return value_to_convert
+
+/**
+ * Determines if a datatype is compatible with another port of a different type.
+ * Note: This is ALWAYS called on the input port, never on the output port.
+ * Inputs need to care about what types they're receiving, output ports don't have to care.
+ *
+ * Arguments:
+ * * datatype_to_check - The datatype to check
+ */
+/datum/circuit_datatype/proc/can_receive_from_datatype(datatype_to_check)
+ return datatype == datatype_to_check // This is already done by default on the input port.
+
+/**
+ * Called when the datatype is given to a port.
+ *
+ * Arguments:
+ * * gained_port - The gained port.
+ */
+/datum/circuit_datatype/proc/on_gain(datum/port/gained_port)
+ gained_port.disconnect()
+
+/**
+ * Called when the datatype is removed from a port.
+ *
+ * Arguments:
+ * * lost_port - The removed port.
+ */
+/datum/circuit_datatype/proc/on_loss(datum/port/lost_port)
+ return
+
+/**
+ * Determines if a port is compatible with this datatype.
+ * This WILL throw a runtime if it returns false. This is for sanity checking and it should not return false
+ * unless under extraordinary circumstances or people fail to write proper code.
+ *
+ * Arguments:
+ * * port - The port to check if it is compatible.
+ */
+/datum/circuit_datatype/proc/is_compatible(datum/port/port)
+ return TRUE
+
+/**
+ * The data to send to the UI attached to the port. Received by the type in FUNDAMENTAL_PORT_TYPES
+ *
+ * Arguments:
+ * * port - The port sending the data.
+ */
+/datum/circuit_datatype/proc/datatype_ui_data(datum/port/port)
+ return
+
+/**
+ * When an input is manually set by a player. This is where extra sanitizing can happen. Will still call convert_value()
+ *
+ * Arguments:
+ * * port - The port sending the data.
+ * *
+ */
+/datum/circuit_datatype/proc/handle_manual_input(datum/port/input/port, mob/user, user_input)
+ return user_input
diff --git a/code/modules/wiremod/datatypes/any.dm b/code/modules/wiremod/datatypes/any.dm
new file mode 100644
index 00000000000..a8a2f8457f6
--- /dev/null
+++ b/code/modules/wiremod/datatypes/any.dm
@@ -0,0 +1,10 @@
+/datum/circuit_datatype/any
+ datatype = PORT_TYPE_ANY
+ color = "blue"
+ datatype_flags = DATATYPE_FLAG_ALLOW_MANUAL_INPUT
+
+/datum/circuit_datatype/any/can_receive_from_datatype(datatype_to_check)
+ return TRUE
+
+/datum/circuit_datatype/any/handle_manual_input(datum/port/input/port, mob/user, user_input)
+ return text2num(user_input) || user_input
diff --git a/code/modules/wiremod/datatypes/basic.dm b/code/modules/wiremod/datatypes/basic.dm
new file mode 100644
index 00000000000..d112f2b9d96
--- /dev/null
+++ b/code/modules/wiremod/datatypes/basic.dm
@@ -0,0 +1,9 @@
+// This file is for types that do not have any special conversion behaviour
+
+/datum/circuit_datatype/list_type
+ datatype = PORT_TYPE_LIST
+ color = "white"
+
+/datum/circuit_datatype/table
+ datatype = PORT_TYPE_TABLE
+ color = "grey"
diff --git a/code/modules/wiremod/datatypes/entity.dm b/code/modules/wiremod/datatypes/entity.dm
new file mode 100644
index 00000000000..44e00b9c6c4
--- /dev/null
+++ b/code/modules/wiremod/datatypes/entity.dm
@@ -0,0 +1,10 @@
+/datum/circuit_datatype/entity
+ datatype = PORT_TYPE_ATOM
+ color = "purple"
+ datatype_flags = DATATYPE_FLAG_ALLOW_MANUAL_INPUT
+
+/datum/circuit_datatype/entity/convert_value(datum/port/port, value_to_convert)
+ var/atom/object = value_to_convert
+ if(QDELETED(object))
+ return null
+ return object
diff --git a/code/modules/wiremod/datatypes/number.dm b/code/modules/wiremod/datatypes/number.dm
new file mode 100644
index 00000000000..7013340249e
--- /dev/null
+++ b/code/modules/wiremod/datatypes/number.dm
@@ -0,0 +1,14 @@
+/datum/circuit_datatype/number
+ datatype = PORT_TYPE_NUMBER
+ color = "green"
+ datatype_flags = DATATYPE_FLAG_ALLOW_MANUAL_INPUT
+
+/datum/circuit_datatype/number/can_receive_from_datatype(datatype_to_check)
+ . = ..()
+ if(.)
+ return
+
+ return datatype_to_check == PORT_TYPE_NUMBER
+
+/datum/circuit_datatype/number/handle_manual_input(datum/port/input/port, mob/user, user_input)
+ return text2num(user_input)
diff --git a/code/modules/wiremod/datatypes/option.dm b/code/modules/wiremod/datatypes/option.dm
new file mode 100644
index 00000000000..c93f60512fd
--- /dev/null
+++ b/code/modules/wiremod/datatypes/option.dm
@@ -0,0 +1,33 @@
+/datum/port/input/option
+ var/list/possible_options
+
+/datum/port/input/option/New(obj/item/circuit_component/to_connect, name, datatype, trigger, default, possible_options)
+ . = ..()
+ src.possible_options = possible_options
+ set_input(default, FALSE)
+
+/datum/circuit_datatype/option
+ datatype = PORT_TYPE_OPTION
+ color = "violet"
+ datatype_flags = DATATYPE_FLAG_ALLOW_MANUAL_INPUT
+
+/datum/circuit_datatype/option/is_compatible(datum/port/gained_port)
+ return istype(gained_port, /datum/port/input/option)
+
+/datum/circuit_datatype/option/can_receive_from_datatype(datatype_to_check)
+ . = ..()
+ if(.)
+ return
+
+ return datatype_to_check == PORT_TYPE_STRING
+
+/datum/circuit_datatype/option/convert_value(datum/port/input/option/port, value_to_convert)
+ if(!port.possible_options)
+ return null
+
+ if(value_to_convert in port.possible_options)
+ return value_to_convert
+ return port.possible_options[1]
+
+/datum/circuit_datatype/option/datatype_ui_data(datum/port/input/option/port)
+ return port.possible_options
diff --git a/code/modules/wiremod/datatypes/signal.dm b/code/modules/wiremod/datatypes/signal.dm
new file mode 100644
index 00000000000..2226f509fc2
--- /dev/null
+++ b/code/modules/wiremod/datatypes/signal.dm
@@ -0,0 +1,17 @@
+/datum/circuit_datatype/signal
+ datatype = PORT_TYPE_SIGNAL
+ color = "teal"
+ datatype_flags = DATATYPE_FLAG_ALLOW_MANUAL_INPUT|DATATYPE_FLAG_AVOID_VALUE_UPDATE
+
+/datum/circuit_datatype/signal/can_receive_from_datatype(datatype_to_check)
+ . = ..()
+ if(.)
+ return
+
+ return datatype_to_check == PORT_TYPE_NUMBER
+
+/datum/circuit_datatype/signal/handle_manual_input(datum/port/input/port, mob/user, user_input)
+ var/atom/parent = port.connected_component
+ if(parent)
+ parent.balloon_alert(user, "triggered [port.name]")
+ return COMPONENT_SIGNAL
diff --git a/code/modules/wiremod/datatypes/string.dm b/code/modules/wiremod/datatypes/string.dm
new file mode 100644
index 00000000000..99c61b4a291
--- /dev/null
+++ b/code/modules/wiremod/datatypes/string.dm
@@ -0,0 +1,17 @@
+/datum/circuit_datatype/string
+ datatype = PORT_TYPE_STRING
+ color = "orange"
+ datatype_flags = DATATYPE_FLAG_ALLOW_MANUAL_INPUT
+
+/datum/circuit_datatype/string/can_receive_from_datatype(datatype_to_check)
+ return TRUE
+
+/datum/circuit_datatype/string/convert_value(datum/port/port, value_to_convert)
+ if(isnull(value_to_convert))
+ return
+
+ // So that they can't easily get the name like this.
+ if(isatom(value_to_convert))
+ return PORT_TYPE_ATOM
+ else
+ return copytext("[value_to_convert]", 1, PORT_MAX_STRING_LENGTH)
diff --git a/code/modules/wiremod/duplicator.dm b/code/modules/wiremod/duplicator.dm
index 7d0c31d61af..ee8602d6c97 100644
--- a/code/modules/wiremod/duplicator.dm
+++ b/code/modules/wiremod/duplicator.dm
@@ -6,6 +6,7 @@ GLOBAL_LIST_INIT(circuit_dupe_whitelisted_types, list(
PORT_TYPE_STRING,
PORT_TYPE_LIST,
PORT_TYPE_ANY,
+ PORT_TYPE_OPTION,
))
/// Loads a circuit based on json data at a location. Can also load usb connections, such as arrest consoles.
@@ -33,6 +34,17 @@ GLOBAL_LIST_INIT(circuit_dupe_whitelisted_types, list(
identifiers_to_circuit[identifier] = component
component.load_data_from_list(component_data)
+ var/list/input_ports_data = component_data["input_ports_stored_data"]
+ for(var/port_name in input_ports_data)
+ var/datum/port/input/port
+ var/list/port_data = input_ports_data[port_name]
+ for(var/datum/port/input/port_to_check as anything in component.input_ports)
+ if(port_to_check.name == port_name)
+ port = port_to_check
+ break
+
+ port.set_input(port_data["stored_data"])
+
var/list/external_objects = general_data["external_objects"]
for(var/identifier in external_objects)
var/list/object_data = external_objects[identifier]
@@ -118,6 +130,7 @@ GLOBAL_LIST_INIT(circuit_dupe_whitelisted_types, list(
component_data["type"] = component.type
var/list/connections = list()
+ var/list/input_ports_stored_data = list()
for(var/datum/port/input/port as anything in component.input_ports)
var/list/connection_data = list()
var/datum/port/output/output_port = port.connected_port
@@ -125,12 +138,13 @@ GLOBAL_LIST_INIT(circuit_dupe_whitelisted_types, list(
if(isnull(port.input_value) || !(port.datatype in GLOB.circuit_dupe_whitelisted_types))
continue
connection_data["stored_data"] = port.input_value
- connections[port.name] = connection_data
+ input_ports_stored_data[port.name] = connection_data
continue
connection_data["component_id"] = circuit_to_identifiers[output_port.connected_component]
connection_data["port_name"] = output_port.name
connections[port.name] = connection_data
component_data["connections"] = connections
+ component_data["input_ports_stored_data"] = input_ports_stored_data
component.save_data_to_list(component_data)
circuit_data[identifier] = component_data
@@ -160,15 +174,11 @@ GLOBAL_LIST_INIT(circuit_dupe_whitelisted_types, list(
component_data["rel_x"] = rel_x
component_data["rel_y"] = rel_y
- component_data["option"] = current_option
-
/// Loads data from a list
/obj/item/circuit_component/proc/load_data_from_list(list/component_data)
rel_x = component_data["rel_x"]
rel_y = component_data["rel_y"]
- set_option(component_data["option"])
-
/client/proc/load_circuit()
set name = "Load Circuit"
set category = "Admin.Fun"
diff --git a/code/modules/wiremod/integrated_circuit.dm b/code/modules/wiremod/integrated_circuit.dm
index a1c47472b51..c48997ccc2e 100644
--- a/code/modules/wiremod/integrated_circuit.dm
+++ b/code/modules/wiremod/integrated_circuit.dm
@@ -245,6 +245,7 @@
"connected_to" = REF(port.connected_port),
"color" = port.color,
"current_data" = current_data,
+ "datatype_data" = port.datatype_ui_data(user),
))
component_data["output_ports"] = list()
for(var/datum/port/output/port as anything in component.output_ports)
@@ -252,14 +253,12 @@
"name" = port.name,
"type" = port.datatype,
"ref" = REF(port),
- "color" = port.color
+ "color" = port.color,
))
component_data["name"] = component.display_name
component_data["x"] = component.rel_x
component_data["y"] = component.rel_y
- component_data["option"] = component.current_option
- component_data["options"] = component.options
component_data["removable"] = component.removable
.["components"] += list(component_data)
@@ -332,7 +331,7 @@
var/datum/port/input/input_port = input_component.input_ports[input_port_id]
var/datum/port/output/output_port = output_component.output_ports[output_port_id]
- if(input_port.datatype != PORT_TYPE_ANY && !output_port.compatible_datatype(input_port.datatype))
+ if(!input_port.can_receive_from_datatype(output_port.datatype))
return
input_port.register_output_port(output_port)
@@ -378,16 +377,6 @@
component.rel_x = min(max(-COMPONENT_MAX_POS, text2num(params["rel_x"])), COMPONENT_MAX_POS)
component.rel_y = min(max(-COMPONENT_MAX_POS, text2num(params["rel_y"])), COMPONENT_MAX_POS)
. = TRUE
- if("set_component_option")
- var/component_id = text2num(params["component_id"])
- if(!WITHIN_RANGE(component_id, attached_components))
- return
- var/obj/item/circuit_component/component = attached_components[component_id]
- var/option = params["option"]
- if(!(option in component.options))
- return
- component.set_option(option)
- . = TRUE
if("set_component_input")
var/component_id = text2num(params["component_id"])
var/port_id = text2num(params["port_id"])
@@ -427,17 +416,10 @@
port.set_input(marker.marked_atom)
return TRUE
- var/user_input = params["input"]
- switch(port.datatype)
- if(PORT_TYPE_NUMBER)
- port.set_input(text2num(user_input))
- if(PORT_TYPE_ANY)
- port.set_input(text2num(user_input) || user_input)
- if(PORT_TYPE_STRING)
- port.set_input(user_input)
- if(PORT_TYPE_SIGNAL)
- balloon_alert(usr, "triggered [port.name]")
- port.set_input(COMPONENT_SIGNAL)
+ var/user_input = port.handle_manual_input(usr, params["input"])
+ if(isnull(user_input))
+ return TRUE
+ port.set_input(user_input)
. = TRUE
if("get_component_value")
var/component_id = text2num(params["component_id"])
diff --git a/code/modules/wiremod/port.dm b/code/modules/wiremod/port.dm
index d2c23b538d9..1fa2c672326 100644
--- a/code/modules/wiremod/port.dm
+++ b/code/modules/wiremod/port.dm
@@ -16,7 +16,7 @@
var/datatype
/// The default port type. Stores the original datatype of the port set on Initialize.
- var/default_datatype
+ var/datum/circuit_datatype/datatype_handler
/// The port color. If unset, appears as blue.
var/color
@@ -30,29 +30,11 @@
// with the other variable declarations
src.connected_component = to_connect
src.name = name
- src.datatype = datatype
- src.default_datatype = datatype
- src.color = datatype_to_color()
-
-
-///Converts the datatype into an appropriate colour
-/datum/port/proc/datatype_to_color()
- switch(datatype)
- if(PORT_TYPE_ATOM)
- return "purple"
- if(PORT_TYPE_NUMBER)
- return "green"
- if(PORT_TYPE_STRING)
- return "orange"
- if(PORT_TYPE_LIST)
- return "white"
- if(PORT_TYPE_SIGNAL)
- return "teal"
- if(PORT_TYPE_TABLE)
- return "grey"
+ set_datatype(datatype)
/datum/port/Destroy(force)
connected_component = null
+ datatype_handler = null
return ..()
/**
@@ -61,30 +43,8 @@
* Used for implicit conversions between outputs and inputs (e.g. number -> string)
* and applying/removing signals on inputs
*/
-/datum/port/proc/convert_value(prev_value, value_to_convert)
- if(prev_value == value_to_convert)
- return prev_value
- . = value_to_convert
-
- if(isnull(value_to_convert))
- return null
-
- switch(datatype)
- if(PORT_TYPE_STRING)
- // So that they can't easily get the name like this.
- if(isatom(value_to_convert))
- return PORT_TYPE_ATOM
- else
- return copytext("[value_to_convert]", 1, PORT_MAX_STRING_LENGTH)
- if(PORT_TYPE_NUMBER)
- if(!istext(value_to_convert) && !isnum(value_to_convert))
- return null
- return text2num(value_to_convert)
-
- if(isatom(value_to_convert))
- var/atom/atom_to_check = value_to_convert
- if(QDELETED(atom_to_check))
- return null
+/datum/port/proc/convert_value(value_to_convert)
+ return datatype_handler.convert_value(src, value_to_convert)
/**
* Sets the datatype of the port.
@@ -93,12 +53,33 @@
* * type_to_set - The type this port is set to.
*/
/datum/port/proc/set_datatype(type_to_set)
+ if(type_to_set == datatype)
+ return
+
+ if(datatype_handler)
+ datatype_handler.on_loss(src)
+ datatype_handler = null
+
+ var/datum/circuit_datatype/handler = GLOB.circuit_datatypes[type_to_set]
+ if(!handler || !handler.is_compatible(src))
+ type_to_set = PORT_TYPE_ANY
+ handler = GLOB.circuit_datatypes[type_to_set]
+ // We can't leave this port without a type or else it'll just keep spewing out unnecessary and unneeded runtimes as well as leaving the circuit in a broken state.
+ stack_trace("[src] port attempted to be set to an incompatible datatype! (target datatype to set: [type_to_set])")
+
datatype = type_to_set
- color = datatype_to_color()
- disconnect()
+ datatype_handler = handler
+ color = datatype_handler.color
+ datatype_handler.on_gain(src)
if(connected_component?.parent)
SStgui.update_uis(connected_component.parent)
+/**
+ * Returns the data from the datatype
+ */
+/datum/port/proc/datatype_ui_data()
+ return datatype_handler.datatype_ui_data(src)
+
/**
* Disconnects a port from all other ports
*
@@ -138,7 +119,7 @@
/datum/port/output/proc/set_output(value)
if(isatom(output_value))
UnregisterSignal(output_value, COMSIG_PARENT_QDELETING)
- output_value = convert_value(output_value, value)
+ output_value = convert_value(value)
if(isatom(output_value))
RegisterSignal(output_value, COMSIG_PARENT_QDELETING, .proc/null_output)
@@ -154,26 +135,6 @@
. = ..()
set_output(null)
-/**
- * Determines if a datatype is compatible with another port of a different type.
- *
- * Arguments:
- * * other_datatype - The datatype to check
- */
-/datum/port/output/proc/compatible_datatype(datatype_to_check)
- if(datatype_to_check == datatype)
- return TRUE
-
- switch(datatype)
- if(PORT_TYPE_NUMBER)
- // Can easily convert a number to string. Everything else has to use a tostring component
- return datatype_to_check == PORT_TYPE_STRING || datatype_to_check == PORT_TYPE_SIGNAL
- if(PORT_TYPE_SIGNAL)
- // A signal port is just a number port but distinguishable
- return datatype_to_check == PORT_TYPE_NUMBER
-
- return FALSE
-
/**
* # Input Port
*
@@ -220,9 +181,28 @@
connected_port = port_to_register
SEND_SIGNAL(connected_port, COMSIG_PORT_OUTPUT_CONNECT, src)
// For signals, we don't update the input to prevent sending a signal when connecting ports.
- if(datatype != PORT_TYPE_SIGNAL)
+ if(!(datatype_handler.datatype_flags & DATATYPE_FLAG_AVOID_VALUE_UPDATE))
set_input(connected_port.output_value)
+/**
+ * Determines if a datatype is compatible with another port of a different type.
+ *
+ * Arguments:
+ * * other_datatype - The datatype to check
+ */
+/datum/port/input/proc/can_receive_from_datatype(datatype_to_check)
+ return datatype_handler.can_receive_from_datatype(datatype_to_check)
+
+/**
+ * Determines if a datatype is compatible with another port of a different type.
+ *
+ * Arguments:
+ * * other_datatype - The datatype to check
+ */
+/datum/port/input/proc/handle_manual_input(mob/user, manual_input)
+ if(datatype_handler.datatype_flags & DATATYPE_FLAG_ALLOW_MANUAL_INPUT)
+ return datatype_handler.handle_manual_input(src, user, manual_input)
+ return null
/**
* Sets a timer depending on the value of the input_receive_delay
@@ -246,7 +226,7 @@
/datum/port/input/proc/set_input(new_value, send_update = TRUE)
if(isatom(input_value))
UnregisterSignal(input_value, COMSIG_PARENT_QDELETING)
- input_value = convert_value(input_value, new_value)
+ input_value = convert_value(new_value)
if(isatom(input_value))
RegisterSignal(input_value, COMSIG_PARENT_QDELETING, .proc/null_output)
diff --git a/code/modules/wiremod/shell/brain_computer_interface.dm b/code/modules/wiremod/shell/brain_computer_interface.dm
index d43c402efb7..d383b70fb86 100644
--- a/code/modules/wiremod/shell/brain_computer_interface.dm
+++ b/code/modules/wiremod/shell/brain_computer_interface.dm
@@ -38,6 +38,9 @@
desc = "Represents an action the user can take when implanted with the brain-computer interface."
required_shells = list(/obj/item/organ/cyberimp/bci)
+ /// The icon of the button
+ var/datum/port/input/option/icon_options
+
/// The name to use for the button
var/datum/port/input/button_name
@@ -51,7 +54,7 @@
. = ..()
if (!isnull(default_icon))
- set_option(default_icon)
+ icon_options.set_input(default_icon)
button_name = add_input_port("Name", PORT_TYPE_STRING)
@@ -99,7 +102,7 @@
"Wireless",
)
- options = action_options
+ icon_options = add_option_port("Icon", action_options)
/obj/item/circuit_component/bci_action/register_shell(atom/movable/shell)
var/obj/item/organ/cyberimp/bci/bci = shell
@@ -126,7 +129,7 @@
/obj/item/circuit_component/bci_action/proc/update_action()
bci_action.name = button_name.input_value
- bci_action.button_icon_state = "bci_[replacetextEx(lowertext(current_option), " ", "_")]"
+ bci_action.button_icon_state = "bci_[replacetextEx(lowertext(icon_options.input_value), " ", "_")]"
/datum/action/innate/bci_action
name = "Action"
diff --git a/tgstation.dme b/tgstation.dme
index ed99d909154..8d7cb7e2e62 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -3685,6 +3685,7 @@
#include "code\modules\vending\youtool.dm"
#include "code\modules\wiremod\component.dm"
#include "code\modules\wiremod\component_printer.dm"
+#include "code\modules\wiremod\datatypes.dm"
#include "code\modules\wiremod\duplicator.dm"
#include "code\modules\wiremod\integrated_circuit.dm"
#include "code\modules\wiremod\marker.dm"
@@ -3742,6 +3743,13 @@
#include "code\modules\wiremod\components\utility\ram.dm"
#include "code\modules\wiremod\components\utility\typecast.dm"
#include "code\modules\wiremod\components\utility\typecheck.dm"
+#include "code\modules\wiremod\datatypes\any.dm"
+#include "code\modules\wiremod\datatypes\basic.dm"
+#include "code\modules\wiremod\datatypes\entity.dm"
+#include "code\modules\wiremod\datatypes\number.dm"
+#include "code\modules\wiremod\datatypes\option.dm"
+#include "code\modules\wiremod\datatypes\signal.dm"
+#include "code\modules\wiremod\datatypes\string.dm"
#include "code\modules\wiremod\preset\hello_world.dm"
#include "code\modules\wiremod\preset\speech_relay.dm"
#include "code\modules\wiremod\shell\airlock.dm"
diff --git a/tgui/packages/tgui/interfaces/IntegratedCircuit/DisplayName.js b/tgui/packages/tgui/interfaces/IntegratedCircuit/DisplayName.js
index e4ab87b7855..9dc9b1d220a 100644
--- a/tgui/packages/tgui/interfaces/IntegratedCircuit/DisplayName.js
+++ b/tgui/packages/tgui/interfaces/IntegratedCircuit/DisplayName.js
@@ -1,21 +1,19 @@
import { useBackend } from '../../backend';
-import {
- Box,
- Button, Flex,
-} from '../../components';
-import { FUNDAMENTAL_DATA_TYPES } from './FundamentalTypes';
+import { Box, Button, Flex } from '../../components';
+import { FUNDAMENTAL_DATA_TYPES, DATATYPE_DISPLAY_HANDLERS } from './FundamentalTypes';
import { NULL_REF } from './constants';
-
export const DisplayName = (props, context) => {
const { act } = useBackend(context);
const { port, isOutput, componentId, portIndex, ...rest } = props;
- const InputComponent = FUNDAMENTAL_DATA_TYPES[port.type || 'any'];
+ const InputComponent = FUNDAMENTAL_DATA_TYPES[port.type || 'unknown'];
+ const TypeDisplayHandler = DATATYPE_DISPLAY_HANDLERS[port.type || 'unknown'];
- const hasInput = !isOutput
- && port.connected_to === NULL_REF
- && InputComponent;
+ const hasInput
+ = !isOutput && port.connected_to === NULL_REF && InputComponent;
+
+ const displayType = TypeDisplayHandler? TypeDisplayHandler(port) : port.type;
return (
@@ -23,24 +21,28 @@ export const DisplayName = (props, context) => {
{(hasInput && (
act('set_component_input', {
- component_id: componentId,
- port_id: portIndex,
- input: val,
- ...extraParams,
- })}
+ setValue={(val, extraParams) =>
+ act('set_component_input', {
+ component_id: componentId,
+ port_id: portIndex,
+ input: val,
+ ...extraParams,
+ })}
color={port.color}
name={port.name}
- value={port.current_data} />
+ value={port.current_data}
+ extraData={port.datatype_data}
+ />
))
|| (isOutput && (
))
@@ -51,7 +53,7 @@ export const DisplayName = (props, context) => {
fontSize={0.75}
opacity={0.25}
textAlign={isOutput ? 'right' : 'left'}>
- {port.type || 'any'}
+ {displayType || 'unknown'}
diff --git a/tgui/packages/tgui/interfaces/IntegratedCircuit/FundamentalTypes.js b/tgui/packages/tgui/interfaces/IntegratedCircuit/FundamentalTypes.js
index 1374fea1e99..52398b875ae 100644
--- a/tgui/packages/tgui/interfaces/IntegratedCircuit/FundamentalTypes.js
+++ b/tgui/packages/tgui/interfaces/IntegratedCircuit/FundamentalTypes.js
@@ -1,5 +1,5 @@
import { BasicInput } from './BasicInput';
-import { NumberInput, Button, Stack, Input } from '../../components';
+import { NumberInput, Button, Stack, Input, Dropdown, Box } from '../../components';
export const FUNDAMENTAL_DATA_TYPES = {
'string': (props, context) => {
@@ -10,6 +10,7 @@ export const FUNDAMENTAL_DATA_TYPES = {
placeholder={name}
value={value}
onChange={(e, val) => setValue(val)}
+ width="96px"
/>
);
@@ -32,7 +33,7 @@ export const FUNDAMENTAL_DATA_TYPES = {
);
},
'entity': (props, context) => {
- const { name, setValue, color } = props;
+ const { name, setValue } = props;
return (
);
},
+ 'option': (props, context) => {
+ const { value, setValue, extraData } = props;
+ return (
+
+ );
+ },
'any': (props, context) => {
const { name, value, setValue, color } = props;
return (
@@ -75,6 +91,7 @@ export const FUNDAMENTAL_DATA_TYPES = {
placeholder={name}
value={value}
onChange={(e, val) => setValue(val)}
+ width="64px"
/>
@@ -82,3 +99,9 @@ export const FUNDAMENTAL_DATA_TYPES = {
);
},
};
+
+export const DATATYPE_DISPLAY_HANDLERS = {
+ 'option': (port) => {
+ return port.name.toLowerCase();
+ },
+};
diff --git a/tgui/packages/tgui/interfaces/IntegratedCircuit/ObjectComponent.js b/tgui/packages/tgui/interfaces/IntegratedCircuit/ObjectComponent.js
index 67e0b5b72aa..08b7e750940 100644
--- a/tgui/packages/tgui/interfaces/IntegratedCircuit/ObjectComponent.js
+++ b/tgui/packages/tgui/interfaces/IntegratedCircuit/ObjectComponent.js
@@ -95,8 +95,6 @@ export class ObjectComponent extends Component {
y,
index,
color = 'blue',
- options,
- option,
removable,
locations,
onPortUpdated,
@@ -142,21 +140,6 @@ export class ObjectComponent extends Component {
{name}
- {!!options && (
-
- act('set_component_option', {
- component_id: index,
- option: selected,
- })} />
-
- )}