Skip to content

Commit

Permalink
Integrated Circuits (Wiremod) (tgstation#59232)
Browse files Browse the repository at this point in the history
Co-authored-by: Watermelon914 <[email protected]>
Co-authored-by: Mothblocks <[email protected]>
Co-authored-by: ATH1909 <[email protected]>
Co-authored-by: Maurukas <[email protected]>
  • Loading branch information
5 people authored May 25, 2021
1 parent bc34e2a commit b84a9f9
Show file tree
Hide file tree
Showing 71 changed files with 7,026 additions and 2,175 deletions.
2,115 changes: 1,114 additions & 1,001 deletions _maps/map_files/Deltastation/DeltaStation2.dmm

Large diffs are not rendered by default.

543 changes: 304 additions & 239 deletions _maps/map_files/IceBoxStation/IceBoxStation.dmm

Large diffs are not rendered by default.

1,242 changes: 797 additions & 445 deletions _maps/map_files/KiloStation/KiloStation.dmm

Large diffs are not rendered by default.

511 changes: 252 additions & 259 deletions _maps/map_files/MetaStation/MetaStation.dmm

Large diffs are not rendered by default.

341 changes: 282 additions & 59 deletions _maps/map_files/tramstation/tramstation.dmm

Large diffs are not rendered by default.

15 changes: 15 additions & 0 deletions code/__DEFINES/dcs/signals.dm
Original file line number Diff line number Diff line change
Expand Up @@ -1268,3 +1268,18 @@
// Exosca signals
/// Sent on exoscan failure/manual interruption: ()
#define COMSIG_EXOSCAN_INTERRUPTED "exoscan_interrupted"

// Component signals
/// From /datum/port/output/set_output: (output_value)
#define COMSIG_PORT_SET_OUTPUT "port_set_output"
/// From /datum/port/input/set_input: (input_value)
#define COMSIG_PORT_SET_INPUT "port_set_input"
/// Sent when a port calls disconnect(). From /datum/port/disconnect: ()
#define COMSIG_PORT_DISCONNECT "port_disconnect"
/// Sent on the output port when an input port registers on it: (datum/port/input/registered_port)
#define COMSIG_PORT_OUTPUT_CONNECT "port_output_connect"

/// Sent when a [/obj/item/circuit_component] is added to a circuit.
#define COMSIG_CIRCUIT_ADD_COMPONENT "circuit_add_component"
/// Cancels adding the component to the circuit.
#define COMPONENT_CANCEL_ADD_COMPONENT (1<<0)
2 changes: 2 additions & 0 deletions code/__DEFINES/machines.dm
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@
#define AWAY_LATHE (1<<8)
/// Imprinters for offstation roles. More limited tech tree.
#define AWAY_IMPRINTER (1<<9)
/// For wiremod/integrated circuits. Uses various minerals.
#define COMPONENT_PRINTER (1<<10)
//Note: More than one of these can be added to a design but imprinter and lathe designs are incompatable.

//Modular computer/NTNet defines
Expand Down
93 changes: 93 additions & 0 deletions code/__DEFINES/wiremod.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
#define PORT_INPUT_RECEIVE_DELAY 0.2 SECONDS

/// 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)

// Port types. Determines what the port can connect to

/// Can accept any datatype. Only works for inputs, output types will runtime.
#define PORT_TYPE_ANY null

// Fundamental datatypes
/// String datatype
#define PORT_TYPE_STRING "string"
#define PORT_MAX_STRING_LENGTH 500
/// Number datatype
#define PORT_TYPE_NUMBER "number"
/// Signal datatype
#define PORT_TYPE_SIGNAL "signal"
/// List datatype
#define PORT_TYPE_LIST "list"

// Other datatypes
/// Atom datatype
#define PORT_TYPE_ATOM "entity"

/// The maximum range between a port and an atom
#define PORT_ATOM_MAX_RANGE 7

#define COMPONENT_DEFAULT_NAME "component"

/// The minimum position of the x and y co-ordinates of the component in the UI
#define COMPONENT_MIN_RANDOM_POS 200
/// The maximum position of the x and y co-ordinates of the component in the UI
#define COMPONENT_MAX_RANDOM_POS 400

/// The maximum position in both directions that a component can be in.
/// Prevents someone from positioning a component at an absurdly high value.
#define COMPONENT_MAX_POS 10000

// Components

/// The value that is sent whenever a component is simply sending a signal. This can be anything.
#define COMPONENT_SIGNAL 1

// Comparison defines
#define COMP_COMPARISON_EQUAL "="
#define COMP_COMPARISON_NOT_EQUAL "!="
#define COMP_COMPARISON_GREATER_THAN ">"
#define COMP_COMPARISON_LESS_THAN "<"
#define COMP_COMPARISON_GREATER_THAN_OR_EQUAL ">="
#define COMP_COMPARISON_LESS_THAN_OR_EQUAL "<="

// Delay defines
/// The minimum delay value that the delay component can have.
#define COMP_DELAY_MIN_VALUE 0.1

// Logic defines
#define COMP_LOGIC_AND "AND"
#define COMP_LOGIC_OR "OR"
#define COMP_LOGIC_XOR "XOR"

// Arithmetic defines
#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"

// Text defines
#define COMP_TEXT_LOWER "To Lower"
#define COMP_TEXT_UPPER "To Upper"

// Typecheck component
#define COMP_TYPECHECK_MOB "organism"
#define COMP_TYPECHECK_HUMAN "humanoid"

// Clock component
#define COMP_CLOCK_DELAY 0.9 SECONDS

// Shells

/// Whether a circuit is stuck on a shell and cannot be removed (by a user)
#define SHELL_FLAG_CIRCUIT_FIXED (1<<0)

/// Whether the shell needs to be anchored for the circuit to be on.
#define SHELL_FLAG_REQUIRE_ANCHOR (1<<1)

// Shell capacities. These can be converted to configs very easily later
#define SHELL_CAPACITY_SMALL 10
#define SHELL_CAPACITY_MEDIUM 25
#define SHELL_CAPACITY_LARGE 50
#define SHELL_CAPACITY_VERY_LARGE 500
3 changes: 3 additions & 0 deletions code/controllers/subsystem/delay_component.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
TIMER_SUBSYSTEM_DEF(circuit_component)
name = "Circuit Components"
priority = FIRE_PRIORITY_DEFAULT
5 changes: 5 additions & 0 deletions code/controllers/subsystem/processing/clock_component.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/// The subsystem used to tick [/datum/component/acid] instances.
PROCESSING_SUBSYSTEM_DEF(clock_component)
name = "Clock Component"
flags = SS_NO_INIT|SS_BACKGROUND|SS_KEEP_TIMING
wait = COMP_CLOCK_DELAY
17 changes: 17 additions & 0 deletions code/datums/components/material_container.dm
Original file line number Diff line number Diff line change
Expand Up @@ -415,3 +415,20 @@
if(!istype(mat))
mat = GET_MATERIAL_REF(mat)
return materials[mat]

/// List format is list(material_name = list(amount = ..., ref = ..., etc.))
/datum/component/material_container/ui_data(mob/user)
var/list/data = list()

for(var/datum/material/material as anything in materials)
var/amount = materials[material]

data += list(list(
"name" = material.name,
"ref" = REF(material),
"amount" = amount,
"sheets" = round(amount / MINERAL_MATERIAL_AMOUNT),
"removable" = amount >= MINERAL_MATERIAL_AMOUNT,
))

return data
18 changes: 18 additions & 0 deletions code/datums/components/remote_materials.dm
Original file line number Diff line number Diff line change
Expand Up @@ -130,3 +130,21 @@ handles linking back and forth.
return "[mat_container.total_amount] / [mat_container.max_amount == INFINITY ? "Unlimited" : mat_container.max_amount] ([silo ? "remote" : "local"])"
else
return "0 / 0"

/// Ejects the given material ref and logs it, or says out loud the problem.
/datum/component/remote_materials/proc/eject_sheets(datum/material/material_ref, eject_amount)
var/atom/movable/movable_parent = parent
if (!istype(movable_parent))
return 0

if (!mat_container)
movable_parent.say("No access to material storage, please contact the quartermaster.")
return 0
if (on_hold())
movable_parent.say("Mineral access is on hold, please contact the quartermaster.")
return 0
var/count = mat_container.retrieve_sheets(eject_amount, material_ref, movable_parent.drop_location())
var/list/matlist = list()
matlist[material_ref] = eject_amount
silo_log(parent, "ejected", -count, "sheets", matlist)
return count
183 changes: 183 additions & 0 deletions code/datums/components/shell.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
/// Makes an atom a shell that is able to take in an attached circuit.
/datum/component/shell
dupe_mode = COMPONENT_DUPE_UNIQUE

/// The circuitboard attached to this shell
var/obj/item/integrated_circuit/attached_circuit

/// Flags containing what this shell can do
var/shell_flags = 0

/// The capacity of the shell.
var/capacity = INFINITY

/// A list of components that cannot be removed
var/list/obj/item/circuit_component/unremovable_circuit_components

/datum/component/shell/Initialize(unremovable_circuit_components, capacity, shell_flags)
. = ..()
if(!ismovable(parent))
return COMPONENT_INCOMPATIBLE

src.shell_flags = shell_flags || src.shell_flags
src.capacity = capacity || src.capacity
src.unremovable_circuit_components = unremovable_circuit_components

for(var/obj/item/circuit_component/circuit_component as anything in unremovable_circuit_components)
circuit_component.removable = FALSE

/datum/component/shell/RegisterWithParent()
RegisterSignal(parent, COMSIG_PARENT_ATTACKBY, .proc/on_attack_by)
RegisterSignal(parent, COMSIG_PARENT_EXAMINE, .proc/on_examine)
RegisterSignal(parent, COMSIG_ATOM_ATTACK_GHOST, .proc/on_attack_ghost)
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)
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_DEFAULT_UNFASTEN_WRENCH,
COMSIG_PARENT_EXAMINE,
COMSIG_ATOM_ATTACK_GHOST
))

QDEL_NULL(attached_circuit)

/datum/component/shell/Destroy(force, silent)
QDEL_LIST(unremovable_circuit_components)
return ..()

/datum/component/shell/proc/on_attack_ghost(datum/source, mob/dead/observer/ghost)
SIGNAL_HANDLER
if(attached_circuit)
INVOKE_ASYNC(attached_circuit, /datum.proc/ui_interact, ghost)

/datum/component/shell/proc/on_examine(datum/source, mob/user, list/examine_text)
SIGNAL_HANDLER
if(!attached_circuit)
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>"
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>"


/**
* Called when the shell is wrenched.
*
* Only applies if the shell has SHELL_FLAG_REQUIRE_ANCHOR.
* Disables the integrated circuit if unanchored, otherwise enable the circuit.
*/
/datum/component/shell/proc/on_unfasten(atom/source, anchored)
SIGNAL_HANDLER
attached_circuit?.on = anchored
/**
* Called when an item hits the parent. This is the method to add the circuitboard to the component.
*/
/datum/component/shell/proc/on_attack_by(atom/source, obj/item/item, mob/living/attacker)
SIGNAL_HANDLER
if(istype(item, /obj/item/stock_parts/cell))
source.balloon_alert(attacker, "can't pull cell in directly!")
return

if(!istype(item, /obj/item/integrated_circuit))
return
var/obj/item/integrated_circuit/logic_board = item
. = COMPONENT_NO_AFTERATTACK

if(logic_board.shell) // I'll be surprised if this ever happens
return

if(attached_circuit)
source.balloon_alert(attacker, "there is already a circuitboard inside!")
return

if(length(logic_board.attached_components) > capacity)
source.balloon_alert(attacker, "this is too large to fit into [parent]!")
return

attach_circuit(logic_board, attacker)

/datum/component/shell/proc/on_multitool_act(atom/source, mob/user, obj/item/tool)
SIGNAL_HANDLER
if(!attached_circuit)
return

attached_circuit.interact(user)
return COMPONENT_BLOCK_TOOL_ATTACK

/**
* Called when a screwdriver is used on the parent. Removes the circuitboard from the component.
*/
/datum/component/shell/proc/on_screwdriver_act(atom/source, mob/user, obj/item/tool)
SIGNAL_HANDLER
if(!attached_circuit)
return

tool.play_tool_sound(parent)
source.balloon_alert(user, "You unscrew [attached_circuit] from [parent].")
remove_circuit()
return COMPONENT_BLOCK_TOOL_ATTACK

/**
* Checks for when the circuitboard moves. If it moves, removes it from the component.
*/
/datum/component/shell/proc/on_circuit_moved(obj/item/integrated_circuit/circuit, atom/new_loc)
SIGNAL_HANDLER
if(new_loc != parent)
remove_circuit()

/**
* Checks for when the circuitboard deletes so that it can be unassigned.
*/
/datum/component/shell/proc/on_circuit_delete(datum/source)
SIGNAL_HANDLER
remove_circuit()

/datum/component/shell/proc/on_circuit_add_component(datum/source, obj/item/circuit_component/added_comp)
SIGNAL_HANDLER
return COMPONENT_CANCEL_ADD_COMPONENT

/**
* Attaches a circuit to the parent. Doesn't do any checks to see for any existing circuits so that should be done beforehand.
*/
/datum/component/shell/proc/attach_circuit(obj/item/integrated_circuit/circuitboard, mob/living/user)
if(!user.transferItemToLoc(circuitboard, parent))
return
attached_circuit = circuitboard
RegisterSignal(circuitboard, COMSIG_MOVABLE_MOVED, .proc/on_circuit_moved)
RegisterSignal(circuitboard, COMSIG_PARENT_QDELETING, .proc/on_circuit_delete)
for(var/obj/item/circuit_component/to_add as anything in unremovable_circuit_components)
to_add.forceMove(attached_circuit)
attached_circuit.add_component(to_add)
RegisterSignal(circuitboard, COMSIG_CIRCUIT_ADD_COMPONENT, .proc/on_circuit_add_component)
attached_circuit.set_shell(parent)

if(shell_flags & SHELL_FLAG_REQUIRE_ANCHOR)
var/atom/movable/parent_atom = parent
on_unfasten(parent_atom, parent_atom.anchored)

/**
* Removes the circuit from the component. Doesn't do any checks to see for an existing circuit so that should be done beforehand.
*/
/datum/component/shell/proc/remove_circuit()
attached_circuit.on = TRUE
attached_circuit.remove_current_shell()
UnregisterSignal(attached_circuit, list(
COMSIG_MOVABLE_MOVED,
COMSIG_PARENT_QDELETING,
COMSIG_CIRCUIT_ADD_COMPONENT,
))
if(attached_circuit.loc == parent)
var/atom/parent_atom = parent
attached_circuit.forceMove(parent_atom.drop_location())

for(var/obj/item/circuit_component/to_remove as anything in unremovable_circuit_components)
attached_circuit.remove_component(to_remove)
to_remove.moveToNullspace()
attached_circuit = null
5 changes: 5 additions & 0 deletions code/modules/asset_cache/asset_list_items.dm
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,11 @@
"ntosradarpointerS.png" = 'icons/ui_icons/tgui/ntosradar_pointer_S.png'
)

/datum/asset/simple/circuit_assets
assets = list(
"grid_background.png" = 'icons/ui_icons/tgui/grid_background.png'
)

/datum/asset/spritesheet/simple/pda
name = "pda"
assets = list(
Expand Down
Loading

0 comments on commit b84a9f9

Please sign in to comment.