mirror of
https://github.com/Aurorastation/Aurora.3.git
synced 2026-08-24 05:23:22 +01:00
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:
@@ -2592,6 +2592,7 @@
|
||||
#include "code\modules\integrated_electronics\core\printer.dm"
|
||||
#include "code\modules\integrated_electronics\core\tools.dm"
|
||||
#include "code\modules\integrated_electronics\core\assemblies\clothing.dm"
|
||||
#include "code\modules\integrated_electronics\core\assemblies\electronic_radio_headset.dm"
|
||||
#include "code\modules\integrated_electronics\core\assemblies\generic.dm"
|
||||
#include "code\modules\integrated_electronics\core\special_pins\boolean_pin.dm"
|
||||
#include "code\modules\integrated_electronics\core\special_pins\char_pin.dm"
|
||||
@@ -2607,15 +2608,18 @@
|
||||
#include "code\modules\integrated_electronics\subtypes\built_in.dm"
|
||||
#include "code\modules\integrated_electronics\subtypes\converters.dm"
|
||||
#include "code\modules\integrated_electronics\subtypes\data_transfer.dm"
|
||||
#include "code\modules\integrated_electronics\subtypes\debug.dm"
|
||||
#include "code\modules\integrated_electronics\subtypes\input.dm"
|
||||
#include "code\modules\integrated_electronics\subtypes\insert_slot.dm"
|
||||
#include "code\modules\integrated_electronics\subtypes\lists.dm"
|
||||
#include "code\modules\integrated_electronics\subtypes\logic.dm"
|
||||
#include "code\modules\integrated_electronics\subtypes\manipulation.dm"
|
||||
#include "code\modules\integrated_electronics\subtypes\math_extended.dm"
|
||||
#include "code\modules\integrated_electronics\subtypes\memory.dm"
|
||||
#include "code\modules\integrated_electronics\subtypes\output.dm"
|
||||
#include "code\modules\integrated_electronics\subtypes\power.dm"
|
||||
#include "code\modules\integrated_electronics\subtypes\reagents.dm"
|
||||
#include "code\modules\integrated_electronics\subtypes\server.dm"
|
||||
#include "code\modules\integrated_electronics\subtypes\smart.dm"
|
||||
#include "code\modules\integrated_electronics\subtypes\time.dm"
|
||||
#include "code\modules\integrated_electronics\subtypes\trig.dm"
|
||||
|
||||
@@ -1,2 +1,6 @@
|
||||
#define IC_COMPONENTS_BASE 25
|
||||
#define IC_COMPLEXITY_BASE 75
|
||||
|
||||
#define IC_OVERFLOW_COMPONENT_TO_COMPLEXITY 2
|
||||
#define IC_OVERFLOW_COMPLEXITY_TO_COMPONENT 6
|
||||
#define IC_OVERFLOW_LIMIT 0.15
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
#define IC_SPAWN_DEFAULT 1 // If the circuit comes in the default circuit box and able to be printed in the IC printer.
|
||||
#define IC_SPAWN_DEFAULT 1 // If the circuit comes in the default circuit box and able to be printed in the IC printer.
|
||||
#define IC_SPAWN_RESEARCH 2 // If the circuit design will be available in the IC printer after upgrading it.
|
||||
|
||||
PROCESSING_SUBSYSTEM_DEF(electronics)
|
||||
name = "Electronics"
|
||||
wait = 2 SECONDS
|
||||
wait = 1 SECOND
|
||||
priority = SS_PRIORITY_ELECTRONICS
|
||||
flags = SS_KEEP_TIMING
|
||||
init_order = INIT_ORDER_MISC_FIRST
|
||||
|
||||
var/list/all_integrated_circuits = list()
|
||||
var/list/printer_recipe_list = list()
|
||||
var/list/printer_recipe_list_basic = list()
|
||||
@@ -20,13 +19,14 @@ PROCESSING_SUBSYSTEM_DEF(electronics)
|
||||
// First loop is to seperate the actual circuits from base circuits.
|
||||
var/list/circuits_to_use = list()
|
||||
for(var/obj/item/integrated_circuit/IC in all_integrated_circuits)
|
||||
if((IC.spawn_flags & (IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH)))
|
||||
if((IC.get_printer_spawn_flags() & (IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH)))
|
||||
circuits_to_use += IC
|
||||
|
||||
// Second loop is to find all categories.
|
||||
for(var/obj/item/integrated_circuit/IC in circuits_to_use)
|
||||
if(!(IC.category_text in found_categories))
|
||||
found_categories += IC.category_text
|
||||
|
||||
found_categories += "Assemblies"
|
||||
found_categories += "Tools"
|
||||
|
||||
@@ -57,6 +57,7 @@ PROCESSING_SUBSYSTEM_DEF(electronics)
|
||||
new /obj/item/electronic_assembly/medium/medical,
|
||||
new /obj/item/electronic_assembly/medium/gun,
|
||||
new /obj/item/electronic_assembly/medium/radio,
|
||||
new /obj/item/electronic_assembly/medium/anomaly_drill,
|
||||
new /obj/item/electronic_assembly/large/default,
|
||||
new /obj/item/electronic_assembly/large/scope,
|
||||
new /obj/item/electronic_assembly/large/terminal,
|
||||
@@ -78,7 +79,7 @@ PROCESSING_SUBSYSTEM_DEF(electronics)
|
||||
new /obj/item/clothing/glasses/circuitry,
|
||||
new /obj/item/clothing/shoes/circuitry,
|
||||
new /obj/item/clothing/head/circuitry,
|
||||
new /obj/item/clothing/ears/circuitry,
|
||||
new /obj/item/radio/headset/circuitry,
|
||||
new /obj/item/clothing/suit/circuitry
|
||||
)
|
||||
|
||||
@@ -94,12 +95,13 @@ PROCESSING_SUBSYSTEM_DEF(electronics)
|
||||
var/is_basic = TRUE
|
||||
if(istype(O, /obj/item/integrated_circuit))
|
||||
var/obj/item/integrated_circuit/IC = O
|
||||
if((IC.spawn_flags & IC_SPAWN_RESEARCH) && (!(IC.spawn_flags & IC_SPAWN_DEFAULT)))
|
||||
var/printer_spawn_flags = IC.get_printer_spawn_flags()
|
||||
if((printer_spawn_flags & IC_SPAWN_RESEARCH) && (!(printer_spawn_flags & IC_SPAWN_DEFAULT)))
|
||||
is_basic = FALSE
|
||||
|
||||
printer_recipe_list_basic += list(list(path = "[O.type]", name = "[O.name]", desc = "[O.desc]", "basic" = is_basic, "category" = category))
|
||||
printer_recipe_list_upgraded += list(list(path = "[O.type]", name = "[O.name]", desc = "[O.desc]", "basic" = TRUE, "category" = category))
|
||||
|
||||
var/list/recipe = list(path = "[O.type]", name = "[O.name]", desc = "[O.desc]", "basic" = is_basic, "category" = category)
|
||||
if(is_basic)
|
||||
printer_recipe_list_basic += list(recipe)
|
||||
printer_recipe_list_upgraded += list(recipe)
|
||||
|
||||
return SS_INIT_SUCCESS
|
||||
|
||||
|
||||
@@ -9,9 +9,9 @@
|
||||
/obj/item/implant/integrated_circuit/isLegal()
|
||||
return TRUE
|
||||
|
||||
/obj/item/implant/integrated_circuit/Initialize()
|
||||
/obj/item/implant/integrated_circuit/Initialize(mapload, printed = FALSE)
|
||||
. = ..()
|
||||
IC = new(src)
|
||||
IC = new(src, printed)
|
||||
IC.implant = src
|
||||
|
||||
/obj/item/implant/integrated_circuit/Destroy()
|
||||
|
||||
@@ -9,34 +9,39 @@
|
||||
return 0
|
||||
|
||||
/obj/item/clothing/attackby(obj/item/attacking_item, mob/user)
|
||||
if(IC && (istype(attacking_item, /obj/item/integrated_circuit) || attacking_item.tool_behaviour == TOOL_WRENCH || attacking_item.tool_behaviour == TOOL_CROWBAR || \
|
||||
if(IC)
|
||||
if(attacking_item.tool_behaviour == TOOL_CROWBAR)
|
||||
IC.attackby(attacking_item, user)
|
||||
return TRUE
|
||||
|
||||
if(IC.opened && (istype(attacking_item, /obj/item/integrated_circuit) || attacking_item.tool_behaviour == TOOL_WRENCH || \
|
||||
istype(attacking_item, /obj/item/integrated_electronics/wirer) || istype(attacking_item, /obj/item/integrated_electronics/debugger) || \
|
||||
attacking_item.tool_behaviour == TOOL_MULTITOOL || attacking_item.tool_behaviour == TOOL_SCREWDRIVER || istype(attacking_item, /obj/item/cell/device)))
|
||||
|
||||
IC.attackby(attacking_item, user)
|
||||
IC.attackby(attacking_item, user)
|
||||
return TRUE
|
||||
|
||||
else if(istype(attacking_item, /obj/item/clothing/accessory))
|
||||
|
||||
if(!valid_accessory_slots || !valid_accessory_slots.len)
|
||||
to_chat(usr, SPAN_WARNING("You cannot attach accessories of any kind to \the [src]."))
|
||||
return
|
||||
to_chat(user, SPAN_WARNING("You cannot attach accessories of any kind to \the [src]."))
|
||||
return TRUE
|
||||
|
||||
var/obj/item/clothing/accessory/A = attacking_item
|
||||
A.before_attached(src, user)
|
||||
if(can_attach_accessory(A))
|
||||
user.drop_item()
|
||||
attach_accessory(user, A)
|
||||
return
|
||||
return TRUE
|
||||
else
|
||||
to_chat(user, SPAN_WARNING("You cannot attach more accessories of this type to [src]."))
|
||||
return
|
||||
return TRUE
|
||||
|
||||
if(LAZYLEN(accessories))
|
||||
for(var/obj/item/clothing/accessory/A in accessories)
|
||||
A.attackby(attacking_item, user)
|
||||
return
|
||||
return TRUE
|
||||
|
||||
..()
|
||||
return ..()
|
||||
|
||||
/obj/item/clothing/attack_hand(var/mob/user)
|
||||
//only forward to the attached accessory if the clothing is equipped (not in a storage)
|
||||
|
||||
@@ -39,6 +39,9 @@
|
||||
|
||||
// Data limits.
|
||||
#define IC_MAX_LIST_LENGTH 200
|
||||
#define IC_DEFAULT_PHORON_COST 0.005
|
||||
#define IC_BLUEPRINT_CHUNK_LIMIT 1000
|
||||
#define IC_BLUEPRINT_BUFFER_LIMIT 500000
|
||||
|
||||
/obj/item/integrated_circuit
|
||||
name = "integrated circuit"
|
||||
@@ -61,6 +64,7 @@
|
||||
var/power_draw_idle = 0 // How much power is drawn when doing nothing.
|
||||
var/spawn_flags // Used for world initializing, see the #defines above.
|
||||
var/category_text = "NO CATEGORY THIS IS A BUG" // To show up on circuit printer, and perhaps other places.
|
||||
var/phoron_cost = IC_DEFAULT_PHORON_COST
|
||||
var/removable = TRUE // Determines if a circuit is removable from the assembly.
|
||||
var/displayed_name = ""
|
||||
var/allow_multitool = TRUE // Allows additional multitool functionality
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
/*
|
||||
* passive/passive.dm
|
||||
* Base passive circuit category for circuits that provide background behavior instead of triggered work.
|
||||
*/
|
||||
|
||||
// 'Passive' components do not have any pins, and instead contribute in some form to the assembly holding them.
|
||||
/obj/item/integrated_circuit/passive
|
||||
inputs = list()
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
/*
|
||||
* passive/power.dm
|
||||
* Passive power circuits and power-network integration for assemblies.
|
||||
*/
|
||||
|
||||
|
||||
/obj/item/integrated_circuit/passive/power
|
||||
name = "power thingy"
|
||||
desc = "Does power stuff."
|
||||
desc = "Base type for integrated power circuits."
|
||||
complexity = 5
|
||||
origin_tech = list(TECH_POWER = 2, TECH_ENGINEERING = 2, TECH_DATA = 2)
|
||||
category_text = "Power - Passive"
|
||||
@@ -12,14 +17,13 @@
|
||||
// For calculators.
|
||||
/obj/item/integrated_circuit/passive/power/solar_cell
|
||||
name = "tiny photovoltaic cell"
|
||||
desc = "It's a very tiny solar cell, generally used in calculators."
|
||||
desc = "A very small solar cell for low-power assemblies."
|
||||
extended_desc = "The cell generates up to 100 W of energy in optimal lighting conditions. Less light will result in less power being generated."
|
||||
icon_state = "solar_cell"
|
||||
complexity = 8
|
||||
origin_tech = list(TECH_POWER = 3, TECH_ENGINEERING = 3, TECH_DATA = 2)
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
|
||||
/// Multiplied by amount of lumens to get amount of power to generate.
|
||||
var/power_factor = 15
|
||||
|
||||
/obj/item/integrated_circuit/passive/power/solar_cell/make_energy()
|
||||
@@ -33,7 +37,7 @@
|
||||
// For fat machines that need fat power, like drones.
|
||||
/obj/item/integrated_circuit/passive/power/relay
|
||||
name = "tesla power relay"
|
||||
desc = "A seemingly enigmatic device which connects to nearby APCs wirelessly and draws power from them."
|
||||
desc = "Connects to nearby APCs wirelessly and draws power from them."
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
extended_desc = "The siphon generates 1 kW of energy, so long as an APC is in the same room, with a cell that has energy. It will always drain \
|
||||
from the 'equipment' power channel."
|
||||
@@ -46,7 +50,7 @@
|
||||
// For really fat machines.
|
||||
/obj/item/integrated_circuit/passive/power/relay/large
|
||||
name = "large tesla power relay"
|
||||
desc = "A seemingly enigmatic device which connects to nearby APCs wirelessly and draws power from them, now in industiral size!"
|
||||
desc = "Connects to nearby APCs wirelessly and draws a larger amount of power from them."
|
||||
w_class = WEIGHT_CLASS_BULKY
|
||||
extended_desc = "The siphon generates 4 kW of energy, so long as an APC is in the same room, with a cell that has energy. It will always drain \
|
||||
from the 'equipment' power channel."
|
||||
@@ -68,7 +72,7 @@
|
||||
// For implants.
|
||||
/obj/item/integrated_circuit/passive/power/metabolic_siphon
|
||||
name = "metabolic siphon"
|
||||
desc = "A complicated piece of technology which converts bodily nutriments of a host into electricity, or vice versa."
|
||||
desc = "Converts a host's nutrients into electricity, or uses electricity to supply nutrients."
|
||||
extended_desc = "The siphon generates 10W of energy, so long as the siphon exists inside a biological entity. The entity will feel an increased \
|
||||
appetite and will need to eat more often due to this. This device will fail if used inside synthetic entities.\
|
||||
If the polarity is reversed, it will instead generate chemical energy with electricity, continuously consuming power from the assembly.\
|
||||
@@ -122,7 +126,7 @@
|
||||
name = "fuel cell"
|
||||
desc = "Produces electricity from chemicals."
|
||||
icon_state = "chemical_cell"
|
||||
extended_desc = "This is effectively an internal beaker. It will consume and produce power from phoron, slime jelly, welding fuel, carbon,\
|
||||
extended_desc = "Functions as an internal beaker for the assembly. It will consume and produce power from phoron, slime jelly, welding fuel, carbon,\
|
||||
ethanol, nutriments and blood, in order of decreasing efficiency. It will consume fuel only if the battery can take more energy."
|
||||
|
||||
atom_flags = ATOM_FLAG_OPEN_CONTAINER
|
||||
@@ -162,25 +166,33 @@
|
||||
name = "power network interface"
|
||||
desc = "Gives or takes power from a wire underneath the machine."
|
||||
icon_state = "powernet"
|
||||
extended_desc = "The assembly must be anchored, with a wrench, and a wire node must be avaiable directly underneath.<br>\
|
||||
extended_desc = "The assembly must be anchored, with a wrench, and a wire node must be available directly underneath.<br>\
|
||||
The first pin determines if power is moved at all. The second pin, if true, will draw from the powernet to charge the assembly's \
|
||||
cell, otherwise it will give power from the cell to the powernet."
|
||||
complexity = 20
|
||||
size = 1
|
||||
inputs = list(
|
||||
"active" = IC_PINTYPE_BOOLEAN,
|
||||
"draw power" = IC_PINTYPE_BOOLEAN
|
||||
)
|
||||
)
|
||||
outputs = list(
|
||||
"power in grid" = IC_PINTYPE_NUMBER,
|
||||
"surplus power" = IC_PINTYPE_NUMBER,
|
||||
"load" = IC_PINTYPE_NUMBER
|
||||
)
|
||||
)
|
||||
activators = list()
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
origin_tech = list(TECH_ENGINEERING = 2, TECH_POWER = 2)
|
||||
var/obj/structure/machinery/power/circuit_io/IO = null // Dummy power machine to move energy in/out without a bunch of code duplication.
|
||||
var/throughput = 10000 // Give/take up to 10kW.
|
||||
|
||||
/obj/item/integrated_circuit/passive/power/powernet/builtin
|
||||
name = "built-in power network interface"
|
||||
desc = "A built-in power network interface for machine-integrated electronic assemblies."
|
||||
complexity = 0
|
||||
size = 0
|
||||
spawn_flags = 0
|
||||
|
||||
/obj/item/integrated_circuit/passive/power/powernet/Initialize()
|
||||
IO = new(src)
|
||||
return ..()
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
/*
|
||||
* subtypes/arithmetic.dm
|
||||
* Arithmetic circuits for numeric operations and math transformations.
|
||||
*/
|
||||
|
||||
//These circuits do simple math.
|
||||
/obj/item/integrated_circuit/arithmetic
|
||||
complexity = 1
|
||||
@@ -13,7 +18,7 @@
|
||||
)
|
||||
outputs = list("result" = IC_PINTYPE_NUMBER)
|
||||
activators = list("compute" = IC_PINTYPE_PULSE_IN, "on computed" = IC_PINTYPE_PULSE_OUT)
|
||||
category_text = "Arithmetic"
|
||||
category_text = "MATH - Arithmetic"
|
||||
power_draw_per_use = 50 // Math is pretty cheap.
|
||||
|
||||
// +Adding+ //
|
||||
@@ -21,7 +26,7 @@
|
||||
/obj/item/integrated_circuit/arithmetic/addition
|
||||
name = "addition circuit"
|
||||
desc = "This circuit can add numbers together."
|
||||
extended_desc = "The order that the calculation goes is;<br>\
|
||||
extended_desc = "Calculation order:<br>\
|
||||
result = ((((A + B) + C) + D) ... ) and so on, until all pins have been added. \
|
||||
Null pins are ignored."
|
||||
icon_state = "addition"
|
||||
@@ -43,7 +48,7 @@
|
||||
/obj/item/integrated_circuit/arithmetic/subtraction
|
||||
name = "subtraction circuit"
|
||||
desc = "This circuit can subtract numbers."
|
||||
extended_desc = "The order that the calculation goes is;<br>\
|
||||
extended_desc = "Calculation order:<br>\
|
||||
result = ((((A - B) - C) - D) ... ) and so on, until all pins have been subtracted. \
|
||||
Null pins are ignored. Pin A <b>must</b> be a number or the circuit will not function."
|
||||
icon_state = "subtraction"
|
||||
@@ -71,7 +76,7 @@
|
||||
/obj/item/integrated_circuit/arithmetic/multiplication
|
||||
name = "multiplication circuit"
|
||||
desc = "This circuit can multiply numbers."
|
||||
extended_desc = "The order that the calculation goes is;<br>\
|
||||
extended_desc = "Calculation order:<br>\
|
||||
result = ((((A * B) * C) * D) ... ) and so on, until all pins have been multiplied. \
|
||||
Null pins are ignored. Pin A <b>must</b> be a number or the circuit will not function."
|
||||
icon_state = "multiplication"
|
||||
@@ -98,8 +103,8 @@
|
||||
|
||||
/obj/item/integrated_circuit/arithmetic/division
|
||||
name = "division circuit"
|
||||
desc = "This circuit can divide numbers, just don't think about trying to divide by zero!"
|
||||
extended_desc = "The order that the calculation goes is;<br>\
|
||||
desc = "Divides one number by another. Division by zero is not valid."
|
||||
extended_desc = "Calculation order:<br>\
|
||||
result = ((((A / B) / C) / D) ... ) and so on, until all pins have been divided. \
|
||||
Null pins, and pins containing 0, are ignored. Pin A <b>must</b> be a number or the circuit will not function."
|
||||
icon_state = "division"
|
||||
@@ -146,8 +151,8 @@
|
||||
|
||||
/obj/item/integrated_circuit/arithmetic/sign
|
||||
name = "sign circuit"
|
||||
desc = "This will say if a number is positive, negative, or zero."
|
||||
extended_desc = "Will output 1, -1, or 0, depending on if A is a postive number, a negative number, or zero, respectively."
|
||||
desc = "Outputs whether a number is positive, negative, or zero."
|
||||
extended_desc = "Outputs 1 for positive numbers, -1 for negative numbers, and 0 for zero."
|
||||
icon_state = "sign"
|
||||
inputs = list("A" = IC_PINTYPE_NUMBER)
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
@@ -196,7 +201,7 @@
|
||||
|
||||
/obj/item/integrated_circuit/arithmetic/absolute
|
||||
name = "absolute circuit"
|
||||
desc = "This outputs a non-negative version of the number you put in. This may also be thought of as its distance from zero."
|
||||
desc = "Outputs the absolute value of A."
|
||||
icon_state = "absolute"
|
||||
inputs = list("A" = IC_PINTYPE_NUMBER)
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
@@ -212,12 +217,70 @@
|
||||
push_data()
|
||||
activate_pin(2)
|
||||
|
||||
// Clamp and deadband //
|
||||
|
||||
/obj/item/integrated_circuit/arithmetic/clamp_deadband
|
||||
name = "clamp and deadband circuit"
|
||||
desc = "Clamps a number to a range and reports whether it is inside an optional deadband."
|
||||
extended_desc = "If minimum and maximum are entered backward, they are swapped. Deadband radius values at or below zero disable the deadband check."
|
||||
icon_state = "comparator"
|
||||
complexity = 2
|
||||
inputs = list(
|
||||
"value" = IC_PINTYPE_NUMBER,
|
||||
"minimum" = IC_PINTYPE_NUMBER,
|
||||
"maximum" = IC_PINTYPE_NUMBER,
|
||||
"deadband center" = IC_PINTYPE_NUMBER,
|
||||
"deadband radius" = IC_PINTYPE_NUMBER
|
||||
)
|
||||
outputs = list(
|
||||
"clamped value" = IC_PINTYPE_NUMBER,
|
||||
"in range" = IC_PINTYPE_BOOLEAN,
|
||||
"inside deadband" = IC_PINTYPE_BOOLEAN
|
||||
)
|
||||
activators = list(
|
||||
"process" = IC_PINTYPE_PULSE_IN,
|
||||
"on processed" = IC_PINTYPE_PULSE_OUT
|
||||
)
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
|
||||
/obj/item/integrated_circuit/arithmetic/clamp_deadband/do_work()
|
||||
var/value = get_pin_data(IC_INPUT, 1)
|
||||
var/minimum = get_pin_data(IC_INPUT, 2)
|
||||
var/maximum = get_pin_data(IC_INPUT, 3)
|
||||
var/deadband_center = get_pin_data(IC_INPUT, 4)
|
||||
var/deadband_radius = get_pin_data(IC_INPUT, 5)
|
||||
|
||||
if(!isnum(value))
|
||||
value = 0
|
||||
if(!isnum(minimum))
|
||||
minimum = value
|
||||
if(!isnum(maximum))
|
||||
maximum = value
|
||||
|
||||
if(minimum > maximum)
|
||||
var/swap_value = minimum
|
||||
minimum = maximum
|
||||
maximum = swap_value
|
||||
|
||||
var/clamped_value = clamp(value, minimum, maximum)
|
||||
var/in_range = (value >= minimum && value <= maximum)
|
||||
var/inside_deadband = FALSE
|
||||
|
||||
if(isnum(deadband_center) && isnum(deadband_radius) && deadband_radius > 0)
|
||||
inside_deadband = abs(value - deadband_center) <= abs(deadband_radius)
|
||||
|
||||
set_pin_data(IC_OUTPUT, 1, clamped_value)
|
||||
set_pin_data(IC_OUTPUT, 2, in_range)
|
||||
set_pin_data(IC_OUTPUT, 3, inside_deadband)
|
||||
push_data()
|
||||
activate_pin(2)
|
||||
|
||||
// Averaging //
|
||||
|
||||
/obj/item/integrated_circuit/arithmetic/average
|
||||
name = "average circuit"
|
||||
desc = "This circuit is of average quality, however it will compute the average for numbers you give it."
|
||||
extended_desc = "Note that null pins are ignored, where as a pin containing 0 is included in the averaging calculation."
|
||||
desc = "Calculates the average of the provided numeric inputs."
|
||||
extended_desc = "Note that null pins are ignored, whereas a pin containing 0 is included in the averaging calculation."
|
||||
icon_state = "average"
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
|
||||
@@ -240,7 +303,7 @@
|
||||
// Pi, because why the hell not? //
|
||||
/obj/item/integrated_circuit/arithmetic/pi
|
||||
name = "pi constant circuit"
|
||||
desc = "Not recommended for cooking. Outputs '3.14159' when it receives a pulse."
|
||||
desc = "Outputs the numeric constant pi when pulsed."
|
||||
icon_state = "pi"
|
||||
inputs = list()
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
@@ -253,7 +316,7 @@
|
||||
// Random //
|
||||
/obj/item/integrated_circuit/arithmetic/random
|
||||
name = "random number generator circuit"
|
||||
desc = "This gives a random (integer) number between values A and B inclusive."
|
||||
desc = "Outputs a random integer between A and B, inclusive."
|
||||
extended_desc = "'Inclusive' means that the upper bound is included in the range of numbers, e.g. L = 1 and H = 3 will allow \
|
||||
for outputs of 1, 2, or 3. H being the higher number is not <i>strictly</i> required."
|
||||
icon_state = "random"
|
||||
@@ -276,7 +339,7 @@
|
||||
|
||||
/obj/item/integrated_circuit/arithmetic/square_root
|
||||
name = "square root circuit"
|
||||
desc = "This outputs the square root of a number you put in."
|
||||
desc = "Outputs the square root of A."
|
||||
icon_state = "square_root"
|
||||
inputs = list("A" = IC_PINTYPE_NUMBER)
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
@@ -285,7 +348,7 @@
|
||||
var/result = 0
|
||||
for(var/datum/integrated_io/I in inputs)
|
||||
I.pull_data()
|
||||
if(isnum(I.data))
|
||||
if(isnum(I.data) && I.data >= 0)
|
||||
result = sqrt(I.data)
|
||||
|
||||
set_pin_data(IC_OUTPUT, 1, result)
|
||||
@@ -296,7 +359,7 @@
|
||||
|
||||
/obj/item/integrated_circuit/arithmetic/modulo
|
||||
name = "modulo circuit"
|
||||
desc = "Gets the remainder of A / B."
|
||||
desc = "Outputs the remainder of A divided by B."
|
||||
icon_state = "modulo"
|
||||
inputs = list("A" = IC_PINTYPE_NUMBER, "B" = IC_PINTYPE_NUMBER)
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
@@ -316,7 +379,7 @@
|
||||
|
||||
/obj/item/integrated_circuit/arithmetic/min
|
||||
name = "min circuit"
|
||||
desc = "This outputs the smallest of the numbers you put in."
|
||||
desc = "Outputs the smallest provided number."
|
||||
// The states are rarely used symbols for the operations
|
||||
// Letters didn't fit as well
|
||||
icon_state = "min"
|
||||
@@ -329,6 +392,9 @@
|
||||
if(isnum(I.data))
|
||||
values.Add(I.data)
|
||||
|
||||
if(!length(values))
|
||||
return
|
||||
|
||||
set_pin_data(IC_OUTPUT, 1, min(values))
|
||||
push_data()
|
||||
activate_pin(2)
|
||||
@@ -337,7 +403,7 @@
|
||||
|
||||
/obj/item/integrated_circuit/arithmetic/max
|
||||
name = "max circuit"
|
||||
desc = "This outputs the biggest of the numbers you put in."
|
||||
desc = "Outputs the largest provided number."
|
||||
icon_state = "max"
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
|
||||
@@ -348,6 +414,9 @@
|
||||
if(isnum(I.data))
|
||||
values.Add(I.data)
|
||||
|
||||
if(!length(values))
|
||||
return
|
||||
|
||||
set_pin_data(IC_OUTPUT, 1, max(values))
|
||||
push_data()
|
||||
activate_pin(2)
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
/*
|
||||
* subtypes/built_in.dm
|
||||
* Built-in non-removable circuits used by assemblies to expose internal behavior to normal circuit networks.
|
||||
*/
|
||||
|
||||
/obj/item/integrated_circuit/built_in
|
||||
name = "integrated circuit"
|
||||
desc = "It's a tiny chip! This one doesn't seem to do much, however."
|
||||
desc = "A base integrated circuit component."
|
||||
icon = 'icons/obj/assemblies/electronic_components.dmi'
|
||||
icon_state = "template"
|
||||
size = -1
|
||||
@@ -9,7 +14,7 @@
|
||||
|
||||
/obj/item/integrated_circuit/built_in/device_input
|
||||
name = "assembly input"
|
||||
desc = "A built in chip for handling pulses from attached assembly items."
|
||||
desc = "A built-in chip for handling pulses from attached assembly items."
|
||||
complexity = 0 //This acts as a limitation on building machines, more resource-intensive components cost more 'space'.
|
||||
activators = list("on pulsed" = IC_PINTYPE_PULSE_OUT)
|
||||
|
||||
@@ -18,7 +23,7 @@
|
||||
|
||||
/obj/item/integrated_circuit/built_in/device_output
|
||||
name = "assembly out"
|
||||
desc = "A built in chip for pulsing attached assembly items."
|
||||
desc = "A built-in chip for pulsing attached assembly items."
|
||||
complexity = 0 //This acts as a limitation on building machines, more resource-intensive components cost more 'space'.
|
||||
activators = list("pulse attached" = IC_PINTYPE_PULSE_IN)
|
||||
|
||||
@@ -30,7 +35,7 @@
|
||||
// Triggered when clothing assembly's hud button is clicked, used in-hand, or when another clothing-specific interaction occurs (like touching something with gloves on).
|
||||
/obj/item/integrated_circuit/built_in/action_button
|
||||
name = "external trigger circuit"
|
||||
desc = "A built in chip that outputs a pulse when an external control event occurs. It also provides additional data depending on the nature of the event and device."
|
||||
desc = "A built-in chip that outputs a pulse when an external control event occurs. It also provides additional data depending on the nature of the event and device."
|
||||
extended_desc = "This outputs a pulse if the assembly's HUD button is clicked while the assembly is closed."
|
||||
complexity = 0
|
||||
activators = list("on activation" = IC_PINTYPE_PULSE_OUT)
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
/*
|
||||
* subtypes/converters.dm
|
||||
* Converter circuits that translate between numbers, strings, booleans, directions, colors, and other pin formats.
|
||||
*/
|
||||
|
||||
//These circuits convert one variable to another.
|
||||
/obj/item/integrated_circuit/converter
|
||||
complexity = 2
|
||||
@@ -10,7 +15,7 @@
|
||||
/obj/item/integrated_circuit/converter/num2text
|
||||
name = "number to string"
|
||||
desc = "This circuit can convert a number variable into a string."
|
||||
extended_desc = "Because of game limitations null/false variables will output a '0' string."
|
||||
extended_desc = "Null or false-equivalent inputs output as the text value '0'."
|
||||
complexity = 1
|
||||
icon_state = "num-string"
|
||||
inputs = list("input" = IC_PINTYPE_NUMBER)
|
||||
@@ -33,7 +38,8 @@
|
||||
/obj/item/integrated_circuit/converter/num2text4
|
||||
name = "4-way number to string"
|
||||
desc = "This circuit can convert up to four number variables into strings."
|
||||
extended_desc = "Because of game limitations null/false variables will output a '0' string."
|
||||
extended_desc = "Null or false-equivalent inputs output as the text value '0'."
|
||||
complexity = 2
|
||||
icon_state = "num-string"
|
||||
inputs = list(
|
||||
"input 1" = IC_PINTYPE_NUMBER,
|
||||
@@ -69,7 +75,7 @@
|
||||
/obj/item/integrated_circuit/converter/num2text8
|
||||
name = "8-way number to string"
|
||||
desc = "This circuit can convert up to eight number variables into strings."
|
||||
extended_desc = "Because of game limitations null/false variables will output a '0' string."
|
||||
extended_desc = "Null or false-equivalent inputs output as the text value '0'."
|
||||
complexity = 4
|
||||
icon_state = "num-string"
|
||||
inputs = list(
|
||||
@@ -116,7 +122,11 @@
|
||||
desc = "This circuit can convert a string variable into a number."
|
||||
icon_state = "string-num"
|
||||
inputs = list("input" = IC_PINTYPE_STRING)
|
||||
outputs = list("output" = IC_PINTYPE_NUMBER)
|
||||
outputs = list(
|
||||
"output" = IC_PINTYPE_NUMBER,
|
||||
"valid" = IC_PINTYPE_BOOLEAN,
|
||||
"status" = IC_PINTYPE_STRING
|
||||
)
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
|
||||
/obj/item/integrated_circuit/converter/text2num/do_work()
|
||||
@@ -126,7 +136,10 @@
|
||||
if(!isnull(incoming))
|
||||
result = text2num(incoming)
|
||||
|
||||
var/valid = isnum(result)
|
||||
set_pin_data(IC_OUTPUT, 1, result)
|
||||
set_pin_data(IC_OUTPUT, 2, valid)
|
||||
set_pin_data(IC_OUTPUT, 3, valid ? "Number parsed." : "Input is not a number.")
|
||||
push_data()
|
||||
activate_pin(2)
|
||||
|
||||
@@ -149,9 +162,80 @@
|
||||
push_data()
|
||||
activate_pin(2)
|
||||
|
||||
/obj/item/integrated_circuit/converter/ref_exists
|
||||
name = "reference exists"
|
||||
desc = "Checks whether a reference currently points to a valid atom."
|
||||
icon_state = "ref-string"
|
||||
inputs = list("input" = IC_PINTYPE_REF)
|
||||
outputs = list(
|
||||
"exists" = IC_PINTYPE_BOOLEAN,
|
||||
"resolved ref" = IC_PINTYPE_REF
|
||||
)
|
||||
activators = list(
|
||||
"convert" = IC_PINTYPE_PULSE_IN,
|
||||
"on convert" = IC_PINTYPE_PULSE_OUT,
|
||||
"on valid" = IC_PINTYPE_PULSE_OUT,
|
||||
"on invalid" = IC_PINTYPE_PULSE_OUT
|
||||
)
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
|
||||
/obj/item/integrated_circuit/converter/ref_exists/do_work()
|
||||
var/atom/A = get_pin_data_as_type(IC_INPUT, 1, /atom)
|
||||
var/valid = !!A
|
||||
|
||||
set_pin_data(IC_OUTPUT, 1, valid)
|
||||
set_pin_data(IC_OUTPUT, 2, valid ? A : null)
|
||||
push_data()
|
||||
activate_pin(2)
|
||||
activate_pin(valid ? 3 : 4)
|
||||
|
||||
/obj/item/integrated_circuit/converter/ref_to_coords
|
||||
name = "reference to coordinates"
|
||||
desc = "Converts a reference into absolute X, Y, Z coordinates and its turf reference."
|
||||
icon_state = "ref-string"
|
||||
inputs = list("input" = IC_PINTYPE_REF)
|
||||
outputs = list(
|
||||
"X" = IC_PINTYPE_NUMBER,
|
||||
"Y" = IC_PINTYPE_NUMBER,
|
||||
"Z" = IC_PINTYPE_NUMBER,
|
||||
"turf" = IC_PINTYPE_REF,
|
||||
"valid" = IC_PINTYPE_BOOLEAN,
|
||||
"status" = IC_PINTYPE_STRING
|
||||
)
|
||||
activators = list(
|
||||
"convert" = IC_PINTYPE_PULSE_IN,
|
||||
"on convert" = IC_PINTYPE_PULSE_OUT,
|
||||
"on valid" = IC_PINTYPE_PULSE_OUT,
|
||||
"on invalid" = IC_PINTYPE_PULSE_OUT
|
||||
)
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
|
||||
/obj/item/integrated_circuit/converter/ref_to_coords/do_work()
|
||||
var/atom/A = get_pin_data_as_type(IC_INPUT, 1, /atom)
|
||||
var/turf/T = A ? get_turf(A) : null
|
||||
|
||||
set_pin_data(IC_OUTPUT, 1, null)
|
||||
set_pin_data(IC_OUTPUT, 2, null)
|
||||
set_pin_data(IC_OUTPUT, 3, null)
|
||||
set_pin_data(IC_OUTPUT, 4, null)
|
||||
set_pin_data(IC_OUTPUT, 5, FALSE)
|
||||
set_pin_data(IC_OUTPUT, 6, "Invalid reference.")
|
||||
|
||||
if(T)
|
||||
set_pin_data(IC_OUTPUT, 1, T.x)
|
||||
set_pin_data(IC_OUTPUT, 2, T.y)
|
||||
set_pin_data(IC_OUTPUT, 3, T.z)
|
||||
set_pin_data(IC_OUTPUT, 4, T)
|
||||
set_pin_data(IC_OUTPUT, 5, TRUE)
|
||||
set_pin_data(IC_OUTPUT, 6, "Coordinates converted.")
|
||||
|
||||
push_data()
|
||||
activate_pin(2)
|
||||
activate_pin(T ? 3 : 4)
|
||||
|
||||
/obj/item/integrated_circuit/converter/lowercase
|
||||
name = "lowercase string converter"
|
||||
desc = "this will cause a string to come out in all lowercase."
|
||||
desc = "Converts text to lowercase."
|
||||
icon_state = "lowercase"
|
||||
inputs = list("input" = IC_PINTYPE_STRING)
|
||||
outputs = list("output" = IC_PINTYPE_STRING)
|
||||
@@ -170,7 +254,7 @@
|
||||
|
||||
/obj/item/integrated_circuit/converter/uppercase
|
||||
name = "uppercase string converter"
|
||||
desc = "THIS WILL CAUSE A STRING TO COME OUT IN ALL UPPERCASE."
|
||||
desc = "Converts text to uppercase."
|
||||
icon_state = "uppercase"
|
||||
inputs = list("input" = IC_PINTYPE_STRING)
|
||||
outputs = list("output" = IC_PINTYPE_STRING)
|
||||
@@ -189,7 +273,7 @@
|
||||
|
||||
/obj/item/integrated_circuit/converter/concatenator
|
||||
name = "concatenator"
|
||||
desc = "This joins many strings together to get one big string."
|
||||
desc = "Joins multiple text inputs into one text output."
|
||||
complexity = 4
|
||||
inputs = list(
|
||||
"A" = IC_PINTYPE_STRING,
|
||||
@@ -218,8 +302,8 @@
|
||||
|
||||
/obj/item/integrated_circuit/converter/separator
|
||||
name = "separator"
|
||||
desc = "This splits as single string into two at the relative split point."
|
||||
extended_desc = "This circuits splits a given string into two, based on the string, and the index value. \
|
||||
desc = "Splits a text input into two outputs at the selected position."
|
||||
extended_desc = "This circuit splits a given string into two, based on the string, and the index value. \
|
||||
The index splits the string <b>after</b> the given index, including spaces. So 'a person' with an index of '3' \
|
||||
will split into 'a p' and 'erson'."
|
||||
complexity = 4
|
||||
@@ -252,7 +336,7 @@
|
||||
|
||||
/obj/item/integrated_circuit/converter/findstring
|
||||
name = "find text"
|
||||
desc = "This gives position of sample in the string. Or returns 0."
|
||||
desc = "Outputs the position of a sample text within the input text, or 0 if it is not found."
|
||||
extended_desc = "The first pin is the string to be examined. The second pin is the sample to be found. \
|
||||
For example, 'eat this burger',' ' will give you position 4. This circuit isn't case sensitive."
|
||||
complexity = 4
|
||||
@@ -297,43 +381,6 @@
|
||||
|
||||
activate_pin(2)
|
||||
|
||||
/obj/item/integrated_circuit/converter/radians2degrees
|
||||
name = "radians to degrees converter"
|
||||
desc = "Converts radians to degrees."
|
||||
inputs = list("radian" = IC_PINTYPE_NUMBER)
|
||||
outputs = list("degrees" = IC_PINTYPE_NUMBER)
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
|
||||
/obj/item/integrated_circuit/converter/radians2degrees/do_work()
|
||||
var/result = null
|
||||
pull_data()
|
||||
var/incoming = get_pin_data(IC_INPUT, 1)
|
||||
if(!isnull(incoming))
|
||||
result = TO_DEGREES(incoming)
|
||||
|
||||
set_pin_data(IC_OUTPUT, 1, result)
|
||||
push_data()
|
||||
activate_pin(2)
|
||||
|
||||
/obj/item/integrated_circuit/converter/degrees2radians
|
||||
name = "degrees to radians converter"
|
||||
desc = "Converts degrees to radians."
|
||||
inputs = list("degrees" = IC_PINTYPE_NUMBER)
|
||||
outputs = list("radians" = IC_PINTYPE_NUMBER)
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
|
||||
/obj/item/integrated_circuit/converter/degrees2radians/do_work()
|
||||
var/result = null
|
||||
pull_data()
|
||||
var/incoming = get_pin_data(IC_INPUT, 1)
|
||||
if(!isnull(incoming))
|
||||
result = TO_RADIANS(incoming)
|
||||
|
||||
set_pin_data(IC_OUTPUT, 1, result)
|
||||
push_data()
|
||||
activate_pin(2)
|
||||
|
||||
|
||||
/obj/item/integrated_circuit/converter/abs_to_rel_coords
|
||||
name = "abs to rel coordinate converter"
|
||||
desc = "Easily convert absolute coordinates to relative coordinates with this."
|
||||
@@ -365,6 +412,113 @@
|
||||
push_data()
|
||||
activate_pin(2)
|
||||
|
||||
/obj/item/integrated_circuit/converter/dir_to_vector
|
||||
name = "direction to vector"
|
||||
desc = "Converts a BYOND direction into a two-number X/Y movement vector."
|
||||
icon_state = "num-string"
|
||||
inputs = list("direction" = IC_PINTYPE_DIR)
|
||||
outputs = list(
|
||||
"X" = IC_PINTYPE_NUMBER,
|
||||
"Y" = IC_PINTYPE_NUMBER,
|
||||
"vector" = IC_PINTYPE_LIST,
|
||||
"valid" = IC_PINTYPE_BOOLEAN
|
||||
)
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
|
||||
/obj/item/integrated_circuit/converter/dir_to_vector/do_work()
|
||||
var/direction = get_pin_data(IC_INPUT, 1)
|
||||
var/x = 0
|
||||
var/y = 0
|
||||
|
||||
if(isnum(direction))
|
||||
if(direction & EAST)
|
||||
x++
|
||||
if(direction & WEST)
|
||||
x--
|
||||
if(direction & NORTH)
|
||||
y++
|
||||
if(direction & SOUTH)
|
||||
y--
|
||||
|
||||
set_pin_data(IC_OUTPUT, 1, x)
|
||||
set_pin_data(IC_OUTPUT, 2, y)
|
||||
set_pin_data(IC_OUTPUT, 3, list(x, y))
|
||||
set_pin_data(IC_OUTPUT, 4, isnum(direction) && (x || y))
|
||||
push_data()
|
||||
activate_pin(2)
|
||||
|
||||
/obj/item/integrated_circuit/converter/vector_to_dir
|
||||
name = "vector to direction"
|
||||
desc = "Converts X/Y vector components into a BYOND direction."
|
||||
icon_state = "num-string"
|
||||
inputs = list(
|
||||
"X" = IC_PINTYPE_NUMBER,
|
||||
"Y" = IC_PINTYPE_NUMBER
|
||||
)
|
||||
outputs = list(
|
||||
"direction" = IC_PINTYPE_DIR,
|
||||
"direction text" = IC_PINTYPE_STRING,
|
||||
"valid" = IC_PINTYPE_BOOLEAN
|
||||
)
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
|
||||
/obj/item/integrated_circuit/converter/vector_to_dir/do_work()
|
||||
var/x = get_pin_data(IC_INPUT, 1)
|
||||
var/y = get_pin_data(IC_INPUT, 2)
|
||||
var/direction = 0
|
||||
|
||||
if(isnum(x) && isnum(y))
|
||||
if(x > 0)
|
||||
direction |= EAST
|
||||
else if(x < 0)
|
||||
direction |= WEST
|
||||
if(y > 0)
|
||||
direction |= NORTH
|
||||
else if(y < 0)
|
||||
direction |= SOUTH
|
||||
|
||||
set_pin_data(IC_OUTPUT, 1, direction || null)
|
||||
set_pin_data(IC_OUTPUT, 2, direction ? dir2text(direction) : null)
|
||||
set_pin_data(IC_OUTPUT, 3, !!direction)
|
||||
push_data()
|
||||
activate_pin(2)
|
||||
|
||||
/obj/item/integrated_circuit/converter/delta_to_dir
|
||||
name = "delta to direction"
|
||||
desc = "Converts relative delta X/Y values into a BYOND direction."
|
||||
icon_state = "num-string"
|
||||
inputs = list(
|
||||
"delta X" = IC_PINTYPE_NUMBER,
|
||||
"delta Y" = IC_PINTYPE_NUMBER
|
||||
)
|
||||
outputs = list(
|
||||
"direction" = IC_PINTYPE_DIR,
|
||||
"direction text" = IC_PINTYPE_STRING,
|
||||
"valid" = IC_PINTYPE_BOOLEAN
|
||||
)
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
|
||||
/obj/item/integrated_circuit/converter/delta_to_dir/do_work()
|
||||
var/x = get_pin_data(IC_INPUT, 1)
|
||||
var/y = get_pin_data(IC_INPUT, 2)
|
||||
var/direction = 0
|
||||
|
||||
if(isnum(x) && isnum(y))
|
||||
if(x > 0)
|
||||
direction |= EAST
|
||||
else if(x < 0)
|
||||
direction |= WEST
|
||||
if(y > 0)
|
||||
direction |= NORTH
|
||||
else if(y < 0)
|
||||
direction |= SOUTH
|
||||
|
||||
set_pin_data(IC_OUTPUT, 1, direction || null)
|
||||
set_pin_data(IC_OUTPUT, 2, direction ? dir2text(direction) : null)
|
||||
set_pin_data(IC_OUTPUT, 3, !!direction)
|
||||
push_data()
|
||||
activate_pin(2)
|
||||
|
||||
/obj/item/integrated_circuit/converter/stringlength
|
||||
name = "len circuit"
|
||||
desc = "This circuit will return the number of characters in a string."
|
||||
|
||||
@@ -1,10 +1,15 @@
|
||||
/*
|
||||
* subtypes/data_transfer.dm
|
||||
* Data transfer circuits for copying, routing, packing, or unpacking values between pins.
|
||||
*/
|
||||
|
||||
/obj/item/integrated_circuit/transfer
|
||||
category_text = "Data Transfer"
|
||||
power_draw_per_use = 20
|
||||
|
||||
/obj/item/integrated_circuit/transfer/multiplexer
|
||||
name = "two multiplexer"
|
||||
desc = "This is what those in the business tend to refer to as a 'mux' or data selector. It moves data from one of the selected inputs to the output."
|
||||
desc = "Selects one input and sends that value to the output."
|
||||
extended_desc = "The first input pin is used to select which of the other input pins which has its data moved to the output. \
|
||||
If the input selection is outside the valid range then no output is given."
|
||||
complexity = 2
|
||||
@@ -58,7 +63,7 @@
|
||||
|
||||
/obj/item/integrated_circuit/transfer/demultiplexer
|
||||
name = "two demultiplexer"
|
||||
desc = "This is what those in the business tend to refer to as a 'demux'. It moves data from the input to one of the selected outputs."
|
||||
desc = "Sends one input value to the selected output."
|
||||
extended_desc = "The first input pin is used to select which of the output pins is given the data from the second input pin. \
|
||||
If the output selection is outside the valid range then no output is given."
|
||||
complexity = 2
|
||||
@@ -114,8 +119,8 @@
|
||||
|
||||
/obj/item/integrated_circuit/transfer/wireless
|
||||
name = "subspace transceiver"
|
||||
desc = "A wireless transmitter-receiver pair that can transmit data between devices."
|
||||
extended_desc = "The first input is the data to send to the other device, and the second input is the channel to send it on."
|
||||
desc = "Transmits data wirelessly between linked devices."
|
||||
extended_desc = "The first input is the data to send. The second input selects the transmission channel."
|
||||
complexity = 12
|
||||
spawn_flags = IC_SPAWN_RESEARCH
|
||||
icon_state = "bluespace"
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* subtypes/debug.dm
|
||||
* Debug/testing circuits used to inspect values, format helper output, and verify integrated electronics behavior.
|
||||
*/
|
||||
|
||||
/obj/item/integrated_circuit/debug
|
||||
category_text = "Debugging"
|
||||
complexity = 1
|
||||
spawn_flags = 0
|
||||
|
||||
/obj/item/integrated_circuit/debug/helper_test
|
||||
name = "helper test circuit"
|
||||
desc = "Tests integrated circuit helper procs."
|
||||
extended_desc = "Outputs formatted helper proc results from one input."
|
||||
icon_state = "template"
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
inputs = list(
|
||||
"input" = IC_PINTYPE_STRING,
|
||||
"number input" = IC_PINTYPE_STRING,
|
||||
"template" = IC_PINTYPE_STRING
|
||||
)
|
||||
outputs = list(
|
||||
"display value" = IC_PINTYPE_STRING,
|
||||
"type text" = IC_PINTYPE_STRING,
|
||||
"safe number" = IC_PINTYPE_NUMBER,
|
||||
"template output" = IC_PINTYPE_STRING
|
||||
)
|
||||
activators = list(
|
||||
"test" = IC_PINTYPE_PULSE_IN,
|
||||
"on tested" = IC_PINTYPE_PULSE_OUT
|
||||
)
|
||||
|
||||
/obj/item/integrated_circuit/debug/helper_test/do_work()
|
||||
pull_data()
|
||||
|
||||
var/input_value = get_pin_data(IC_INPUT, 1)
|
||||
var/number_value = get_pin_data(IC_INPUT, 2)
|
||||
var/template_value = get_pin_data(IC_INPUT, 3)
|
||||
|
||||
set_pin_data(IC_OUTPUT, 1, ic_display_value(input_value))
|
||||
set_pin_data(IC_OUTPUT, 2, ic_type_text(input_value))
|
||||
set_pin_data(IC_OUTPUT, 3, ic_safe_number(number_value, 0))
|
||||
set_pin_data(IC_OUTPUT, 4, ic_apply_template(template_value, input_value, number_value, ic_type_text(input_value)))
|
||||
|
||||
push_data()
|
||||
activate_pin(2)
|
||||
|
||||
/obj/item/integrated_circuit/debug/one_shot_pulse
|
||||
name = "one-shot pulse"
|
||||
desc = "Allows one pulse through, then blocks further pulses until reset."
|
||||
extended_desc = "This circuit is useful for preventing repeated signals. When triggered, it sends one pulse if it has not already fired. After firing, it will ignore further trigger pulses until the reset activator is pulsed."
|
||||
icon_state = "template"
|
||||
complexity = 2
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
size = 1
|
||||
power_draw_per_use = 50
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
|
||||
var/has_fired = FALSE
|
||||
|
||||
inputs = list(
|
||||
"enabled" = IC_PINTYPE_BOOLEAN
|
||||
)
|
||||
|
||||
outputs = list(
|
||||
"has fired" = IC_PINTYPE_BOOLEAN
|
||||
)
|
||||
|
||||
activators = list(
|
||||
"trigger" = IC_PINTYPE_PULSE_IN,
|
||||
"reset" = IC_PINTYPE_PULSE_IN,
|
||||
"pulse out" = IC_PINTYPE_PULSE_OUT,
|
||||
"blocked" = IC_PINTYPE_PULSE_OUT
|
||||
)
|
||||
|
||||
/obj/item/integrated_circuit/debug/one_shot_pulse/do_work(activator_id)
|
||||
var/active_pin = activator_id
|
||||
|
||||
if(istype(active_pin, /datum/integrated_io))
|
||||
active_pin = activators.Find(active_pin)
|
||||
|
||||
if(istext(active_pin))
|
||||
for(var/i = 1 to activators.len)
|
||||
var/datum/integrated_io/A = activators[i]
|
||||
if(A.name == active_pin)
|
||||
active_pin = i
|
||||
break
|
||||
|
||||
if(!isnum(active_pin))
|
||||
active_pin = 1
|
||||
|
||||
switch(active_pin)
|
||||
if(1)
|
||||
trigger_once()
|
||||
return
|
||||
if(2)
|
||||
reset_latch()
|
||||
return
|
||||
|
||||
/obj/item/integrated_circuit/debug/one_shot_pulse/proc/trigger_once()
|
||||
pull_data()
|
||||
|
||||
var/enabled = get_pin_data(IC_INPUT, 1)
|
||||
|
||||
if(!enabled)
|
||||
enabled = TRUE
|
||||
|
||||
if(!enabled)
|
||||
set_pin_data(IC_OUTPUT, 1, has_fired)
|
||||
push_data()
|
||||
activate_pin(4)
|
||||
return
|
||||
|
||||
if(has_fired)
|
||||
set_pin_data(IC_OUTPUT, 1, has_fired)
|
||||
push_data()
|
||||
activate_pin(4)
|
||||
return
|
||||
|
||||
has_fired = TRUE
|
||||
set_pin_data(IC_OUTPUT, 1, has_fired)
|
||||
push_data()
|
||||
activate_pin(3)
|
||||
|
||||
/obj/item/integrated_circuit/debug/one_shot_pulse/proc/reset_latch()
|
||||
has_fired = FALSE
|
||||
set_pin_data(IC_OUTPUT, 1, has_fired)
|
||||
push_data()
|
||||
|
||||
/obj/item/integrated_circuit/debug/one_shot_pulse/copy_clone_state_to(obj/item/integrated_circuit/target)
|
||||
var/obj/item/integrated_circuit/debug/one_shot_pulse/new_latch = target
|
||||
if(!istype(new_latch))
|
||||
return
|
||||
|
||||
new_latch.has_fired = has_fired
|
||||
|
||||
/obj/item/integrated_circuit/debug/blank
|
||||
name = "debug marker"
|
||||
desc = "A blank debug circuit. It does nothing and exists only as a movable, removable, renameable marker."
|
||||
extended_desc = "This circuit has no inputs, outputs, or activators. It is useful as a spacer, label, or visual divider inside an assembly."
|
||||
icon_state = "template"
|
||||
complexity = 0
|
||||
size = 0
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
|
||||
inputs = list()
|
||||
outputs = list()
|
||||
activators = list()
|
||||
|
||||
/obj/item/integrated_circuit/debug/blank/do_work()
|
||||
return
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,56 +1,114 @@
|
||||
//Insert slots allow items to be inserted into assemblies from outside
|
||||
//These items can then be used by other components
|
||||
/*
|
||||
* subtypes/insert_slot.dm
|
||||
* Insert-slot circuits that hold items and expose slot state, item references, and capacity information to the circuit network.
|
||||
*/
|
||||
|
||||
//Insert slots allow items to be inserted into assemblies from outside.
|
||||
//These items can then be used by other components through ref pins.
|
||||
|
||||
/obj/item/integrated_circuit/insert_slot
|
||||
category_text = "Insert slot"
|
||||
var/capacity = 0
|
||||
var/list/allowed_types = list()
|
||||
var/list/items_contained = list()
|
||||
activators = list("eject contents" = IC_PINTYPE_PULSE_IN)
|
||||
outputs = list("has item" = IC_PINTYPE_BOOLEAN)
|
||||
|
||||
activators = list(
|
||||
"eject contents" = IC_PINTYPE_PULSE_IN,
|
||||
"on inserted" = IC_PINTYPE_PULSE_OUT,
|
||||
"on ejected" = IC_PINTYPE_PULSE_OUT
|
||||
)
|
||||
|
||||
outputs = list(
|
||||
"has item" = IC_PINTYPE_BOOLEAN,
|
||||
"slot reference" = IC_PINTYPE_REF,
|
||||
"item reference" = IC_PINTYPE_REF,
|
||||
"item name" = IC_PINTYPE_STRING,
|
||||
"stored count" = IC_PINTYPE_NUMBER,
|
||||
"remaining capacity" = IC_PINTYPE_NUMBER
|
||||
)
|
||||
|
||||
power_draw_per_use = 10
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
size = 5
|
||||
complexity = 1
|
||||
|
||||
//call this function from components that want to get items from this component
|
||||
//set remove to FALSE if you dont want the item removed from the component and just want a reference to it
|
||||
//(e.g. for beakers)
|
||||
/obj/item/integrated_circuit/insert_slot/proc/get_item(var/remove = FALSE)
|
||||
if(items_contained.len > 0)
|
||||
var/itemToReturn = items_contained[1]
|
||||
if(remove)
|
||||
items_contained -= itemToReturn
|
||||
if(items_contained.len <= 0)
|
||||
set_pin_data(IC_OUTPUT, 1, FALSE)
|
||||
push_data()
|
||||
return itemToReturn
|
||||
/obj/item/integrated_circuit/insert_slot/Initialize()
|
||||
. = ..()
|
||||
items_contained = list()
|
||||
update_outputs()
|
||||
|
||||
/obj/item/integrated_circuit/insert_slot/interact(mob/user)
|
||||
update_outputs()
|
||||
. = ..()
|
||||
|
||||
/obj/item/integrated_circuit/insert_slot/proc/get_first_item()
|
||||
if(items_contained.len)
|
||||
return items_contained[1]
|
||||
return null
|
||||
|
||||
//Call this from components that want to get items from this component.
|
||||
//Set remove to FALSE if you do not want the item removed from the slot and just want a reference.
|
||||
/obj/item/integrated_circuit/insert_slot/proc/get_item(var/remove = FALSE)
|
||||
if(items_contained.len > 0)
|
||||
var/obj/item/item_to_return = items_contained[1]
|
||||
|
||||
if(remove)
|
||||
items_contained -= item_to_return
|
||||
update_outputs()
|
||||
push_data()
|
||||
|
||||
return item_to_return
|
||||
|
||||
return null
|
||||
|
||||
/obj/item/integrated_circuit/insert_slot/proc/update_outputs()
|
||||
var/obj/item/held_item = get_first_item()
|
||||
|
||||
set_pin_data(IC_OUTPUT, 1, !!held_item)
|
||||
set_pin_data(IC_OUTPUT, 2, src)
|
||||
set_pin_data(IC_OUTPUT, 3, held_item)
|
||||
set_pin_data(IC_OUTPUT, 4, held_item ? held_item.name : null)
|
||||
set_pin_data(IC_OUTPUT, 5, items_contained.len)
|
||||
set_pin_data(IC_OUTPUT, 6, max(capacity - items_contained.len, 0))
|
||||
|
||||
/obj/item/integrated_circuit/insert_slot/do_work()
|
||||
for(var/obj/item/O in items_contained)
|
||||
while(items_contained.len)
|
||||
var/obj/item/O = items_contained[1]
|
||||
items_contained -= O
|
||||
O.forceMove(get_turf(src))
|
||||
visible_message(SPAN_NOTICE("\The [src] drops [O] on the ground."))
|
||||
items_contained -= O
|
||||
set_pin_data(IC_OUTPUT, 1, FALSE)
|
||||
|
||||
update_outputs()
|
||||
push_data()
|
||||
activate_pin(3)
|
||||
return TRUE
|
||||
|
||||
/obj/item/integrated_circuit/insert_slot/proc/insert(var/obj/item/O, var/mob/user)
|
||||
if(is_type_in_list(O, allowed_types))
|
||||
if(items_contained.len >= capacity)
|
||||
to_chat(user, SPAN_WARNING("\The [src] is too full to add [O]."))
|
||||
return FALSE
|
||||
items_contained += O
|
||||
user.drop_from_inventory(O,src)
|
||||
to_chat(user, SPAN_NOTICE("You add [O] to \the [src]."))
|
||||
set_pin_data(IC_OUTPUT, 1, TRUE)
|
||||
return TRUE
|
||||
if(!O || !user)
|
||||
return FALSE
|
||||
|
||||
if(!is_type_in_list(O, allowed_types))
|
||||
return FALSE
|
||||
|
||||
if(items_contained.len >= capacity)
|
||||
to_chat(user, SPAN_WARNING("\The [src] is too full to add [O]."))
|
||||
return FALSE
|
||||
|
||||
items_contained += O
|
||||
user.drop_from_inventory(O, src)
|
||||
|
||||
to_chat(user, SPAN_NOTICE("You add [O] to \the [src]."))
|
||||
|
||||
update_outputs()
|
||||
push_data()
|
||||
activate_pin(2)
|
||||
return TRUE
|
||||
|
||||
/obj/item/integrated_circuit/insert_slot/paper_tray
|
||||
name = "paper tray"
|
||||
desc = "A simple paper tray similar to one from a printer."
|
||||
extended_desc = "A simple paper tray, paper can be inserted and used by other components. \
|
||||
Paper can be inserted through a slot in the casing. Holds 10 sheets"
|
||||
extended_desc = "A simple paper tray. Paper can be inserted and used by other components. Holds 10 sheets. \
|
||||
The slot reference output can be wired directly into printer paper-source inputs."
|
||||
capacity = 10
|
||||
size = 8
|
||||
power_draw_per_use = 30
|
||||
@@ -58,13 +116,336 @@
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
origin_tech = list(TECH_ENGINEERING = 2, TECH_MATERIAL = 2)
|
||||
|
||||
outputs = list(
|
||||
"has item" = IC_PINTYPE_BOOLEAN,
|
||||
"slot reference" = IC_PINTYPE_REF,
|
||||
"item reference" = IC_PINTYPE_REF,
|
||||
"item name" = IC_PINTYPE_STRING,
|
||||
"stored count" = IC_PINTYPE_NUMBER,
|
||||
"remaining capacity" = IC_PINTYPE_NUMBER,
|
||||
"top paper text" = IC_PINTYPE_STRING,
|
||||
"top paper used length" = IC_PINTYPE_NUMBER
|
||||
)
|
||||
|
||||
/obj/item/integrated_circuit/insert_slot/paper_tray/update_outputs()
|
||||
..()
|
||||
|
||||
var/obj/item/paper/P = get_first_item()
|
||||
|
||||
if(P)
|
||||
set_pin_data(IC_OUTPUT, 7, P.info)
|
||||
set_pin_data(IC_OUTPUT, 8, length(P.info))
|
||||
else
|
||||
set_pin_data(IC_OUTPUT, 7, null)
|
||||
set_pin_data(IC_OUTPUT, 8, 0)
|
||||
|
||||
/obj/item/integrated_circuit/insert_slot/beaker_holder
|
||||
name = "beaker holder"
|
||||
desc = "A slot for holding a beaker"
|
||||
extended_desc = "A slot for holding a beaker with reagents. \
|
||||
It has a bracket to hold the beaker in place and a lid to prevent spillage. \
|
||||
There is an extraction tube built into the lid"
|
||||
desc = "A slot for holding a beaker."
|
||||
extended_desc = "A slot for holding a beaker with reagents. It has a bracket to hold the beaker in place and a lid to prevent spillage. \
|
||||
The slot reference output can be wired directly into reagent pump source inputs."
|
||||
capacity = 1
|
||||
allowed_types = list(/obj/item/reagent_containers/glass/beaker)
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
origin_tech = list(TECH_ENGINEERING = 2, TECH_BIO = 2, TECH_MATERIAL = 2)
|
||||
|
||||
outputs = list(
|
||||
"has item" = IC_PINTYPE_BOOLEAN,
|
||||
"slot reference" = IC_PINTYPE_REF,
|
||||
"item reference" = IC_PINTYPE_REF,
|
||||
"item name" = IC_PINTYPE_STRING,
|
||||
"stored count" = IC_PINTYPE_NUMBER,
|
||||
"remaining capacity" = IC_PINTYPE_NUMBER,
|
||||
"reagent volume" = IC_PINTYPE_NUMBER,
|
||||
"maximum volume" = IC_PINTYPE_NUMBER,
|
||||
"free space" = IC_PINTYPE_NUMBER,
|
||||
"reagent names" = IC_PINTYPE_LIST
|
||||
)
|
||||
|
||||
/obj/item/integrated_circuit/insert_slot/beaker_holder/update_outputs()
|
||||
..()
|
||||
|
||||
var/obj/item/reagent_containers/glass/beaker/B = get_first_item()
|
||||
var/list/reagent_names = list()
|
||||
|
||||
if(B && B.reagents)
|
||||
for(var/_RE in B.reagents.reagent_volumes)
|
||||
var/singleton/reagent/RE = GET_SINGLETON(_RE)
|
||||
reagent_names += RE.name
|
||||
|
||||
set_pin_data(IC_OUTPUT, 7, B.reagents.total_volume)
|
||||
set_pin_data(IC_OUTPUT, 8, B.reagents.maximum_volume)
|
||||
set_pin_data(IC_OUTPUT, 9, REAGENTS_FREE_SPACE(B.reagents))
|
||||
set_pin_data(IC_OUTPUT, 10, reagent_names)
|
||||
else
|
||||
set_pin_data(IC_OUTPUT, 7, 0)
|
||||
set_pin_data(IC_OUTPUT, 8, 0)
|
||||
set_pin_data(IC_OUTPUT, 9, 0)
|
||||
set_pin_data(IC_OUTPUT, 10, list())
|
||||
|
||||
/obj/item/integrated_circuit/insert_slot/id_slot
|
||||
name = "ID card slot"
|
||||
desc = "A slot for holding and reading an ID card."
|
||||
extended_desc = "A narrow slot for holding a single ID card. Outputs the card reference, registered name, assignment, job title, corporation, and access list. \
|
||||
If credential caching is enabled, inserted access is copied to the assembly access card."
|
||||
capacity = 1
|
||||
size = 4
|
||||
power_draw_per_use = 15
|
||||
allowed_types = list(/obj/item/card/id)
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
origin_tech = list(TECH_ENGINEERING = 2, TECH_DATA = 2)
|
||||
|
||||
inputs = list(
|
||||
"enable credential cache" = IC_PINTYPE_BOOLEAN
|
||||
)
|
||||
|
||||
outputs = list(
|
||||
"has item" = IC_PINTYPE_BOOLEAN,
|
||||
"slot reference" = IC_PINTYPE_REF,
|
||||
"item reference" = IC_PINTYPE_REF,
|
||||
"item name" = IC_PINTYPE_STRING,
|
||||
"stored count" = IC_PINTYPE_NUMBER,
|
||||
"remaining capacity" = IC_PINTYPE_NUMBER,
|
||||
"registered name" = IC_PINTYPE_STRING,
|
||||
"assignment" = IC_PINTYPE_STRING,
|
||||
"job title" = IC_PINTYPE_STRING,
|
||||
"corporation" = IC_PINTYPE_STRING,
|
||||
"passkey" = IC_PINTYPE_LIST
|
||||
)
|
||||
|
||||
/obj/item/integrated_circuit/insert_slot/id_slot/insert(var/obj/item/O, var/mob/user)
|
||||
. = ..()
|
||||
if(.)
|
||||
cache_access_if_enabled(O)
|
||||
|
||||
/obj/item/integrated_circuit/insert_slot/id_slot/proc/cache_access_if_enabled(var/obj/item/I)
|
||||
if(!get_pin_data(IC_INPUT, 1))
|
||||
return
|
||||
|
||||
if(!assembly || !assembly.access_card)
|
||||
return
|
||||
|
||||
var/list/access = I.GetAccess()
|
||||
if(access)
|
||||
assembly.access_card.access |= access
|
||||
|
||||
/obj/item/integrated_circuit/insert_slot/id_slot/update_outputs()
|
||||
..()
|
||||
|
||||
var/obj/item/I = get_first_item()
|
||||
set_pin_data(IC_OUTPUT, 1, !!I)
|
||||
set_pin_data(IC_OUTPUT, 2, src)
|
||||
set_pin_data(IC_OUTPUT, 3, I)
|
||||
set_pin_data(IC_OUTPUT, 4, I ? I.name : null)
|
||||
set_pin_data(IC_OUTPUT, 5, I ? 1 : 0)
|
||||
set_pin_data(IC_OUTPUT, 6, I ? 0 : capacity)
|
||||
var/obj/item/card/id/card = null
|
||||
var/list/access = null
|
||||
|
||||
if(I)
|
||||
card = I.GetID()
|
||||
access = I.GetAccess()
|
||||
|
||||
if(card)
|
||||
var/list/split_assignment = ic_split_assignment(card.assignment)
|
||||
|
||||
set_pin_data(IC_OUTPUT, 7, card.registered_name)
|
||||
set_pin_data(IC_OUTPUT, 8, card.assignment)
|
||||
set_pin_data(IC_OUTPUT, 9, split_assignment["job title"])
|
||||
set_pin_data(IC_OUTPUT, 10, split_assignment["corporation"])
|
||||
set_pin_data(IC_OUTPUT, 11, access ? access : list())
|
||||
else
|
||||
set_pin_data(IC_OUTPUT, 7, null)
|
||||
set_pin_data(IC_OUTPUT, 8, null)
|
||||
set_pin_data(IC_OUTPUT, 9, null)
|
||||
set_pin_data(IC_OUTPUT, 10, null)
|
||||
set_pin_data(IC_OUTPUT, 11, list())
|
||||
|
||||
/obj/item/integrated_circuit/insert_slot/card_slot
|
||||
name = "card slot"
|
||||
desc = "A generic slot for holding and reading card-like objects."
|
||||
extended_desc = "A generic card slot. It accepts any card object, outputs the held item reference, and attempts to read access data from it."
|
||||
capacity = 1
|
||||
size = 4
|
||||
power_draw_per_use = 15
|
||||
allowed_types = list(/obj/item/card)
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
origin_tech = list(TECH_ENGINEERING = 2, TECH_DATA = 2)
|
||||
|
||||
inputs = list(
|
||||
"enable credential cache" = IC_PINTYPE_BOOLEAN
|
||||
)
|
||||
|
||||
outputs = list(
|
||||
"has item" = IC_PINTYPE_BOOLEAN,
|
||||
"slot reference" = IC_PINTYPE_REF,
|
||||
"item reference" = IC_PINTYPE_REF,
|
||||
"item name" = IC_PINTYPE_STRING,
|
||||
"stored count" = IC_PINTYPE_NUMBER,
|
||||
"remaining capacity" = IC_PINTYPE_NUMBER,
|
||||
"registered name" = IC_PINTYPE_STRING,
|
||||
"assignment" = IC_PINTYPE_STRING,
|
||||
"job title" = IC_PINTYPE_STRING,
|
||||
"corporation" = IC_PINTYPE_STRING,
|
||||
"passkey" = IC_PINTYPE_LIST,
|
||||
"has access data" = IC_PINTYPE_BOOLEAN
|
||||
)
|
||||
|
||||
/obj/item/integrated_circuit/insert_slot/card_slot/insert(var/obj/item/O, var/mob/user)
|
||||
. = ..()
|
||||
if(.)
|
||||
cache_access_if_enabled(O)
|
||||
|
||||
/obj/item/integrated_circuit/insert_slot/card_slot/proc/cache_access_if_enabled(var/obj/item/I)
|
||||
if(!get_pin_data(IC_INPUT, 1))
|
||||
return
|
||||
|
||||
if(!assembly || !assembly.access_card)
|
||||
return
|
||||
|
||||
var/list/access = I.GetAccess()
|
||||
if(access)
|
||||
assembly.access_card.access |= access
|
||||
|
||||
/obj/item/integrated_circuit/insert_slot/card_slot/update_outputs()
|
||||
..()
|
||||
|
||||
var/obj/item/I = get_first_item()
|
||||
var/obj/item/card/id/card = null
|
||||
var/list/access = null
|
||||
|
||||
if(I)
|
||||
card = I.GetID()
|
||||
access = I.GetAccess()
|
||||
|
||||
if(card)
|
||||
var/list/split_assignment = ic_split_assignment(card.assignment)
|
||||
|
||||
set_pin_data(IC_OUTPUT, 7, card.registered_name)
|
||||
set_pin_data(IC_OUTPUT, 8, card.assignment)
|
||||
set_pin_data(IC_OUTPUT, 9, split_assignment["job title"])
|
||||
set_pin_data(IC_OUTPUT, 10, split_assignment["corporation"])
|
||||
set_pin_data(IC_OUTPUT, 11, access ? access : list())
|
||||
set_pin_data(IC_OUTPUT, 12, TRUE)
|
||||
else
|
||||
set_pin_data(IC_OUTPUT, 7, null)
|
||||
set_pin_data(IC_OUTPUT, 8, null)
|
||||
set_pin_data(IC_OUTPUT, 9, null)
|
||||
set_pin_data(IC_OUTPUT, 10, null)
|
||||
set_pin_data(IC_OUTPUT, 11, access ? access : list())
|
||||
set_pin_data(IC_OUTPUT, 12, !!length(access))
|
||||
|
||||
/obj/item/integrated_circuit/insert_slot/power_cell_slot
|
||||
name = "power cell slot"
|
||||
desc = "A socket for holding and reading a power cell."
|
||||
extended_desc = "A reinforced socket that holds a single power cell. Outputs charge, maximum charge, and charge percentage."
|
||||
capacity = 1
|
||||
size = 7
|
||||
power_draw_per_use = 20
|
||||
allowed_types = list(
|
||||
/obj/item/cell,
|
||||
/obj/item/cell/device,
|
||||
/obj/item/cell/device/high
|
||||
)
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
origin_tech = list(TECH_ENGINEERING = 2, TECH_POWER = 3)
|
||||
|
||||
outputs = list(
|
||||
"has item" = IC_PINTYPE_BOOLEAN,
|
||||
"slot reference" = IC_PINTYPE_REF,
|
||||
"item reference" = IC_PINTYPE_REF,
|
||||
"item name" = IC_PINTYPE_STRING,
|
||||
"stored count" = IC_PINTYPE_NUMBER,
|
||||
"remaining capacity" = IC_PINTYPE_NUMBER,
|
||||
"cell charge" = IC_PINTYPE_NUMBER,
|
||||
"max charge" = IC_PINTYPE_NUMBER,
|
||||
"percentage" = IC_PINTYPE_NUMBER
|
||||
)
|
||||
|
||||
/obj/item/integrated_circuit/insert_slot/power_cell_slot/update_outputs()
|
||||
..()
|
||||
|
||||
var/obj/item/cell/C = get_first_item()
|
||||
|
||||
if(C)
|
||||
set_pin_data(IC_OUTPUT, 7, C.charge)
|
||||
set_pin_data(IC_OUTPUT, 8, C.maxcharge)
|
||||
set_pin_data(IC_OUTPUT, 9, C.percent())
|
||||
else
|
||||
set_pin_data(IC_OUTPUT, 7, 0)
|
||||
set_pin_data(IC_OUTPUT, 8, 0)
|
||||
set_pin_data(IC_OUTPUT, 9, 0)
|
||||
|
||||
|
||||
/obj/item/integrated_circuit/insert_slot/storage_slot
|
||||
name = "storage slot"
|
||||
desc = "A bracket for holding a storage container."
|
||||
extended_desc = "A bracket that can hold one storage item. Outputs the storage reference for scanner, grabber, sorter, or custom storage logic."
|
||||
capacity = 1
|
||||
size = 8
|
||||
power_draw_per_use = 25
|
||||
allowed_types = list(/obj/item/storage)
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
origin_tech = list(TECH_ENGINEERING = 2, TECH_MATERIAL = 2)
|
||||
|
||||
outputs = list(
|
||||
"has item" = IC_PINTYPE_BOOLEAN,
|
||||
"slot reference" = IC_PINTYPE_REF,
|
||||
"item reference" = IC_PINTYPE_REF,
|
||||
"item name" = IC_PINTYPE_STRING,
|
||||
"stored count" = IC_PINTYPE_NUMBER,
|
||||
"remaining capacity" = IC_PINTYPE_NUMBER,
|
||||
"storage reference" = IC_PINTYPE_REF,
|
||||
"contained item count" = IC_PINTYPE_NUMBER
|
||||
)
|
||||
|
||||
/obj/item/integrated_circuit/insert_slot/storage_slot/update_outputs()
|
||||
..()
|
||||
|
||||
var/obj/item/storage/S = get_first_item()
|
||||
|
||||
if(S)
|
||||
set_pin_data(IC_OUTPUT, 7, S)
|
||||
set_pin_data(IC_OUTPUT, 8, S.contents.len)
|
||||
else
|
||||
set_pin_data(IC_OUTPUT, 7, null)
|
||||
set_pin_data(IC_OUTPUT, 8, 0)
|
||||
|
||||
/obj/item/integrated_circuit/insert_slot/tool_slot
|
||||
name = "tool slot"
|
||||
desc = "A reinforced slot for holding a tool."
|
||||
extended_desc = "A utility slot that can hold one tool or general item. Outputs the held item reference for machines that require a physical tool."
|
||||
capacity = 1
|
||||
size = 6
|
||||
power_draw_per_use = 20
|
||||
allowed_types = list(/obj/item)
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
origin_tech = list(TECH_ENGINEERING = 2, TECH_MATERIAL = 2)
|
||||
|
||||
outputs = list(
|
||||
"has item" = IC_PINTYPE_BOOLEAN,
|
||||
"slot reference" = IC_PINTYPE_REF,
|
||||
"item reference" = IC_PINTYPE_REF,
|
||||
"item name" = IC_PINTYPE_STRING,
|
||||
"stored count" = IC_PINTYPE_NUMBER,
|
||||
"remaining capacity" = IC_PINTYPE_NUMBER,
|
||||
"tool reference" = IC_PINTYPE_REF
|
||||
)
|
||||
|
||||
/obj/item/integrated_circuit/insert_slot/tool_slot/update_outputs()
|
||||
..()
|
||||
|
||||
var/obj/item/I = get_first_item()
|
||||
set_pin_data(IC_OUTPUT, 7, I)
|
||||
|
||||
/obj/item/integrated_circuit/insert_slot/item_tray
|
||||
name = "general item tray"
|
||||
desc = "A generic tray for holding small items."
|
||||
extended_desc = "A broad item tray. It accepts ordinary items and exposes the held item reference, name, count, and remaining capacity. \
|
||||
Use this when a more specific insert slot does not exist."
|
||||
capacity = 5
|
||||
size = 8
|
||||
power_draw_per_use = 20
|
||||
allowed_types = list(/obj/item)
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
origin_tech = list(TECH_ENGINEERING = 2, TECH_MATERIAL = 2)
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
/*
|
||||
* subtypes/lists.dm
|
||||
* List circuits for creating, reading, writing, merging, filtering, and transforming list pin data.
|
||||
*/
|
||||
|
||||
//These circuits do things with lists, and use special list pins for stability.
|
||||
/obj/item/integrated_circuit/list
|
||||
complexity = 1
|
||||
@@ -9,27 +14,47 @@
|
||||
category_text = "Lists"
|
||||
power_draw_per_use = 200
|
||||
|
||||
|
||||
/obj/item/integrated_circuit/list/empty
|
||||
name = "empty list circuit"
|
||||
desc = "This circuit outputs an empty list."
|
||||
extended_desc = "Outputs an empty list that can be passed into append, write, and other list-editing circuits."
|
||||
inputs = list()
|
||||
outputs = list(
|
||||
"empty list" = IC_PINTYPE_LIST
|
||||
)
|
||||
icon_state = "addition"
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
|
||||
/obj/item/integrated_circuit/list/empty/do_work()
|
||||
set_pin_data(IC_OUTPUT, 1, list())
|
||||
push_data()
|
||||
activate_pin(2)
|
||||
|
||||
|
||||
/obj/item/integrated_circuit/list/pick
|
||||
name = "pick circuit"
|
||||
desc = "This circuit will randomly 'pick' an element from a list that is inputted."
|
||||
extended_desc = "Will output null if the list is empty. Input list is unmodified."
|
||||
extended_desc = "Outputs null if the list is empty. The input list is not changed."
|
||||
icon_state = "addition"
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
|
||||
/obj/item/integrated_circuit/list/pick/do_work()
|
||||
var/result = null
|
||||
var/list/input_list = get_pin_data(IC_INPUT, 1) // List pins guarantee that there is a list inside, even if just an empty one.
|
||||
if(input_list.len)
|
||||
var/list/input_list = get_pin_data(IC_INPUT, 1)
|
||||
|
||||
if(islist(input_list) && input_list.len)
|
||||
result = pick(input_list)
|
||||
|
||||
set_pin_data(IC_OUTPUT, 1, result)
|
||||
push_data()
|
||||
activate_pin(2)
|
||||
|
||||
|
||||
/obj/item/integrated_circuit/list/append
|
||||
name = "append circuit"
|
||||
desc = "This circuit will add an element to a list."
|
||||
extended_desc = "The new element will always be at the bottom of the list."
|
||||
extended_desc = "Adds the new element to the end of the list."
|
||||
inputs = list(
|
||||
"list to append" = IC_PINTYPE_LIST,
|
||||
"input" = IC_PINTYPE_ANY
|
||||
@@ -42,14 +67,105 @@
|
||||
|
||||
/obj/item/integrated_circuit/list/append/do_work()
|
||||
var/list/input_list = get_pin_data(IC_INPUT, 1)
|
||||
var/list/output_list = list()
|
||||
var/new_entry = get_pin_data(IC_INPUT, 2)
|
||||
output_list = input_list + new_entry
|
||||
var/list/output_list = islist(input_list) ? input_list.Copy() : list()
|
||||
var/new_entry = get_pin_data(IC_INPUT, 2, FALSE)
|
||||
|
||||
output_list += list(new_entry)
|
||||
|
||||
set_pin_data(IC_OUTPUT, 1, output_list)
|
||||
push_data()
|
||||
activate_pin(2)
|
||||
|
||||
|
||||
/obj/item/integrated_circuit/list/unique_append
|
||||
name = "unique append circuit"
|
||||
desc = "Appends a value only if the list does not already contain it."
|
||||
extended_desc = "The output list is copied from the input list and capped at the requested max length, up to a hard maximum of 64 entries."
|
||||
inputs = list(
|
||||
"list to append" = IC_PINTYPE_LIST,
|
||||
"input" = IC_PINTYPE_ANY,
|
||||
"max length" = IC_PINTYPE_NUMBER
|
||||
)
|
||||
inputs_default = list(
|
||||
"3" = 16
|
||||
)
|
||||
outputs = list(
|
||||
"appended list" = IC_PINTYPE_LIST,
|
||||
"appended" = IC_PINTYPE_BOOLEAN,
|
||||
"duplicate" = IC_PINTYPE_BOOLEAN,
|
||||
"full" = IC_PINTYPE_BOOLEAN,
|
||||
"length" = IC_PINTYPE_NUMBER
|
||||
)
|
||||
activators = list(
|
||||
"append" = IC_PINTYPE_PULSE_IN,
|
||||
"on appended" = IC_PINTYPE_PULSE_OUT,
|
||||
"on duplicate" = IC_PINTYPE_PULSE_OUT,
|
||||
"on full" = IC_PINTYPE_PULSE_OUT,
|
||||
"on invalid" = IC_PINTYPE_PULSE_OUT
|
||||
)
|
||||
icon_state = "addition"
|
||||
complexity = 3
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
|
||||
/obj/item/integrated_circuit/list/unique_append/do_work()
|
||||
var/list/input_list = get_pin_data(IC_INPUT, 1)
|
||||
var/new_entry = get_pin_data(IC_INPUT, 2, FALSE)
|
||||
var/max_length = get_pin_data(IC_INPUT, 3)
|
||||
|
||||
if(!islist(input_list))
|
||||
set_pin_data(IC_OUTPUT, 1, list())
|
||||
set_pin_data(IC_OUTPUT, 2, FALSE)
|
||||
set_pin_data(IC_OUTPUT, 3, FALSE)
|
||||
set_pin_data(IC_OUTPUT, 4, FALSE)
|
||||
set_pin_data(IC_OUTPUT, 5, 0)
|
||||
push_data()
|
||||
activate_pin(5)
|
||||
return
|
||||
|
||||
if(!isnum(max_length))
|
||||
max_length = 16
|
||||
max_length = clamp(round(max_length), 1, 64)
|
||||
|
||||
var/list/output_list = list()
|
||||
for(var/i = 1 to min(input_list.len, max_length))
|
||||
output_list += list(input_list[i])
|
||||
|
||||
var/appended = FALSE
|
||||
|
||||
// Match list_contains behavior so refs and display-equivalent primitive values do not create accidental duplicates.
|
||||
for(var/item in output_list)
|
||||
if(item == new_entry || "[item]" == "[new_entry]")
|
||||
set_pin_data(IC_OUTPUT, 1, output_list)
|
||||
set_pin_data(IC_OUTPUT, 2, FALSE)
|
||||
set_pin_data(IC_OUTPUT, 3, TRUE)
|
||||
set_pin_data(IC_OUTPUT, 4, FALSE)
|
||||
set_pin_data(IC_OUTPUT, 5, output_list.len)
|
||||
push_data()
|
||||
activate_pin(3)
|
||||
return
|
||||
|
||||
if(output_list.len >= max_length)
|
||||
set_pin_data(IC_OUTPUT, 1, output_list)
|
||||
set_pin_data(IC_OUTPUT, 2, FALSE)
|
||||
set_pin_data(IC_OUTPUT, 3, FALSE)
|
||||
set_pin_data(IC_OUTPUT, 4, TRUE)
|
||||
set_pin_data(IC_OUTPUT, 5, output_list.len)
|
||||
push_data()
|
||||
activate_pin(4)
|
||||
return
|
||||
|
||||
output_list += list(new_entry)
|
||||
appended = TRUE
|
||||
|
||||
set_pin_data(IC_OUTPUT, 1, output_list)
|
||||
set_pin_data(IC_OUTPUT, 2, appended)
|
||||
set_pin_data(IC_OUTPUT, 3, FALSE)
|
||||
set_pin_data(IC_OUTPUT, 4, FALSE)
|
||||
set_pin_data(IC_OUTPUT, 5, output_list.len)
|
||||
push_data()
|
||||
activate_pin(2)
|
||||
|
||||
|
||||
/obj/item/integrated_circuit/list/search
|
||||
name = "search circuit"
|
||||
desc = "This circuit will give index of desired element in the list."
|
||||
@@ -67,10 +183,12 @@
|
||||
/obj/item/integrated_circuit/list/search/do_work()
|
||||
var/list/input_list = get_pin_data(IC_INPUT, 1)
|
||||
var/item = get_pin_data(IC_INPUT, 2)
|
||||
set_pin_data(IC_OUTPUT, 1, input_list.Find(item))
|
||||
|
||||
set_pin_data(IC_OUTPUT, 1, islist(input_list) ? input_list.Find(item) : 0)
|
||||
push_data()
|
||||
activate_pin(2)
|
||||
|
||||
|
||||
/obj/item/integrated_circuit/list/at
|
||||
name = "at circuit"
|
||||
desc = "This circuit will pick an element from a list by index."
|
||||
@@ -79,18 +197,102 @@
|
||||
"list" = IC_PINTYPE_LIST,
|
||||
"index" = IC_PINTYPE_NUMBER
|
||||
)
|
||||
outputs = list("item" = IC_PINTYPE_ANY)
|
||||
outputs = list(
|
||||
"item" = IC_PINTYPE_ANY,
|
||||
"valid" = IC_PINTYPE_BOOLEAN,
|
||||
"status" = IC_PINTYPE_STRING
|
||||
)
|
||||
icon_state = "addition"
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
|
||||
/obj/item/integrated_circuit/list/at/do_work()
|
||||
var/list/input_list = get_pin_data(IC_INPUT, 1)
|
||||
var/index = get_pin_data(IC_INPUT, 2)
|
||||
var/item = input_list[index]
|
||||
var/item = null
|
||||
var/valid = FALSE
|
||||
var/status = "Invalid index."
|
||||
|
||||
if(!islist(input_list))
|
||||
input_list = list()
|
||||
|
||||
if(!isnull(index))
|
||||
index = round(index)
|
||||
|
||||
if(index >= 1 && index <= input_list.len)
|
||||
item = input_list[index]
|
||||
valid = TRUE
|
||||
status = "Item read."
|
||||
else
|
||||
status = "Index out of range."
|
||||
|
||||
set_pin_data(IC_OUTPUT, 1, item)
|
||||
set_pin_data(IC_OUTPUT, 2, valid)
|
||||
set_pin_data(IC_OUTPUT, 3, status)
|
||||
push_data()
|
||||
activate_pin(2)
|
||||
|
||||
|
||||
/obj/item/integrated_circuit/list/ring_index
|
||||
name = "ring index circuit"
|
||||
desc = "Advances an index through a list and wraps safely at either end."
|
||||
extended_desc = "Outputs the wrapped next index and selected value. Empty lists return invalid without changing anything."
|
||||
inputs = list(
|
||||
"list" = IC_PINTYPE_LIST,
|
||||
"current index" = IC_PINTYPE_NUMBER,
|
||||
"step" = IC_PINTYPE_NUMBER
|
||||
)
|
||||
inputs_default = list(
|
||||
"2" = 0,
|
||||
"3" = 1
|
||||
)
|
||||
outputs = list(
|
||||
"next index" = IC_PINTYPE_NUMBER,
|
||||
"selected value" = IC_PINTYPE_ANY,
|
||||
"length" = IC_PINTYPE_NUMBER,
|
||||
"valid" = IC_PINTYPE_BOOLEAN
|
||||
)
|
||||
activators = list(
|
||||
"select" = IC_PINTYPE_PULSE_IN,
|
||||
"on selected" = IC_PINTYPE_PULSE_OUT,
|
||||
"on invalid" = IC_PINTYPE_PULSE_OUT
|
||||
)
|
||||
icon_state = "addition"
|
||||
complexity = 2
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
|
||||
/obj/item/integrated_circuit/list/ring_index/do_work()
|
||||
var/list/input_list = get_pin_data(IC_INPUT, 1)
|
||||
var/list_length = islist(input_list) ? input_list.len : 0
|
||||
|
||||
if(!list_length)
|
||||
set_pin_data(IC_OUTPUT, 1, null)
|
||||
set_pin_data(IC_OUTPUT, 2, null)
|
||||
set_pin_data(IC_OUTPUT, 3, 0)
|
||||
set_pin_data(IC_OUTPUT, 4, FALSE)
|
||||
push_data()
|
||||
activate_pin(3)
|
||||
return
|
||||
|
||||
var/current_index = get_pin_data(IC_INPUT, 2)
|
||||
var/step = get_pin_data(IC_INPUT, 3)
|
||||
|
||||
if(!isnum(current_index))
|
||||
current_index = 0
|
||||
if(!isnum(step))
|
||||
step = 1
|
||||
|
||||
var/next_index = ((round(current_index) + round(step) - 1) % list_length) + 1
|
||||
if(next_index < 1)
|
||||
next_index += list_length
|
||||
|
||||
set_pin_data(IC_OUTPUT, 1, next_index)
|
||||
set_pin_data(IC_OUTPUT, 2, input_list[next_index])
|
||||
set_pin_data(IC_OUTPUT, 3, list_length)
|
||||
set_pin_data(IC_OUTPUT, 4, TRUE)
|
||||
push_data()
|
||||
activate_pin(2)
|
||||
|
||||
|
||||
/obj/item/integrated_circuit/list/delete
|
||||
name = "delete circuit"
|
||||
desc = "This circuit will delete the element from a list by index."
|
||||
@@ -100,73 +302,183 @@
|
||||
"index" = IC_PINTYPE_NUMBER
|
||||
)
|
||||
outputs = list(
|
||||
"item" = IC_PINTYPE_LIST
|
||||
"redacted list" = IC_PINTYPE_LIST,
|
||||
"deleted" = IC_PINTYPE_BOOLEAN,
|
||||
"status" = IC_PINTYPE_STRING
|
||||
)
|
||||
icon_state = "addition"
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
|
||||
/obj/item/integrated_circuit/list/delete/do_work()
|
||||
var/list/input_list = get_pin_data(IC_INPUT, 1)
|
||||
var/list/red_list = list()
|
||||
var/list/output_list = islist(input_list) ? input_list.Copy() : list()
|
||||
var/index = get_pin_data(IC_INPUT, 2)
|
||||
var/j = 0
|
||||
for(var/I in input_list)
|
||||
j = j + 1
|
||||
if(j != index)
|
||||
red_list.Add(I)
|
||||
set_pin_data(IC_OUTPUT, 1, red_list)
|
||||
var/deleted = FALSE
|
||||
var/status = "Invalid index."
|
||||
|
||||
if(!isnull(index))
|
||||
index = round(index)
|
||||
|
||||
if(index >= 1 && index <= output_list.len)
|
||||
output_list.Cut(index, index + 1)
|
||||
deleted = TRUE
|
||||
status = "Item deleted."
|
||||
else
|
||||
status = "Index out of range."
|
||||
|
||||
set_pin_data(IC_OUTPUT, 1, output_list)
|
||||
set_pin_data(IC_OUTPUT, 2, deleted)
|
||||
set_pin_data(IC_OUTPUT, 3, status)
|
||||
push_data()
|
||||
activate_pin(2)
|
||||
|
||||
|
||||
/obj/item/integrated_circuit/list/write
|
||||
name = "write circuit"
|
||||
desc = "This circuit will write element in list with given index."
|
||||
extended_desc = "If there is no element with such index, it will give the same list, as before."
|
||||
desc = "This circuit will write an element into a list with a given index."
|
||||
extended_desc = "If the index is beyond the current list length, the list will expand with null entries until the index exists."
|
||||
inputs = list(
|
||||
"list" = IC_PINTYPE_LIST,
|
||||
"index" = IC_PINTYPE_NUMBER,
|
||||
"item" = IC_PINTYPE_ANY
|
||||
)
|
||||
outputs = list(
|
||||
"redacted list" = IC_PINTYPE_LIST
|
||||
"redacted list" = IC_PINTYPE_LIST,
|
||||
"written" = IC_PINTYPE_BOOLEAN,
|
||||
"status" = IC_PINTYPE_STRING
|
||||
)
|
||||
icon_state = "addition"
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
|
||||
/obj/item/integrated_circuit/list/write/do_work()
|
||||
var/list/input_list = get_pin_data(IC_INPUT, 1)
|
||||
var/list/output_list = islist(input_list) ? input_list.Copy() : list()
|
||||
var/index = get_pin_data(IC_INPUT, 2)
|
||||
var/item = get_pin_data(IC_INPUT, 3)
|
||||
input_list[index] = item
|
||||
set_pin_data(IC_OUTPUT, 1, input_list)
|
||||
var/written = FALSE
|
||||
var/status = "Invalid index."
|
||||
|
||||
if(!isnull(index))
|
||||
index = round(index)
|
||||
|
||||
if(index >= 1 && index <= IC_MAX_LIST_LENGTH)
|
||||
while(output_list.len < index)
|
||||
output_list.Add(null)
|
||||
|
||||
output_list[index] = item
|
||||
written = TRUE
|
||||
status = "Item written."
|
||||
else
|
||||
status = "Index out of range."
|
||||
|
||||
set_pin_data(IC_OUTPUT, 1, output_list)
|
||||
set_pin_data(IC_OUTPUT, 2, written)
|
||||
set_pin_data(IC_OUTPUT, 3, status)
|
||||
push_data()
|
||||
activate_pin(2)
|
||||
|
||||
|
||||
/obj/item/integrated_circuit/list/write4
|
||||
name = "4-way write circuit"
|
||||
desc = "This circuit writes up to four items into a list."
|
||||
extended_desc = "Each item is written directly to its matching list position. Item 1 writes to list position 1, item 2 writes to position 2, and so on."
|
||||
inputs = list(
|
||||
"list" = IC_PINTYPE_LIST,
|
||||
"item 1" = IC_PINTYPE_ANY,
|
||||
"item 2" = IC_PINTYPE_ANY,
|
||||
"item 3" = IC_PINTYPE_ANY,
|
||||
"item 4" = IC_PINTYPE_ANY
|
||||
)
|
||||
outputs = list(
|
||||
"redacted list" = IC_PINTYPE_LIST
|
||||
)
|
||||
icon_state = "addition"
|
||||
complexity = 2
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
|
||||
/obj/item/integrated_circuit/list/write4/do_work()
|
||||
var/list/input_list = get_pin_data(IC_INPUT, 1)
|
||||
var/list/output_list = islist(input_list) ? input_list.Copy() : list()
|
||||
|
||||
for(var/i = 1; i <= 4; i++)
|
||||
var/item = get_pin_data(IC_INPUT, i + 1)
|
||||
|
||||
while(output_list.len < i)
|
||||
output_list.Add(null)
|
||||
|
||||
output_list[i] = item
|
||||
|
||||
set_pin_data(IC_OUTPUT, 1, output_list)
|
||||
push_data()
|
||||
activate_pin(2)
|
||||
|
||||
|
||||
/obj/item/integrated_circuit/list/write8
|
||||
name = "8-way write circuit"
|
||||
desc = "This circuit writes up to eight items into a list."
|
||||
extended_desc = "Each item is written directly to its matching list position. Item 1 writes to list position 1, item 2 writes to position 2, and so on."
|
||||
inputs = list(
|
||||
"list" = IC_PINTYPE_LIST,
|
||||
"item 1" = IC_PINTYPE_ANY,
|
||||
"item 2" = IC_PINTYPE_ANY,
|
||||
"item 3" = IC_PINTYPE_ANY,
|
||||
"item 4" = IC_PINTYPE_ANY,
|
||||
"item 5" = IC_PINTYPE_ANY,
|
||||
"item 6" = IC_PINTYPE_ANY,
|
||||
"item 7" = IC_PINTYPE_ANY,
|
||||
"item 8" = IC_PINTYPE_ANY
|
||||
)
|
||||
outputs = list(
|
||||
"redacted list" = IC_PINTYPE_LIST
|
||||
)
|
||||
icon_state = "addition"
|
||||
complexity = 3
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
|
||||
/obj/item/integrated_circuit/list/write8/do_work()
|
||||
var/list/input_list = get_pin_data(IC_INPUT, 1)
|
||||
var/list/output_list = islist(input_list) ? input_list.Copy() : list()
|
||||
|
||||
for(var/i = 1; i <= 8; i++)
|
||||
var/item = get_pin_data(IC_INPUT, i + 1)
|
||||
|
||||
while(output_list.len < i)
|
||||
output_list.Add(null)
|
||||
|
||||
output_list[i] = item
|
||||
|
||||
set_pin_data(IC_OUTPUT, 1, output_list)
|
||||
push_data()
|
||||
activate_pin(2)
|
||||
|
||||
|
||||
/obj/item/integrated_circuit/list/len
|
||||
name = "len circuit"
|
||||
desc = "This circuit will give length of the list."
|
||||
inputs = list(
|
||||
"list" = IC_PINTYPE_LIST,
|
||||
)
|
||||
"list" = IC_PINTYPE_LIST
|
||||
)
|
||||
outputs = list(
|
||||
"item" = IC_PINTYPE_NUMBER
|
||||
"length" = IC_PINTYPE_NUMBER
|
||||
)
|
||||
icon_state = "addition"
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
|
||||
/obj/item/integrated_circuit/list/len/do_work()
|
||||
var/list/input_list = get_pin_data(IC_INPUT, 1)
|
||||
set_pin_data(IC_OUTPUT, 1, input_list.len)
|
||||
|
||||
set_pin_data(IC_OUTPUT, 1, islist(input_list) ? input_list.len : 0)
|
||||
push_data()
|
||||
activate_pin(2)
|
||||
|
||||
|
||||
/obj/item/integrated_circuit/list/jointext
|
||||
name = "join text circuit"
|
||||
desc = "This circuit will add all elements of a list into one string, seperated by a character."
|
||||
extended_desc = "Default settings will encode the entire list into a string."
|
||||
desc = "This circuit will add all elements of a list into one string, separated by a character."
|
||||
extended_desc = "Default settings will encode the entire list into a string. Mixed list values are converted to display text before joining."
|
||||
inputs = list(
|
||||
"list to join" = IC_PINTYPE_LIST,
|
||||
"delimiter" = IC_PINTYPE_CHAR,
|
||||
"delimiter" = IC_PINTYPE_STRING,
|
||||
"start" = IC_PINTYPE_NUMBER,
|
||||
"end" = IC_PINTYPE_NUMBER
|
||||
)
|
||||
@@ -189,9 +501,501 @@
|
||||
|
||||
var/result = null
|
||||
|
||||
if(input_list.len && delimiter && !isnull(start) && !isnull(end))
|
||||
result = jointext(input_list, delimiter, start, end)
|
||||
if(islist(input_list) && input_list.len && !isnull(delimiter) && !isnull(start) && !isnull(end))
|
||||
var/list/filtered_list = list()
|
||||
for(var/item in input_list)
|
||||
if(!isnull(item))
|
||||
filtered_list += item
|
||||
result = jointext(filtered_list, delimiter, start, end)
|
||||
|
||||
set_pin_data(IC_OUTPUT, 1, result)
|
||||
push_data()
|
||||
activate_pin(2)
|
||||
|
||||
|
||||
/obj/item/integrated_circuit/list/any_greater_than
|
||||
name = "any greater than circuit"
|
||||
desc = "This circuit checks whether any number in a list is greater than a target value."
|
||||
extended_desc = "Non-number values are ignored. Outputs true if at least one number in the list is greater than the comparison value."
|
||||
category_text = "MATH - List Comparisons"
|
||||
inputs = list(
|
||||
"list" = IC_PINTYPE_LIST,
|
||||
"compare value" = IC_PINTYPE_NUMBER
|
||||
)
|
||||
outputs = list(
|
||||
"result" = IC_PINTYPE_BOOLEAN
|
||||
)
|
||||
activators = list(
|
||||
"compare" = IC_PINTYPE_PULSE_IN,
|
||||
"on true result" = IC_PINTYPE_PULSE_OUT,
|
||||
"on false result" = IC_PINTYPE_PULSE_OUT
|
||||
)
|
||||
icon_state = "addition"
|
||||
complexity = 2
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
|
||||
/obj/item/integrated_circuit/list/any_greater_than/do_work()
|
||||
var/list/input_list = get_pin_data(IC_INPUT, 1)
|
||||
var/compare_value = get_pin_data(IC_INPUT, 2)
|
||||
|
||||
var/result = FALSE
|
||||
|
||||
if(islist(input_list) && !isnull(compare_value))
|
||||
for(var/value in input_list)
|
||||
if(!isnum(value))
|
||||
continue
|
||||
|
||||
if(value > compare_value)
|
||||
result = TRUE
|
||||
break
|
||||
|
||||
set_pin_data(IC_OUTPUT, 1, result)
|
||||
push_data()
|
||||
|
||||
if(result)
|
||||
activate_pin(2)
|
||||
else
|
||||
activate_pin(3)
|
||||
|
||||
|
||||
/obj/item/integrated_circuit/list/any_less_than
|
||||
name = "any less than circuit"
|
||||
desc = "This circuit checks whether any number in a list is less than a target value."
|
||||
extended_desc = "Non-number values are ignored. Outputs true if at least one number in the list is less than the comparison value."
|
||||
category_text = "MATH - List Comparisons"
|
||||
inputs = list(
|
||||
"list" = IC_PINTYPE_LIST,
|
||||
"compare value" = IC_PINTYPE_NUMBER
|
||||
)
|
||||
outputs = list(
|
||||
"result" = IC_PINTYPE_BOOLEAN
|
||||
)
|
||||
activators = list(
|
||||
"compare" = IC_PINTYPE_PULSE_IN,
|
||||
"on true result" = IC_PINTYPE_PULSE_OUT,
|
||||
"on false result" = IC_PINTYPE_PULSE_OUT
|
||||
)
|
||||
icon_state = "addition"
|
||||
complexity = 2
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
|
||||
/obj/item/integrated_circuit/list/any_less_than/do_work()
|
||||
var/list/input_list = get_pin_data(IC_INPUT, 1)
|
||||
var/compare_value = get_pin_data(IC_INPUT, 2)
|
||||
|
||||
var/result = FALSE
|
||||
|
||||
if(islist(input_list) && !isnull(compare_value))
|
||||
for(var/value in input_list)
|
||||
if(!isnum(value))
|
||||
continue
|
||||
|
||||
if(value < compare_value)
|
||||
result = TRUE
|
||||
break
|
||||
|
||||
set_pin_data(IC_OUTPUT, 1, result)
|
||||
push_data()
|
||||
|
||||
if(result)
|
||||
activate_pin(2)
|
||||
else
|
||||
activate_pin(3)
|
||||
|
||||
|
||||
/obj/item/integrated_circuit/list/any_equal_to
|
||||
name = "any equal to circuit"
|
||||
desc = "This circuit checks whether any value in a list is equal to a target value."
|
||||
extended_desc = "Outputs true if at least one value in the list is equal to the comparison value. This can compare numbers, strings, booleans, refs, or null."
|
||||
category_text = "MATH - List Comparisons"
|
||||
inputs = list(
|
||||
"list" = IC_PINTYPE_LIST,
|
||||
"compare value" = IC_PINTYPE_ANY
|
||||
)
|
||||
outputs = list(
|
||||
"result" = IC_PINTYPE_BOOLEAN
|
||||
)
|
||||
activators = list(
|
||||
"compare" = IC_PINTYPE_PULSE_IN,
|
||||
"on true result" = IC_PINTYPE_PULSE_OUT,
|
||||
"on false result" = IC_PINTYPE_PULSE_OUT
|
||||
)
|
||||
icon_state = "addition"
|
||||
complexity = 2
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
|
||||
/obj/item/integrated_circuit/list/any_equal_to/do_work()
|
||||
var/list/input_list = get_pin_data(IC_INPUT, 1)
|
||||
var/compare_value = get_pin_data(IC_INPUT, 2)
|
||||
|
||||
var/result = FALSE
|
||||
|
||||
if(islist(input_list))
|
||||
for(var/value in input_list)
|
||||
if(value == compare_value)
|
||||
result = TRUE
|
||||
break
|
||||
|
||||
set_pin_data(IC_OUTPUT, 1, result)
|
||||
push_data()
|
||||
|
||||
if(result)
|
||||
activate_pin(2)
|
||||
else
|
||||
activate_pin(3)
|
||||
|
||||
/obj/item/integrated_circuit/list/arithmetic
|
||||
name = "list arithmetic"
|
||||
desc = "This circuit performs basic arithmetic between two lists of numbers."
|
||||
extended_desc = "Takes two lists and applies the selected operation index-by-index. If either value is not a number, the output at that position is null. Supported operations are add, subtract, multiply, and divide."
|
||||
category_text = "MATH - List Math"
|
||||
icon_state = "addition"
|
||||
complexity = 8
|
||||
inputs = list(
|
||||
"list A" = IC_PINTYPE_LIST,
|
||||
"list B" = IC_PINTYPE_LIST,
|
||||
"operation" = IC_PINTYPE_STRING
|
||||
)
|
||||
outputs = list(
|
||||
"result" = IC_PINTYPE_LIST
|
||||
)
|
||||
activators = list(
|
||||
"calculate" = IC_PINTYPE_PULSE_IN,
|
||||
"on calculated" = IC_PINTYPE_PULSE_OUT
|
||||
)
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
|
||||
/obj/item/integrated_circuit/list/arithmetic/do_work()
|
||||
pull_data()
|
||||
|
||||
var/list/list_a = get_pin_data(IC_INPUT, 1)
|
||||
var/list/list_b = get_pin_data(IC_INPUT, 2)
|
||||
var/operation = lowertext("[get_pin_data(IC_INPUT, 3)]")
|
||||
|
||||
var/list/result = list()
|
||||
|
||||
if(!islist(list_a) || !islist(list_b))
|
||||
set_pin_data(IC_OUTPUT, 1, null)
|
||||
push_data()
|
||||
activate_pin(2)
|
||||
return
|
||||
|
||||
var/max_length = max(length(list_a), length(list_b))
|
||||
|
||||
for(var/i = 1 to max_length)
|
||||
var/a = list_a[i]
|
||||
var/b = list_b[i]
|
||||
|
||||
if(!isnum(a) || !isnum(b))
|
||||
result.len++
|
||||
continue
|
||||
|
||||
switch(operation)
|
||||
if("add", "+", "addition")
|
||||
result += a + b
|
||||
|
||||
if("subtract", "-", "subtraction")
|
||||
result += a - b
|
||||
|
||||
if("multiply", "*", "multiplication")
|
||||
result += a * b
|
||||
|
||||
if("divide", "/", "division")
|
||||
if(b == 0)
|
||||
result.len++
|
||||
else
|
||||
result += a / b
|
||||
|
||||
else
|
||||
result.len++
|
||||
|
||||
set_pin_data(IC_OUTPUT, 1, result)
|
||||
push_data()
|
||||
activate_pin(2)
|
||||
|
||||
/obj/item/integrated_circuit/list/list_contains
|
||||
name = "list contains"
|
||||
desc = "Checks whether a list contains a value."
|
||||
category_text = "MATH - List Comparisons"
|
||||
icon_state = "template"
|
||||
complexity = 3
|
||||
inputs = list(
|
||||
"list" = IC_PINTYPE_LIST,
|
||||
"value" = IC_PINTYPE_ANY
|
||||
)
|
||||
outputs = list(
|
||||
"contains" = IC_PINTYPE_BOOLEAN,
|
||||
"index" = IC_PINTYPE_NUMBER,
|
||||
"matched value" = IC_PINTYPE_ANY
|
||||
)
|
||||
activators = list(
|
||||
"check" = IC_PINTYPE_PULSE_IN,
|
||||
"found" = IC_PINTYPE_PULSE_OUT,
|
||||
"not found" = IC_PINTYPE_PULSE_OUT
|
||||
)
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
|
||||
/obj/item/integrated_circuit/list/list_contains/do_work()
|
||||
var/list/input_list = get_pin_data(IC_INPUT, 1)
|
||||
var/value = get_pin_data(IC_INPUT, 2, FALSE)
|
||||
|
||||
set_pin_data(IC_OUTPUT, 1, FALSE)
|
||||
set_pin_data(IC_OUTPUT, 2, null)
|
||||
set_pin_data(IC_OUTPUT, 3, null)
|
||||
|
||||
if(!islist(input_list) || !length(input_list))
|
||||
push_data()
|
||||
activate_pin(3)
|
||||
return
|
||||
|
||||
var/index = 1
|
||||
|
||||
for(var/item in input_list)
|
||||
if(item == value || "[item]" == "[value]")
|
||||
set_pin_data(IC_OUTPUT, 1, TRUE)
|
||||
set_pin_data(IC_OUTPUT, 2, index)
|
||||
set_pin_data(IC_OUTPUT, 3, item)
|
||||
push_data()
|
||||
activate_pin(2)
|
||||
return
|
||||
|
||||
index++
|
||||
|
||||
push_data()
|
||||
activate_pin(3)
|
||||
|
||||
|
||||
/obj/item/integrated_circuit/list/list_filter_text
|
||||
name = "list text filter"
|
||||
desc = "Filters a list by matching text against each value."
|
||||
icon_state = "template"
|
||||
complexity = 5
|
||||
inputs = list(
|
||||
"list" = IC_PINTYPE_LIST,
|
||||
"match text" = IC_PINTYPE_STRING
|
||||
)
|
||||
outputs = list(
|
||||
"filtered list" = IC_PINTYPE_LIST,
|
||||
"matches found" = IC_PINTYPE_BOOLEAN
|
||||
)
|
||||
activators = list(
|
||||
"filter" = IC_PINTYPE_PULSE_IN,
|
||||
"found" = IC_PINTYPE_PULSE_OUT,
|
||||
"not found" = IC_PINTYPE_PULSE_OUT
|
||||
)
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
|
||||
/obj/item/integrated_circuit/list/list_filter_text/do_work()
|
||||
var/list/input_list = get_pin_data(IC_INPUT, 1)
|
||||
var/match_text = get_pin_data(IC_INPUT, 2)
|
||||
var/list/filtered_list = list()
|
||||
|
||||
if(!islist(input_list) || !istext(match_text) || !length(match_text))
|
||||
set_pin_data(IC_OUTPUT, 1, filtered_list)
|
||||
set_pin_data(IC_OUTPUT, 2, FALSE)
|
||||
push_data()
|
||||
activate_pin(3)
|
||||
return
|
||||
|
||||
var/lower_match = lowertext(match_text)
|
||||
|
||||
for(var/item in input_list)
|
||||
var/check_text = lowertext("[item]")
|
||||
|
||||
if(isweakref(item))
|
||||
var/datum/weakref/WR = item
|
||||
var/atom/A = WR.resolve()
|
||||
if(A)
|
||||
check_text = lowertext("[A.name] [A.desc]")
|
||||
|
||||
else if(istype(item, /atom))
|
||||
var/atom/A = item
|
||||
check_text = lowertext("[A.name] [A.desc]")
|
||||
|
||||
if(findtext(check_text, lower_match))
|
||||
filtered_list += item
|
||||
|
||||
set_pin_data(IC_OUTPUT, 1, filtered_list)
|
||||
set_pin_data(IC_OUTPUT, 2, length(filtered_list) ? TRUE : FALSE)
|
||||
|
||||
push_data()
|
||||
activate_pin(length(filtered_list) ? 2 : 3)
|
||||
|
||||
|
||||
/obj/item/integrated_circuit/list/list_join
|
||||
name = "list joiner"
|
||||
desc = "Joins a list into a single string using a separator."
|
||||
icon_state = "template"
|
||||
complexity = 3
|
||||
inputs = list(
|
||||
"list" = IC_PINTYPE_LIST,
|
||||
"separator" = IC_PINTYPE_STRING
|
||||
)
|
||||
outputs = list(
|
||||
"joined string" = IC_PINTYPE_STRING
|
||||
)
|
||||
activators = list(
|
||||
"join" = IC_PINTYPE_PULSE_IN,
|
||||
"on joined" = IC_PINTYPE_PULSE_OUT
|
||||
)
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
|
||||
/obj/item/integrated_circuit/list/list_join/do_work()
|
||||
var/list/input_list = get_pin_data(IC_INPUT, 1)
|
||||
var/separator = get_pin_data(IC_INPUT, 2)
|
||||
|
||||
if(!islist(input_list))
|
||||
input_list = list()
|
||||
|
||||
if(!istext(separator))
|
||||
separator = ", "
|
||||
|
||||
var/list/text_values = list()
|
||||
|
||||
for(var/item in input_list)
|
||||
text_values += "[item]"
|
||||
|
||||
set_pin_data(IC_OUTPUT, 1, jointext(text_values, separator))
|
||||
push_data()
|
||||
activate_pin(2)
|
||||
|
||||
|
||||
/obj/item/integrated_circuit/list/list_sort
|
||||
name = "list sorter"
|
||||
desc = "Sorts a list."
|
||||
extended_desc = "Sorts values alphabetically or numerically depending on what the list contains."
|
||||
icon_state = "template"
|
||||
complexity = 4
|
||||
inputs = list(
|
||||
"list" = IC_PINTYPE_LIST,
|
||||
"ascending" = IC_PINTYPE_BOOLEAN
|
||||
)
|
||||
outputs = list(
|
||||
"sorted list" = IC_PINTYPE_LIST
|
||||
)
|
||||
activators = list(
|
||||
"sort" = IC_PINTYPE_PULSE_IN,
|
||||
"on sorted" = IC_PINTYPE_PULSE_OUT
|
||||
)
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
|
||||
/obj/item/integrated_circuit/list/list_sort/do_work()
|
||||
var/list/input_list = get_pin_data(IC_INPUT, 1)
|
||||
var/ascending = get_pin_data(IC_INPUT, 2)
|
||||
|
||||
if(!islist(input_list))
|
||||
input_list = list()
|
||||
|
||||
var/list/sorted_list = input_list.Copy()
|
||||
sortTim(sorted_list, /proc/cmp_text_asc)
|
||||
|
||||
if(!ascending)
|
||||
sorted_list = reverseList(sorted_list)
|
||||
|
||||
set_pin_data(IC_OUTPUT, 1, sorted_list)
|
||||
push_data()
|
||||
activate_pin(2)
|
||||
|
||||
|
||||
/obj/item/integrated_circuit/list/random_selector
|
||||
name = "random list selector"
|
||||
desc = "Selects a random value from a list."
|
||||
icon_state = "template"
|
||||
complexity = 3
|
||||
inputs = list(
|
||||
"list" = IC_PINTYPE_LIST
|
||||
)
|
||||
outputs = list(
|
||||
"selected value" = IC_PINTYPE_ANY,
|
||||
"selected index" = IC_PINTYPE_NUMBER
|
||||
)
|
||||
activators = list(
|
||||
"select" = IC_PINTYPE_PULSE_IN,
|
||||
"selected" = IC_PINTYPE_PULSE_OUT,
|
||||
"not selected" = IC_PINTYPE_PULSE_OUT
|
||||
)
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
|
||||
/obj/item/integrated_circuit/list/random_selector/do_work()
|
||||
var/list/input_list = get_pin_data(IC_INPUT, 1)
|
||||
|
||||
var/list_length = islist(input_list) ? input_list.len : 0
|
||||
if(!list_length)
|
||||
set_pin_data(IC_OUTPUT, 1, null)
|
||||
set_pin_data(IC_OUTPUT, 2, null)
|
||||
push_data()
|
||||
activate_pin(3)
|
||||
return
|
||||
|
||||
var/index = rand(1, list_length)
|
||||
|
||||
set_pin_data(IC_OUTPUT, 1, input_list[index])
|
||||
set_pin_data(IC_OUTPUT, 2, index)
|
||||
push_data()
|
||||
activate_pin(2)
|
||||
|
||||
|
||||
/obj/item/integrated_circuit/list/weighted_random_selector
|
||||
name = "weighted random selector"
|
||||
desc = "Selects a random value from a list using a matching list of weights."
|
||||
icon_state = "template"
|
||||
complexity = 6
|
||||
inputs = list(
|
||||
"values" = IC_PINTYPE_LIST,
|
||||
"weights" = IC_PINTYPE_LIST
|
||||
)
|
||||
outputs = list(
|
||||
"selected value" = IC_PINTYPE_ANY,
|
||||
"selected index" = IC_PINTYPE_NUMBER
|
||||
)
|
||||
activators = list(
|
||||
"select" = IC_PINTYPE_PULSE_IN,
|
||||
"selected" = IC_PINTYPE_PULSE_OUT,
|
||||
"not selected" = IC_PINTYPE_PULSE_OUT
|
||||
)
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
|
||||
/obj/item/integrated_circuit/list/weighted_random_selector/do_work()
|
||||
var/list/values = get_pin_data(IC_INPUT, 1)
|
||||
var/list/weights = get_pin_data(IC_INPUT, 2)
|
||||
|
||||
if(!islist(values) || !islist(weights) || !length(values) || !length(weights))
|
||||
set_pin_data(IC_OUTPUT, 1, null)
|
||||
set_pin_data(IC_OUTPUT, 2, null)
|
||||
push_data()
|
||||
activate_pin(3)
|
||||
return
|
||||
|
||||
var/selection_count = min(values.len, weights.len)
|
||||
var/total_weight = 0
|
||||
|
||||
for(var/i = 1 to selection_count)
|
||||
var/weight = weights[i]
|
||||
if(isnum(weight) && weight > 0)
|
||||
total_weight += weight
|
||||
|
||||
if(total_weight <= 0)
|
||||
push_data()
|
||||
activate_pin(3)
|
||||
return
|
||||
|
||||
var/roll = rand(1, total_weight)
|
||||
var/current_weight = 0
|
||||
|
||||
for(var/i = 1 to selection_count)
|
||||
var/weight = weights[i]
|
||||
|
||||
if(!isnum(weight) || weight <= 0)
|
||||
continue
|
||||
|
||||
current_weight += weight
|
||||
|
||||
if(roll <= current_weight)
|
||||
set_pin_data(IC_OUTPUT, 1, values[i])
|
||||
set_pin_data(IC_OUTPUT, 2, i)
|
||||
push_data()
|
||||
activate_pin(2)
|
||||
return
|
||||
|
||||
push_data()
|
||||
activate_pin(3)
|
||||
|
||||
@@ -1,11 +1,16 @@
|
||||
/*
|
||||
* subtypes/logic.dm
|
||||
* Logic and comparison circuits for boolean gates, equality checks, numeric comparisons, and conditional routing.
|
||||
*/
|
||||
|
||||
/obj/item/integrated_circuit/logic
|
||||
name = "logic gate"
|
||||
desc = "This tiny chip will decide for you!"
|
||||
extended_desc = "Logic circuits will treat a null, 0, and a \"\" string value as FALSE and anything else as TRUE. If inputs are of mismatching type, expect undocumented behaviour."
|
||||
extended_desc = "Logic circuits treat null, 0, and empty text as FALSE. Non-zero numbers, non-empty text, valid refs, and populated lists are TRUE. Compare matching value types for reliable results."
|
||||
complexity = 3
|
||||
outputs = list("result" = IC_PINTYPE_BOOLEAN)
|
||||
activators = list("compare" = IC_PINTYPE_PULSE_IN)
|
||||
category_text = "Logic"
|
||||
category_text = "LOGIC - Boolean Logic"
|
||||
power_draw_per_use = 10
|
||||
|
||||
/obj/item/integrated_circuit/logic/binary
|
||||
@@ -72,6 +77,7 @@
|
||||
name = "equal gate"
|
||||
desc = "This gate compares two values, and outputs the number one if both are the same."
|
||||
icon_state = "equal"
|
||||
category_text = "LOGIC - Comparisons"
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
|
||||
/obj/item/integrated_circuit/logic/binary/equals/do_compare(A, B)
|
||||
@@ -159,6 +165,7 @@
|
||||
name = "not equal gate"
|
||||
desc = "This gate compares two values, and outputs the number one if both are different."
|
||||
icon_state = "not_equal"
|
||||
category_text = "LOGIC - Comparisons"
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
|
||||
/obj/item/integrated_circuit/logic/binary/not_equals/do_compare(A, B)
|
||||
@@ -186,6 +193,7 @@
|
||||
name = "less than gate"
|
||||
desc = "This will output 'one' if the first input is less than the second input."
|
||||
icon_state = "less_than"
|
||||
category_text = "LOGIC - Comparisons"
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
|
||||
/obj/item/integrated_circuit/logic/binary/less_than/do_compare(A, B)
|
||||
@@ -195,6 +203,7 @@
|
||||
name = "less than or equal gate"
|
||||
desc = "This will output 'one' if the first input is less than, or equal to the second input."
|
||||
icon_state = "less_than_or_equal"
|
||||
category_text = "LOGIC - Comparisons"
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
|
||||
/obj/item/integrated_circuit/logic/binary/less_than_or_equal/do_compare(A, B)
|
||||
@@ -204,6 +213,7 @@
|
||||
name = "greater than gate"
|
||||
desc = "This will output 'one' if the first input is greater than the second input."
|
||||
icon_state = "greater_than"
|
||||
category_text = "LOGIC - Comparisons"
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
|
||||
/obj/item/integrated_circuit/logic/binary/greater_than/do_compare(A, B)
|
||||
@@ -213,6 +223,7 @@
|
||||
name = "greater_than or equal gate"
|
||||
desc = "This will output 'one' if the first input is greater than, or equal to the second input."
|
||||
icon_state = "greater_than_or_equal"
|
||||
category_text = "LOGIC - Comparisons"
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
|
||||
/obj/item/integrated_circuit/logic/binary/greater_than_or_equal/do_compare(A, B)
|
||||
@@ -227,3 +238,336 @@
|
||||
|
||||
/obj/item/integrated_circuit/logic/unary/not/do_check(A)
|
||||
return !A
|
||||
|
||||
/obj/item/integrated_circuit/logic/edge_detector
|
||||
name = "edge detector"
|
||||
desc = "Turns a changing boolean signal into one-shot output pulses."
|
||||
extended_desc = "Stores the previous signal state internally. It only pulses when the input changes, making it useful for preventing ticker-fed logic from repeatedly firing the same action."
|
||||
icon_state = "template"
|
||||
complexity = 2
|
||||
inputs = list(
|
||||
"signal" = IC_PINTYPE_BOOLEAN
|
||||
)
|
||||
outputs = list(
|
||||
"current state" = IC_PINTYPE_BOOLEAN,
|
||||
"previous state" = IC_PINTYPE_BOOLEAN
|
||||
)
|
||||
activators = list(
|
||||
"check" = IC_PINTYPE_PULSE_IN,
|
||||
"on rising edge" = IC_PINTYPE_PULSE_OUT,
|
||||
"on falling edge" = IC_PINTYPE_PULSE_OUT,
|
||||
"on changed" = IC_PINTYPE_PULSE_OUT,
|
||||
"on unchanged" = IC_PINTYPE_PULSE_OUT
|
||||
)
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
|
||||
var/previous_state = FALSE
|
||||
var/has_previous_state = FALSE
|
||||
|
||||
/obj/item/integrated_circuit/logic/edge_detector/do_work()
|
||||
var/current_state = get_pin_data(IC_INPUT, 1) ? TRUE : FALSE
|
||||
var/old_state = previous_state
|
||||
|
||||
set_pin_data(IC_OUTPUT, 1, current_state)
|
||||
set_pin_data(IC_OUTPUT, 2, old_state)
|
||||
push_data()
|
||||
|
||||
if(!has_previous_state)
|
||||
previous_state = current_state
|
||||
has_previous_state = TRUE
|
||||
activate_pin(5)
|
||||
return
|
||||
|
||||
if(current_state == previous_state)
|
||||
activate_pin(5)
|
||||
return
|
||||
|
||||
previous_state = current_state
|
||||
activate_pin(current_state ? 2 : 3)
|
||||
activate_pin(4)
|
||||
|
||||
/obj/item/integrated_circuit/logic/threshold_comparator
|
||||
name = "threshold comparator"
|
||||
desc = "Checks whether a number is below, inside, or above a range."
|
||||
icon_state = "comparator"
|
||||
category_text = "LOGIC - Comparisons"
|
||||
complexity = 3
|
||||
inputs = list(
|
||||
"value" = IC_PINTYPE_NUMBER,
|
||||
"minimum" = IC_PINTYPE_NUMBER,
|
||||
"maximum" = IC_PINTYPE_NUMBER
|
||||
)
|
||||
outputs = list(
|
||||
"below range" = IC_PINTYPE_BOOLEAN,
|
||||
"inside range" = IC_PINTYPE_BOOLEAN,
|
||||
"above range" = IC_PINTYPE_BOOLEAN,
|
||||
"status text" = IC_PINTYPE_STRING
|
||||
)
|
||||
activators = list(
|
||||
"compare" = IC_PINTYPE_PULSE_IN,
|
||||
"below" = IC_PINTYPE_PULSE_OUT,
|
||||
"inside" = IC_PINTYPE_PULSE_OUT,
|
||||
"above" = IC_PINTYPE_PULSE_OUT
|
||||
)
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
|
||||
/obj/item/integrated_circuit/logic/threshold_comparator/do_work()
|
||||
var/value = get_pin_data(IC_INPUT, 1)
|
||||
var/minimum = get_pin_data(IC_INPUT, 2)
|
||||
var/maximum = get_pin_data(IC_INPUT, 3)
|
||||
|
||||
if(!isnum(value) || !isnum(minimum) || !isnum(maximum))
|
||||
return
|
||||
|
||||
var/below = value < minimum
|
||||
var/above = value > maximum
|
||||
var/inside = !below && !above
|
||||
|
||||
set_pin_data(IC_OUTPUT, 1, below)
|
||||
set_pin_data(IC_OUTPUT, 2, inside)
|
||||
set_pin_data(IC_OUTPUT, 3, above)
|
||||
set_pin_data(IC_OUTPUT, 4, below ? "BELOW RANGE" : above ? "ABOVE RANGE" : "INSIDE RANGE")
|
||||
|
||||
push_data()
|
||||
|
||||
if(below)
|
||||
activate_pin(2)
|
||||
else if(inside)
|
||||
activate_pin(3)
|
||||
else
|
||||
activate_pin(4)
|
||||
|
||||
|
||||
/obj/item/integrated_circuit/logic/multi_threshold_status
|
||||
name = "multi-threshold status"
|
||||
desc = "Classifies a number as normal, warning, or danger using low and high thresholds."
|
||||
icon_state = "comparator"
|
||||
category_text = "LOGIC - Comparisons"
|
||||
complexity = 5
|
||||
inputs = list(
|
||||
"value" = IC_PINTYPE_NUMBER,
|
||||
"danger low" = IC_PINTYPE_NUMBER,
|
||||
"warning low" = IC_PINTYPE_NUMBER,
|
||||
"warning high" = IC_PINTYPE_NUMBER,
|
||||
"danger high" = IC_PINTYPE_NUMBER
|
||||
)
|
||||
outputs = list(
|
||||
"normal" = IC_PINTYPE_BOOLEAN,
|
||||
"warning" = IC_PINTYPE_BOOLEAN,
|
||||
"danger" = IC_PINTYPE_BOOLEAN,
|
||||
"status text" = IC_PINTYPE_STRING
|
||||
)
|
||||
activators = list(
|
||||
"check" = IC_PINTYPE_PULSE_IN,
|
||||
"normal" = IC_PINTYPE_PULSE_OUT,
|
||||
"warning" = IC_PINTYPE_PULSE_OUT,
|
||||
"danger" = IC_PINTYPE_PULSE_OUT
|
||||
)
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
|
||||
/obj/item/integrated_circuit/logic/multi_threshold_status/do_work()
|
||||
var/value = get_pin_data(IC_INPUT, 1)
|
||||
var/danger_low = get_pin_data(IC_INPUT, 2)
|
||||
var/warning_low = get_pin_data(IC_INPUT, 3)
|
||||
var/warning_high = get_pin_data(IC_INPUT, 4)
|
||||
var/danger_high = get_pin_data(IC_INPUT, 5)
|
||||
|
||||
if(!isnum(value) || !isnum(danger_low) || !isnum(warning_low) || !isnum(warning_high) || !isnum(danger_high))
|
||||
return
|
||||
|
||||
var/normal = FALSE
|
||||
var/warning = FALSE
|
||||
var/danger = FALSE
|
||||
var/status = "NORMAL"
|
||||
|
||||
if(value <= danger_low)
|
||||
danger = TRUE
|
||||
status = "LOW DANGER"
|
||||
else if(value < warning_low)
|
||||
warning = TRUE
|
||||
status = "LOW WARNING"
|
||||
else if(value >= danger_high)
|
||||
danger = TRUE
|
||||
status = "HIGH DANGER"
|
||||
else if(value > warning_high)
|
||||
warning = TRUE
|
||||
status = "HIGH WARNING"
|
||||
else
|
||||
normal = TRUE
|
||||
|
||||
set_pin_data(IC_OUTPUT, 1, normal)
|
||||
set_pin_data(IC_OUTPUT, 2, warning)
|
||||
set_pin_data(IC_OUTPUT, 3, danger)
|
||||
set_pin_data(IC_OUTPUT, 4, status)
|
||||
|
||||
push_data()
|
||||
|
||||
if(normal)
|
||||
activate_pin(2)
|
||||
else if(warning)
|
||||
activate_pin(3)
|
||||
else
|
||||
activate_pin(4)
|
||||
|
||||
|
||||
/obj/item/integrated_circuit/logic/cooldown_limiter
|
||||
name = "cooldown limiter"
|
||||
desc = "Allows a pulse through only when its cooldown has expired."
|
||||
extended_desc = "Cooldown is clamped between 1 and 600 seconds. Disabled gates block incoming pulses without updating their cooldown."
|
||||
icon_state = "template"
|
||||
complexity = 4
|
||||
inputs = list(
|
||||
"cooldown seconds" = IC_PINTYPE_NUMBER,
|
||||
"enabled" = IC_PINTYPE_BOOLEAN
|
||||
)
|
||||
inputs_default = list(
|
||||
"1" = 2,
|
||||
"2" = TRUE
|
||||
)
|
||||
outputs = list(
|
||||
"ready" = IC_PINTYPE_BOOLEAN,
|
||||
"remaining cooldown" = IC_PINTYPE_NUMBER
|
||||
)
|
||||
activators = list(
|
||||
"pulse in" = IC_PINTYPE_PULSE_IN,
|
||||
"pulse out" = IC_PINTYPE_PULSE_OUT,
|
||||
"on blocked" = IC_PINTYPE_PULSE_OUT
|
||||
)
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
power_draw_per_use = 20
|
||||
|
||||
var/next_allowed_time = 0
|
||||
|
||||
/obj/item/integrated_circuit/logic/cooldown_limiter/do_work()
|
||||
var/cooldown_seconds = get_pin_data(IC_INPUT, 1)
|
||||
var/enabled = get_pin_data(IC_INPUT, 2)
|
||||
|
||||
if(!isnum(cooldown_seconds))
|
||||
cooldown_seconds = 2
|
||||
|
||||
cooldown_seconds = between(1, cooldown_seconds, 600)
|
||||
|
||||
if(!enabled)
|
||||
set_pin_data(IC_OUTPUT, 1, FALSE)
|
||||
set_pin_data(IC_OUTPUT, 2, 0)
|
||||
push_data()
|
||||
activate_pin(3)
|
||||
return
|
||||
|
||||
if(world.time >= next_allowed_time)
|
||||
next_allowed_time = world.time + cooldown_seconds SECONDS
|
||||
set_pin_data(IC_OUTPUT, 1, TRUE)
|
||||
set_pin_data(IC_OUTPUT, 2, 0)
|
||||
push_data()
|
||||
activate_pin(2)
|
||||
return
|
||||
|
||||
var/remaining = max(round((next_allowed_time - world.time) / 10, 0.1), 0)
|
||||
set_pin_data(IC_OUTPUT, 1, FALSE)
|
||||
set_pin_data(IC_OUTPUT, 2, remaining)
|
||||
push_data()
|
||||
activate_pin(3)
|
||||
|
||||
|
||||
/obj/item/integrated_circuit/logic/pulse_counter
|
||||
name = "threshold pulse counter"
|
||||
desc = "Counts incoming pulses and reports when a threshold has been reached."
|
||||
extended_desc = "Count is clamped between -100000 and 100000. Use the reset pulse to set the count to the configured reset value."
|
||||
icon_state = "counter"
|
||||
complexity = 3
|
||||
inputs = list(
|
||||
"threshold" = IC_PINTYPE_NUMBER,
|
||||
"reset value" = IC_PINTYPE_NUMBER
|
||||
)
|
||||
inputs_default = list(
|
||||
"1" = 1,
|
||||
"2" = 0
|
||||
)
|
||||
outputs = list(
|
||||
"count" = IC_PINTYPE_NUMBER,
|
||||
"threshold met" = IC_PINTYPE_BOOLEAN
|
||||
)
|
||||
activators = list(
|
||||
"increment" = IC_PINTYPE_PULSE_IN,
|
||||
"decrement" = IC_PINTYPE_PULSE_IN,
|
||||
"reset" = IC_PINTYPE_PULSE_IN,
|
||||
"on count changed" = IC_PINTYPE_PULSE_OUT,
|
||||
"on threshold met" = IC_PINTYPE_PULSE_OUT
|
||||
)
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
power_draw_per_use = 20
|
||||
|
||||
var/count = 0
|
||||
|
||||
/obj/item/integrated_circuit/logic/pulse_counter/do_work(activator_id)
|
||||
var/active_pin = activator_id
|
||||
|
||||
if(istype(active_pin, /datum/integrated_io))
|
||||
active_pin = activators.Find(active_pin)
|
||||
|
||||
if(!isnum(active_pin))
|
||||
active_pin = 1
|
||||
|
||||
switch(active_pin)
|
||||
if(2)
|
||||
count--
|
||||
if(3)
|
||||
var/reset_value = get_pin_data(IC_INPUT, 2)
|
||||
count = isnum(reset_value) ? round(reset_value) : 0
|
||||
else
|
||||
count++
|
||||
|
||||
count = clamp(count, -100000, 100000)
|
||||
var/threshold = get_pin_data(IC_INPUT, 1)
|
||||
if(!isnum(threshold))
|
||||
threshold = 1
|
||||
threshold = clamp(round(threshold), -100000, 100000)
|
||||
var/threshold_met = count >= threshold
|
||||
|
||||
set_pin_data(IC_OUTPUT, 1, count)
|
||||
set_pin_data(IC_OUTPUT, 2, threshold_met)
|
||||
push_data()
|
||||
activate_pin(4)
|
||||
if(threshold_met)
|
||||
activate_pin(5)
|
||||
|
||||
|
||||
/obj/item/integrated_circuit/logic/pulse_sequencer
|
||||
name = "pulse sequencer"
|
||||
desc = "Cycles through four output pulses. If reset is true when pulsed, the sequence resets instead."
|
||||
icon_state = "template"
|
||||
complexity = 4
|
||||
inputs = list(
|
||||
"reset" = IC_PINTYPE_BOOLEAN
|
||||
)
|
||||
outputs = list(
|
||||
"current step" = IC_PINTYPE_NUMBER
|
||||
)
|
||||
activators = list(
|
||||
"pulse" = IC_PINTYPE_PULSE_IN,
|
||||
"step 1 pulse" = IC_PINTYPE_PULSE_OUT,
|
||||
"step 2 pulse" = IC_PINTYPE_PULSE_OUT,
|
||||
"step 3 pulse" = IC_PINTYPE_PULSE_OUT,
|
||||
"step 4 pulse" = IC_PINTYPE_PULSE_OUT,
|
||||
"on reset" = IC_PINTYPE_PULSE_OUT
|
||||
)
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
|
||||
var/current_step = 0
|
||||
|
||||
/obj/item/integrated_circuit/logic/pulse_sequencer/do_work()
|
||||
if(get_pin_data(IC_INPUT, 1))
|
||||
current_step = 0
|
||||
set_pin_data(IC_OUTPUT, 1, current_step)
|
||||
push_data()
|
||||
activate_pin(6)
|
||||
return
|
||||
|
||||
current_step++
|
||||
|
||||
if(current_step > 4)
|
||||
current_step = 1
|
||||
|
||||
set_pin_data(IC_OUTPUT, 1, current_step)
|
||||
push_data()
|
||||
activate_pin(current_step + 1)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,3 +1,8 @@
|
||||
/*
|
||||
* subtypes/memory.dm
|
||||
* Memory circuits that store circuit values across pulses and expose saved values through output pins.
|
||||
*/
|
||||
|
||||
/obj/item/integrated_circuit/memory
|
||||
complexity = 1
|
||||
category_text = "Memory"
|
||||
@@ -40,6 +45,9 @@
|
||||
/obj/item/integrated_circuit/memory/storage/do_work()
|
||||
for(var/i = 1 to inputs.len)
|
||||
var/data = get_pin_data(IC_INPUT, i)
|
||||
if(islist(data))
|
||||
var/list/list_data = data
|
||||
data = list_data.Copy()
|
||||
set_pin_data(IC_OUTPUT, i, data)
|
||||
push_data()
|
||||
activate_pin(2)
|
||||
@@ -53,7 +61,7 @@
|
||||
|
||||
/obj/item/integrated_circuit/memory/storage/large
|
||||
name = "large memory circuit"
|
||||
desc = "This big circuit can hold eight pieces of data."
|
||||
desc = "This circuit can store eight pieces of data."
|
||||
icon_state = "memory8"
|
||||
origin_tech = list(TECH_ENGINEERING = 3, TECH_DATA = 3)
|
||||
power_draw_per_use = 40
|
||||
@@ -61,7 +69,7 @@
|
||||
|
||||
/obj/item/integrated_circuit/memory/storage/huge
|
||||
name = "large memory stick"
|
||||
desc = "This stick of memory can hold up up to sixteen pieces of data."
|
||||
desc = "This memory stick can store up to sixteen pieces of data."
|
||||
icon_state = "memory16"
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
spawn_flags = IC_SPAWN_RESEARCH
|
||||
@@ -71,7 +79,7 @@
|
||||
|
||||
/obj/item/integrated_circuit/memory/constant
|
||||
name = "constant chip"
|
||||
desc = "This tiny chip can store one piece of data, which cannot be overwritten without disassembly."
|
||||
desc = "This chip stores one constant value. It cannot be changed without disassembly."
|
||||
icon_state = "memory1"
|
||||
inputs = list()
|
||||
outputs = list("output pin" = IC_PINTYPE_ANY)
|
||||
@@ -84,7 +92,11 @@
|
||||
var/data
|
||||
|
||||
/obj/item/integrated_circuit/memory/constant/do_work()
|
||||
set_pin_data(IC_OUTPUT, 1, data)
|
||||
var/output_data = data
|
||||
if(islist(output_data))
|
||||
var/list/list_data = output_data
|
||||
output_data = list_data.Copy()
|
||||
set_pin_data(IC_OUTPUT, 1, output_data)
|
||||
push_data()
|
||||
activate_pin(2)
|
||||
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
/*
|
||||
* subtypes/output.dm
|
||||
* Output circuits that speak, display, signal, pulse, transmit, or otherwise emit circuit results into the game world.
|
||||
*/
|
||||
|
||||
/obj/item/integrated_circuit/output
|
||||
category_text = "Output"
|
||||
|
||||
/obj/item/integrated_circuit/output/screen
|
||||
name = "small screen"
|
||||
desc = "This small screen can display a single piece of data, when the machine is examined closely."
|
||||
desc = "Displays one value when the assembly is examined closely."
|
||||
icon_state = "screen"
|
||||
inputs = list("displayed data" = IC_PINTYPE_ANY)
|
||||
outputs = list()
|
||||
@@ -34,31 +39,130 @@
|
||||
|
||||
/obj/item/integrated_circuit/output/screen/medium
|
||||
name = "screen"
|
||||
desc = "This screen allows for people holding the device to see a piece of data."
|
||||
desc = "Displays data to the person holding the device."
|
||||
icon_state = "screen_medium"
|
||||
power_draw_per_use = 200
|
||||
|
||||
/obj/item/integrated_circuit/output/screen/medium/do_work()
|
||||
..()
|
||||
var/list/nearby_things = range(0, get_turf(src))
|
||||
var/turf/T = get_turf(src)
|
||||
if(!T)
|
||||
return
|
||||
var/list/nearby_things = range(0, T)
|
||||
var/list/viewing = viewers(T)
|
||||
for(var/mob/M in nearby_things)
|
||||
var/obj/O = assembly ? assembly : src
|
||||
to_chat(M, SPAN_NOTICE("[icon2html(O, viewers(get_turf(src)))] [stuff_to_display]"))
|
||||
to_chat(M, SPAN_NOTICE("[icon2html(O, viewing)] [stuff_to_display]"))
|
||||
|
||||
/obj/item/integrated_circuit/output/screen/large
|
||||
name = "large screen"
|
||||
desc = "This screen allows for people able to see the device to see a piece of data."
|
||||
desc = "Displays data to nearby viewers who can see the device."
|
||||
icon_state = "screen_large"
|
||||
power_draw_per_use = 400
|
||||
|
||||
/obj/item/integrated_circuit/output/screen/large/do_work()
|
||||
..()
|
||||
var/obj/O = assembly ? loc : assembly
|
||||
O.visible_message(SPAN_NOTICE("[icon2html(O, viewers(get_turf(src)))] [stuff_to_display]"))
|
||||
var/obj/O = assembly ? assembly : src
|
||||
var/turf/T = get_turf(src)
|
||||
if(!O || !T)
|
||||
return
|
||||
O.visible_message(SPAN_NOTICE("[icon2html(O, viewers(T))] [stuff_to_display]"))
|
||||
|
||||
/obj/item/integrated_circuit/output/state_display
|
||||
name = "state display"
|
||||
desc = "Displays a compact label and value when the assembly is examined closely."
|
||||
icon_state = "screen"
|
||||
complexity = 2
|
||||
inputs = list(
|
||||
"label" = IC_PINTYPE_STRING,
|
||||
"value" = IC_PINTYPE_ANY,
|
||||
"enabled" = IC_PINTYPE_BOOLEAN
|
||||
)
|
||||
inputs_default = list(
|
||||
"1" = "Status",
|
||||
"3" = TRUE
|
||||
)
|
||||
outputs = list(
|
||||
"displayed" = IC_PINTYPE_BOOLEAN
|
||||
)
|
||||
activators = list(
|
||||
"update" = IC_PINTYPE_PULSE_IN,
|
||||
"on updated" = IC_PINTYPE_PULSE_OUT,
|
||||
"on invalid" = IC_PINTYPE_PULSE_OUT
|
||||
)
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
power_draw_per_use = 100
|
||||
|
||||
var/stuff_to_display = null
|
||||
|
||||
/obj/item/integrated_circuit/output/state_display/disconnect_all()
|
||||
..()
|
||||
stuff_to_display = null
|
||||
|
||||
/obj/item/integrated_circuit/output/state_display/any_examine(mob/user)
|
||||
. = ..()
|
||||
if(!isnull(stuff_to_display))
|
||||
. += "There is a little status display reading '[stuff_to_display]'."
|
||||
|
||||
/obj/item/integrated_circuit/output/state_display/do_work()
|
||||
if(!get_pin_data(IC_INPUT, 3))
|
||||
stuff_to_display = null
|
||||
set_pin_data(IC_OUTPUT, 1, FALSE)
|
||||
push_data()
|
||||
activate_pin(3)
|
||||
return
|
||||
|
||||
var/label = get_pin_data(IC_INPUT, 1)
|
||||
var/value = get_pin_data(IC_INPUT, 2, FALSE)
|
||||
|
||||
if(isnull(value))
|
||||
stuff_to_display = null
|
||||
set_pin_data(IC_OUTPUT, 1, FALSE)
|
||||
push_data()
|
||||
activate_pin(3)
|
||||
return
|
||||
|
||||
stuff_to_display = sanitizeSafe("[ic_safe_text(label, "Status")]: [ic_display_value(value)]", MAX_MESSAGE_LEN)
|
||||
set_pin_data(IC_OUTPUT, 1, TRUE)
|
||||
push_data()
|
||||
activate_pin(2)
|
||||
|
||||
/obj/item/integrated_circuit/output/pulse_result
|
||||
name = "pulse result router"
|
||||
desc = "Routes a value into true, false, or invalid pulse outputs."
|
||||
icon_state = "template"
|
||||
complexity = 1
|
||||
inputs = list(
|
||||
"value" = IC_PINTYPE_ANY
|
||||
)
|
||||
outputs = list(
|
||||
"value" = IC_PINTYPE_ANY
|
||||
)
|
||||
activators = list(
|
||||
"evaluate" = IC_PINTYPE_PULSE_IN,
|
||||
"on true" = IC_PINTYPE_PULSE_OUT,
|
||||
"on false" = IC_PINTYPE_PULSE_OUT,
|
||||
"on invalid" = IC_PINTYPE_PULSE_OUT
|
||||
)
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
power_draw_per_use = 10
|
||||
|
||||
/obj/item/integrated_circuit/output/pulse_result/do_work()
|
||||
var/value = get_pin_data(IC_INPUT, 1, FALSE)
|
||||
|
||||
set_pin_data(IC_OUTPUT, 1, value)
|
||||
push_data()
|
||||
|
||||
if(isnull(value))
|
||||
activate_pin(4)
|
||||
else if(ic_truthy(value))
|
||||
activate_pin(2)
|
||||
else
|
||||
activate_pin(3)
|
||||
|
||||
/obj/item/integrated_circuit/output/light
|
||||
name = "light"
|
||||
desc = "This light can turn on and off on command."
|
||||
desc = "Turns a light on or off when pulsed."
|
||||
icon_state = "light"
|
||||
complexity = 4
|
||||
inputs = list()
|
||||
@@ -112,7 +216,7 @@
|
||||
|
||||
/obj/item/integrated_circuit/output/light/advanced
|
||||
name = "advanced light"
|
||||
desc = "This light can turn on and off on command, in any color, and in various brightness levels."
|
||||
desc = "Turns a configurable colored light on or off when pulsed."
|
||||
icon_state = "light_adv"
|
||||
complexity = 8
|
||||
inputs = list(
|
||||
@@ -128,7 +232,7 @@
|
||||
|
||||
/obj/item/integrated_circuit/output/sound
|
||||
name = "speaker circuit"
|
||||
desc = "A miniature speaker is attached to this component."
|
||||
desc = "Plays sounds from the assembly."
|
||||
icon_state = "speaker"
|
||||
complexity = 8
|
||||
cooldown_per_use = 1 SECOND
|
||||
@@ -144,8 +248,8 @@
|
||||
|
||||
/obj/item/integrated_circuit/output/text_to_speech
|
||||
name = "text-to-speech circuit"
|
||||
desc = "A miniature speaker is attached to this component."
|
||||
extended_desc = "This unit is more advanced than the plain speaker circuit, able to transpose any valid text to speech."
|
||||
desc = "Plays sounds from the assembly."
|
||||
extended_desc = "Converts valid text input into spoken audio."
|
||||
icon_state = "speaker"
|
||||
complexity = 12
|
||||
cooldown_per_use = 1 SECOND
|
||||
@@ -156,10 +260,30 @@
|
||||
power_draw_per_use = 600
|
||||
|
||||
/obj/item/integrated_circuit/output/text_to_speech/do_work()
|
||||
text = get_pin_data(IC_INPUT, 1)
|
||||
if(!isnull(text))
|
||||
var/obj/O = assembly ? loc : assembly
|
||||
audible_message("[icon2html(O, viewers(get_turf(O)))] \The [O.name] states, \"[text]\"")
|
||||
var/text = get_pin_data(IC_INPUT, 1)
|
||||
|
||||
if(isnull(text))
|
||||
return
|
||||
|
||||
/*
|
||||
* If this TTS circuit is inside an electronic radio headset,
|
||||
* output privately to the headset wearer only.
|
||||
*/
|
||||
var/obj/item/electronic_assembly/clothing/A = loc
|
||||
|
||||
if(istype(A))
|
||||
var/obj/item/radio/headset/circuitry/H = A.clothing
|
||||
|
||||
if(istype(H))
|
||||
H.private_tts_output(text)
|
||||
return
|
||||
|
||||
/*
|
||||
* Fallback behavior for every TTS circuit outside the electronic radio headset.
|
||||
*/
|
||||
var/obj/O = loc ? loc : src
|
||||
var/turf/T = get_turf(O)
|
||||
audible_message("[icon2html(O, viewers(T))] \The [O.name] states, \"[text]\"")
|
||||
|
||||
/obj/item/integrated_circuit/output/sound/Initialize()
|
||||
. = ..()
|
||||
@@ -183,7 +307,7 @@
|
||||
|
||||
/obj/item/integrated_circuit/output/sound/beeper
|
||||
name = "beeper circuit"
|
||||
desc = "A miniature speaker is attached to this component. This is often used in the construction of motherboards, which use \
|
||||
desc = "Plays sounds from the assembly. This is often used in the construction of motherboards, which use \
|
||||
the speaker to tell the user if something goes very wrong when booting up. It can also do other similar synthetic sounds such \
|
||||
as buzzing, pinging, chiming, and more."
|
||||
sounds = list(
|
||||
@@ -200,7 +324,7 @@
|
||||
|
||||
/obj/item/integrated_circuit/output/sound/beepsky
|
||||
name = "securitron sound circuit"
|
||||
desc = "A miniature speaker is attached to this component. Considered by some to be the essential component for a securitron."
|
||||
desc = "A miniature speaker that plays alert tones or warning sounds."
|
||||
sounds = list(
|
||||
"creep" = 'sound/voice/bcreep.ogg',
|
||||
"criminal" = 'sound/voice/bcriminal.ogg',
|
||||
@@ -215,7 +339,7 @@
|
||||
|
||||
/obj/item/integrated_circuit/output/sound/medbot
|
||||
name = "medibot sound circuit"
|
||||
desc = "A miniature speaker is attached to this component, used to annoy patients while they get pricked by a medbot."
|
||||
desc = "A miniature speaker that plays medical bot audio cues."
|
||||
sounds = list(
|
||||
"surgeon" = 'sound/voice/medbot/msurgeon.ogg',
|
||||
"radar" = 'sound/voice/medbot/mradar.ogg',
|
||||
@@ -237,8 +361,8 @@
|
||||
|
||||
/obj/item/integrated_circuit/output/video_camera
|
||||
name = "video camera circuit"
|
||||
desc = "This small camera allows a remote viewer to see what it sees."
|
||||
extended_desc = "The camera is linked to the Research camera network by default, but can be changed."
|
||||
desc = "Creates a camera feed from the assembly's position."
|
||||
extended_desc = "Creates a camera feed. It uses the Research camera network by default, but the network can be changed."
|
||||
icon_state = "video_camera"
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
complexity = 10
|
||||
@@ -295,8 +419,8 @@
|
||||
|
||||
/obj/item/integrated_circuit/output/led
|
||||
name = "light-emitting diode"
|
||||
desc = "This a LED that is lit whenever there is TRUE-equivalent data on its input."
|
||||
extended_desc = "TRUE-equivalent values are: Non-empty strings, non-zero numbers, and valid refs."
|
||||
desc = "This LED lights while its input contains TRUE-equivalent data."
|
||||
extended_desc = "TRUE values include non-empty text, non-zero numbers, valid refs, and populated lists. FALSE values include null, 0, and empty text."
|
||||
complexity = 0.1
|
||||
icon_state = "led"
|
||||
inputs = list("lit" = IC_PINTYPE_BOOLEAN)
|
||||
@@ -375,7 +499,7 @@
|
||||
|
||||
/obj/item/integrated_circuit/output/printer
|
||||
name = "printer"
|
||||
desc = "This printer can print text to a sheet of paper. If the eject pin is set or the paper is full of text it will eject the paper after printing"
|
||||
desc = "Prints text to paper. If the eject input is enabled, or if the paper is full, the paper is ejected after printing."
|
||||
icon_state = "screen"
|
||||
inputs = list("printed data" = IC_PINTYPE_ANY, "paper source" = IC_PINTYPE_REF, "eject sheet" = IC_PINTYPE_BOOLEAN)
|
||||
outputs = list()
|
||||
@@ -410,6 +534,8 @@
|
||||
paper_sheet.set_content(null, copytext(stuff_to_print, 1, MAX_PAPER_MESSAGE_LEN))
|
||||
stuff_to_print = copytext(stuff_to_print, MAX_PAPER_MESSAGE_LEN)
|
||||
if(stuff_to_print || eject)
|
||||
if(!using_tray)
|
||||
return
|
||||
paper_sheet = paper_source.get_item(TRUE)
|
||||
audible_message(SPAN_NOTICE("\The [src] buzzes and spits out a sheet of paper."))
|
||||
paper_sheet.forceMove(get_turf(src))
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
/*
|
||||
* subtypes/power.dm
|
||||
* Active power-management circuits that expose assembly charge, draw, and cell state to the circuit network.
|
||||
*/
|
||||
|
||||
/obj/item/integrated_circuit/power/
|
||||
category_text = "Power - Active"
|
||||
|
||||
/obj/item/integrated_circuit/power/transmitter
|
||||
name = "power transmission circuit"
|
||||
desc = "This can wirelessly transmit electricity from an assembly's battery towards a nearby machine."
|
||||
desc = "Wirelessly transmits electricity from an assembly battery to a nearby machine."
|
||||
icon_state = "power_transmitter"
|
||||
extended_desc = "This circuit transmits 5 kJ of electricity every time the activator pin is pulsed. The input pin must be \
|
||||
a reference to a machine to send electricity to. This can be a battery, or anything containing a battery. The machine can exist \
|
||||
@@ -25,7 +30,7 @@
|
||||
|
||||
/obj/item/integrated_circuit/power/transmitter/large
|
||||
name = "large power transmission circuit"
|
||||
desc = "This can wirelessly transmit a lot of electricity from an assembly's battery towards a nearby machine. Warning: Do not operate in flammable enviroments."
|
||||
desc = "Wirelessly transmits a large amount of electricity from an assembly battery to a nearby machine. Avoid use near flammable environments."
|
||||
extended_desc = "This circuit transmits 20 kJ of electricity every time the activator pin is pulsed. The input pin must be \
|
||||
a reference to a machine to send electricity to. This can be a battery, or anything containing a battery. The machine can exist \
|
||||
inside the assembly, or adjacent to it. The power is sourced from the assembly's power cell. If the target is outside of the assembly, \
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
/*
|
||||
* subtypes/reagents.dm
|
||||
* Reagent circuits for reading containers, transferring chemicals, and exposing reagent metadata.
|
||||
*/
|
||||
|
||||
/obj/item/integrated_circuit/reagent
|
||||
category_text = "Reagent"
|
||||
var/volume = 0
|
||||
@@ -10,7 +15,7 @@
|
||||
|
||||
/obj/item/integrated_circuit/reagent/injector
|
||||
name = "integrated hypo-injector"
|
||||
desc = "This scary looking thing is able to pump liquids into whatever it's pointed at."
|
||||
desc = "Pumps reagents into the targeted adjacent container or target."
|
||||
icon_state = "injector"
|
||||
extended_desc = "This autoinjector can push reagents into another container or someone else outside of the machine. The target \
|
||||
must be adjacent to the machine, and if it is a person, they cannot be wearing thick clothing."
|
||||
@@ -19,7 +24,7 @@
|
||||
cooldown_per_use = 6 SECONDS
|
||||
inputs = list("target" = IC_PINTYPE_REF, "injection amount" = IC_PINTYPE_NUMBER)
|
||||
inputs_default = list("2" = 5)
|
||||
outputs = list("volume used" = IC_PINTYPE_NUMBER,"self reference" = IC_PINTYPE_REF)
|
||||
outputs = list("volume used" = IC_PINTYPE_NUMBER, "self reference" = IC_PINTYPE_REF)
|
||||
activators = list("inject" = IC_PINTYPE_PULSE_IN, "on injected" = IC_PINTYPE_PULSE_OUT, "on fail" = IC_PINTYPE_PULSE_OUT)
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
volume = 30
|
||||
@@ -27,11 +32,13 @@
|
||||
var/direc = 1
|
||||
var/transfer_amount = 10
|
||||
|
||||
|
||||
/obj/item/integrated_circuit/reagent/injector/interact(mob/user)
|
||||
set_pin_data(IC_OUTPUT, 2, src)
|
||||
push_data()
|
||||
..()
|
||||
|
||||
|
||||
/obj/item/integrated_circuit/reagent/injector/on_reagent_change()
|
||||
set_pin_data(IC_OUTPUT, 1, reagents.total_volume)
|
||||
push_data()
|
||||
@@ -39,94 +46,144 @@
|
||||
|
||||
/obj/item/integrated_circuit/reagent/injector/on_data_written()
|
||||
var/new_amount = get_pin_data(IC_INPUT, 2)
|
||||
|
||||
if(!isnum(new_amount))
|
||||
return
|
||||
|
||||
if(new_amount < 0)
|
||||
new_amount = -new_amount
|
||||
direc = 0
|
||||
else
|
||||
direc = 1
|
||||
if(isnum(new_amount))
|
||||
new_amount = clamp(new_amount, 0, volume)
|
||||
transfer_amount = new_amount
|
||||
|
||||
new_amount = clamp(new_amount, 0, volume)
|
||||
transfer_amount = new_amount
|
||||
|
||||
|
||||
/obj/item/integrated_circuit/reagent/injector/do_work()
|
||||
set waitfor = 0 // Don't sleep in a proc that is called by a processor without this set, otherwise it'll delay the entire thing
|
||||
|
||||
var/atom/movable/AM = get_pin_data_as_type(IC_INPUT, 1, /atom/movable)
|
||||
if(!istype(AM)) //Invalid input
|
||||
|
||||
if(!istype(AM))
|
||||
activate_pin(3)
|
||||
return
|
||||
|
||||
if(direc == 1)
|
||||
if(!reagents || !reagents.total_volume)
|
||||
activate_pin(3)
|
||||
return
|
||||
|
||||
if(!istype(AM)) //Invalid input
|
||||
if(!AM.can_be_injected_by(src))
|
||||
activate_pin(3)
|
||||
return
|
||||
if(!reagents.total_volume) // Empty
|
||||
activate_pin(3)
|
||||
return
|
||||
if(AM.can_be_injected_by(src))
|
||||
if(isliving(AM))
|
||||
var/mob/living/L = AM
|
||||
var/turf/T = get_turf(AM)
|
||||
|
||||
if(isliving(AM))
|
||||
var/mob/living/L = AM
|
||||
var/turf/T = get_turf(AM)
|
||||
|
||||
if(T)
|
||||
T.visible_message(SPAN_WARNING("[assembly] is trying to inject [L]!"))
|
||||
sleep(3 SECONDS)
|
||||
if(!L.can_be_injected_by(src))
|
||||
activate_pin(3)
|
||||
return
|
||||
var/contained = reagents.get_reagents()
|
||||
var/trans = reagents.trans_to_mob(L, transfer_amount, CHEM_BLOOD)
|
||||
message_admins("[assembly] injected \the [L] with [trans]u of [contained].")
|
||||
to_chat(AM, SPAN_NOTICE("You feel a tiny prick!"))
|
||||
visible_message(SPAN_WARNING("[assembly] injects [L]!"))
|
||||
else
|
||||
reagents.trans_to(AM, transfer_amount)
|
||||
else
|
||||
|
||||
if(reagents.total_volume >= volume) // Full
|
||||
addtimer(CALLBACK(src, PROC_REF(finish_living_injection), L), 3 SECONDS)
|
||||
return
|
||||
|
||||
if(reagents.trans_to(AM, transfer_amount))
|
||||
activate_pin(2)
|
||||
else
|
||||
activate_pin(3)
|
||||
|
||||
return
|
||||
|
||||
if(reagents.total_volume >= volume)
|
||||
activate_pin(3)
|
||||
return
|
||||
|
||||
var/obj/target = AM
|
||||
|
||||
if(!target.reagents)
|
||||
activate_pin(3)
|
||||
return
|
||||
|
||||
var/turf/TS = get_turf(src)
|
||||
var/turf/TT = get_turf(AM)
|
||||
|
||||
if(!TS || !TT || !TS.Adjacent(TT))
|
||||
activate_pin(3)
|
||||
return
|
||||
|
||||
var/tramount = clamp(min(transfer_amount, REAGENTS_FREE_SPACE(reagents)), 0, reagents.maximum_volume)
|
||||
|
||||
if(ismob(target))
|
||||
if(!istype(target, /mob/living/carbon))
|
||||
activate_pin(3)
|
||||
return
|
||||
var/obj/target = AM
|
||||
if(!target.reagents)
|
||||
activate_pin(3)
|
||||
return
|
||||
var/turf/TS = get_turf(src)
|
||||
var/turf/TT = get_turf(AM)
|
||||
if(!TS.Adjacent(TT))
|
||||
activate_pin(3)
|
||||
return
|
||||
var/tramount = clamp(min(transfer_amount, REAGENTS_FREE_SPACE(reagents)), 0, reagents.maximum_volume)
|
||||
if(ismob(target))//Blood!
|
||||
if(istype(target, /mob/living/carbon))
|
||||
var/mob/living/carbon/T = target
|
||||
if(!T.dna)
|
||||
if(T.reagents.trans_to_obj(src, tramount))
|
||||
activate_pin(2)
|
||||
else
|
||||
activate_pin(3)
|
||||
return
|
||||
if((T.mutations & NOCLONE)) //target done been et, no more blood in him
|
||||
if(T.reagents.trans_to_obj(src, tramount))
|
||||
activate_pin(2)
|
||||
else
|
||||
activate_pin(3)
|
||||
return
|
||||
T.take_blood(src,tramount)
|
||||
visible_message( SPAN_NOTICE("[assembly] takes a blood sample from [target]."))
|
||||
|
||||
var/mob/living/carbon/T = target
|
||||
|
||||
if(!T.dna)
|
||||
if(T.reagents.trans_to_obj(src, tramount))
|
||||
activate_pin(2)
|
||||
else
|
||||
activate_pin(3)
|
||||
return
|
||||
return
|
||||
|
||||
else //if not mob
|
||||
if(!target.reagents.total_volume)
|
||||
visible_message( SPAN_NOTICE("[target] is empty."))
|
||||
if(T.mutations & NOCLONE)
|
||||
if(T.reagents.trans_to_obj(src, tramount))
|
||||
activate_pin(2)
|
||||
else
|
||||
activate_pin(3)
|
||||
return
|
||||
target.reagents.trans_to_obj(src, tramount)
|
||||
return
|
||||
|
||||
T.take_blood(src, tramount)
|
||||
visible_message(SPAN_NOTICE("[assembly] takes a blood sample from [target]."))
|
||||
activate_pin(2)
|
||||
return
|
||||
|
||||
if(!target.reagents.total_volume)
|
||||
visible_message(SPAN_NOTICE("[target] is empty."))
|
||||
activate_pin(3)
|
||||
return
|
||||
|
||||
target.reagents.trans_to_obj(src, tramount)
|
||||
activate_pin(2)
|
||||
|
||||
|
||||
/obj/item/integrated_circuit/reagent/injector/proc/finish_living_injection(mob/living/L)
|
||||
if(QDELETED(src) || QDELETED(L))
|
||||
return
|
||||
|
||||
if(!assembly)
|
||||
activate_pin(3)
|
||||
return
|
||||
|
||||
if(!reagents || !reagents.total_volume)
|
||||
activate_pin(3)
|
||||
return
|
||||
|
||||
if(!L.can_be_injected_by(src))
|
||||
activate_pin(3)
|
||||
return
|
||||
|
||||
var/turf/TS = get_turf(src)
|
||||
var/turf/TL = get_turf(L)
|
||||
|
||||
if(!TS || !TL || !TS.Adjacent(TL))
|
||||
activate_pin(3)
|
||||
return
|
||||
|
||||
var/contained = reagents.get_reagents()
|
||||
var/trans = reagents.trans_to_mob(L, transfer_amount, CHEM_BLOOD)
|
||||
|
||||
if(trans)
|
||||
message_admins("[assembly] injected \the [L] with [trans]u of [contained].")
|
||||
to_chat(L, SPAN_NOTICE("You feel a tiny prick!"))
|
||||
visible_message(SPAN_WARNING("[assembly] injects [L]!"))
|
||||
activate_pin(2)
|
||||
else
|
||||
activate_pin(3)
|
||||
|
||||
/obj/item/integrated_circuit/reagent/pump
|
||||
name = "reagent pump"
|
||||
desc = "Moves liquids safely inside a machine, or even nearby it."
|
||||
desc = "Moves reagents inside the assembly or to nearby targets."
|
||||
icon_state = "reagent_pump"
|
||||
extended_desc = "This is a pump, which will move liquids from the source ref to the target ref. The third pin determines \
|
||||
how much liquid is moved per pulse, between 0 and 50. The pump can move reagents to any open container inside the machine, or \
|
||||
@@ -195,9 +252,9 @@
|
||||
|
||||
/obj/item/integrated_circuit/reagent/storage
|
||||
name = "reagent storage"
|
||||
desc = "Stores liquid inside, and away from electrical components. Can store up to 60u."
|
||||
desc = "Stores reagents safely inside the assembly. Can store up to 60u."
|
||||
icon_state = "reagent_storage"
|
||||
extended_desc = "This is effectively an internal beaker."
|
||||
extended_desc = "Functions as an internal beaker for the assembly."
|
||||
atom_flags = ATOM_FLAG_OPEN_CONTAINER
|
||||
complexity = 4
|
||||
inputs = list()
|
||||
@@ -218,9 +275,9 @@
|
||||
|
||||
/obj/item/integrated_circuit/reagent/storage/cryo
|
||||
name = "cryo reagent storage"
|
||||
desc = "Stores liquid inside, and away from electrical components. Can store up to 60u. This will also suppress reactions."
|
||||
desc = "Stores reagents safely inside the assembly. Can store up to 60u. This will also suppress reactions."
|
||||
icon_state = "reagent_storage_cryo"
|
||||
extended_desc = "This is effectively an internal cryo beaker."
|
||||
extended_desc = "Functions as an internal cryo beaker for the assembly."
|
||||
atom_flags = ATOM_FLAG_OPEN_CONTAINER | ATOM_FLAG_NO_REACT
|
||||
complexity = 8
|
||||
spawn_flags = IC_SPAWN_RESEARCH
|
||||
@@ -228,9 +285,9 @@
|
||||
|
||||
/obj/item/integrated_circuit/reagent/storage/big
|
||||
name = "big reagent storage"
|
||||
desc = "Stores liquid inside, and away from electrical components. Can store up to 180u."
|
||||
desc = "Stores reagents safely inside the assembly. Can store up to 180u."
|
||||
icon_state = "reagent_storage_big"
|
||||
extended_desc = "This is effectively an internal beaker."
|
||||
extended_desc = "Functions as an internal beaker for the assembly."
|
||||
atom_flags = ATOM_FLAG_OPEN_CONTAINER
|
||||
complexity = 16
|
||||
volume = 180
|
||||
@@ -239,9 +296,9 @@
|
||||
|
||||
/obj/item/integrated_circuit/reagent/storage/scan
|
||||
name = "reagent scanner"
|
||||
desc = "Stores liquid inside, and away from electrical components. Can store up to 60u. On pulse this beaker will send list of contained reagents, as well as analyse their taste."
|
||||
desc = "Stores reagents safely inside the assembly. Can store up to 60u. On pulse, outputs a list of contained reagents and analyzes their taste."
|
||||
icon_state = "reagent_scan"
|
||||
extended_desc = "Mostly useful for reagent filters."
|
||||
extended_desc = "Useful for reagent filters and other chemistry circuits that need a target reagent name."
|
||||
atom_flags = ATOM_FLAG_OPEN_CONTAINER
|
||||
complexity = 8
|
||||
outputs = list("volume used" = IC_PINTYPE_NUMBER,"self reference" = IC_PINTYPE_REF,"list of reagents" = IC_PINTYPE_LIST,"taste" = IC_PINTYPE_STRING)
|
||||
@@ -261,7 +318,7 @@
|
||||
|
||||
/obj/item/integrated_circuit/reagent/filter
|
||||
name = "reagent filter"
|
||||
desc = "Filtering liquids by list of desired or unwanted reagents."
|
||||
desc = "Filters reagents using a configured list of desired or blocked reagent names."
|
||||
icon_state = "reagent_filter"
|
||||
extended_desc = "This is a filter which will move liquids from the source ref to the target ref. \
|
||||
It will move all reagents, except list, given in fourth pin if amount value is positive.\
|
||||
|
||||
@@ -0,0 +1,878 @@
|
||||
GLOBAL_LIST_EMPTY(ic_database_servers)
|
||||
|
||||
/proc/ic_normalize_database_id(database_id)
|
||||
if(!istext(database_id) || !length(database_id))
|
||||
return "main"
|
||||
|
||||
return lowertext(database_id)
|
||||
|
||||
|
||||
/proc/ic_database_response(success = FALSE, response = null, status = "No response.")
|
||||
return list(
|
||||
"success" = success,
|
||||
"response" = response,
|
||||
"status" = status
|
||||
)
|
||||
|
||||
|
||||
/obj/item/integrated_circuit/server
|
||||
category_text = "Data Server"
|
||||
complexity = 2
|
||||
power_draw_per_use = 300
|
||||
spawn_flags = 0
|
||||
activators = list(
|
||||
"compute" = IC_PINTYPE_PULSE_IN,
|
||||
"on computed" = IC_PINTYPE_PULSE_OUT
|
||||
)
|
||||
|
||||
|
||||
/obj/item/integrated_circuit/server/proc/build_record_from_pins(field_count)
|
||||
var/list/record = list()
|
||||
|
||||
for(var/i = 1 to field_count)
|
||||
var/key = get_pin_data(IC_INPUT, (i * 2) - 1)
|
||||
if(istext(key) && length(key))
|
||||
record[key] = get_pin_data(IC_INPUT, i * 2)
|
||||
|
||||
return record
|
||||
|
||||
|
||||
/obj/item/integrated_circuit/server/database
|
||||
name = "database server"
|
||||
desc = "A keyed database server for integrated circuits."
|
||||
extended_desc = "Stores keyed values for server client circuits. Commands: GET, SET, DELETE, CLEAR, HAS, KEYS, LEN, APPEND."
|
||||
icon_state = "addition"
|
||||
complexity = 8
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
|
||||
inputs = list(
|
||||
"server id" = IC_PINTYPE_STRING,
|
||||
"command" = IC_PINTYPE_STRING,
|
||||
"key" = IC_PINTYPE_STRING,
|
||||
"value" = IC_PINTYPE_ANY
|
||||
)
|
||||
|
||||
inputs_default = list(
|
||||
"1" = "main",
|
||||
"2" = "GET"
|
||||
)
|
||||
|
||||
outputs = list(
|
||||
"success" = IC_PINTYPE_BOOLEAN,
|
||||
"response" = IC_PINTYPE_ANY,
|
||||
"status" = IC_PINTYPE_STRING
|
||||
)
|
||||
|
||||
var/database_id = "main"
|
||||
var/list/storage = list()
|
||||
|
||||
|
||||
/obj/item/integrated_circuit/server/database/Initialize()
|
||||
. = ..()
|
||||
register_database()
|
||||
|
||||
|
||||
/obj/item/integrated_circuit/server/database/Destroy()
|
||||
unregister_database()
|
||||
storage = null
|
||||
return ..()
|
||||
|
||||
|
||||
/obj/item/integrated_circuit/server/database/proc/register_database()
|
||||
database_id = ic_normalize_database_id(database_id)
|
||||
GLOB.ic_database_servers[database_id] = src
|
||||
|
||||
|
||||
/obj/item/integrated_circuit/server/database/proc/unregister_database()
|
||||
if(database_id && GLOB.ic_database_servers[database_id] == src)
|
||||
GLOB.ic_database_servers -= database_id
|
||||
|
||||
|
||||
/obj/item/integrated_circuit/server/database/proc/set_database_id(new_id)
|
||||
new_id = ic_normalize_database_id(new_id)
|
||||
|
||||
if(new_id == database_id)
|
||||
return
|
||||
|
||||
unregister_database()
|
||||
database_id = new_id
|
||||
register_database()
|
||||
|
||||
|
||||
/obj/item/integrated_circuit/server/database/proc/handle_request(command, key, value)
|
||||
if(!istext(command))
|
||||
return ic_database_response(FALSE, null, "Command must be text.")
|
||||
|
||||
command = uppertext(command)
|
||||
|
||||
switch(command)
|
||||
if("GET")
|
||||
if(!istext(key) || !length(key))
|
||||
return ic_database_response(FALSE, null, "GET requires a text key.")
|
||||
|
||||
return ic_database_response(TRUE, storage[key], "Read complete.")
|
||||
|
||||
if("SET")
|
||||
if(!istext(key) || !length(key))
|
||||
return ic_database_response(FALSE, null, "SET requires a text key.")
|
||||
|
||||
storage[key] = value
|
||||
return ic_database_response(TRUE, value, "Write complete.")
|
||||
|
||||
if("DELETE")
|
||||
if(!istext(key) || !length(key))
|
||||
return ic_database_response(FALSE, null, "DELETE requires a text key.")
|
||||
|
||||
var/existed = (key in storage)
|
||||
storage -= key
|
||||
|
||||
if(existed)
|
||||
return ic_database_response(TRUE, TRUE, "Deleted.")
|
||||
|
||||
return ic_database_response(FALSE, FALSE, "Key not found.")
|
||||
|
||||
if("CLEAR")
|
||||
storage.Cut()
|
||||
return ic_database_response(TRUE, TRUE, "Database cleared.")
|
||||
|
||||
if("HAS")
|
||||
if(!istext(key) || !length(key))
|
||||
return ic_database_response(FALSE, null, "HAS requires a text key.")
|
||||
|
||||
return ic_database_response(TRUE, (key in storage), "Check complete.")
|
||||
|
||||
if("KEYS")
|
||||
var/list/keys = list()
|
||||
|
||||
for(var/K in storage)
|
||||
keys.Add(K)
|
||||
|
||||
return ic_database_response(TRUE, keys, "Keys returned.")
|
||||
|
||||
if("LEN")
|
||||
return ic_database_response(TRUE, storage.len, "Length returned.")
|
||||
|
||||
if("APPEND")
|
||||
if(!istext(key) || !length(key))
|
||||
return ic_database_response(FALSE, null, "APPEND requires a text key.")
|
||||
|
||||
var/list/current = storage[key]
|
||||
|
||||
if(!islist(current))
|
||||
current = list()
|
||||
|
||||
current.Add(value)
|
||||
storage[key] = current
|
||||
|
||||
return ic_database_response(TRUE, current, "Append complete.")
|
||||
|
||||
return ic_database_response(FALSE, null, "Unknown command.")
|
||||
|
||||
|
||||
/obj/item/integrated_circuit/server/database/do_work()
|
||||
pull_data()
|
||||
|
||||
var/new_id = get_pin_data(IC_INPUT, 1)
|
||||
var/command = get_pin_data(IC_INPUT, 2)
|
||||
var/key = get_pin_data(IC_INPUT, 3)
|
||||
var/value = get_pin_data(IC_INPUT, 4)
|
||||
|
||||
set_database_id(new_id)
|
||||
|
||||
var/list/result = handle_request(command, key, value)
|
||||
|
||||
set_pin_data(IC_OUTPUT, 1, result["success"])
|
||||
set_pin_data(IC_OUTPUT, 2, result["response"])
|
||||
set_pin_data(IC_OUTPUT, 3, result["status"])
|
||||
|
||||
push_data()
|
||||
activate_pin(2)
|
||||
|
||||
|
||||
/obj/item/integrated_circuit/server/client
|
||||
name = "database client"
|
||||
desc = "Sends requests to a database server."
|
||||
extended_desc = "Targets a database server by server id. Commands: GET, SET, DELETE, CLEAR, HAS, KEYS, LEN, APPEND."
|
||||
icon_state = "addition"
|
||||
complexity = 4
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
|
||||
inputs = list(
|
||||
"server id" = IC_PINTYPE_STRING,
|
||||
"command" = IC_PINTYPE_STRING,
|
||||
"key" = IC_PINTYPE_STRING,
|
||||
"value" = IC_PINTYPE_ANY
|
||||
)
|
||||
|
||||
inputs_default = list(
|
||||
"1" = "main",
|
||||
"2" = "GET"
|
||||
)
|
||||
|
||||
outputs = list(
|
||||
"success" = IC_PINTYPE_BOOLEAN,
|
||||
"response" = IC_PINTYPE_ANY,
|
||||
"status" = IC_PINTYPE_STRING
|
||||
)
|
||||
|
||||
|
||||
/obj/item/integrated_circuit/server/client/do_work()
|
||||
pull_data()
|
||||
|
||||
var/database_id = ic_normalize_database_id(get_pin_data(IC_INPUT, 1))
|
||||
var/command = get_pin_data(IC_INPUT, 2)
|
||||
var/key = get_pin_data(IC_INPUT, 3)
|
||||
var/value = get_pin_data(IC_INPUT, 4)
|
||||
|
||||
var/list/result = ic_database_response(FALSE, null, "Server not found.")
|
||||
|
||||
var/obj/item/integrated_circuit/server/database/S = GLOB.ic_database_servers[database_id]
|
||||
|
||||
if(istype(S))
|
||||
result = S.handle_request(command, key, value)
|
||||
|
||||
set_pin_data(IC_OUTPUT, 1, result["success"])
|
||||
set_pin_data(IC_OUTPUT, 2, result["response"])
|
||||
set_pin_data(IC_OUTPUT, 3, result["status"])
|
||||
|
||||
push_data()
|
||||
activate_pin(2)
|
||||
|
||||
|
||||
/obj/item/integrated_circuit/server/scanner
|
||||
name = "database scanner"
|
||||
desc = "Outputs a list of active database server ids."
|
||||
extended_desc = "Useful for debugging database wiring or discovering which database servers are available."
|
||||
icon_state = "addition"
|
||||
complexity = 2
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
|
||||
inputs = list()
|
||||
|
||||
outputs = list(
|
||||
"server ids" = IC_PINTYPE_LIST,
|
||||
"server count" = IC_PINTYPE_NUMBER
|
||||
)
|
||||
|
||||
|
||||
/obj/item/integrated_circuit/server/scanner/do_work()
|
||||
var/list/server_ids = list()
|
||||
|
||||
for(var/database_id in GLOB.ic_database_servers)
|
||||
var/obj/item/integrated_circuit/server/database/S = GLOB.ic_database_servers[database_id]
|
||||
|
||||
if(istype(S))
|
||||
server_ids.Add(database_id)
|
||||
|
||||
set_pin_data(IC_OUTPUT, 1, server_ids)
|
||||
set_pin_data(IC_OUTPUT, 2, server_ids.len)
|
||||
|
||||
push_data()
|
||||
activate_pin(2)
|
||||
|
||||
|
||||
/obj/item/integrated_circuit/server/record_builder4
|
||||
name = "4-field record builder"
|
||||
desc = "Builds an associative list record from up to four key/value pairs."
|
||||
extended_desc = "This is useful for making database records like pressure, oxygen, temperature, and status."
|
||||
icon_state = "addition"
|
||||
complexity = 3
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
|
||||
inputs = list(
|
||||
"key 1" = IC_PINTYPE_STRING,
|
||||
"value 1" = IC_PINTYPE_ANY,
|
||||
"key 2" = IC_PINTYPE_STRING,
|
||||
"value 2" = IC_PINTYPE_ANY,
|
||||
"key 3" = IC_PINTYPE_STRING,
|
||||
"value 3" = IC_PINTYPE_ANY,
|
||||
"key 4" = IC_PINTYPE_STRING,
|
||||
"value 4" = IC_PINTYPE_ANY
|
||||
)
|
||||
|
||||
outputs = list(
|
||||
"record" = IC_PINTYPE_LIST
|
||||
)
|
||||
|
||||
|
||||
/obj/item/integrated_circuit/server/record_builder4/do_work()
|
||||
pull_data()
|
||||
|
||||
set_pin_data(IC_OUTPUT, 1, build_record_from_pins(4))
|
||||
|
||||
push_data()
|
||||
activate_pin(2)
|
||||
|
||||
|
||||
/obj/item/integrated_circuit/server/record_builder8
|
||||
name = "8-field record builder"
|
||||
desc = "Builds an associative list record from up to eight key/value pairs."
|
||||
extended_desc = "This is useful for larger database records."
|
||||
icon_state = "addition"
|
||||
complexity = 5
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
|
||||
inputs = list(
|
||||
"key 1" = IC_PINTYPE_STRING,
|
||||
"value 1" = IC_PINTYPE_ANY,
|
||||
"key 2" = IC_PINTYPE_STRING,
|
||||
"value 2" = IC_PINTYPE_ANY,
|
||||
"key 3" = IC_PINTYPE_STRING,
|
||||
"value 3" = IC_PINTYPE_ANY,
|
||||
"key 4" = IC_PINTYPE_STRING,
|
||||
"value 4" = IC_PINTYPE_ANY,
|
||||
"key 5" = IC_PINTYPE_STRING,
|
||||
"value 5" = IC_PINTYPE_ANY,
|
||||
"key 6" = IC_PINTYPE_STRING,
|
||||
"value 6" = IC_PINTYPE_ANY,
|
||||
"key 7" = IC_PINTYPE_STRING,
|
||||
"value 7" = IC_PINTYPE_ANY,
|
||||
"key 8" = IC_PINTYPE_STRING,
|
||||
"value 8" = IC_PINTYPE_ANY
|
||||
)
|
||||
|
||||
outputs = list(
|
||||
"record" = IC_PINTYPE_LIST
|
||||
)
|
||||
|
||||
|
||||
/obj/item/integrated_circuit/server/record_builder8/do_work()
|
||||
pull_data()
|
||||
|
||||
set_pin_data(IC_OUTPUT, 1, build_record_from_pins(8))
|
||||
|
||||
push_data()
|
||||
activate_pin(2)
|
||||
|
||||
|
||||
/obj/item/integrated_circuit/server/record_reader
|
||||
name = "record reader"
|
||||
desc = "Reads one field from an associative list record."
|
||||
extended_desc = "Use this after a database GET returns a record list."
|
||||
icon_state = "addition"
|
||||
complexity = 2
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
|
||||
inputs = list(
|
||||
"record" = IC_PINTYPE_LIST,
|
||||
"field" = IC_PINTYPE_STRING
|
||||
)
|
||||
|
||||
outputs = list(
|
||||
"value" = IC_PINTYPE_ANY,
|
||||
"found" = IC_PINTYPE_BOOLEAN
|
||||
)
|
||||
|
||||
|
||||
/obj/item/integrated_circuit/server/record_reader/do_work()
|
||||
pull_data()
|
||||
|
||||
var/list/record = get_pin_data(IC_INPUT, 1)
|
||||
var/field = get_pin_data(IC_INPUT, 2)
|
||||
|
||||
var/value = null
|
||||
var/found = FALSE
|
||||
|
||||
if(islist(record) && istext(field) && length(field))
|
||||
value = record[field]
|
||||
found = !isnull(value) || (field in record)
|
||||
|
||||
set_pin_data(IC_OUTPUT, 1, value)
|
||||
set_pin_data(IC_OUTPUT, 2, found)
|
||||
|
||||
push_data()
|
||||
activate_pin(2)
|
||||
|
||||
|
||||
/obj/item/integrated_circuit/server/record_writer
|
||||
name = "record writer"
|
||||
desc = "Writes one field into an associative list record."
|
||||
extended_desc = "Takes an existing record, writes a field, and outputs the edited record."
|
||||
icon_state = "addition"
|
||||
complexity = 2
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
|
||||
inputs = list(
|
||||
"record" = IC_PINTYPE_LIST,
|
||||
"field" = IC_PINTYPE_STRING,
|
||||
"value" = IC_PINTYPE_ANY
|
||||
)
|
||||
|
||||
outputs = list(
|
||||
"record" = IC_PINTYPE_LIST,
|
||||
"success" = IC_PINTYPE_BOOLEAN
|
||||
)
|
||||
|
||||
|
||||
/obj/item/integrated_circuit/server/record_writer/do_work()
|
||||
pull_data()
|
||||
|
||||
var/list/input_record = get_pin_data(IC_INPUT, 1)
|
||||
var/field = get_pin_data(IC_INPUT, 2)
|
||||
var/value = get_pin_data(IC_INPUT, 3)
|
||||
|
||||
var/list/output_record = list()
|
||||
var/success = FALSE
|
||||
|
||||
if(islist(input_record))
|
||||
output_record = input_record.Copy()
|
||||
|
||||
if(istext(field) && length(field))
|
||||
output_record[field] = value
|
||||
success = TRUE
|
||||
|
||||
set_pin_data(IC_OUTPUT, 1, output_record)
|
||||
set_pin_data(IC_OUTPUT, 2, success)
|
||||
|
||||
push_data()
|
||||
activate_pin(2)
|
||||
|
||||
|
||||
/obj/item/integrated_circuit/server/record_keys
|
||||
name = "record keys"
|
||||
desc = "Outputs a list of keys from an associative list record."
|
||||
extended_desc = "Useful for reading database records and checking their field names."
|
||||
icon_state = "addition"
|
||||
complexity = 2
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
|
||||
inputs = list(
|
||||
"record" = IC_PINTYPE_LIST
|
||||
)
|
||||
|
||||
outputs = list(
|
||||
"keys" = IC_PINTYPE_LIST,
|
||||
"length" = IC_PINTYPE_NUMBER
|
||||
)
|
||||
|
||||
|
||||
/obj/item/integrated_circuit/server/record_keys/do_work()
|
||||
pull_data()
|
||||
|
||||
var/list/record = get_pin_data(IC_INPUT, 1)
|
||||
var/list/keys = list()
|
||||
|
||||
if(islist(record))
|
||||
for(var/K in record)
|
||||
keys.Add(K)
|
||||
|
||||
set_pin_data(IC_OUTPUT, 1, keys)
|
||||
set_pin_data(IC_OUTPUT, 2, keys.len)
|
||||
|
||||
push_data()
|
||||
activate_pin(2)
|
||||
|
||||
|
||||
/obj/item/integrated_circuit/server/text_contains
|
||||
name = "text contains"
|
||||
desc = "Checks if one text value contains another."
|
||||
extended_desc = "Useful for filtering logs, messages, status strings, or command text."
|
||||
icon_state = "textpad"
|
||||
complexity = 2
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
|
||||
inputs = list(
|
||||
"text" = IC_PINTYPE_STRING,
|
||||
"search" = IC_PINTYPE_STRING,
|
||||
"case sensitive" = IC_PINTYPE_BOOLEAN
|
||||
)
|
||||
|
||||
inputs_default = list(
|
||||
"3" = FALSE
|
||||
)
|
||||
|
||||
outputs = list(
|
||||
"contains" = IC_PINTYPE_BOOLEAN,
|
||||
"position" = IC_PINTYPE_NUMBER
|
||||
)
|
||||
|
||||
|
||||
/obj/item/integrated_circuit/server/text_contains/do_work()
|
||||
pull_data()
|
||||
|
||||
var/text = get_pin_data(IC_INPUT, 1)
|
||||
var/search = get_pin_data(IC_INPUT, 2)
|
||||
var/case_sensitive = get_pin_data(IC_INPUT, 3)
|
||||
|
||||
var/position = 0
|
||||
|
||||
if(istext(text) && istext(search) && length(search))
|
||||
if(case_sensitive)
|
||||
position = findtext(text, search)
|
||||
else
|
||||
position = findtext(lowertext(text), lowertext(search))
|
||||
|
||||
set_pin_data(IC_OUTPUT, 1, position > 0)
|
||||
set_pin_data(IC_OUTPUT, 2, position)
|
||||
|
||||
push_data()
|
||||
activate_pin(2)
|
||||
|
||||
|
||||
/obj/item/integrated_circuit/server/queue_push
|
||||
name = "queue push"
|
||||
desc = "Adds a value to the end of a queue list."
|
||||
extended_desc = "Use this with database APPEND or with a retrieved list."
|
||||
icon_state = "addition"
|
||||
complexity = 2
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
|
||||
inputs = list(
|
||||
"queue" = IC_PINTYPE_LIST,
|
||||
"value" = IC_PINTYPE_ANY
|
||||
)
|
||||
|
||||
outputs = list(
|
||||
"queue" = IC_PINTYPE_LIST,
|
||||
"length" = IC_PINTYPE_NUMBER
|
||||
)
|
||||
|
||||
|
||||
/obj/item/integrated_circuit/server/queue_push/do_work()
|
||||
pull_data()
|
||||
|
||||
var/list/input_queue = get_pin_data(IC_INPUT, 1)
|
||||
var/value = get_pin_data(IC_INPUT, 2)
|
||||
|
||||
var/list/output_queue = list()
|
||||
|
||||
if(islist(input_queue))
|
||||
output_queue = input_queue.Copy()
|
||||
|
||||
output_queue.Add(value)
|
||||
|
||||
set_pin_data(IC_OUTPUT, 1, output_queue)
|
||||
set_pin_data(IC_OUTPUT, 2, output_queue.len)
|
||||
|
||||
push_data()
|
||||
activate_pin(2)
|
||||
|
||||
|
||||
/obj/item/integrated_circuit/server/queue_pop
|
||||
name = "queue pop"
|
||||
desc = "Removes and outputs the first value from a queue list."
|
||||
extended_desc = "Outputs the first list item separately, then outputs the remaining list as a new queue."
|
||||
icon_state = "subtraction"
|
||||
complexity = 2
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
|
||||
inputs = list(
|
||||
"queue" = IC_PINTYPE_LIST
|
||||
)
|
||||
|
||||
outputs = list(
|
||||
"value" = IC_PINTYPE_ANY,
|
||||
"remaining queue" = IC_PINTYPE_LIST,
|
||||
"had value" = IC_PINTYPE_BOOLEAN
|
||||
)
|
||||
|
||||
|
||||
/obj/item/integrated_circuit/server/queue_pop/do_work()
|
||||
pull_data()
|
||||
|
||||
var/list/input_queue = get_pin_data(IC_INPUT, 1)
|
||||
var/list/output_queue = list()
|
||||
var/value = null
|
||||
var/had_value = FALSE
|
||||
|
||||
if(islist(input_queue))
|
||||
output_queue = input_queue.Copy()
|
||||
|
||||
if(output_queue.len)
|
||||
value = output_queue[1]
|
||||
output_queue.Cut(1, 2)
|
||||
had_value = TRUE
|
||||
|
||||
set_pin_data(IC_OUTPUT, 1, value)
|
||||
set_pin_data(IC_OUTPUT, 2, output_queue)
|
||||
set_pin_data(IC_OUTPUT, 3, had_value)
|
||||
|
||||
push_data()
|
||||
activate_pin(2)
|
||||
|
||||
|
||||
/obj/item/integrated_circuit/server/list_first_last
|
||||
name = "list first/last"
|
||||
desc = "Outputs the first and last values from a list."
|
||||
extended_desc = "Useful for logs, queues, and message buffers."
|
||||
icon_state = "addition"
|
||||
complexity = 2
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
|
||||
inputs = list(
|
||||
"list" = IC_PINTYPE_LIST
|
||||
)
|
||||
|
||||
outputs = list(
|
||||
"first" = IC_PINTYPE_ANY,
|
||||
"last" = IC_PINTYPE_ANY,
|
||||
"length" = IC_PINTYPE_NUMBER,
|
||||
"has values" = IC_PINTYPE_BOOLEAN
|
||||
)
|
||||
|
||||
|
||||
/obj/item/integrated_circuit/server/list_first_last/do_work()
|
||||
pull_data()
|
||||
|
||||
var/list/input_list = get_pin_data(IC_INPUT, 1)
|
||||
|
||||
var/first = null
|
||||
var/last = null
|
||||
var/length = 0
|
||||
var/has_values = FALSE
|
||||
|
||||
if(islist(input_list))
|
||||
length = input_list.len
|
||||
|
||||
if(length)
|
||||
first = input_list[1]
|
||||
last = input_list[length]
|
||||
has_values = TRUE
|
||||
|
||||
set_pin_data(IC_OUTPUT, 1, first)
|
||||
set_pin_data(IC_OUTPUT, 2, last)
|
||||
set_pin_data(IC_OUTPUT, 3, length)
|
||||
set_pin_data(IC_OUTPUT, 4, has_values)
|
||||
|
||||
push_data()
|
||||
activate_pin(2)
|
||||
|
||||
|
||||
/obj/item/integrated_circuit/server/database_counter
|
||||
name = "database counter client"
|
||||
desc = "Reads a numeric database value, changes it, and writes it back."
|
||||
extended_desc = "Useful for scores, cycle counts, alarm counts, and quotas."
|
||||
icon_state = "addition"
|
||||
complexity = 5
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
|
||||
inputs = list(
|
||||
"server id" = IC_PINTYPE_STRING,
|
||||
"key" = IC_PINTYPE_STRING,
|
||||
"amount" = IC_PINTYPE_NUMBER
|
||||
)
|
||||
|
||||
inputs_default = list(
|
||||
"1" = "main",
|
||||
"3" = 1
|
||||
)
|
||||
|
||||
outputs = list(
|
||||
"success" = IC_PINTYPE_BOOLEAN,
|
||||
"new value" = IC_PINTYPE_NUMBER,
|
||||
"status" = IC_PINTYPE_STRING
|
||||
)
|
||||
|
||||
|
||||
/obj/item/integrated_circuit/server/database_counter/do_work()
|
||||
pull_data()
|
||||
|
||||
var/database_id = ic_normalize_database_id(get_pin_data(IC_INPUT, 1))
|
||||
var/key = get_pin_data(IC_INPUT, 2)
|
||||
var/amount = get_pin_data(IC_INPUT, 3)
|
||||
|
||||
var/success = FALSE
|
||||
var/new_value = 0
|
||||
var/status = "Server not found."
|
||||
|
||||
if(isnull(amount))
|
||||
amount = 1
|
||||
|
||||
if(!istext(key) || !length(key))
|
||||
status = "Counter requires a text key."
|
||||
else
|
||||
var/obj/item/integrated_circuit/server/database/S = GLOB.ic_database_servers[database_id]
|
||||
|
||||
if(istype(S))
|
||||
var/current = S.storage[key]
|
||||
|
||||
if(isnum(current))
|
||||
new_value = current
|
||||
else
|
||||
new_value = 0
|
||||
|
||||
new_value += amount
|
||||
S.storage[key] = new_value
|
||||
|
||||
success = TRUE
|
||||
status = "Counter updated."
|
||||
|
||||
set_pin_data(IC_OUTPUT, 1, success)
|
||||
set_pin_data(IC_OUTPUT, 2, new_value)
|
||||
set_pin_data(IC_OUTPUT, 3, status)
|
||||
|
||||
push_data()
|
||||
activate_pin(2)
|
||||
|
||||
|
||||
/obj/item/integrated_circuit/server/database_compare_write
|
||||
name = "database compare-write client"
|
||||
desc = "Writes a database value only if the current value matches the expected value."
|
||||
extended_desc = "Useful for locks, queues, safe counters, and avoiding accidental overwrites."
|
||||
icon_state = "addition"
|
||||
complexity = 6
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
|
||||
inputs = list(
|
||||
"server id" = IC_PINTYPE_STRING,
|
||||
"key" = IC_PINTYPE_STRING,
|
||||
"expected value" = IC_PINTYPE_ANY,
|
||||
"new value" = IC_PINTYPE_ANY
|
||||
)
|
||||
|
||||
inputs_default = list(
|
||||
"1" = "main"
|
||||
)
|
||||
|
||||
outputs = list(
|
||||
"success" = IC_PINTYPE_BOOLEAN,
|
||||
"current value" = IC_PINTYPE_ANY,
|
||||
"status" = IC_PINTYPE_STRING
|
||||
)
|
||||
|
||||
|
||||
/obj/item/integrated_circuit/server/database_compare_write/do_work()
|
||||
pull_data()
|
||||
|
||||
var/database_id = ic_normalize_database_id(get_pin_data(IC_INPUT, 1))
|
||||
var/key = get_pin_data(IC_INPUT, 2)
|
||||
var/expected_value = get_pin_data(IC_INPUT, 3)
|
||||
var/new_value = get_pin_data(IC_INPUT, 4)
|
||||
|
||||
var/success = FALSE
|
||||
var/current_value = null
|
||||
var/status = "Server not found."
|
||||
|
||||
if(!istext(key) || !length(key))
|
||||
status = "Compare-write requires a text key."
|
||||
else
|
||||
var/obj/item/integrated_circuit/server/database/S = GLOB.ic_database_servers[database_id]
|
||||
|
||||
if(istype(S))
|
||||
current_value = S.storage[key]
|
||||
|
||||
if(current_value == expected_value)
|
||||
S.storage[key] = new_value
|
||||
current_value = new_value
|
||||
success = TRUE
|
||||
status = "Compare-write complete."
|
||||
else
|
||||
status = "Current value did not match expected value."
|
||||
|
||||
set_pin_data(IC_OUTPUT, 1, success)
|
||||
set_pin_data(IC_OUTPUT, 2, current_value)
|
||||
set_pin_data(IC_OUTPUT, 3, status)
|
||||
|
||||
push_data()
|
||||
activate_pin(2)
|
||||
|
||||
/obj/item/integrated_circuit/server/command_pad
|
||||
name = "database command pad"
|
||||
desc = "Parses typed text commands and sends them to a database server."
|
||||
extended_desc = "Commands: READ key, WRITE key value, DELETE key, HAS key, KEYS, LEN, CLEAR, APPEND key value."
|
||||
icon_state = "addition"
|
||||
complexity = 6
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
|
||||
inputs = list(
|
||||
"server id" = IC_PINTYPE_STRING,
|
||||
"command text" = IC_PINTYPE_STRING
|
||||
)
|
||||
|
||||
inputs_default = list(
|
||||
"1" = "research"
|
||||
)
|
||||
|
||||
outputs = list(
|
||||
"success" = IC_PINTYPE_BOOLEAN,
|
||||
"response" = IC_PINTYPE_ANY,
|
||||
"status" = IC_PINTYPE_STRING,
|
||||
"parsed command" = IC_PINTYPE_STRING,
|
||||
"parsed key" = IC_PINTYPE_STRING,
|
||||
"parsed value" = IC_PINTYPE_STRING
|
||||
)
|
||||
|
||||
activators = list(
|
||||
"submit" = IC_PINTYPE_PULSE_IN,
|
||||
"on accepted" = IC_PINTYPE_PULSE_OUT,
|
||||
"on rejected" = IC_PINTYPE_PULSE_OUT
|
||||
)
|
||||
|
||||
|
||||
/obj/item/integrated_circuit/server/command_pad/do_work()
|
||||
pull_data()
|
||||
|
||||
var/database_id = ic_normalize_database_id(get_pin_data(IC_INPUT, 1))
|
||||
var/raw_text = get_pin_data(IC_INPUT, 2)
|
||||
|
||||
var/success = FALSE
|
||||
var/response = null
|
||||
var/status = "No command."
|
||||
var/parsed_command = null
|
||||
var/parsed_key = null
|
||||
var/parsed_value = null
|
||||
|
||||
if(!istext(raw_text) || !length(raw_text))
|
||||
set_pin_data(IC_OUTPUT, 1, FALSE)
|
||||
set_pin_data(IC_OUTPUT, 2, null)
|
||||
set_pin_data(IC_OUTPUT, 3, "Command pad requires text.")
|
||||
set_pin_data(IC_OUTPUT, 4, null)
|
||||
set_pin_data(IC_OUTPUT, 5, null)
|
||||
set_pin_data(IC_OUTPUT, 6, null)
|
||||
push_data()
|
||||
activate_pin(3)
|
||||
return
|
||||
|
||||
var/text = trim(raw_text)
|
||||
var/first_space = findtext(text, " ")
|
||||
|
||||
if(first_space)
|
||||
parsed_command = uppertext(trim(copytext(text, 1, first_space)))
|
||||
var/remainder = trim(copytext(text, first_space + 1))
|
||||
|
||||
var/second_space = findtext(remainder, " ")
|
||||
if(second_space)
|
||||
parsed_key = trim(copytext(remainder, 1, second_space))
|
||||
parsed_value = trim(copytext(remainder, second_space + 1))
|
||||
else
|
||||
parsed_key = remainder
|
||||
else
|
||||
parsed_command = uppertext(text)
|
||||
|
||||
switch(parsed_command)
|
||||
if("READ")
|
||||
parsed_command = "GET"
|
||||
|
||||
if("WRITE")
|
||||
parsed_command = "SET"
|
||||
|
||||
if("REMOVE")
|
||||
parsed_command = "DELETE"
|
||||
|
||||
if("ADD")
|
||||
parsed_command = "APPEND"
|
||||
|
||||
var/obj/item/integrated_circuit/server/database/S = GLOB.ic_database_servers[database_id]
|
||||
|
||||
if(!istype(S))
|
||||
status = "Server not found."
|
||||
else
|
||||
var/list/result = S.handle_request(parsed_command, parsed_key, parsed_value)
|
||||
|
||||
success = result["success"]
|
||||
response = result["response"]
|
||||
status = result["status"]
|
||||
|
||||
set_pin_data(IC_OUTPUT, 1, success)
|
||||
set_pin_data(IC_OUTPUT, 2, response)
|
||||
set_pin_data(IC_OUTPUT, 3, status)
|
||||
set_pin_data(IC_OUTPUT, 4, parsed_command)
|
||||
set_pin_data(IC_OUTPUT, 5, parsed_key)
|
||||
set_pin_data(IC_OUTPUT, 6, parsed_value)
|
||||
|
||||
push_data()
|
||||
|
||||
if(success)
|
||||
activate_pin(2)
|
||||
else
|
||||
activate_pin(3)
|
||||
@@ -1,54 +1,86 @@
|
||||
/*
|
||||
* subtypes/smart.dm
|
||||
* Smart utility circuits such as pathfinding and higher-level automation helpers.
|
||||
*/
|
||||
|
||||
/obj/item/integrated_circuit/smart
|
||||
category_text = "Smart"
|
||||
spawn_flags = 0
|
||||
|
||||
/obj/item/integrated_circuit/smart/basic_pathfinder
|
||||
name = "basic pathfinder"
|
||||
desc = "This complex circuit is able to determine what direction a given target is."
|
||||
extended_desc = "This circuit uses a miniturized integrated camera to determine where the target is. If the machine \
|
||||
desc = "Outputs the direction of the selected target."
|
||||
extended_desc = "This circuit uses a miniaturized integrated camera to determine where the target is. If the machine \
|
||||
cannot see the target, it will not be able to calculate the correct direction."
|
||||
icon_state = "numberpad"
|
||||
complexity = 5
|
||||
inputs = list("target" = IC_PINTYPE_REF,"ignore obstacles" = IC_PINTYPE_BOOLEAN)
|
||||
outputs = list("dir" = IC_PINTYPE_DIR)
|
||||
activators = list("calculate dir" = IC_PINTYPE_PULSE_IN, "on calculated" = IC_PINTYPE_PULSE_OUT,"not calculated" = IC_PINTYPE_PULSE_OUT)
|
||||
inputs = list(
|
||||
"target" = IC_PINTYPE_REF,
|
||||
"ignore obstacles" = IC_PINTYPE_BOOLEAN
|
||||
)
|
||||
outputs = list(
|
||||
"dir" = IC_PINTYPE_DIR
|
||||
)
|
||||
activators = list(
|
||||
"calculate dir" = IC_PINTYPE_PULSE_IN,
|
||||
"on calculated" = IC_PINTYPE_PULSE_OUT,
|
||||
"not calculated" = IC_PINTYPE_PULSE_OUT
|
||||
)
|
||||
spawn_flags = IC_SPAWN_RESEARCH
|
||||
power_draw_per_use = 400
|
||||
|
||||
/obj/item/integrated_circuit/smart/basic_pathfinder/do_work()
|
||||
var/datum/integrated_io/I = inputs[1]
|
||||
set_pin_data(IC_OUTPUT, 1, null)
|
||||
|
||||
if(!isweakref(I.data))
|
||||
activate_pin(3)
|
||||
return
|
||||
var/atom/A = I.data.resolve()
|
||||
|
||||
var/datum/weakref/W = I.data
|
||||
var/atom/A = W.resolve()
|
||||
|
||||
if(!A)
|
||||
activate_pin(3)
|
||||
return
|
||||
if(!(A in view(get_turf(src))))
|
||||
|
||||
var/turf/start = get_turf(src)
|
||||
var/turf/target_turf = get_turf(A)
|
||||
|
||||
if(!start || !target_turf || !(A in view(start)))
|
||||
push_data()
|
||||
activate_pin(3)
|
||||
return // Can't see the target.
|
||||
return
|
||||
|
||||
if(get_pin_data(IC_INPUT, 2))
|
||||
set_pin_data(IC_OUTPUT, 1, get_dir(get_turf(src), get_turf(A)))
|
||||
set_pin_data(IC_OUTPUT, 1, get_dir(start, target_turf))
|
||||
else
|
||||
set_pin_data(IC_OUTPUT, 1, get_dir(get_turf(src), get_step_towards2(get_turf(src),A)))
|
||||
set_pin_data(IC_OUTPUT, 1, get_dir(start, get_step_towards2(start, A)))
|
||||
|
||||
push_data()
|
||||
activate_pin(2)
|
||||
|
||||
/obj/item/integrated_circuit/smart/coord_basic_pathfinder
|
||||
name = "coordinate pathfinder"
|
||||
desc = "This complex circuit is able to determine what direction a given target is."
|
||||
extended_desc = "This circuit uses absolute coordinates to determine where the target is. If the machine \
|
||||
cannot see the target, it will not be able to calculate the correct direction. \
|
||||
desc = "Outputs the direction of the selected target."
|
||||
extended_desc = "This circuit uses absolute coordinates to determine where the target is. \
|
||||
This circuit will only work while inside an assembly."
|
||||
icon_state = "numberpad"
|
||||
complexity = 5
|
||||
inputs = list("X" = IC_PINTYPE_NUMBER,"Y" = IC_PINTYPE_NUMBER,"ignore obstacles" = IC_PINTYPE_BOOLEAN)
|
||||
outputs = list( "dir" = IC_PINTYPE_DIR,
|
||||
"distance" = IC_PINTYPE_NUMBER
|
||||
inputs = list(
|
||||
"X" = IC_PINTYPE_NUMBER,
|
||||
"Y" = IC_PINTYPE_NUMBER,
|
||||
"ignore obstacles" = IC_PINTYPE_BOOLEAN
|
||||
)
|
||||
outputs = list(
|
||||
"dir" = IC_PINTYPE_DIR,
|
||||
"distance" = IC_PINTYPE_NUMBER
|
||||
)
|
||||
activators = list(
|
||||
"calculate dir" = IC_PINTYPE_PULSE_IN,
|
||||
"on calculated" = IC_PINTYPE_PULSE_OUT,
|
||||
"not calculated" = IC_PINTYPE_PULSE_OUT
|
||||
)
|
||||
activators = list("calculate dir" = IC_PINTYPE_PULSE_IN, "on calculated" = IC_PINTYPE_PULSE_OUT,"not calculated" = IC_PINTYPE_PULSE_OUT)
|
||||
spawn_flags = IC_SPAWN_RESEARCH
|
||||
power_draw_per_use = 400
|
||||
|
||||
@@ -56,18 +88,547 @@
|
||||
if(!assembly)
|
||||
activate_pin(3)
|
||||
return
|
||||
|
||||
var/turf/T = get_turf(assembly)
|
||||
var/target_x = clamp(get_pin_data(IC_INPUT, 1), 0, world.maxx)
|
||||
var/target_y = clamp(get_pin_data(IC_INPUT, 2), 0, world.maxy)
|
||||
var/turf/A = locate(target_x, target_y, T.z)
|
||||
set_pin_data(IC_OUTPUT, 1, null)
|
||||
if(!A||A==T)
|
||||
if(!T)
|
||||
activate_pin(3)
|
||||
return
|
||||
if(get_pin_data(IC_INPUT, 2))
|
||||
set_pin_data(IC_OUTPUT, 1, get_dir(get_turf(src), get_turf(A)))
|
||||
|
||||
var/target_x = round(clamp(get_pin_data(IC_INPUT, 1), 1, world.maxx))
|
||||
var/target_y = round(clamp(get_pin_data(IC_INPUT, 2), 1, world.maxy))
|
||||
var/turf/A = locate(target_x, target_y, T.z)
|
||||
|
||||
set_pin_data(IC_OUTPUT, 1, null)
|
||||
|
||||
if(!A || A == T)
|
||||
push_data()
|
||||
activate_pin(3)
|
||||
return
|
||||
|
||||
if(get_pin_data(IC_INPUT, 3))
|
||||
set_pin_data(IC_OUTPUT, 1, get_dir(T, A))
|
||||
else
|
||||
set_pin_data(IC_OUTPUT, 1, get_dir(get_turf(src), get_step_towards2(get_turf(src),A)))
|
||||
set_pin_data(IC_OUTPUT, 2, sqrt((A.x-T.x)*(A.x-T.x)+ (A.y-T.y)*(A.y-T.y)))
|
||||
set_pin_data(IC_OUTPUT, 1, get_dir(T, get_step_towards2(T, A)))
|
||||
|
||||
set_pin_data(IC_OUTPUT, 2, sqrt((A.x - T.x) * (A.x - T.x) + (A.y - T.y) * (A.y - T.y)))
|
||||
push_data()
|
||||
activate_pin(2)
|
||||
|
||||
/obj/item/integrated_circuit/smart/relative_position
|
||||
name = "relative position calculator"
|
||||
desc = "Calculates relative coordinates between two supplied references."
|
||||
extended_desc = "This does not scan, pathfind, or move anything. It only compares refs already supplied to the circuit and fails safely if either ref is invalid."
|
||||
icon_state = "numberpad"
|
||||
complexity = 5
|
||||
inputs = list(
|
||||
"origin ref" = IC_PINTYPE_REF,
|
||||
"target ref" = IC_PINTYPE_REF
|
||||
)
|
||||
outputs = list(
|
||||
"relative X" = IC_PINTYPE_NUMBER,
|
||||
"relative Y" = IC_PINTYPE_NUMBER,
|
||||
"relative Z" = IC_PINTYPE_NUMBER,
|
||||
"distance" = IC_PINTYPE_NUMBER,
|
||||
"valid" = IC_PINTYPE_BOOLEAN
|
||||
)
|
||||
activators = list(
|
||||
"calculate" = IC_PINTYPE_PULSE_IN,
|
||||
"on valid" = IC_PINTYPE_PULSE_OUT,
|
||||
"on invalid" = IC_PINTYPE_PULSE_OUT
|
||||
)
|
||||
spawn_flags = IC_SPAWN_RESEARCH
|
||||
power_draw_per_use = 200
|
||||
|
||||
/obj/item/integrated_circuit/smart/relative_position/do_work()
|
||||
var/origin = get_pin_data(IC_INPUT, 1)
|
||||
var/target = get_pin_data(IC_INPUT, 2)
|
||||
|
||||
if(!istype(origin, /atom) || !istype(target, /atom))
|
||||
set_relative_position_result(null, null, null, null, FALSE)
|
||||
return
|
||||
|
||||
var/turf/origin_turf = get_turf(origin)
|
||||
var/turf/target_turf = get_turf(target)
|
||||
|
||||
if(!origin_turf || !target_turf)
|
||||
set_relative_position_result(null, null, null, null, FALSE)
|
||||
return
|
||||
|
||||
var/dx = target_turf.x - origin_turf.x
|
||||
var/dy = target_turf.y - origin_turf.y
|
||||
var/dz = target_turf.z - origin_turf.z
|
||||
var/distance = sqrt(dx * dx + dy * dy + dz * dz)
|
||||
|
||||
set_relative_position_result(dx, dy, dz, distance, TRUE)
|
||||
|
||||
/obj/item/integrated_circuit/smart/relative_position/proc/set_relative_position_result(dx, dy, dz, distance, valid)
|
||||
set_pin_data(IC_OUTPUT, 1, dx)
|
||||
set_pin_data(IC_OUTPUT, 2, dy)
|
||||
set_pin_data(IC_OUTPUT, 3, dz)
|
||||
set_pin_data(IC_OUTPUT, 4, distance)
|
||||
set_pin_data(IC_OUTPUT, 5, valid)
|
||||
push_data()
|
||||
activate_pin(valid ? 2 : 3)
|
||||
|
||||
/obj/item/integrated_circuit/smart/coordinate_navigator
|
||||
name = "coordinate navigator"
|
||||
desc = "This complex circuit calculates a walkable path toward absolute coordinates."
|
||||
extended_desc = "This circuit finds a walkable cardinal path toward absolute coordinates. It can route around walls, long barriers, and U-shaped obstructions within its search limit. It is intended for drones using a locomotion circuit."
|
||||
icon_state = "numberpad"
|
||||
complexity = 20
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
size = 3
|
||||
power_draw_per_use = 800
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
|
||||
var/list/current_path = list()
|
||||
var/path_index = 1
|
||||
var/last_target_x = null
|
||||
var/last_target_y = null
|
||||
var/max_search_nodes = 600
|
||||
|
||||
inputs = list(
|
||||
"target X" = IC_PINTYPE_NUMBER,
|
||||
"target Y" = IC_PINTYPE_NUMBER,
|
||||
"recalculate if blocked" = IC_PINTYPE_BOOLEAN,
|
||||
"max search nodes" = IC_PINTYPE_NUMBER
|
||||
)
|
||||
|
||||
outputs = list(
|
||||
"direction" = IC_PINTYPE_DIR,
|
||||
"distance remaining" = IC_PINTYPE_NUMBER,
|
||||
"path length" = IC_PINTYPE_NUMBER,
|
||||
"status" = IC_PINTYPE_STRING
|
||||
)
|
||||
|
||||
activators = list(
|
||||
"calculate path" = IC_PINTYPE_PULSE_IN,
|
||||
"step path" = IC_PINTYPE_PULSE_IN,
|
||||
"clear path" = IC_PINTYPE_PULSE_IN,
|
||||
"on step ready" = IC_PINTYPE_PULSE_OUT,
|
||||
"on arrived" = IC_PINTYPE_PULSE_OUT,
|
||||
"on failed" = IC_PINTYPE_PULSE_OUT
|
||||
)
|
||||
|
||||
/obj/item/integrated_circuit/smart/coordinate_navigator/do_work(activator_id)
|
||||
if(!assembly)
|
||||
set_navigation_failure("Circuit is not installed in an assembly.")
|
||||
return
|
||||
|
||||
var/active_pin = activator_id
|
||||
|
||||
if(istype(active_pin, /datum/integrated_io))
|
||||
active_pin = activators.Find(active_pin)
|
||||
|
||||
if(istext(active_pin))
|
||||
for(var/i = 1 to activators.len)
|
||||
var/datum/integrated_io/A = activators[i]
|
||||
if(A.name == active_pin)
|
||||
active_pin = i
|
||||
break
|
||||
|
||||
if(!isnum(active_pin))
|
||||
active_pin = 1
|
||||
|
||||
switch(active_pin)
|
||||
if(1)
|
||||
calculate_path()
|
||||
return
|
||||
if(2)
|
||||
step_path()
|
||||
return
|
||||
if(3)
|
||||
clear_path()
|
||||
return
|
||||
|
||||
set_navigation_failure("Unknown navigation activator: [activator_id].")
|
||||
|
||||
/obj/item/integrated_circuit/smart/coordinate_navigator/proc/clear_path()
|
||||
current_path = list()
|
||||
path_index = 1
|
||||
last_target_x = null
|
||||
last_target_y = null
|
||||
|
||||
set_pin_data(IC_OUTPUT, 1, null)
|
||||
set_pin_data(IC_OUTPUT, 2, 0)
|
||||
set_pin_data(IC_OUTPUT, 3, 0)
|
||||
set_pin_data(IC_OUTPUT, 4, "Path cleared.")
|
||||
push_data()
|
||||
|
||||
/obj/item/integrated_circuit/smart/coordinate_navigator/proc/calculate_path()
|
||||
var/turf/start = get_turf(assembly)
|
||||
if(!start)
|
||||
set_navigation_failure("No assembly turf.")
|
||||
return
|
||||
|
||||
var/target_x = round(get_pin_data(IC_INPUT, 1))
|
||||
var/target_y = round(get_pin_data(IC_INPUT, 2))
|
||||
|
||||
if(!isnum(target_x) || !isnum(target_y))
|
||||
set_navigation_failure("Invalid target coordinates.")
|
||||
return
|
||||
|
||||
target_x = clamp(target_x, 1, world.maxx)
|
||||
target_y = clamp(target_y, 1, world.maxy)
|
||||
|
||||
var/turf/goal = locate(target_x, target_y, start.z)
|
||||
if(!goal)
|
||||
set_navigation_failure("Target turf does not exist.")
|
||||
return
|
||||
|
||||
if(start == goal)
|
||||
current_path = list(start)
|
||||
path_index = 1
|
||||
last_target_x = target_x
|
||||
last_target_y = target_y
|
||||
|
||||
set_pin_data(IC_OUTPUT, 1, null)
|
||||
set_pin_data(IC_OUTPUT, 2, 0)
|
||||
set_pin_data(IC_OUTPUT, 3, 1)
|
||||
set_pin_data(IC_OUTPUT, 4, "Already at target.")
|
||||
push_data()
|
||||
activate_pin(5)
|
||||
return
|
||||
|
||||
var/node_limit = round(get_pin_data(IC_INPUT, 4))
|
||||
if(!isnum(node_limit) || node_limit <= 0)
|
||||
node_limit = max_search_nodes
|
||||
|
||||
var/list/new_path = find_path_to_turf(start, goal, node_limit)
|
||||
|
||||
if(!new_path || !new_path.len)
|
||||
set_navigation_failure("No path found within [node_limit] nodes.")
|
||||
return
|
||||
|
||||
current_path = new_path
|
||||
path_index = 2
|
||||
last_target_x = target_x
|
||||
last_target_y = target_y
|
||||
|
||||
output_next_step("Path calculated.")
|
||||
|
||||
/obj/item/integrated_circuit/smart/coordinate_navigator/proc/step_path()
|
||||
var/turf/start = get_turf(assembly)
|
||||
if(!start)
|
||||
set_navigation_failure("No assembly turf.")
|
||||
return
|
||||
|
||||
var/target_x = round(get_pin_data(IC_INPUT, 1))
|
||||
var/target_y = round(get_pin_data(IC_INPUT, 2))
|
||||
|
||||
if(!isnum(target_x) || !isnum(target_y))
|
||||
set_navigation_failure("Invalid target coordinates.")
|
||||
return
|
||||
|
||||
target_x = clamp(target_x, 1, world.maxx)
|
||||
target_y = clamp(target_y, 1, world.maxy)
|
||||
|
||||
if(!current_path || !current_path.len)
|
||||
calculate_path()
|
||||
return
|
||||
|
||||
if(target_x != last_target_x || target_y != last_target_y)
|
||||
calculate_path()
|
||||
return
|
||||
|
||||
advance_path_index(start)
|
||||
|
||||
if(path_index > current_path.len)
|
||||
set_pin_data(IC_OUTPUT, 1, null)
|
||||
set_pin_data(IC_OUTPUT, 2, 0)
|
||||
set_pin_data(IC_OUTPUT, 3, current_path.len)
|
||||
set_pin_data(IC_OUTPUT, 4, "Arrived.")
|
||||
push_data()
|
||||
activate_pin(5)
|
||||
return
|
||||
|
||||
var/turf/next_turf = current_path[path_index]
|
||||
if(!next_turf || turf_is_blocked_for_navigation(next_turf))
|
||||
if(get_pin_data(IC_INPUT, 3))
|
||||
calculate_path()
|
||||
return
|
||||
|
||||
set_navigation_failure("Next path turf is blocked.")
|
||||
return
|
||||
|
||||
output_next_step("Step ready.")
|
||||
|
||||
/obj/item/integrated_circuit/smart/coordinate_navigator/proc/output_next_step(status)
|
||||
var/turf/start = get_turf(assembly)
|
||||
if(!start)
|
||||
set_navigation_failure("No assembly turf.")
|
||||
return
|
||||
|
||||
advance_path_index(start)
|
||||
|
||||
if(path_index > current_path.len)
|
||||
set_pin_data(IC_OUTPUT, 1, null)
|
||||
set_pin_data(IC_OUTPUT, 2, 0)
|
||||
set_pin_data(IC_OUTPUT, 3, current_path.len)
|
||||
set_pin_data(IC_OUTPUT, 4, "Arrived.")
|
||||
push_data()
|
||||
activate_pin(5)
|
||||
return
|
||||
|
||||
var/turf/next_turf = current_path[path_index]
|
||||
if(!next_turf)
|
||||
set_navigation_failure("Path index points to no turf.")
|
||||
return
|
||||
|
||||
if(get_dist(start, next_turf) > 1)
|
||||
if(get_pin_data(IC_INPUT, 3))
|
||||
calculate_path()
|
||||
return
|
||||
|
||||
set_navigation_failure("Path is stale.")
|
||||
return
|
||||
|
||||
if(turf_is_blocked_for_navigation(next_turf))
|
||||
if(get_pin_data(IC_INPUT, 3))
|
||||
calculate_path()
|
||||
return
|
||||
|
||||
set_navigation_failure("Next path turf is blocked.")
|
||||
return
|
||||
|
||||
var/dir_to_next = get_dir(start, next_turf)
|
||||
var/distance_remaining = max(0, current_path.len - path_index + 1)
|
||||
|
||||
set_pin_data(IC_OUTPUT, 1, dir_to_next)
|
||||
set_pin_data(IC_OUTPUT, 2, distance_remaining)
|
||||
set_pin_data(IC_OUTPUT, 3, current_path.len)
|
||||
set_pin_data(IC_OUTPUT, 4, status)
|
||||
push_data()
|
||||
activate_pin(4)
|
||||
|
||||
/obj/item/integrated_circuit/smart/coordinate_navigator/proc/advance_path_index(turf/current_turf)
|
||||
while(path_index <= current_path.len && current_path[path_index] == current_turf)
|
||||
path_index++
|
||||
|
||||
/obj/item/integrated_circuit/smart/coordinate_navigator/proc/set_navigation_failure(status)
|
||||
set_pin_data(IC_OUTPUT, 1, null)
|
||||
set_pin_data(IC_OUTPUT, 2, 0)
|
||||
set_pin_data(IC_OUTPUT, 3, current_path ? current_path.len : 0)
|
||||
set_pin_data(IC_OUTPUT, 4, status)
|
||||
push_data()
|
||||
activate_pin(6)
|
||||
|
||||
/obj/item/integrated_circuit/smart/coordinate_navigator/proc/find_path_to_turf(turf/start, turf/goal, node_limit)
|
||||
if(!start || !goal)
|
||||
return null
|
||||
|
||||
if(turf_is_blocked_for_navigation(goal))
|
||||
return null
|
||||
|
||||
var/list/queue = list(start)
|
||||
var/list/visited = list()
|
||||
var/list/parents = list()
|
||||
|
||||
visited[start] = TRUE
|
||||
|
||||
var/head = 1
|
||||
var/nodes_checked = 0
|
||||
var/found_goal = FALSE
|
||||
|
||||
while(head <= queue.len)
|
||||
var/turf/current = queue[head]
|
||||
head++
|
||||
nodes_checked++
|
||||
|
||||
if(nodes_checked > node_limit)
|
||||
break
|
||||
|
||||
if(current == goal)
|
||||
found_goal = TRUE
|
||||
break
|
||||
|
||||
for(var/check_dir in get_prioritized_dirs(current, goal))
|
||||
var/turf/next_turf = get_step(current, check_dir)
|
||||
if(!next_turf)
|
||||
continue
|
||||
|
||||
if(visited[next_turf])
|
||||
continue
|
||||
|
||||
if(turf_is_blocked_for_navigation(next_turf))
|
||||
continue
|
||||
|
||||
visited[next_turf] = TRUE
|
||||
parents[next_turf] = current
|
||||
queue += next_turf
|
||||
|
||||
if(!found_goal)
|
||||
return null
|
||||
|
||||
var/list/reversed_path = list()
|
||||
var/turf/walk = goal
|
||||
|
||||
while(walk)
|
||||
reversed_path += walk
|
||||
|
||||
if(walk == start)
|
||||
break
|
||||
|
||||
walk = parents[walk]
|
||||
|
||||
if(!walk)
|
||||
return null
|
||||
|
||||
var/list/final_path = list()
|
||||
for(var/i = reversed_path.len, i >= 1, i--)
|
||||
final_path += reversed_path[i]
|
||||
|
||||
return final_path
|
||||
|
||||
/obj/item/integrated_circuit/smart/coordinate_navigator/proc/get_prioritized_dirs(turf/current, turf/goal)
|
||||
var/list/dirs = list()
|
||||
|
||||
if(!current || !goal)
|
||||
return GLOB.cardinals
|
||||
|
||||
var/dx = goal.x - current.x
|
||||
var/dy = goal.y - current.y
|
||||
|
||||
if(abs(dx) >= abs(dy))
|
||||
if(dx > 0)
|
||||
dirs += EAST
|
||||
else if(dx < 0)
|
||||
dirs += WEST
|
||||
|
||||
if(dy > 0)
|
||||
dirs += NORTH
|
||||
else if(dy < 0)
|
||||
dirs += SOUTH
|
||||
else
|
||||
if(dy > 0)
|
||||
dirs += NORTH
|
||||
else if(dy < 0)
|
||||
dirs += SOUTH
|
||||
|
||||
if(dx > 0)
|
||||
dirs += EAST
|
||||
else if(dx < 0)
|
||||
dirs += WEST
|
||||
|
||||
for(var/D in GLOB.cardinals)
|
||||
if(!(D in dirs))
|
||||
dirs += D
|
||||
|
||||
return dirs
|
||||
|
||||
/obj/item/integrated_circuit/smart/coordinate_navigator/proc/turf_is_blocked_for_navigation(turf/T)
|
||||
if(!T)
|
||||
return TRUE
|
||||
|
||||
if(T.density)
|
||||
return TRUE
|
||||
|
||||
for(var/atom/movable/AM in T)
|
||||
if(AM == assembly)
|
||||
continue
|
||||
|
||||
if(AM.density)
|
||||
return TRUE
|
||||
|
||||
return FALSE
|
||||
|
||||
/obj/item/integrated_circuit/smart/coordinate_command_parser
|
||||
name = "coordinate command parser"
|
||||
desc = "Parses simple coordinate commands into X and Y number outputs."
|
||||
extended_desc = "This circuit parses text commands such as 'GOTO 25 56', '25 56', 'X 25 Y 56', or 'X=25 Y=56'. It outputs target X and Y coordinates for use with a coordinate navigator."
|
||||
icon_state = "numberpad"
|
||||
complexity = 6
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
size = 1
|
||||
power_draw_per_use = 200
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
|
||||
inputs = list(
|
||||
"command" = IC_PINTYPE_STRING
|
||||
)
|
||||
|
||||
outputs = list(
|
||||
"target X" = IC_PINTYPE_NUMBER,
|
||||
"target Y" = IC_PINTYPE_NUMBER,
|
||||
"valid" = IC_PINTYPE_BOOLEAN,
|
||||
"status" = IC_PINTYPE_STRING
|
||||
)
|
||||
|
||||
activators = list(
|
||||
"parse command" = IC_PINTYPE_PULSE_IN,
|
||||
"on parsed" = IC_PINTYPE_PULSE_OUT,
|
||||
"on failed" = IC_PINTYPE_PULSE_OUT
|
||||
)
|
||||
|
||||
/obj/item/integrated_circuit/smart/coordinate_command_parser/do_work()
|
||||
pull_data()
|
||||
|
||||
var/command = get_pin_data(IC_INPUT, 1)
|
||||
|
||||
if(!istext(command) || !length(command))
|
||||
set_parse_result(null, null, FALSE, "No command.")
|
||||
return
|
||||
|
||||
var/list/numbers = extract_numbers_from_command(command)
|
||||
|
||||
if(!numbers || numbers.len < 2)
|
||||
set_parse_result(null, null, FALSE, "Command needs two numbers.")
|
||||
return
|
||||
|
||||
var/target_x = round(numbers[1])
|
||||
var/target_y = round(numbers[2])
|
||||
|
||||
target_x = clamp(target_x, 1, world.maxx)
|
||||
target_y = clamp(target_y, 1, world.maxy)
|
||||
|
||||
set_parse_result(target_x, target_y, TRUE, "Parsed coordinates: [target_x], [target_y].")
|
||||
|
||||
/obj/item/integrated_circuit/smart/coordinate_command_parser/proc/set_parse_result(target_x, target_y, valid, status)
|
||||
set_pin_data(IC_OUTPUT, 1, target_x)
|
||||
set_pin_data(IC_OUTPUT, 2, target_y)
|
||||
set_pin_data(IC_OUTPUT, 3, valid)
|
||||
set_pin_data(IC_OUTPUT, 4, status)
|
||||
push_data()
|
||||
|
||||
if(valid)
|
||||
activate_pin(2)
|
||||
else
|
||||
activate_pin(3)
|
||||
|
||||
/obj/item/integrated_circuit/smart/coordinate_command_parser/proc/extract_numbers_from_command(command)
|
||||
var/list/numbers = list()
|
||||
var/current_number = ""
|
||||
var/reading_number = FALSE
|
||||
var/allow_negative = TRUE
|
||||
|
||||
for(var/i = 1 to length(command))
|
||||
var/char = copytext(command, i, i + 1)
|
||||
|
||||
if(char >= "0" && char <= "9")
|
||||
current_number += char
|
||||
reading_number = TRUE
|
||||
allow_negative = FALSE
|
||||
continue
|
||||
|
||||
if(char == "-" && allow_negative)
|
||||
current_number += char
|
||||
reading_number = TRUE
|
||||
allow_negative = FALSE
|
||||
continue
|
||||
|
||||
if(reading_number)
|
||||
var/parsed = text2num(current_number)
|
||||
if(!isnull(parsed))
|
||||
numbers += parsed
|
||||
|
||||
current_number = ""
|
||||
reading_number = FALSE
|
||||
|
||||
allow_negative = TRUE
|
||||
|
||||
if(reading_number)
|
||||
var/parsed = text2num(current_number)
|
||||
if(!isnull(parsed))
|
||||
numbers += parsed
|
||||
|
||||
return numbers
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
/*
|
||||
* subtypes/time.dm
|
||||
* Timing circuits: delays, clocks, pulses, cooldown-style behavior, and scheduled activation.
|
||||
*/
|
||||
|
||||
/obj/item/integrated_circuit/time
|
||||
name = "time circuit"
|
||||
desc = "Now you can build your own clock!"
|
||||
desc = "Outputs the current local time when pulsed."
|
||||
complexity = 2
|
||||
inputs = list()
|
||||
outputs = list()
|
||||
@@ -14,7 +19,7 @@
|
||||
var/delay = 2 SECONDS
|
||||
activators = list("incoming"= IC_PINTYPE_PULSE_IN,"outgoing" = IC_PINTYPE_PULSE_OUT)
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
power_draw_per_use = 20
|
||||
power_draw_per_use = 30
|
||||
|
||||
/obj/item/integrated_circuit/time/delay/do_work()
|
||||
addtimer(CALLBACK(src, TYPE_PROC_REF(/obj/item/integrated_circuit, activate_pin), 2), delay)
|
||||
@@ -26,6 +31,7 @@
|
||||
icon_state = "delay-50"
|
||||
delay = 5 SECONDS
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
power_draw_per_use = 20
|
||||
|
||||
/obj/item/integrated_circuit/time/delay/one_sec
|
||||
name = "one-sec delay circuit"
|
||||
@@ -34,30 +40,37 @@
|
||||
icon_state = "delay-10"
|
||||
delay = 1 SECOND
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
power_draw_per_use = 40
|
||||
|
||||
/obj/item/integrated_circuit/time/delay/half_sec
|
||||
name = "half-sec delay circuit"
|
||||
desc = "This sends a pulse signal out after a delay, critical for ensuring proper control flow in a complex machine. \
|
||||
This circuit is set to send a pulse after a delay of half a second."
|
||||
icon_state = "delay-5"
|
||||
complexity = 4
|
||||
delay = 5
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
power_draw_per_use = 60
|
||||
|
||||
/obj/item/integrated_circuit/time/delay/tenth_sec
|
||||
name = "tenth-sec delay circuit"
|
||||
desc = "This sends a pulse signal out after a delay, critical for ensuring proper control flow in a complex machine. \
|
||||
This circuit is set to send a pulse after a delay of 1/10th of a second."
|
||||
icon_state = "delay-1"
|
||||
complexity = 6
|
||||
delay = 1
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
power_draw_per_use = 100
|
||||
|
||||
/obj/item/integrated_circuit/time/delay/custom
|
||||
name = "custom delay circuit"
|
||||
desc = "This sends a pulse signal out after a delay, critical for ensuring proper control flow in a complex machine. \
|
||||
This circuit's delay can be customized, between 1/10th of a second to one hour. The delay is updated upon receiving a pulse."
|
||||
icon_state = "delay"
|
||||
complexity = 6
|
||||
inputs = list("delay time" = IC_PINTYPE_NUMBER)
|
||||
spawn_flags = IC_SPAWN_RESEARCH
|
||||
power_draw_per_use = 100
|
||||
|
||||
/obj/item/integrated_circuit/time/delay/custom/on_data_written()
|
||||
delay = between(1, get_pin_data(IC_INPUT, 1), 1 HOUR)
|
||||
@@ -65,10 +78,10 @@
|
||||
|
||||
/obj/item/integrated_circuit/time/ticker
|
||||
name = "ten second ticker"
|
||||
desc = "This circuit sends an automatic pulse every ten seconds."
|
||||
desc = "Sends an automatic pulse every ten seconds."
|
||||
icon_state = "tick-m"
|
||||
complexity = 8
|
||||
var/seconds_to_pulse = 10 SECONDS
|
||||
var/seconds_to_pulse = 10
|
||||
var/ticks_completed = 0
|
||||
var/is_running = FALSE
|
||||
inputs = list("enable ticking" = IC_PINTYPE_BOOLEAN)
|
||||
@@ -85,33 +98,51 @@
|
||||
if(do_tick && !is_running)
|
||||
is_running = TRUE
|
||||
START_PROCESSING(SSelectronics, src)
|
||||
else if(is_running)
|
||||
else if(!do_tick && is_running)
|
||||
is_running = FALSE
|
||||
STOP_PROCESSING(SSelectronics, src)
|
||||
ticks_completed = 0
|
||||
|
||||
/obj/item/integrated_circuit/time/ticker/process()
|
||||
var/process_ticks = SSelectronics.wait
|
||||
var/pulse_ticks = SecondsToTicks(seconds_to_pulse)
|
||||
ticks_completed += process_ticks
|
||||
if(ticks_completed >= SecondsToTicks(seconds_to_pulse))
|
||||
if(SecondsToTicks(seconds_to_pulse) >= process_ticks)
|
||||
ticks_completed -= SecondsToTicks(seconds_to_pulse)
|
||||
if(ticks_completed >= pulse_ticks)
|
||||
if(pulse_ticks >= process_ticks)
|
||||
ticks_completed -= pulse_ticks
|
||||
else
|
||||
ticks_completed = 0
|
||||
if(!check_power())
|
||||
power_fail()
|
||||
return
|
||||
activate_pin(1)
|
||||
|
||||
/obj/item/integrated_circuit/time/ticker/power_fail()
|
||||
is_running = FALSE
|
||||
STOP_PROCESSING(SSelectronics, src)
|
||||
ticks_completed = 0
|
||||
|
||||
/obj/item/integrated_circuit/time/ticker/rapid
|
||||
name = "one second ticker"
|
||||
desc = "Sends a high-speed automatic pulse every second."
|
||||
icon_state = "tick-f"
|
||||
complexity = 18
|
||||
seconds_to_pulse = 1
|
||||
spawn_flags = IC_SPAWN_RESEARCH
|
||||
power_draw_per_use = 240
|
||||
|
||||
/obj/item/integrated_circuit/time/ticker/fast
|
||||
name = "two second ticker"
|
||||
desc = "This advanced circuit sends an automatic pulse every two seconds."
|
||||
desc = "Sends an automatic pulse every two seconds."
|
||||
icon_state = "tick-f"
|
||||
complexity = 12
|
||||
seconds_to_pulse = 2
|
||||
spawn_flags = IC_SPAWN_RESEARCH
|
||||
power_draw_per_use = 80
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
power_draw_per_use = 120
|
||||
|
||||
/obj/item/integrated_circuit/time/ticker/slow
|
||||
name = "thirty second ticker"
|
||||
desc = "This simple circuit sends an automatic pulse every thirty seconds."
|
||||
desc = "Sends an automatic pulse every thirty seconds."
|
||||
icon_state = "tick-s"
|
||||
complexity = 4
|
||||
seconds_to_pulse = 30
|
||||
@@ -120,7 +151,7 @@
|
||||
|
||||
/obj/item/integrated_circuit/time/ticker/very_slow
|
||||
name = "five minute ticker"
|
||||
desc = "This simple circuit sends an automatic pulse every five minutes (three hundred seconds)."
|
||||
desc = "Sends an automatic pulse every five minutes."
|
||||
icon_state = "tick-s"
|
||||
complexity = 4
|
||||
seconds_to_pulse = 300
|
||||
@@ -129,12 +160,12 @@
|
||||
|
||||
/obj/item/integrated_circuit/time/ticker/custom
|
||||
name = "custom ticker"
|
||||
desc = "This advanced circuit sends an automatic pulse with a configurable interval between 2 and 600 seconds. Default: 60 seconds."
|
||||
desc = "Sends automatic pulses at a configurable interval between 2 and 600 seconds. Default: 60 seconds."
|
||||
icon_state = "tick-f"
|
||||
complexity = 15
|
||||
seconds_to_pulse = 60
|
||||
spawn_flags = IC_SPAWN_RESEARCH
|
||||
power_draw_per_use = 80
|
||||
power_draw_per_use = 120
|
||||
inputs = list("enable ticking" = IC_PINTYPE_BOOLEAN, "ticker time" = IC_PINTYPE_NUMBER)
|
||||
|
||||
/obj/item/integrated_circuit/time/ticker/custom/on_data_written()
|
||||
@@ -143,7 +174,7 @@
|
||||
|
||||
/obj/item/integrated_circuit/time/clock
|
||||
name = "integrated clock"
|
||||
desc = "Tells you what the local time is, specific to your station, planet, or facility."
|
||||
desc = "Outputs the local station, planet, or facility time."
|
||||
icon_state = "clock"
|
||||
inputs = list()
|
||||
outputs = list(
|
||||
@@ -164,3 +195,137 @@
|
||||
|
||||
push_data()
|
||||
activate_pin(2)
|
||||
|
||||
/obj/item/integrated_circuit/timed/signal_burst_ticker
|
||||
name = "signal burst ticker"
|
||||
desc = "A ticker that starts when pulsed, ticks a fixed number of times, then stops."
|
||||
extended_desc = "Useful when you want a signaler, scanner, button, or other pulse source to temporarily enable a repeating circuit chain. Pulse count is clamped from 1 to 20, and interval is clamped from 1 to 60 seconds."
|
||||
icon_state = "clock"
|
||||
complexity = 10
|
||||
spawn_flags = IC_SPAWN_RESEARCH
|
||||
category_text = "Time"
|
||||
power_draw_per_use = 160
|
||||
|
||||
inputs = list(
|
||||
"pulse count" = IC_PINTYPE_NUMBER,
|
||||
"interval seconds" = IC_PINTYPE_NUMBER,
|
||||
"enabled" = IC_PINTYPE_BOOLEAN
|
||||
)
|
||||
|
||||
inputs_default = list(
|
||||
"1" = 4,
|
||||
"2" = 2,
|
||||
"3" = TRUE
|
||||
)
|
||||
|
||||
outputs = list(
|
||||
"current pulse" = IC_PINTYPE_NUMBER,
|
||||
"running" = IC_PINTYPE_BOOLEAN
|
||||
)
|
||||
|
||||
activators = list(
|
||||
"start" = IC_PINTYPE_PULSE_IN,
|
||||
"stop" = IC_PINTYPE_PULSE_IN,
|
||||
"on pulse" = IC_PINTYPE_PULSE_OUT,
|
||||
"on finished" = IC_PINTYPE_PULSE_OUT
|
||||
)
|
||||
|
||||
var/running = FALSE
|
||||
var/current_tick = 0
|
||||
var/max_ticks = 4
|
||||
var/delay_time = 2 SECONDS
|
||||
var/burst_id = 0
|
||||
|
||||
|
||||
/obj/item/integrated_circuit/timed/signal_burst_ticker/do_work(activator_id)
|
||||
var/active_pin = activator_id
|
||||
|
||||
if(istype(active_pin, /datum/integrated_io))
|
||||
active_pin = activators.Find(active_pin)
|
||||
|
||||
if(!isnum(active_pin))
|
||||
active_pin = 1
|
||||
|
||||
if(active_pin == 2)
|
||||
stop_burst(FALSE)
|
||||
return
|
||||
|
||||
if(running)
|
||||
return
|
||||
|
||||
pull_data()
|
||||
|
||||
if(!get_pin_data(IC_INPUT, 3))
|
||||
stop_burst(FALSE)
|
||||
return
|
||||
|
||||
var/input_ticks = get_pin_data(IC_INPUT, 1)
|
||||
var/input_delay = get_pin_data(IC_INPUT, 2)
|
||||
|
||||
if(isnum(input_delay))
|
||||
input_delay = between(1, input_delay, 60)
|
||||
else
|
||||
input_delay = 2
|
||||
|
||||
if(isnum(input_ticks))
|
||||
input_ticks = between(1, round(input_ticks), 20)
|
||||
else
|
||||
input_ticks = 4
|
||||
|
||||
delay_time = input_delay SECONDS
|
||||
max_ticks = input_ticks
|
||||
current_tick = 0
|
||||
running = TRUE
|
||||
burst_id++
|
||||
|
||||
set_pin_data(IC_OUTPUT, 1, current_tick)
|
||||
set_pin_data(IC_OUTPUT, 2, running)
|
||||
push_data()
|
||||
|
||||
// Timer IDs make old callbacks harmless after stop/restart or deletion.
|
||||
addtimer(CALLBACK(src, PROC_REF(process_tick), burst_id), delay_time)
|
||||
|
||||
|
||||
/obj/item/integrated_circuit/timed/signal_burst_ticker/proc/process_tick(expected_burst_id)
|
||||
if(!running || expected_burst_id != burst_id)
|
||||
return
|
||||
|
||||
if(!check_power())
|
||||
power_fail()
|
||||
return
|
||||
|
||||
current_tick++
|
||||
|
||||
set_pin_data(IC_OUTPUT, 1, current_tick)
|
||||
set_pin_data(IC_OUTPUT, 2, running)
|
||||
push_data()
|
||||
activate_pin(3)
|
||||
|
||||
if(current_tick >= max_ticks)
|
||||
stop_burst(TRUE)
|
||||
return
|
||||
|
||||
addtimer(CALLBACK(src, PROC_REF(process_tick), expected_burst_id), delay_time)
|
||||
|
||||
/obj/item/integrated_circuit/timed/signal_burst_ticker/proc/stop_burst(finished)
|
||||
if(!running && !finished)
|
||||
set_pin_data(IC_OUTPUT, 2, FALSE)
|
||||
push_data()
|
||||
return
|
||||
|
||||
running = FALSE
|
||||
burst_id++
|
||||
set_pin_data(IC_OUTPUT, 2, running)
|
||||
push_data()
|
||||
|
||||
if(finished)
|
||||
activate_pin(4)
|
||||
|
||||
|
||||
/obj/item/integrated_circuit/timed/signal_burst_ticker/Destroy()
|
||||
running = FALSE
|
||||
burst_id++
|
||||
return ..()
|
||||
|
||||
/obj/item/integrated_circuit/timed/signal_burst_ticker/power_fail()
|
||||
stop_burst(FALSE)
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
/*
|
||||
* subtypes/trig.dm
|
||||
* Trigonometry and coordinate math circuits.
|
||||
*/
|
||||
|
||||
//These circuits do not-so-simple math.
|
||||
/obj/item/integrated_circuit/trig
|
||||
complexity = 1
|
||||
@@ -16,7 +21,7 @@
|
||||
"compute" = IC_PINTYPE_PULSE_IN,
|
||||
"on computed" = IC_PINTYPE_PULSE_OUT
|
||||
)
|
||||
category_text = "Trig"
|
||||
category_text = "MATH - Trigonometry"
|
||||
extended_desc = "Input and output are in degrees."
|
||||
power_draw_per_use = 10 // Still cheap math.
|
||||
|
||||
@@ -24,7 +29,7 @@
|
||||
|
||||
/obj/item/integrated_circuit/trig/sine
|
||||
name = "sin circuit"
|
||||
desc = "Has nothing to do with evil, unless you consider trigonometry to be evil. Outputs the sine of A."
|
||||
desc = "Outputs the sine of A."
|
||||
icon_state = "sine"
|
||||
inputs = list("A" = IC_PINTYPE_NUMBER)
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
@@ -64,7 +69,7 @@
|
||||
|
||||
/obj/item/integrated_circuit/trig/tangent
|
||||
name = "tan circuit"
|
||||
desc = "Outputs the tangent of A. Guaranteed to not go on a tangent about its existance."
|
||||
desc = "Outputs the tangent of A."
|
||||
icon_state = "tangent"
|
||||
inputs = list("A" = IC_PINTYPE_NUMBER)
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
@@ -105,7 +110,7 @@
|
||||
|
||||
/obj/item/integrated_circuit/trig/secant
|
||||
name = "sec circuit"
|
||||
desc = "Outputs the secant of A. Has nothing to do with the security department."
|
||||
desc = "Outputs the secant of A."
|
||||
icon_state = "secant"
|
||||
inputs = list("A" = IC_PINTYPE_NUMBER)
|
||||
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
/*
|
||||
* ~defines/~defines.dm
|
||||
* Undefines temporary macros after integrated electronics files finish compiling.
|
||||
*/
|
||||
|
||||
#undef IC_INPUT
|
||||
#undef IC_OUTPUT
|
||||
#undef IC_ACTIVATOR
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
name = "impassable substrate"
|
||||
color = "#222222"
|
||||
|
||||
/// This is a global list so we can share the same list with all mineral turfs; it's the same for all of them anyways.
|
||||
GLOBAL_LIST_INIT(mineral_can_smooth_with, list(
|
||||
/turf/simulated/mineral,
|
||||
/turf/simulated/wall,
|
||||
@@ -395,6 +394,31 @@ GLOBAL_LIST_INIT(mineral_can_smooth_with, list(
|
||||
new /obj/structure/sculpting_block(src)
|
||||
GetDrilled(1)
|
||||
|
||||
/turf/simulated/mineral/proc/ic_precision_excavate(var/amount)
|
||||
if(!finds?.len)
|
||||
return "No xenoarch find in target rock."
|
||||
|
||||
var/datum/find/F = finds[1]
|
||||
if(!F)
|
||||
return "Invalid xenoarch find."
|
||||
|
||||
if(amount <= 0)
|
||||
return "Invalid excavation amount."
|
||||
|
||||
if(excavation_level + amount > F.excavation_required)
|
||||
return "Unsafe: excavation would strike past the find."
|
||||
|
||||
if(excavation_level + amount > F.excavation_required - F.clearance_range)
|
||||
if(round(excavation_level + amount) == F.excavation_required)
|
||||
excavation_level += amount
|
||||
excavate_find(100, F)
|
||||
return "Perfect extraction complete."
|
||||
|
||||
return "Unsafe: excavation would breach clearance zone."
|
||||
|
||||
excavation_level += amount
|
||||
return "Excavation advanced."
|
||||
|
||||
/turf/simulated/mineral/proc/get_geodata()
|
||||
if(!geologic_data)
|
||||
geologic_data = new /datum/geosample(src)
|
||||
@@ -742,8 +766,6 @@ GLOBAL_LIST_INIT(mineral_can_smooth_with, list(
|
||||
roof_type = null
|
||||
turf_flags = TURF_FLAG_BACKGROUND
|
||||
|
||||
/// Same as the other, this is a global so we don't have a lot of pointless lists floating around.
|
||||
/// Basalt is explicitly omitted so ash will spill onto basalt turfs.
|
||||
GLOBAL_LIST_INIT(asteroid_floor_smooth, list(
|
||||
/turf/simulated/floor/exoplanet/asteroid/ash,
|
||||
/turf/simulated/mineral,
|
||||
|
||||
@@ -56,13 +56,20 @@
|
||||
/datum/design/item/integrated_electronics/custom_circuit_printer
|
||||
name = "Portable Integrated Circuit Printer"
|
||||
desc = "A portable(ish) printer for modular machines."
|
||||
req_tech = list(TECH_MATERIAL = 3, TECH_ENGINEERING = 4, TECH_DATA = 5)
|
||||
req_tech = list(TECH_MATERIAL = 3, TECH_ENGINEERING = 3, TECH_DATA = 3)
|
||||
materials = list(MATERIAL_STEEL = 10000)
|
||||
build_path = /obj/item/integrated_circuit_printer
|
||||
|
||||
/datum/design/item/integrated_electronics/custom_circuit_printer_upgrade
|
||||
name = "Integrated Circuit Printer Upgrade - Advanced Designs"
|
||||
desc = "Allows the integrated circuit printer to create advanced circuits."
|
||||
req_tech = list(TECH_ENGINEERING = 3, TECH_DATA = 4)
|
||||
req_tech = list(TECH_ENGINEERING = 3, TECH_DATA = 5)
|
||||
materials = list(MATERIAL_STEEL = 2000)
|
||||
build_path = /obj/item/disk/integrated_circuit/upgrade/advanced
|
||||
|
||||
/datum/design/item/integrated_electronics/custom_circuit_printer_upgrade/clone
|
||||
name = "Integrated Circuit Printer Upgrade Disk - Circuit Cloner"
|
||||
desc = "An upgrade disk that allows the integrated circuit printer to duplicate assemblies."
|
||||
req_tech = list(TECH_ENGINEERING = 5, TECH_DATA = 6)
|
||||
materials = list(DEFAULT_WALL_MATERIAL = 3000)
|
||||
build_path = /obj/item/disk/integrated_circuit/upgrade/clone
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
author: mineymonkey
|
||||
|
||||
delete-after: True
|
||||
|
||||
changes:
|
||||
- rscadd: "Added electronic radio headsets, wearable radios with internal integrated circuit assemblies, encryption key support, and private text-to-speech output."
|
||||
- rscadd: "Added integrated circuit printer cloning and blueprint import/export support for assemblies and supported hosted assemblies."
|
||||
- rscadd: "Added new integrated circuit tools for data storage, database commands, radio commands, references, coordinates, access checks, card/item slots, power cells, and item trays."
|
||||
- rscadd: "Added expanded math circuits, including algebra, geometry, list math, statistics, vectors, matrices, calculus, and vector calculus."
|
||||
- rscadd: "Added practical automation circuits, including edge detection, cooldown limiting, pulse counting, pulse routing, state display, list utilities, coordinate navigation, and command parsing."
|
||||
- rscadd: "Added xenoarch precision excavator circuit support with anomaly depth, clearance, excavation, and target direction outputs."
|
||||
- rscadd: "Added additional manipulation circuits and a low-complexity debug circuit for organizing circuit layouts."
|
||||
- rscadd: "Made the circuit cloner upgrade disk printable in the protolathe."
|
||||
- qol: "Reorganized integrated circuit printer categories, math subgroups, logic/comparison groups, circuit descriptions, and circuit box descriptions."
|
||||
- qol: "Improved cloning preservation for circuit names, pin data, constant memory values, built-in circuit links, hosted assembly state, and electronic radio headset internals."
|
||||
- qol: "Improved scanner, server, command pad, reference, coordinate, list, ticker, and printer workflows with clearer outputs, safer invalid-input handling, and bounded pulse behavior."
|
||||
- bugfix: "Fixed imported electronic radio headset blueprints failing to recreate the headset wrapper item or correctly bind the internal assembly."
|
||||
- bugfix: "Fixed large integrated circuit blueprint imports losing or corrupting JSON characters during chunked transfer."
|
||||
- bugfix: "Fixed several integrated circuit edge cases involving invalid refs, empty or null lists, injector targets, radio command receiver declarations, and abstract math circuits appearing in printers."
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
@@ -1,19 +1,40 @@
|
||||
import {
|
||||
Button,
|
||||
Input,
|
||||
LabeledList,
|
||||
ProgressBar,
|
||||
Section,
|
||||
TextArea,
|
||||
} from 'tgui-core/components';
|
||||
import type { BooleanLike } from 'tgui-core/react';
|
||||
import { useBackend } from '../backend';
|
||||
import { useBackend, useLocalState } from '../backend';
|
||||
import { Window } from '../layouts';
|
||||
|
||||
const BLUEPRINT_IMPORT_CHUNK_DELAY = 250;
|
||||
|
||||
const sleep = (duration: number) =>
|
||||
new Promise((resolve) => setTimeout(resolve, duration));
|
||||
|
||||
export type PrinterData = {
|
||||
metal: number;
|
||||
metal_max: number;
|
||||
phoron: number;
|
||||
phoron_max: number;
|
||||
upgraded: BooleanLike;
|
||||
can_clone: BooleanLike;
|
||||
assembly_to_clone: string;
|
||||
clone_cost: number;
|
||||
clone_phoron_cost: number;
|
||||
clone_print_time: number;
|
||||
currently_printing: BooleanLike;
|
||||
has_clone_loaded: BooleanLike;
|
||||
has_live_clone_scan: BooleanLike;
|
||||
has_clone_blueprint: BooleanLike;
|
||||
has_clone_blueprint_export: BooleanLike;
|
||||
clone_blueprint_export_visible: BooleanLike;
|
||||
clone_blueprint_export: string;
|
||||
blueprint_chunk_limit: number;
|
||||
blueprint_buffer_limit: number;
|
||||
circuits: Circuit[];
|
||||
categories: string[];
|
||||
};
|
||||
@@ -26,11 +47,159 @@ type Circuit = {
|
||||
category: string;
|
||||
};
|
||||
|
||||
type CircuitSubgroup = {
|
||||
key: string;
|
||||
group: string;
|
||||
subgroup: string;
|
||||
circuits: Circuit[];
|
||||
};
|
||||
|
||||
type CircuitGroup = {
|
||||
group: string;
|
||||
subgroups: CircuitSubgroup[];
|
||||
};
|
||||
|
||||
const splitCircuitCategory = (category: string) => {
|
||||
const separator = ' - ';
|
||||
const subgroupedGroups = ['LOGIC', 'MATH'];
|
||||
const separatorIndex = category.indexOf(separator);
|
||||
const group = category.slice(0, separatorIndex);
|
||||
|
||||
if (separatorIndex < 0 || !subgroupedGroups.includes(group)) {
|
||||
return {
|
||||
group: category,
|
||||
subgroup: category,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
group,
|
||||
subgroup: category.slice(separatorIndex + separator.length),
|
||||
};
|
||||
};
|
||||
|
||||
export const CircuitPrinter = (props) => {
|
||||
const { act, data } = useBackend<PrinterData>();
|
||||
|
||||
const [searchTerm, setSearchTerm] = useLocalState<string>('searchTerm', '');
|
||||
const [blueprintText, setBlueprintText] = useLocalState<string>(
|
||||
'blueprintText',
|
||||
'',
|
||||
);
|
||||
const [showBlueprintImport, setShowBlueprintImport] = useLocalState<boolean>(
|
||||
'showBlueprintImport',
|
||||
false,
|
||||
);
|
||||
const [isImportingBlueprint, setIsImportingBlueprint] =
|
||||
useLocalState<boolean>('isImportingBlueprint', false);
|
||||
const [collapsedCategories, setCollapsedCategories] = useLocalState<
|
||||
Record<string, boolean>
|
||||
>('collapsedCategories', {});
|
||||
|
||||
const normalizedSearchTerm = searchTerm.toLowerCase();
|
||||
const categories = [...data.categories].sort();
|
||||
const categoryGroups = categories.reduce<CircuitGroup[]>(
|
||||
(groups, category) => {
|
||||
const { group, subgroup } = splitCircuitCategory(category);
|
||||
const groupMatches = group.toLowerCase().includes(normalizedSearchTerm);
|
||||
const subgroupMatches = subgroup
|
||||
.toLowerCase()
|
||||
.includes(normalizedSearchTerm);
|
||||
const categoryMatches = category
|
||||
.toLowerCase()
|
||||
.includes(normalizedSearchTerm);
|
||||
|
||||
const circuits = data.circuits.filter((circuit) => {
|
||||
if (circuit.category !== category) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (
|
||||
!normalizedSearchTerm ||
|
||||
groupMatches ||
|
||||
subgroupMatches ||
|
||||
categoryMatches
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return !!circuit.name?.toLowerCase().includes(normalizedSearchTerm);
|
||||
});
|
||||
|
||||
if (!circuits.length) {
|
||||
return groups;
|
||||
}
|
||||
|
||||
let circuitGroup = groups.find((entry) => entry.group === group);
|
||||
|
||||
if (!circuitGroup) {
|
||||
circuitGroup = {
|
||||
group,
|
||||
subgroups: [],
|
||||
};
|
||||
groups.push(circuitGroup);
|
||||
}
|
||||
|
||||
circuitGroup.subgroups.push({
|
||||
key: category,
|
||||
group,
|
||||
subgroup,
|
||||
circuits,
|
||||
});
|
||||
|
||||
return groups;
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
categoryGroups.sort((a, b) => a.group.localeCompare(b.group));
|
||||
categoryGroups.forEach((group) => {
|
||||
group.subgroups.sort((a, b) => a.subgroup.localeCompare(b.subgroup));
|
||||
});
|
||||
|
||||
const importPastedBlueprint = async () => {
|
||||
const importText = blueprintText;
|
||||
|
||||
if (!importText || isImportingBlueprint) {
|
||||
return;
|
||||
}
|
||||
|
||||
setIsImportingBlueprint(true);
|
||||
|
||||
let offset = 0;
|
||||
const chunkLimit = Math.max(1, data.blueprint_chunk_limit || 1000);
|
||||
const bufferLimit = data.blueprint_buffer_limit || 500000;
|
||||
|
||||
if (importText.length > bufferLimit) {
|
||||
act('reject_oversized_import_tgui', {
|
||||
length: importText.length,
|
||||
});
|
||||
setIsImportingBlueprint(false);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await act('begin_import_buffer');
|
||||
|
||||
while (offset < importText.length) {
|
||||
const chunk = importText.slice(offset, offset + chunkLimit);
|
||||
|
||||
await act('append_import_chunk_tgui', {
|
||||
chunk: encodeURIComponent(chunk),
|
||||
});
|
||||
|
||||
offset += chunk.length;
|
||||
await sleep(BLUEPRINT_IMPORT_CHUNK_DELAY);
|
||||
}
|
||||
|
||||
await act('finish_import_buffer_tgui');
|
||||
} finally {
|
||||
setIsImportingBlueprint(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Window>
|
||||
<Window width={720} height={760}>
|
||||
<Window.Content scrollable>
|
||||
<Section title="Status">
|
||||
<LabeledList>
|
||||
@@ -48,27 +217,256 @@ export const CircuitPrinter = (props) => {
|
||||
{data.metal} sheets
|
||||
</ProgressBar>
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Phoron">
|
||||
<ProgressBar
|
||||
ranges={{
|
||||
good: [data.phoron_max * 0.75, data.phoron_max],
|
||||
average: [data.phoron_max * 0.3, data.phoron_max * 0.75],
|
||||
bad: [0, data.phoron_max * 0.3],
|
||||
}}
|
||||
value={data.phoron}
|
||||
minValue={0}
|
||||
maxValue={data.phoron_max}
|
||||
>
|
||||
{data.phoron} sheets
|
||||
</ProgressBar>
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Upgraded">
|
||||
{data.upgraded ? 'Yes' : 'No'}
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Cloner">
|
||||
{data.can_clone ? 'Installed' : 'Not Installed'}
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Printing">
|
||||
{data.currently_printing ? 'Yes' : 'No'}
|
||||
</LabeledList.Item>
|
||||
</LabeledList>
|
||||
</Section>
|
||||
{data.categories.sort().map((category) => (
|
||||
<Section title={category} key={category}>
|
||||
{data.circuits.map((circuit) =>
|
||||
circuit.category === category ? (
|
||||
|
||||
{!!data.can_clone && (
|
||||
<Section title="Circuit Cloning">
|
||||
<LabeledList>
|
||||
<LabeledList.Item label="Loaded Blueprint">
|
||||
{data.assembly_to_clone || 'None'}
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Steel Cost">
|
||||
{data.assembly_to_clone && data.assembly_to_clone !== 'None'
|
||||
? `${data.clone_cost} sheets`
|
||||
: 'N/A'}
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Phoron Cost">
|
||||
{data.assembly_to_clone && data.assembly_to_clone !== 'None'
|
||||
? `${data.clone_phoron_cost} sheets`
|
||||
: 'N/A'}
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Print Time">
|
||||
{data.assembly_to_clone && data.assembly_to_clone !== 'None'
|
||||
? `${data.clone_print_time} seconds`
|
||||
: 'N/A'}
|
||||
</LabeledList.Item>
|
||||
</LabeledList>
|
||||
|
||||
<Button
|
||||
content="Clone Assembly"
|
||||
icon="copy"
|
||||
disabled={
|
||||
!data.has_clone_loaded ||
|
||||
data.currently_printing ||
|
||||
data.metal < data.clone_cost ||
|
||||
data.phoron < data.clone_phoron_cost
|
||||
}
|
||||
onClick={() => act('clone')}
|
||||
/>
|
||||
<Button
|
||||
content="Clear Scan"
|
||||
icon="times"
|
||||
disabled={!data.has_live_clone_scan || data.currently_printing}
|
||||
onClick={() => act('clear_clone')}
|
||||
/>
|
||||
<Button
|
||||
content={
|
||||
showBlueprintImport ? 'Cancel Import' : 'Import Blueprint'
|
||||
}
|
||||
icon="file-import"
|
||||
disabled={data.currently_printing || isImportingBlueprint}
|
||||
onClick={() => {
|
||||
setShowBlueprintImport(!showBlueprintImport);
|
||||
act('hide_clone_blueprint_export');
|
||||
}}
|
||||
/>
|
||||
<Button
|
||||
content={
|
||||
data.clone_blueprint_export_visible
|
||||
? 'Hide Export'
|
||||
: 'Export Blueprint'
|
||||
}
|
||||
icon="file-export"
|
||||
disabled={
|
||||
!data.has_clone_blueprint_export ||
|
||||
data.currently_printing ||
|
||||
isImportingBlueprint
|
||||
}
|
||||
onClick={() => {
|
||||
setShowBlueprintImport(false);
|
||||
act(
|
||||
data.clone_blueprint_export_visible
|
||||
? 'hide_clone_blueprint_export'
|
||||
: 'show_clone_blueprint_export',
|
||||
);
|
||||
}}
|
||||
/>
|
||||
<Button
|
||||
content="Clear Imported Blueprint"
|
||||
icon="trash"
|
||||
disabled={!data.has_clone_blueprint || data.currently_printing}
|
||||
onClick={() => act('clear_imported_clone')}
|
||||
/>
|
||||
{showBlueprintImport && (
|
||||
<>
|
||||
<TextArea
|
||||
fluid
|
||||
height="240px"
|
||||
mt={0.5}
|
||||
placeholder="Paste blueprint JSON"
|
||||
value={blueprintText}
|
||||
onChange={setBlueprintText}
|
||||
style={{
|
||||
fontFamily: 'monospace',
|
||||
}}
|
||||
/>
|
||||
<Button
|
||||
key={circuit.name}
|
||||
onClick={() => act('build', { build: circuit.path })}
|
||||
>
|
||||
{circuit.name}
|
||||
</Button>
|
||||
) : (
|
||||
''
|
||||
),
|
||||
mt={0.5}
|
||||
content={
|
||||
isImportingBlueprint
|
||||
? 'Importing Blueprint'
|
||||
: 'Import Pasted Blueprint'
|
||||
}
|
||||
icon="file-import"
|
||||
disabled={
|
||||
!blueprintText ||
|
||||
data.currently_printing ||
|
||||
isImportingBlueprint
|
||||
}
|
||||
onClick={importPastedBlueprint}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
{!!data.clone_blueprint_export_visible && (
|
||||
<TextArea
|
||||
fluid
|
||||
height="240px"
|
||||
mt={0.5}
|
||||
value={data.clone_blueprint_export}
|
||||
style={{
|
||||
fontFamily: 'monospace',
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</Section>
|
||||
))}
|
||||
)}
|
||||
|
||||
<Section
|
||||
title="Circuits"
|
||||
buttons={
|
||||
<Input
|
||||
autoFocus
|
||||
autoSelect
|
||||
placeholder="Search categories or circuits"
|
||||
maxLength={512}
|
||||
onChange={setSearchTerm}
|
||||
value={searchTerm}
|
||||
/>
|
||||
}
|
||||
>
|
||||
{categoryGroups.map(({ group, subgroups }) => {
|
||||
const circuitCount = subgroups.reduce(
|
||||
(count, subgroup) => count + subgroup.circuits.length,
|
||||
0,
|
||||
);
|
||||
const hasSubgroups = ['LOGIC', 'MATH'].includes(group);
|
||||
const groupCollapsed = !!collapsedCategories[group];
|
||||
|
||||
return (
|
||||
<Section
|
||||
title={`${group} (${circuitCount})`}
|
||||
key={group}
|
||||
buttons={
|
||||
<Button
|
||||
icon={groupCollapsed ? 'chevron-right' : 'chevron-down'}
|
||||
tooltip={
|
||||
groupCollapsed ? 'Expand category' : 'Collapse category'
|
||||
}
|
||||
onClick={() =>
|
||||
setCollapsedCategories({
|
||||
...collapsedCategories,
|
||||
[group]: !collapsedCategories[group],
|
||||
})
|
||||
}
|
||||
/>
|
||||
}
|
||||
>
|
||||
{!groupCollapsed &&
|
||||
!hasSubgroups &&
|
||||
subgroups.flatMap(({ circuits }) =>
|
||||
circuits.map((circuit) => (
|
||||
<Button
|
||||
key={circuit.path}
|
||||
content={circuit.name}
|
||||
tooltip={circuit.desc}
|
||||
disabled={data.currently_printing}
|
||||
onClick={() => act('build', { build: circuit.path })}
|
||||
/>
|
||||
)),
|
||||
)}
|
||||
{!groupCollapsed &&
|
||||
hasSubgroups &&
|
||||
subgroups.map(({ key, subgroup, circuits }) => {
|
||||
const subgroupCollapsed = !!collapsedCategories[key];
|
||||
|
||||
return (
|
||||
<Section
|
||||
title={`${subgroup} (${circuits.length})`}
|
||||
key={key}
|
||||
buttons={
|
||||
<Button
|
||||
icon={
|
||||
subgroupCollapsed
|
||||
? 'chevron-right'
|
||||
: 'chevron-down'
|
||||
}
|
||||
tooltip={
|
||||
subgroupCollapsed
|
||||
? 'Expand category'
|
||||
: 'Collapse category'
|
||||
}
|
||||
onClick={() =>
|
||||
setCollapsedCategories({
|
||||
...collapsedCategories,
|
||||
[key]: !collapsedCategories[key],
|
||||
})
|
||||
}
|
||||
/>
|
||||
}
|
||||
>
|
||||
{!subgroupCollapsed &&
|
||||
circuits.map((circuit) => (
|
||||
<Button
|
||||
key={circuit.path}
|
||||
content={circuit.name}
|
||||
tooltip={circuit.desc}
|
||||
disabled={data.currently_printing}
|
||||
onClick={() =>
|
||||
act('build', { build: circuit.path })
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</Section>
|
||||
);
|
||||
})}
|
||||
</Section>
|
||||
);
|
||||
})}
|
||||
</Section>
|
||||
</Window.Content>
|
||||
</Window>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user