mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-23 21:18:37 +01:00
[MIRROR] Refactors port types completely and adds the option type. Refactors options to use this new type (#7386)
* Refactors port types completely and adds the option type. Refactors options to use this new type (#60571) Co-authored-by: Watermelon914 <3052169-Watermelon914@ users.noreply.gitlab.com> * Refactors port types completely and adds the option type. Refactors options to use this new type Co-authored-by: Watermelon914 <37270891+Watermelon914@users.noreply.github.com> Co-authored-by: Watermelon914 <3052169-Watermelon914@ users.noreply.gitlab.com>
This commit is contained in:
co-authored by
Watermelon914
Watermelon914
parent
742f11f0d8
commit
3ab1e7ebe2
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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"
|
||||
@@ -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
|
||||
@@ -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)
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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)
|
||||
@@ -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"
|
||||
|
||||
@@ -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"])
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -3671,6 +3671,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"
|
||||
@@ -3728,6 +3729,13 @@
|
||||
#include "code\modules\wiremod\components\utility\router.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"
|
||||
|
||||
@@ -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 (
|
||||
<Box {...rest}>
|
||||
@@ -23,24 +21,28 @@ export const DisplayName = (props, context) => {
|
||||
<Flex.Item>
|
||||
{(hasInput && (
|
||||
<InputComponent
|
||||
setValue={(val, extraParams) => 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 && (
|
||||
<Button
|
||||
compact
|
||||
color="transparent"
|
||||
onClick={() => act('get_component_value', {
|
||||
component_id: componentId,
|
||||
port_id: portIndex,
|
||||
})}>
|
||||
onClick={() =>
|
||||
act('get_component_value', {
|
||||
component_id: componentId,
|
||||
port_id: portIndex,
|
||||
})}>
|
||||
<Box color="white">{port.name}</Box>
|
||||
</Button>
|
||||
))
|
||||
@@ -51,7 +53,7 @@ export const DisplayName = (props, context) => {
|
||||
fontSize={0.75}
|
||||
opacity={0.25}
|
||||
textAlign={isOutput ? 'right' : 'left'}>
|
||||
{port.type || 'any'}
|
||||
{displayType || 'unknown'}
|
||||
</Box>
|
||||
</Flex.Item>
|
||||
</Flex>
|
||||
|
||||
@@ -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"
|
||||
/>
|
||||
</BasicInput>
|
||||
);
|
||||
@@ -32,7 +33,7 @@ export const FUNDAMENTAL_DATA_TYPES = {
|
||||
);
|
||||
},
|
||||
'entity': (props, context) => {
|
||||
const { name, setValue, color } = props;
|
||||
const { name, setValue } = props;
|
||||
return (
|
||||
<Button
|
||||
content={name}
|
||||
@@ -54,6 +55,21 @@ export const FUNDAMENTAL_DATA_TYPES = {
|
||||
/>
|
||||
);
|
||||
},
|
||||
'option': (props, context) => {
|
||||
const { value, setValue, extraData } = props;
|
||||
return (
|
||||
<Dropdown
|
||||
className="Datatype__Option"
|
||||
color={"transparent"}
|
||||
options={typeof extraData === 'object'
|
||||
? Object.keys(extraData)
|
||||
: extraData}
|
||||
onSelected={setValue}
|
||||
displayText={value}
|
||||
noscroll
|
||||
/>
|
||||
);
|
||||
},
|
||||
'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"
|
||||
/>
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
@@ -82,3 +99,9 @@ export const FUNDAMENTAL_DATA_TYPES = {
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
export const DATATYPE_DISPLAY_HANDLERS = {
|
||||
'option': (port) => {
|
||||
return port.name.toLowerCase();
|
||||
},
|
||||
};
|
||||
|
||||
@@ -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 {
|
||||
<Stack.Item grow={1} unselectable="on">
|
||||
{name}
|
||||
</Stack.Item>
|
||||
{!!options && (
|
||||
<Stack.Item>
|
||||
<Dropdown
|
||||
color={color}
|
||||
nochevron
|
||||
over
|
||||
options={options}
|
||||
displayText={option}
|
||||
noscroll
|
||||
onSelected={(selected) => act('set_component_option', {
|
||||
component_id: index,
|
||||
option: selected,
|
||||
})} />
|
||||
</Stack.Item>
|
||||
)}
|
||||
<Stack.Item>
|
||||
<Button
|
||||
color="transparent"
|
||||
|
||||
@@ -43,3 +43,12 @@ $bg-map: colors.$bg-map !default;
|
||||
stroke: $color-value !important;
|
||||
}
|
||||
}
|
||||
|
||||
$border-color: #88bfff !default;
|
||||
$border-radius: base.$border-radius !default;
|
||||
|
||||
.Datatype__Option {
|
||||
border: base.em(1px) solid $border-color;
|
||||
border: base.em(1px) solid rgba($border-color, 0.75);
|
||||
border-radius: $border-radius;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user