Adds Circuit variables (#60590)

Co-authored-by: Watermelon914 <3052169-Watermelon914@users.noreply.gitlab.com>
This commit is contained in:
Watermelon914
2021-08-12 18:30:50 -07:00
committed by GitHub
co-authored by Watermelon914
parent 63e8466f39
commit 05ede8dc30
20 changed files with 494 additions and 106 deletions
@@ -211,7 +211,7 @@
/obj/item/circuit_component/module/ui_static_data(mob/user)
. = list()
.["global_port_types"] = GLOB.wiremod_types
.["global_port_types"] = GLOB.wiremod_basic_types
/obj/item/circuit_component/module/attackby(obj/item/I, mob/living/user, params)
if(istype(I, /obj/item/circuit_component))
@@ -280,7 +280,7 @@
if(action == "set_port_type")
var/type = params["port_type"]
if(!(type in GLOB.wiremod_types))
if(!(type in GLOB.wiremod_basic_types))
return
component_port.set_datatype(type)
internal_component_port.set_datatype(type)
@@ -45,10 +45,10 @@
/obj/item/circuit_component/light/input_received(datum/port/input/port)
. = ..()
brightness.set_input(clamp(brightness.value || 0, 0, max_power))
red.set_input(clamp(red.value, 0, 255))
blue.set_input(clamp(blue.value, 0, 255))
green.set_input(clamp(green.value, 0, 255))
brightness.set_value(clamp(brightness.value || 0, 0, max_power))
red.set_value(clamp(red.value, 0, 255))
blue.set_value(clamp(blue.value, 0, 255))
green.set_value(clamp(green.value, 0, 255))
var/list/hsl = rgb2hsl(red.value || 0, green.value || 0, blue.value || 0)
var/list/light_col = hsl2rgb(hsl[1], hsl[2], max(min_lightness, hsl[3]))
shell_light_color = rgb(light_col[1], light_col[2], light_col[3])
@@ -45,7 +45,7 @@
/obj/item/circuit_component/radio/input_received(datum/port/input/port)
. = ..()
freq.set_input(sanitize_frequency(freq.value, TRUE))
freq.set_value(sanitize_frequency(freq.value, TRUE))
if(.)
return
var/frequency = freq.value
@@ -49,8 +49,8 @@
/obj/item/circuit_component/soundemitter/input_received(datum/port/input/port)
. = ..()
volume.set_input(clamp(volume.value, 0, 100))
frequency.set_input(clamp(frequency.value, -100, 100))
volume.set_value(clamp(volume.value, 0, 100))
frequency.set_value(clamp(frequency.value, -100, 100))
if(.)
return
@@ -0,0 +1,70 @@
/**
* # Getter Component
*
* Gets the current value from a variable.
*/
/obj/item/circuit_component/getter
display_name = "Variable Getter"
desc = "A component that gets a variable globally on the circuit."
/// Variable name
var/datum/port/input/option/variable_name
/// The value of the variable
var/datum/port/output/value
var/datum/circuit_variable/current_variable
/obj/item/circuit_component/getter/populate_options()
variable_name = add_option_port("Variable", null)
/obj/item/circuit_component/getter/add_to(obj/item/integrated_circuit/added_to)
. = ..()
variable_name.possible_options = added_to.circuit_variables
/obj/item/circuit_component/getter/removed_from(obj/item/integrated_circuit/removed_from)
variable_name.possible_options = null
return ..()
/obj/item/circuit_component/getter/Initialize()
. = ..()
value = add_output_port("Value", PORT_TYPE_ANY)
/obj/item/circuit_component/getter/input_received(datum/port/input/port)
. = ..()
// We don't care much about the parent's return value. We only care if the parent exists
// since this should never really fail.
if(!parent)
return
var/variable_string = variable_name.value
if(!variable_string)
remove_current_variable()
value.set_output(null)
return
var/datum/circuit_variable/variable = parent.circuit_variables[variable_string]
if(!variable)
remove_current_variable()
value.set_output(null)
return
set_current_variable(variable)
value.set_output(variable.value)
/obj/item/circuit_component/getter/proc/remove_current_variable()
SIGNAL_HANDLER
if(current_variable)
current_variable.remove_listener(src)
UnregisterSignal(current_variable, COMSIG_PARENT_QDELETING)
current_variable = null
/obj/item/circuit_component/getter/proc/set_current_variable(datum/circuit_variable/variable)
if(variable == current_variable)
return
remove_current_variable()
current_variable = variable
current_variable.add_listener(src)
RegisterSignal(current_variable, COMSIG_PARENT_QDELETING, .proc/remove_current_variable)
value.set_datatype(variable.datatype)
@@ -1,72 +0,0 @@
/**
* # RAM Component
*
* Stores the current input when triggered.
* Players will need to think logically when using the RAM component
* as there can be race conditions due to the delays of transferring signals
*/
/obj/item/circuit_component/ram
display_name = "RAM"
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
var/datum/port/input/trigger
/// Clears the current input
var/datum/port/input/clear
/// The current set value
var/datum/port/output/output
var/current_type
/obj/item/circuit_component/ram/populate_options()
var/static/component_options = list(
PORT_TYPE_ANY,
PORT_TYPE_STRING,
PORT_TYPE_NUMBER,
PORT_TYPE_LIST,
PORT_TYPE_ATOM,
PORT_TYPE_SIGNAL,
)
ram_options = add_option_port("RAM Options", component_options)
/obj/item/circuit_component/ram/Initialize()
. = ..()
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", PORT_TYPE_ANY)
/obj/item/circuit_component/ram/Destroy()
input_port = null
trigger = null
clear = null
output = null
return ..()
/obj/item/circuit_component/ram/input_received(datum/port/input/port)
. = ..()
if(current_type != ram_options.value)
current_type = ram_options.value
input_port.set_datatype(current_type)
output.set_datatype(current_type)
if(.)
return
if(COMPONENT_TRIGGERED_BY(clear, port))
output.set_output(null)
return
if(!COMPONENT_TRIGGERED_BY(trigger, port))
return TRUE
var/input_val = input_port.value
output.set_output(input_val)
@@ -0,0 +1,58 @@
/**
* # Setter Component
*
* Stores the current input when triggered into a variable.
*/
/obj/item/circuit_component/setter
display_name = "Variable Setter"
desc = "A component that sets a variable globally on the circuit."
circuit_flags = CIRCUIT_FLAG_OUTPUT_SIGNAL
/// Variable name
var/datum/port/input/option/variable_name
/// The input to store
var/datum/port/input/input_port
/// The trigger to store the current value of the input
var/datum/port/input/trigger
var/current_type
/obj/item/circuit_component/setter/populate_options()
variable_name = add_option_port("Variable", null)
/obj/item/circuit_component/setter/add_to(obj/item/integrated_circuit/added_to)
. = ..()
variable_name.possible_options = added_to.circuit_variables
/obj/item/circuit_component/setter/removed_from(obj/item/integrated_circuit/removed_from)
variable_name.possible_options = null
return ..()
/obj/item/circuit_component/setter/Initialize()
. = ..()
input_port = add_input_port("Input", PORT_TYPE_ANY)
trigger = add_input_port("Store", PORT_TYPE_SIGNAL)
/obj/item/circuit_component/setter/input_received(datum/port/input/port)
. = ..()
var/variable_string = variable_name.value
if(!variable_string)
return
var/datum/circuit_variable/variable = parent.circuit_variables[variable_string]
if(!variable)
return
if(variable.datatype != current_type)
current_type = variable.datatype
input_port.set_datatype(current_type)
if(.)
return
if(!COMPONENT_TRIGGERED_BY(trigger, port))
return TRUE
variable.set_value(input_port.value)
+1 -1
View File
@@ -4,7 +4,7 @@
/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)
set_value(default, force = TRUE)
/datum/circuit_datatype/option
datatype = PORT_TYPE_OPTION
+14
View File
@@ -20,6 +20,11 @@ GLOBAL_LIST_INIT(circuit_dupe_whitelisted_types, list(
if(general_data["display_name"])
set_display_name(general_data["display_name"])
var/list/variable_data = general_data["variables"]
for(var/list/variable as anything in variable_data)
var/variable_name = variable["name"]
circuit_variables[variable_name] = new /datum/circuit_variable(variable_name, variable["datatype"])
admin_only = general_data["admin_only"]
var/list/circuit_data = general_data["components"]
@@ -164,6 +169,15 @@ GLOBAL_LIST_INIT(circuit_dupe_whitelisted_types, list(
general_data["display_name"] = display_name
general_data["admin_only"] = admin_only
var/list/variables = list()
for(var/variable_identifier in circuit_variables)
var/list/new_data = list()
var/datum/circuit_variable/variable = circuit_variables[variable_identifier]
new_data["name"] = variable.name
new_data["datatype"] = variable.datatype
variables += list(new_data)
general_data["variables"] = variables
return json_encode(general_data)
/obj/item/integrated_circuit/proc/load_component(type)
+81 -3
View File
@@ -48,12 +48,27 @@ GLOBAL_LIST_EMPTY_TYPED(integrated_circuits, /obj/item/integrated_circuit)
/// Set by the shell. Holds the reference to the owner who inserted the component into the shell.
var/datum/weakref/inserter_mind
/// Variables stored on this integrated circuit. with a `variable_name = value` structure
var/list/datum/circuit_variable/circuit_variables = list()
/// The maximum amount of setters and getters a circuit can have
var/max_setters_and_getters = 30
/// The current setter and getter count the circuit has.
var/setter_and_getter_count = 0
/// X position of the examined_component
var/examined_rel_x = 0
/// Y position of the examined component
var/examined_rel_y = 0
/// The X position of the screen. Used for adding components
var/screen_x = 0
/// The Y position of the screen. Used for adding components.
var/screen_y = 0
/obj/item/integrated_circuit/Initialize()
. = ..()
@@ -69,6 +84,7 @@ GLOBAL_LIST_EMPTY_TYPED(integrated_circuits, /obj/item/integrated_circuit)
for(var/obj/item/circuit_component/to_delete in attached_components)
remove_component(to_delete)
qdel(to_delete)
QDEL_LIST(circuit_variables)
attached_components.Cut()
shell = null
examined_component = null
@@ -182,8 +198,8 @@ GLOBAL_LIST_EMPTY_TYPED(integrated_circuits, /obj/item/integrated_circuit)
if(!success)
return
to_add.rel_x = rand(COMPONENT_MIN_RANDOM_POS, COMPONENT_MAX_RANDOM_POS)
to_add.rel_y = rand(COMPONENT_MIN_RANDOM_POS, COMPONENT_MAX_RANDOM_POS)
to_add.rel_x = rand(COMPONENT_MIN_RANDOM_POS, COMPONENT_MAX_RANDOM_POS) - screen_x
to_add.rel_y = rand(COMPONENT_MIN_RANDOM_POS, COMPONENT_MAX_RANDOM_POS) - screen_y
to_add.parent = src
attached_components += to_add
RegisterSignal(to_add, COMSIG_MOVABLE_MOVED, .proc/component_move_handler)
@@ -191,6 +207,7 @@ GLOBAL_LIST_EMPTY_TYPED(integrated_circuits, /obj/item/integrated_circuit)
if(shell)
to_add.register_shell(shell)
return TRUE
/**
* Adds a component to the circuitboard through a manual action.
@@ -199,7 +216,7 @@ GLOBAL_LIST_EMPTY_TYPED(integrated_circuits, /obj/item/integrated_circuit)
if (SEND_SIGNAL(src, COMSIG_CIRCUIT_ADD_COMPONENT_MANUALLY, to_add, user) & COMPONENT_CANCEL_ADD_COMPONENT)
return
add_component(to_add, user)
return add_component(to_add, user)
/obj/item/integrated_circuit/proc/component_move_handler(obj/item/circuit_component/source)
SIGNAL_HANDLER
@@ -231,6 +248,12 @@ GLOBAL_LIST_EMPTY_TYPED(integrated_circuits, /obj/item/integrated_circuit)
get_asset_datum(/datum/asset/simple/circuit_assets)
)
/obj/item/integrated_circuit/ui_static_data(mob/user)
. = list()
.["global_basic_types"] = GLOB.wiremod_basic_types
.["screen_x"] = screen_x
.["screen_y"] = screen_y
/obj/item/integrated_circuit/ui_data(mob/user)
. = list()
.["components"] = list()
@@ -272,6 +295,16 @@ GLOBAL_LIST_EMPTY_TYPED(integrated_circuits, /obj/item/integrated_circuit)
component_data["removable"] = component.removable
.["components"] += list(component_data)
.["variables"] = list()
for(var/variable_name in circuit_variables)
var/datum/circuit_variable/variable = circuit_variables[variable_name]
var/list/variable_data = list()
variable_data["name"] = variable.name
variable_data["datatype"] = variable.datatype
variable_data["color"] = variable.color
.["variables"] += list(variable_data)
.["display_name"] = display_name
var/obj/item/circuit_component/examined
@@ -479,6 +512,51 @@ GLOBAL_LIST_EMPTY_TYPED(integrated_circuits, /obj/item/integrated_circuit)
. = TRUE
if("save_circuit")
return attempt_save_to(usr.client)
if("add_variable")
var/variable_identifier = trim(copytext(params["variable_name"], 1, PORT_MAX_NAME_LENGTH))
if(variable_identifier in circuit_variables)
return TRUE
if(variable_identifier == "")
return TRUE
var/variable_datatype = params["variable_datatype"]
if(!(variable_datatype in GLOB.wiremod_basic_types))
return
circuit_variables[variable_identifier] = new /datum/circuit_variable(variable_identifier, variable_datatype)
. = TRUE
if("remove_variable")
var/variable_identifier = params["variable_name"]
if(!(variable_identifier in circuit_variables))
return
var/datum/circuit_variable/variable = circuit_variables[variable_identifier]
if(!variable)
return
circuit_variables -= variable_identifier
qdel(variable)
. = TRUE
if("add_setter_or_getter")
if(setter_and_getter_count >= max_setters_and_getters)
balloon_alert(usr, "setter and getter count at maximum capacity")
return
var/designated_type = /obj/item/circuit_component/getter
if(params["is_setter"])
designated_type = /obj/item/circuit_component/setter
var/obj/item/circuit_component/component = new designated_type(src)
if(!add_component(component, usr))
qdel(component)
return
RegisterSignal(component, COMSIG_CIRCUIT_COMPONENT_REMOVED, .proc/clear_setter_or_getter)
setter_and_getter_count++
if("move_screen")
screen_x = text2num(params["screen_x"])
screen_y = text2num(params["screen_y"])
/obj/item/integrated_circuit/proc/clear_setter_or_getter(datum/source)
SIGNAL_HANDLER
// This'll also be called in the Destroy() override of /obj/item/circuit_component
if(!QDELING(source))
qdel(source)
setter_and_getter_count--
/obj/item/integrated_circuit/proc/on_atom_usb_cable_try_attach(datum/source, obj/item/usb_cable/usb_cable, mob/user)
SIGNAL_HANDLER
+3 -3
View File
@@ -41,8 +41,8 @@
* Sets the port's value to value.
* Casts to the port's datatype (e.g. number -> string), and assumes this can be done.
*/
/datum/port/proc/set_value(value)
if(src.value != value)
/datum/port/proc/set_value(value, force = FALSE)
if(src.value != value || force)
if(isatom(value))
UnregisterSignal(value, COMSIG_PARENT_QDELETING)
src.value = datatype_handler.convert_value(src, value)
@@ -156,7 +156,7 @@
/datum/port/input/New(obj/item/circuit_component/to_connect, name, datatype, trigger, default)
. = ..()
set_input(default)
set_value(default)
src.trigger = trigger
src.connected_ports = list()
+49
View File
@@ -0,0 +1,49 @@
/**
* A circuit variable that holds the name, the datatype and the colour of the variable (taken from the datatype).
*
* Used in integrated circuits for setter and getter circuit components.
*/
/datum/circuit_variable
/// The display name of the circuit variable
var/name
/// The datatype of the circuit variable. Used by the setter and getter circuit components
var/datatype
/// The colour that appears in the UI. The value is set to the datatype's matching colour
var/color
/// The current value held by the variable.
var/value
/// The components that are currently listening. Triggers them when the value is updated.
var/list/obj/item/circuit_component/listeners
/datum/circuit_variable/New(name, datatype)
. = ..()
src.name = name
src.datatype = datatype
var/datum/circuit_datatype/circuit_datatype = GLOB.circuit_datatypes[datatype]
src.listeners = list()
src.color = circuit_datatype.color
/datum/circuit_variable/Destroy(force, ...)
listeners = null
return ..()
/// Sets the value of the circuit component and triggers the appropriate listeners
/datum/circuit_variable/proc/set_value(new_value)
value = new_value
for(var/obj/item/circuit_component/component as anything in listeners)
TRIGGER_CIRCUIT_COMPONENT(component, null)
/// Adds a listener to receive inputs when the variable has a value that is set.
/datum/circuit_variable/proc/add_listener(obj/item/circuit_component/to_add)
listeners += to_add
/// Removes a listener to receive inputs when the variable has a value that is set. Listener will usually clean themselves up
/datum/circuit_variable/proc/remove_listener(obj/item/circuit_component/to_remove)
listeners -= to_remove