mirror of
https://github.com/SPLURT-Station/S.P.L.U.R.T-Station-13.git
synced 2025-12-10 01:49:19 +00:00
217 lines
6.4 KiB
Plaintext
217 lines
6.4 KiB
Plaintext
/**
|
|
* # Component Port
|
|
*
|
|
* A port used by a component. Connects to other ports.
|
|
*/
|
|
/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 value that's currently in the port. It's of the above type.
|
|
var/value
|
|
|
|
/// The default port type. Stores the original datatype of the port set on Initialize.
|
|
var/datum/circuit_datatype/datatype_handler
|
|
|
|
/// 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
|
|
. = ..()
|
|
connected_component = to_connect
|
|
src.name = name
|
|
set_datatype(datatype)
|
|
|
|
/datum/port/Destroy(force)
|
|
disconnect_all()
|
|
connected_component = null
|
|
datatype_handler = null
|
|
return ..()
|
|
|
|
/**
|
|
* 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, force = FALSE)
|
|
if(src.value != value || force)
|
|
if(isatom(value))
|
|
UnregisterSignal(value, COMSIG_PARENT_QDELETING)
|
|
src.value = datatype_handler.convert_value(src, value)
|
|
if(isatom(value))
|
|
RegisterSignal(value, COMSIG_PARENT_QDELETING, .proc/null_value)
|
|
SEND_SIGNAL(src, COMSIG_PORT_SET_VALUE, value)
|
|
|
|
/**
|
|
* Updates the value of the input and calls input_received on the connected component
|
|
*/
|
|
/datum/port/input/proc/set_input(value)
|
|
if(QDELETED(src)) //Pain
|
|
return
|
|
set_value(value)
|
|
if(trigger)
|
|
TRIGGER_CIRCUIT_COMPONENT(connected_component, src)
|
|
|
|
/datum/port/output/proc/set_output(value)
|
|
set_value(value)
|
|
|
|
/**
|
|
* Sets the datatype of the port.
|
|
*
|
|
* Arguments:
|
|
* * new_type - The type this port is to be 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
|
|
datatype_handler = handler
|
|
color = datatype_handler.color
|
|
datatype_handler.on_gain(src)
|
|
src.value = datatype_handler.convert_value(src, value)
|
|
SEND_SIGNAL(src, COMSIG_PORT_SET_TYPE, type_to_set)
|
|
if(connected_component?.parent)
|
|
SStgui.update_uis(connected_component.parent)
|
|
|
|
/datum/port/input/set_datatype(new_type)
|
|
for(var/datum/port/output/output as anything in connected_ports)
|
|
check_type(output)
|
|
..()
|
|
|
|
/**
|
|
* Returns the data from the datatype
|
|
*/
|
|
/datum/port/proc/datatype_ui_data()
|
|
return datatype_handler.datatype_ui_data(src)
|
|
|
|
/**
|
|
* # Output Port
|
|
*
|
|
* An output port that many input ports can connect to
|
|
*
|
|
* Sends a signal whenever the output value is changed
|
|
*/
|
|
/datum/port/output
|
|
|
|
/**
|
|
* 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_all()
|
|
SEND_SIGNAL(src, COMSIG_PORT_DISCONNECT)
|
|
|
|
/datum/port/input/disconnect_all()
|
|
..()
|
|
for(var/datum/port/output/output as anything in connected_ports)
|
|
disconnect(output)
|
|
|
|
/datum/port/input/proc/disconnect(datum/port/output/output)
|
|
connected_ports -= output
|
|
UnregisterSignal(output, COMSIG_PORT_SET_VALUE)
|
|
UnregisterSignal(output, COMSIG_PORT_SET_TYPE)
|
|
UnregisterSignal(output, COMSIG_PORT_DISCONNECT)
|
|
|
|
/// Do our part in setting all source references anywhere to null.
|
|
/datum/port/proc/on_value_qdeleting(datum/source)
|
|
SIGNAL_HANDLER
|
|
if(value == source)
|
|
value = null
|
|
else
|
|
stack_trace("Impossible? [src] should only receive COMSIG_PARENT_QDELETING from an atom currently in the port, not [source].")
|
|
|
|
/**
|
|
* # Input Port
|
|
*
|
|
* An input port remembers connected output ports.
|
|
*
|
|
* Registers the PORT_SET_VALUE signal on each connected port,
|
|
* and keeps its value equal to the last such signal received.
|
|
*/
|
|
/datum/port/input
|
|
/// Whether this port triggers an update whenever an output is received.
|
|
var/trigger = FALSE
|
|
|
|
/// The ports this port is wired to.
|
|
var/list/datum/port/output/connected_ports
|
|
|
|
/datum/port/input/New(obj/item/circuit_component/to_connect, name, datatype, trigger, default)
|
|
. = ..()
|
|
set_value(default)
|
|
src.trigger = trigger
|
|
src.connected_ports = list()
|
|
|
|
/**
|
|
* Introduces two ports to one another.
|
|
*/
|
|
/datum/port/input/proc/connect(datum/port/output/output)
|
|
connected_ports |= output
|
|
RegisterSignal(output, COMSIG_PORT_SET_VALUE, .proc/receive_value)
|
|
RegisterSignal(output, COMSIG_PORT_SET_TYPE, .proc/check_type)
|
|
RegisterSignal(output, COMSIG_PORT_DISCONNECT, .proc/disconnect)
|
|
// For signals, we don't update the input to prevent sending a signal when connecting ports.
|
|
if(!(datatype_handler.datatype_flags & DATATYPE_FLAG_AVOID_VALUE_UPDATE))
|
|
set_input(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
|
|
|
|
/**
|
|
* Mirror value updates from connected output ports after an input_receive_delay.
|
|
*/
|
|
/datum/port/input/proc/receive_value(datum/port/output/output, value)
|
|
SIGNAL_HANDLER
|
|
SScircuit_component.add_callback(CALLBACK(src, .proc/set_input, value))
|
|
|
|
/// 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/proc/null_value(datum/source)
|
|
SIGNAL_HANDLER
|
|
if(value == source)
|
|
value = null
|
|
|
|
/**
|
|
* Handle type updates from connected output ports, breaking uncastable connections.
|
|
*/
|
|
/datum/port/input/proc/check_type(datum/port/output/output)
|
|
SIGNAL_HANDLER
|
|
if(!can_receive_from_datatype(output.datatype))
|
|
disconnect(output)
|