mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2025-12-13 11:12:14 +00:00
* Drastically improved the USB connection for air alarms. Any airlock can now be made into a shell (#68632) The USB connections for air alarms have been improved and now include scrubber control, vent control and the setting of the air alarm mode. Also fixes a bug where the limits were not being properly set. The scrubber, vent and limit control can be duplicated in the circuit to allow multiple limits/scrubbers/vents to be controlled by one circuit. Any airlock can be made into a shell during construction by configuring the airlock electronic before insert. * Drastically improved the USB connection for air alarms. Any airlock can now be made into a shell Co-authored-by: Watermelon914 <37270891+Watermelon914@users.noreply.github.com>
403 lines
13 KiB
Plaintext
403 lines
13 KiB
Plaintext
/**
|
|
* # Integrated Circuit Component
|
|
*
|
|
* A component that performs a function when given an input
|
|
*
|
|
* Can be attached to an integrated circuitboard, where it can then
|
|
* be connected between other components to provide an output or to receive
|
|
* an input. This is the base type of all components
|
|
*/
|
|
/obj/item/circuit_component
|
|
name = COMPONENT_DEFAULT_NAME
|
|
icon = 'icons/obj/module.dmi'
|
|
icon_state = "component"
|
|
inhand_icon_state = "electronic"
|
|
|
|
/// The name of the component shown on the UI
|
|
var/display_name = "Generic"
|
|
|
|
/// The category of the component in the UI
|
|
var/category = COMPONENT_DEFAULT_CATEGORY
|
|
|
|
/// The colour this circuit component appears in the UI
|
|
var/ui_color = "blue"
|
|
|
|
/// The integrated_circuit that this component is attached to.
|
|
var/obj/item/integrated_circuit/parent
|
|
|
|
/// A list that contains the outpurt ports on this component
|
|
/// Used to connect between the ports
|
|
var/list/datum/port/output/output_ports = list()
|
|
|
|
/// A list that contains the components the input ports on this component
|
|
/// Used to connect between the ports
|
|
var/list/datum/port/input/input_ports = list()
|
|
|
|
/// Generic trigger input for triggering this component
|
|
var/datum/port/input/trigger_input
|
|
var/datum/port/output/trigger_output
|
|
|
|
/// The flags of the circuit to control basic generalised behaviour.
|
|
var/circuit_flags = NONE
|
|
|
|
/// Used to determine the x position of the component within the UI
|
|
var/rel_x = 0
|
|
/// Used to determine the y position of the component within the UI
|
|
var/rel_y = 0
|
|
|
|
/// The power usage whenever this component receives an input
|
|
var/power_usage_per_input = 1
|
|
|
|
/// 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
|
|
|
|
/// Determines the amount of space this circuit occupies in an integrated circuit.
|
|
var/circuit_size = 1
|
|
|
|
/// The UI buttons of this circuit component. An assoc list that has this format: "button_icon" = "action_name"
|
|
var/ui_buttons = null
|
|
|
|
/// Called when the option ports should be set up
|
|
/obj/item/circuit_component/proc/populate_options()
|
|
return
|
|
|
|
/// Called when the rest of the ports should be set up
|
|
/obj/item/circuit_component/proc/populate_ports()
|
|
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, order = 0, trigger = .proc/input_received)
|
|
return add_input_port(name, PORT_TYPE_OPTION, order = order, trigger = trigger, port_type = /datum/port/input/option, extra_args = list("possible_options" = list_to_use))
|
|
|
|
/obj/item/circuit_component/Initialize(mapload)
|
|
. = ..()
|
|
if(name == COMPONENT_DEFAULT_NAME)
|
|
name = "[lowertext(display_name)] [COMPONENT_DEFAULT_NAME]"
|
|
populate_options()
|
|
populate_ports()
|
|
if((circuit_flags & CIRCUIT_FLAG_INPUT_SIGNAL) && !trigger_input)
|
|
trigger_input = add_input_port("Trigger", PORT_TYPE_SIGNAL, order = 2)
|
|
if((circuit_flags & CIRCUIT_FLAG_OUTPUT_SIGNAL) && !trigger_output)
|
|
trigger_output = add_output_port("Triggered", PORT_TYPE_SIGNAL, order = 2)
|
|
if(circuit_flags & CIRCUIT_FLAG_INSTANT)
|
|
ui_color = "orange"
|
|
if(circuit_flags & CIRCUIT_FLAG_REFUSE_MODULE)
|
|
desc += " Incompatible with module components."
|
|
|
|
/obj/item/circuit_component/Destroy()
|
|
if(parent)
|
|
// Prevents a Destroy() recursion
|
|
var/obj/item/integrated_circuit/old_parent = parent
|
|
parent = null
|
|
old_parent.remove_component(src)
|
|
|
|
trigger_input = null
|
|
trigger_output = null
|
|
|
|
QDEL_LIST(output_ports)
|
|
QDEL_LIST(input_ports)
|
|
return ..()
|
|
|
|
/obj/item/circuit_component/drop_location()
|
|
if(parent?.shell)
|
|
return parent.shell.drop_location()
|
|
return ..()
|
|
|
|
/obj/item/circuit_component/examine(mob/user)
|
|
. = ..()
|
|
if(circuit_flags & CIRCUIT_FLAG_REFUSE_MODULE)
|
|
. += span_notice("It's incompatible with module components.")
|
|
|
|
/**
|
|
* Called when a shell is registered from the component/the component is added to a circuit.
|
|
*
|
|
* Register all signals here on the shell.
|
|
* Arguments:
|
|
* * shell - Shell being registered
|
|
*/
|
|
/obj/item/circuit_component/proc/register_shell(atom/movable/shell)
|
|
return
|
|
|
|
/**
|
|
* Called when a shell is unregistered from the component/the component is removed from a circuit.
|
|
*
|
|
* Unregister all signals here on the shell.
|
|
* Arguments:
|
|
* * shell - Shell being unregistered
|
|
*/
|
|
/obj/item/circuit_component/proc/unregister_shell(atom/movable/shell)
|
|
return
|
|
|
|
/**
|
|
* Disconnects a component from other components
|
|
*
|
|
* Disconnects both the input and output ports of the component
|
|
*/
|
|
/obj/item/circuit_component/proc/disconnect()
|
|
for(var/datum/port/output/port_to_disconnect as anything in output_ports)
|
|
port_to_disconnect.disconnect_all()
|
|
|
|
for(var/datum/port/input/port_to_disconnect as anything in input_ports)
|
|
port_to_disconnect.disconnect_all()
|
|
|
|
/**
|
|
* Adds an input port and returns it
|
|
*
|
|
* Arguments:
|
|
* * name - The name of the input port
|
|
* * 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, order = 1, trigger = .proc/input_received, default = 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))
|
|
input_ports += input_port
|
|
sortTim(input_ports, /proc/cmp_port_order_asc)
|
|
if(parent)
|
|
SStgui.update_uis(parent)
|
|
return input_port
|
|
|
|
/**
|
|
* Removes an input port and deletes it. This will not cleanup any references made by derivatives of the circuit component
|
|
*
|
|
* Arguments:
|
|
* * input_port - The input port to remove.
|
|
*/
|
|
/obj/item/circuit_component/proc/remove_input_port(datum/port/input/input_port)
|
|
input_ports -= input_port
|
|
qdel(input_port)
|
|
if(parent)
|
|
SStgui.update_uis(parent)
|
|
|
|
/**
|
|
* Adds an output port and returns it
|
|
*
|
|
* Arguments:
|
|
* * name - The name of the output port
|
|
* * type - The datatype it handles.
|
|
*/
|
|
/obj/item/circuit_component/proc/add_output_port(name, type, order = 1)
|
|
var/list/arguments = list(src)
|
|
arguments += args
|
|
var/datum/port/output/output_port = new(arglist(arguments))
|
|
output_ports += output_port
|
|
sortTim(output_ports, /proc/cmp_port_order_asc)
|
|
return output_port
|
|
|
|
/**
|
|
* Removes an output port and deletes it. This will not cleanup any references made by derivatives of the circuit component
|
|
*
|
|
* Arguments:
|
|
* * output_port - The output port to remove.
|
|
*/
|
|
/obj/item/circuit_component/proc/remove_output_port(datum/port/output/output_port)
|
|
output_ports -= output_port
|
|
qdel(output_port)
|
|
if(parent)
|
|
SStgui.update_uis(parent)
|
|
|
|
|
|
/**
|
|
* Called whenever an input is received from one of the ports.
|
|
*
|
|
* Return value indicates whether the trigger was successful or not.
|
|
* Arguments:
|
|
* * port - Can be null. The port that sent the input
|
|
* * return_values - Only defined if the component is receiving an input due to instant execution. Contains the values to be returned once execution has stopped.
|
|
*/
|
|
/obj/item/circuit_component/proc/trigger_component(datum/port/input/port, list/return_values)
|
|
SHOULD_NOT_SLEEP(TRUE)
|
|
pre_input_received(port)
|
|
if(!should_receive_input(port))
|
|
return FALSE
|
|
|
|
var/result
|
|
if(port)
|
|
var/proc_to_call = port.trigger
|
|
if(!proc_to_call)
|
|
return FALSE
|
|
result = call(src, proc_to_call)(port, return_values)
|
|
else
|
|
result = input_received(null, return_values)
|
|
|
|
if(result)
|
|
return FALSE
|
|
|
|
if(circuit_flags & CIRCUIT_FLAG_OUTPUT_SIGNAL)
|
|
trigger_output.set_output(COMPONENT_SIGNAL)
|
|
return TRUE
|
|
|
|
/obj/item/circuit_component/proc/set_circuit_size(new_size)
|
|
if(parent)
|
|
parent.current_size -= circuit_size
|
|
|
|
circuit_size = new_size
|
|
|
|
if(parent)
|
|
parent.current_size += circuit_size
|
|
|
|
/**
|
|
* Called whether this circuit component should receive an input.
|
|
* If this returns false, the proc that is supposed to be triggered will not be called and an output signal will not be sent.
|
|
* This is to only return false if flow of execution should be stopped because something bad has happened (e.g. no power)
|
|
* Returning no value in input_received() is not an issue because it means flow of execution will continue even if the component failed to execute properly.
|
|
*
|
|
* Return value indicates whether or not
|
|
* Arguments:
|
|
* * port - Can be null. The port that sent the input
|
|
*/
|
|
/obj/item/circuit_component/proc/should_receive_input(datum/port/input/port)
|
|
SHOULD_NOT_SLEEP(TRUE)
|
|
if(!parent?.on)
|
|
return FALSE
|
|
|
|
if(!parent.admin_only)
|
|
if(circuit_flags & CIRCUIT_FLAG_ADMIN)
|
|
message_admins("[display_name] tried to execute on [parent.get_creator_admin()] that has admin_only set to 0")
|
|
return FALSE
|
|
|
|
var/flags = SEND_SIGNAL(parent, COMSIG_CIRCUIT_PRE_POWER_USAGE, power_usage_per_input)
|
|
if(!(flags & COMPONENT_OVERRIDE_POWER_USAGE))
|
|
var/obj/item/stock_parts/cell/cell = parent.get_cell()
|
|
if(!cell?.use(power_usage_per_input))
|
|
return FALSE
|
|
|
|
if((!port || port.trigger == .proc/input_received) && (circuit_flags & CIRCUIT_FLAG_INPUT_SIGNAL) && !COMPONENT_TRIGGERED_BY(trigger_input, port))
|
|
return FALSE
|
|
|
|
return TRUE
|
|
|
|
/// Called when trying to get the physical location of this object
|
|
/obj/item/circuit_component/proc/get_location()
|
|
return get_turf(src) || get_turf(parent?.shell)
|
|
|
|
/obj/item/circuit_component/balloon_alert(mob/viewer, text)
|
|
if(parent)
|
|
return parent.balloon_alert(viewer, text)
|
|
return ..()
|
|
|
|
|
|
/// Called before input_received and should_receive_input. Used to perform behaviour that shouldn't care whether the input should be received or not.
|
|
/obj/item/circuit_component/proc/pre_input_received(datum/port/input/port)
|
|
SHOULD_NOT_SLEEP(TRUE)
|
|
return
|
|
|
|
/**
|
|
* Called from trigger_component. General component behaviour should go in this proc. This is the default proc that is called if no trigger proc is specified.
|
|
*
|
|
* Return value indicates that the circuit should not send an output signal.
|
|
* Arguments:
|
|
* * port - Can be null. The port that sent the input
|
|
* * return_values - Only defined if the component is receiving an input due to instant execution. Contains the values to be returned once execution has stopped.
|
|
*/
|
|
/obj/item/circuit_component/proc/input_received(datum/port/input/port, list/return_values)
|
|
SHOULD_NOT_SLEEP(TRUE)
|
|
return
|
|
|
|
/// Called when this component is about to be added to an integrated_circuit.
|
|
/obj/item/circuit_component/proc/add_to(obj/item/integrated_circuit/added_to)
|
|
if(circuit_flags & CIRCUIT_FLAG_ADMIN)
|
|
ADD_TRAIT(added_to, TRAIT_CIRCUIT_UNDUPABLE, REF(src))
|
|
return TRUE
|
|
|
|
/// Called when this component is removed from an integrated_circuit.
|
|
/obj/item/circuit_component/proc/removed_from(obj/item/integrated_circuit/removed_from)
|
|
REMOVE_TRAIT(removed_from, TRAIT_CIRCUIT_UNDUPABLE, REF(src))
|
|
return
|
|
|
|
/**
|
|
* Gets the UI notices to be displayed on the CircuitInfo panel.
|
|
*
|
|
* Returns a list of buttons in the following format
|
|
* list(
|
|
* "icon" = ICON(string)
|
|
* "content" = CONTENT(string)
|
|
* "color" = COLOR(string, not a hex)
|
|
* )
|
|
*/
|
|
/obj/item/circuit_component/proc/get_ui_notices()
|
|
. = list()
|
|
|
|
if(circuit_flags & CIRCUIT_FLAG_INSTANT)
|
|
. += create_ui_notice("Instant Execution", "red", "tachometer-alt")
|
|
|
|
if(!removable)
|
|
. += create_ui_notice("Unremovable", "red", "lock")
|
|
|
|
if(length(required_shells))
|
|
. += create_ui_notice("Supported Shells:", "green", "notes-medical")
|
|
for(var/atom/movable/shell as anything in required_shells)
|
|
. += create_ui_notice(initial(shell.name), "green", "plus-square")
|
|
|
|
if(length(input_ports))
|
|
. += create_ui_notice("Power Usage Per Input: [power_usage_per_input]", "orange", "bolt")
|
|
|
|
/**
|
|
* Called when a special button is pressed on this component in the UI.
|
|
*
|
|
* Arguments:
|
|
* * user - Interacting mob
|
|
* * action - A string for which action is being performed. No parameters passed because it's only a button press.
|
|
*/
|
|
/obj/item/circuit_component/proc/ui_perform_action(mob/user, action)
|
|
return
|
|
|
|
/**
|
|
* Creates a UI notice entry to be used in get_ui_notices()
|
|
*
|
|
* Returns a list that can then be added to the return list in get_ui_notices()
|
|
*/
|
|
/obj/item/circuit_component/proc/create_ui_notice(content, color, icon)
|
|
SHOULD_BE_PURE(TRUE)
|
|
SHOULD_NOT_OVERRIDE(TRUE)
|
|
return list(list(
|
|
"icon" = icon,
|
|
"content" = content,
|
|
"color" = color,
|
|
))
|
|
|
|
/obj/item/circuit_component/ui_host(mob/user)
|
|
if(parent)
|
|
return parent.ui_host()
|
|
return ..()
|
|
|
|
/**
|
|
* Creates a table UI notice entry to be used in get_ui_notices()
|
|
*
|
|
* Returns a list that can then be added to the return list in get_ui_notices()
|
|
* Used by components to list their available columns. Recommended to use at the end of get_ui_notices()
|
|
*/
|
|
/obj/item/circuit_component/proc/create_table_notices(list/entries, column_name = "Column", column_name_plural = "Columns")
|
|
SHOULD_BE_PURE(TRUE)
|
|
SHOULD_NOT_OVERRIDE(TRUE)
|
|
. = list()
|
|
. += create_ui_notice("Available [column_name_plural]:", "grey", "question-circle")
|
|
|
|
|
|
for(var/entry in entries)
|
|
. += create_ui_notice("[column_name] Name: '[entry]'", "grey", "columns")
|
|
|
|
/**
|
|
* Called when a circuit component is added to an object with a USB port.
|
|
*
|
|
* Arguments:
|
|
* * shell - The object that USB cables can connect to
|
|
*/
|
|
/obj/item/circuit_component/proc/register_usb_parent(atom/movable/shell)
|
|
return
|
|
|
|
/**
|
|
* Called when a circuit component is removed from an object with a USB port.
|
|
*
|
|
* Arguments:
|
|
* * shell - The object that USB cables can connect to
|
|
*/
|
|
/obj/item/circuit_component/proc/unregister_usb_parent(atom/movable/shell)
|
|
return
|