mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-01-01 20:42:08 +00:00
* RAM now has an option to select between types. Refactored the any type to be more friendly with circuit code. (#59953) RAM now has an option to select between types and an output signal. Refactored the any type to be more friendly with user displays. Code that includes changing type is no longer hard to read because of snowflake code for the "any" type. RAM can now more easily act as a constant value component. RAM also has an output signal because it should and the fact that it doesn't was an oversight when converting everything to use input and output signals. * RAM now has an option to select between types. Refactored the any type to be more friendly with circuit code. Co-authored-by: Watermelon914 <37270891+Watermelon914@users.noreply.github.com>
287 lines
7.8 KiB
Plaintext
287 lines
7.8 KiB
Plaintext
/**
|
|
* # Component Port
|
|
*
|
|
* A base type port used by a component
|
|
*
|
|
* Connects to other ports. This is an abstract type that should not be instanciated
|
|
*/
|
|
/datum/port
|
|
/// The component this port is attached to
|
|
var/obj/item/circuit_component/connected_component
|
|
|
|
/// Name of the port. Used when displaying the port.
|
|
var/name
|
|
|
|
/// The port type. Ports can only connect to each other if the type matches
|
|
var/datatype
|
|
|
|
/// The default port type. Stores the original datatype of the port set on Initialize.
|
|
var/default_datatype
|
|
|
|
/// The port color. If unset, appears as blue.
|
|
var/color
|
|
|
|
/datum/port/New(obj/item/circuit_component/to_connect, name, datatype)
|
|
if(!to_connect)
|
|
qdel(src)
|
|
return
|
|
. = ..()
|
|
// Don't need to do src.connected_component here, but it looks inline
|
|
// 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"
|
|
|
|
/datum/port/Destroy(force)
|
|
if(!force && !QDELETED(connected_component))
|
|
// This should never happen. Ports should be deleted with their components
|
|
stack_trace("Attempted to delete a port with a non-destroyed connected_component! (port name: [name], component type: [connected_component.type])")
|
|
return QDEL_HINT_LETMELIVE
|
|
connected_component = null
|
|
return ..()
|
|
|
|
/**
|
|
* 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/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(isatom(value_to_convert))
|
|
var/atom/atom_to_check = value_to_convert
|
|
if(QDELETED(atom_to_check))
|
|
return null
|
|
|
|
/**
|
|
* Sets the datatype of the port.
|
|
*
|
|
* Arguments:
|
|
* * type_to_set - The type this port is set to.
|
|
*/
|
|
/datum/port/proc/set_datatype(type_to_set)
|
|
datatype = type_to_set
|
|
color = datatype_to_color()
|
|
disconnect()
|
|
if(connected_component?.parent)
|
|
SStgui.update_uis(connected_component.parent)
|
|
|
|
/**
|
|
* Disconnects a port from all other ports
|
|
*
|
|
* Called by [/obj/item/circuit_component] whenever it is disconnected from
|
|
* an integrated circuit
|
|
*/
|
|
/datum/port/proc/disconnect()
|
|
SHOULD_CALL_PARENT(TRUE)
|
|
SEND_SIGNAL(src, COMSIG_PORT_DISCONNECT)
|
|
|
|
|
|
/**
|
|
* # Output Port
|
|
*
|
|
* An output port that many input ports can connect to
|
|
*
|
|
* Sends a signal whenever the output value is changed
|
|
*/
|
|
/datum/port/output
|
|
/// The output value of the port
|
|
var/output_value
|
|
|
|
/datum/port/output/disconnect()
|
|
set_output(null)
|
|
return ..()
|
|
|
|
/datum/port/output/Destroy(force)
|
|
output_value = null
|
|
return ..()
|
|
|
|
/**
|
|
* Sets the output value of the port
|
|
*
|
|
* Arguments:
|
|
* * value - The value to set it to
|
|
*/
|
|
/datum/port/output/proc/set_output(value)
|
|
if(isatom(output_value))
|
|
UnregisterSignal(output_value, COMSIG_PARENT_QDELETING)
|
|
output_value = convert_value(output_value, value)
|
|
if(isatom(output_value))
|
|
RegisterSignal(output_value, COMSIG_PARENT_QDELETING, .proc/null_output)
|
|
|
|
SEND_SIGNAL(src, COMSIG_PORT_SET_OUTPUT, output_value)
|
|
|
|
/// Signal handler proc to null the output if an atom is deleted. An update is not sent because this was not set.
|
|
/datum/port/output/proc/null_output(datum/source)
|
|
SIGNAL_HANDLER
|
|
if(output_value == source)
|
|
output_value = null
|
|
|
|
/datum/port/output/set_datatype(type_to_set)
|
|
. = ..()
|
|
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
|
|
*
|
|
* An input port that can only be connected to 1 output port
|
|
*
|
|
* Registers a signal on the target output port to listen out for any output
|
|
* so that an update can be sent to the attached component
|
|
*/
|
|
/datum/port/input
|
|
/// The output value of the port
|
|
var/input_value
|
|
|
|
/// The connected output port
|
|
var/datum/port/output/connected_port
|
|
|
|
/// Whether this port triggers an update whenever an output is received.
|
|
var/trigger = FALSE
|
|
|
|
/// The default value of this input
|
|
var/default
|
|
|
|
/datum/port/input/New(obj/item/circuit_component/to_connect, name, datatype, trigger, default)
|
|
. = ..()
|
|
src.trigger = trigger
|
|
src.default = default
|
|
set_input(default, FALSE)
|
|
|
|
/**
|
|
* Connects the input port to the output port
|
|
*
|
|
* Sets the input_value and registers a signal to receive future updates.
|
|
* Arguments:
|
|
* * port_to_register - The port to connect the input port to
|
|
*/
|
|
/datum/port/input/proc/register_output_port(datum/port/output/port_to_register)
|
|
unregister_output_port()
|
|
|
|
RegisterSignal(port_to_register, COMSIG_PORT_SET_OUTPUT, .proc/receive_output)
|
|
RegisterSignal(port_to_register, list(
|
|
COMSIG_PORT_DISCONNECT,
|
|
COMSIG_PARENT_QDELETING
|
|
), .proc/unregister_output_port)
|
|
|
|
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)
|
|
set_input(connected_port.output_value)
|
|
|
|
|
|
/**
|
|
* Sets a timer depending on the value of the input_receive_delay
|
|
*
|
|
* The timer will call a proc that updates the value.
|
|
* Arguments:
|
|
* * connected_port - The connected output port
|
|
* * new_value - The new value received from the output port
|
|
*/
|
|
/datum/port/input/proc/receive_output(datum/port/output/connected_port, new_value)
|
|
SIGNAL_HANDLER
|
|
SScircuit_component.add_callback(CALLBACK(src, .proc/set_input, new_value))
|
|
|
|
/**
|
|
* Updates the value of the input
|
|
*
|
|
* It updates the value of the input and calls input_received on the connected component
|
|
* Arguments:
|
|
* * port_to_register - The port to connect the input port to
|
|
*/
|
|
/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)
|
|
if(isatom(input_value))
|
|
RegisterSignal(input_value, COMSIG_PARENT_QDELETING, .proc/null_output)
|
|
|
|
SEND_SIGNAL(src, COMSIG_PORT_SET_INPUT, input_value)
|
|
if(trigger && send_update)
|
|
TRIGGER_CIRCUIT_COMPONENT(connected_component, src)
|
|
|
|
/// Signal handler proc to null the input if an atom is deleted. An update is not sent because this was not set by anything.
|
|
/datum/port/input/proc/null_output(datum/source)
|
|
SIGNAL_HANDLER
|
|
if(input_value == source)
|
|
input_value = null
|
|
|
|
/datum/port/input/disconnect()
|
|
unregister_output_port()
|
|
return ..()
|
|
|
|
/datum/port/input/set_datatype(type_to_set)
|
|
. = ..()
|
|
set_input(default)
|
|
|
|
/datum/port/input/proc/unregister_output_port()
|
|
SIGNAL_HANDLER
|
|
if(!connected_port)
|
|
return
|
|
UnregisterSignal(connected_port, list(
|
|
COMSIG_PARENT_QDELETING,
|
|
COMSIG_PORT_SET_OUTPUT,
|
|
COMSIG_PORT_DISCONNECT
|
|
))
|
|
connected_port = null
|
|
set_input(default)
|
|
|
|
/datum/port/input/Destroy()
|
|
unregister_output_port()
|
|
connected_port = null
|
|
return ..()
|