[MIRROR] More circuit components. Restructures the circuit components folder to be more organised. (#6142)

* More circuit components. Restructures the circuit components folder to be more organised.

* Mirror!

Co-authored-by: Watermelon914 <37270891+Watermelon914@users.noreply.github.com>
Co-authored-by: Funce <funce.973@gmail.com>
This commit is contained in:
SkyratBot
2021-06-05 17:15:43 +12:00
committed by GitHub
co-authored by Watermelon914 Funce
parent 6e52d05e2e
commit cc5cf407b0
42 changed files with 630 additions and 106 deletions
+3
View File
@@ -1293,3 +1293,6 @@
#define COMSIG_CIRCUIT_ADD_COMPONENT "circuit_add_component"
/// Cancels adding the component to the circuit.
#define COMPONENT_CANCEL_ADD_COMPONENT (1<<0)
/// Called in /obj/structure/moneybot/add_money(). (to_add)
#define COMSIG_MONEYBOT_ADD_MONEY "moneybot_add_money"
+12
View File
@@ -3,6 +3,9 @@
/// Helper define that can only be used in /obj/item/circuit_component/input_received()
#define COMPONENT_TRIGGERED_BY(trigger, port) (trigger.input_value && trigger == port)
/// Define to automatically handle calling the output port. Will not call the output port if the input_received proc returns TRUE.
#define TRIGGER_CIRCUIT_COMPONENT(component, port) if(!component.input_received(port) && (component.circuit_flags & CIRCUIT_FLAG_OUTPUT_SIGNAL)) component.trigger_output.set_output(COMPONENT_SIGNAL)
// Port types. Determines what the port can connect to
/// Can accept any datatype. Only works for inputs, output types will runtime.
@@ -78,6 +81,9 @@
// Clock component
#define COMP_CLOCK_DELAY 0.9 SECONDS
// Combiner component
#define COMP_COMBINER_ANY "any"
// Shells
/// Whether a circuit is stuck on a shell and cannot be removed (by a user)
@@ -91,3 +97,9 @@
#define SHELL_CAPACITY_MEDIUM 25
#define SHELL_CAPACITY_LARGE 50
#define SHELL_CAPACITY_VERY_LARGE 500
// Circuit flags
/// Creates an input trigger that means the component won't be triggered unless the trigger is pulsed.
#define CIRCUIT_FLAG_INPUT_SIGNAL (1<<0)
/// Creates an output trigger that sends a pulse whenever the component is successfully triggered
#define CIRCUIT_FLAG_OUTPUT_SIGNAL (1<<1)
+26 -1
View File
@@ -14,6 +14,8 @@
/// A list of components that cannot be removed
var/list/obj/item/circuit_component/unremovable_circuit_components
var/locked = FALSE
/datum/component/shell/Initialize(unremovable_circuit_components, capacity, shell_flags)
. = ..()
if(!ismovable(parent))
@@ -33,14 +35,17 @@
if(!(shell_flags & SHELL_FLAG_CIRCUIT_FIXED))
RegisterSignal(parent, COMSIG_ATOM_TOOL_ACT(TOOL_SCREWDRIVER), .proc/on_screwdriver_act)
RegisterSignal(parent, COMSIG_ATOM_TOOL_ACT(TOOL_MULTITOOL), .proc/on_multitool_act)
RegisterSignal(parent, COMSIG_OBJ_DECONSTRUCT, .proc/on_object_deconstruct)
if(shell_flags & SHELL_FLAG_REQUIRE_ANCHOR)
RegisterSignal(parent, COMSIG_OBJ_DEFAULT_UNFASTEN_WRENCH, .proc/on_unfasten)
/datum/component/shell/UnregisterFromParent()
UnregisterSignal(parent, list(
COMSIG_PARENT_ATTACKBY,
COMSIG_ATOM_TOOL_ACT(TOOL_SCREWDRIVER),
COMSIG_ATOM_TOOL_ACT(TOOL_MULTITOOL),
COMSIG_OBJ_DECONSTRUCT,
COMSIG_OBJ_DEFAULT_UNFASTEN_WRENCH,
COMSIG_PARENT_EXAMINE,
COMSIG_ATOM_ATTACK_GHOST
@@ -52,6 +57,10 @@
QDEL_LIST(unremovable_circuit_components)
return ..()
/datum/component/shell/proc/on_object_deconstruct()
SIGNAL_HANDLER
remove_circuit()
/datum/component/shell/proc/on_attack_ghost(datum/source, mob/dead/observer/ghost)
SIGNAL_HANDLER
if(attached_circuit)
@@ -60,9 +69,11 @@
/datum/component/shell/proc/on_examine(datum/source, mob/user, list/examine_text)
SIGNAL_HANDLER
if(!attached_circuit)
examine_text += "<span class='notice'>There is no integrated circuit attached.</span>"
return
examine_text += "<span class='notice'>There is an integrated circuit attached. Use a multitool to access the wiring. Use a screwdriver to remove it from [source].</span>"
examine_text += "<span class='notice'>The cover panel to the integrated circuit is [locked? "locked" : "unlocked"].</span>"
var/obj/item/stock_parts/cell/cell = attached_circuit.cell
examine_text += "<span class='notice'>The charge meter reads [cell ? round(cell.percent(), 1) : 0]%.</span>"
@@ -85,6 +96,11 @@
source.balloon_alert(attacker, "can't pull cell in directly!")
return
if(attached_circuit?.owner_id && item == attached_circuit.owner_id.resolve())
locked = !locked
source.balloon_alert(attacker, "[locked? "locked" : "unlocked"] [source]")
return COMPONENT_NO_AFTERATTACK
if(!istype(item, /obj/item/integrated_circuit))
return
var/obj/item/integrated_circuit/logic_board = item
@@ -108,6 +124,10 @@
if(!attached_circuit)
return
if(locked)
source.balloon_alert(user, "it's locked!")
return COMPONENT_BLOCK_TOOL_ATTACK
attached_circuit.interact(user)
return COMPONENT_BLOCK_TOOL_ATTACK
@@ -119,8 +139,12 @@
if(!attached_circuit)
return
if(locked)
source.balloon_alert(user, "it's locked!")
return COMPONENT_BLOCK_TOOL_ATTACK
tool.play_tool_sound(parent)
source.balloon_alert(user, "You unscrew [attached_circuit] from [parent].")
source.balloon_alert(user, "you unscrew [attached_circuit] from [parent].")
remove_circuit()
return COMPONENT_BLOCK_TOOL_ATTACK
@@ -149,6 +173,7 @@
/datum/component/shell/proc/attach_circuit(obj/item/integrated_circuit/circuitboard, mob/living/user)
if(!user.transferItemToLoc(circuitboard, parent))
return
locked = FALSE
attached_circuit = circuitboard
RegisterSignal(circuitboard, COMSIG_MOVABLE_MOVED, .proc/on_circuit_moved)
RegisterSignal(circuitboard, COMSIG_PARENT_QDELETING, .proc/on_circuit_delete)
@@ -153,6 +153,35 @@
id = "comp_radio"
build_path = /obj/item/circuit_component/radio
/datum/design/component/gps
name = "GPS Component"
desc = "A component that returns the xyz co-ordinates of itself."
id = "comp_gps"
build_path = /obj/item/circuit_component/gps
/datum/design/component/direction
name = "Direction Component"
desc = "A component that returns the direction of itself and an entity."
id = "comp_direction"
build_path = /obj/item/circuit_component/direction
/datum/design/component/health
name = "Health Component"
desc = "A component that returns the health of an organism."
id = "comp_health"
build_path = /obj/item/circuit_component/health
/datum/design/component/combiner
name = "Combiner Component"
desc = "A component that combines multiple inputs to provide 1 output."
id = "comp_combiner"
build_path = /obj/item/circuit_component/combiner
/datum/design/component/pull
name = "Pull Component"
desc = "A component that can force the shell to pull entities. Only works for drone shells."
id = "comp_pull"
build_path = /obj/item/circuit_component/pull
/datum/design/compact_remote_shell
name = "Compact Remote Shell"
@@ -181,6 +210,15 @@
materials = list(/datum/material/glass = 2000, /datum/material/iron = 10000)
category = list("Circuitry", "Shells")
/datum/design/money_bot_shell
name = "Money Bot Shell"
desc = "An immobile shell that is similar to a regular bot shell, but accepts monetary inputs and can also dispense money."
id = "money_bot_shell"
build_path = /obj/item/shell/money_bot
build_type = PROTOLATHE | COMPONENT_PRINTER
materials = list(/datum/material/glass = 2000, /datum/material/iron = 10000, /datum/material/gold = 50)
category = list("Circuitry", "Shells")
/datum/design/drone_shell
name = "Drone Shell"
desc = "A shell with the ability to move itself around."
@@ -219,9 +219,13 @@
"circuit_multitool",
"comp_arithmetic",
"comp_clock",
"comp_combiner",
"comp_comparison",
"comp_concat",
"comp_delay",
"comp_direction",
"comp_gps",
"comp_health",
"comp_hear",
"comp_index",
"comp_length",
@@ -676,6 +680,7 @@
design_ids = list(
"bot_shell",
"controller_shell",
"money_bot_shell",
)
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
@@ -685,6 +690,7 @@
description = "Grants access to movable shells."
prereq_ids = list("adv_shells", "robotics")
design_ids = list(
"comp_pull",
"drone_shell",
)
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 3000)
+7 -5
View File
@@ -31,7 +31,8 @@
var/datum/port/input/trigger_input
var/datum/port/output/trigger_output
var/has_trigger = FALSE
/// The flags of the circuit to control basic generalised behaviour.
var/circuit_flags = NONE
/// Used to determine the x position of the component within the UI
var/rel_x = 0
@@ -60,8 +61,9 @@
/obj/item/circuit_component/LateInitialize()
. = ..()
if(has_trigger)
if(circuit_flags & CIRCUIT_FLAG_INPUT_SIGNAL)
trigger_input = add_input_port("Trigger", PORT_TYPE_SIGNAL)
if(circuit_flags & CIRCUIT_FLAG_OUTPUT_SIGNAL)
trigger_output = add_output_port("Triggered", PORT_TYPE_SIGNAL)
/obj/item/circuit_component/Destroy()
@@ -117,7 +119,7 @@
*/
/obj/item/circuit_component/proc/set_option(option)
current_option = option
input_received()
TRIGGER_CIRCUIT_COMPONENT(src, null)
/**
* Matches the output port's datatype with the input port's current connected port.
@@ -165,7 +167,7 @@
/**
* Called whenever an input is received from one of the ports.
*
* Return value indicates that the circuit should not do anything
* Return value indicates that the circuit should not do anything. Also prevents an output signal.
* Arguments:
* * port - Can be null. The port that sent the input
*/
@@ -178,5 +180,5 @@
if(!cell?.use(power_usage_per_input))
return TRUE
if(has_trigger && !COMPONENT_TRIGGERED_BY(trigger_input, port))
if((circuit_flags & CIRCUIT_FLAG_INPUT_SIGNAL) && !COMPONENT_TRIGGERED_BY(trigger_input, port))
return TRUE
@@ -41,7 +41,7 @@
/obj/item/circuit_component/light/register_shell(atom/movable/shell)
. = ..()
input_received()
TRIGGER_CIRCUIT_COMPONENT(src, null)
/obj/item/circuit_component/light/unregister_shell(atom/movable/shell)
shell.set_light_on(FALSE)
@@ -49,10 +49,10 @@
/obj/item/circuit_component/light/input_received(datum/port/input/port)
. = ..()
brightness.set_input(min(max(brightness.input_value || 0, 0), max_power), FALSE)
red.set_input(min(max(red.input_value, 0), 255), FALSE)
blue.set_input(min(max(blue.input_value, 0), 255), FALSE)
green.set_input(min(max(green.input_value, 0), 255), FALSE)
brightness.set_input(clamp(brightness.input_value || 0, 0, max_power), FALSE)
red.set_input(clamp(red.input_value, 0, 255), FALSE)
blue.set_input(clamp(blue.input_value, 0, 255), FALSE)
green.set_input(clamp(green.input_value, 0, 255), FALSE)
var/list/hsl = rgb2hsl(red.input_value || 0, green.input_value || 0, blue.input_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])
@@ -0,0 +1,34 @@
/**
* # 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"
/// 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/Destroy()
target = null
return ..()
/obj/item/circuit_component/pull/input_received(datum/port/input/port)
. = ..()
if(.)
return
var/atom/target_atom = target.input_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)
@@ -1,7 +1,7 @@
/**
* # Radio Component
*
* Listens out for signals on the designated frequencies and
* Listens out for signals on the designated frequencies and sends signals on designated frequencies
*/
/obj/item/circuit_component/radio
display_name = "Radio"
@@ -20,14 +20,13 @@
. = ..()
freq = add_input_port("Frequency", PORT_TYPE_NUMBER, default = FREQ_SIGNALER)
code = add_input_port("Code", PORT_TYPE_NUMBER, default = DEFAULT_SIGNALER_CODE)
// 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()
freq = null
code = null
trigger_input = null
trigger_output = null
SSradio.remove_object(src, current_freq)
radio_connection = null
return ..()
@@ -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"
/// 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/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/Destroy()
input_port = null
output = null
return ..()
/obj/item/circuit_component/direction/input_received(datum/port/input/port)
. = ..()
if(.)
return
var/atom/object = input_port.input_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,39 @@
/**
* # GPS Component
*
* Return the location of this
*/
/obj/item/circuit_component/gps
display_name = "Internal GPS"
/// 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/Destroy()
x_pos = null
y_pos = null
z_pos = null
return ..()
/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,66 @@
/**
* # Get Health Component
*
* Return the health of a mob
*/
/obj/item/circuit_component/health
display_name = "Get Health"
/// 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/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/Destroy()
input_port = null
brute = null
burn = null
toxin = null
oxy = null
health = null
return ..()
/obj/item/circuit_component/health/input_received(datum/port/input/port)
. = ..()
if(.)
return
var/mob/living/organism = input_port.input_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)
@@ -12,7 +12,7 @@
/// The result from the output
var/datum/port/output/output
has_trigger = TRUE
circuit_flags = CIRCUIT_FLAG_INPUT_SIGNAL|CIRCUIT_FLAG_OUTPUT_SIGNAL
/obj/item/circuit_component/species/Initialize()
. = ..()
@@ -36,4 +36,4 @@
return
output.set_output(human.dna.species.name)
trigger_output.set_output(COMPONENT_SIGNAL)
-33
View File
@@ -1,33 +0,0 @@
/**
* # Dummy Component
*
* Dummy component that does nothing, only for debugging purposes
*
* Has two input and output ports that do nothing
*/
/obj/item/circuit_component/dummy
display_name = "Dummy Component"
/// The input ports of the dummy component
var/datum/port/input/receive1
var/datum/port/input/receive2
/// The output ports of the dummy component
var/datum/port/output/output1
var/datum/port/output/output2
/obj/item/circuit_component/dummy/Initialize()
. = ..()
receive1 = add_input_port("Receive 1", PORT_TYPE_ANY)
receive2 = add_input_port("Receive 2", PORT_TYPE_ANY)
output1 = add_output_port("Output 1", PORT_TYPE_NUMBER)
output2 = add_output_port("Output 2", PORT_TYPE_NUMBER)
/obj/item/circuit_component/dummy/Destroy()
// Cleaned up in parent proc
receive1 = null
receive2 = null
output1 = null
output2 = null
return ..()
@@ -13,7 +13,7 @@
/// The result from the output
var/datum/port/output/output
has_trigger = TRUE
circuit_flags = CIRCUIT_FLAG_INPUT_SIGNAL|CIRCUIT_FLAG_OUTPUT_SIGNAL
GLOBAL_LIST_INIT(comp_arithmetic_options, list(
COMP_ARITHMETIC_ADD,
@@ -72,4 +72,4 @@ GLOBAL_LIST_INIT(comp_arithmetic_options, list(
result = min(result, value)
output.set_output(result)
trigger_output.set_output(COMPONENT_SIGNAL)
@@ -12,7 +12,7 @@
/// The result from the output
var/datum/port/output/output
has_trigger = TRUE
circuit_flags = CIRCUIT_FLAG_INPUT_SIGNAL|CIRCUIT_FLAG_OUTPUT_SIGNAL
/obj/item/circuit_component/index/Initialize()
. = ..()
@@ -44,4 +44,4 @@
return
output.set_output(list_input[index])
trigger_output.set_output(COMPONENT_SIGNAL)
@@ -11,7 +11,7 @@
/// The result from the output
var/datum/port/output/output
has_trigger = TRUE
circuit_flags = CIRCUIT_FLAG_INPUT_SIGNAL|CIRCUIT_FLAG_OUTPUT_SIGNAL
/obj/item/circuit_component/length/Initialize()
. = ..()
@@ -30,4 +30,4 @@
return
output.set_output(length(input_port.input_value))
trigger_output.set_output(COMPONENT_SIGNAL)
@@ -11,7 +11,7 @@
/// The result from the output
var/datum/port/output/result
has_trigger = TRUE
circuit_flags = CIRCUIT_FLAG_INPUT_SIGNAL|CIRCUIT_FLAG_OUTPUT_SIGNAL
/obj/item/circuit_component/not/Initialize()
. = ..()
@@ -30,4 +30,4 @@
return
result.set_output(!input_port.input_value)
trigger_output.set_output(COMPONENT_SIGNAL)
@@ -11,7 +11,7 @@
/// The maximum value that the random number can be
var/datum/port/input/maximum
has_trigger = TRUE
circuit_flags = CIRCUIT_FLAG_INPUT_SIGNAL|CIRCUIT_FLAG_OUTPUT_SIGNAL
/// The result from the output
var/datum/port/output/output
@@ -42,4 +42,4 @@
return
output.set_output(rand(min_val, max_val))
trigger_output.set_output(COMPONENT_SIGNAL)
@@ -11,7 +11,7 @@
/// The result from the output
var/datum/port/output/output
has_trigger = TRUE
circuit_flags = CIRCUIT_FLAG_INPUT_SIGNAL|CIRCUIT_FLAG_OUTPUT_SIGNAL
/obj/item/circuit_component/concat/Initialize()
. = ..()
@@ -42,4 +42,4 @@
result += "[value]"
output.set_output(result)
trigger_output.set_output(COMPONENT_SIGNAL)
@@ -12,7 +12,7 @@
/// The result of the text operation
var/datum/port/output/output
has_trigger = TRUE
circuit_flags = CIRCUIT_FLAG_INPUT_SIGNAL|CIRCUIT_FLAG_OUTPUT_SIGNAL
GLOBAL_LIST_INIT(comp_text_operations, list(
COMP_TEXT_LOWER,
@@ -47,4 +47,4 @@ GLOBAL_LIST_INIT(comp_text_operations, list(
result = uppertext(value)
output.set_output(result)
trigger_output.set_output(COMPONENT_SIGNAL)
@@ -12,9 +12,9 @@
/// The result from the output
var/datum/port/output/output
has_trigger = TRUE
circuit_flags = CIRCUIT_FLAG_INPUT_SIGNAL|CIRCUIT_FLAG_OUTPUT_SIGNAL
var/min_range = 5
var/max_range = 5
/obj/item/circuit_component/tostring/Initialize()
. = ..()
@@ -36,9 +36,9 @@
if(isatom(input_value))
var/turf/location = get_turf(src)
var/atom/object = input_value
if(object.z != location.z || get_dist(location, object) > min_range)
if(object.z != location.z || get_dist(location, object) > max_range)
output.set_output(PORT_TYPE_ATOM)
return
output.set_output("[input_value]")
trigger_output.set_output(COMPONENT_SIGNAL)
@@ -0,0 +1,46 @@
/**
* # Combiner Component
*
* Combines multiple inputs into 1 output port.
*/
/obj/item/circuit_component/combiner
display_name = "Combiner"
/// The amount of input ports to have
var/input_port_amount = 4
var/datum/port/output/output_port
var/current_type
GLOBAL_LIST_INIT(comp_combiner_options, list(
COMP_COMBINER_ANY,
PORT_TYPE_STRING,
PORT_TYPE_NUMBER,
PORT_TYPE_LIST,
PORT_TYPE_ATOM,
PORT_TYPE_SIGNAL,
))
/obj/item/circuit_component/combiner/Initialize()
options = GLOB.comp_combiner_options
. = ..()
current_type = current_option
for(var/port_id in 1 to input_port_amount)
var/letter = ascii2text(text2ascii("A") + (port_id-1))
add_input_port(letter, current_type)
output_port = add_output_port("Output", current_type)
/obj/item/circuit_component/combiner/input_received(datum/port/input/port)
. = ..()
if(current_type != current_option && (current_option != COMP_COMBINER_ANY || current_type != PORT_TYPE_ANY))
current_type = current_option
if(current_type == COMP_COMBINER_ANY)
current_type = PORT_TYPE_ANY
for(var/datum/port/input/input_port as anything in input_ports)
input_port.set_datatype(current_type)
output_port.set_datatype(current_type)
output_port.set_output(port?.input_value)
if(. || !port)
return TRUE
@@ -8,9 +8,6 @@
input_port_amount = 1
has_trigger = TRUE
GLOBAL_LIST_INIT(comp_typecheck_options, list(
PORT_TYPE_STRING,
PORT_TYPE_NUMBER,
@@ -45,4 +42,4 @@ GLOBAL_LIST_INIT(comp_typecheck_options, list(
return ismob(input_val)
if(COMP_TYPECHECK_HUMAN)
return ishuman(input_val)
trigger_output.set_output(COMPONENT_SIGNAL)
+36 -2
View File
@@ -11,6 +11,12 @@
icon_state = "integrated_circuit"
inhand_icon_state = "electronic"
/// The name that appears on the shell.
var/display_name = ""
/// The max length of the name.
var/label_max_length = 24
/// The power of the integrated circuit
var/obj/item/stock_parts/cell/cell
@@ -23,6 +29,9 @@
/// Whether the integrated circuit is on or not. Handled by the shell.
var/on = FALSE
/// The ID that is authorized to unlock/lock the shell so that the circuit can/cannot be removed.
var/datum/weakref/owner_id
/obj/item/integrated_circuit/loaded/Initialize()
. = ..()
cell = new /obj/item/stock_parts/cell/high(src)
@@ -50,7 +59,7 @@
if(istype(I, /obj/item/stock_parts/cell))
if(cell)
balloon_alert(user, "<span class='warning'>There already is a cell inside!</span>")
balloon_alert(user, "there already is a cell inside!")
return
if(!user.transferItemToLoc(I, src))
return
@@ -59,6 +68,11 @@
user.visible_message("<span class='notice'>[user] inserts a power cell into [src].</span>", "<span class='notice'>You insert the power cell into [src].</span>")
return
if(istype(I, /obj/item/card/id))
balloon_alert(user, "owner id set for [I]")
owner_id = WEAKREF(I)
return
if(I.tool_behaviour == TOOL_SCREWDRIVER)
if(!cell)
return
@@ -85,7 +99,9 @@
attached_component.register_shell(shell)
// Their input ports may be updated with user values, but the outputs haven't updated
// because on is FALSE
attached_component.input_received()
TRIGGER_CIRCUIT_COMPONENT(attached_component, null)
if(display_name != "")
shell.name = "[initial(shell.name)] ([display_name])"
/**
* Unregisters the current shell attached to this circuit.
@@ -94,6 +110,7 @@
SIGNAL_HANDLER
if(!shell)
return
shell.name = initial(shell.name)
for(var/obj/item/circuit_component/attached_component as anything in attached_components)
attached_component.unregister_shell(shell)
UnregisterSignal(shell, COMSIG_PARENT_QDELETING)
@@ -194,6 +211,8 @@
component_data["removable"] = component.removable
.["components"] += list(component_data)
.["display_name"] = display_name
/obj/item/integrated_circuit/ui_host(mob/user)
if(shell)
return shell
@@ -347,5 +366,20 @@
value = "null"
balloon_alert(usr, "[port.name] value: [value]")
. = TRUE
if("set_display_name")
var/new_name = params["display_name"]
if(new_name)
display_name = strip_html(params["display_name"], label_max_length)
else
display_name = ""
if(shell)
if(display_name != "")
shell.name = "[initial(shell.name)] ([display_name])"
else
shell.name = initial(shell.name)
. = TRUE
#undef WITHIN_RANGE
+4 -1
View File
@@ -64,6 +64,9 @@
return prev_value
. = value_to_convert
if(isnull(value_to_convert))
return null
switch(datatype)
if(PORT_TYPE_STRING)
// So that they can't easily get the name like this.
@@ -248,7 +251,7 @@
SEND_SIGNAL(src, COMSIG_PORT_SET_INPUT, input_value)
if(trigger && send_update)
connected_component.input_received(src)
TRIGGER_CIRCUIT_COMPONENT(connected_component, src)
/// Signal handler proc to null the input if an atom is deleted. An update is not sent because this was not set by anything.
/datum/port/input/proc/null_output(datum/source)
+17 -4
View File
@@ -34,6 +34,15 @@
var/datum/port/input/south
var/datum/port/input/west
// Done like this so that travelling diagonally is more simple
COOLDOWN_DECLARE(north_delay)
COOLDOWN_DECLARE(east_delay)
COOLDOWN_DECLARE(south_delay)
COOLDOWN_DECLARE(west_delay)
/// Delay between each movement
var/move_delay = COMP_CLOCK_DELAY
/obj/item/circuit_component/bot_circuit/Initialize()
. = ..()
north = add_input_port("Move North", PORT_TYPE_SIGNAL)
@@ -52,14 +61,18 @@
var/direction
if(COMPONENT_TRIGGERED_BY(north, port))
if(COMPONENT_TRIGGERED_BY(north, port) && COOLDOWN_FINISHED(src, north_delay))
direction = NORTH
else if(COMPONENT_TRIGGERED_BY(east, port))
COOLDOWN_START(src, north_delay, move_delay)
else if(COMPONENT_TRIGGERED_BY(east, port) && COOLDOWN_FINISHED(src, east_delay))
direction = EAST
else if(COMPONENT_TRIGGERED_BY(south, port))
COOLDOWN_START(src, east_delay, move_delay)
else if(COMPONENT_TRIGGERED_BY(south, port) && COOLDOWN_FINISHED(src, south_delay))
direction = SOUTH
else if(COMPONENT_TRIGGERED_BY(west, port))
COOLDOWN_START(src, south_delay, move_delay)
else if(COMPONENT_TRIGGERED_BY(west, port) && COOLDOWN_FINISHED(src, west_delay))
direction = WEST
COOLDOWN_START(src, west_delay, move_delay)
if(!direction)
return
+138
View File
@@ -0,0 +1,138 @@
/**
* # Money Bot
*
* Immobile (but not dense) shell that can receive and dispense money.
*/
/obj/structure/money_bot
name = "money bot"
icon = 'icons/obj/wiremod.dmi'
icon_state = "setup_large"
density = FALSE
light_system = MOVABLE_LIGHT
light_on = FALSE
var/stored_money = 0
/obj/structure/money_bot/deconstruct(disassembled)
new /obj/item/holochip(drop_location(), stored_money)
return ..()
/obj/structure/money_bot/proc/add_money(to_add)
stored_money += to_add
SEND_SIGNAL(src, COMSIG_MONEYBOT_ADD_MONEY, to_add)
/obj/structure/money_bot/Initialize()
. = ..()
AddComponent(/datum/component/shell, list(
new /obj/item/circuit_component/money_bot(),
new /obj/item/circuit_component/money_dispenser()
), SHELL_CAPACITY_LARGE)
/obj/structure/money_bot/wrench_act(mob/living/user, obj/item/tool)
set_anchored(!anchored)
tool.play_tool_sound(src)
balloon_alert(user, "You [anchored?"secure":"unsecure"] [src].")
return TRUE
/obj/item/circuit_component/money_dispenser
display_name = "Money Dispenser"
circuit_flags = CIRCUIT_FLAG_INPUT_SIGNAL|CIRCUIT_FLAG_OUTPUT_SIGNAL
/// The amount of money to dispense
var/datum/port/input/dispense_amount
var/obj/structure/money_bot/attached_bot
/obj/item/circuit_component/money_dispenser/Initialize()
. = ..()
dispense_amount = add_input_port("Amount", PORT_TYPE_NUMBER)
/obj/item/circuit_component/money_dispenser/register_shell(atom/movable/shell)
. = ..()
if(istype(shell, /obj/structure/money_bot))
attached_bot = shell
/obj/item/circuit_component/money_dispenser/unregister_shell(atom/movable/shell)
attached_bot = null
return ..()
/obj/item/circuit_component/money_dispenser/input_received(datum/port/input/port)
. = ..()
if(.)
return
if(!attached_bot)
return
var/to_dispense = clamp(dispense_amount.input_value, 0, attached_bot.stored_money)
attached_bot.add_money(-to_dispense)
new /obj/item/holochip(drop_location(), to_dispense)
/obj/item/circuit_component/money_dispenser/Destroy()
dispense_amount = null
attached_bot = null
return ..()
/obj/item/circuit_component/money_bot
display_name = "Money Bot"
var/obj/structure/money_bot/attached_bot
/// Total money in the shell
var/datum/port/output/total_money
/// Amount of the last money inputted into the shell
var/datum/port/output/money_input
/// Trigger for when money is inputted into the shell
var/datum/port/output/money_trigger
/obj/item/circuit_component/money_bot/Initialize()
. = ..()
total_money = add_output_port("Total Money", PORT_TYPE_NUMBER)
money_input = add_output_port("Last Input Money", PORT_TYPE_NUMBER)
money_trigger = add_output_port("Money Input", PORT_TYPE_SIGNAL)
/obj/item/circuit_component/money_bot/register_shell(atom/movable/shell)
. = ..()
if(istype(shell, /obj/structure/money_bot))
attached_bot = shell
total_money.set_output(attached_bot.stored_money)
RegisterSignal(shell, COMSIG_PARENT_ATTACKBY, .proc/handle_money_insert)
RegisterSignal(shell, COMSIG_MONEYBOT_ADD_MONEY, .proc/handle_money_update)
/obj/item/circuit_component/money_bot/unregister_shell(atom/movable/shell)
UnregisterSignal(shell, list(
COMSIG_PARENT_ATTACKBY,
COMSIG_MONEYBOT_ADD_MONEY,
))
total_money.set_output(null)
attached_bot = null
return ..()
/obj/item/circuit_component/money_bot/Destroy()
attached_bot = null
total_money = null
money_input = null
money_trigger = null
return ..()
/obj/item/circuit_component/money_bot/proc/handle_money_insert(atom/source, obj/item/item, mob/living/attacker)
SIGNAL_HANDLER
if(!attached_bot || !iscash(item))
return
var/amount_to_insert = item.get_item_credit_value()
if(!amount_to_insert)
balloon_alert(attacker, "this has no value!")
return
attached_bot.add_money(amount_to_insert)
balloon_alert(attacker, "inserted [amount_to_insert] credits.")
money_input.set_output(amount_to_insert)
money_trigger.set_output(COMPONENT_SIGNAL)
qdel(item)
/obj/item/circuit_component/money_bot/proc/handle_money_update(atom/source)
SIGNAL_HANDLER
if(attached_bot)
total_money.set_output(attached_bot.stored_money)
@@ -30,6 +30,11 @@
icon_state = "setup_medium_box-open"
shell_to_spawn = /obj/structure/bot
/obj/item/shell/money_bot
name = "money bot assembly"
icon_state = "setup_large-open"
shell_to_spawn = /obj/structure/money_bot
/obj/item/shell/drone
name = "drone assembly"
icon_state = "setup_medium_med-open"
+27 -22
View File
@@ -3588,35 +3588,40 @@
#include "code\modules\wiremod\integrated_circuit.dm"
#include "code\modules\wiremod\marker.dm"
#include "code\modules\wiremod\port.dm"
#include "code\modules\wiremod\components\arithmetic.dm"
#include "code\modules\wiremod\components\clock.dm"
#include "code\modules\wiremod\components\comparison.dm"
#include "code\modules\wiremod\components\concat.dm"
#include "code\modules\wiremod\components\contains.dm"
#include "code\modules\wiremod\components\delay.dm"
#include "code\modules\wiremod\components\dummy.dm"
#include "code\modules\wiremod\components\hear.dm"
#include "code\modules\wiremod\components\index.dm"
#include "code\modules\wiremod\components\length.dm"
#include "code\modules\wiremod\components\light.dm"
#include "code\modules\wiremod\components\logic.dm"
#include "code\modules\wiremod\components\not.dm"
#include "code\modules\wiremod\components\radio.dm"
#include "code\modules\wiremod\components\ram.dm"
#include "code\modules\wiremod\components\random.dm"
#include "code\modules\wiremod\components\self.dm"
#include "code\modules\wiremod\components\species.dm"
#include "code\modules\wiremod\components\speech.dm"
#include "code\modules\wiremod\components\textcase.dm"
#include "code\modules\wiremod\components\tostring.dm"
#include "code\modules\wiremod\components\typecheck.dm"
#include "code\modules\wiremod\components\abstract\compare.dm"
#include "code\modules\wiremod\components\action\light.dm"
#include "code\modules\wiremod\components\action\pull.dm"
#include "code\modules\wiremod\components\action\radio.dm"
#include "code\modules\wiremod\components\action\speech.dm"
#include "code\modules\wiremod\components\atom\direction.dm"
#include "code\modules\wiremod\components\atom\gps.dm"
#include "code\modules\wiremod\components\atom\health.dm"
#include "code\modules\wiremod\components\atom\hear.dm"
#include "code\modules\wiremod\components\atom\self.dm"
#include "code\modules\wiremod\components\atom\species.dm"
#include "code\modules\wiremod\components\math\arithmetic.dm"
#include "code\modules\wiremod\components\math\comparison.dm"
#include "code\modules\wiremod\components\math\index.dm"
#include "code\modules\wiremod\components\math\length.dm"
#include "code\modules\wiremod\components\math\logic.dm"
#include "code\modules\wiremod\components\math\not.dm"
#include "code\modules\wiremod\components\math\random.dm"
#include "code\modules\wiremod\components\string\concat.dm"
#include "code\modules\wiremod\components\string\contains.dm"
#include "code\modules\wiremod\components\string\textcase.dm"
#include "code\modules\wiremod\components\string\tostring.dm"
#include "code\modules\wiremod\components\utility\clock.dm"
#include "code\modules\wiremod\components\utility\combiner.dm"
#include "code\modules\wiremod\components\utility\delay.dm"
#include "code\modules\wiremod\components\utility\ram.dm"
#include "code\modules\wiremod\components\utility\typecheck.dm"
#include "code\modules\wiremod\preset\hello_world.dm"
#include "code\modules\wiremod\preset\speech_relay.dm"
#include "code\modules\wiremod\shell\bot.dm"
#include "code\modules\wiremod\shell\compact_remote.dm"
#include "code\modules\wiremod\shell\controller.dm"
#include "code\modules\wiremod\shell\drone.dm"
#include "code\modules\wiremod\shell\moneybot.dm"
#include "code\modules\wiremod\shell\server.dm"
#include "code\modules\wiremod\shell\shell_items.dm"
#include "code\modules\zombie\items.dm"
@@ -168,13 +168,21 @@ export class IntegratedCircuit extends Component {
render() {
const { act, data } = useBackend(this.context);
const { components } = data;
const { components, display_name } = data;
const { locations } = this.state;
return (
<Window
width={600}
height={600}
buttons={(
<Input
fluid
placeholder="Circuit Name"
value={display_name}
onChange={(e, value) => act("set_display_name", { display_name: value })}
/>
)}
>
<Window.Content
style={{
+14 -5
View File
@@ -9,7 +9,7 @@ import { useDispatch } from 'common/redux';
import { decodeHtmlEntities, toTitleCase } from 'common/string';
import { Component } from 'inferno';
import { backendSuspendStart, useBackend } from '../backend';
import { Icon } from '../components';
import { Icon, Flex } from '../components';
import { UI_DISABLED, UI_INTERACTIVE, UI_UPDATE } from '../constants';
import { useDebug } from '../debug';
import { toggleKitchenSink } from '../debug/actions';
@@ -66,6 +66,7 @@ export class Window extends Component {
theme,
title,
children,
buttons,
} = this.props;
const {
config,
@@ -94,7 +95,9 @@ export class Window extends Component {
logger.log('pressed close');
dispatch(backendSuspendStart());
}}
canClose={canClose} />
canClose={canClose}>
{buttons}
</TitleBar>
<div
className={classes([
'Window__rest',
@@ -166,6 +169,7 @@ const TitleBar = (props, context) => {
fancy,
onDragStart,
onClose,
children,
} = props;
const dispatch = useDispatch(context);
return (
@@ -185,15 +189,20 @@ const TitleBar = (props, context) => {
color={statusToColor(status)}
name="eye" />
)}
<div
className="TitleBar__dragZone"
onMousedown={e => fancy && onDragStart(e)} />
<div className="TitleBar__title">
{typeof title === 'string'
&& title === title.toLowerCase()
&& toTitleCase(title)
|| title}
{!!children && (
<div className="TitleBar__buttons">
{children}
</div>
)}
</div>
<div
className="TitleBar__dragZone"
onMousedown={e => fancy && onDragStart(e)} />
{process.env.NODE_ENV !== 'production' && (
<div
className="TitleBar__devBuildIndicator"
@@ -35,6 +35,7 @@ $shadow-color: rgba(0, 0, 0, 0.1) !default;
.TitleBar__title {
position: absolute;
display: inline-block;
top: 0;
left: 46px;
left: base.rem(46px);
@@ -44,6 +45,14 @@ $shadow-color: rgba(0, 0, 0, 0.1) !default;
line-height: 31px;
line-height: base.rem(31px);
white-space: nowrap;
pointer-events: none;
}
.TitleBar__buttons {
pointer-events: initial;
display: inline-block;
width: 100%;
margin-left: 10px;
}
.TitleBar__dragZone {