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 (