tgui backend
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* # Compare Component
|
||||
*
|
||||
* Abstract component to build conditional components
|
||||
*/
|
||||
/obj/item/circuit_component/compare
|
||||
display_name = "Compare"
|
||||
|
||||
/// The amount of input ports to have
|
||||
var/input_port_amount = 4
|
||||
|
||||
/// The trigger for the true/false signals
|
||||
var/datum/port/input/compare
|
||||
|
||||
/// Signals sent on compare
|
||||
var/datum/port/output/true
|
||||
var/datum/port/output/false
|
||||
|
||||
/// 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))
|
||||
compare_ports += add_input_port(letter, PORT_TYPE_ANY)
|
||||
|
||||
load_custom_ports()
|
||||
compare = add_input_port("Compare", PORT_TYPE_SIGNAL)
|
||||
|
||||
true = add_output_port("True", PORT_TYPE_SIGNAL)
|
||||
false = add_output_port("False", PORT_TYPE_SIGNAL)
|
||||
result = add_output_port("Result", PORT_TYPE_NUMBER)
|
||||
|
||||
/**
|
||||
* Used by derivatives to load their own ports in for custom use.
|
||||
*/
|
||||
/obj/item/circuit_component/compare/proc/load_custom_ports()
|
||||
return
|
||||
|
||||
/obj/item/circuit_component/compare/input_received(datum/port/input/port)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
|
||||
var/logic_result = do_comparisons(compare_ports)
|
||||
if(COMPONENT_TRIGGERED_BY(compare, port))
|
||||
if(logic_result)
|
||||
true.set_output(COMPONENT_SIGNAL)
|
||||
else
|
||||
false.set_output(COMPONENT_SIGNAL)
|
||||
result.set_output(logic_result)
|
||||
|
||||
/// Do the comparisons and return a result
|
||||
/obj/item/circuit_component/compare/proc/do_comparisons(list/ports)
|
||||
return FALSE
|
||||
@@ -0,0 +1,306 @@
|
||||
/**
|
||||
* # Module Component
|
||||
*
|
||||
* A component that has an input, output
|
||||
*/
|
||||
/obj/item/circuit_component/module
|
||||
display_name = "Module"
|
||||
desc = "A component that has other components within it, acting like a function. Use it in your hand to control the amount of input and output ports it has, as well as being able to access the integrated circuit contained inside."
|
||||
|
||||
var/obj/item/integrated_circuit/module/internal_circuit
|
||||
|
||||
var/obj/item/circuit_component/module_input/input_component
|
||||
var/obj/item/circuit_component/module_output/output_component
|
||||
|
||||
/// Linked ports that follow a `first_port = second_port` keyed structure.
|
||||
var/list/linked_ports = list()
|
||||
|
||||
var/port_limit = 10
|
||||
|
||||
/obj/item/integrated_circuit/module
|
||||
var/obj/item/circuit_component/module/attached_module
|
||||
|
||||
/obj/item/integrated_circuit/module/ui_host(mob/user)
|
||||
. = ..()
|
||||
if(. == src)
|
||||
return attached_module
|
||||
|
||||
/obj/item/integrated_circuit/module/set_display_name(new_name)
|
||||
. = ..()
|
||||
attached_module.display_name = new_name
|
||||
attached_module.name = "module ([new_name])"
|
||||
|
||||
/obj/item/integrated_circuit/module/load_component(type)
|
||||
if(!attached_module)
|
||||
return ..()
|
||||
|
||||
if(ispath(type, /obj/item/circuit_component/module_input))
|
||||
return attached_module.input_component
|
||||
|
||||
if(ispath(type, /obj/item/circuit_component/module_output))
|
||||
return attached_module.output_component
|
||||
|
||||
return ..()
|
||||
|
||||
/obj/item/integrated_circuit/module/Destroy()
|
||||
attached_module = null
|
||||
return ..()
|
||||
|
||||
/obj/item/circuit_component/module_input
|
||||
display_name = "Input"
|
||||
desc = "A component that receives data from the module it is attached to"
|
||||
|
||||
removable = FALSE
|
||||
|
||||
/// The currently attached module
|
||||
var/obj/item/circuit_component/module/attached_module
|
||||
|
||||
/obj/item/circuit_component/module_input/Destroy()
|
||||
attached_module = null
|
||||
return ..()
|
||||
|
||||
/obj/item/circuit_component/module_output
|
||||
display_name = "Output"
|
||||
desc = "A component that outputs data to the module it is attached to."
|
||||
|
||||
removable = FALSE
|
||||
|
||||
/// The currently attached module
|
||||
var/obj/item/circuit_component/module/attached_module
|
||||
|
||||
/obj/item/circuit_component/module_output/input_received(datum/port/input/port)
|
||||
. = ..()
|
||||
if(!port)
|
||||
return
|
||||
// We don't check the parent here because frankly, we don't care. We only sync our input with the module's output
|
||||
var/datum/port/output/port_to_update = attached_module.linked_ports[port]
|
||||
if(!port_to_update)
|
||||
CRASH("[port.type] doesn't have a linked port in [type]!")
|
||||
|
||||
port_to_update.set_output(port.value)
|
||||
|
||||
/obj/item/circuit_component/module/input_received(datum/port/input/port)
|
||||
. = ..()
|
||||
if(!port)
|
||||
return
|
||||
var/datum/port/output/port_to_update = linked_ports[port]
|
||||
if(!port_to_update)
|
||||
CRASH("[port.type] doesn't have a linked port in [type]!")
|
||||
|
||||
port_to_update.set_output(port.value)
|
||||
|
||||
/obj/item/circuit_component/module_output/Destroy()
|
||||
attached_module = null
|
||||
return ..()
|
||||
|
||||
/obj/item/circuit_component/module/Initialize()
|
||||
. = ..()
|
||||
internal_circuit = new(src)
|
||||
internal_circuit.attached_module = src
|
||||
|
||||
input_component = new(internal_circuit)
|
||||
input_component.attached_module = src
|
||||
internal_circuit.add_component(input_component)
|
||||
input_component.rel_x = 0
|
||||
input_component.rel_y = 200
|
||||
|
||||
output_component = new(internal_circuit)
|
||||
output_component.attached_module = src
|
||||
internal_circuit.add_component(output_component)
|
||||
output_component.rel_x = 400
|
||||
output_component.rel_y = 200
|
||||
|
||||
/obj/item/circuit_component/module/save_data_to_list(list/component_data)
|
||||
. = ..()
|
||||
component_data["integrated_circuit"] = internal_circuit.convert_to_json()
|
||||
|
||||
var/list/input_data = list()
|
||||
for(var/datum/port/input/input_port as anything in input_ports)
|
||||
input_data += list(list(
|
||||
"name" = input_port.name,
|
||||
"type" = input_port.datatype,
|
||||
))
|
||||
|
||||
var/list/output_data = list()
|
||||
for(var/datum/port/output/output_port as anything in output_ports)
|
||||
output_data += list(list(
|
||||
"name" = output_port.name,
|
||||
"type" = output_port.datatype,
|
||||
))
|
||||
|
||||
component_data["input_ports"] = input_data
|
||||
component_data["output_ports"] = output_data
|
||||
|
||||
/obj/item/circuit_component/module/load_data_from_list(list/component_data)
|
||||
. = ..()
|
||||
|
||||
var/list/input_ports = component_data["input_ports"]
|
||||
for(var/list/port_data as anything in input_ports)
|
||||
add_and_link_input_port(port_data["name"], port_data["type"])
|
||||
|
||||
var/list/output_ports = component_data["output_ports"]
|
||||
for(var/list/port_data as anything in output_ports)
|
||||
add_and_link_output_port(port_data["name"], port_data["type"])
|
||||
|
||||
if(component_data["integrated_circuit"])
|
||||
internal_circuit.load_circuit_data(component_data["integrated_circuit"])
|
||||
|
||||
/obj/item/circuit_component/module/proc/add_and_link_input_port(name, type)
|
||||
var/datum/port/new_port = add_input_port(name, type)
|
||||
linked_ports[new_port] = input_component.add_output_port(name, type)
|
||||
|
||||
/obj/item/circuit_component/module/proc/add_and_link_output_port(name, type)
|
||||
var/datum/port/new_port = output_component.add_input_port(name, type)
|
||||
linked_ports[new_port] = add_output_port(name, type)
|
||||
|
||||
/obj/item/circuit_component/module/add_to(obj/item/integrated_circuit/added_to)
|
||||
. = ..()
|
||||
RegisterSignal(added_to, COMSIG_CIRCUIT_SET_CELL, .proc/handle_set_cell)
|
||||
RegisterSignal(added_to, COMSIG_CIRCUIT_SET_ON, .proc/handle_set_on)
|
||||
RegisterSignal(added_to, COMSIG_CIRCUIT_SET_SHELL, .proc/handle_set_shell)
|
||||
internal_circuit.set_cell(added_to.cell)
|
||||
internal_circuit.set_shell(added_to.shell)
|
||||
internal_circuit.set_on(added_to.on)
|
||||
|
||||
|
||||
/obj/item/circuit_component/module/removed_from(obj/item/integrated_circuit/removed_from)
|
||||
internal_circuit.set_cell(null)
|
||||
internal_circuit.set_on(FALSE)
|
||||
internal_circuit.remove_current_shell()
|
||||
UnregisterSignal(removed_from, list(
|
||||
COMSIG_CIRCUIT_SET_CELL,
|
||||
COMSIG_CIRCUIT_SET_ON,
|
||||
COMSIG_CIRCUIT_SET_SHELL,
|
||||
))
|
||||
return ..()
|
||||
|
||||
/obj/item/circuit_component/module/proc/handle_set_cell(datum/source, obj/item/stock_parts/cell/cell)
|
||||
SIGNAL_HANDLER
|
||||
internal_circuit.set_cell(cell)
|
||||
|
||||
/obj/item/circuit_component/module/proc/handle_set_on(datum/source, new_value)
|
||||
SIGNAL_HANDLER
|
||||
internal_circuit.set_on(new_value)
|
||||
|
||||
/obj/item/circuit_component/module/proc/handle_set_shell(datum/source, atom/movable/new_shell)
|
||||
SIGNAL_HANDLER
|
||||
internal_circuit.set_shell(new_shell)
|
||||
|
||||
/obj/item/circuit_component/module/Destroy()
|
||||
QDEL_NULL(input_component)
|
||||
QDEL_NULL(output_component)
|
||||
QDEL_NULL(internal_circuit)
|
||||
linked_ports = null
|
||||
return ..()
|
||||
|
||||
/obj/item/circuit_component/module/ui_data(mob/user)
|
||||
. = list()
|
||||
.["input_ports"] = list()
|
||||
for(var/datum/port/input/input_port as anything in input_ports)
|
||||
.["input_ports"] += list(list(
|
||||
"name" = input_port.name,
|
||||
"type" = input_port.datatype,
|
||||
))
|
||||
|
||||
.["output_ports"] = list()
|
||||
for(var/datum/port/output/output_port as anything in output_ports)
|
||||
.["output_ports"] += list(list(
|
||||
"name" = output_port.name,
|
||||
"type" = output_port.datatype,
|
||||
))
|
||||
|
||||
/obj/item/circuit_component/module/ui_static_data(mob/user)
|
||||
. = list()
|
||||
.["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))
|
||||
internal_circuit.attackby(I, user, params)
|
||||
return
|
||||
return ..()
|
||||
|
||||
#define WITHIN_RANGE(id, table) (id >= 1 && id <= length(table))
|
||||
|
||||
/obj/item/circuit_component/module/ui_act(action, list/params)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
|
||||
switch(action)
|
||||
if("open_internal_circuit")
|
||||
internal_circuit.interact(usr)
|
||||
. = TRUE
|
||||
if("add_input_port")
|
||||
if(length(input_ports) > port_limit)
|
||||
return
|
||||
add_and_link_input_port("Input Port", PORT_TYPE_ANY)
|
||||
. = TRUE
|
||||
if("remove_input_port")
|
||||
var/port_id = text2num(params["port_id"])
|
||||
if(!WITHIN_RANGE(port_id, input_ports))
|
||||
return
|
||||
var/datum/port/removed_port = input_ports[port_id]
|
||||
linked_ports -= removed_port
|
||||
remove_input_port(removed_port)
|
||||
input_component.remove_output_port(input_component.output_ports[port_id])
|
||||
. = TRUE
|
||||
if("add_output_port")
|
||||
if(length(output_ports) > port_limit)
|
||||
return
|
||||
add_and_link_output_port("Output Port", PORT_TYPE_ANY)
|
||||
. = TRUE
|
||||
if("remove_output_port")
|
||||
var/port_id = text2num(params["port_id"])
|
||||
if(!WITHIN_RANGE(port_id, output_ports))
|
||||
return
|
||||
|
||||
var/datum/port/removed_port = output_component.input_ports[port_id]
|
||||
linked_ports -= removed_port
|
||||
remove_output_port(output_ports[port_id])
|
||||
output_component.remove_input_port(removed_port)
|
||||
. = TRUE
|
||||
if("set_port_name", "set_port_type")
|
||||
var/port_id = text2num(params["port_id"])
|
||||
var/is_input = params["is_input"]
|
||||
|
||||
var/list/ports_to_use
|
||||
var/list/internal_ports_to_use
|
||||
if(is_input)
|
||||
ports_to_use = input_ports
|
||||
internal_ports_to_use = input_component.output_ports
|
||||
else
|
||||
ports_to_use = output_ports
|
||||
internal_ports_to_use = output_component.input_ports
|
||||
|
||||
if(!WITHIN_RANGE(port_id, ports_to_use))
|
||||
return
|
||||
|
||||
var/datum/port/component_port = ports_to_use[port_id]
|
||||
var/datum/port/internal_component_port = internal_ports_to_use[port_id]
|
||||
|
||||
if(action == "set_port_type")
|
||||
var/type = params["port_type"]
|
||||
if(!(type in GLOB.wiremod_basic_types))
|
||||
return
|
||||
component_port.set_datatype(type)
|
||||
internal_component_port.set_datatype(type)
|
||||
else
|
||||
var/port_name = params["port_name"]
|
||||
if(!port_name)
|
||||
return
|
||||
port_name = strip_html(port_name, PORT_MAX_NAME_LENGTH)
|
||||
component_port.name = port_name
|
||||
internal_component_port.name = port_name
|
||||
. = TRUE
|
||||
|
||||
if(.)
|
||||
SStgui.update_uis(internal_circuit)
|
||||
|
||||
#undef WITHIN_RANGE
|
||||
|
||||
/obj/item/circuit_component/module/ui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, "CircuitModule", name)
|
||||
ui.open()
|
||||
ui.set_autoupdate(FALSE)
|
||||
@@ -0,0 +1,68 @@
|
||||
/**
|
||||
* # Light Component
|
||||
*
|
||||
* Emits a light of a specific brightness and colour. Requires a shell.
|
||||
*/
|
||||
/obj/item/circuit_component/light
|
||||
display_name = "Light"
|
||||
desc = "A component that emits a light of a specific brightness and colour. Requires a shell."
|
||||
|
||||
/// The colours of the light
|
||||
var/datum/port/input/red
|
||||
var/datum/port/input/green
|
||||
var/datum/port/input/blue
|
||||
|
||||
/// The brightness
|
||||
var/datum/port/input/brightness
|
||||
|
||||
/// Whether the light is on or not
|
||||
var/datum/port/input/on
|
||||
|
||||
var/max_power = 5
|
||||
var/min_lightness = 0.4
|
||||
var/shell_light_color
|
||||
|
||||
/obj/item/circuit_component/light/get_ui_notices()
|
||||
. = ..()
|
||||
. += create_ui_notice("Maximum Brightness: [max_power]", "orange", "lightbulb")
|
||||
|
||||
/obj/item/circuit_component/light/Initialize()
|
||||
. = ..()
|
||||
red = add_input_port("Red", PORT_TYPE_NUMBER)
|
||||
green = add_input_port("Green", PORT_TYPE_NUMBER)
|
||||
blue = add_input_port("Blue", PORT_TYPE_NUMBER)
|
||||
brightness = add_input_port("Brightness", PORT_TYPE_NUMBER)
|
||||
|
||||
on = add_input_port("On", PORT_TYPE_NUMBER)
|
||||
|
||||
/obj/item/circuit_component/light/register_shell(atom/movable/shell)
|
||||
. = ..()
|
||||
TRIGGER_CIRCUIT_COMPONENT(src, null)
|
||||
|
||||
/obj/item/circuit_component/light/unregister_shell(atom/movable/shell)
|
||||
shell.set_light_on(FALSE)
|
||||
return ..()
|
||||
|
||||
/obj/item/circuit_component/light/input_received(datum/port/input/port)
|
||||
. = ..()
|
||||
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])
|
||||
if(.)
|
||||
return
|
||||
|
||||
if(parent.shell)
|
||||
set_atom_light(parent.shell)
|
||||
|
||||
/obj/item/circuit_component/light/proc/set_atom_light(atom/movable/target_atom)
|
||||
// Clamp anyways just for safety
|
||||
var/bright_val = min(max(brightness.value || 0, 0), max_power)
|
||||
|
||||
target_atom.set_light_power(bright_val)
|
||||
target_atom.set_light_range(bright_val)
|
||||
target_atom.set_light_color(shell_light_color)
|
||||
target_atom.set_light_on(!!on.value)
|
||||
@@ -0,0 +1,175 @@
|
||||
/**
|
||||
* # Man-Machine Interface Component
|
||||
*
|
||||
* Allows an MMI to be inserted into a shell, allowing it to be linked up. Requires a shell.
|
||||
*/
|
||||
/obj/item/circuit_component/mmi
|
||||
display_name = "Man-Machine Interface"
|
||||
desc = "A component that allows MMI to enter shells to send output signals."
|
||||
|
||||
/// The message to send to the MMI in the shell.
|
||||
var/datum/port/input/message
|
||||
/// Sends the current MMI a message
|
||||
var/datum/port/input/send
|
||||
/// Ejects the current MMI
|
||||
var/datum/port/input/eject
|
||||
|
||||
/// Called when the MMI tries moving north
|
||||
var/datum/port/output/north
|
||||
/// Called when the MMI tries moving east
|
||||
var/datum/port/output/east
|
||||
/// Called when the MMI tries moving south
|
||||
var/datum/port/output/south
|
||||
/// Called when the MMI tries moving west
|
||||
var/datum/port/output/west
|
||||
|
||||
/// Returns what the MMI last clicked on.
|
||||
var/datum/port/output/clicked_atom
|
||||
/// Called when the MMI clicks.
|
||||
var/datum/port/output/attack
|
||||
/// Called when the MMI right clicks.
|
||||
var/datum/port/output/secondary_attack
|
||||
|
||||
/// The current MMI card
|
||||
var/obj/item/mmi/brain
|
||||
|
||||
/// Maximum length of the message that can be sent to the MMI
|
||||
var/max_length = 300
|
||||
|
||||
/obj/item/circuit_component/mmi/Initialize()
|
||||
. = ..()
|
||||
message = add_input_port("Message", PORT_TYPE_STRING)
|
||||
send = add_input_port("Send Message", PORT_TYPE_SIGNAL)
|
||||
eject = add_input_port("Eject", PORT_TYPE_SIGNAL)
|
||||
|
||||
north = add_output_port("North", PORT_TYPE_SIGNAL)
|
||||
east = add_output_port("East", PORT_TYPE_SIGNAL)
|
||||
south = add_output_port("South", PORT_TYPE_SIGNAL)
|
||||
west = add_output_port("West", PORT_TYPE_SIGNAL)
|
||||
|
||||
attack = add_output_port("Attack", PORT_TYPE_SIGNAL)
|
||||
secondary_attack = add_output_port("Secondary Attack", PORT_TYPE_SIGNAL)
|
||||
clicked_atom = add_output_port("Target Entity", PORT_TYPE_ATOM)
|
||||
|
||||
/obj/item/circuit_component/mmi/Destroy()
|
||||
remove_current_brain()
|
||||
return ..()
|
||||
|
||||
/obj/item/circuit_component/mmi/input_received(datum/port/input/port)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
|
||||
if(!brain)
|
||||
return
|
||||
|
||||
if(COMPONENT_TRIGGERED_BY(eject, port))
|
||||
remove_current_brain()
|
||||
if(COMPONENT_TRIGGERED_BY(send, port))
|
||||
if(!message.value)
|
||||
return
|
||||
|
||||
var/msg_str = copytext(html_encode(message.value), 1, max_length)
|
||||
|
||||
var/mob/living/target = brain.brainmob
|
||||
if(!target)
|
||||
return
|
||||
|
||||
to_chat(target, "[span_bold("You hear a message in your ear: ")][msg_str]")
|
||||
|
||||
|
||||
/obj/item/circuit_component/mmi/register_shell(atom/movable/shell)
|
||||
. = ..()
|
||||
RegisterSignal(shell, COMSIG_PARENT_ATTACKBY, .proc/handle_attack_by)
|
||||
|
||||
/obj/item/circuit_component/mmi/unregister_shell(atom/movable/shell)
|
||||
UnregisterSignal(shell, COMSIG_PARENT_ATTACKBY)
|
||||
remove_current_brain()
|
||||
return ..()
|
||||
|
||||
/obj/item/circuit_component/mmi/proc/handle_attack_by(atom/movable/shell, obj/item/item, mob/living/attacker)
|
||||
SIGNAL_HANDLER
|
||||
if(istype(item, /obj/item/mmi))
|
||||
var/obj/item/mmi/target_mmi = item
|
||||
if(!target_mmi.brainmob)
|
||||
return
|
||||
add_mmi(item)
|
||||
return COMPONENT_NO_AFTERATTACK
|
||||
|
||||
/obj/item/circuit_component/mmi/proc/add_mmi(obj/item/mmi/to_add)
|
||||
remove_current_brain()
|
||||
|
||||
to_add.forceMove(src)
|
||||
if(to_add.brainmob)
|
||||
update_mmi_mob(to_add, null, to_add.brainmob)
|
||||
brain = to_add
|
||||
RegisterSignal(to_add, COMSIG_PARENT_QDELETING, .proc/remove_current_brain)
|
||||
RegisterSignal(to_add, COMSIG_MOVABLE_MOVED, .proc/mmi_moved)
|
||||
|
||||
/obj/item/circuit_component/mmi/proc/mmi_moved(atom/movable/mmi)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(mmi.loc != src)
|
||||
remove_current_brain()
|
||||
|
||||
/obj/item/circuit_component/mmi/proc/remove_current_brain()
|
||||
SIGNAL_HANDLER
|
||||
if(!brain)
|
||||
return
|
||||
|
||||
if(brain.brainmob)
|
||||
update_mmi_mob(brain, brain.brainmob)
|
||||
UnregisterSignal(brain, list(
|
||||
COMSIG_PARENT_QDELETING,
|
||||
COMSIG_MOVABLE_MOVED
|
||||
))
|
||||
if(brain.loc == src)
|
||||
brain.forceMove(drop_location())
|
||||
brain = null
|
||||
|
||||
/obj/item/circuit_component/mmi/proc/update_mmi_mob(datum/source, mob/living/old_mmi, mob/living/new_mmi)
|
||||
SIGNAL_HANDLER
|
||||
if(old_mmi)
|
||||
old_mmi.remote_control = null
|
||||
UnregisterSignal(old_mmi, COMSIG_MOB_CLICKON)
|
||||
if(new_mmi)
|
||||
new_mmi.remote_control = src
|
||||
RegisterSignal(new_mmi, COMSIG_MOB_CLICKON, .proc/handle_mmi_attack)
|
||||
|
||||
/obj/item/circuit_component/mmi/relaymove(mob/living/user, direct)
|
||||
if(user != brain.brainmob)
|
||||
return ..()
|
||||
|
||||
if(direct & NORTH)
|
||||
north.set_output(COMPONENT_SIGNAL)
|
||||
if(direct & WEST)
|
||||
west.set_output(COMPONENT_SIGNAL)
|
||||
if(direct & EAST)
|
||||
east.set_output(COMPONENT_SIGNAL)
|
||||
if(direct & SOUTH)
|
||||
south.set_output(COMPONENT_SIGNAL)
|
||||
|
||||
return TRUE
|
||||
|
||||
/obj/item/circuit_component/mmi/proc/handle_mmi_attack(mob/living/source, atom/target, list/mods)
|
||||
SIGNAL_HANDLER
|
||||
var/list/modifiers = params2list(mods)
|
||||
if(modifiers[RIGHT_CLICK])
|
||||
clicked_atom.set_output(target)
|
||||
secondary_attack.set_output(COMPONENT_SIGNAL)
|
||||
. = COMSIG_MOB_CANCEL_CLICKON
|
||||
else if(modifiers[LEFT_CLICK] && !modifiers[SHIFT_CLICK] && !modifiers[ALT_CLICK] && !modifiers[CTRL_CLICK])
|
||||
clicked_atom.set_output(target)
|
||||
attack.set_output(COMPONENT_SIGNAL)
|
||||
. = COMSIG_MOB_CANCEL_CLICKON
|
||||
|
||||
/obj/item/circuit_component/mmi/add_to(obj/item/integrated_circuit/add_to)
|
||||
. = ..()
|
||||
if(HAS_TRAIT(add_to, TRAIT_COMPONENT_MMI))
|
||||
return FALSE
|
||||
ADD_TRAIT(add_to, TRAIT_COMPONENT_MMI, src)
|
||||
|
||||
/obj/item/circuit_component/mmi/removed_from(obj/item/integrated_circuit/removed_from)
|
||||
REMOVE_TRAIT(removed_from, TRAIT_COMPONENT_MMI, src)
|
||||
remove_current_brain()
|
||||
return ..()
|
||||
@@ -0,0 +1,113 @@
|
||||
/**
|
||||
* # Pathfinding component
|
||||
*
|
||||
* Calcualtes a path, returns a list of entities. Each entity is the next step in the path. Can be used with the direction component to move.
|
||||
*/
|
||||
/obj/item/circuit_component/pathfind
|
||||
display_name = "Pathfinder"
|
||||
desc = "When triggered, the next step to the target's location as an entity. This can be used with the direction component and the drone shell to make it move on its own. The Id Card input port is for considering ID access when pathing, it does not give the shell actual access."
|
||||
circuit_flags = CIRCUIT_FLAG_INPUT_SIGNAL|CIRCUIT_FLAG_OUTPUT_SIGNAL
|
||||
|
||||
var/datum/port/input/input_X
|
||||
var/datum/port/input/input_Y
|
||||
var/datum/port/input/id_card
|
||||
|
||||
var/datum/port/output/output
|
||||
var/datum/port/output/finished
|
||||
var/datum/port/output/failed
|
||||
var/datum/port/output/reason_failed
|
||||
|
||||
var/list/path
|
||||
var/turf/old_dest
|
||||
var/turf/next_turf
|
||||
|
||||
// Cooldown to limit how frequently we can path to the same location.
|
||||
var/same_path_cooldown = 5 SECONDS
|
||||
var/different_path_cooldown = 30 SECONDS
|
||||
|
||||
var/max_range = 60
|
||||
|
||||
/obj/item/circuit_component/pathfind/get_ui_notices()
|
||||
. = ..()
|
||||
// Not necessary to show the same path cooldown, since it doesn't change much for the player
|
||||
. += create_ui_notice("Pathfinding Cooldown: [DisplayTimeText(different_path_cooldown)]", "orange", "stopwatch")
|
||||
. += create_ui_notice("Maximum Range: [max_range] tiles", "orange", "info")
|
||||
|
||||
/obj/item/circuit_component/pathfind/Initialize()
|
||||
. = ..()
|
||||
input_X = add_input_port("Target X", PORT_TYPE_NUMBER, FALSE)
|
||||
input_Y = add_input_port("Target Y", PORT_TYPE_NUMBER, FALSE)
|
||||
id_card = add_input_port("ID Card", PORT_TYPE_ATOM, FALSE)
|
||||
|
||||
output = add_output_port("Next step", PORT_TYPE_ATOM)
|
||||
finished = add_output_port("Arrived to destination", PORT_TYPE_SIGNAL)
|
||||
failed = add_output_port("Failed", PORT_TYPE_SIGNAL)
|
||||
reason_failed = add_output_port("Fail reason", PORT_TYPE_STRING)
|
||||
|
||||
/obj/item/circuit_component/pathfind/input_received(datum/port/input/port)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
|
||||
var/target_X = input_X.value
|
||||
if(isnull(target_X))
|
||||
return
|
||||
|
||||
var/target_Y = input_Y.value
|
||||
if(isnull(target_Y))
|
||||
return
|
||||
|
||||
var/atom/path_id = id_card.value
|
||||
if(path_id && !istype(path_id, /obj/item/card/id))
|
||||
path_id = null
|
||||
failed.set_output(COMPONENT_SIGNAL)
|
||||
reason_failed.set_output("Object marked is not an ID! Using no ID instead.")
|
||||
|
||||
// Get both the current turf and the destination's turf
|
||||
var/turf/current_turf = get_turf(src)
|
||||
var/turf/destination = locate(target_X, target_Y, current_turf?.z)
|
||||
|
||||
// We're already here! No need to do anything.
|
||||
if(current_turf == destination)
|
||||
finished.set_output(COMPONENT_SIGNAL)
|
||||
old_dest = null
|
||||
TIMER_COOLDOWN_END(parent, COOLDOWN_CIRCUIT_PATHFIND_SAME)
|
||||
next_turf = null
|
||||
return
|
||||
|
||||
// If we're going to the same place and the cooldown hasn't subsided, we're probably on the same path as before
|
||||
if (destination == old_dest && TIMER_COOLDOWN_CHECK(parent, COOLDOWN_CIRCUIT_PATHFIND_SAME))
|
||||
|
||||
// Check if the current turf is the same as the current turf we're supposed to be in. If so, then we set the next step as the next turf on the list
|
||||
if(current_turf == next_turf)
|
||||
popleft(path)
|
||||
next_turf = get_turf(path[1])
|
||||
output.set_output(next_turf)
|
||||
|
||||
// Restart the cooldown since we don't need a new path ( TIMER_COOLDOWN_START might restart the timer by itself and i dont need to call TIMER_COOLDOWN_END, but better safe than sorry )
|
||||
TIMER_COOLDOWN_END(parent, COOLDOWN_CIRCUIT_PATHFIND_SAME)
|
||||
TIMER_COOLDOWN_START(parent, COOLDOWN_CIRCUIT_PATHFIND_SAME, same_path_cooldown)
|
||||
|
||||
|
||||
else // Either we're not going to the same place or the cooldown is over. Either way, we need a new path
|
||||
|
||||
if(destination != old_dest && TIMER_COOLDOWN_CHECK(parent, COOLDOWN_CIRCUIT_PATHFIND_DIF))
|
||||
failed.set_output(COMPONENT_SIGNAL)
|
||||
reason_failed.set_output("Cooldown still active!")
|
||||
return
|
||||
|
||||
TIMER_COOLDOWN_END(parent, COOLDOWN_CIRCUIT_PATHFIND_SAME)
|
||||
|
||||
old_dest = destination
|
||||
path = get_path_to(src, destination, max_range, id=path_id)
|
||||
if(length(path) == 0 || !path)// Check if we can even path there
|
||||
next_turf = null
|
||||
failed.set_output(COMPONENT_SIGNAL)
|
||||
reason_failed.set_output("Can't go there!")
|
||||
return
|
||||
else
|
||||
TIMER_COOLDOWN_START(parent, COOLDOWN_CIRCUIT_PATHFIND_DIF, different_path_cooldown)
|
||||
next_turf = get_turf(path[1])
|
||||
output.set_output(next_turf)
|
||||
TIMER_COOLDOWN_START(parent, COOLDOWN_CIRCUIT_PATHFIND_SAME, same_path_cooldown)
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* # Pull Component
|
||||
*
|
||||
* Tells the shell to start pulling on a designated atom. Only works on movable shells.
|
||||
*/
|
||||
/obj/item/circuit_component/pull
|
||||
display_name = "Start Pulling"
|
||||
desc = "A component that can force the shell to pull entities. Only works for drone shells."
|
||||
|
||||
/// Frequency input
|
||||
var/datum/port/input/target
|
||||
circuit_flags = CIRCUIT_FLAG_INPUT_SIGNAL|CIRCUIT_FLAG_OUTPUT_SIGNAL
|
||||
|
||||
/obj/item/circuit_component/pull/Initialize()
|
||||
. = ..()
|
||||
target = add_input_port("Target", PORT_TYPE_ATOM)
|
||||
|
||||
/obj/item/circuit_component/pull/input_received(datum/port/input/port)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
|
||||
var/atom/target_atom = target.value
|
||||
if(!target_atom)
|
||||
return
|
||||
|
||||
var/mob/shell = parent.shell
|
||||
if(!istype(shell) || get_dist(shell, target_atom) > 1 || shell.z != target_atom.z)
|
||||
return
|
||||
|
||||
shell.start_pulling(target_atom)
|
||||
@@ -0,0 +1,74 @@
|
||||
#define COMP_RADIO_PUBLIC "public"
|
||||
#define COMP_RADIO_PRIVATE "private"
|
||||
|
||||
/**
|
||||
* # Radio Component
|
||||
*
|
||||
* Listens out for signals on the designated frequencies and sends signals on designated frequencies
|
||||
*/
|
||||
/obj/item/circuit_component/radio
|
||||
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
|
||||
var/datum/port/input/code
|
||||
|
||||
/// Current frequency value
|
||||
var/current_freq = DEFAULT_SIGNALER_CODE
|
||||
|
||||
var/datum/radio_frequency/radio_connection
|
||||
|
||||
/obj/item/circuit_component/radio/populate_options()
|
||||
var/static/component_options = list(
|
||||
COMP_RADIO_PUBLIC,
|
||||
COMP_RADIO_PRIVATE,
|
||||
)
|
||||
public_options = add_option_port("Encryption Options", component_options)
|
||||
|
||||
/obj/item/circuit_component/radio/Initialize()
|
||||
. = ..()
|
||||
freq = add_input_port("Frequency", PORT_TYPE_NUMBER, default = FREQ_SIGNALER)
|
||||
code = add_input_port("Code", PORT_TYPE_NUMBER, default = DEFAULT_SIGNALER_CODE)
|
||||
TRIGGER_CIRCUIT_COMPONENT(src, null)
|
||||
// These are cleaned up on the parent
|
||||
trigger_input = add_input_port("Send", PORT_TYPE_SIGNAL)
|
||||
trigger_output = add_output_port("Received", PORT_TYPE_SIGNAL)
|
||||
|
||||
/obj/item/circuit_component/radio/Destroy()
|
||||
SSradio.remove_object(src, current_freq)
|
||||
return ..()
|
||||
|
||||
/obj/item/circuit_component/radio/input_received(datum/port/input/port)
|
||||
. = ..()
|
||||
freq.set_value(sanitize_frequency(freq.value, TRUE))
|
||||
if(.)
|
||||
return
|
||||
var/frequency = freq.value
|
||||
|
||||
SSradio.remove_object(src, current_freq)
|
||||
radio_connection = SSradio.add_object(src, frequency, RADIO_SIGNALER)
|
||||
current_freq = frequency
|
||||
|
||||
if(COMPONENT_TRIGGERED_BY(trigger_input, port))
|
||||
var/datum/signal/signal = new(list("code" = round(code.value) || 0, "key" = parent?.owner_id))
|
||||
radio_connection.post_signal(src, signal)
|
||||
|
||||
/obj/item/circuit_component/radio/receive_signal(datum/signal/signal)
|
||||
. = FALSE
|
||||
if(!signal)
|
||||
return
|
||||
if(signal.data["code"] != round(code.value || 0))
|
||||
return
|
||||
|
||||
if(public_options.value == COMP_RADIO_PRIVATE && parent?.owner_id != signal.data["key"])
|
||||
return
|
||||
|
||||
trigger_output.set_output(COMPONENT_SIGNAL)
|
||||
|
||||
#undef COMP_RADIO_PUBLIC
|
||||
#undef COMP_RADIO_PRIVATE
|
||||
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
* # Sound Emitter Component
|
||||
*
|
||||
* A component that emits a sound when it receives an input.
|
||||
*/
|
||||
/obj/item/circuit_component/soundemitter
|
||||
display_name = "Sound Emitter"
|
||||
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
|
||||
|
||||
/// Frequency of the sound when played
|
||||
var/datum/port/input/frequency
|
||||
|
||||
/// The cooldown for this component of how often it can play sounds.
|
||||
var/sound_cooldown = 2 SECONDS
|
||||
|
||||
var/list/options_map
|
||||
|
||||
/obj/item/circuit_component/soundemitter/get_ui_notices()
|
||||
. = ..()
|
||||
. += create_ui_notice("Sound Cooldown: [DisplayTimeText(sound_cooldown)]", "orange", "stopwatch")
|
||||
|
||||
|
||||
/obj/item/circuit_component/soundemitter/Initialize()
|
||||
. = ..()
|
||||
volume = add_input_port("Volume", PORT_TYPE_NUMBER, default = 35)
|
||||
frequency = add_input_port("Frequency", PORT_TYPE_NUMBER, default = 0)
|
||||
|
||||
/obj/item/circuit_component/soundemitter/populate_options()
|
||||
var/static/component_options = list(
|
||||
"Buzz" = 'sound/machines/buzz-sigh.ogg',
|
||||
"Buzz Twice" = 'sound/machines/buzz-two.ogg',
|
||||
"Chime" = 'sound/machines/chime.ogg',
|
||||
"Honk" = 'sound/items/bikehorn.ogg',
|
||||
"Ping" = 'sound/machines/ping.ogg',
|
||||
"Sad Trombone" = 'sound/misc/sadtrombone.ogg',
|
||||
"Warn" = 'sound/machines/warning-buzzer.ogg',
|
||||
"Slow Clap" = 'sound/machines/slowclap.ogg',
|
||||
)
|
||||
sound_file = add_option_port("Sound Option", component_options)
|
||||
options_map = component_options
|
||||
|
||||
|
||||
/obj/item/circuit_component/soundemitter/input_received(datum/port/input/port)
|
||||
. = ..()
|
||||
volume.set_value(clamp(volume.value, 0, 100))
|
||||
frequency.set_value(clamp(frequency.value, -100, 100))
|
||||
if(.)
|
||||
return
|
||||
|
||||
if(TIMER_COOLDOWN_CHECK(parent, COOLDOWN_CIRCUIT_SOUNDEMITTER))
|
||||
return
|
||||
|
||||
var/sound_to_play = options_map[sound_file.value]
|
||||
if(!sound_to_play)
|
||||
return
|
||||
|
||||
playsound(src, sound_to_play, volume.value, frequency != 0, frequency = frequency.value)
|
||||
|
||||
TIMER_COOLDOWN_START(parent, COOLDOWN_CIRCUIT_SOUNDEMITTER, sound_cooldown)
|
||||
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* # Speech Component
|
||||
*
|
||||
* Sends a message. Requires a shell.
|
||||
*/
|
||||
/obj/item/circuit_component/speech
|
||||
display_name = "Speech"
|
||||
desc = "A component that sends a message. Requires a shell."
|
||||
circuit_flags = CIRCUIT_FLAG_INPUT_SIGNAL|CIRCUIT_FLAG_OUTPUT_SIGNAL
|
||||
|
||||
/// The message to send
|
||||
var/datum/port/input/message
|
||||
|
||||
/// The cooldown for this component of how often it can send speech messages.
|
||||
var/speech_cooldown = 1 SECONDS
|
||||
|
||||
/obj/item/circuit_component/speech/get_ui_notices()
|
||||
. = ..()
|
||||
. += create_ui_notice("Speech Cooldown: [DisplayTimeText(speech_cooldown)]", "orange", "stopwatch")
|
||||
|
||||
/obj/item/circuit_component/speech/Initialize()
|
||||
. = ..()
|
||||
message = add_input_port("Message", PORT_TYPE_STRING, FALSE)
|
||||
|
||||
/obj/item/circuit_component/speech/input_received(datum/port/input/port)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
|
||||
if(TIMER_COOLDOWN_CHECK(parent, COOLDOWN_CIRCUIT_SPEECH))
|
||||
return
|
||||
|
||||
if(message.value)
|
||||
var/atom/movable/shell = parent.shell
|
||||
// Prevents appear as the individual component if there is a shell.
|
||||
if(shell)
|
||||
shell.say(message.value)
|
||||
else
|
||||
say(message.value)
|
||||
TIMER_COOLDOWN_START(parent, COOLDOWN_CIRCUIT_SPEECH, speech_cooldown)
|
||||
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* # Get Variable Component
|
||||
*
|
||||
* A component that gets a variable on an object
|
||||
*/
|
||||
/obj/item/circuit_component/get_variable
|
||||
display_name = "Get Variable"
|
||||
desc = "A component that gets a variable on an object."
|
||||
circuit_flags = CIRCUIT_FLAG_INPUT_SIGNAL|CIRCUIT_FLAG_OUTPUT_SIGNAL|CIRCUIT_FLAG_ADMIN
|
||||
|
||||
/// Entity to get variable of
|
||||
var/datum/port/input/entity
|
||||
|
||||
/// Variable name
|
||||
var/datum/port/input/variable_name
|
||||
|
||||
/// Variable value
|
||||
var/datum/port/output/output_value
|
||||
|
||||
|
||||
/obj/item/circuit_component/get_variable/Initialize()
|
||||
. = ..()
|
||||
entity = add_input_port("Target", PORT_TYPE_ATOM)
|
||||
variable_name = add_input_port("Variable Name", PORT_TYPE_STRING)
|
||||
|
||||
output_value = add_output_port("Output Value", PORT_TYPE_ANY)
|
||||
|
||||
/obj/item/circuit_component/get_variable/input_received(datum/port/input/port)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
var/atom/object = entity.value
|
||||
var/var_name = variable_name.value
|
||||
if(!var_name || !object)
|
||||
output_value.set_output(null)
|
||||
return
|
||||
|
||||
if(!object.can_vv_get(var_name) || !(var_name in object.vars))
|
||||
output_value.set_output(null)
|
||||
return
|
||||
|
||||
output_value.set_output(object.vars[var_name])
|
||||
@@ -0,0 +1,72 @@
|
||||
#define COMP_PROC_GLOBAL "Global"
|
||||
#define COMP_PROC_OBJECT "Object"
|
||||
|
||||
|
||||
/**
|
||||
* # Proc Call Component
|
||||
*
|
||||
* A component that calls a proc on an object and outputs the return value
|
||||
*/
|
||||
/obj/item/circuit_component/proccall
|
||||
display_name = "Proc Call"
|
||||
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
|
||||
|
||||
/// Proc to call
|
||||
var/datum/port/input/proc_name
|
||||
|
||||
/// Arguments
|
||||
var/datum/port/input/arguments
|
||||
|
||||
/// Returns the output from the proccall
|
||||
var/datum/port/output/output_value
|
||||
|
||||
/obj/item/circuit_component/proccall/populate_options()
|
||||
var/static/list/component_options = list(
|
||||
COMP_PROC_OBJECT,
|
||||
COMP_PROC_GLOBAL,
|
||||
)
|
||||
|
||||
proccall_options = add_option_port("Proccall Options", component_options)
|
||||
|
||||
/obj/item/circuit_component/proccall/Initialize()
|
||||
. = ..()
|
||||
entity = add_input_port("Target", PORT_TYPE_ATOM)
|
||||
proc_name = add_input_port("Proc Name", PORT_TYPE_STRING)
|
||||
arguments = add_input_port("Arguments", PORT_TYPE_LIST)
|
||||
|
||||
output_value = add_output_port("Output Value", PORT_TYPE_ANY)
|
||||
|
||||
/obj/item/circuit_component/proccall/input_received(datum/port/input/port)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
|
||||
var/called_on
|
||||
if(proccall_options.value == COMP_PROC_OBJECT)
|
||||
called_on = entity.value
|
||||
else
|
||||
called_on = GLOBAL_PROC
|
||||
|
||||
if(!called_on)
|
||||
return
|
||||
|
||||
var/to_invoke = proc_name.value
|
||||
var/params = arguments.value || list()
|
||||
|
||||
if(!to_invoke)
|
||||
return
|
||||
|
||||
GLOB.AdminProcCaller = "CHAT_[parent.display_name]" //_ won't show up in ckeys so it'll never match with a real admin
|
||||
var/result = WrapAdminProcCall(called_on, to_invoke, params)
|
||||
GLOB.AdminProcCaller = null
|
||||
|
||||
output_value.set_output(result)
|
||||
|
||||
#undef COMP_PROC_GLOBAL
|
||||
#undef COMP_PROC_OBJECT
|
||||
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* # SDQL Component
|
||||
*
|
||||
* A component that performs an sdql operation
|
||||
*/
|
||||
/obj/item/circuit_component/sdql_operation
|
||||
display_name = "SDQL Operation"
|
||||
desc = "A component that performs an SDQL operation when invoked."
|
||||
circuit_flags = CIRCUIT_FLAG_INPUT_SIGNAL|CIRCUIT_FLAG_OUTPUT_SIGNAL|CIRCUIT_FLAG_ADMIN
|
||||
|
||||
/// SDQL Operation to invoke
|
||||
var/datum/port/input/sdql_operation
|
||||
|
||||
var/datum/port/output/results
|
||||
|
||||
|
||||
/obj/item/circuit_component/sdql_operation/Initialize()
|
||||
. = ..()
|
||||
sdql_operation = add_input_port("SDQL String", PORT_TYPE_STRING)
|
||||
results = add_output_port("Result", PORT_TYPE_LIST)
|
||||
|
||||
/obj/item/circuit_component/sdql_operation/input_received(datum/port/input/port)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
|
||||
var/operation = sdql_operation.value
|
||||
|
||||
if(GLOB.AdminProcCaller || !operation)
|
||||
return TRUE
|
||||
|
||||
GLOB.AdminProcCaller = "CHAT_[parent.display_name]" //_ won't show up in ckeys so it'll never match with a real admin
|
||||
var/list/result = world.SDQL2_query(operation, parent.get_creator_admin(), parent.get_creator())
|
||||
GLOB.AdminProcCaller = null
|
||||
|
||||
results.set_output(result)
|
||||
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* # Set Variable Component
|
||||
*
|
||||
* A component that sets a variable on an object
|
||||
*/
|
||||
/obj/item/circuit_component/set_variable
|
||||
display_name = "Set Variable"
|
||||
desc = "A component that sets a variable on an object."
|
||||
circuit_flags = CIRCUIT_FLAG_INPUT_SIGNAL|CIRCUIT_FLAG_OUTPUT_SIGNAL|CIRCUIT_FLAG_ADMIN
|
||||
|
||||
/// Entity to set variable of
|
||||
var/datum/port/input/entity
|
||||
|
||||
/// Variable name
|
||||
var/datum/port/input/variable_name
|
||||
|
||||
/// New value to set the variable name to.
|
||||
var/datum/port/input/new_value
|
||||
|
||||
|
||||
/obj/item/circuit_component/set_variable/Initialize()
|
||||
. = ..()
|
||||
entity = add_input_port("Target", PORT_TYPE_ATOM)
|
||||
variable_name = add_input_port("Variable Name", PORT_TYPE_STRING)
|
||||
new_value = add_input_port("New Value", PORT_TYPE_ANY)
|
||||
|
||||
/obj/item/circuit_component/set_variable/input_received(datum/port/input/port)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
var/atom/object = entity.value
|
||||
var/var_name = variable_name.value
|
||||
if(!var_name || !object)
|
||||
return
|
||||
|
||||
object.vv_edit_var(var_name, new_value.value)
|
||||
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* # Spawn Atom Component
|
||||
*
|
||||
* Spawns an atom.
|
||||
*/
|
||||
/obj/item/circuit_component/spawn_atom
|
||||
display_name = "Spawn Atom"
|
||||
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
|
||||
var/datum/port/input/input_path
|
||||
|
||||
/// The turf to spawn them at
|
||||
var/datum/port/input/spawn_at
|
||||
|
||||
/// Parameters to pass to the atom being spawned
|
||||
var/datum/port/input/parameters
|
||||
|
||||
/// The result from the output
|
||||
var/datum/port/output/spawned_atom
|
||||
|
||||
/obj/item/circuit_component/spawn_atom/Initialize()
|
||||
. = ..()
|
||||
input_path = add_input_port("Type", PORT_TYPE_ANY)
|
||||
spawn_at = add_input_port("Spawn At", PORT_TYPE_ATOM)
|
||||
parameters = add_input_port("Parameters", PORT_TYPE_LIST)
|
||||
|
||||
spawned_atom = add_output_port("Spawned Atom", PORT_TYPE_ATOM)
|
||||
|
||||
/obj/item/circuit_component/spawn_atom/input_received(datum/port/input/port)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
|
||||
var/typepath = input_path.value
|
||||
|
||||
if(!ispath(typepath, /atom))
|
||||
return
|
||||
|
||||
var/list/params = parameters.value
|
||||
if(!params)
|
||||
params = list()
|
||||
|
||||
params.Insert(1, spawn_at.value)
|
||||
|
||||
spawned_atom.set_output(new typepath(arglist(params)))
|
||||
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* # To Type Component
|
||||
*
|
||||
* Converts a string into a typepath. Useful for adding components.
|
||||
*/
|
||||
/obj/item/circuit_component/to_type
|
||||
display_name = "String To Type"
|
||||
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
|
||||
var/datum/port/input/input_path
|
||||
|
||||
/// The type output
|
||||
var/datum/port/output/type_output
|
||||
|
||||
/obj/item/circuit_component/to_type/Initialize()
|
||||
. = ..()
|
||||
input_path = add_input_port("Type", PORT_TYPE_STRING)
|
||||
type_output = add_output_port("Typepath", PORT_TYPE_ANY)
|
||||
|
||||
/obj/item/circuit_component/to_type/input_received(datum/port/input/port)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
|
||||
type_output.set_output(text2path(input_path.value))
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
* # Direction Component
|
||||
*
|
||||
* Return the direction of a mob relative to the component
|
||||
*/
|
||||
/obj/item/circuit_component/direction
|
||||
display_name = "Get Direction"
|
||||
desc = "A component that returns the direction of itself and an entity."
|
||||
|
||||
/// The input port
|
||||
var/datum/port/input/input_port
|
||||
|
||||
/// The result from the output
|
||||
var/datum/port/output/output
|
||||
|
||||
// Directions outputs
|
||||
var/datum/port/output/north
|
||||
var/datum/port/output/south
|
||||
var/datum/port/output/east
|
||||
var/datum/port/output/west
|
||||
|
||||
circuit_flags = CIRCUIT_FLAG_INPUT_SIGNAL|CIRCUIT_FLAG_OUTPUT_SIGNAL
|
||||
|
||||
/// Maximum range for a valid direction to be returned
|
||||
var/max_range = 7
|
||||
|
||||
/obj/item/circuit_component/direction/get_ui_notices()
|
||||
. = ..()
|
||||
. += create_ui_notice("Maximum Range: [max_range] tiles", "orange", "info")
|
||||
|
||||
/obj/item/circuit_component/direction/Initialize()
|
||||
. = ..()
|
||||
input_port = add_input_port("Organism", PORT_TYPE_ATOM)
|
||||
|
||||
output = add_output_port("Direction", PORT_TYPE_STRING)
|
||||
|
||||
north = add_output_port("North", PORT_TYPE_SIGNAL)
|
||||
east = add_output_port("East", PORT_TYPE_SIGNAL)
|
||||
south = add_output_port("South", PORT_TYPE_SIGNAL)
|
||||
west = add_output_port("West", PORT_TYPE_SIGNAL)
|
||||
|
||||
/obj/item/circuit_component/direction/input_received(datum/port/input/port)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
|
||||
var/atom/object = input_port.value
|
||||
if(!object)
|
||||
return
|
||||
var/turf/location = get_turf(src)
|
||||
|
||||
if(object.z != location.z || get_dist(location, object) > max_range)
|
||||
output.set_output(null)
|
||||
return
|
||||
|
||||
var/direction = get_dir(location, get_turf(object))
|
||||
output.set_output(dir2text(direction))
|
||||
|
||||
if(direction & NORTH)
|
||||
north.set_output(COMPONENT_SIGNAL)
|
||||
if(direction & SOUTH)
|
||||
south.set_output(COMPONENT_SIGNAL)
|
||||
if(direction & EAST)
|
||||
east.set_output(COMPONENT_SIGNAL)
|
||||
if(direction & WEST)
|
||||
west.set_output(COMPONENT_SIGNAL)
|
||||
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* # GPS Component
|
||||
*
|
||||
* Return the location of this
|
||||
*/
|
||||
/obj/item/circuit_component/gps
|
||||
display_name = "Internal GPS"
|
||||
desc = "A component that returns the xyz co-ordinates of itself."
|
||||
|
||||
/// The result from the output
|
||||
var/datum/port/output/x_pos
|
||||
var/datum/port/output/y_pos
|
||||
var/datum/port/output/z_pos
|
||||
|
||||
circuit_flags = CIRCUIT_FLAG_INPUT_SIGNAL|CIRCUIT_FLAG_OUTPUT_SIGNAL
|
||||
|
||||
/obj/item/circuit_component/gps/Initialize()
|
||||
. = ..()
|
||||
|
||||
x_pos = add_output_port("X", PORT_TYPE_NUMBER)
|
||||
y_pos = add_output_port("Y", PORT_TYPE_NUMBER)
|
||||
z_pos = add_output_port("Z", PORT_TYPE_NUMBER)
|
||||
|
||||
/obj/item/circuit_component/gps/input_received(datum/port/input/port)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
|
||||
var/turf/location = get_turf(src)
|
||||
|
||||
x_pos.set_output(location?.x)
|
||||
y_pos.set_output(location?.y)
|
||||
z_pos.set_output(location?.z)
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* # Get Health Component
|
||||
*
|
||||
* Return the health of a mob
|
||||
*/
|
||||
/obj/item/circuit_component/health
|
||||
display_name = "Get Health"
|
||||
desc = "A component that returns the health of an organism."
|
||||
|
||||
/// The input port
|
||||
var/datum/port/input/input_port
|
||||
|
||||
/// Brute damage
|
||||
var/datum/port/output/brute
|
||||
/// Burn damage
|
||||
var/datum/port/output/burn
|
||||
/// Toxin damage
|
||||
var/datum/port/output/toxin
|
||||
/// Oxyloss damage
|
||||
var/datum/port/output/oxy
|
||||
/// Health
|
||||
var/datum/port/output/health
|
||||
|
||||
circuit_flags = CIRCUIT_FLAG_INPUT_SIGNAL|CIRCUIT_FLAG_OUTPUT_SIGNAL
|
||||
|
||||
var/max_range = 5
|
||||
|
||||
/obj/item/circuit_component/health/get_ui_notices()
|
||||
. = ..()
|
||||
. += create_ui_notice("Maximum Range: [max_range] tiles", "orange", "info")
|
||||
|
||||
/obj/item/circuit_component/health/Initialize()
|
||||
. = ..()
|
||||
input_port = add_input_port("Organism", PORT_TYPE_ATOM)
|
||||
|
||||
brute = add_output_port("Brute Damage", PORT_TYPE_NUMBER)
|
||||
burn = add_output_port("Burn Damage", PORT_TYPE_NUMBER)
|
||||
toxin = add_output_port("Toxin Damage", PORT_TYPE_NUMBER)
|
||||
oxy = add_output_port("Suffocation Damage", PORT_TYPE_NUMBER)
|
||||
health = add_output_port("Health", PORT_TYPE_NUMBER)
|
||||
|
||||
/obj/item/circuit_component/health/input_received(datum/port/input/port)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
|
||||
var/mob/living/organism = input_port.value
|
||||
var/turf/current_turf = get_turf(src)
|
||||
if(!istype(organism) || get_dist(current_turf, organism) > max_range || current_turf.z != organism.z)
|
||||
brute.set_output(null)
|
||||
burn.set_output(null)
|
||||
toxin.set_output(null)
|
||||
oxy.set_output(null)
|
||||
health.set_output(null)
|
||||
return
|
||||
|
||||
brute.set_output(organism.getBruteLoss())
|
||||
burn.set_output(organism.getFireLoss())
|
||||
toxin.set_output(organism.getToxLoss())
|
||||
oxy.set_output(organism.getOxyLoss())
|
||||
health.set_output(organism.health)
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* # Hear Component
|
||||
*
|
||||
* Listens for messages. Requires a shell.
|
||||
*/
|
||||
/obj/item/circuit_component/hear
|
||||
display_name = "Voice Activator"
|
||||
desc = "A component that listens for messages. Requires a shell."
|
||||
|
||||
/// The message heard
|
||||
var/datum/port/output/message_port
|
||||
/// The language heard
|
||||
var/datum/port/output/language_port
|
||||
/// The speaker
|
||||
var/datum/port/output/speaker_port
|
||||
/// The trigger sent when this event occurs
|
||||
var/datum/port/output/trigger_port
|
||||
|
||||
/obj/item/circuit_component/hear/Initialize()
|
||||
. = ..()
|
||||
message_port = add_output_port("Message", PORT_TYPE_STRING)
|
||||
language_port = add_output_port("Language", PORT_TYPE_STRING)
|
||||
speaker_port = add_output_port("Speaker", PORT_TYPE_ATOM)
|
||||
trigger_port = add_output_port("Triggered", PORT_TYPE_SIGNAL)
|
||||
become_hearing_sensitive(ROUNDSTART_TRAIT)
|
||||
|
||||
/obj/item/circuit_component/hear/Hear(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, list/message_mods)
|
||||
if(speaker == parent?.shell)
|
||||
return
|
||||
|
||||
message_port.set_output(raw_message)
|
||||
if(message_language)
|
||||
language_port.set_output(initial(message_language.name))
|
||||
speaker_port.set_output(speaker)
|
||||
trigger_port.set_output(COMPONENT_SIGNAL)
|
||||
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* # Self Component
|
||||
*
|
||||
* Return the current shell.
|
||||
*/
|
||||
/obj/item/circuit_component/self
|
||||
display_name = "Self"
|
||||
desc = "A component that returns the current shell."
|
||||
|
||||
/// The shell this component is attached to.
|
||||
var/datum/port/output/output
|
||||
|
||||
/obj/item/circuit_component/self/Initialize()
|
||||
. = ..()
|
||||
output = add_output_port("Self", PORT_TYPE_ATOM)
|
||||
|
||||
/obj/item/circuit_component/self/register_shell(atom/movable/shell)
|
||||
output.set_output(shell)
|
||||
|
||||
/obj/item/circuit_component/self/unregister_shell(atom/movable/shell)
|
||||
output.set_output(null)
|
||||
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* # Get Species Component
|
||||
*
|
||||
* Return the species of a mob
|
||||
*/
|
||||
/obj/item/circuit_component/species
|
||||
display_name = "Get Species"
|
||||
desc = "A component that returns the species of its input."
|
||||
|
||||
/// The input port
|
||||
var/datum/port/input/input_port
|
||||
|
||||
/// The result from the output
|
||||
var/datum/port/output/output
|
||||
|
||||
circuit_flags = CIRCUIT_FLAG_INPUT_SIGNAL|CIRCUIT_FLAG_OUTPUT_SIGNAL
|
||||
|
||||
/obj/item/circuit_component/species/Initialize()
|
||||
. = ..()
|
||||
input_port = add_input_port("Organism", PORT_TYPE_ATOM)
|
||||
|
||||
output = add_output_port("Species", PORT_TYPE_STRING)
|
||||
|
||||
/obj/item/circuit_component/species/input_received(datum/port/input/port)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
|
||||
var/mob/living/carbon/human/human = input_port.value
|
||||
if(!istype(human) || !human.has_dna())
|
||||
output.set_output(null)
|
||||
return
|
||||
|
||||
output.set_output(human.dna.species.name)
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
#define COMP_BAR_OVERLAY_VERTICAL "Vertical"
|
||||
#define COMP_BAR_OVERLAY_HORIZONTAL "Horizontal"
|
||||
|
||||
/**
|
||||
* # Bar Overlay Component
|
||||
*
|
||||
* Basically an advanced verion of object overlay component that shows a horizontal/vertical bar.
|
||||
* Requires a BCI shell.
|
||||
*/
|
||||
|
||||
/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(
|
||||
COMP_BAR_OVERLAY_VERTICAL = "barvert",
|
||||
COMP_BAR_OVERLAY_HORIZONTAL = "barhoriz"
|
||||
)
|
||||
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) >= overlay_limit)
|
||||
return
|
||||
|
||||
var/current_option = bar_overlay_options.value
|
||||
|
||||
if(active_overlays[target_atom])
|
||||
QDEL_NULL(active_overlays[target_atom])
|
||||
|
||||
var/number_clear = clamp(bar_number.value, 0, 100)
|
||||
if(current_option == COMP_BAR_OVERLAY_HORIZONTAL)
|
||||
number_clear = round(number_clear / 6.25) * 6.25
|
||||
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)
|
||||
|
||||
if(image_pixel_x.value)
|
||||
cool_overlay.pixel_x = image_pixel_x.value
|
||||
|
||||
if(image_pixel_y.value)
|
||||
cool_overlay.pixel_y = image_pixel_y.value
|
||||
|
||||
active_overlays[target_atom] = WEAKREF(target_atom.add_alt_appearance(
|
||||
/datum/atom_hud/alternate_appearance/basic/one_person,
|
||||
"bar_overlay_[REF(src)]",
|
||||
cool_overlay,
|
||||
owner,
|
||||
))
|
||||
|
||||
#undef COMP_BAR_OVERLAY_VERTICAL
|
||||
#undef COMP_BAR_OVERLAY_HORIZONTAL
|
||||
@@ -0,0 +1,103 @@
|
||||
/**
|
||||
* # Counter Overlay Component
|
||||
*
|
||||
* Shows an counter overlay.
|
||||
* Requires a BCI shell.
|
||||
*/
|
||||
|
||||
/obj/item/circuit_component/counter_overlay
|
||||
display_name = "Counter Overlay"
|
||||
desc = "A component that shows an three digit counter. Requires a BCI shell."
|
||||
|
||||
required_shells = list(/obj/item/organ/cyberimp/bci)
|
||||
|
||||
var/datum/port/input/counter_number
|
||||
|
||||
var/datum/port/input/image_pixel_x
|
||||
var/datum/port/input/image_pixel_y
|
||||
|
||||
var/datum/port/input/signal_update
|
||||
|
||||
var/obj/item/organ/cyberimp/bci/bci
|
||||
var/list/numbers = list()
|
||||
var/counter_appearance
|
||||
|
||||
/obj/item/circuit_component/counter_overlay/Initialize()
|
||||
. = ..()
|
||||
counter_number = add_input_port("Displayed Number", PORT_TYPE_NUMBER)
|
||||
|
||||
signal_update = add_input_port("Update Overlay", PORT_TYPE_SIGNAL)
|
||||
|
||||
image_pixel_x = add_input_port("X-Axis Shift", PORT_TYPE_NUMBER)
|
||||
image_pixel_y = add_input_port("Y-Axis Shift", PORT_TYPE_NUMBER)
|
||||
|
||||
/obj/item/circuit_component/counter_overlay/register_shell(atom/movable/shell)
|
||||
if(istype(shell, /obj/item/organ/cyberimp/bci))
|
||||
bci = shell
|
||||
RegisterSignal(shell, COMSIG_ORGAN_REMOVED, .proc/on_organ_removed)
|
||||
|
||||
/obj/item/circuit_component/counter_overlay/unregister_shell(atom/movable/shell)
|
||||
bci = null
|
||||
QDEL_NULL(counter_appearance)
|
||||
for(var/number in numbers)
|
||||
QDEL_NULL(number)
|
||||
UnregisterSignal(shell, COMSIG_ORGAN_REMOVED)
|
||||
|
||||
/obj/item/circuit_component/counter_overlay/input_received(datum/port/input/port)
|
||||
. = ..()
|
||||
|
||||
if(. || !bci)
|
||||
return
|
||||
|
||||
var/mob/living/owner = bci.owner
|
||||
|
||||
if(!owner || !istype(owner) || !owner.client)
|
||||
return
|
||||
|
||||
for(var/number in numbers)
|
||||
QDEL_NULL(number)
|
||||
numbers = list()
|
||||
|
||||
QDEL_NULL(counter_appearance)
|
||||
var/image/counter = image(icon = 'icons/hud/screen_bci.dmi', icon_state = "hud_numbers", loc = owner)
|
||||
if(image_pixel_x.value)
|
||||
counter.pixel_x = image_pixel_x.value
|
||||
if(image_pixel_y.value)
|
||||
counter.pixel_y = image_pixel_y.value
|
||||
|
||||
counter_appearance = WEAKREF(owner.add_alt_appearance(
|
||||
/datum/atom_hud/alternate_appearance/basic/one_person,
|
||||
"counter_overlay_[REF(src)]",
|
||||
counter,
|
||||
owner,
|
||||
))
|
||||
|
||||
var/cleared_number = clamp(round(counter_number.value), 0, 999)
|
||||
|
||||
for(var/i = 1 to 3)
|
||||
var/cur_num = round(cleared_number / (10 ** (3 - i))) % 10
|
||||
var/image/number = image(icon = 'icons/hud/screen_bci.dmi', icon_state = "hud_number_[cur_num]", loc = owner)
|
||||
|
||||
if(image_pixel_x.value)
|
||||
number.pixel_x = image_pixel_x.value + (i - 1) * 9
|
||||
if(image_pixel_y.value)
|
||||
number.pixel_y = image_pixel_y.value
|
||||
|
||||
numbers.Add(WEAKREF(owner.add_alt_appearance(
|
||||
/datum/atom_hud/alternate_appearance/basic/one_person,
|
||||
"counter_overlay_[REF(src)]_[i]",
|
||||
number,
|
||||
owner,
|
||||
)))
|
||||
|
||||
/obj/item/circuit_component/counter_overlay/proc/on_organ_removed(datum/source, mob/living/carbon/owner)
|
||||
SIGNAL_HANDLER
|
||||
QDEL_NULL(counter_appearance)
|
||||
for(var/number in numbers)
|
||||
QDEL_NULL(number)
|
||||
|
||||
/obj/item/circuit_component/counter_overlay/Destroy()
|
||||
QDEL_NULL(counter_appearance)
|
||||
for(var/number in numbers)
|
||||
QDEL_NULL(number)
|
||||
return ..()
|
||||
@@ -0,0 +1,122 @@
|
||||
/**
|
||||
* # Object Overlay Component
|
||||
*
|
||||
* Shows an overlay ontop of an object. Toggleable.
|
||||
* Requires a BCI shell.
|
||||
*/
|
||||
|
||||
#define OBJECT_OVERLAY_LIMIT 10
|
||||
|
||||
/obj/item/circuit_component/object_overlay
|
||||
display_name = "Object Overlay"
|
||||
desc = "Requires a BCI shell. A component that shows an overlay on top of an object."
|
||||
|
||||
required_shells = list(/obj/item/organ/cyberimp/bci)
|
||||
|
||||
var/datum/port/input/option/object_overlay_options
|
||||
|
||||
/// Target atom
|
||||
var/datum/port/input/target
|
||||
|
||||
var/datum/port/input/image_pixel_x
|
||||
var/datum/port/input/image_pixel_y
|
||||
|
||||
/// On/Off signals
|
||||
var/datum/port/input/signal_on
|
||||
var/datum/port/input/signal_off
|
||||
|
||||
var/obj/item/organ/cyberimp/bci/bci
|
||||
var/list/active_overlays = list()
|
||||
var/list/options_map
|
||||
|
||||
/obj/item/circuit_component/object_overlay/Initialize()
|
||||
. = ..()
|
||||
target = add_input_port("Target", PORT_TYPE_ATOM)
|
||||
|
||||
signal_on = add_input_port("Create Overlay", PORT_TYPE_SIGNAL)
|
||||
signal_off = add_input_port("Remove Overlay", PORT_TYPE_SIGNAL)
|
||||
|
||||
image_pixel_x = add_input_port("X-Axis Shift", PORT_TYPE_NUMBER)
|
||||
image_pixel_y = add_input_port("Y-Axis Shift", PORT_TYPE_NUMBER)
|
||||
|
||||
/obj/item/circuit_component/object_overlay/Destroy()
|
||||
for(var/active_overlay in active_overlays)
|
||||
QDEL_NULL(active_overlay)
|
||||
return ..()
|
||||
|
||||
/obj/item/circuit_component/object_overlay/populate_options()
|
||||
var/static/component_options = list(
|
||||
"Corners (Blue)" = "hud_corners",
|
||||
"Corners (Red)" = "hud_corners_red",
|
||||
"Circle (Blue)" = "hud_circle",
|
||||
"Circle (Red)" = "hud_circle_red",
|
||||
"Small Corners (Blue)" = "hud_corners_small",
|
||||
"Small Corners (Red)" = "hud_corners_small_red",
|
||||
"Triangle (Blue)" = "hud_triangle",
|
||||
"Triangle (Red)" = "hud_triangle_red",
|
||||
"HUD mark (Blue)" = "hud_mark",
|
||||
"HUD mark (Red)" = "hud_mark_red"
|
||||
)
|
||||
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))
|
||||
bci = shell
|
||||
RegisterSignal(shell, COMSIG_ORGAN_REMOVED, .proc/on_organ_removed)
|
||||
|
||||
/obj/item/circuit_component/object_overlay/unregister_shell(atom/movable/shell)
|
||||
bci = null
|
||||
UnregisterSignal(shell, COMSIG_ORGAN_REMOVED)
|
||||
|
||||
/obj/item/circuit_component/object_overlay/input_received(datum/port/input/port)
|
||||
. = ..()
|
||||
|
||||
if(. || !bci)
|
||||
return
|
||||
|
||||
var/mob/living/owner = bci.owner
|
||||
var/atom/target_atom = target.value
|
||||
|
||||
if(!owner || !istype(owner) || !owner.client || !target_atom)
|
||||
return
|
||||
|
||||
if(COMPONENT_TRIGGERED_BY(signal_on, port))
|
||||
show_to_owner(target_atom, owner)
|
||||
|
||||
if(COMPONENT_TRIGGERED_BY(signal_off, port) && (target_atom in active_overlays))
|
||||
QDEL_NULL(active_overlays[target_atom])
|
||||
active_overlays.Remove(target_atom)
|
||||
|
||||
/obj/item/circuit_component/object_overlay/proc/show_to_owner(atom/target_atom, mob/living/owner)
|
||||
if(LAZYLEN(active_overlays) >= OBJECT_OVERLAY_LIMIT)
|
||||
return
|
||||
|
||||
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[object_overlay_options.value], layer = RIPPLE_LAYER)
|
||||
|
||||
if(image_pixel_x.value)
|
||||
cool_overlay.pixel_x = image_pixel_x.value
|
||||
|
||||
if(image_pixel_y.value)
|
||||
cool_overlay.pixel_y = image_pixel_y.value
|
||||
|
||||
var/alt_appearance = WEAKREF(target_atom.add_alt_appearance(
|
||||
/datum/atom_hud/alternate_appearance/basic/one_person,
|
||||
"object_overlay_[REF(src)]",
|
||||
cool_overlay,
|
||||
owner,
|
||||
))
|
||||
|
||||
active_overlays[target_atom] = alt_appearance
|
||||
|
||||
/obj/item/circuit_component/object_overlay/proc/on_organ_removed(datum/source, mob/living/carbon/owner)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
for(var/atom/target_atom in active_overlays)
|
||||
QDEL_NULL(active_overlays[target_atom])
|
||||
active_overlays.Remove(target_atom)
|
||||
|
||||
#undef OBJECT_OVERLAY_LIMIT
|
||||
@@ -0,0 +1,64 @@
|
||||
/**
|
||||
* # Target Intercept Component
|
||||
*
|
||||
* When activated intercepts next click and outputs clicked atom.
|
||||
* Requires a BCI shell.
|
||||
*/
|
||||
|
||||
/obj/item/circuit_component/target_intercept
|
||||
display_name = "Target Intercept"
|
||||
desc = "Requires a BCI shell. When activated, this component will allow user to target an object using their brain and will output the reference to said object."
|
||||
|
||||
required_shells = list(/obj/item/organ/cyberimp/bci)
|
||||
|
||||
var/datum/port/output/clicked_atom
|
||||
|
||||
var/obj/item/organ/cyberimp/bci/bci
|
||||
var/intercept_cooldown = 1 SECONDS
|
||||
|
||||
/obj/item/circuit_component/target_intercept/Initialize()
|
||||
. = ..()
|
||||
trigger_input = add_input_port("Activate", PORT_TYPE_SIGNAL)
|
||||
trigger_output = add_output_port("Triggered", PORT_TYPE_SIGNAL)
|
||||
clicked_atom = add_output_port("Targeted Object", PORT_TYPE_ATOM)
|
||||
|
||||
/obj/item/circuit_component/target_intercept/register_shell(atom/movable/shell)
|
||||
if(istype(shell, /obj/item/organ/cyberimp/bci))
|
||||
bci = shell
|
||||
RegisterSignal(shell, COMSIG_ORGAN_REMOVED, .proc/on_organ_removed)
|
||||
|
||||
/obj/item/circuit_component/target_intercept/unregister_shell(atom/movable/shell)
|
||||
bci = null
|
||||
UnregisterSignal(shell, COMSIG_ORGAN_REMOVED)
|
||||
|
||||
/obj/item/circuit_component/target_intercept/input_received(datum/port/input/port)
|
||||
. = ..()
|
||||
|
||||
if(. || !bci)
|
||||
return
|
||||
|
||||
var/mob/living/owner = bci.owner
|
||||
if(!owner || !istype(owner) || !owner.client)
|
||||
return
|
||||
|
||||
if(TIMER_COOLDOWN_CHECK(parent, COOLDOWN_CIRCUIT_TARGET_INTERCEPT))
|
||||
return
|
||||
|
||||
to_chat(owner, "<B>Left-click to trigger target interceptor!</B>")
|
||||
owner.client.click_intercept = src
|
||||
|
||||
/obj/item/circuit_component/target_intercept/proc/on_organ_removed(datum/source, mob/living/carbon/owner)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(owner.client && owner.client.click_intercept == src)
|
||||
owner.client.click_intercept = null
|
||||
|
||||
/obj/item/circuit_component/target_intercept/proc/InterceptClickOn(mob/user, params, atom/object)
|
||||
user.client.click_intercept = null
|
||||
clicked_atom.set_output(object)
|
||||
trigger_output.set_output(COMPONENT_SIGNAL)
|
||||
TIMER_COOLDOWN_START(parent, COOLDOWN_CIRCUIT_TARGET_INTERCEPT, intercept_cooldown)
|
||||
|
||||
/obj/item/circuit_component/target_intercept/get_ui_notices()
|
||||
. = ..()
|
||||
. += create_ui_notice("Target Interception Cooldown: [DisplayTimeText(intercept_cooldown)]", "orange", "stopwatch")
|
||||
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* # Concat List Component
|
||||
*
|
||||
* Concatenates a list with a separator
|
||||
*/
|
||||
/obj/item/circuit_component/concat_list
|
||||
display_name = "Concatenate List"
|
||||
desc = "A component that joins up a list with a separator into a single string."
|
||||
|
||||
/// The input port
|
||||
var/datum/port/input/list_port
|
||||
|
||||
/// The seperator
|
||||
var/datum/port/input/separator
|
||||
|
||||
/// The result from the output
|
||||
var/datum/port/output/output
|
||||
circuit_flags = CIRCUIT_FLAG_INPUT_SIGNAL|CIRCUIT_FLAG_OUTPUT_SIGNAL
|
||||
|
||||
/obj/item/circuit_component/concat_list/Initialize()
|
||||
. = ..()
|
||||
list_port = add_input_port("List", PORT_TYPE_LIST)
|
||||
separator = add_input_port("Seperator", PORT_TYPE_STRING)
|
||||
|
||||
output = add_output_port("Output", PORT_TYPE_STRING)
|
||||
|
||||
/obj/item/circuit_component/concat_list/input_received(datum/port/input/port)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
|
||||
var/seperator = separator.value
|
||||
if(!seperator)
|
||||
return
|
||||
|
||||
var/list/list_input = list_port.value
|
||||
if(!list_input)
|
||||
return
|
||||
|
||||
var/list/text_list = list()
|
||||
for(var/entry in list_input)
|
||||
if(isatom(entry))
|
||||
text_list += PORT_TYPE_ATOM
|
||||
else
|
||||
text_list += "[entry]"
|
||||
|
||||
output.set_output(text_list.Join(seperator))
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* # Get Column Component
|
||||
*
|
||||
* Gets the column of a table and returns it as a regular list.
|
||||
*/
|
||||
/obj/item/circuit_component/get_column
|
||||
display_name = "Get Column"
|
||||
desc = "Gets the column of a table and returns it as a regular list."
|
||||
circuit_flags = CIRCUIT_FLAG_INPUT_SIGNAL|CIRCUIT_FLAG_OUTPUT_SIGNAL
|
||||
|
||||
/// The list to perform the filter on
|
||||
var/datum/port/input/received_table
|
||||
|
||||
/// The name of the column to check
|
||||
var/datum/port/input/column_name
|
||||
|
||||
/// The filtered list
|
||||
var/datum/port/output/output_list
|
||||
|
||||
/obj/item/circuit_component/get_column/Initialize()
|
||||
. = ..()
|
||||
received_table = add_input_port("Input", PORT_TYPE_TABLE)
|
||||
column_name = add_input_port("Column Name", PORT_TYPE_STRING)
|
||||
output_list = add_output_port("Output", PORT_TYPE_LIST)
|
||||
|
||||
/obj/item/circuit_component/get_column/input_received(datum/port/input/port)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
|
||||
var/list/input_list = received_table.value
|
||||
if(!islist(input_list) || isnum(column_name.value))
|
||||
return
|
||||
|
||||
var/list/new_list = list()
|
||||
for(var/list/entry in input_list)
|
||||
var/anything = entry[column_name.value]
|
||||
if(islist(anything))
|
||||
continue
|
||||
new_list += anything
|
||||
|
||||
output_list.set_output(new_list)
|
||||
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* # Index Component
|
||||
*
|
||||
* Return the index of a list
|
||||
*/
|
||||
/obj/item/circuit_component/index
|
||||
display_name = "Index List"
|
||||
desc = "A component that returns the value of a list at a given index."
|
||||
|
||||
/// The input port
|
||||
var/datum/port/input/list_port
|
||||
var/datum/port/input/index_port
|
||||
|
||||
/// The result from the output
|
||||
var/datum/port/output/output
|
||||
circuit_flags = CIRCUIT_FLAG_INPUT_SIGNAL|CIRCUIT_FLAG_OUTPUT_SIGNAL
|
||||
|
||||
/obj/item/circuit_component/index/Initialize()
|
||||
. = ..()
|
||||
index_port = add_input_port("Index", PORT_TYPE_ANY)
|
||||
list_port = add_input_port("List", PORT_TYPE_LIST)
|
||||
|
||||
output = add_output_port("Value", PORT_TYPE_ANY)
|
||||
|
||||
/obj/item/circuit_component/index/input_received(datum/port/input/port)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
|
||||
var/index = index_port.value
|
||||
var/list/list_input = list_port.value
|
||||
|
||||
if(!islist(list_input) || !index)
|
||||
output.set_output(null)
|
||||
return
|
||||
|
||||
if(isnum(index) && (index < 1 || index > length(list_input)))
|
||||
output.set_output(null)
|
||||
return
|
||||
|
||||
output.set_output(list_input[index])
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* # Index Table Component
|
||||
*
|
||||
* Gets the row of a table using the index inputted. Will return no value if the index is invalid or a proper table is not returned.
|
||||
*/
|
||||
/obj/item/circuit_component/index_table
|
||||
display_name = "Index Table"
|
||||
desc = "Gets the row of a table using the index inputted. Will return no value if the index is invalid or a proper table is not returned."
|
||||
circuit_flags = CIRCUIT_FLAG_INPUT_SIGNAL|CIRCUIT_FLAG_OUTPUT_SIGNAL
|
||||
|
||||
/// The list to perform the filter on
|
||||
var/datum/port/input/received_table
|
||||
|
||||
/// The target index
|
||||
var/datum/port/input/target_index
|
||||
|
||||
/// The filtered list
|
||||
var/datum/port/output/output_list
|
||||
|
||||
/obj/item/circuit_component/index_table/Initialize()
|
||||
. = ..()
|
||||
received_table = add_input_port("Input", PORT_TYPE_TABLE)
|
||||
target_index = add_input_port("Index", PORT_TYPE_NUMBER)
|
||||
|
||||
output_list = add_output_port("Output", PORT_TYPE_LIST)
|
||||
|
||||
/obj/item/circuit_component/index_table/input_received(datum/port/input/port)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
|
||||
var/list/target_list = received_table.value
|
||||
if(!islist(target_list) || !length(target_list))
|
||||
output_list.set_output(null)
|
||||
return
|
||||
|
||||
var/index = target_index.value
|
||||
if(index < 1 || index > length(target_list))
|
||||
output_list.set_output(null)
|
||||
return
|
||||
|
||||
output_list.set_output(target_list[index])
|
||||
@@ -0,0 +1,86 @@
|
||||
/**
|
||||
* # List Literal Component
|
||||
*
|
||||
* Return a list literal.
|
||||
*/
|
||||
/obj/item/circuit_component/list_literal
|
||||
display_name = "List Literal"
|
||||
desc = "A component that returns the value of a list at a given index. Attack in hand to increase list size, right click to decrease list size."
|
||||
circuit_flags = CIRCUIT_FLAG_INPUT_SIGNAL|CIRCUIT_FLAG_OUTPUT_SIGNAL
|
||||
|
||||
/// The inputs used to create the list
|
||||
var/list/datum/port/input/entry_ports = list()
|
||||
/// The result from the output
|
||||
var/datum/port/output/list_output
|
||||
|
||||
var/length = 0
|
||||
|
||||
var/default_list_size = 2
|
||||
|
||||
var/min_size = 1
|
||||
var/max_size = 20
|
||||
|
||||
/obj/item/circuit_component/list_literal/save_data_to_list(list/component_data)
|
||||
. = ..()
|
||||
component_data["length"] = length
|
||||
|
||||
/obj/item/circuit_component/list_literal/load_data_from_list(list/component_data)
|
||||
set_list_size(component_data["length"])
|
||||
|
||||
return ..()
|
||||
|
||||
/obj/item/circuit_component/list_literal/proc/set_list_size(new_size)
|
||||
if(new_size <= 0)
|
||||
for(var/datum/port/input/port in entry_ports)
|
||||
remove_input_port(port)
|
||||
entry_ports = list()
|
||||
length = 0
|
||||
return
|
||||
|
||||
while(length > new_size)
|
||||
var/index = length(entry_ports)
|
||||
var/entry_port = entry_ports[index]
|
||||
entry_ports -= entry_port
|
||||
remove_input_port(entry_port)
|
||||
length--
|
||||
|
||||
while(length < new_size)
|
||||
length++
|
||||
var/index = length(input_ports)
|
||||
if(trigger_input)
|
||||
index -= 1
|
||||
entry_ports += add_input_port("Index [index+1]", PORT_TYPE_ANY, index = index+1)
|
||||
|
||||
/obj/item/circuit_component/list_literal/Initialize()
|
||||
. = ..()
|
||||
set_list_size(default_list_size)
|
||||
list_output = add_output_port("Value", PORT_TYPE_LIST)
|
||||
|
||||
/obj/item/circuit_component/list_literal/Destroy()
|
||||
list_output = null
|
||||
return ..()
|
||||
|
||||
// Increases list length
|
||||
/obj/item/circuit_component/list_literal/attack_self(mob/user, list/modifiers)
|
||||
. = ..()
|
||||
set_list_size(min(length + 1, max_size))
|
||||
balloon_alert(user, "new size is now [length]")
|
||||
|
||||
// Decreases list length
|
||||
/obj/item/circuit_component/list_literal/attack_self_secondary(mob/user, list/modifiers)
|
||||
. = ..()
|
||||
set_list_size(max(length - 1, min_size))
|
||||
balloon_alert(user, "new size is now [length]")
|
||||
|
||||
/obj/item/circuit_component/list_literal/input_received(datum/port/input/port)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
|
||||
var/list/new_literal = list()
|
||||
for(var/datum/port/input/entry_port as anything in entry_ports)
|
||||
// Prevents lists from merging together
|
||||
new_literal += list(entry_port.value)
|
||||
|
||||
list_output.set_output(new_literal)
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
/**
|
||||
* # Select Component
|
||||
*
|
||||
* Selects a list from a list of lists by a specific column. Used only by USBs for communications to and from computers with lists of varying sizes.
|
||||
*/
|
||||
/obj/item/circuit_component/select
|
||||
display_name = "Select Query"
|
||||
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
|
||||
|
||||
/// The name of the column to check
|
||||
var/datum/port/input/column_name
|
||||
|
||||
/// The input to compare with
|
||||
var/datum/port/input/comparison_input
|
||||
|
||||
/// The filtered list
|
||||
var/datum/port/output/filtered_table
|
||||
|
||||
var/current_type = PORT_TYPE_ANY
|
||||
|
||||
/obj/item/circuit_component/select/populate_options()
|
||||
var/static/component_options = list(
|
||||
COMP_COMPARISON_EQUAL,
|
||||
COMP_COMPARISON_NOT_EQUAL,
|
||||
COMP_COMPARISON_GREATER_THAN,
|
||||
COMP_COMPARISON_LESS_THAN,
|
||||
COMP_COMPARISON_GREATER_THAN_OR_EQUAL,
|
||||
COMP_COMPARISON_LESS_THAN_OR_EQUAL,
|
||||
)
|
||||
comparison_options = add_option_port("Comparison Options", component_options)
|
||||
|
||||
/obj/item/circuit_component/select/Initialize()
|
||||
. = ..()
|
||||
received_table = add_input_port("Input", PORT_TYPE_TABLE)
|
||||
column_name = add_input_port("Column Name", PORT_TYPE_STRING)
|
||||
comparison_input = add_input_port("Comparison Input", PORT_TYPE_ANY)
|
||||
|
||||
filtered_table = add_output_port("Output", PORT_TYPE_TABLE)
|
||||
|
||||
/obj/item/circuit_component/select/input_received(datum/port/input/port)
|
||||
. = ..()
|
||||
var/current_option = comparison_options.value
|
||||
|
||||
switch(current_option)
|
||||
if(COMP_COMPARISON_EQUAL, COMP_COMPARISON_NOT_EQUAL)
|
||||
if(current_type != PORT_TYPE_ANY)
|
||||
current_type = PORT_TYPE_ANY
|
||||
comparison_input.set_datatype(PORT_TYPE_ANY)
|
||||
else
|
||||
if(current_type != PORT_TYPE_NUMBER)
|
||||
current_type = PORT_TYPE_NUMBER
|
||||
comparison_input.set_datatype(PORT_TYPE_NUMBER)
|
||||
|
||||
if(.)
|
||||
return
|
||||
|
||||
var/list/input_list = received_table.value
|
||||
if(!islist(input_list) || isnum(column_name.value))
|
||||
return
|
||||
|
||||
var/comparison_value = comparison_input.value
|
||||
var/list/new_list = list()
|
||||
for(var/list/entry in input_list)
|
||||
var/anything = entry[column_name.value]
|
||||
if(islist(anything))
|
||||
continue
|
||||
if(current_option != COMP_COMPARISON_EQUAL && current_option != COMP_COMPARISON_NOT_EQUAL && !isnum(anything))
|
||||
continue
|
||||
var/add_to_list = FALSE
|
||||
switch(current_option)
|
||||
if(COMP_COMPARISON_EQUAL)
|
||||
add_to_list = anything == comparison_value
|
||||
if(COMP_COMPARISON_NOT_EQUAL)
|
||||
add_to_list = anything != comparison_value
|
||||
if(COMP_COMPARISON_GREATER_THAN)
|
||||
add_to_list = anything > comparison_value
|
||||
if(COMP_COMPARISON_GREATER_THAN_OR_EQUAL)
|
||||
add_to_list = anything >= comparison_value
|
||||
if(COMP_COMPARISON_LESS_THAN)
|
||||
add_to_list = anything < comparison_value
|
||||
if(COMP_COMPARISON_LESS_THAN_OR_EQUAL)
|
||||
add_to_list = anything <= comparison_value
|
||||
|
||||
if(add_to_list)
|
||||
new_list += list(entry)
|
||||
|
||||
filtered_table.set_output(new_list)
|
||||
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* # Split component
|
||||
*
|
||||
* Splits a string
|
||||
*/
|
||||
/obj/item/circuit_component/split
|
||||
display_name = "Split"
|
||||
desc = "Splits a string by the separator, turning it into a list"
|
||||
|
||||
/// The input port
|
||||
var/datum/port/input/input_port
|
||||
|
||||
/// The seperator
|
||||
var/datum/port/input/separator
|
||||
|
||||
/// The result from the output
|
||||
var/datum/port/output/output
|
||||
|
||||
circuit_flags = CIRCUIT_FLAG_INPUT_SIGNAL|CIRCUIT_FLAG_OUTPUT_SIGNAL
|
||||
|
||||
/obj/item/circuit_component/split/Initialize()
|
||||
. = ..()
|
||||
input_port = add_input_port("Input", PORT_TYPE_STRING)
|
||||
separator = add_input_port("Seperator", PORT_TYPE_STRING)
|
||||
output = add_output_port("Output", PORT_TYPE_LIST)
|
||||
|
||||
/obj/item/circuit_component/split/input_received(datum/port/input/port)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
|
||||
var/separator_value = separator.value
|
||||
if(isnull(separator_value))
|
||||
return
|
||||
|
||||
var/value = input_port.value
|
||||
if(isnull(value))
|
||||
return
|
||||
|
||||
var/list/result = splittext(value,separator_value)
|
||||
|
||||
output.set_output(result)
|
||||
@@ -0,0 +1,88 @@
|
||||
#define COMP_ARITHMETIC_ADD "Add"
|
||||
#define COMP_ARITHMETIC_SUBTRACT "Subtract"
|
||||
#define COMP_ARITHMETIC_MULTIPLY "Multiply"
|
||||
#define COMP_ARITHMETIC_DIVIDE "Divide"
|
||||
#define COMP_ARITHMETIC_MIN "Minimum"
|
||||
#define COMP_ARITHMETIC_MAX "Maximum"
|
||||
|
||||
/**
|
||||
* # Arithmetic Component
|
||||
*
|
||||
* General arithmetic unit with add/sub/mult/divide capabilities
|
||||
* This one only works with numbers.
|
||||
*/
|
||||
/obj/item/circuit_component/arithmetic
|
||||
display_name = "Arithmetic"
|
||||
desc = "General arithmetic component with arithmetic capabilities."
|
||||
|
||||
/// 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()
|
||||
var/static/component_options = list(
|
||||
COMP_ARITHMETIC_ADD,
|
||||
COMP_ARITHMETIC_SUBTRACT,
|
||||
COMP_ARITHMETIC_MULTIPLY,
|
||||
COMP_ARITHMETIC_DIVIDE,
|
||||
COMP_ARITHMETIC_MIN,
|
||||
COMP_ARITHMETIC_MAX,
|
||||
)
|
||||
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))
|
||||
arithmetic_ports += add_input_port(letter, PORT_TYPE_NUMBER)
|
||||
|
||||
output = add_output_port("Output", PORT_TYPE_NUMBER)
|
||||
|
||||
/obj/item/circuit_component/arithmetic/input_received(datum/port/input/port)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
|
||||
var/list/ports = arithmetic_ports.Copy()
|
||||
var/datum/port/input/first_port = popleft(ports)
|
||||
var/result = first_port.value
|
||||
|
||||
for(var/datum/port/input/input_port as anything in ports)
|
||||
var/value = input_port.value
|
||||
if(isnull(value))
|
||||
continue
|
||||
|
||||
switch(arithmetic_option.value)
|
||||
if(COMP_ARITHMETIC_ADD)
|
||||
result += value
|
||||
if(COMP_ARITHMETIC_SUBTRACT)
|
||||
result -= value
|
||||
if(COMP_ARITHMETIC_MULTIPLY)
|
||||
result *= value
|
||||
if(COMP_ARITHMETIC_DIVIDE)
|
||||
// Protect from div by zero errors.
|
||||
if(value == 0)
|
||||
result = null
|
||||
break
|
||||
result /= value
|
||||
if(COMP_ARITHMETIC_MAX)
|
||||
result = max(result, value)
|
||||
if(COMP_ARITHMETIC_MIN)
|
||||
result = min(result, value)
|
||||
|
||||
output.set_output(result)
|
||||
|
||||
#undef COMP_ARITHMETIC_ADD
|
||||
#undef COMP_ARITHMETIC_SUBTRACT
|
||||
#undef COMP_ARITHMETIC_MULTIPLY
|
||||
#undef COMP_ARITHMETIC_DIVIDE
|
||||
#undef COMP_ARITHMETIC_MIN
|
||||
#undef COMP_ARITHMETIC_MAX
|
||||
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* # Comparison Component
|
||||
*
|
||||
* Compares two objects
|
||||
*/
|
||||
/obj/item/circuit_component/compare/comparison
|
||||
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
|
||||
|
||||
/obj/item/circuit_component/compare/comparison/populate_options()
|
||||
var/static/component_options = list(
|
||||
COMP_COMPARISON_EQUAL,
|
||||
COMP_COMPARISON_NOT_EQUAL,
|
||||
COMP_COMPARISON_GREATER_THAN,
|
||||
COMP_COMPARISON_LESS_THAN,
|
||||
COMP_COMPARISON_GREATER_THAN_OR_EQUAL,
|
||||
COMP_COMPARISON_LESS_THAN_OR_EQUAL,
|
||||
)
|
||||
comparison_option = add_option_port("Comparison Option", component_options)
|
||||
|
||||
/obj/item/circuit_component/compare/comparison/input_received(datum/port/input/port)
|
||||
switch(comparison_option.value)
|
||||
if(COMP_COMPARISON_EQUAL, COMP_COMPARISON_NOT_EQUAL)
|
||||
if(current_type != PORT_TYPE_ANY)
|
||||
current_type = 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
|
||||
compare_ports[1].set_datatype(PORT_TYPE_NUMBER)
|
||||
compare_ports[2].set_datatype(PORT_TYPE_NUMBER)
|
||||
return ..()
|
||||
|
||||
|
||||
/obj/item/circuit_component/compare/comparison/do_comparisons(list/ports)
|
||||
if(length(ports) < input_port_amount)
|
||||
return FALSE
|
||||
|
||||
// Comparison component only compares the first two ports
|
||||
var/input1 = compare_ports[1].value
|
||||
var/input2 = compare_ports[2].value
|
||||
var/current_option = comparison_option.value
|
||||
|
||||
switch(current_option)
|
||||
if(COMP_COMPARISON_EQUAL)
|
||||
return input1 == input2
|
||||
if(COMP_COMPARISON_NOT_EQUAL)
|
||||
return input1 != input2
|
||||
if(COMP_COMPARISON_GREATER_THAN)
|
||||
return input1 > input2
|
||||
if(COMP_COMPARISON_GREATER_THAN_OR_EQUAL)
|
||||
return input1 >= input2
|
||||
if(COMP_COMPARISON_LESS_THAN)
|
||||
return input1 < input2
|
||||
if(COMP_COMPARISON_LESS_THAN_OR_EQUAL)
|
||||
return input1 <= input2
|
||||
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* # Length Component
|
||||
*
|
||||
* Return the length of an input
|
||||
*/
|
||||
/obj/item/circuit_component/length
|
||||
display_name = "Length"
|
||||
desc = "A component that returns the length of its input."
|
||||
|
||||
/// The input port
|
||||
var/datum/port/input/input_port
|
||||
|
||||
/// The result from the output
|
||||
var/datum/port/output/output
|
||||
circuit_flags = CIRCUIT_FLAG_INPUT_SIGNAL|CIRCUIT_FLAG_OUTPUT_SIGNAL
|
||||
|
||||
/obj/item/circuit_component/length/Initialize()
|
||||
. = ..()
|
||||
input_port = add_input_port("Input", PORT_TYPE_ANY)
|
||||
|
||||
output = add_output_port("Length", PORT_TYPE_NUMBER)
|
||||
|
||||
/obj/item/circuit_component/length/input_received(datum/port/input/port)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
|
||||
output.set_output(length(input_port.value))
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
#define COMP_LOGIC_AND "AND"
|
||||
#define COMP_LOGIC_OR "OR"
|
||||
#define COMP_LOGIC_XOR "XOR"
|
||||
|
||||
/**
|
||||
* # Logic Component
|
||||
*
|
||||
* General logic unit with AND OR capabilities
|
||||
*/
|
||||
/obj/item/circuit_component/compare/logic
|
||||
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,
|
||||
)
|
||||
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.value
|
||||
|
||||
// Used by XOR
|
||||
var/total_ports = 0
|
||||
var/total_true_ports = 0
|
||||
for(var/datum/port/input/port as anything in ports)
|
||||
if(isnull(port.value) && length(port.connected_ports) == 0)
|
||||
continue
|
||||
|
||||
total_ports += 1
|
||||
switch(current_option)
|
||||
if(COMP_LOGIC_AND)
|
||||
if(!port.value)
|
||||
return FALSE
|
||||
. = TRUE
|
||||
if(COMP_LOGIC_OR)
|
||||
if(port.value)
|
||||
return TRUE
|
||||
if(COMP_LOGIC_XOR)
|
||||
if(port.value)
|
||||
. = TRUE
|
||||
total_true_ports += 1
|
||||
|
||||
if(current_option == COMP_LOGIC_XOR)
|
||||
if(total_ports == total_true_ports)
|
||||
return FALSE
|
||||
if(.)
|
||||
return TRUE
|
||||
|
||||
#undef COMP_LOGIC_AND
|
||||
#undef COMP_LOGIC_OR
|
||||
#undef COMP_LOGIC_XOR
|
||||
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* # Logic Component
|
||||
*
|
||||
* General logic unit with AND OR capabilities
|
||||
*/
|
||||
/obj/item/circuit_component/not
|
||||
display_name = "Not"
|
||||
desc = "A component that inverts its input."
|
||||
|
||||
/// The input port
|
||||
var/datum/port/input/input_port
|
||||
|
||||
/// The result from the output
|
||||
var/datum/port/output/result
|
||||
circuit_flags = CIRCUIT_FLAG_INPUT_SIGNAL|CIRCUIT_FLAG_OUTPUT_SIGNAL
|
||||
|
||||
/obj/item/circuit_component/not/Initialize()
|
||||
. = ..()
|
||||
input_port = add_input_port("Input", PORT_TYPE_ANY)
|
||||
|
||||
result = add_output_port("Result", PORT_TYPE_NUMBER)
|
||||
|
||||
/obj/item/circuit_component/not/input_received(datum/port/input/port)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
|
||||
result.set_output(!input_port.value)
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* # Random Component
|
||||
*
|
||||
* Generates a random number between specific values
|
||||
*/
|
||||
/obj/item/circuit_component/random
|
||||
display_name = "Random"
|
||||
desc = "A component that returns random values."
|
||||
|
||||
/// The minimum value that the random number can be
|
||||
var/datum/port/input/minimum
|
||||
/// The maximum value that the random number can be
|
||||
var/datum/port/input/maximum
|
||||
|
||||
circuit_flags = CIRCUIT_FLAG_INPUT_SIGNAL|CIRCUIT_FLAG_OUTPUT_SIGNAL
|
||||
|
||||
/// The result from the output
|
||||
var/datum/port/output/output
|
||||
|
||||
/obj/item/circuit_component/random/Initialize()
|
||||
. = ..()
|
||||
minimum = add_input_port("Minimum", PORT_TYPE_NUMBER, FALSE)
|
||||
maximum = add_input_port("Maximum", PORT_TYPE_NUMBER, FALSE)
|
||||
|
||||
output = add_output_port("Output", PORT_TYPE_NUMBER)
|
||||
|
||||
/obj/item/circuit_component/random/input_received(datum/port/input/port)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
|
||||
var/min_val = minimum.value || 0
|
||||
var/max_val = maximum.value || 0
|
||||
|
||||
if(max_val < min_val)
|
||||
output.set_output(0)
|
||||
return
|
||||
|
||||
output.set_output(rand(min_val, max_val))
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* # NTNet Receiver Component
|
||||
*
|
||||
* Receives data through NTNet.
|
||||
*/
|
||||
|
||||
/obj/item/circuit_component/ntnet_receive
|
||||
display_name = "NTNet Receiver"
|
||||
desc = "Receives data packages through NTNet. If Encryption Key is set then only signals with the same Encryption Key will be received."
|
||||
|
||||
circuit_flags = CIRCUIT_FLAG_OUTPUT_SIGNAL //trigger_output
|
||||
|
||||
network_id = __NETWORK_CIRCUITS
|
||||
|
||||
var/datum/port/input/push_hid
|
||||
var/datum/port/output/hid
|
||||
var/datum/port/output/data_package
|
||||
var/datum/port/output/secondary_package
|
||||
var/datum/port/input/enc_key
|
||||
var/datum/port/input/option/data_type_options
|
||||
var/datum/port/input/option/secondary_data_type_options
|
||||
|
||||
/obj/item/circuit_component/ntnet_receive/Initialize()
|
||||
. = ..()
|
||||
data_package = add_output_port("Data Package", PORT_TYPE_ANY)
|
||||
secondary_package = add_output_port("Secondary Package", PORT_TYPE_ANY)
|
||||
enc_key = add_input_port("Encryption Key", PORT_TYPE_STRING)
|
||||
RegisterSignal(src, COMSIG_COMPONENT_NTNET_RECEIVE, .proc/ntnet_receive)
|
||||
|
||||
/obj/item/circuit_component/ntnet_receive/populate_options()
|
||||
var/static/component_options = list(
|
||||
PORT_TYPE_ANY,
|
||||
PORT_TYPE_STRING,
|
||||
PORT_TYPE_NUMBER,
|
||||
PORT_TYPE_LIST,
|
||||
PORT_TYPE_ATOM,
|
||||
)
|
||||
data_type_options = add_option_port("Data Type", component_options)
|
||||
secondary_data_type_options = add_option_port("Secondary Data Type", component_options)
|
||||
|
||||
/obj/item/circuit_component/ntnet_receive/input_received(datum/port/input/port)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
|
||||
if(COMPONENT_TRIGGERED_BY(data_type_options, port))
|
||||
data_package.set_datatype(data_type_options.value)
|
||||
|
||||
if(COMPONENT_TRIGGERED_BY(secondary_data_type_options, port))
|
||||
secondary_package.set_datatype(secondary_data_type_options.value)
|
||||
|
||||
return TRUE
|
||||
|
||||
/obj/item/circuit_component/ntnet_receive/proc/ntnet_receive(datum/source, datum/netdata/data)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(data.data["enc_key"] != enc_key.value)
|
||||
return
|
||||
|
||||
data_package.set_output(data.data["data"])
|
||||
secondary_package.set_output(data.data["data_secondary"])
|
||||
trigger_output.set_output(COMPONENT_SIGNAL)
|
||||
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* # NTNet Transmitter Component
|
||||
*
|
||||
* Sends a data package through NTNet
|
||||
*/
|
||||
|
||||
/obj/item/circuit_component/ntnet_send
|
||||
display_name = "NTNet Transmitter"
|
||||
desc = "Sends a data package through NTNet. If Encryption Key is set then transmitted data will be only picked up by receivers with the same Encryption Key."
|
||||
|
||||
circuit_flags = CIRCUIT_FLAG_INPUT_SIGNAL
|
||||
|
||||
network_id = __NETWORK_CIRCUITS
|
||||
|
||||
var/datum/port/input/data_package
|
||||
var/datum/port/input/secondary_package
|
||||
var/datum/port/input/enc_key
|
||||
|
||||
/obj/item/circuit_component/ntnet_send/Initialize()
|
||||
. = ..()
|
||||
data_package = add_input_port("Data Package", PORT_TYPE_ANY)
|
||||
secondary_package = add_input_port("Secondary Package", PORT_TYPE_ANY)
|
||||
enc_key = add_input_port("Encryption Key", PORT_TYPE_STRING)
|
||||
|
||||
/obj/item/circuit_component/ntnet_send/input_received(datum/port/input/port)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
ntnet_send(list("data" = data_package.value, "data_secondary" = secondary_package.value, "enc_key" = enc_key.value))
|
||||
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* # Pressure Sensor
|
||||
*
|
||||
* Returns the pressure of the tile
|
||||
*/
|
||||
/obj/item/circuit_component/pressuresensor
|
||||
display_name = "Pressure Sensor"
|
||||
desc = "Outputs the current pressure of the tile"
|
||||
|
||||
circuit_flags = CIRCUIT_FLAG_INPUT_SIGNAL|CIRCUIT_FLAG_OUTPUT_SIGNAL
|
||||
|
||||
/// The result from the output
|
||||
var/datum/port/output/result
|
||||
|
||||
/obj/item/circuit_component/pressuresensor/Initialize()
|
||||
. = ..()
|
||||
result = add_output_port("Result", PORT_TYPE_NUMBER)
|
||||
|
||||
/obj/item/circuit_component/pressuresensor/input_received(datum/port/input/port)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
//Get current turf
|
||||
var/turf/location = get_turf(src)
|
||||
if(!location)
|
||||
result.set_output(null)
|
||||
return
|
||||
//Get environment info
|
||||
var/datum/gas_mixture/environment = location.return_air()
|
||||
var/total_moles = environment.total_moles()
|
||||
var/pressure = environment.return_pressure()
|
||||
if(total_moles)
|
||||
//If there's atmos, return pressure
|
||||
result.set_output(round(pressure,1))
|
||||
else
|
||||
result.set_output(0)
|
||||
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* # Temperature Sensor
|
||||
*
|
||||
* Returns the temperature of the tile
|
||||
*/
|
||||
/obj/item/circuit_component/tempsensor
|
||||
display_name = "Temperature Sensor"
|
||||
desc = "Outputs the current temperature of the tile"
|
||||
|
||||
circuit_flags = CIRCUIT_FLAG_INPUT_SIGNAL|CIRCUIT_FLAG_OUTPUT_SIGNAL
|
||||
|
||||
/// The result from the output
|
||||
var/datum/port/output/result
|
||||
|
||||
/obj/item/circuit_component/tempsensor/Initialize()
|
||||
. = ..()
|
||||
result = add_output_port("Result", PORT_TYPE_NUMBER)
|
||||
|
||||
/obj/item/circuit_component/tempsensor/input_received(datum/port/input/port)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
//Get current turf
|
||||
var/turf/location = get_turf(src)
|
||||
if(!location)
|
||||
result.set_output(null)
|
||||
return
|
||||
//Get environment info
|
||||
var/datum/gas_mixture/environment = location.return_air()
|
||||
var/total_moles = environment.total_moles()
|
||||
if(total_moles)
|
||||
//If there's atmos, return temperature
|
||||
result.set_output(round(environment.temperature,1))
|
||||
else
|
||||
result.set_output(0)
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* # Concatenate Component
|
||||
*
|
||||
* General string concatenation component. Puts strings together.
|
||||
*/
|
||||
/obj/item/circuit_component/concat
|
||||
display_name = "Concatenate"
|
||||
desc = "A component that combines strings."
|
||||
|
||||
/// The amount of input ports to have
|
||||
var/input_port_amount = 4
|
||||
|
||||
/// The result from the output
|
||||
var/datum/port/output/output
|
||||
circuit_flags = CIRCUIT_FLAG_INPUT_SIGNAL|CIRCUIT_FLAG_OUTPUT_SIGNAL
|
||||
|
||||
/obj/item/circuit_component/concat/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_STRING)
|
||||
|
||||
output = add_output_port("Output", PORT_TYPE_STRING)
|
||||
|
||||
/obj/item/circuit_component/concat/input_received(datum/port/input/port)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
|
||||
var/result = ""
|
||||
var/list/ports = input_ports.Copy()
|
||||
ports -= trigger_input
|
||||
|
||||
for(var/datum/port/input/input_port as anything in ports)
|
||||
var/value = input_port.value
|
||||
if(isnull(value))
|
||||
continue
|
||||
|
||||
result += "[value]"
|
||||
|
||||
output.set_output(result)
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* # String Contains Component
|
||||
*
|
||||
* Checks if a string contains a word/letter
|
||||
*/
|
||||
/obj/item/circuit_component/compare/contains
|
||||
display_name = "String Contains"
|
||||
desc = "Checks if a string contains a word/letter"
|
||||
|
||||
input_port_amount = 0
|
||||
|
||||
var/datum/port/input/needle
|
||||
var/datum/port/input/haystack
|
||||
|
||||
/obj/item/circuit_component/compare/contains/load_custom_ports()
|
||||
needle = add_input_port("Needle", PORT_TYPE_STRING)
|
||||
haystack = add_input_port("Haystack", PORT_TYPE_STRING)
|
||||
|
||||
/obj/item/circuit_component/compare/contains/Destroy()
|
||||
needle = null
|
||||
haystack = null
|
||||
return ..()
|
||||
|
||||
|
||||
/obj/item/circuit_component/compare/contains/do_comparisons(list/ports)
|
||||
if(length(ports) < input_port_amount)
|
||||
return
|
||||
|
||||
var/to_find = needle.value
|
||||
var/to_search = haystack.value
|
||||
|
||||
if(!to_find || !to_search)
|
||||
return
|
||||
|
||||
return findtext(to_search, to_find)
|
||||
@@ -0,0 +1,54 @@
|
||||
#define COMP_TEXT_LOWER "To Lower"
|
||||
#define COMP_TEXT_UPPER "To Upper"
|
||||
|
||||
/**
|
||||
* # Text Component
|
||||
*
|
||||
* Either makes the text upper case or lower case.
|
||||
*/
|
||||
/obj/item/circuit_component/textcase
|
||||
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
|
||||
|
||||
/// The result of the text operation
|
||||
var/datum/port/output/output
|
||||
|
||||
circuit_flags = CIRCUIT_FLAG_INPUT_SIGNAL|CIRCUIT_FLAG_OUTPUT_SIGNAL
|
||||
|
||||
/obj/item/circuit_component/textcase/populate_options()
|
||||
var/static/component_options = list(
|
||||
COMP_TEXT_LOWER,
|
||||
COMP_TEXT_UPPER,
|
||||
)
|
||||
textcase_options = add_option_port("Textcase Options", component_options)
|
||||
|
||||
/obj/item/circuit_component/textcase/Initialize()
|
||||
. = ..()
|
||||
input_port = add_input_port("Input", PORT_TYPE_STRING)
|
||||
output = add_output_port("Output", PORT_TYPE_STRING)
|
||||
|
||||
/obj/item/circuit_component/textcase/input_received(datum/port/input/port)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
|
||||
var/value = input_port.value
|
||||
if(isnull(value))
|
||||
return
|
||||
|
||||
var/result
|
||||
switch(textcase_options.value)
|
||||
if(COMP_TEXT_LOWER)
|
||||
result = lowertext(value)
|
||||
if(COMP_TEXT_UPPER)
|
||||
result = uppertext(value)
|
||||
|
||||
output.set_output(result)
|
||||
|
||||
#undef COMP_TEXT_LOWER
|
||||
#undef COMP_TEXT_UPPER
|
||||
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* #To Number Component
|
||||
*
|
||||
* Converts a string into a Number
|
||||
*/
|
||||
/obj/item/circuit_component/tonumber
|
||||
display_name = "To Number"
|
||||
desc = "A component that converts its input (a string) to a number. If there's text in the input, it'll only consider it if it starts with a number. It will take that number and ignore the rest."
|
||||
|
||||
/// The input port
|
||||
var/datum/port/input/input_port
|
||||
|
||||
/// The result from the output
|
||||
var/datum/port/output/output
|
||||
|
||||
circuit_flags = CIRCUIT_FLAG_INPUT_SIGNAL|CIRCUIT_FLAG_OUTPUT_SIGNAL
|
||||
|
||||
/obj/item/circuit_component/tonumber/Initialize()
|
||||
. = ..()
|
||||
input_port = add_input_port("Input", PORT_TYPE_STRING)
|
||||
|
||||
output = add_output_port("Output", PORT_TYPE_NUMBER)
|
||||
|
||||
/obj/item/circuit_component/tonumber/input_received(datum/port/input/port)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
|
||||
output.set_output(text2num(input_port.value))
|
||||
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* # To String Component
|
||||
*
|
||||
* Converts any value into a string
|
||||
*/
|
||||
/obj/item/circuit_component/tostring
|
||||
display_name = "To String"
|
||||
desc = "A component that converts its input to text."
|
||||
|
||||
/// The input port
|
||||
var/datum/port/input/input_port
|
||||
|
||||
/// The result from the output
|
||||
var/datum/port/output/output
|
||||
|
||||
circuit_flags = CIRCUIT_FLAG_INPUT_SIGNAL|CIRCUIT_FLAG_OUTPUT_SIGNAL
|
||||
|
||||
var/max_range = 5
|
||||
|
||||
/obj/item/circuit_component/tostring/Initialize()
|
||||
. = ..()
|
||||
input_port = add_input_port("Input", PORT_TYPE_ANY)
|
||||
|
||||
output = add_output_port("Output", PORT_TYPE_STRING)
|
||||
|
||||
/obj/item/circuit_component/tostring/input_received(datum/port/input/port)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
|
||||
var/value = input_port.value
|
||||
if(isatom(value))
|
||||
var/turf/location = get_turf(src)
|
||||
var/atom/object = value
|
||||
if(object.z != location.z || get_dist(location, object) > max_range)
|
||||
output.set_output(PORT_TYPE_ATOM)
|
||||
return
|
||||
|
||||
output.set_output("[value]")
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* # Clock Component
|
||||
*
|
||||
* Fires every tick of the circuit timer SS
|
||||
*/
|
||||
/obj/item/circuit_component/clock
|
||||
display_name = "Clock"
|
||||
desc = "A component that repeatedly fires."
|
||||
|
||||
/// Whether the clock is on or not
|
||||
var/datum/port/input/on
|
||||
|
||||
/// The signal from this clock component
|
||||
var/datum/port/output/signal
|
||||
|
||||
/obj/item/circuit_component/clock/get_ui_notices()
|
||||
. = ..()
|
||||
. += create_ui_notice("Clock Interval: [DisplayTimeText(COMP_CLOCK_DELAY)]", "orange", "clock")
|
||||
|
||||
/obj/item/circuit_component/clock/Initialize()
|
||||
. = ..()
|
||||
on = add_input_port("On", PORT_TYPE_NUMBER)
|
||||
|
||||
signal = add_output_port("Signal", PORT_TYPE_SIGNAL)
|
||||
|
||||
/obj/item/circuit_component/clock/input_received(datum/port/input/port)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
|
||||
if(on.value)
|
||||
start_process()
|
||||
else
|
||||
stop_process()
|
||||
|
||||
/obj/item/circuit_component/clock/Destroy()
|
||||
stop_process()
|
||||
return ..()
|
||||
|
||||
/obj/item/circuit_component/clock/process(delta_time)
|
||||
signal.set_output(COMPONENT_SIGNAL)
|
||||
|
||||
/**
|
||||
* Adds the component to the SSclock_component process list
|
||||
*
|
||||
* Starts ticking to send signals between periods of time
|
||||
*/
|
||||
/obj/item/circuit_component/clock/proc/start_process()
|
||||
START_PROCESSING(SSclock_component, src)
|
||||
|
||||
/**
|
||||
* Removes the component to the SSclock_component process list
|
||||
*
|
||||
* Signals stop getting sent.
|
||||
*/
|
||||
/obj/item/circuit_component/clock/proc/stop_process()
|
||||
STOP_PROCESSING(SSclock_component, src)
|
||||
@@ -0,0 +1,43 @@
|
||||
/// The minimum delay value that the delay component can have.
|
||||
#define COMP_DELAY_MIN_VALUE 0.1
|
||||
|
||||
/**
|
||||
* # Delay Component
|
||||
*
|
||||
* Delays a signal by a specified duration.
|
||||
*/
|
||||
/obj/item/circuit_component/delay
|
||||
display_name = "Delay"
|
||||
desc = "A component that delays a signal by a specified duration."
|
||||
|
||||
/// Amount to delay by
|
||||
var/datum/port/input/delay_amount
|
||||
/// Input signal to fire the delay
|
||||
var/datum/port/input/trigger
|
||||
|
||||
/// The output of the signal
|
||||
var/datum/port/output/output
|
||||
|
||||
/obj/item/circuit_component/delay/Initialize()
|
||||
. = ..()
|
||||
delay_amount = add_input_port("Delay", PORT_TYPE_NUMBER, FALSE)
|
||||
trigger = add_input_port("Trigger", PORT_TYPE_SIGNAL)
|
||||
|
||||
output = add_output_port("Result", PORT_TYPE_SIGNAL)
|
||||
|
||||
/obj/item/circuit_component/delay/input_received(datum/port/input/port)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
|
||||
if(!COMPONENT_TRIGGERED_BY(trigger, port))
|
||||
return
|
||||
|
||||
var/delay = delay_amount.value
|
||||
if(delay > COMP_DELAY_MIN_VALUE)
|
||||
// Convert delay into deciseconds
|
||||
addtimer(CALLBACK(output, /datum/port/output.proc/set_output, trigger.value), delay*10)
|
||||
else
|
||||
output.set_output(trigger.value)
|
||||
|
||||
#undef COMP_DELAY_MIN_VALUE
|
||||
@@ -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)
|
||||
@@ -0,0 +1,82 @@
|
||||
/**
|
||||
* # Router Component
|
||||
*
|
||||
* Writes one of multiple inputs to one of multiple outputs.
|
||||
*/
|
||||
/obj/item/circuit_component/router
|
||||
display_name = "Router"
|
||||
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
|
||||
|
||||
/// How many ports to have.
|
||||
var/input_port_amount = 4
|
||||
var/output_port_amount = 4
|
||||
|
||||
/// Current type of the ports
|
||||
var/current_type
|
||||
|
||||
/// The ports to route.
|
||||
var/list/datum/port/input/ins
|
||||
var/list/datum/port/output/outs
|
||||
|
||||
/obj/item/circuit_component/router/populate_options()
|
||||
var/static/component_options = list(
|
||||
PORT_TYPE_ANY,
|
||||
PORT_TYPE_STRING,
|
||||
PORT_TYPE_NUMBER,
|
||||
PORT_TYPE_LIST,
|
||||
PORT_TYPE_ATOM,
|
||||
)
|
||||
router_options = add_option_port("Router Options", component_options)
|
||||
|
||||
/obj/item/circuit_component/router/Initialize()
|
||||
. = ..()
|
||||
current_type = router_options.value
|
||||
if(input_port_amount > 1)
|
||||
input_selector = add_input_port("Input Selector", PORT_TYPE_NUMBER, default = 1)
|
||||
if(output_port_amount > 1)
|
||||
output_selector = add_input_port("Output Selector", PORT_TYPE_NUMBER, default = 1)
|
||||
ins = list()
|
||||
for(var/port_id in 1 to input_port_amount)
|
||||
ins += add_input_port(input_port_amount > 1 ? "Input [port_id]" : "Input", current_type)
|
||||
outs = list()
|
||||
for(var/port_id in 1 to output_port_amount)
|
||||
outs += add_output_port(output_port_amount > 1 ? "Output [port_id]" : "Output", current_type)
|
||||
|
||||
/obj/item/circuit_component/router/Destroy()
|
||||
input_selector = null
|
||||
output_selector = null
|
||||
ins.Cut()
|
||||
ins = null
|
||||
outs.Cut()
|
||||
outs = null
|
||||
return ..()
|
||||
|
||||
|
||||
// If I is in range, L[I]. If I is out of range, wrap around.
|
||||
#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.value
|
||||
if(current_type != current_option)
|
||||
current_type = current_option
|
||||
for(var/datum/port/input/input as anything in ins)
|
||||
input.set_datatype(current_type)
|
||||
for(var/datum/port/output/output as anything in outs)
|
||||
output.set_datatype(current_type)
|
||||
if(.)
|
||||
return
|
||||
var/datum/port/input/input = WRAPACCESS(ins, input_selector ? input_selector.value : 1)
|
||||
var/datum/port/output/output = WRAPACCESS(outs, output_selector ? output_selector.value : 1)
|
||||
output.set_output(input.value)
|
||||
|
||||
/obj/item/circuit_component/router/multiplexer
|
||||
display_name = "Multiplexer"
|
||||
desc = "Copies the input chosen by \"Input Selector\" to the output."
|
||||
output_port_amount = 1
|
||||
@@ -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)
|
||||
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* # Typecast Component
|
||||
*
|
||||
* A component that casts a value to a type if it matches or outputs null.
|
||||
*/
|
||||
/obj/item/circuit_component/typecast
|
||||
display_name = "Typecast"
|
||||
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
|
||||
|
||||
var/current_type
|
||||
|
||||
/obj/item/circuit_component/typecast/Initialize()
|
||||
. = ..()
|
||||
current_type = typecast_options.value
|
||||
input_value = add_input_port("Input", PORT_TYPE_ANY)
|
||||
output_value = add_output_port("Output", current_type)
|
||||
|
||||
/obj/item/circuit_component/typecast/populate_options()
|
||||
var/static/list/component_options = list(
|
||||
PORT_TYPE_STRING,
|
||||
PORT_TYPE_NUMBER,
|
||||
PORT_TYPE_LIST,
|
||||
PORT_TYPE_ATOM,
|
||||
)
|
||||
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.value
|
||||
if(current_type != current_option)
|
||||
current_type = current_option
|
||||
output_value.set_datatype(current_type)
|
||||
|
||||
if(.)
|
||||
return
|
||||
|
||||
var/value = input_value.value
|
||||
var/value_to_set = null
|
||||
switch(current_option)
|
||||
if(PORT_TYPE_STRING)
|
||||
if(istext(value))
|
||||
value_to_set = value
|
||||
if(PORT_TYPE_NUMBER)
|
||||
if(isnum(value))
|
||||
value_to_set = value
|
||||
if(PORT_TYPE_LIST)
|
||||
if(islist(value))
|
||||
value_to_set = value
|
||||
if(PORT_TYPE_ATOM)
|
||||
if(isatom(value))
|
||||
value_to_set = value
|
||||
|
||||
output_value.set_output(value_to_set)
|
||||
@@ -0,0 +1,51 @@
|
||||
#define COMP_TYPECHECK_MOB "organism"
|
||||
#define COMP_TYPECHECK_HUMAN "humanoid"
|
||||
|
||||
/**
|
||||
* # Typecheck Component
|
||||
*
|
||||
* Checks the type of a value
|
||||
*/
|
||||
/obj/item/circuit_component/compare/typecheck
|
||||
display_name = "Typecheck"
|
||||
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(
|
||||
PORT_TYPE_STRING,
|
||||
PORT_TYPE_NUMBER,
|
||||
PORT_TYPE_LIST,
|
||||
PORT_TYPE_ATOM,
|
||||
COMP_TYPECHECK_MOB,
|
||||
COMP_TYPECHECK_HUMAN,
|
||||
)
|
||||
typecheck_options = add_option_port("Typecheck Options", component_options)
|
||||
|
||||
/obj/item/circuit_component/compare/typecheck/do_comparisons(list/ports)
|
||||
if(!length(ports))
|
||||
return
|
||||
. = FALSE
|
||||
|
||||
// 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.value
|
||||
switch(typecheck_options.value)
|
||||
if(PORT_TYPE_STRING)
|
||||
return istext(input_val)
|
||||
if(PORT_TYPE_NUMBER)
|
||||
return isnum(input_val)
|
||||
if(PORT_TYPE_LIST)
|
||||
return islist(input_val)
|
||||
if(PORT_TYPE_ATOM)
|
||||
return isatom(input_val)
|
||||
if(COMP_TYPECHECK_MOB)
|
||||
return ismob(input_val)
|
||||
if(COMP_TYPECHECK_HUMAN)
|
||||
return ishuman(input_val)
|
||||
|
||||
|
||||
#undef COMP_TYPECHECK_MOB
|
||||
#undef COMP_TYPECHECK_HUMAN
|
||||
Reference in New Issue
Block a user