Integrated Circuit Overhaul 2.0 (#22647)

Complete overhaul of Integrated Circuits Final Edition!

- Adds phoron cost to circuits (not assemblies).
- Printer searching capability.
- Changed names of assemblies to better match their description.
- Adds cloning and auto appending JSON for large builds.
- Adds database, debug, advanced math circuits.
- Reworks the list circuits to finally accept anything other than NUM.
- Adds plenty of list circuits to allow functional building and clearing
of lists.
- Reworks Complexity/Space to allow a bit better flexibility in creation
of devices.
- Adds a "Headroom" concept where space/complexity can go beyond the
maximum to a very slight degree. Concretely, unused space gives `2`
extra complexity per unused component slot, capped at `15%` of
`max_complexity`. Unused complexity gives `1` extra component slot per
`6` unused complexity, capped at `15%` of `max_components`.
- Groups math and logic circuits and adds subgroups.
- Doesn't mess with the circuit tool kit.
- Adds a xenoarch drill assembly with a nice sprite. Thank you
@EnchantedCrocolisk for the sprite!
- Changes activation limit time to 1 second from 2 seconds, adds a 1
second timer that is unique to the INTEGRATED CIRCUIT PRINTER with the
advanced design disk.
- Ports several Baystation integrated-circuit manipulation components,
primarily from
Baystation12/Baystation12https://github.com/Baystation12/Baystation12/pull/22458,
with anchoring bolts and hatch lock sourced from
Baystation12/Baystation12https://github.com/Baystation12/Baystation12/pull/25052.
- Changes the electronic ear piece into a workable radio headset with
working encryption keys capability and unique ways the Microphone and
TTS interacts with it.
- Removed the ability for all the electronic wearables to spawn with a
basic cell.
- Combines https://github.com/Aurorastation/Aurora.3/pull/22466,
https://github.com/Aurorastation/Aurora.3/pull/22456,
https://github.com/Aurorastation/Aurora.3/pull/22455,
https://github.com/Aurorastation/Aurora.3/pull/22446 that are now
closed.
This commit is contained in:
mineymonkey
2026-07-26 19:52:31 +00:00
committed by GitHub
parent e7b3da61c6
commit 6c6f596d89
52 changed files with 10433 additions and 842 deletions
@@ -1,6 +1,11 @@
/*
* core/assemblies.dm
* Base electronic assembly behavior: circuit storage, open/closed handling, interaction, icon updates, cloning hooks, and wiring rules.
*/
/obj/item/electronic_assembly
name = "electronic assembly"
desc = "It's a case, for building small electronics with."
name = "small circuit case"
desc = "A case for building small electronic assemblies."
w_class = WEIGHT_CLASS_SMALL
icon = 'icons/obj/assemblies/electronic_setups.dmi'
icon_state = "setup_small"
@@ -9,25 +14,32 @@
var/max_components = IC_COMPONENTS_BASE
var/max_complexity = IC_COMPLEXITY_BASE
var/max_components_device = 16
var/max_complexity_device = 42
var/max_components_implant = 16
var/max_complexity_implant = 42
// Whether the assembly panel is open for direct circuit access.
var/opened = 0
var/can_anchor = FALSE // If true, wrenching it will anchor it.
var/obj/item/cell/device/battery // Internal cell which most circuits need to work.
// Power cell or battery object feeding the assembly.
var/obj/item/cell/battery // Internal cell which most circuits need to work.
// User-selected detail color used for assembly and wearable overlays.
var/detail_color = COLOR_ASSEMBLY_BLACK
var/obj/item/card/id/access_card
/obj/item/electronic_assembly/implant
name = "electronic implant"
icon_state = "setup_implant"
desc = "It's a case, for building very tiny electronics with."
desc = "A case for building very small electronic assemblies."
w_class = WEIGHT_CLASS_TINY
max_components = IC_COMPONENTS_BASE * 3/4
max_complexity = IC_COMPLEXITY_BASE * 3/4
max_components = /obj/item/electronic_assembly::max_components_implant
max_complexity = /obj/item/electronic_assembly::max_complexity_implant
var/obj/item/implant/integrated_circuit/implant = null
/obj/item/electronic_assembly/Initialize(mapload, printed = FALSE)
. = ..()
if (!printed)
battery = new(src)
battery = new /obj/item/cell/device(src)
START_PROCESSING(SSelectronics, src)
access_card = new /obj/item/card/id(src)
@@ -86,11 +98,13 @@
total_parts += part.size
total_complexity = total_complexity + part.complexity
var/list/HTML = list()
var/effective_component_limit = get_effective_component_limit(total_complexity)
var/effective_complexity_limit = get_effective_complexity_limit(total_parts)
HTML += "<br><a href='byond://?src=[REF(src)]'>Refresh</a> | "
HTML += "<a href='byond://?src=[REF(src)];rename=1'>Rename</a><br>"
HTML += "[total_parts]/[max_components] ([round((total_parts / max_components) * 100, 0.1)]%) space taken up in the assembly.<br>"
HTML += "[total_complexity]/[max_complexity] ([round((total_complexity / max_complexity) * 100, 0.1)]%) maximum complexity.<br>"
HTML += "[total_parts]/[max_components] space taken up in the assembly[effective_component_limit > max_components ? " ([effective_component_limit] with headroom)" : ""].<br>"
HTML += "[total_complexity]/[max_complexity] maximum complexity[effective_complexity_limit > max_complexity ? " ([effective_complexity_limit] with headroom)" : ""].<br>"
if(battery)
HTML += "[round(battery.charge, 0.1)]/[battery.maxcharge] ([round(battery.percent(), 0.1)]%) cell charge. <a href='byond://?src=[REF(src)];remove_cell=1'>Remove</a>"
else
@@ -150,7 +164,7 @@
/obj/item/electronic_assembly/verb/rename()
set name = "Rename Circuit"
set category = "Object"
set desc = "Rename your circuit, useful to stay organized."
set desc = "Renames the circuit to make assemblies easier to organize."
set src in usr
var/mob/M = usr
@@ -186,7 +200,7 @@
/obj/item/electronic_assembly/feedback_hints(mob/user, distance, is_adjacent)
. = ..()
if(opened && is_adjacent)
if(is_adjacent && opened)
for(var/obj/item/integrated_circuit/IC in contents)
. += SPAN_NOTICE("It contains \a [IC].")
@@ -200,6 +214,16 @@
for(var/obj/item/integrated_circuit/part in contents)
. += part.size
/obj/item/electronic_assembly/proc/get_effective_complexity_limit(total_part_size)
var/remaining_size = max(0, max_components - total_part_size)
var/overflow_limit = round(max_complexity * IC_OVERFLOW_LIMIT)
return max_complexity + min(remaining_size * IC_OVERFLOW_COMPONENT_TO_COMPLEXITY, overflow_limit)
/obj/item/electronic_assembly/proc/get_effective_component_limit(total_complexity)
var/remaining_complexity = max(0, max_complexity - total_complexity)
var/overflow_limit = round(max_components * IC_OVERFLOW_LIMIT)
return max_components + min(round(remaining_complexity / IC_OVERFLOW_COMPLEXITY_TO_COMPONENT), overflow_limit)
// Returns true if the circuit made it inside.
/obj/item/electronic_assembly/proc/add_circuit(obj/item/integrated_circuit/IC, mob/user)
if(!opened)
@@ -212,11 +236,13 @@
var/total_part_size = get_part_size()
var/total_complexity = get_part_complexity()
var/new_part_size = total_part_size + IC.size
var/new_complexity = total_complexity + IC.complexity
if((total_part_size + IC.size) > max_components)
if(new_part_size > get_effective_component_limit(new_complexity))
to_chat(user, SPAN_WARNING("You can't seem to add the '[IC.name]', as there's insufficient space."))
return FALSE
if((total_complexity + IC.complexity) > max_complexity)
if(new_complexity > get_effective_complexity_limit(new_part_size))
to_chat(user, SPAN_WARNING("You can't seem to add the '[IC.name]', since this setup's too complicated for the case."))
return FALSE
@@ -273,7 +299,7 @@
return TRUE
else if(istype(attacking_item, /obj/item/cell/device))
else if(istype(attacking_item, /obj/item/cell))
if(!opened)
to_chat(user, SPAN_WARNING("\The [src] isn't open, so you can't put anything inside. Try using a crowbar."))
for(var/obj/item/integrated_circuit/input/S in contents)
@@ -286,7 +312,7 @@
S.attackby_react(attacking_item,user,user.a_intent)
return FALSE
var/obj/item/cell/device/cell = attacking_item
var/obj/item/cell/cell = attacking_item
user.drop_from_inventory(cell,src)
battery = cell
playsound(get_turf(src), 'sound/items/Deconstruct.ogg', 50, 1)
@@ -313,6 +339,7 @@
return
if(opened)
interact(user)
return
var/list/input_selection = list()
var/list/available_inputs = list()
@@ -1,15 +1,28 @@
/*
* core/assemblies/clothing.dm
* Wearable electronic assemblies that can be embedded into clothing-style items and driven through item actions.
*/
// The base subtype for assemblies that can be worn. Certain pieces will have more or less capabilities
// E.g. Glasses have less room than something worn over the chest.
// Note that the electronic assembly is INSIDE the object that actually gets worn, in a similar way to implants.
/obj/item/electronic_assembly
var/max_components_clothing = 26
var/max_complexity_clothing = 68
/obj/item/electronic_assembly/clothing
name = "electronic clothing"
var/clothing_icon_state = "circuitry" // Needs to match the clothing's base icon_state.
desc = "It's a case, for building machines attached to clothing."
desc = "A clothing-mounted case for integrated electronics."
w_class = WEIGHT_CLASS_SMALL
max_components = IC_COMPONENTS_BASE
max_complexity = IC_COMPLEXITY_BASE
var/max_components_clothing_small = 14
var/max_complexity_clothing_small = 36
var/max_components_clothing_large = 42
var/max_complexity_clothing_large = 105
max_components = /obj/item/electronic_assembly::max_components_clothing
max_complexity = /obj/item/electronic_assembly::max_complexity_clothing
var/obj/item/clothing/clothing = null
/obj/item/electronic_assembly/clothing/ui_host()
@@ -22,23 +35,29 @@
return clothing
/obj/item/electronic_assembly/clothing/update_icon()
clothing.icon_state = "[initial(clothing.icon_state)][opened ? "-open" : ""]"
if(!clothing)
return
clothing.icon_state = opened ? "[initial(clothing.icon_state)]-open" : initial(clothing.icon_state)
clothing.ClearOverlays()
var/image/detail_overlay = image('icons/obj/assemblies/wearable_electronic_setups.dmi', "[initial(clothing.icon_state)][opened ? "-open" : ""]-color")
var/image/detail_overlay = image('icons/obj/assemblies/wearable_electronic_setups.dmi', "[clothing.icon_state]-color")
detail_overlay.color = detail_color
clothing.AddOverlays(detail_overlay)
clothing.update_clothing_icon()
if(hascall(clothing, "update_clothing_icon"))
call(clothing, "update_clothing_icon")()
// This is 'small' relative to the size of regular clothing assemblies.
/obj/item/electronic_assembly/clothing/small
max_components = IC_COMPONENTS_BASE / 2
max_complexity = IC_COMPLEXITY_BASE / 2
max_components = /obj/item/electronic_assembly/clothing::max_components_clothing_small
max_complexity = /obj/item/electronic_assembly/clothing::max_complexity_clothing_small
w_class = WEIGHT_CLASS_TINY
// Ditto.
/obj/item/electronic_assembly/clothing/large
max_components = IC_COMPONENTS_BASE * 2
max_complexity = IC_COMPLEXITY_BASE * 2
max_components = /obj/item/electronic_assembly/clothing::max_components_clothing_large
max_complexity = /obj/item/electronic_assembly/clothing::max_complexity_clothing_large
w_class = WEIGHT_CLASS_NORMAL
/obj/item/electronic_assembly/clothing/rename()
@@ -63,9 +82,9 @@
..()
// Does most of the repeatative setup.
/obj/item/clothing/proc/setup_integrated_circuit(new_type)
/obj/item/clothing/proc/setup_integrated_circuit(new_type, printed = FALSE)
// Set up the internal circuit holder.
IC = new new_type(src)
IC = new new_type(src, printed)
IC.clothing = src
IC.name = name
@@ -83,22 +102,22 @@
// Jumpsuit.
/obj/item/clothing/under/circuitry
name = "electronic jumpsuit"
desc = "It's a wearable case for electronics. This one is a black jumpsuit with wiring weaved into the fabric."
desc = "A wearable case for integrated electronics. This one is a black jumpsuit with wiring weaved into the fabric."
icon = 'icons/obj/assemblies/wearable_electronic_setups.dmi'
contained_sprite = TRUE
icon_state = "jumpsuit"
item_state = "jumpsuit"
worn_state = "jumpsuit"
/obj/item/clothing/under/circuitry/Initialize()
setup_integrated_circuit(/obj/item/electronic_assembly/clothing)
/obj/item/clothing/under/circuitry/Initialize(mapload, printed = FALSE)
setup_integrated_circuit(/obj/item/electronic_assembly/clothing, printed)
return ..()
/obj/item/clothing/under/circuitry/build_additional_parts(mob/living/carbon/human/H, mob_icon, slot)
var/static/list/valid_slots
if(!valid_slots)
valid_slots = list(slot_w_uniform_str)
if(IC.detail_color && (slot in valid_slots))
if(IC?.detail_color && (slot in valid_slots))
var/image/electronic_overlay = overlay_image(icon, "[item_state][slot_str_to_contained_flag(slot)]-color", IC.detail_color, RESET_COLOR)
return electronic_overlay
return ..()
@@ -106,22 +125,22 @@
// Gloves.
/obj/item/clothing/gloves/circuitry
name = "electronic gloves"
desc = "It's a wearable case for electronics. This one is a pair of black gloves, with wires woven into them. A small \
desc = "A wearable case for integrated electronics. This one is a pair of black gloves, with wires woven into them. A small \
device with a screen is attached to the left glove."
icon = 'icons/obj/assemblies/wearable_electronic_setups.dmi'
contained_sprite = TRUE
icon_state = "gloves"
item_state = "gloves"
/obj/item/clothing/gloves/circuitry/Initialize()
setup_integrated_circuit(/obj/item/electronic_assembly/clothing/small)
/obj/item/clothing/gloves/circuitry/Initialize(mapload, printed = FALSE)
setup_integrated_circuit(/obj/item/electronic_assembly/clothing/small, printed)
return ..()
/obj/item/clothing/gloves/circuitry/build_additional_parts(mob/living/carbon/human/H, mob_icon, slot)
var/static/list/valid_slots
if(!valid_slots)
valid_slots = list(slot_gloves_str)
if(IC.detail_color && (slot in valid_slots))
if(IC?.detail_color && (slot in valid_slots))
var/image/electronic_overlay = overlay_image(icon, "[item_state][slot_str_to_contained_flag(slot)]-color", IC.detail_color, RESET_COLOR)
return electronic_overlay
return ..()
@@ -139,22 +158,22 @@
// Glasses.
/obj/item/clothing/glasses/circuitry
name = "electronic goggles"
desc = "It's a wearable case for electronics. This one is a pair of goggles, with wiring sticking out. \
desc = "A wearable case for integrated electronics. This one is a pair of goggles, with wiring sticking out. \
Could this augment your vision?" // Sadly it won't, or at least not yet.
icon = 'icons/obj/assemblies/wearable_electronic_setups.dmi'
contained_sprite = TRUE
icon_state = "goggles"
item_state = "goggles"
/obj/item/clothing/glasses/circuitry/Initialize()
setup_integrated_circuit(/obj/item/electronic_assembly/clothing/small)
/obj/item/clothing/glasses/circuitry/Initialize(mapload, printed = FALSE)
setup_integrated_circuit(/obj/item/electronic_assembly/clothing/small, printed)
return ..()
/obj/item/clothing/glasses/circuitry/build_additional_parts(mob/living/carbon/human/H, mob_icon, slot)
var/static/list/valid_slots
if(!valid_slots)
valid_slots = list(slot_glasses_str, slot_l_hand_str, slot_r_hand_str)
if(IC.detail_color && (slot in valid_slots))
if(IC?.detail_color && (slot in valid_slots))
var/image/electronic_overlay = overlay_image(icon, "[item_state][slot_str_to_contained_flag(slot)]-color", IC.detail_color, RESET_COLOR)
return electronic_overlay
return ..()
@@ -177,22 +196,22 @@
// Shoes
/obj/item/clothing/shoes/circuitry
name = "electronic boots"
desc = "It's a wearable case for electronics. This one is a pair of boots, with wires attached to a small \
desc = "A wearable case for integrated electronics. This one is a pair of boots, with wires attached to a small \
cover."
icon = 'icons/obj/assemblies/wearable_electronic_setups.dmi'
contained_sprite = TRUE
icon_state = "shoes"
item_state = "shoes"
/obj/item/clothing/shoes/circuitry/Initialize()
setup_integrated_circuit(/obj/item/electronic_assembly/clothing/small)
/obj/item/clothing/shoes/circuitry/Initialize(mapload, printed = FALSE)
setup_integrated_circuit(/obj/item/electronic_assembly/clothing/small, printed)
return ..()
/obj/item/clothing/shoes/circuitry/build_additional_parts(mob/living/carbon/human/H, mob_icon, slot)
var/static/list/valid_slots
if(!valid_slots)
valid_slots = list(slot_shoes_str)
if(IC.detail_color && (slot in valid_slots))
if(IC?.detail_color && (slot in valid_slots))
var/image/electronic_overlay = overlay_image(icon, "[item_state][slot_str_to_contained_flag(slot)]-color", IC.detail_color, RESET_COLOR)
return electronic_overlay
return ..()
@@ -200,44 +219,44 @@
// Head
/obj/item/clothing/head/circuitry
name = "electronic headwear"
desc = "It's a wearable case for electronics. This one appears to be a very technical-looking piece that \
desc = "A wearable case for integrated electronics. This one appears to be a very technical-looking piece that \
goes around the collar, with a heads-up-display attached on the right."
icon = 'icons/obj/assemblies/wearable_electronic_setups.dmi'
contained_sprite = TRUE
icon_state = "head"
item_state = "head"
/obj/item/clothing/head/circuitry/Initialize()
setup_integrated_circuit(/obj/item/electronic_assembly/clothing/small)
/obj/item/clothing/head/circuitry/Initialize(mapload, printed = FALSE)
setup_integrated_circuit(/obj/item/electronic_assembly/clothing/small, printed)
return ..()
/obj/item/clothing/head/circuitry/build_additional_parts(mob/living/carbon/human/H, mob_icon, slot)
var/static/list/valid_slots
if(!valid_slots)
valid_slots = list(slot_head_str)
if(IC.detail_color && (slot in valid_slots))
if(IC?.detail_color && (slot in valid_slots))
var/image/electronic_overlay = overlay_image(icon, "[item_state][slot_str_to_contained_flag(slot)]-color", IC.detail_color, RESET_COLOR)
return electronic_overlay
return ..()
// Ear
// Ears
/obj/item/clothing/ears/circuitry
name = "electronic earwear"
desc = "It's a wearable case for electronics. This one appears to be a technical-looking headset."
desc = "A wearable case for integrated electronics. This one appears to be a technical-looking headset."
icon = 'icons/obj/assemblies/wearable_electronic_setups.dmi'
contained_sprite = TRUE
icon_state = "headset"
item_state = "headset"
/obj/item/clothing/ears/circuitry/Initialize()
setup_integrated_circuit(/obj/item/electronic_assembly/clothing/small)
/obj/item/clothing/ears/circuitry/Initialize(mapload, printed = FALSE)
setup_integrated_circuit(/obj/item/electronic_assembly/clothing/small, printed)
return ..()
/obj/item/clothing/ears/circuitry/build_additional_parts(mob/living/carbon/human/H, mob_icon, slot)
var/static/list/valid_slots
if(!valid_slots)
valid_slots = list(slot_l_ear_str, slot_r_ear_str)
if(IC.detail_color && (slot in valid_slots))
if(IC?.detail_color && (slot in valid_slots))
var/image/electronic_overlay = overlay_image(icon, "[item_state][slot_str_to_contained_flag(slot)]-color", IC.detail_color, RESET_COLOR)
return electronic_overlay
return ..()
@@ -245,22 +264,22 @@
// Exo-slot
/obj/item/clothing/suit/circuitry
name = "electronic chestpiece"
desc = "It's a wearable case for electronics. This one appears to be a very technical-looking vest, that \
desc = "A wearable case for integrated electronics. This one appears to be a very technical-looking vest, that \
almost looks professionally made, however the wiring popping out betrays that idea."
icon = 'icons/obj/assemblies/wearable_electronic_setups.dmi'
contained_sprite = TRUE
icon_state = "chest"
item_state = "chest"
/obj/item/clothing/suit/circuitry/Initialize()
setup_integrated_circuit(/obj/item/electronic_assembly/clothing/large)
/obj/item/clothing/suit/circuitry/Initialize(mapload, printed = FALSE)
setup_integrated_circuit(/obj/item/electronic_assembly/clothing/large, printed)
return ..()
/obj/item/clothing/suit/circuitry/build_additional_parts(mob/living/carbon/human/H, mob_icon, slot)
var/static/list/valid_slots
if(!valid_slots)
valid_slots = list(slot_wear_suit_str)
if(IC.detail_color && (slot in valid_slots))
if(IC?.detail_color && (slot in valid_slots))
var/image/electronic_overlay = overlay_image(icon, "[item_state][slot_str_to_contained_flag(slot)]-color", IC.detail_color, RESET_COLOR)
return electronic_overlay
return ..()
@@ -0,0 +1,261 @@
/obj/item/radio/headset/circuitry
name = "electronic radio headset"
desc = "A radio headset modified to accept integrated circuitry. Takes encryption keys."
icon = 'icons/obj/assemblies/wearable_electronic_setups.dmi'
contained_sprite = TRUE
icon_state = "headset"
item_state = "headset"
slot_flags = SLOT_EARS
ks1type = null
ks2type = null
// Internal assembly that stores the actual circuits installed inside the host item.
var/obj/item/electronic_assembly/clothing/small/circuit_assembly = null
// Built-in action circuit used to expose an activation button to the wearer/user.
var/obj/item/integrated_circuit/built_in/action_button/circuit_action = null
/obj/item/radio/headset/circuitry/Initialize(mapload, printed = FALSE)
. = ..()
setup_headset_integrated_circuit()
refresh_headset_sprite()
refresh_radio_state()
/obj/item/radio/headset/circuitry/Destroy()
QDEL_NULL(circuit_assembly)
circuit_action = null
return ..()
/obj/item/radio/headset/circuitry/proc/setup_headset_integrated_circuit()
if(circuit_assembly)
circuit_assembly.forceMove(src)
circuit_assembly.clothing = src
circuit_assembly.name = name
else
circuit_assembly = new /obj/item/electronic_assembly/clothing/small(src, TRUE)
circuit_assembly.clothing = src
circuit_assembly.name = name
QDEL_NULL(circuit_assembly.battery)
for(var/obj/item/integrated_circuit/C in circuit_assembly.contents)
C.assembly = circuit_assembly
circuit_action = locate(/obj/item/integrated_circuit/built_in/action_button) in circuit_assembly.contents
if(!circuit_action)
circuit_action = new(circuit_assembly)
circuit_assembly.force_add_circuit(circuit_action)
default_action_type = /datum/action/item_action/integrated_circuit
action_button_name = "Activate [capitalize_first_letters(name)]"
/obj/item/radio/headset/circuitry/proc/get_cloneable_assembly()
return circuit_assembly
/obj/item/radio/headset/circuitry/proc/get_clone_host_type()
return type
/obj/item/radio/headset/circuitry/feedback_hints(mob/user, distance, is_adjacent)
. = ..()
if(distance <= 1 && !circuit_assembly?.opened)
return
var/obj/item/electronic_assembly/E = get_cloneable_assembly()
if(E)
for(var/obj/item/integrated_circuit/IC in E.contents)
. += SPAN_NOTICE("It contains \a [IC].")
/obj/item/radio/headset/circuitry/proc/clone_with_integrated_assembly(atom/location, obj/item/integrated_circuit_printer/printer, obj/item/electronic_assembly/source_assembly)
if(!location || !printer || !source_assembly)
return null
var/obj/item/radio/headset/circuitry/new_headset = new type(location)
if(!new_headset || !new_headset.circuit_assembly)
if(new_headset)
qdel(new_headset)
return null
var/obj/item/electronic_assembly/clothing/small/internal_assembly = new_headset.circuit_assembly
if(!printer.copy_assembly_into_existing(source_assembly, internal_assembly))
qdel(new_headset)
return null
internal_assembly.forceMove(new_headset)
internal_assembly.clothing = new_headset
internal_assembly.name = source_assembly.name
internal_assembly.detail_color = source_assembly.detail_color
internal_assembly.opened = FALSE
internal_assembly.battery = null
for(var/obj/item/integrated_circuit/C in internal_assembly.contents)
C.assembly = internal_assembly
new_headset.name = source_assembly.name
new_headset.circuit_assembly = internal_assembly
new_headset.circuit_action = locate(/obj/item/integrated_circuit/built_in/action_button) in internal_assembly.contents
if(!new_headset.circuit_action)
new_headset.circuit_action = new(internal_assembly)
internal_assembly.force_add_circuit(new_headset.circuit_action)
new_headset.default_action_type = /datum/action/item_action/integrated_circuit
new_headset.action_button_name = "Activate [capitalize_first_letters(new_headset.name)]"
new_headset.refresh_headset_sprite()
new_headset.refresh_radio_state()
return new_headset
/obj/item/radio/headset/circuitry/proc/refresh_radio_state()
on = TRUE
set_frequency(PUB_FREQ)
set_listening(TRUE)
recalculateChannels(TRUE)
if(ismob(loc))
possibly_deactivate_in_loc()
/obj/item/radio/headset/circuitry/proc/refresh_headset_sprite()
icon = 'icons/obj/assemblies/wearable_electronic_setups.dmi'
contained_sprite = TRUE
icon_state = circuit_assembly?.opened ? "headset-open" : "headset"
item_state = "headset"
ClearOverlays()
if(circuit_assembly?.detail_color)
var/image/detail_overlay = image('icons/obj/assemblies/wearable_electronic_setups.dmi', "[icon_state]-color")
detail_overlay.color = circuit_assembly.detail_color
AddOverlays(detail_overlay)
if(hascall(src, "update_clothing_icon"))
call(src, "update_clothing_icon")()
/obj/item/radio/headset/circuitry/attack_self(mob/user)
return ..()
/obj/item/radio/headset/circuitry/attackby(obj/item/attacking_item, mob/user)
if(istype(attacking_item, /obj/item/integrated_circuit_printer))
var/obj/item/integrated_circuit_printer/P = attacking_item
if(P.scan_cloneable_item(src, user))
return TRUE
if(attacking_item.tool_behaviour == TOOL_CROWBAR && circuit_assembly)
circuit_assembly.attackby(attacking_item, user)
refresh_headset_sprite()
refresh_radio_state()
return TRUE
if(istype(attacking_item, /obj/item/encryptionkey))
. = ..()
refresh_radio_state()
return
if(circuit_assembly?.opened)
circuit_assembly.attackby(attacking_item, user)
refresh_headset_sprite()
return TRUE
return ..()
/obj/item/radio/headset/circuitry/AltClick(mob/user)
if(!circuit_assembly)
return ..()
if(!circuit_assembly.opened)
to_chat(user, SPAN_WARNING("The circuit panel is closed."))
return
return circuit_assembly.attack_self(user)
/obj/item/radio/headset/circuitry/verb/access_integrated_circuit()
set category = "Object.Equipped"
set name = "Access Integrated Circuit"
set src in usr
if(!circuit_assembly)
return
if(!circuit_assembly.opened)
to_chat(usr, SPAN_WARNING("The circuit panel is closed."))
return
circuit_assembly.attack_self(usr)
/obj/item/radio/headset/circuitry/equipped(mob/user, slot)
. = ..()
if(slot == slot_l_ear || slot == slot_r_ear || slot == slot_l_ear_str || slot == slot_r_ear_str)
refresh_radio_state()
refresh_headset_sprite()
/obj/item/radio/headset/circuitry/dropped(mob/user)
. = ..()
set_listening(FALSE, actual_setting = FALSE)
/obj/item/radio/headset/circuitry/Moved(atom/old_loc, forced)
. = ..()
possibly_deactivate_in_loc()
/obj/item/radio/headset/circuitry/build_additional_parts(mob/living/carbon/human/H, mob_icon, slot)
var/static/list/valid_slots
if(!valid_slots)
valid_slots = list(slot_l_ear_str, slot_r_ear_str)
if(circuit_assembly?.detail_color && (slot in valid_slots))
var/image/electronic_overlay = overlay_image(icon, "[item_state][slot_str_to_contained_flag(slot)]-color", circuit_assembly.detail_color, RESET_COLOR)
return electronic_overlay
return ..()
/obj/item/radio/headset/circuitry/proc/get_wearer()
if(!ishuman(loc))
return null
var/mob/living/carbon/human/H = loc
if(H.l_ear == src)
return H
if(H.r_ear == src)
return H
return null
/obj/item/radio/headset/circuitry/proc/private_output(message)
var/mob/living/carbon/human/H = get_wearer()
if(!H)
return
to_chat(H, SPAN_NOTICE("[message]"))
/obj/item/radio/headset/circuitry/proc/private_tts_output(message)
var/mob/living/carbon/human/H = get_wearer()
if(!H)
return
to_chat(H, SPAN_NOTICE("\The [src] states, \"[message]\""))
@@ -1,213 +1,311 @@
/*
* core/assemblies/generic.dm
* Generic handheld, large, wall-mounted, and specialty electronic assembly variants.
*/
// Generic subtypes without a lot of special code.
// Anchored pickup protection.
// This prevents anchored electronic assemblies from being picked up like normal items.
// Anchored assemblies still pass ordinary hand interaction through attack_self(), so closed
// assemblies expose their external inputs and opened assemblies expose the circuit UI.
/obj/item/electronic_assembly
var/supports_builtin_powernet = FALSE
var/supports_builtin_locomotion = FALSE
var/max_components_tiny_assembly = 12
var/max_complexity_tiny_assembly = 30
var/max_components_medium_assembly = 55
var/max_complexity_medium_assembly = 140
var/max_components_large_assembly = 110
var/max_complexity_large_assembly = 240
var/max_components_drone = 38
var/max_complexity_drone = 95
var/max_components_wallmount = 55
var/max_complexity_wallmount = 140
/obj/item/electronic_assembly/attack_hand(mob/user)
if(anchored)
if(!check_interactivity(user))
return TRUE
attack_self(user)
return TRUE
return ..()
/obj/item/electronic_assembly/mob_can_equip(mob/user, slot, disable_warning = FALSE, bypass_blocked_check = FALSE, is_overlay_check = FALSE)
if(anchored)
if(!disable_warning)
to_chat(user, SPAN_WARNING("\The [src] is anchored in place."))
return FALSE
return ..(user, slot, disable_warning, bypass_blocked_check, is_overlay_check)
// Small assemblies.
/obj/item/electronic_assembly/default
name = "type-a electronic assembly"
name = "basic small circuit case"
/obj/item/electronic_assembly/calc
name = "type-b electronic assembly"
name = "calculator small circuit case"
icon_state = "setup_small_calc"
desc = "It's a case, for building small electronics with. This one resembles a pocket calculator."
desc = "A case for building small electronic assemblies. This one resembles a pocket calculator."
/obj/item/electronic_assembly/clam
name = "type-c electronic assembly"
name = "clamshell small circuit case"
icon_state = "setup_small_clam"
desc = "It's a case, for building small electronics with. This one has a clamshell design."
desc = "A case for building small electronic assemblies. This one has a clamshell design."
/obj/item/electronic_assembly/simple
name = "type-d electronic assembly"
name = "compact small circuit case"
icon_state = "setup_small_simple"
desc = "It's a case, for building small electronics with. This one has a simple design."
desc = "A case for building small electronic assemblies. This one has a simple design."
/obj/item/electronic_assembly/hook
name = "type-e electronic assembly"
name = "belt-clip small circuit case"
icon_state = "setup_small_hook"
desc = "It's a case, for building small electronics with. This one looks like it has a belt clip, but it's purely decorative."
desc = "A case for building small electronic assemblies. This one looks like it has a belt clip, but it's purely decorative."
/obj/item/electronic_assembly/pda
name = "type-f electronic assembly"
name = "PDA-style small circuit case"
icon_state = "setup_small_pda"
desc = "It's a case, for building small electronics with. This one resembles a PDA."
desc = "A case for building small electronic assemblies. This one resembles a PDA."
// Tiny assemblies.
/obj/item/electronic_assembly/tiny
name = "electronic device"
name = "tiny circuit case"
icon_state = "setup_device"
desc = "It's a case, for building tiny-sized electronics with."
desc = "A case for building tiny electronic assemblies."
w_class = WEIGHT_CLASS_TINY
max_components = IC_COMPONENTS_BASE / 2
max_complexity = IC_COMPLEXITY_BASE / 2
max_components = /obj/item/electronic_assembly::max_components_tiny_assembly
max_complexity = /obj/item/electronic_assembly::max_complexity_tiny_assembly
/obj/item/electronic_assembly/tiny/default
name = "type-a electronic device"
name = "basic tiny circuit case"
/obj/item/electronic_assembly/tiny/cylinder
name = "type-b electronic device"
name = "cylindrical tiny circuit case"
icon_state = "setup_device_cylinder"
desc = "It's a case, for building tiny-sized electronics with. This one has a cylindrical design."
desc = "A case for building tiny electronic assemblies. This one has a cylindrical design."
/obj/item/electronic_assembly/tiny/scanner
name = "type-c electronic device"
name = "scanner tiny circuit case"
icon_state = "setup_device_scanner"
desc = "It's a case, for building tiny-sized electronics with. This one has a scanner-like design."
desc = "A case for building tiny electronic assemblies. This one has a scanner-like design."
/obj/item/electronic_assembly/tiny/hook
name = "type-d electronic device"
name = "belt-clip tiny circuit case"
icon_state = "setup_device_hook"
desc = "It's a case, for building tiny-sized electronics with. This one looks like it has a belt clip, but it's purely decorative."
desc = "A case for building tiny electronic assemblies. This one looks like it has a belt clip, but it's purely decorative."
/obj/item/electronic_assembly/tiny/box
name = "type-e electronic device"
name = "boxy tiny circuit case"
icon_state = "setup_device_box"
desc = "It's a case, for building tiny-sized electronics with. This one has a boxy design."
desc = "A case for building tiny electronic assemblies. This one has a boxy design."
// Medium assemblies.
/obj/item/electronic_assembly/medium
name = "electronic mechanism"
name = "medium circuit case"
icon_state = "setup_medium"
desc = "It's a case, for building medium-sized electronics with."
desc = "A case for building medium electronic assemblies."
w_class = WEIGHT_CLASS_NORMAL
max_components = IC_COMPONENTS_BASE * 2
max_complexity = IC_COMPLEXITY_BASE * 2
var/max_components_anomaly_drill = 30
var/max_complexity_anomaly_drill = 80
max_components = /obj/item/electronic_assembly::max_components_medium_assembly
max_complexity = /obj/item/electronic_assembly::max_complexity_medium_assembly
/obj/item/electronic_assembly/medium/default
name = "type-a electronic mechanism"
name = "basic medium circuit case"
/obj/item/electronic_assembly/medium/box
name = "type-b electronic mechanism"
name = "boxy medium circuit case"
icon_state = "setup_medium_box"
desc = "It's a case, for building medium-sized electronics with. This one has a boxy design."
desc = "A case for building medium electronic assemblies. This one has a boxy design."
/obj/item/electronic_assembly/medium/clam
name = "type-c electronic mechanism"
name = "clamshell medium circuit case"
icon_state = "setup_medium_clam"
desc = "It's a case, for building medium-sized electronics with. This one has a clamshell design."
desc = "A case for building medium electronic assemblies. This one has a clamshell design."
/obj/item/electronic_assembly/medium/medical
name = "type-d electronic mechanism"
name = "medical medium circuit case"
icon_state = "setup_medium_med"
desc = "It's a case, for building medium-sized electronics with. This one resembles some type of medical apparatus."
desc = "A case for building medium electronic assemblies. This one resembles some type of medical apparatus."
/obj/item/electronic_assembly/medium/gun
name = "type-e electronic mechanism"
name = "tool-shaped medium circuit case"
icon_state = "setup_medium_gun"
item_state = "circuitgun"
desc = "It's a case, for building medium-sized electronics with. This one resembles a gun, or some type of tool, \
desc = "A case for building medium electronic assemblies. This one resembles a gun, or some type of tool, \
if you're feeling optimistic."
/obj/item/electronic_assembly/medium/radio
name = "type-f electronic mechanism"
name = "radio medium circuit case"
icon_state = "setup_medium_radio"
desc = "It's a case, for building medium-sized electronics with. This one resembles an old radio."
desc = "A case for building medium electronic assemblies. This one resembles an old radio."
/obj/item/electronic_assembly/medium/anomaly_drill
name = "anomaly drill assembly"
desc = "A prebuilt electronic assembly designed to drill toward anomaly sensor coordinates."
icon_state = "setup_medium_drill"
w_class = WEIGHT_CLASS_NORMAL
max_components = /obj/item/electronic_assembly/medium::max_components_anomaly_drill
max_complexity = /obj/item/electronic_assembly/medium::max_complexity_anomaly_drill
can_anchor = FALSE
/obj/item/electronic_assembly/medium/anomaly_drill/Initialize(mapload, printed = FALSE)
. = ..()
var/obj/item/integrated_circuit/manipulation/xenoarch_precision_excavator/drill_controller = new(src)
drill_controller.removable = FALSE
drill_controller.assembly = src
force_add_circuit(drill_controller)
// Large assemblies.
// These get a built-in, non-removable power network interface.
/obj/item/electronic_assembly/large
name = "electronic machine"
name = "large circuit machine"
icon_state = "setup_large"
desc = "It's a case, for building large electronics with."
desc = "A case for building large electronic assemblies."
w_class = WEIGHT_CLASS_BULKY
max_components = IC_COMPONENTS_BASE * 4
max_complexity = IC_COMPLEXITY_BASE * 4
max_components = /obj/item/electronic_assembly::max_components_large_assembly
max_complexity = /obj/item/electronic_assembly::max_complexity_large_assembly
can_anchor = TRUE
supports_builtin_powernet = TRUE
/obj/item/electronic_assembly/large/Initialize(mapload, printed = FALSE)
. = ..()
add_builtin_powernet()
/obj/item/electronic_assembly/large/default
name = "type-a electronic machine"
name = "basic large circuit machine"
/obj/item/electronic_assembly/large/scope
name = "type-b electronic machine"
name = "oscilloscope large circuit machine"
icon_state = "setup_large_scope"
desc = "It's a case, for building large electronics with. This one resembles an oscilloscope."
desc = "A case for building large electronic assemblies. This one resembles an oscilloscope."
/obj/item/electronic_assembly/large/terminal
name = "type-c electronic machine"
name = "terminal large circuit machine"
icon_state = "setup_large_terminal"
desc = "It's a case, for building large electronics with. This one resembles a computer terminal."
desc = "A case for building large electronic assemblies. This one resembles a computer terminal."
/obj/item/electronic_assembly/large/arm
name = "type-d electronic machine"
name = "robotic arm large circuit machine"
icon_state = "setup_large_arm"
desc = "It's a case, for building large electronics with. This one resembles a robotic arm."
desc = "A case for building large electronic assemblies. This one resembles a robotic arm."
/obj/item/electronic_assembly/large/tall
name = "type-e electronic machine"
name = "tall large circuit machine"
icon_state = "setup_large_tall"
desc = "It's a case, for building large electronics with. This one has a tall design."
desc = "A case for building large electronic assemblies. This one has a tall design."
/obj/item/electronic_assembly/large/industrial
name = "type-f electronic machine"
name = "industrial large circuit machine"
icon_state = "setup_large_industrial"
desc = "It's a case, for building large electronics with. This one resembles some kind of industrial machinery."
desc = "A case for building large electronic assemblies. This one resembles some kind of industrial machinery."
// Drone assemblies, which can move with the locomotion circuit.
/obj/item/electronic_assembly/drone
name = "electronic drone"
name = "circuit drone"
icon_state = "setup_drone"
desc = "It's a case, for building mobile electronics with."
desc = "A mobile case for building electronic assemblies."
w_class = WEIGHT_CLASS_NORMAL
max_components = IC_COMPONENTS_BASE * 1.5
max_complexity = IC_COMPLEXITY_BASE * 1.5
max_components = /obj/item/electronic_assembly::max_components_drone
max_complexity = /obj/item/electronic_assembly::max_complexity_drone
can_anchor = FALSE
supports_builtin_locomotion = TRUE
/obj/item/electronic_assembly/drone/Initialize(mapload, printed = FALSE)
. = ..()
add_builtin_locomotion()
/obj/item/electronic_assembly/drone/can_move()
return TRUE
/obj/item/electronic_assembly/drone/default
name = "type-a electronic drone"
name = "basic circuit drone"
/obj/item/electronic_assembly/drone/arms
name = "type-b electronic drone"
name = "armed circuit drone"
icon_state = "setup_drone_arms"
desc = "It's a case, for building mobile electronics with. This one is armed and dangerous."
desc = "A mobile case for building weapon-capable electronic assemblies."
/obj/item/electronic_assembly/drone/medbot
name = "type-d electronic drone"
name = "medical circuit drone"
icon_state = "setup_drone_medbot"
desc = "It's a case, for building mobile electronics with. This one resembles a Medibot."
desc = "A mobile case for building electronic assemblies. This one resembles a Medibot."
/obj/item/electronic_assembly/drone/genbot
name = "type-e electronic drone"
name = "utility circuit drone"
icon_state = "setup_drone_genbot"
desc = "It's a case, for building mobile electronics with. This one has a generic bot design."
desc = "A mobile case for building electronic assemblies. This one has a generic bot design."
/obj/item/electronic_assembly/drone/android
name = "type-f electronic drone"
name = "android circuit drone"
icon_state = "setup_drone_android"
desc = "It's a case, for building mobile electronics with. This one has a hominoid design."
desc = "A mobile case for building electronic assemblies. This one has a hominoid design."
// Wall mounted assemblies.
// These get a built-in, non-removable power network interface.
/obj/item/electronic_assembly/wallmount
name = "wall-mounted electronic assembly"
name = "medium wall-mounted circuit case"
icon_state = "setup_wallmount_medium"
desc = "It's a case, for building medium-sized electronics with. It has a magnetized \
desc = "A case for building medium electronic assemblies. It has a magnetized \
backing to allow it to stick to walls."
w_class = WEIGHT_CLASS_NORMAL
max_components = IC_COMPONENTS_BASE * 2
max_complexity = IC_COMPLEXITY_BASE * 2
var/max_components_wallmount_heavy = 110
var/max_complexity_wallmount_heavy = 240
var/max_components_wallmount_light = IC_COMPONENTS_BASE
var/max_complexity_wallmount_light = IC_COMPLEXITY_BASE
var/max_components_wallmount_tiny = 12
var/max_complexity_wallmount_tiny = 30
max_components = /obj/item/electronic_assembly::max_components_wallmount
max_complexity = /obj/item/electronic_assembly::max_complexity_wallmount
can_anchor = TRUE
supports_builtin_powernet = TRUE
/obj/item/electronic_assembly/wallmount/Initialize(mapload, printed = FALSE)
. = ..()
add_builtin_powernet()
/obj/item/electronic_assembly/wallmount/proc/mount_assembly(turf/on_wall, mob/user)
if(get_dist(on_wall,user) > 1)
if(get_dist(on_wall, user) > 1)
return
var/ndir = get_dir(on_wall, user)
if(!(ndir in GLOB.cardinals))
return
var/turf/T = get_turf(user)
if(!istype(T, /turf/simulated/floor))
to_chat(user, SPAN_WARNING("You cannot place \the [src] on this spot!"))
return
playsound(src.loc, 'sound/machines/click.ogg', 75, 1)
user.visible_message("\The [user] attaches \the [src] to the wall.",
user.visible_message(
"\The [user] attaches \the [src] to the wall.",
SPAN_NOTICE("You attach \the [src] to the wall."),
"<span class='italics'>You hear clicking.</span>")
if(isrobot(user)) //Robots cannot unequip/drop items, for Safety Reasons.
"<span class='italics'>You hear clicking.</span>"
)
if(isrobot(user)) // Robots cannot unequip/drop items, for safety reasons.
forceMove(T)
user.drop_item(T)
else
user.drop_item(T)
anchored = TRUE
on_anchored()
set_pixel_offsets()
@@ -222,31 +320,58 @@
pixel_y = DIR2PIXEL_Y(dir)
/obj/item/electronic_assembly/wallmount/heavy
name = "heavy wall-mounted electronic assembly"
name = "large wall-mounted circuit machine"
icon_state = "setup_wallmount_large"
desc = "It's a case, for building large electronics with. It has a magnetized backing \
desc = "A case for building large electronic assemblies. It has a magnetized backing \
to allow it to stick to walls."
w_class = WEIGHT_CLASS_BULKY
max_components = IC_COMPONENTS_BASE * 4
max_complexity = IC_COMPLEXITY_BASE * 4
max_components = /obj/item/electronic_assembly/wallmount::max_components_wallmount_heavy
max_complexity = /obj/item/electronic_assembly/wallmount::max_complexity_wallmount_heavy
/obj/item/electronic_assembly/wallmount/light
name = "light wall-mounted electronic assembly"
name = "small wall-mounted circuit case"
icon_state = "setup_wallmount_small"
desc = "It's a case, for building small electronics with. It has a magnetized backing \
desc = "A case for building small electronic assemblies. It has a magnetized backing \
to allow it to stick to walls."
w_class = WEIGHT_CLASS_SMALL
max_components = IC_COMPONENTS_BASE
max_complexity = IC_COMPLEXITY_BASE
max_components = /obj/item/electronic_assembly/wallmount::max_components_wallmount_light
max_complexity = /obj/item/electronic_assembly/wallmount::max_complexity_wallmount_light
/obj/item/electronic_assembly/wallmount/tiny
name = "tiny wall-mounted electronic assembly"
name = "tiny wall-mounted circuit case"
icon_state = "setup_wallmount_tiny"
desc = "It's a case, for building tiny electronics with. It has a magnetized backing \
desc = "A case for building tiny electronic assemblies. It has a magnetized backing \
to allow it to stick to walls."
w_class = WEIGHT_CLASS_TINY
max_components = IC_COMPONENTS_BASE / 2
max_complexity = IC_COMPLEXITY_BASE / 2
max_components = /obj/item/electronic_assembly/wallmount::max_components_wallmount_tiny
max_complexity = /obj/item/electronic_assembly/wallmount::max_complexity_wallmount_tiny
// Built-in circuits.
/obj/item/electronic_assembly/proc/add_builtin_powernet()
if(!supports_builtin_powernet)
return
for(var/obj/item/integrated_circuit/passive/power/powernet/P in contents)
return
var/obj/item/integrated_circuit/passive/power/powernet/builtin/P = new(src)
P.removable = FALSE
P.assembly = src
force_add_circuit(P)
/obj/item/electronic_assembly/proc/add_builtin_locomotion()
if(!supports_builtin_locomotion)
return
for(var/obj/item/integrated_circuit/manipulation/locomotion/builtin/L in contents)
return
var/obj/item/integrated_circuit/manipulation/locomotion/builtin/L = new(src)
L.removable = FALSE
L.assembly = src
force_add_circuit(L)
/obj/item/electronic_assembly/proc/get_assembly_holder()
return src
@@ -1,7 +1,13 @@
/*
* core/device.dm
* Base device support for electronics-related items that are not themselves circuit assemblies.
*/
/obj/item/assembly/electronic_assembly
name = "electronic device"
desc = "It's a case for building electronics with. It can be attached to other small devices."
desc = "A case for building electronics that can attach to other small devices."
icon_state = "setup_device"
// Whether the assembly panel is open for direct circuit access.
var/opened = 0
var/obj/item/electronic_assembly/device/EA
@@ -61,17 +67,17 @@
set src in usr
set category = "Object"
set name = "Open/Close Device Assembly"
set desc = "Open or close device assembly!"
set desc = "Opens or closes the device assembly."
toggle_open(usr)
/obj/item/electronic_assembly/device
name = "electronic device"
icon_state = "setup_device"
desc = "It's a tiny electronic device with specific use for attaching to other devices."
desc = "A tiny electronic device designed to attach to other devices."
w_class = WEIGHT_CLASS_TINY
max_components = IC_COMPONENTS_BASE * 3/4
max_complexity = IC_COMPLEXITY_BASE * 3/4
max_components = /obj/item/electronic_assembly::max_components_device
max_complexity = /obj/item/electronic_assembly::max_complexity_device
var/obj/item/assembly/electronic_assembly/holder
var/obj/item/integrated_circuit/built_in/device_input/input
@@ -1,13 +1,21 @@
/*
* core/helpers.dm
* Utility procs for integrated electronics, including formatting, data conversion, cloning, list handling, and shared validation.
*/
/obj/item/integrated_circuit/proc/setup_io(list/io_list, io_type, list/io_default_list)
var/list/io_list_copy = io_list.Copy()
io_list.Cut()
var/i = 0
for(var/io_entry in io_list_copy)
i++
var/default_data = null
var/io_type_override = null
// Override the default data.
if(LAZYLEN(io_default_list)) // List containing special pin types that need to be added.
default_data = io_default_list["[i]"] // This is deliberately text because the index is a number in text form.
if(LAZYLEN(io_default_list))
default_data = io_default_list["[i]"]
// Override the pin type.
if(io_list_copy[io_entry])
@@ -19,25 +27,32 @@
io_list += new io_type(src, io_entry, default_data)
/obj/item/integrated_circuit/proc/set_pin_data(pin_type, pin_number, datum/new_data)
if (istype(new_data) && !isweakref(new_data))
if(istype(new_data) && !isweakref(new_data))
new_data = WEAKREF(new_data)
var/datum/integrated_io/pin = get_pin_ref(pin_type, pin_number)
if (!pin)
if(!pin)
CRASH("Invalid pin ref.")
return pin.write_data_to_pin(new_data)
/obj/item/integrated_circuit/proc/get_pin_data(pin_type, pin_number, var/resolve_weakrefs = TRUE)
var/datum/integrated_io/pin = get_pin_ref(pin_type, pin_number)
if(!pin)
return null
return pin.get_data(resolve_weakrefs)
/obj/item/integrated_circuit/proc/get_pin_data_as_type(pin_type, pin_number, as_type)
var/datum/integrated_io/pin = get_pin_ref(pin_type, pin_number)
if(!pin)
return null
return pin.data_as_type(as_type)
/obj/item/integrated_circuit/proc/activate_pin(pin_number)
var/datum/integrated_io/activate/A = activators[pin_number]
if(!A)
return FALSE
A.push_data(pin_number)
return TRUE
/datum/integrated_io/proc/get_data(var/resolve_weakrefs = TRUE)
if(resolve_weakrefs && isweakref(data))
@@ -45,6 +60,9 @@
return data
/obj/item/integrated_circuit/proc/get_pin_ref(pin_type, pin_number)
if(!pin_number || pin_number < 1)
return null
switch(pin_type)
if(IC_INPUT)
if(pin_number > inputs.len)
@@ -58,26 +76,389 @@
if(pin_number > activators.len)
return null
return activators[pin_number]
return null
/obj/item/integrated_circuit/proc/handle_wire(datum/integrated_io/pin, obj/item/integrated_electronics/tool)
if(!pin || !tool)
return FALSE
if(istype(tool, /obj/item/integrated_electronics/wirer))
var/obj/item/integrated_electronics/wirer/wirer = tool
if(pin)
wirer.wire(pin, usr)
return 1
wirer.wire(pin, usr)
return TRUE
else if(istype(tool, /obj/item/integrated_electronics/debugger))
if(istype(tool, /obj/item/integrated_electronics/debugger))
var/obj/item/integrated_electronics/debugger/debugger = tool
if(pin)
debugger.write_data(pin, usr)
return 1
return 0
debugger.write_data(pin, usr)
return TRUE
return FALSE
/proc/XorEncrypt(string, key)
if(!string || !key ||!istext(string)||!istext(key))
return
if(!string || !key || !istext(string) || !istext(key))
return null
var/r
for(var/i = 1 to length(string))
r += ascii2text(text2ascii(string,i) ^ text2ascii(key,(i-1)%length(string)+1))
r += ascii2text(text2ascii(string, i) ^ text2ascii(key, (i - 1) % length(key) + 1))
return r
// ------------------------------------------------------------
// Integrated circuit helper procs.
// These are intentionally generic so new circuits can reuse them
// instead of duplicating null, list, text, number, and boolean checks.
// ------------------------------------------------------------
/proc/ic_is_null(value)
return isnull(value)
/proc/ic_is_text(value)
return istext(value)
/proc/ic_is_number(value)
return isnum(value)
/proc/ic_is_list(value)
return islist(value)
/proc/ic_is_ref(value)
if(isweakref(value))
return TRUE
if(istype(value, /datum))
return TRUE
return FALSE
/proc/ic_is_safe_ref_atom(atom/A)
if(!istype(A))
return FALSE
if(istype(A, /mob/abstract/ghost))
return FALSE
return TRUE
/proc/ic_truthy(value)
if(isnull(value))
return FALSE
if(isnum(value))
return value != 0
if(istext(value))
return length(value) > 0
if(islist(value))
var/list/L = value
return L.len > 0
return TRUE
/proc/ic_falsey(value)
return !ic_truthy(value)
/proc/ic_safe_number(value, default_value = 0)
if(isnum(value))
return value
if(istext(value))
var/converted = text2num(value)
if(!isnull(converted))
return converted
return default_value
/proc/ic_safe_text(value, default_value = "")
if(isnull(value))
return default_value
if(istext(value))
return value
if(isnum(value))
return num2text(value)
if(isweakref(value))
var/datum/weakref/W = value
var/datum/resolved = W.resolve()
if(resolved)
return "[resolved]"
return default_value
return "[value]"
/proc/ic_safe_bool(value)
return ic_truthy(value)
/proc/ic_display_value(value)
if(isnull(value))
return "null"
if(isweakref(value))
var/datum/weakref/W = value
var/datum/resolved = W.resolve()
if(resolved)
return "[resolved]"
return "null ref"
if(islist(value))
var/list/L = value
return ic_list_to_text(L, ", ")
if(istext(value))
return value
if(isnum(value))
return num2text(value)
return "[value]"
/proc/ic_type_text(value)
if(isnull(value))
return "null"
if(isweakref(value))
return "weakref"
if(isnum(value))
return "number"
if(istext(value))
return "string"
if(islist(value))
return "list"
if(istype(value, /datum))
return "ref"
return "unknown"
/proc/ic_list_to_text(list/L, separator = ", ")
if(!islist(L))
return ""
var/list/output = list()
for(var/entry in L)
output += ic_display_value(entry)
return jointext(output, separator)
/proc/ic_text_to_list(text, separator = ",")
if(!istext(text))
return list()
var/list/output = list()
var/list/split_values = splittext(text, separator)
for(var/entry in split_values)
output += trim(entry)
return output
/proc/ic_copy_list(list/L)
if(!islist(L))
return list()
return L.Copy()
/proc/ic_filter_nulls(list/L)
if(!islist(L))
return list()
var/list/output = list()
for(var/entry in L)
if(!isnull(entry))
output += entry
return output
/proc/ic_list_contains(list/L, value)
if(!islist(L))
return FALSE
return L.Find(value) ? TRUE : FALSE
/proc/ic_list_length(list/L)
if(!islist(L))
return 0
return L.len
/proc/ic_clamp_number(value, minimum, maximum)
var/number = ic_safe_number(value, minimum)
if(number < minimum)
return minimum
if(number > maximum)
return maximum
return number
/proc/ic_percent(value, maximum)
var/number = ic_safe_number(value, 0)
var/max_number = ic_safe_number(maximum, 0)
if(max_number <= 0)
return 0
return (number / max_number) * 100
/proc/ic_range_check(value, minimum, maximum)
var/number = ic_safe_number(value, 0)
if(number < minimum)
return -1
if(number > maximum)
return 1
return 0
/proc/ic_range_text(value, minimum, maximum)
var/range_result = ic_range_check(value, minimum, maximum)
if(range_result < 0)
return "low"
if(range_result > 0)
return "high"
return "normal"
/proc/ic_format_status(label, value)
return "[ic_safe_text(label, "Status")]: [ic_display_value(value)]"
/proc/ic_format_warning(label, value)
return "WARNING: [ic_safe_text(label, "Value")] [ic_display_value(value)]"
/proc/ic_format_error(label, value)
return "ERROR: [ic_safe_text(label, "Value")] [ic_display_value(value)]"
/proc/ic_join_lines(list/L)
if(!islist(L))
return ""
var/list/output = list()
for(var/entry in L)
if(isnull(entry))
continue
output += ic_display_value(entry)
return jointext(output, "\n")
/proc/ic_make_saveable_value(value)
if(isnull(value) || isnum(value) || istext(value))
return value
if(isweakref(value))
var/datum/weakref/W = value
var/datum/resolved = W.resolve()
if(resolved)
return "[resolved]"
return null
if(islist(value))
var/list/source_list = value
var/list/new_list = list()
for(var/entry in source_list)
new_list += ic_make_saveable_value(entry)
return new_list
return "[value]"
/proc/ic_sanitize_template_value(value)
var/text_value = ic_display_value(value)
text_value = replacetext(text_value, "\n", " ")
text_value = replacetext(text_value, ascii2text(13), " ")
return text_value
/proc/ic_apply_template(template, value_1 = null, value_2 = null, value_3 = null, value_4 = null, value_5 = null, value_6 = null, value_7 = null, value_8 = null)
if(!istext(template))
return ""
var/output = template
output = replacetext(output, "{1}", ic_sanitize_template_value(value_1))
output = replacetext(output, "{2}", ic_sanitize_template_value(value_2))
output = replacetext(output, "{3}", ic_sanitize_template_value(value_3))
output = replacetext(output, "{4}", ic_sanitize_template_value(value_4))
output = replacetext(output, "{5}", ic_sanitize_template_value(value_5))
output = replacetext(output, "{6}", ic_sanitize_template_value(value_6))
output = replacetext(output, "{7}", ic_sanitize_template_value(value_7))
output = replacetext(output, "{8}", ic_sanitize_template_value(value_8))
return output
/proc/ic_get_nested_list_value(list/L, index, default_value = null)
if(!islist(L))
return default_value
var/number_index = round(ic_safe_number(index, 0))
if(number_index < 1 || number_index > L.len)
return default_value
return L[number_index]
/proc/ic_set_nested_list_value(list/L, index, value)
if(!islist(L))
return list()
var/number_index = round(ic_safe_number(index, 0))
if(number_index < 1 || number_index > IC_MAX_LIST_LENGTH)
return L
while(L.len < number_index)
L += null
L[number_index] = value
return L
/proc/ic_number_or_null(value)
if(isnum(value))
return value
if(istext(value))
var/converted = text2num(value)
if(!isnull(converted))
return converted
return null
/proc/ic_add_numbers(value_1, value_2)
var/A = ic_number_or_null(value_1)
var/B = ic_number_or_null(value_2)
if(isnull(A) || isnull(B))
return null
return A + B
/proc/ic_subtract_numbers(value_1, value_2)
var/A = ic_number_or_null(value_1)
var/B = ic_number_or_null(value_2)
if(isnull(A) || isnull(B))
return null
return A - B
/proc/ic_multiply_numbers(value_1, value_2)
var/A = ic_number_or_null(value_1)
var/B = ic_number_or_null(value_2)
if(isnull(A) || isnull(B))
return null
return A * B
/proc/ic_divide_numbers(value_1, value_2)
var/A = ic_number_or_null(value_1)
var/B = ic_number_or_null(value_2)
if(isnull(A) || isnull(B) || B == 0)
return null
return A / B
@@ -29,6 +29,9 @@ a creative player the means to solve many problems. Circuits are held inside an
/obj/item/integrated_circuit/proc/on_data_written() //Override this for special behaviour when new data gets pushed to the circuit.
return
/obj/item/integrated_circuit/proc/get_printer_spawn_flags()
return spawn_flags
/obj/item/integrated_circuit/Destroy()
for(var/datum/integrated_io/I in inputs)
qdel(I)
@@ -70,7 +73,7 @@ a creative player the means to solve many problems. Circuits are held inside an
/obj/item/integrated_circuit/verb/rename_component()
set name = "Rename Circuit"
set category = "Object"
set desc = "Rename your circuit, useful to stay organized."
set desc = "Renames the circuit to make assemblies easier to organize."
var/mob/M = usr
if(!check_interactivity(M))
@@ -175,7 +178,8 @@ a creative player the means to solve many problems. Circuits are held inside an
HTML += "<br><span class='highlight'>Power Draw: [power_draw_idle] W (Idle)</span>"
if(power_draw_per_use)
HTML += "<br><span class='highlight'>Power Draw: [power_draw_per_use] W (Active)</span>" // Borgcode says that powercells' checked_use() takes joules as input.
HTML += "<br><span class='highlight'>[extended_desc]</span>"
if(extended_desc)
HTML += "<br><span class='highlight'>[extended_desc]</span>"
var/datum/browser/B = new(user, assembly ? "assembly-[REF(assembly)]" : "circuit-[REF(src)]", (displayed_name && displayed_name != name) ? "[displayed_name] ([name])" : name, window_width, window_height)
B.set_content(HTML.Join())
@@ -319,7 +323,7 @@ a creative player the means to solve many problems. Circuits are held inside an
/obj/item/integrated_circuit/proc/pull_data()
for(var/datum/integrated_io/I in inputs)
I.push_data()
I.pull_data()
/obj/item/integrated_circuit/proc/draw_idle_power()
if(assembly)
@@ -1,6 +1,6 @@
/*
Pins both hold data for circuits, as well move data between them. Some also cause circuits to do their function. DATA_CHANNEL pins are the data holding/moving kind,
where as PULSE_CHANNEL causes circuits to work() when their pulse hits them.
whereas PULSE_CHANNEL causes circuits to work() when their pulse hits them.
A visualization of how pins work is below. Imagine the below image involves an addition circuit.
@@ -68,14 +68,15 @@ list[](
if(islist(input))
var/list/my_list = input
var/result = "list\[[my_list.len]\]("
if(my_list.len)
var/list_length = length(my_list)
var/result = "list\[[list_length]\]("
if(list_length)
result += "<br>"
var/pos = 0
for(var/line in my_list)
result += "[display_data(line)]"
pos++
if(pos != my_list.len)
if(pos != list_length)
result += ",<br>"
result += "<br>"
result += ")"
File diff suppressed because it is too large Load Diff
@@ -1,3 +1,8 @@
/*
* core/special_pins/boolean_pin.dm
* Boolean pin type behavior and conversion for TRUE/FALSE style circuit values.
*/
// These pins only contain 0 or 1. Null is not allowed.
/datum/integrated_io/boolean
name = "boolean pin"
@@ -1,3 +1,8 @@
/*
* core/special_pins/char_pin.dm
* Character/string single-character pin behavior and validation.
*/
// These pins can only contain a 1 character string or null.
/datum/integrated_io/char
name = "char pin"
@@ -1,3 +1,8 @@
/*
* core/special_pins/color_pin.dm
* Color pin parsing, validation, and display handling for circuit color values.
*/
// These pins can only contain a color (in the form of #FFFFFF) or null.
/datum/integrated_io/color
name = "color pin"
@@ -13,18 +18,19 @@
if(isnull(new_data) || istext(new_data))
if(istext(new_data))
new_data = uppertext(new_data)
if(length(new_data) != 7) // We can hex if we want to, we can leave your strings behind
return // Cause your strings don't hex and if they don't hex
var/friends = copytext(new_data, 2, 8) // Well they're are no strings of mine
// I say, we can go where we want to, a place where they will never find
if(length(new_data) != 7)
return
if(copytext(new_data, 1, 2) != "#")
return
var/hex_digits = copytext(new_data, 2, 8)
var/safety_dance = 1
while(safety_dance >= 7) // And we can act like we come from out of this world.log
var/hex = copytext(friends, safety_dance, safety_dance+1)
if(!(hex in list("0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F")))
return // Leave the fake one far behind,
while(safety_dance <= 6)
var/hex = copytext(hex_digits, safety_dance, safety_dance + 1)
if(!findtext("0123456789ABCDEF", hex))
return
safety_dance++
data = new_data // And we can hex
data = new_data
holder.on_data_written()
// This randomizes the color.
@@ -1,3 +1,8 @@
/*
* core/special_pins/dir_pin.dm
* Direction pin conversion and validation for BYOND direction constants.
*/
// These pins can only contain directions (1,2,4,8...) or null.
/datum/integrated_io/dir
name = "dir pin"
@@ -1,4 +1,12 @@
// These pins contain a list. Null is not allowed.
/*
* core/special_pins/list_pin.dm
* List pin serialization, display, cloning, and safety handling for list-valued circuit data.
*/
// These pins contain a list.
// Lists may contain strings, numbers, weakrefs, nested lists, or null.
// Individual circuits are responsible for deciding what data types they accept.
/datum/integrated_io/list
name = "list pin"
data = list()
@@ -6,14 +14,10 @@
/datum/integrated_io/list/ask_for_pin_data(mob/user)
interact(user)
// Positionless remove/Edit are a bit weird,
// not sure if adding these buttons is quite a good idea.
// They introduce uncertainty, since, in case of 2 elements,
// they will work just with the 1st one
/datum/integrated_io/list/proc/interact(mob/user)
var/list/my_list = data
var/t = "<h2>[src]</h2><br>"
t += "List length: [my_list.len]<br>"
t += "List length: [length(my_list)]<br>"
t += "<a href='byond://?src=[REF(src)]'>Refresh</a> | "
t += "<a href='byond://?src=[REF(src)];add=1'>Add</a> | "
t += "<a href='byond://?src=[REF(src)];remove=1'>Remove</a> | "
@@ -21,113 +25,161 @@
t += "<a href='byond://?src=[REF(src)];swap=1'>Swap</a> | "
t += "<a href='byond://?src=[REF(src)];clear=1'>Clear</a><br>"
t += "<hr>"
// Iterating by index simplifies editing/deletion in game,
// since the href_list["pos"] var is consistent
for(var/i = 1; i <= length(my_list); i++)
t += "#[i] | [display_data(my_list[i])] | "
t += "<a href='byond://?src=[REF(src)];edit=1;pos=[i]'>Edit</a> | "
t += "<a href='byond://?src=[REF(src)];remove=1;pos=[i]'>Remove</a><br>"
var/datum/browser/B = new(user, "list_pin_[REF(src)]", null, 500, 400)
B.set_content(t)
B.open(FALSE)
/datum/integrated_io/list/proc/add_to_list(mob/user, new_entry)
if(!new_entry && user)
new_entry = ask_for_data_type(user)
// is_valid can't be used here, since is_valid checks "data" and has no arguments
if(!isnull(new_entry))
Add(new_entry)
if(isnull(new_entry) && user)
new_entry = ask_for_data_type(user, null, list("string", "number", "null"))
Add(new_entry)
/datum/integrated_io/list/proc/Add(new_entry)
if(!islist(data))
data = list()
var/list/my_list = data
if(my_list.len > IC_MAX_LIST_LENGTH)
if(length(my_list) >= IC_MAX_LIST_LENGTH)
my_list.Cut(1, 2)
my_list.Add(new_entry)
my_list += list(new_entry)
holder.on_data_written()
/datum/integrated_io/list/proc/remove_from_list_by_position(mob/user, position)
var/list/my_list = data
if(!my_list.len)
if(!length(my_list))
to_chat(user, SPAN_WARNING("The list is empty, there's nothing to remove."))
return
if(!position)
if(isnull(position))
return
if(position > my_list.len)
position = round(position)
if(position < 1 || position > length(my_list))
return
var/target_entry = my_list[position]
// Should be able to remove nulls, since we can add a null to the list from the outside.
my_list -= target_entry
my_list.Cut(position, position + 1)
holder.on_data_written()
/datum/integrated_io/list/proc/remove_from_list(mob/user, target_entry)
var/list/my_list = data
if(!my_list.len)
if(!length(my_list))
to_chat(user, SPAN_WARNING("The list is empty, there's nothing to remove."))
return
if(!target_entry)
if(isnull(target_entry))
target_entry = input("Which piece of data do you want to remove?", "Remove") as null|anything in my_list
if(target_entry)
my_list -= target_entry
if(!isnull(target_entry))
var/position = my_list.Find(target_entry)
if(position)
my_list.Cut(position, position + 1)
holder.on_data_written()
/datum/integrated_io/list/proc/edit_in_list(mob/user, target_entry)
var/list/my_list = data
if(!my_list.len)
if(!length(my_list))
to_chat(user, SPAN_WARNING("The list is empty, there's nothing to modify."))
return
if(!target_entry)
if(isnull(target_entry))
target_entry = input("Which piece of data do you want to edit?", "Edit") as null|anything in my_list
if(target_entry)
var/edited_entry = ask_for_data_type(user, target_entry)
var/i = my_list.Find(target_entry)
if(edited_entry)
my_list[i] = edited_entry
/datum/integrated_io/list/proc/edit_in_list_by_position(mob/user, var/position)
if(!isnull(target_entry))
var/i = my_list.Find(target_entry)
if(i)
var/edited_entry = ask_for_data_type(user, target_entry, list("string", "number", "null"))
my_list[i] = edited_entry
holder.on_data_written()
/datum/integrated_io/list/proc/edit_in_list_by_position(mob/user, position)
var/list/my_list = data
if(!my_list.len)
if(!length(my_list))
to_chat(user, SPAN_WARNING("The list is empty, there's nothing to modify."))
return
if(!position)
return
if(position > my_list.len)
return
var/target_entry = my_list[position]
if(target_entry)
var/edited_entry = ask_for_data_type(user, target_entry)
if(edited_entry)
my_list[position] = edited_entry
/datum/integrated_io/list/proc/swap_inside_list(mob/user, var/first_target, var/second_target)
if(isnull(position))
return
position = round(position)
if(position < 1 || position > length(my_list))
return
var/target_entry = my_list[position]
var/edited_entry = ask_for_data_type(user, target_entry, list("string", "number", "null"))
my_list[position] = edited_entry
holder.on_data_written()
/datum/integrated_io/list/proc/swap_inside_list(mob/user, first_target, second_target)
var/list/my_list = data
if(my_list.len <= 1)
if(length(my_list) <= 1)
to_chat(user, SPAN_WARNING("The list is empty, or too small to do any meaningful swapping."))
return
if(!first_target)
if(isnull(first_target))
first_target = input("Which piece of data do you want to swap? (1)", "Swap") as null|anything in my_list
if(first_target)
if(!second_target)
second_target = input("Which piece of data do you want to swap? (2)", "Swap") as null|anything in my_list - first_target
if(isnull(first_target))
return
if(second_target)
var/first_pos = my_list.Find(first_target)
var/second_pos = my_list.Find(second_target)
my_list.Swap(first_pos, second_pos)
if(isnull(second_target))
second_target = input("Which piece of data do you want to swap? (2)", "Swap") as null|anything in my_list - first_target
if(isnull(second_target))
return
var/first_pos = my_list.Find(first_target)
var/second_pos = my_list.Find(second_target)
if(first_pos && second_pos)
my_list.Swap(first_pos, second_pos)
holder.on_data_written()
/datum/integrated_io/list/proc/clear_list(mob/user)
var/list/my_list = data
my_list.Cut()
holder.on_data_written()
/datum/integrated_io/list/scramble()
var/list/my_list = data
my_list = shuffle(my_list)
data = shuffle(my_list)
push_data()
/datum/integrated_io/list/write_data_to_pin(var/new_data)
if(islist(new_data))
var/list/new_list = new_data
// Sanitize the input - no nulls allowed.
while(new_list.Remove(null) == 1)
data = new_list.Copy()
if(isnull(new_data))
data = list()
holder.on_data_written()
return
if(!islist(new_data))
return
var/list/new_list = new_data
var/list/sanitized = list()
for(var/value in new_list)
if(sanitized.len >= IC_MAX_LIST_LENGTH)
break
if(isnull(value) || isnum(value) || istext(value) || isweakref(value) || islist(value))
sanitized += list(value)
data = sanitized
holder.on_data_written()
/datum/integrated_io/list/display_pin_type()
return IC_FORMAT_LIST
@@ -135,8 +187,9 @@
/datum/integrated_io/list/Topic(href, href_list, state = GLOB.always_state)
if(!holder.check_interactivity(usr))
return
if(..())
return 1
return TRUE
if(href_list["add"])
add_to_list(usr)
@@ -159,5 +212,7 @@
else
edit_in_list(usr)
holder.interact(usr) // Refresh the main UI,
interact(usr) // and the list UI.
holder.interact(usr)
interact(usr)
return TRUE
@@ -1,3 +1,8 @@
/*
* core/special_pins/number_pin.dm
* Number pin conversion, validation, and formatting.
*/
// These pins can only contain numbers (int and floating point) or null.
/datum/integrated_io/number
name = "number pin"
@@ -1,3 +1,8 @@
/*
* core/special_pins/ref_pin.dm
* Reference pin behavior for passing object references between circuits.
*/
// These pins only contain weakrefs or null.
/datum/integrated_io/ref
name = "ref pin"
@@ -1,3 +1,8 @@
/*
* core/special_pins/string_pin.dm
* String pin conversion, validation, and formatting.
*/
// These pins can only contain text and null.
/datum/integrated_io/string
name = "string pin"
@@ -1,3 +1,8 @@
/*
* core/tools.dm
* Tools used to manipulate integrated electronics, such as wiring, debugging, and assembly maintenance helpers.
*/
#define WIRE "wire"
#define WIRING "wiring"
#define UNWIRE "unwire"
@@ -176,6 +181,7 @@
icon_state = "detailer"
item_flags = ITEM_FLAG_NO_BLUDGEON
w_class = WEIGHT_CLASS_SMALL
// User-selected detail color used for assembly and wearable overlays.
var/detail_color = COLOR_ASSEMBLY_WHITE
var/static/list/color_list = list(
"black" = COLOR_ASSEMBLY_BLACK,
@@ -217,7 +223,7 @@
/obj/item/storage/bag/circuits
name = "circuit kit"
desc = "This kit is essential for any circuitry projects."
desc = "A kit containing basic tools and parts for circuit projects."
icon = 'icons/obj/assemblies/electronic_tools.dmi'
icon_state = "circuit_kit"
w_class = WEIGHT_CLASS_NORMAL
@@ -279,7 +285,7 @@
/obj/item/storage/bag/circuits/mini
name = "circuit box"
desc = "Used to partition categories of circuits, for a neater workspace."
desc = "Stores circuits by category for easier organization."
w_class = WEIGHT_CLASS_SMALL
display_contents_with_number = TRUE
pickup_blacklist = list(
@@ -299,7 +305,7 @@
/obj/item/storage/bag/circuits/mini/arithmetic
name = "arithmetic circuit box"
desc = "Warning: Contains math."
desc = "Contains arithmetic and numeric utility circuits."
icon_state = "box_arithmetic"
spawn_types = list(
/obj/item/integrated_circuit/arithmetic
@@ -310,7 +316,7 @@
/obj/item/storage/bag/circuits/mini/trig
name = "trig circuit box"
desc = "Danger: Contains more math."
desc = "Contains trigonometric circuits."
icon_state = "box_trig"
spawn_types = list(
/obj/item/integrated_circuit/trig
@@ -321,7 +327,7 @@
/obj/item/storage/bag/circuits/mini/input
name = "input circuit box"
desc = "Tell these circuits everything you know."
desc = "Contains circuits that read data from the surrounding environment."
icon_state = "box_input"
spawn_types = list(
/obj/item/integrated_circuit/input
@@ -332,7 +338,7 @@
/obj/item/storage/bag/circuits/mini/output
name = "output circuit box"
desc = "Circuits to interface with the world beyond itself."
desc = "Contains circuits that display, announce, or transmit data."
icon_state = "box_output"
spawn_types = list(
/obj/item/integrated_circuit/output
@@ -343,7 +349,7 @@
/obj/item/storage/bag/circuits/mini/memory
name = "memory circuit box"
desc = "Machines can be quite forgetful without these."
desc = "Contains memory circuits for storing circuit data."
icon_state = "box_memory"
spawn_types = list(
/obj/item/integrated_circuit/memory
@@ -354,7 +360,7 @@
/obj/item/storage/bag/circuits/mini/logic
name = "logic circuit box"
desc = "May or may not be Turing complete."
desc = "Contains logic circuits for boolean-style control and comparisons."
icon_state = "box_logic"
spawn_types = list(
/obj/item/integrated_circuit/logic
@@ -365,18 +371,55 @@
/obj/item/storage/bag/circuits/mini/time
name = "time circuit box"
desc = "No time machine parts, sadly."
desc = "Contains timer and clock circuits."
icon_state = "box_time"
spawn_types = list(
/obj/item/integrated_circuit/time
)
/obj/item/storage/bag/circuits/mini/time/fill()
var/list/basic_time_circuits = list(
/obj/item/integrated_circuit/time/delay,
/obj/item/integrated_circuit/time/delay/five_sec,
/obj/item/integrated_circuit/time/delay/one_sec,
/obj/item/integrated_circuit/time/delay/half_sec,
/obj/item/integrated_circuit/time/delay/tenth_sec,
/obj/item/integrated_circuit/time/ticker/fast,
/obj/item/integrated_circuit/time/ticker,
/obj/item/integrated_circuit/time/ticker/slow,
/obj/item/integrated_circuit/time/ticker/very_slow,
/obj/item/integrated_circuit/time/clock
)
for(var/circuit_type in basic_time_circuits)
for(var/i in 1 to 4)
new circuit_type(src)
/obj/item/storage/bag/circuits/mini/time/all
spawn_flags_to_use = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
/obj/item/storage/bag/circuits/mini/time/all/fill()
var/list/all_time_circuits = list(
/obj/item/integrated_circuit/time/delay,
/obj/item/integrated_circuit/time/delay/five_sec,
/obj/item/integrated_circuit/time/delay/one_sec,
/obj/item/integrated_circuit/time/delay/half_sec,
/obj/item/integrated_circuit/time/delay/tenth_sec,
/obj/item/integrated_circuit/time/delay/custom,
/obj/item/integrated_circuit/time/ticker/rapid,
/obj/item/integrated_circuit/time/ticker/fast,
/obj/item/integrated_circuit/time/ticker,
/obj/item/integrated_circuit/time/ticker/slow,
/obj/item/integrated_circuit/time/ticker/very_slow,
/obj/item/integrated_circuit/time/ticker/custom,
/obj/item/integrated_circuit/time/clock
)
for(var/circuit_type in all_time_circuits)
for(var/i in 1 to 4)
new circuit_type(src)
/obj/item/storage/bag/circuits/mini/reagents
name = "reagent circuit box"
desc = "Unlike most electronics, these circuits are supposed to come in contact with liquids."
desc = "Contains circuits for handling reagents and containers."
icon_state = "box_reagents"
spawn_types = list(
/obj/item/integrated_circuit/reagent
@@ -387,7 +430,7 @@
/obj/item/storage/bag/circuits/mini/transfer
name = "transfer circuit box"
desc = "Useful for moving data representing something arbitrary to another arbitrary virtual place."
desc = "Contains circuits for routing data between pins and devices."
icon_state = "box_transfer"
spawn_types = list(
/obj/item/integrated_circuit/transfer
@@ -398,7 +441,7 @@
/obj/item/storage/bag/circuits/mini/converter
name = "converter circuit box"
desc = "Transform one piece of data to another type of data with these."
desc = "Contains circuits for converting data between supported formats."
icon_state = "box_converter"
spawn_types = list(
/obj/item/integrated_circuit/converter
@@ -409,7 +452,7 @@
/obj/item/storage/bag/circuits/mini/smart
name = "smart box"
desc = "Sentience not included."
desc = "Contains smart control circuits for navigation and automation."
icon_state = "box_ai"
spawn_types = list(
/obj/item/integrated_circuit/smart
@@ -420,7 +463,7 @@
/obj/item/storage/bag/circuits/mini/manipulation
name = "manipulation box"
desc = "Make your machines actually useful with these."
desc = "Contains circuits that perform physical actions through an assembly."
icon_state = "box_manipulation"
spawn_types = list(
/obj/item/integrated_circuit/manipulation
@@ -431,7 +474,7 @@
/obj/item/storage/bag/circuits/mini/power
name = "power circuit box"
desc = "Electronics generally require electricity."
desc = "Contains circuits that generate, receive, or transmit power."
icon_state = "box_power"
spawn_types = list(
/obj/item/integrated_circuit/passive/power,