Port Integrated Electronics from Polaris (#3371)

Ports Polaris' integrated electronics system, whichallows for Roboticists & Electricians/Engineers to build custom devices and machines for a variety of purposes.
This commit is contained in:
Lohikar
2017-09-12 21:41:39 -05:00
committed by GitHub
parent ee2c01c1ec
commit e28c29a551
77 changed files with 5240 additions and 43 deletions
+37
View File
@@ -190,6 +190,7 @@
#include "code\controllers\subsystems\processing\calamity.dm"
#include "code\controllers\subsystems\processing\disease.dm"
#include "code\controllers\subsystems\processing\disposals.dm"
#include "code\controllers\subsystems\processing\electronics.dm"
#include "code\controllers\subsystems\processing\fast_process.dm"
#include "code\controllers\subsystems\processing\modifiers.dm"
#include "code\controllers\subsystems\processing\nanoui.dm"
@@ -830,6 +831,7 @@
#include "code\game\objects\items\weapons\implants\implant.dm"
#include "code\game\objects\items\weapons\implants\implantcase.dm"
#include "code\game\objects\items\weapons\implants\implantchair.dm"
#include "code\game\objects\items\weapons\implants\implantcircuits.dm"
#include "code\game\objects\items\weapons\implants\implanter.dm"
#include "code\game\objects\items\weapons\implants\implantfreedom.dm"
#include "code\game\objects\items\weapons\implants\implantpad.dm"
@@ -1344,6 +1346,40 @@
#include "code\modules\hydroponics\trays\tray_soil.dm"
#include "code\modules\hydroponics\trays\tray_tools.dm"
#include "code\modules\hydroponics\trays\tray_update_icons.dm"
#include "code\modules\integrated_electronics\_defines.dm"
#include "code\modules\integrated_electronics\core\assemblies.dm"
#include "code\modules\integrated_electronics\core\device.dm"
#include "code\modules\integrated_electronics\core\helpers.dm"
#include "code\modules\integrated_electronics\core\integrated_circuit.dm"
#include "code\modules\integrated_electronics\core\pins.dm"
#include "code\modules\integrated_electronics\core\printer.dm"
#include "code\modules\integrated_electronics\core\tools.dm"
#include "code\modules\integrated_electronics\core\special_pins\boolean_pin.dm"
#include "code\modules\integrated_electronics\core\special_pins\char_pin.dm"
#include "code\modules\integrated_electronics\core\special_pins\color_pin.dm"
#include "code\modules\integrated_electronics\core\special_pins\dir_pin.dm"
#include "code\modules\integrated_electronics\core\special_pins\list_pin.dm"
#include "code\modules\integrated_electronics\core\special_pins\number_pin.dm"
#include "code\modules\integrated_electronics\core\special_pins\ref_pin.dm"
#include "code\modules\integrated_electronics\core\special_pins\string_pin.dm"
#include "code\modules\integrated_electronics\passive\passive.dm"
#include "code\modules\integrated_electronics\passive\power.dm"
#include "code\modules\integrated_electronics\subtypes\arithmetic.dm"
#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\input.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\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\smart.dm"
#include "code\modules\integrated_electronics\subtypes\time.dm"
#include "code\modules\integrated_electronics\subtypes\trig.dm"
#include "code\modules\integrated_electronics\~defines\~defines.dm"
#include "code\modules\intern\intern.dm"
#include "code\modules\item_worth\_helpers.dm"
#include "code\modules\item_worth\item_worth.dm"
@@ -1931,6 +1967,7 @@
#include "code\modules\reagents\Chemistry-Machinery.dm"
#include "code\modules\reagents\Chemistry-Metabolism.dm"
#include "code\modules\reagents\Chemistry-Readme.dm"
#include "code\modules\reagents\Chemistry-Reagents-Helpers.dm"
#include "code\modules\reagents\Chemistry-Reagents.dm"
#include "code\modules\reagents\Chemistry-Recipes.dm"
#include "code\modules\reagents\reagent_containers.dm"
+2
View File
@@ -78,3 +78,5 @@
#define CanInteract(user, state) (CanUseTopic(user, state) == STATUS_INTERACTIVE)
#define isopenturf(target) istype(target, /turf/simulated/open)
#define isweakref(target) istype(target, /datum/weakref)
#define isdatum(target) istype(target, /datum)
+4 -1
View File
@@ -1,5 +1,5 @@
// Math constants.
#define M_PI 3.14159265
#define M_PI 3.14159
#define R_IDEAL_GAS_EQUATION 8.31 // kPa*L/(K*mol).
#define ONE_ATMOSPHERE 101.325 // kPa.
@@ -43,3 +43,6 @@
//for when you need a reliable time number that doesn't depend on byond time.
#define REALTIMEOFDAY (world.timeofday + (MIDNIGHT_ROLLOVER * MIDNIGHT_ROLLOVER_CHECK))
#define MIDNIGHT_ROLLOVER_CHECK ( rollovercheck_last_timeofday != world.timeofday ? update_midnight_rollover() : midnight_rollovers )
#define round_duration_in_ticks (round_start_time ? world.time - round_start_time : 0)
#define station_time_in_ticks (roundstart_hour HOURS + round_duration_in_ticks)
+7
View File
@@ -382,3 +382,10 @@ Will print: "/mob/living/carbon/human/death" (you can optionally embed it in a s
//If set to 0, then armor will always prevent the same amount of damage, always, with no randomness whatsoever.
//Of course, this will affect code that checks for blocked < 100, as blocked will be less likely to actually be 100.
#define ARMOR_BLOCK_CHANCE_MULT 1.0
// We should start using these.
#define ITEMSIZE_TINY 1
#define ITEMSIZE_SMALL 2
#define ITEMSIZE_NORMAL 3
#define ITEMSIZE_LARGE 4
#define ITEMSIZE_HUGE 5
+3
View File
@@ -83,3 +83,6 @@
// -- SSlistener --
#define GET_LISTENERS(id) (id ? SSlistener.listeners["[id]"] : null)
// Connection prefixes for player-editable fields
#define WP_ELECTRONICS "elec_"
+1
View File
@@ -36,6 +36,7 @@
#define SS_PRIORITY_MOB 150 // Mob Life().
#define SS_PRIORITY_NANOUI 120 // UI updates.
#define SS_PRIORITY_VOTE 110
#define SS_PRIORITY_ELECTRONICS 100 // Integrated Electronics processing.
#define SS_PRIORITY_MACHINERY 95 // Machinery + powernet ticks.
#define SS_PRIORITY_CHEMISTRY 90 // Multi-tick chemical reactions.
#define SS_PRIORITY_SHUTTLE 85 // Shuttle movement.
+32 -6
View File
@@ -44,12 +44,16 @@
return 1
return 0
/proc/instances_of_type_in_list(var/atom/A, var/list/L)
var/instances = 0
for(var/type in L)
if(istype(A, type))
instances++
return instances
/proc/instances_of_type_in_list(atom/A, list/L, strict = FALSE)
. = 0
if (strict)
for (var/type in L)
if (type == A.type)
.++
else
for(var/type in L)
if(istype(A, type))
.++
//Removes any null entries from the list
//Returns TRUE if the list had nulls, FALSE otherwise
@@ -292,6 +296,28 @@
L += new path()
return L
//returns a new list with only atoms that are in typecache L
/proc/typecache_filter_list(list/atoms, list/typecache)
. = list()
for(var/thing in atoms)
var/atom/A = thing
if (typecache[A.type])
. += A
/proc/typecache_filter_list_reverse(list/atoms, list/typecache)
. = list()
for(var/thing in atoms)
var/atom/A = thing
if(!typecache[A.type])
. += A
/proc/typecache_filter_multi_list_exclusion(list/atoms, list/typecache_include, list/typecache_exclude)
. = list()
for(var/thing in atoms)
var/atom/A = thing
if(typecache_include[A.type] && !typecache_exclude[A.type])
. += A
//Like typesof() or subtypesof(), but returns a typecache instead of a list
/proc/typecacheof(path, ignore_root_path, only_root_path = FALSE)
if(ispath(path))
+16 -3
View File
@@ -4,16 +4,24 @@
#define MINUTE *600
#define MINUTES *600
#define HOUR *36000
#define HOURS *36000
#define DAY *864000
#define DAYS *864000
var/roundstart_hour = 0
var/round_start_time
//Returns the world time in english
/proc/worldtime2text(time = world.time, timeshift = 1)
if(!roundstart_hour) roundstart_hour = rand(0, 23)
return timeshift ? time2text(time+(36000*roundstart_hour), "hh:mm") : time2text(time, "hh:mm")
return timeshift ? time2text(time+(roundstart_hour HOURS), "hh:mm") : time2text(time, "hh:mm")
/proc/worldtime2hours()
if (!roundstart_hour)
worldtime2text()
. = text2num(time2text(world.time + (36000 * roundstart_hour), "hh"))
. = text2num(time2text(world.time + (roundstart_hour HOURS), "hh"))
/proc/worlddate2text()
return num2text(game_year) + "-" + time2text(world.timeofday, "MM-DD")
@@ -39,8 +47,13 @@ var/last_round_duration = 0
if(last_round_duration && world.time < next_duration_update)
return last_round_duration
var/mills = world.time // 1/10 of a second, not real milliseconds but whatever
var/mills = round_duration_in_ticks // 1/10 of a second, not real milliseconds but whatever
//var/secs = ((mills % 36000) % 600) / 10 //Not really needed, but I'll leave it here for refrence.. or something
if (!mills)
last_round_duration = "00:00"
next_duration_update = world.time + 1 MINUTE
return last_round_duration
var/mins = round((mills % 36000) / 600)
var/hours = round(mills / 36000)
+28 -29
View File
@@ -2,14 +2,14 @@
/datum/controller/subsystem
// Metadata; you should define these.
name = "fire coderbus" //name of the subsystem
var/init_order = SS_INIT_MISC //order of initialization. Higher numbers are initialized first, lower numbers later. Can be decimal and negative values.
var/wait = 20 //time to wait (in deciseconds) between each call to fire(). Must be a positive integer.
var/priority = 50 //When mutiple subsystems need to run in the same tick, higher priority subsystems will run first and be given a higher share of the tick before MC_TICK_CHECK triggers a sleep
name = "fire coderbus" //name of the subsystem
var/init_order = SS_INIT_MISC //order of initialization. Higher numbers are initialized first, lower numbers later. Can be decimal and negative values.
var/wait = 20 //time to wait between each call to fire(). Must be a positive integer. In ticks if SS_TICKER, deciseconds otherwise.
var/priority = 50 //When mutiple subsystems need to run in the same tick, higher priority subsystems will run first and be given a higher share of the tick before MC_TICK_CHECK triggers a sleep.
var/flags = 0 //see MC.dm in __DEFINES Most flags must be set on world start to take full effect. (You can also restart the mc to force them to process again)
var/flags = 0 //see master_controller.dm in __defines. Most flags must be set on world start to take full effect. (You can also restart the mc to force them to process again)
//set to 0 to prevent fire() calls, mostly for admin use or subsystems that may be resumed later
//set to 0 to prevent fire() calls, mostly for admin use.
// use the SS_NO_FIRE flag instead for systems that never fire to keep it from even being added to the list
var/can_fire = TRUE
// Similar to can_fire, but intended explicitly for subsystems that are asleep. Using this var instead of can_fire
@@ -17,30 +17,30 @@
var/suspended = FALSE
// Bookkeeping variables; probably shouldn't mess with these.
var/last_fire = 0 //last world.time we called fire()
var/next_fire = 0 //scheduled world.time for next fire()
var/cost = 0 //average time to execute
var/tick_usage = 0 //average tick usage
var/tick_overrun = 0 //average tick overrun
var/state = SS_IDLE //tracks the current state of the ss, running, paused, etc.
var/paused_ticks = 0 //ticks this ss is taking to run right now.
var/paused_tick_usage //total tick_usage of all of our runs while pausing this run
var/ticks = 1 //how many ticks does this ss take to run on avg.
var/times_fired = 0 //number of times we have called fire()
var/queued_time = 0 //time we entered the queue, (for timing and priority reasons)
var/queued_priority //we keep a running total to make the math easier, if priority changes mid-fire that would break our running total, so we store it here
// Subsystem startup accounting.
var/init_state = FALSE
var/init_time = 0
var/init_start = 0
var/init_finish
var/last_fire = 0 //last world.time we called fire()
var/next_fire = 0 //scheduled world.time for next fire()
var/cost = 0 //average time to execute
var/tick_usage = 0 //average tick usage
var/tick_overrun = 0 //average tick overrun
var/state = SS_IDLE //tracks the current state of the ss, running, paused, etc.
var/paused_ticks = 0 //ticks this ss is taking to run right now.
var/paused_tick_usage //total tick_usage of all of our runs while pausing this run
var/ticks = 1 //how many ticks does this ss take to run on avg.
var/times_fired = 0 //number of times we have called fire()
var/queued_time = 0 //time we entered the queue, (for timing and priority reasons)
var/queued_priority //we keep a running total to make the math easier, if priority changes mid-fire that would break our running total, so we store it here
// Subsystem startup accounting - these variables cannot be trusted if the subsystem has crashed and been Recover()'d.
var/init_state = SS_INITSTATE_NONE // The current initialization state of this SS - this might be invalid if the subsystem has been Recover()'d.
var/init_time = 0 // How long the subsystem took to initialize, in seconds.
var/init_start = 0 // What timeofday did we start initializing?
var/init_finish // What timeofday did we finish initializing?
//linked list stuff for the queue
var/datum/controller/subsystem/queue_next
var/datum/controller/subsystem/queue_prev
var/static/list/failure_strikes //How many times we suspect a subsystem type has crashed the MC, 3 strikes and you're out!
var/static/list/failure_strikes //How many times we suspect a subsystem type has crashed the MC, 3 strikes and you're out! This is an assoc list indexed by type.
// Used to initialize the subsystem BEFORE the map has loaded
/datum/controller/subsystem/New()
@@ -167,12 +167,11 @@
init_state = SS_INITSTATE_DONE
//used to initialize the subsystem AFTER the map has loaded
/datum/controller/subsystem/Initialize(start_timeofday, silent = FALSE)
/datum/controller/subsystem/Initialize(start_timeofday)
var/time = (REALTIMEOFDAY - start_timeofday) / 10
init_time = time
var/msg = "Initialized [name] subsystem within [time] second[time == 1 ? "" : "s"]!"
if (!silent)
admin_notice(span("danger", msg), R_DEBUG)
admin_notice(span("danger", msg), R_DEBUG)
world.log << "SS Init: [msg]"
log_ss_init(msg)
return time
@@ -21,7 +21,7 @@ var/datum/controller/subsystem/nightlight/SSnightlight
fire(FALSE, FALSE)
..(timeofday, silent = TRUE)
..()
/datum/controller/subsystem/nightlight/stat_entry()
..("A:[isactive] T:[worldtime2hours()] DT:[config.nl_start] NT:[config.nl_finish] D:[disable_type]")
@@ -0,0 +1,60 @@
#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.
/var/datum/controller/subsystem/processing/electronics/SSelectronics
/datum/controller/subsystem/processing/electronics
name = "Electronics"
wait = 2 SECONDS
priority = SS_PRIORITY_ELECTRONICS
flags = SS_KEEP_TIMING
init_order = SS_INIT_MISC_FIRST
var/list/all_integrated_circuits = list()
var/list/printer_recipe_list = list()
/datum/controller/subsystem/processing/electronics/New()
NEW_SS_GLOBAL(SSelectronics)
/datum/controller/subsystem/processing/electronics/Initialize(timeofday)
init_subtypes(/obj/item/integrated_circuit, all_integrated_circuits)
// 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)))
circuits_to_use += IC
// Second loop is to find all categories.
var/list/found_categories = list()
for(var/obj/item/integrated_circuit/IC in circuits_to_use)
if(!(IC.category_text in found_categories))
found_categories += IC.category_text
// Third loop is to initialize lists by category names, then put circuits matching the category inside.
for(var/category in found_categories)
printer_recipe_list[category] = list()
var/list/current_list = printer_recipe_list[category]
for(var/obj/item/integrated_circuit/IC in circuits_to_use)
if(IC.category_text == category)
current_list += IC
// Now for non-circuit things.
printer_recipe_list["Assemblies"] = list(
new /obj/item/device/electronic_assembly,
new /obj/item/device/electronic_assembly/medium,
new /obj/item/device/electronic_assembly/large,
new /obj/item/device/electronic_assembly/drone,
new /obj/item/weapon/implant/integrated_circuit,
new /obj/item/device/assembly/electronic_assembly
)
printer_recipe_list["Tools"] = list(
new /obj/item/device/integrated_electronics/wirer,
new /obj/item/device/integrated_electronics/debugger
)
..()
#undef IC_SPAWN_DEFAULT
#undef IC_SPAWN_RESEARCH
@@ -25,7 +25,7 @@ var/datum/controller/subsystem/processing/SSprocessing
while(current_run.len)
var/datum/thing = current_run[current_run.len]
current_run.len--
if(thing)
if(!QDELETED(thing))
if (thing.process() == PROCESS_KILL)
stop_processing(thing)
else
+1
View File
@@ -398,6 +398,7 @@ var/datum/controller/subsystem/ticker/SSticker
data_core.manifest()
Master.RoundStart()
round_start_time = world.time
callHook("roundstart")
+14
View File
@@ -426,3 +426,17 @@
/atom/proc/change_area_name(var/oldname, var/newname)
name = replacetext(name,oldname,newname)
/atom/movable/proc/dropInto(var/atom/destination)
while(istype(destination))
var/atom/drop_destination = destination.onDropInto(src)
if(!istype(drop_destination) || drop_destination == destination)
return forceMove(destination)
destination = drop_destination
return forceMove(null)
/atom/proc/onDropInto(var/atom/movable/AM)
return // If onDropInto returns null, then dropInto will forceMove AM into us.
/atom/movable/onDropInto(var/atom/movable/AM)
return loc // If onDropInto returns something, then dropInto will attempt to drop AM there.
@@ -58,6 +58,18 @@
implants -= src
return ..()
/obj/item/weapon/implant/attackby(obj/item/I, mob/user)
if(istype(I, /obj/item/weapon/implanter))
var/obj/item/weapon/implanter/implanter = I
if(implanter.imp)
return // It's full.
user.drop_from_inventory(src)
forceMove(implanter)
implanter.imp = src
implanter.update()
else
..()
/obj/item/weapon/implant/tracking
name = "tracking implant"
desc = "Track with this."
@@ -0,0 +1,48 @@
/obj/item/weapon/implant/integrated_circuit
name = "electronic implant"
desc = "It's a case, for building very tiny electronics with."
icon = 'icons/obj/electronic_assemblies.dmi'
icon_state = "setup_implant"
var/obj/item/device/electronic_assembly/implant/IC = null
/obj/item/weapon/implant/integrated_circuit/islegal()
return TRUE
/obj/item/weapon/implant/integrated_circuit/Initialize()
..()
IC = new(src)
IC.implant = src
/obj/item/weapon/implant/integrated_circuit/Destroy()
IC.implant = null
qdel(IC)
return ..()
/obj/item/weapon/implant/integrated_circuit/get_data()
var/dat = {"
<b>Implant Specifications:</b><BR>
<b>Name:</b> Modular Implant<BR>
<b>Life:</b> 3 years.<BR>
<b>Important Notes: EMP can cause malfunctions in the internal electronics of this implant.</B><BR>
<HR>
<b>Implant Details:</b><BR>
<b>Function:</b> Contains no innate functions until other components are added.<BR>
<b>Special Features:</b>
<i>Modular Circuitry</i>- Can be loaded with specific modular circuitry in order to fulfill a wide possibility of functions.<BR>
<b>Integrity:</b> Implant is not shielded from electromagnetic interference, otherwise it is independant of subject's status."}
return dat
/obj/item/weapon/implant/integrated_circuit/emp_act(severity)
IC.emp_act(severity)
/obj/item/weapon/implant/integrated_circuit/examine(mob/user)
IC.examine(user)
/obj/item/weapon/implant/integrated_circuit/attackby(var/obj/item/O, var/mob/user)
if(istype(O, /obj/item/weapon/crowbar) || istype(O, /obj/item/device/integrated_electronics) || istype(O, /obj/item/integrated_circuit) || istype(O, /obj/item/weapon/screwdriver) || istype(O, /obj/item/weapon/cell/device) )
IC.attackby(O, user)
else
..()
/obj/item/weapon/implant/integrated_circuit/attack_self(mob/user)
IC.attack_self(user)
@@ -322,7 +322,7 @@
usr << "<span class='notice'>[src] cannot hold \the [W].</span>"
return 0
var/max_instances = can_hold[W.type]
if(max_instances && instances_of_type_in_list(W, contents) >= max_instances)
if(max_instances && instances_of_type_in_list(W, contents, TRUE) >= max_instances)
if(!stop_messages && !istype(W, /obj/item/weapon/hand_labeler))
usr << "<span class='notice'>[src] has no more space specifically for \the [W].</span>"
return 0
@@ -450,3 +450,5 @@
BD.unwrap()
open()
/obj/structure/closet/onDropInto(var/atom/movable/AM)
return
@@ -0,0 +1,67 @@
#define IC_INPUT "input"
#define IC_OUTPUT "output"
#define IC_ACTIVATOR "activator"
// Pin functionality.
#define DATA_CHANNEL "data channel"
#define PULSE_CHANNEL "pulse channel"
// Methods of obtaining a circuit. These are also defined in SSelectronics.
#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.
// Displayed along with the pin name to show what type of pin it is.
#define IC_FORMAT_ANY "\<ANY\>"
#define IC_FORMAT_STRING "\<TEXT\>"
#define IC_FORMAT_CHAR "\<CHAR\>"
#define IC_FORMAT_COLOR "\<COLOR\>"
#define IC_FORMAT_NUMBER "\<NUM\>"
#define IC_FORMAT_DIR "\<DIR\>"
#define IC_FORMAT_BOOLEAN "\<BOOL\>"
#define IC_FORMAT_REF "\<REF\>"
#define IC_FORMAT_LIST "\<LIST\>"
#define IC_FORMAT_PULSE "\<PULSE\>"
// Used inside input/output list to tell the constructor what pin to make.
#define IC_PINTYPE_ANY /datum/integrated_io
#define IC_PINTYPE_STRING /datum/integrated_io/string
#define IC_PINTYPE_CHAR /datum/integrated_io/char
#define IC_PINTYPE_COLOR /datum/integrated_io/color
#define IC_PINTYPE_NUMBER /datum/integrated_io/number
#define IC_PINTYPE_DIR /datum/integrated_io/dir
#define IC_PINTYPE_BOOLEAN /datum/integrated_io/boolean
#define IC_PINTYPE_REF /datum/integrated_io/ref
#define IC_PINTYPE_LIST /datum/integrated_io/list
#define IC_PINTYPE_PULSE_IN /datum/integrated_io/activate
#define IC_PINTYPE_PULSE_OUT /datum/integrated_io/activate/out
// Data limits.
#define IC_MAX_LIST_LENGTH 200
/obj/item/integrated_circuit
name = "integrated circuit"
desc = "It's a tiny chip! This one doesn't seem to do much, however."
icon = 'icons/obj/electronic_assemblies.dmi'
icon_state = "template"
w_class = ITEMSIZE_TINY
var/obj/item/device/electronic_assembly/assembly // Reference to the assembly holding this circuit, if any.
var/extended_desc
var/list/inputs = list()
var/list/inputs_default = list() // Assoc list which will fill a pin with data upon creation. e.g. "2" = 0 will set input pin 2 to equal 0 instead of null.
var/list/outputs = list()
var/list/outputs_default = list() // Ditto, for output.
var/list/activators = list()
var/next_use = 0 //Uses world.time
var/complexity = 1 //This acts as a limitation on building machines, more resource-intensive components cost more 'space'.
var/size //This acts as a limitation on building machines, bigger components cost more 'space'. -1 for size 0
var/cooldown_per_use = 1 SECOND // Circuits are limited in how many times they can be work()'d by this variable.
var/power_draw_per_use = 0 // How much power is drawn when work()'d.
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/removable = TRUE // Determines if a circuit is removable from the assembly.
var/displayed_name = ""
var/allow_multitool = TRUE // Allows additional multitool functionality
// Used as a global var, (Do not set manually in children).
@@ -0,0 +1,336 @@
#define IC_COMPONENTS_BASE 20
#define IC_COMPLEXITY_BASE 60
/obj/item/device/electronic_assembly
name = "electronic assembly"
desc = "It's a case, for building small electronics with."
w_class = ITEMSIZE_SMALL
icon = 'icons/obj/electronic_assemblies.dmi'
icon_state = "setup_small"
var/max_components = IC_COMPONENTS_BASE
var/max_complexity = IC_COMPLEXITY_BASE
var/opened = 0
var/obj/item/weapon/cell/device/battery // Internal cell which most circuits need to work.
/obj/item/device/electronic_assembly/medium
name = "electronic mechanism"
icon_state = "setup_medium"
desc = "It's a case, for building medium-sized electronics with."
w_class = ITEMSIZE_NORMAL
max_components = IC_COMPONENTS_BASE * 2
max_complexity = IC_COMPLEXITY_BASE * 2
/obj/item/device/electronic_assembly/large
name = "electronic machine"
icon_state = "setup_large"
desc = "It's a case, for building large electronics with."
w_class = ITEMSIZE_LARGE
max_components = IC_COMPONENTS_BASE * 4
max_complexity = IC_COMPLEXITY_BASE * 4
/obj/item/device/electronic_assembly/drone
name = "electronic drone"
icon_state = "setup_drone"
desc = "It's a case, for building mobile electronics with."
w_class = ITEMSIZE_NORMAL
max_components = IC_COMPONENTS_BASE * 1.5
max_complexity = IC_COMPLEXITY_BASE * 1.5
/obj/item/device/electronic_assembly/implant
name = "electronic implant"
icon_state = "setup_implant"
desc = "It's a case, for building very tiny electronics with."
w_class = ITEMSIZE_TINY
max_components = IC_COMPONENTS_BASE / 2
max_complexity = IC_COMPLEXITY_BASE / 2
var/obj/item/weapon/implant/integrated_circuit/implant = null
/obj/item/device/electronic_assembly/Initialize(mapload, printed = FALSE)
..()
if (!printed)
battery = new(src)
START_PROCESSING(SSelectronics, src)
/obj/item/device/electronic_assembly/Destroy()
QDEL_NULL(battery)
STOP_PROCESSING(SSelectronics, src)
return ..()
/obj/item/device/electronic_assembly/process()
handle_idle_power()
/obj/item/device/electronic_assembly/proc/handle_idle_power()
// First we generate power.
for(var/obj/item/integrated_circuit/passive/power/P in contents)
P.make_energy()
// Now spend it.
for(var/obj/item/integrated_circuit/IC in contents)
if(IC.power_draw_idle && !draw_power(IC.power_draw_idle))
IC.power_fail()
/obj/item/device/electronic_assembly/implant/update_icon()
..()
implant.icon_state = icon_state
/obj/item/device/electronic_assembly/implant/nano_host()
return implant
/obj/item/device/electronic_assembly/proc/resolve_nano_host()
return src
/obj/item/device/electronic_assembly/implant/resolve_nano_host()
return implant
/obj/item/device/electronic_assembly/proc/check_interactivity(mob/user)
if(!CanInteract(user, physical_state))
return 0
return 1
/obj/item/device/electronic_assembly/interact(mob/user)
if(!check_interactivity(user))
return
var/total_parts = 0
var/total_complexity = 0
for(var/obj/item/integrated_circuit/part in contents)
total_parts += part.size
total_complexity = total_complexity + part.complexity
var/list/HTML = list()
HTML += "<br><a href='?src=\ref[src]'>Refresh</a> | "
HTML += "<a href='?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>"
if(battery)
HTML += "[round(battery.charge, 0.1)]/[battery.maxcharge] ([round(battery.percent(), 0.1)]%) cell charge. <a href='?src=\ref[src];remove_cell=1'>Remove</a>"
else
HTML += "<span class='danger'>No powercell detected!</span>"
HTML += "<br><br>"
HTML += "Components:<hr>"
HTML += "Built in:<br>"
//Put removable circuits in separate categories from non-removable
for(var/obj/item/integrated_circuit/circuit in contents)
if(!circuit.removable)
HTML += "<a href=?src=\ref[circuit];examine=1;from_assembly=1>[circuit.displayed_name]</a> | "
HTML += "<a href=?src=\ref[circuit];rename=1;from_assembly=1>Rename</a> | "
HTML += "<a href=?src=\ref[circuit];scan=1;from_assembly=1>Scan with Debugger</a> | "
HTML += "<a href=?src=\ref[circuit];bottom=\ref[circuit];from_assembly=1>Move to Bottom</a>"
HTML += "<br>"
HTML += "<hr>"
HTML += "Removable:<br>"
for(var/obj/item/integrated_circuit/circuit in contents)
if(circuit.removable)
HTML += "<a href=?src=\ref[circuit];examine=1;from_assembly=1>[circuit.displayed_name]</a> | "
HTML += "<a href=?src=\ref[circuit];rename=1;from_assembly=1>Rename</a> | "
HTML += "<a href=?src=\ref[circuit];scan=1;from_assembly=1>Scan with Debugger</a> | "
HTML += "<a href=?src=\ref[circuit];remove=1;from_assembly=1>Remove</a> | "
HTML += "<a href=?src=\ref[circuit];bottom=\ref[circuit];from_assembly=1>Move to Bottom</a>"
HTML += "<br>"
var/datum/browser/B = new(user, "assembly-\ref[src]", name, 600, 400)
B.set_content(HTML.Join())
B.open(FALSE)
/obj/item/device/electronic_assembly/Topic(href, href_list[])
if(..())
return 1
if(!opened)
to_chat(usr, "<span class='warning'>\The [src] is not open!</span>")
return
if(href_list["rename"])
rename(usr)
if(href_list["remove_cell"])
if(!battery)
to_chat(usr, "<span class='warning'>There's no power cell to remove from \the [src].</span>")
else
var/turf/T = get_turf(src)
battery.forceMove(T)
playsound(T, 'sound/items/Crowbar.ogg', 50, 1)
to_chat(usr, "<span class='notice'>You pull \the [battery] out of \the [src]'s power supply.</span>")
battery = null
interact(usr) // To refresh the UI.
/obj/item/device/electronic_assembly/verb/rename()
set name = "Rename Circuit"
set category = "Object"
set desc = "Rename your circuit, useful to stay organized."
var/mob/M = usr
if(!check_interactivity(M))
return
var/input = sanitizeSafe(input("What do you want to name this?", "Rename", src.name) as null|text, MAX_NAME_LEN)
if(src && input)
to_chat(M, "<span class='notice'>The machine now has a label reading '[input]'.</span>")
name = input
/obj/item/device/electronic_assembly/proc/can_move()
return FALSE
/obj/item/device/electronic_assembly/drone/can_move()
return TRUE
/obj/item/device/electronic_assembly/update_icon()
if(opened)
icon_state = "[initial(icon_state)]-open"
else
icon_state = initial(icon_state)
/obj/item/device/electronic_assembly/GetAccess()
. = list()
for(var/obj/item/integrated_circuit/part in contents)
. |= part.GetAccess()
/obj/item/device/electronic_assembly/examine(mob/user)
. = ..(user, 1)
if(.)
for(var/obj/item/integrated_circuit/IC in contents)
IC.external_examine(user)
if(opened)
interact(user)
/obj/item/device/electronic_assembly/proc/get_part_complexity()
. = 0
for(var/obj/item/integrated_circuit/part in contents)
. += part.complexity
/obj/item/device/electronic_assembly/proc/get_part_size()
. = 0
for(var/obj/item/integrated_circuit/part in contents)
. += part.size
// Returns true if the circuit made it inside.
/obj/item/device/electronic_assembly/proc/add_circuit(obj/item/integrated_circuit/IC, mob/user)
if(!opened)
to_chat(user, "<span class='warning'>\The [src] isn't opened, so you can't put anything inside. Try using a crowbar.</span>")
return FALSE
if(IC.w_class > w_class)
to_chat(user, "<span class='warning'>\The [IC] is way too big to fit into \the [src].</span>")
return FALSE
var/total_part_size = get_part_size()
var/total_complexity = get_part_complexity()
if((total_part_size + IC.size) > max_components)
to_chat(user, "<span class='warning'>You can't seem to add the '[IC.name]', as there's insufficient space.</span>")
return FALSE
if((total_complexity + IC.complexity) > max_complexity)
to_chat(user, "<span class='warning'>You can't seem to add the '[IC.name]', since this setup's too complicated for the case.</span>")
return FALSE
if(!IC.forceMove(src))
return FALSE
IC.assembly = src
return TRUE
/obj/item/device/electronic_assembly/afterattack(atom/target, mob/user, proximity)
if(proximity)
var/scanned = FALSE
for(var/obj/item/integrated_circuit/input/sensor/S in contents)
if(S.scan(target))
scanned = TRUE
if(scanned)
visible_message("<span class='notice'>\The [user] waves \the [src] around [target].</span>")
/obj/item/device/electronic_assembly/attackby(obj/item/I, mob/user)
if(istype(I, /obj/item/integrated_circuit))
if(!user.unEquip(I))
return FALSE
if(add_circuit(I, user))
to_chat(user, "<span class='notice'>You slide \the [I] inside \the [src].</span>")
playsound(get_turf(src), 'sound/items/Deconstruct.ogg', 50, 1)
interact(user)
return TRUE
else if(istype(I, /obj/item/weapon/crowbar))
playsound(get_turf(src), 'sound/items/Crowbar.ogg', 50, 1)
opened = !opened
to_chat(user, "<span class='notice'>You [opened ? "open" : "close"] \the [src].</span>")
update_icon()
return TRUE
else if(istype(I, /obj/item/device/integrated_electronics/wirer) || istype(I, /obj/item/device/integrated_electronics/debugger) || istype(I, /obj/item/weapon/screwdriver))
if(opened)
interact(user)
else
to_chat(user, "<span class='warning'>\The [src] isn't open, so you can't fiddle with the internal components. \
Try using a crowbar.</span>")
else if(istype(I, /obj/item/weapon/cell/device))
if(!opened)
to_chat(user, "<span class='warning'>\The [src] isn't open, so you can't put anything inside. Try using a crowbar.</span>")
return FALSE
if(battery)
to_chat(user, "<span class='warning'>\The [src] already has \a [battery] inside. Remove it first if you want to replace it.</span>")
return FALSE
var/obj/item/weapon/cell/device/cell = I
user.drop_item(cell)
cell.forceMove(src)
battery = cell
playsound(get_turf(src), 'sound/items/Deconstruct.ogg', 50, 1)
to_chat(user, "<span class='notice'>You slot \the [cell] inside \the [src]'s power supply.</span>")
interact(user)
return TRUE
else
return ..()
/obj/item/device/electronic_assembly/attack_self(mob/user)
if(!check_interactivity(user))
return
if(opened)
interact(user)
var/list/input_selection = list()
var/list/available_inputs = list()
for(var/obj/item/integrated_circuit/input/input in contents)
if(input.can_be_asked_input)
available_inputs.Add(input)
var/i = 0
for(var/obj/item/integrated_circuit/s in available_inputs)
if(s.name == input.name && s.displayed_name == input.displayed_name && s != input)
i++
var/disp_name= "[input.displayed_name] \[[input.name]\]"
if(i)
disp_name += " ([i+1])"
input_selection.Add(disp_name)
var/obj/item/integrated_circuit/input/choice
if(available_inputs)
var/selection = input(user, "What do you want to interact with?", "Interaction") as null|anything in input_selection
if(selection)
var/index = input_selection.Find(selection)
choice = available_inputs[index]
if(choice)
choice.ask_for_input(user)
/obj/item/device/electronic_assembly/emp_act(severity)
..()
for(var/atom/movable/AM in contents)
AM.emp_act(severity)
// Returns true if power was successfully drawn.
/obj/item/device/electronic_assembly/proc/draw_power(amount)
if(battery && battery.checked_use(amount * CELLRATE))
return TRUE
return FALSE
// Ditto for giving.
/obj/item/device/electronic_assembly/proc/give_power(amount)
if(battery && battery.give(amount * CELLRATE))
return TRUE
return FALSE
@@ -0,0 +1,81 @@
/obj/item/device/assembly/electronic_assembly
name = "electronic device"
desc = "It's a case for building electronics with. It can be attached to other small devices."
icon_state = "setup_device"
var/opened = 0
var/obj/item/device/electronic_assembly/device/EA
/obj/item/device/assembly/electronic_assembly/Initialize()
EA = new(src)
EA.holder = src
. = ..()
/obj/item/device/assembly/electronic_assembly/attackby(obj/item/I, mob/user)
if (iscrowbar(I))
toggle_open(user)
else if (opened)
EA.attackby(I, user)
else
..()
/obj/item/device/assembly/electronic_assembly/proc/toggle_open(mob/user)
playsound(get_turf(src), 'sound/items/Crowbar.ogg', 50, 1)
opened = !opened
EA.opened = opened
to_chat(user, "<span class='notice'>You [opened ? "open" : "close"] \the [src].</span>")
secured = 1
update_icon()
/obj/item/device/assembly/electronic_assembly/update_icon()
if(EA)
icon_state = initial(icon_state)
else
icon_state = "[initial(icon_state)]0"
if(opened)
icon_state = "[icon_state]-open"
/obj/item/device/assembly/electronic_assembly/attack_self(mob/user as mob)
if(EA)
EA.attack_self(user)
//Called when another assembly acts on this one, var/radio will determine where it came from for wire calcs
/obj/item/device/assembly/electronic_assembly/pulsed(radio = 0)
if(EA)
for(var/obj/item/integrated_circuit/built_in/device_input/I in EA.contents)
I.do_work()
/obj/item/device/assembly/electronic_assembly/examine(mob/user)
. = ..(user, 1)
if(EA)
for(var/obj/item/integrated_circuit/IC in EA.contents)
IC.external_examine(user)
/obj/item/device/assembly/electronic_assembly/verb/toggle()
set src in usr
set category = "Object"
set name = "Open/Close Device Assembly"
set desc = "Open or close device assembly!"
toggle_open(usr)
/obj/item/device/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."
var/obj/item/device/assembly/electronic_assembly/holder
w_class = ITEMSIZE_TINY
max_components = IC_COMPONENTS_BASE * 3/4
max_complexity = IC_COMPLEXITY_BASE * 3/4
/obj/item/device/electronic_assembly/device/Initialize()
. = ..()
var/obj/item/integrated_circuit/built_in/device_input/input = new(src)
var/obj/item/integrated_circuit/built_in/device_output/output = new(src)
input.assembly = src
output.assembly = src
/obj/item/device/electronic_assembly/device/check_interactivity(mob/user)
if(!CanInteract(user, state = deep_inventory_state))
return 0
return 1
@@ -0,0 +1,78 @@
/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)
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.
// Override the pin type.
if(io_list_copy[io_entry])
io_type_override = io_list_copy[io_entry]
if(io_type_override)
io_list += new io_type_override(src, io_entry, default_data)
else
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))
PROCLOG_WEIRD("converting hardref to [DEBUG_REF(new_data)] into weakref.")
new_data = WEAKREF(new_data)
var/datum/integrated_io/pin = get_pin_ref(pin_type, pin_number)
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/datum/integrated_io/pin = get_pin_ref(pin_type, pin_number)
return pin.get_data()
/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)
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]
A.push_data()
/datum/integrated_io/proc/get_data()
if(isnull(data))
return
if(isweakref(data))
return data.resolve()
return data
/obj/item/integrated_circuit/proc/get_pin_ref(pin_type, pin_number)
switch(pin_type)
if(IC_INPUT)
if(pin_number > inputs.len)
return null
return inputs[pin_number]
if(IC_OUTPUT)
if(pin_number > outputs.len)
return null
return outputs[pin_number]
if(IC_ACTIVATOR)
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/device/integrated_electronics/tool)
if(istype(tool, /obj/item/device/integrated_electronics/wirer))
var/obj/item/device/integrated_electronics/wirer/wirer = tool
if(pin)
wirer.wire(pin, usr)
return 1
else if(istype(tool, /obj/item/device/integrated_electronics/debugger))
var/obj/item/device/integrated_electronics/debugger/debugger = tool
if(pin)
debugger.write_data(pin, usr)
return 1
return 0
@@ -0,0 +1,355 @@
/*
Integrated circuits are essentially modular machines. Each circuit has a specific function, and combining them inside Electronic Assemblies allows
a creative player the means to solve many problems. Circuits are held inside an electronic assembly, and are wired using special tools.
*/
/obj/item/integrated_circuit/examine(mob/user)
interact(user)
external_examine(user)
. = ..()
// This should be used when someone is examining while the case is opened.
/obj/item/integrated_circuit/proc/internal_examine(mob/user)
to_chat(user, "This board has [inputs.len] input pin\s, [outputs.len] output pin\s and [activators.len] activation pin\s.")
for(var/datum/integrated_io/I in inputs)
if(I.linked.len)
to_chat(user, "The '[I]' is connected to [I.get_linked_to_desc()].")
for(var/datum/integrated_io/O in outputs)
if(O.linked.len)
to_chat(user, "The '[O]' is connected to [O.get_linked_to_desc()].")
for(var/datum/integrated_io/activate/A in activators)
if(A.linked.len)
to_chat(user, "The '[A]' is connected to [A.get_linked_to_desc()].")
any_examine(user)
interact(user)
// This should be used when someone is examining from an 'outside' perspective, e.g. reading a screen or LED.
/obj/item/integrated_circuit/proc/external_examine(mob/user)
any_examine(user)
/obj/item/integrated_circuit/proc/any_examine(mob/user)
return
/obj/item/integrated_circuit/Initialize()
displayed_name = name
if(!size)
size = w_class
if(size == -1)
size = 0
setup_io(inputs, /datum/integrated_io, inputs_default)
setup_io(outputs, /datum/integrated_io, outputs_default)
setup_io(activators, /datum/integrated_io/activate)
. = ..()
/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/Destroy()
for(var/datum/integrated_io/I in inputs)
qdel(I)
for(var/datum/integrated_io/O in outputs)
qdel(O)
for(var/datum/integrated_io/A in activators)
qdel(A)
. = ..()
/obj/item/integrated_circuit/nano_host()
if(istype(src.loc, /obj/item/device/electronic_assembly))
var/obj/item/device/electronic_assembly/assembly = loc
return assembly.resolve_nano_host()
return ..()
/obj/item/integrated_circuit/emp_act(severity)
for(var/datum/integrated_io/io in inputs + outputs + activators)
io.scramble()
/obj/item/integrated_circuit/proc/check_interactivity(mob/user)
if(assembly)
return assembly.check_interactivity(user)
else if(!CanInteract(user, physical_state))
return 0
return 1
/obj/item/integrated_circuit/verb/rename_component()
set name = "Rename Circuit"
set category = "Object"
set desc = "Rename your circuit, useful to stay organized."
var/mob/M = usr
if(!check_interactivity(M))
return
var/input = sanitizeSafe(input("What do you want to name the circuit?", "Rename", src.name) as null|text, MAX_NAME_LEN)
if(src && input && assembly.check_interactivity(M))
to_chat(M, "<span class='notice'>The circuit '[src.name]' is now labeled '[input]'.</span>")
displayed_name = input
/obj/item/integrated_circuit/interact(mob/user)
if(!check_interactivity(user))
return
var/window_height = 350
var/window_width = 600
var/table_edge_width = "30%"
var/table_middle_width = "40%"
var/list/HTML = list(
"<div align='center'>",
"<table border='1' style='undefined;table-layout: fixed; width: 80%'>",
"<br><a href='?src=\ref[src];return=1'>Return to Assembly</a>",
"<br><a href='?src=\ref[src];'>Refresh</a> | ",
"<a href='?src=\ref[src];rename=1'>Rename</a> | ",
"<a href='?src=\ref[src];scan=1'>Scan with Device</a> | "
)
if(src.removable)
HTML += "<a href='?src=\ref[src];remove=1'>Remove</a><br>"
HTML += "<colgroup>"
HTML += "<col style='width: [table_edge_width]'>"
HTML += "<col style='width: [table_middle_width]'>"
HTML += "<col style='width: [table_edge_width]'>"
HTML += "</colgroup>"
var/column_width = 3
var/row_height = max(inputs.len, outputs.len, 1)
for(var/i = 1 to row_height)
HTML += "<tr>"
for(var/j = 1 to column_width)
var/datum/integrated_io/io = null
var/words = list()
var/height = 1
switch(j)
if(1)
io = get_pin_ref(IC_INPUT, i)
if(io)
words += "<b><a href=?src=\ref[src];pin_name=1;pin=\ref[io]>[io.display_pin_type()] [io.name]</a> <a href=?src=\ref[src];pin_data=1;pin=\ref[io]>[io.display_data(io.data)]</a></b><br>"
if(io.linked.len)
for(var/datum/integrated_io/linked in io.linked)
words += "<a href=?src=\ref[src];pin_unwire=1;pin=\ref[io];link=\ref[linked]>[linked.name]</a> \
@ <a href=?src=\ref[linked.holder];examine=1;>[linked.holder.displayed_name]</a><br>"
if(outputs.len > inputs.len)
height = 1
if(2)
if(i == 1)
words += "[src.displayed_name]<br>[src.name != src.displayed_name ? "([src.name])":""]<hr>[src.desc]"
height = row_height
else
continue
if(3)
io = get_pin_ref(IC_OUTPUT, i)
if(io)
words += "<b><a href=?src=\ref[src];pin_name=1;pin=\ref[io]>[io.display_pin_type()] [io.name]</a> <a href=?src=\ref[src];pin_data=1;pin=\ref[io]>[io.display_data(io.data)]</a></b><br>"
if(io.linked.len)
for(var/datum/integrated_io/linked in io.linked)
words += "<a href=?src=\ref[src];pin_unwire=1;pin=\ref[io];link=\ref[linked]>[linked.name]</a> \
@ <a href=?src=\ref[linked.holder];examine=1;>[linked.holder.displayed_name]</a><br>"
if(inputs.len > outputs.len)
height = 1
HTML += "<td align='center' rowspan='[height]'>[jointext(words, null)]</td>"
HTML += "</tr>"
for(var/activator in activators)
var/datum/integrated_io/io = activator
var/words = list(
"<b><a href=?src=\ref[src];pin_name=1;pin=\ref[io]><span class='bad'>[io.name]</span></a> <a href=?src=\ref[src];pin_data=1;pin=\ref[io]><span class='bad'>[io.data?"\<PULSE OUT\>":"\<PULSE IN\>"]</span></a></b><br>"
)
if(io.linked.len)
for(var/datum/integrated_io/linked in io.linked)
words += "<a href=?src=\ref[src];pin_unwire=1;pin=\ref[io];link=\ref[linked]><span class='bad'>[linked.name]</span></a> \
@ <a href=?src=\ref[linked.holder];examine=1;><span class='bad'>[linked.holder.displayed_name]</span></a><br>"
HTML += "<tr>"
HTML += "<td colspan='3' align='center'>[jointext(words, null)]</td>"
HTML += "</tr>"
HTML += "</table>"
HTML += "</div>"
// HTML += "<br><font color='33CC33'>Meta Variables;</font>" // If more meta vars get introduced, uncomment this.
// HTML += "<br>"
HTML += "<br><span class='highlight'>Complexity: [complexity]</span>"
if(power_draw_idle)
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>"
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())
B.open()
/obj/item/integrated_circuit/Topic(href, href_list, state = interactive_state)
if(!check_interactivity(usr))
return
if (assembly && !assembly.opened)
to_chat(usr, "<span class='warning'>\The [assembly] is not open!</span>")
return
if(..())
return 1
var/update = 1
var/obj/item/device/electronic_assembly/A = src.assembly
var/update_to_assembly = 0
var/datum/integrated_io/pin = locate(href_list["pin"]) in inputs + outputs + activators
var/datum/integrated_io/linked = null
if(href_list["link"])
linked = locate(href_list["link"]) in pin.linked
var/obj/held_item = usr.get_active_hand()
if(href_list["rename"])
rename_component(usr)
if(href_list["from_assembly"])
update = 0
var/obj/item/device/electronic_assembly/ea = loc
if(istype(ea))
ea.interact(usr)
if(href_list["pin_name"])
if (!istype(held_item, /obj/item/device/multitool) || !allow_multitool)
href_list["wire"] = 1
else
var/obj/item/device/multitool/M = held_item
M.wire(pin,usr)
if(href_list["pin_data"])
if (!istype(held_item, /obj/item/device/multitool) || !allow_multitool)
href_list["wire"] = 1
else
var/datum/integrated_io/io = pin
io.ask_for_pin_data(usr) // The pins themselves will determine how to ask for data, and will validate the data.
if(href_list["pin_unwire"])
if (!istype(held_item, /obj/item/device/multitool) || !allow_multitool)
href_list["wire"] = 1
else
var/obj/item/device/multitool/M = held_item
M.unwire(pin, linked, usr)
if(href_list["wire"])
if(istype(held_item, /obj/item/device/integrated_electronics/wirer))
var/obj/item/device/integrated_electronics/wirer/wirer = held_item
if(linked)
wirer.wire(linked, usr)
else if(pin)
wirer.wire(pin, usr)
else if(istype(held_item, /obj/item/device/integrated_electronics/debugger))
var/obj/item/device/integrated_electronics/debugger/debugger = held_item
if(pin)
debugger.write_data(pin, usr)
else
to_chat(usr, "<span class='warning'>You can't do a whole lot without the proper tools.</span>")
if(href_list["examine"])
var/obj/item/integrated_circuit/examined
if(href_list["examined"])
examined = href_list["examined"]
else
examined = src
examined.interact(usr)
update = 0
if(href_list["bottom"])
var/obj/item/integrated_circuit/circuit = locate(href_list["bottom"]) in src.assembly.contents
var/assy = circuit.assembly
if(!circuit)
return
circuit.loc = null
circuit.loc = assy
. = 1
update_to_assembly = 1
if(href_list["scan"])
if(istype(held_item, /obj/item/device/integrated_electronics/debugger))
var/obj/item/device/integrated_electronics/debugger/D = held_item
if(D.accepting_refs)
D.afterattack(src, usr, TRUE)
else
to_chat(usr, "<span class='warning'>The Debugger's 'ref scanner' needs to be on.</span>")
else
to_chat(usr, "<span class='warning'>You need a multitool/debugger set to 'ref' mode to do that.</span>")
if(href_list["return"])
if(A)
update_to_assembly = 1
usr << browse(null, "window=circuit-\ref[src]")
else
to_chat(usr, "<span class='warning'>This circuit is not in an assembly!</span>")
if(href_list["remove"])
if(!A)
to_chat(usr, "<span class='warning'>This circuit is not in an assembly!</span>")
return
if(!removable)
to_chat(usr, "<span class='warning'>\The [src] seems to be permanently attached to the case.</span>")
return
var/obj/item/device/electronic_assembly/ea = loc
disconnect_all()
var/turf/T = get_turf(src)
forceMove(T)
assembly = null
playsound(T, 'sound/items/Crowbar.ogg', 50, 1)
to_chat(usr, "<span class='notice'>You pop \the [src] out of the case, and slide it out.</span>")
if(istype(ea))
ea.interact(usr)
update = 0
return
if(update)
if(istype(A) && update_to_assembly)
A.interact(usr)
else
interact(usr) // To refresh the UI.
/obj/item/integrated_circuit/proc/push_data()
for(var/datum/integrated_io/O in outputs)
O.push_data()
/obj/item/integrated_circuit/proc/pull_data()
for(var/datum/integrated_io/I in inputs)
I.push_data()
/obj/item/integrated_circuit/proc/draw_idle_power()
if(assembly)
return assembly.draw_power(power_draw_idle)
// Override this for special behaviour when there's no power left.
/obj/item/integrated_circuit/proc/power_fail()
return
// Returns true if there's enough power to work().
/obj/item/integrated_circuit/proc/check_power()
if(!assembly)
return FALSE // Not in an assembly, therefore no power.
if(assembly.draw_power(power_draw_per_use))
return TRUE // Battery has enough.
return FALSE // Not enough power.
/obj/item/integrated_circuit/proc/check_then_do_work(ignore_power = FALSE)
if(world.time < next_use) // All intergrated circuits have an internal cooldown, to protect from spam.
return
if(power_draw_per_use && !ignore_power)
if(!check_power())
power_fail()
return
next_use = world.time + cooldown_per_use
do_work()
/obj/item/integrated_circuit/proc/do_work()
return
/obj/item/integrated_circuit/proc/disconnect_all()
for(var/datum/integrated_io/I in inputs)
I.disconnect()
for(var/datum/integrated_io/O in outputs)
O.disconnect()
for(var/datum/integrated_io/activate/A in activators)
A.disconnect()
@@ -0,0 +1,188 @@
/*
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.
A visualization of how pins work is below. Imagine the below image involves an addition circuit.
When the bottom pin, the activator, receives a pulse, all the numbers on the left (input) get added, and the answer goes on the right side (output).
Inputs Outputs
A [2]\ /[8] result
B [1]-\|++|/
C [4]-/|++|
D [1]/ ||
||
Activator
*/
/datum/integrated_io
var/name = "input/output"
var/obj/item/integrated_circuit/holder = null
var/datum/weakref/data = null // This is a weakref, to reduce typecasts. Note that oftentimes numbers and text may also occupy this.
var/list/linked = list()
var/io_type = DATA_CHANNEL
/datum/integrated_io/New(var/newloc, var/name, var/new_data)
..()
src.name = name
if(new_data)
src.data = new_data
holder = newloc
if(!istype(holder))
message_admins("ERROR: An integrated_io ([src.name]) spawned without a valid holder! This is a bug.")
log_debug("ERROR: An integrated_io ([src.name]) spawned without a valid holder! This is a bug.")
/datum/integrated_io/Destroy()
disconnect()
data = null
holder = null
. = ..()
/datum/integrated_io/nano_host()
return holder.nano_host()
/datum/integrated_io/proc/data_as_type(var/as_type)
if(!isweakref(data))
return
var/datum/weakref/w = data
var/output = w.resolve()
return istype(output, as_type) ? output : null
/datum/integrated_io/proc/display_data(var/input)
if(isnull(input))
return "(null)" // Empty data means nothing to show.
if(istext(input))
return "(\"[input]\")" // Wraps the 'string' in escaped quotes, so that people know it's a 'string'.
/*
list[](
"A",
"B",
"C"
)
*/
if(islist(input))
var/list/my_list = input
var/result = "list\[[my_list.len]\]("
if(my_list.len)
result += "<br>"
var/pos = 0
for(var/line in my_list)
result += "[display_data(line)]"
pos++
if(pos != my_list.len)
result += ",<br>"
result += "<br>"
result += ")"
return result
if(isweakref(input))
var/datum/weakref/w = input
var/atom/A = w.resolve()
//return A ? "([A.name] \[Ref\])" : "(null)" // For refs, we want just the name displayed.
return A ? "(\ref[A] \[Ref\])" : "(null)"
return "([input])" // Nothing special needed for numbers or other stuff.
/datum/integrated_io/activate/display_data()
return "(\[pulse\])"
/datum/integrated_io/proc/display_pin_type()
return IC_FORMAT_ANY
/datum/integrated_io/activate/display_pin_type()
return IC_FORMAT_PULSE
/datum/integrated_io/proc/scramble()
if(isnull(data))
return
if(isnum(data))
write_data_to_pin(rand(-10000, 10000))
if(istext(data))
write_data_to_pin("ERROR")
push_data()
/datum/integrated_io/activate/scramble()
push_data()
/datum/integrated_io/proc/write_data_to_pin(var/new_data)
if(isnull(new_data) || isnum(new_data) || istext(new_data) || isweakref(new_data)) // Anything else is a type we don't want.
data = new_data
holder.on_data_written()
/datum/integrated_io/proc/push_data()
for(var/datum/integrated_io/io in linked)
io.write_data_to_pin(data)
/datum/integrated_io/activate/push_data()
for(var/datum/integrated_io/io in linked)
io.holder.check_then_do_work()
/datum/integrated_io/proc/pull_data()
for(var/datum/integrated_io/io in linked)
write_data_to_pin(io.data)
/datum/integrated_io/proc/get_linked_to_desc()
if(linked.len)
return "the [english_list(linked)]"
return "nothing"
/datum/integrated_io/proc/disconnect()
//First we iterate over everything we are linked to.
for(var/datum/integrated_io/their_io in linked)
//While doing that, we iterate them as well, and disconnect ourselves from them.
for(var/datum/integrated_io/their_linked_io in their_io.linked)
if(their_linked_io == src)
their_io.linked -= src
//Now that we're removed from them, we gotta remove them from us.
linked -= their_io
/datum/integrated_io/proc/ask_for_data_type(mob/user, var/default, var/list/allowed_data_types = list("string","number","null"))
var/type_to_use = input("Please choose a type to use.","[src] type setting") as null|anything in allowed_data_types
if(!holder.check_interactivity(user))
return
var/new_data = null
switch(type_to_use)
if("string")
new_data = sanitize(input("Now type in a string.","[src] string writing", istext(default) ? default : null) as null|text)
if(istext(new_data) && holder.check_interactivity(user) )
to_chat(user, "<span class='notice'>You input [new_data] into the pin.</span>")
return new_data
if("number")
new_data = input("Now type in a number.","[src] number writing", isnum(default) ? default : null) as null|num
if(isnum(new_data) && holder.check_interactivity(user) )
to_chat(user, "<span class='notice'>You input [new_data] into the pin.</span>")
return new_data
if("null")
if(holder.check_interactivity(user))
to_chat(user, "<span class='notice'>You clear the pin's memory.</span>")
return new_data
// Basically a null check
/datum/integrated_io/proc/is_valid()
return !isnull(data)
// This proc asks for the data to write, then writes it.
/datum/integrated_io/proc/ask_for_pin_data(mob/user)
var/new_data = ask_for_data_type(user)
write_data_to_pin(new_data)
/datum/integrated_io/activate/ask_for_pin_data(mob/user) // This just pulses the pin.
holder.check_then_do_work(ignore_power = TRUE)
to_chat(user, "<span class='notice'>You pulse \the [holder]'s [src] pin.</span>")
/datum/integrated_io/activate
name = "activation pin"
io_type = PULSE_CHANNEL
/datum/integrated_io/activate/out // All this does is just make the UI say 'out' instead of 'in'
data = 1
@@ -0,0 +1,159 @@
/obj/item/device/integrated_circuit_printer
name = "integrated circuit printer"
desc = "A portable(ish) machine made to print tiny modular circuitry out of metal."
icon = 'icons/obj/electronic_assemblies.dmi'
icon_state = "circuit_printer"
w_class = ITEMSIZE_LARGE
var/metal = 0
var/max_metal = 100
var/metal_per_sheet = 10 // One sheet equals this much metal.
var/upgraded = FALSE // When hit with an upgrade disk, will turn true, allowing it to print the higher tier circuits.
var/can_clone = FALSE // Same for above, but will allow the printer to duplicate a specific assembly.
var/current_category
var/obj/item/device/electronic_assembly/assembly_to_clone
/obj/item/device/integrated_circuit_printer/upgraded
upgraded = TRUE
can_clone = TRUE
/obj/item/device/integrated_circuit_printer/attackby(var/obj/item/O, var/mob/user)
if(istype(O,/obj/item/stack/material))
var/obj/item/stack/material/stack = O
if(stack.material.name == DEFAULT_WALL_MATERIAL)
var/num = min((max_metal - metal) / metal_per_sheet, stack.amount)
if(num < 1)
to_chat(user, "<span class='warning'>\The [src] is too full to add more metal.</span>")
return
if(stack.use(num))
to_chat(user, "<span class='notice'>You add [num] sheet\s to \the [src].</span>")
metal += num * metal_per_sheet
interact(user)
return TRUE
if(istype(O,/obj/item/integrated_circuit))
to_chat(user, "<span class='notice'>You insert the circuit into \the [src]. </span>")
user.unEquip(O)
metal = min(metal + O.w_class, max_metal)
qdel(O)
interact(user)
return TRUE
if(istype(O,/obj/item/weapon/disk/integrated_circuit/upgrade/advanced))
if(upgraded)
to_chat(user, "<span class='warning'>\The [src] already has this upgrade. </span>")
return TRUE
to_chat(user, "<span class='notice'>You install \the [O] into \the [src]. </span>")
upgraded = TRUE
interact(user)
return TRUE
if(istype(O,/obj/item/weapon/disk/integrated_circuit/upgrade/clone))
if(can_clone)
to_chat(user, "<span class='warning'>\The [src] already has this upgrade. </span>")
return TRUE
to_chat(user, "<span class='notice'>You install \the [O] into \the [src]. </span>")
can_clone = TRUE
interact(user)
return TRUE
return ..()
/obj/item/device/integrated_circuit_printer/attack_self(var/mob/user)
interact(user)
/obj/item/device/integrated_circuit_printer/interact(mob/user)
var/window_height = 600
var/window_width = 500
if(isnull(current_category))
current_category = SSelectronics.printer_recipe_list[1]
var/HTML = "<center><h2>Integrated Circuit Printer</h2></center><br>"
HTML += "Metal: [metal/metal_per_sheet]/[max_metal/metal_per_sheet] sheets.<br>"
HTML += "Circuits available: [upgraded ? "Regular":"Advanced"]."
HTML += "Assembly Cloning: [can_clone ? "Available": "Unavailable"]."
if(assembly_to_clone)
HTML += "Assembly '[assembly_to_clone.name]' loaded."
HTML += "Crossed out circuits mean that the printer is not sufficentally upgraded to create that circuit.<br>"
HTML += "<hr>"
HTML += "Categories:"
for(var/category in SSelectronics.printer_recipe_list)
if(category != current_category)
HTML += " <a href='?src=\ref[src];category=[category]'>[category]</a> "
else // Bold the button if it's already selected.
HTML += " <b>[category]</b> "
HTML += "<hr>"
HTML += "<center><h4>[current_category]</h4></center>"
var/list/current_list = SSelectronics.printer_recipe_list[current_category]
for(var/obj/O in current_list)
var/can_build = 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)) && !upgraded)
can_build = FALSE
if(can_build)
HTML += "<A href='?src=\ref[src];build=[O.type]'>[O.name]</A>: [O.desc]<br>"
else
HTML += "<s>[O.name]: [O.desc]</s><br>"
var/datum/browser/B = new(user, "integrated_printer", null, window_width, window_height)
B.set_content(HTML)
B.open(FALSE)
/obj/item/device/integrated_circuit_printer/Topic(href, href_list)
if(..())
return 1
add_fingerprint(usr)
if(href_list["category"])
current_category = href_list["category"]
if(href_list["build"])
var/build_type = text2path(href_list["build"])
if(!build_type || !ispath(build_type))
return 1
var/cost = 1
var/is_asm = FALSE
if(ispath(build_type, /obj/item/device/electronic_assembly))
var/obj/item/device/electronic_assembly/E = build_type
cost = round( (initial(E.max_complexity) + initial(E.max_components) ) / 4)
is_asm = TRUE
else if(ispath(build_type, /obj/item/integrated_circuit))
var/obj/item/integrated_circuit/IC = build_type
cost = initial(IC.w_class)
if(metal - cost < 0)
to_chat(usr, "<span class='warning'>You need [cost] metal to build that!.</span>")
return 1
metal -= cost
if (is_asm)
new build_type(get_turf(loc), TRUE)
else
new build_type(get_turf(loc))
interact(usr)
// FUKKEN UPGRADE DISKS
/obj/item/weapon/disk/integrated_circuit/upgrade
name = "integrated circuit printer upgrade disk"
desc = "Install this into your integrated circuit printer to enhance it."
icon = 'icons/obj/electronic_assemblies.dmi'
icon_state = "upgrade_disk"
item_state = "card-id"
w_class = ITEMSIZE_SMALL
origin_tech = list(TECH_ENGINEERING = 3, TECH_DATA = 4)
/obj/item/weapon/disk/integrated_circuit/upgrade/advanced
name = "integrated circuit printer upgrade disk - advanced designs"
desc = "Install this into your integrated circuit printer to enhance it. This one adds new, advanced designs to the printer."
// To be implemented later.
/obj/item/weapon/disk/integrated_circuit/upgrade/clone
name = "integrated circuit printer upgrade disk - circuit cloner"
desc = "Install this into your integrated circuit printer to enhance it. This one allows the printer to duplicate assemblies."
icon_state = "upgrade_disk_clone"
origin_tech = list(TECH_ENGINEERING = 5, TECH_DATA = 6)
@@ -0,0 +1,25 @@
// These pins only contain 0 or 1. Null is not allowed.
/datum/integrated_io/boolean
name = "boolean pin"
data = FALSE
/datum/integrated_io/boolean/ask_for_pin_data(mob/user) // 'Ask' is a bit misleading, acts more like a toggle.
var/new_data = !data
write_data_to_pin(new_data)
/datum/integrated_io/boolean/write_data_to_pin(var/new_data)
if(new_data == FALSE || new_data == TRUE)
data = new_data
holder.on_data_written()
/datum/integrated_io/boolean/scramble()
write_data_to_pin(rand(FALSE,TRUE))
push_data()
/datum/integrated_io/boolean/display_pin_type()
return IC_FORMAT_BOOLEAN
/datum/integrated_io/boolean/display_data(var/input)
if(data == TRUE)
return "(True)"
return "(False)"
@@ -0,0 +1,27 @@
// These pins can only contain a 1 character string or null.
/datum/integrated_io/char
name = "char pin"
/datum/integrated_io/char/ask_for_pin_data(mob/user)
var/new_data = sanitize(input("Please type in one character.","[src] char writing") as null|text)
if(holder.check_interactivity(user) )
to_chat(user, "<span class='notice'>You input [new_data ? "'[new_data]'" : "NULL"] into the pin.</span>")
write_data_to_pin(new_data)
/datum/integrated_io/char/write_data_to_pin(var/new_data)
if(isnull(new_data) || istext(new_data))
if(length(new_data) > 1)
return
data = new_data
holder.on_data_written()
// This makes the text go from "A" to "%".
/datum/integrated_io/char/scramble()
if(!is_valid())
return
var/list/options = list("!","@","#","$","%","^","&","*") + alphabet_uppercase
data = pick(options)
push_data()
/datum/integrated_io/char/display_pin_type()
return IC_FORMAT_CHAR
@@ -0,0 +1,44 @@
// These pins can only contain a color (in the form of #FFFFFF) or null.
/datum/integrated_io/color
name = "color pin"
/datum/integrated_io/color/ask_for_pin_data(mob/user)
var/new_data = input("Please select a color.","[src] color writing") as null|color
if(holder.check_interactivity(user) )
to_chat(user, "<span class='notice'>You input a <font color='[new_data]'>new color</font> into the pin.</span>")
write_data_to_pin(new_data)
/datum/integrated_io/color/write_data_to_pin(new_data)
// Since this is storing the color as a string hex color code, we need to make sure it's actually one.
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
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,
safety_dance++
data = new_data // And we can hex
holder.on_data_written()
// This randomizes the color.
/datum/integrated_io/color/scramble()
if(!is_valid())
return
var/new_data = get_random_colour(simple = FALSE, lower = 0, upper = 255)
data = new_data
push_data()
/datum/integrated_io/color/display_pin_type()
return IC_FORMAT_COLOR
/datum/integrated_io/color/display_data(input)
if(!isnull(data))
return "(<font color='[data]'>[data]</font>)"
return ..()
@@ -0,0 +1,33 @@
// These pins can only contain directions (1,2,4,8...) or null.
/datum/integrated_io/dir
name = "dir pin"
/datum/integrated_io/dir/ask_for_pin_data(mob/user)
var/new_data = input("Please type in a valid dir number. \
Valid dirs are;\n\
North/Fore = [NORTH],\n\
South/Aft = [SOUTH],\n\
East/Starboard = [EAST],\n\
West/Port = [WEST],\n\
Northeast = [NORTHEAST],\n\
Northwest = [NORTHWEST],\n\
Southeast = [SOUTHEAST],\n\
Southwest = [SOUTHWEST],\n\
Up = [UP],\n\
Down = [DOWN]","[src] dir writing") as null|num
if(isnum(new_data) && holder.check_interactivity(user) )
to_chat(user, "<span class='notice'>You input [new_data] into the pin.</span>")
write_data_to_pin(new_data)
/datum/integrated_io/dir/write_data_to_pin(var/new_data)
if(isnull(new_data) || new_data in alldirs + list(UP, DOWN))
data = new_data
holder.on_data_written()
/datum/integrated_io/dir/display_pin_type()
return IC_FORMAT_DIR
/datum/integrated_io/dir/display_data(var/input)
if(!isnull(data))
return "([dir2text(data)])"
return ..()
@@ -0,0 +1,149 @@
// These pins contain a list. Null is not allowed.
/datum/integrated_io/list
name = "list pin"
data = list()
/datum/integrated_io/list/ask_for_pin_data(mob/user)
interact(user)
/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 += "<a href='?src=\ref[src]'>Refresh</a> | "
t += "<a href='?src=\ref[src];add=1'>Add</a> | "
t += "<a href='?src=\ref[src];swap=1'>Swap</a> | "
t += "<a href='?src=\ref[src];clear=1'>Clear</a><br>"
t += "<hr>"
var/i = 0
for(var/line in my_list)
i++
t += "#[i] | [display_data(line)] | "
t += "<a href='?src=\ref[src];edit=1;pos=[i]'>Edit</a> | "
t += "<a href='?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)
if(is_valid(new_entry))
Add(new_entry)
/datum/integrated_io/list/proc/Add(new_entry)
var/list/my_list = data
if(my_list.len > IC_MAX_LIST_LENGTH)
my_list.Cut(1, 2)
my_list.Add(new_entry)
/datum/integrated_io/list/proc/remove_from_list_by_position(mob/user, position)
var/list/my_list = data
if(!my_list.len)
to_chat(user, "<span class='warning'>The list is empty, there's nothing to remove.</span>")
return
if(!position)
return
var/target_entry = my_list.Find(position)
if(target_entry)
my_list -= target_entry
/datum/integrated_io/list/proc/remove_from_list(mob/user, target_entry)
var/list/my_list = data
if(!my_list.len)
to_chat(user, "<span class='warning'>The list is empty, there's nothing to remove.</span>")
return
if(!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
/datum/integrated_io/list/proc/edit_in_list(mob/user, target_entry)
var/list/my_list = data
if(!my_list.len)
to_chat(user, "<span class='warning'>The list is empty, there's nothing to modify.</span>")
return
if(!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)
if(edited_entry)
target_entry = edited_entry
/datum/integrated_io/list/proc/edit_in_list_by_position(mob/user, var/position)
var/list/my_list = data
if(!my_list.len)
to_chat(user, "<span class='warning'>The list is empty, there's nothing to modify.</span>")
return
if(!position)
return
var/target_entry = my_list.Find(position)
if(target_entry)
var/edited_entry = ask_for_data_type(user, target_entry)
if(edited_entry)
target_entry = edited_entry
/datum/integrated_io/list/proc/swap_inside_list(mob/user, var/first_target, var/second_target)
var/list/my_list = data
if(my_list.len <= 1)
to_chat(user, "<span class='warning'>The list is empty, or too small to do any meaningful swapping.</span>")
return
if(!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(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)
/datum/integrated_io/list/proc/clear_list(mob/user)
var/list/my_list = data
my_list.Cut()
/datum/integrated_io/list/scramble()
var/list/my_list = data
my_list = 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
data = new_list.Copy()
holder.on_data_written()
/datum/integrated_io/list/display_pin_type()
return IC_FORMAT_LIST
/datum/integrated_io/list/Topic(href, href_list, state = interactive_state)
if(!holder.check_interactivity(usr))
return
if(..())
return 1
if(href_list["add"])
add_to_list(usr)
if(href_list["swap"])
swap_inside_list(usr)
if(href_list["clear"])
clear_list(usr)
if(href_list["remove"])
if(href_list["pos"])
remove_from_list_by_position(usr, text2num(href_list["pos"]))
else
remove_from_list(usr)
if(href_list["edit"])
if(href_list["pos"])
edit_in_list_by_position(usr, text2num(href_list["pos"]))
else
edit_in_list(usr)
holder.interact(usr) // Refresh the main UI,
interact(usr) // and the list UI.
@@ -0,0 +1,17 @@
// These pins can only contain numbers (int and floating point) or null.
/datum/integrated_io/number
name = "number pin"
/datum/integrated_io/number/ask_for_pin_data(mob/user)
var/new_data = input("Please type in a number.","[src] number writing") as null|num
if(isnum(new_data) && holder.check_interactivity(user) )
to_chat(user, "<span class='notice'>You input [new_data] into the pin.</span>")
write_data_to_pin(new_data)
/datum/integrated_io/number/write_data_to_pin(var/new_data)
if(isnull(new_data) || isnum(new_data))
data = new_data
holder.on_data_written()
/datum/integrated_io/number/display_pin_type()
return IC_FORMAT_NUMBER
@@ -0,0 +1,14 @@
// These pins only contain weakrefs or null.
/datum/integrated_io/ref
name = "ref pin"
/datum/integrated_io/ref/ask_for_pin_data(mob/user) // This clears the pin.
write_data_to_pin(null)
/datum/integrated_io/ref/write_data_to_pin(var/new_data)
if(isnull(new_data) || isweakref(new_data))
data = new_data
holder.on_data_written()
/datum/integrated_io/ref/display_pin_type()
return IC_FORMAT_REF
@@ -0,0 +1,29 @@
// These pins can only contain text and null.
/datum/integrated_io/string
name = "string pin"
/datum/integrated_io/string/ask_for_pin_data(mob/user)
var/new_data = sanitize(input("Please type in a string.","[src] string writing") as null|text)
if(holder.check_interactivity(user) )
to_chat(user, "<span class='notice'>You input [new_data ? "new_data" : "NULL"] into the pin.</span>")
write_data_to_pin(new_data)
/datum/integrated_io/string/write_data_to_pin(var/new_data)
if(isnull(new_data) || istext(new_data))
data = new_data
holder.on_data_written()
// This makes the text go "from this" to "#G&*!HD$%L"
/datum/integrated_io/string/scramble()
if(!is_valid())
return
var/string_length = length(data)
var/list/options = list("!","@","#","$","%","^","&","*") + alphabet_uppercase
var/new_data = ""
while(string_length)
new_data += pick(options)
string_length--
push_data()
/datum/integrated_io/string/display_pin_type()
return IC_FORMAT_STRING
@@ -0,0 +1,461 @@
#define WIRE "wire"
#define WIRING "wiring"
#define UNWIRE "unwire"
#define UNWIRING "unwiring"
/obj/item/device/integrated_electronics/wirer
name = "circuit wirer"
desc = "It's a small wiring tool, with a wire roll, electric soldering iron, wire cutter, and more in one package. \
The wires used are generally useful for small electronics, such as circuitboards and breadboards, as opposed to larger wires \
used for power or data transmission."
icon = 'icons/obj/electronic_assemblies.dmi'
icon_state = "wirer-wire"
item_state = "wirer"
flags = CONDUCT
w_class = 2
var/datum/integrated_io/selected_io
var/mode = WIRE
/obj/item/device/integrated_electronics/wirer/update_icon()
icon_state = "wirer-[mode]"
/obj/item/device/integrated_electronics/wirer/proc/wire(var/datum/integrated_io/io, mob/user)
if(!io.holder.assembly)
to_chat(user, "<span class='warning'>\The [io.holder] needs to be secured inside an assembly first.</span>")
return
switch (mode)
if (WIRE)
selected_io = io
to_chat(user, "<span class='notice'>You attach a data wire to \the [selected_io.holder]'s [selected_io.name] data channel.</span>")
mode = WIRING
update_icon()
if (WIRING)
if(io == selected_io)
to_chat(user, "<span class='warning'>Wiring \the [selected_io.holder]'s [selected_io.name] into itself is rather pointless.</span>")
return
if(io.io_type != selected_io.io_type)
to_chat(user, "<span class='warning'>Those two types of channels are incompatable. The first is a [selected_io.io_type], \
while the second is a [io.io_type].</span>")
return
if(io.holder.assembly && io.holder.assembly != selected_io.holder.assembly)
to_chat(user, "<span class='warning'>Both \the [io.holder] and \the [selected_io.holder] need to be inside the same assembly.</span>")
return
selected_io.linked |= io
io.linked |= selected_io
to_chat(user, "<span class='notice'>You connect \the [selected_io.holder]'s [selected_io.name] to \the [io.holder]'s [io.name].</span>")
mode = WIRE
update_icon()
selected_io.holder.interact(user) // This is to update the UI.
selected_io = null
if (UNWIRE)
selected_io = io
if(!io.linked.len)
to_chat(user, "<span class='warning'>There is nothing connected to \the [selected_io] data channel.</span>")
selected_io = null
return
to_chat(user, "<span class='notice'>You prepare to detach a data wire from \the [selected_io.holder]'s [selected_io.name] data channel.</span>")
mode = UNWIRING
update_icon()
if (UNWIRING)
if(io == selected_io)
to_chat(user, "<span class='warning'>You can't wire a pin into each other, so unwiring \the [selected_io.holder] from \
the same pin is rather moot.</span>")
return
if(selected_io in io.linked)
io.linked.Remove(selected_io)
selected_io.linked.Remove(io)
to_chat(user, "<span class='notice'>You disconnect \the [selected_io.holder]'s [selected_io.name] from \
\the [io.holder]'s [io.name].</span>")
selected_io.holder.interact(user) // This is to update the UI.
selected_io = null
mode = UNWIRE
update_icon()
else
to_chat(user, "<span class='warning'>\The [selected_io.holder]'s [selected_io.name] and \the [io.holder]'s \
[io.name] are not connected.</span>")
/obj/item/device/integrated_electronics/wirer/attack_self(mob/user)
switch(mode)
if(WIRE)
mode = UNWIRE
if(WIRING)
if(selected_io)
to_chat(user, "<span class='notice'>You decide not to wire the data channel.</span>")
selected_io = null
mode = WIRE
if(UNWIRE)
mode = WIRE
if(UNWIRING)
if(selected_io)
to_chat(user, "<span class='notice'>You decide not to disconnect the data channel.</span>")
selected_io = null
mode = UNWIRE
update_icon()
to_chat(user, "<span class='notice'>You set \the [src] to [mode].</span>")
#undef WIRE
#undef WIRING
#undef UNWIRE
#undef UNWIRING
/obj/item/device/integrated_electronics/debugger
name = "circuit debugger"
desc = "This small tool allows one working with custom machinery to directly set data to a specific pin, useful for writing \
settings to specific circuits, or for debugging purposes. It can also pulse activation pins."
icon = 'icons/obj/electronic_assemblies.dmi'
icon_state = "debugger"
flags = CONDUCT
w_class = 2
var/data_to_write = null
var/accepting_refs = 0
/obj/item/device/integrated_electronics/debugger/attack_self(mob/user)
var/type_to_use = input("Please choose a type to use.","[src] type setting") as null|anything in list("string","number","ref", "null")
if(!CanInteract(user, physical_state))
return
var/new_data = null
switch(type_to_use)
if("string")
accepting_refs = 0
new_data = sanitize(input("Now type in a string.","[src] string writing") as null|text)
if(istext(new_data) && CanInteract(user, physical_state))
data_to_write = new_data
to_chat(user, "<span class='notice'>You set \the [src]'s memory to \"[new_data]\".</span>")
if("number")
accepting_refs = 0
new_data = input("Now type in a number.","[src] number writing") as null|num
if(isnum(new_data) && CanInteract(user, physical_state))
data_to_write = new_data
to_chat(user, "<span class='notice'>You set \the [src]'s memory to [new_data].</span>")
if("ref")
accepting_refs = 1
to_chat(user, "<span class='notice'>You turn \the [src]'s ref scanner on. Slide it across \
an object for a ref of that object to save it in memory.</span>")
if("null")
data_to_write = null
to_chat(user, "<span class='notice'>You set \the [src]'s memory to absolutely nothing.</span>")
/obj/item/device/integrated_electronics/debugger/afterattack(atom/target, mob/living/user, proximity)
if(accepting_refs && proximity)
data_to_write = WEAKREF(target)
visible_message("<span class='notice'>[user] slides [src]'s ref scanner over \the [target].</span>")
to_chat(user, "<span class='notice'>You set \the [src]'s memory to a reference to [target.name] \[Ref\]. The ref scanner is \
now off.</span>")
accepting_refs = 0
/obj/item/device/integrated_electronics/debugger/proc/write_data(var/datum/integrated_io/io, mob/user)
switch (io.io_type)
if (DATA_CHANNEL)
io.write_data_to_pin(data_to_write)
var/data_to_show = data_to_write
if(isweakref(data_to_write))
var/datum/weakref/w = data_to_write
var/atom/A = w.resolve()
data_to_show = A.name
to_chat(user, "<span class='notice'>You write '[data_to_write ? data_to_show : "NULL"]' to the '[io]' pin of \the [io.holder].</span>")
if (PULSE_CHANNEL)
io.holder.check_then_do_work(ignore_power = TRUE)
to_chat(user, "<span class='notice'>You pulse \the [io.holder]'s '[io]' pin.</span>")
io.holder.interact(user) // This is to update the UI.
/obj/item/device/multitool
var/datum/integrated_io/selected_io = null
var/mode = 0
/obj/item/device/multitool/attack_self(mob/user)
if(selected_io)
selected_io = null
to_chat(user, "<span class='notice'>You clear the wired connection from the multitool.</span>")
else
..()
update_icon()
/obj/item/device/multitool/update_icon()
if(selected_io)
if(buffer || connecting || buffer_object)
icon_state = "multitool_tracking"
else
icon_state = "multitool_red"
else
if(buffer || connecting || buffer_object)
icon_state = "multitool_tracking_fail"
else
icon_state = "multitool"
/obj/item/device/multitool/proc/wire(datum/integrated_io/io, mob/user)
if(!io.holder.assembly)
to_chat(user, "<span class='warning'>\The [io.holder] needs to be secured inside an assembly first.</span>")
return
if(selected_io)
if(io == selected_io)
to_chat(user, "<span class='warning'>Wiring \the [selected_io.holder]'s '[selected_io.name]' pin into itself is rather pointless.</span>")
return
if(io.io_type != selected_io.io_type)
to_chat(user, "<span class='warning'>Those two types of channels are incompatable. The first is a [selected_io.io_type], \
while the second is a [io.io_type].</span>")
return
if(io.holder.assembly && io.holder.assembly != selected_io.holder.assembly)
to_chat(user, "<span class='warning'>Both \the [io.holder] and \the [selected_io.holder] need to be inside the same assembly.</span>")
return
selected_io.linked |= io
io.linked |= selected_io
to_chat(user, "<span class='notice'>You connect \the [selected_io.holder]'s '[selected_io.name]' pin to \the [io.holder]'s '[io.name]' pin.</span>")
selected_io.holder.interact(user) // This is to update the UI.
selected_io = null
else
selected_io = io
to_chat(user, "<span class='notice'>You link \the multitool to \the [selected_io.holder]'s [selected_io.name] data channel.</span>")
update_icon()
/obj/item/device/multitool/proc/unwire(datum/integrated_io/io1, datum/integrated_io/io2, mob/user)
if(!io1.linked.len || !io2.linked.len)
to_chat(user, "<span class='warning'>There is nothing connected to the data channel.</span>")
return
if(!(io1 in io2.linked) || !(io2 in io1.linked) )
to_chat(user, "<span class='warning'>These data pins aren't connected!</span>")
return
else
io1.linked.Remove(io2)
io2.linked.Remove(io1)
to_chat(user, "<span class='notice'>You clip the data connection between the [io1.holder.displayed_name]'s \
'[io1.name]' pin and the [io2.holder.displayed_name]'s '[io2.name]' pin.</span>")
io1.holder.interact(user) // This is to update the UI.
update_icon()
/obj/item/weapon/storage/bag/circuits
name = "circuit kit"
desc = "This kit's essential for any circuitry projects."
icon = 'icons/obj/electronic_assemblies.dmi'
icon_state = "circuit_kit"
w_class = 3
display_contents_with_number = 0
can_hold = list(
/obj/item/integrated_circuit,
/obj/item/weapon/storage/bag/circuits/mini,
/obj/item/device/electronic_assembly,
/obj/item/device/integrated_electronics,
/obj/item/weapon/crowbar,
/obj/item/weapon/screwdriver,
/obj/item/device/multitool
)
/obj/item/weapon/storage/bag/circuits/basic/fill()
new /obj/item/weapon/storage/bag/circuits/mini/arithmetic(src)
new /obj/item/weapon/storage/bag/circuits/mini/trig(src)
new /obj/item/weapon/storage/bag/circuits/mini/input(src)
new /obj/item/weapon/storage/bag/circuits/mini/output(src)
new /obj/item/weapon/storage/bag/circuits/mini/memory(src)
new /obj/item/weapon/storage/bag/circuits/mini/logic(src)
new /obj/item/weapon/storage/bag/circuits/mini/time(src)
new /obj/item/weapon/storage/bag/circuits/mini/reagents(src)
new /obj/item/weapon/storage/bag/circuits/mini/transfer(src)
new /obj/item/weapon/storage/bag/circuits/mini/converter(src)
new /obj/item/weapon/storage/bag/circuits/mini/power(src)
new /obj/item/device/electronic_assembly(src)
new /obj/item/device/assembly/electronic_assembly(src)
new /obj/item/device/assembly/electronic_assembly(src)
new /obj/item/device/multitool(src)
new /obj/item/weapon/screwdriver(src)
new /obj/item/weapon/crowbar(src)
make_exact_fit()
/obj/item/weapon/storage/bag/circuits/all/fill()
..()
new /obj/item/weapon/storage/bag/circuits/mini/arithmetic/all(src)
new /obj/item/weapon/storage/bag/circuits/mini/trig/all(src)
new /obj/item/weapon/storage/bag/circuits/mini/input/all(src)
new /obj/item/weapon/storage/bag/circuits/mini/output/all(src)
new /obj/item/weapon/storage/bag/circuits/mini/memory/all(src)
new /obj/item/weapon/storage/bag/circuits/mini/logic/all(src)
new /obj/item/weapon/storage/bag/circuits/mini/smart/all(src)
new /obj/item/weapon/storage/bag/circuits/mini/manipulation/all(src)
new /obj/item/weapon/storage/bag/circuits/mini/time/all(src)
new /obj/item/weapon/storage/bag/circuits/mini/reagents/all(src)
new /obj/item/weapon/storage/bag/circuits/mini/transfer/all(src)
new /obj/item/weapon/storage/bag/circuits/mini/converter/all(src)
new /obj/item/weapon/storage/bag/circuits/mini/power/all(src)
new /obj/item/device/electronic_assembly(src)
new /obj/item/device/electronic_assembly/medium(src)
new /obj/item/device/electronic_assembly/large(src)
new /obj/item/device/electronic_assembly/drone(src)
new /obj/item/device/integrated_electronics/wirer(src)
new /obj/item/device/integrated_electronics/debugger(src)
new /obj/item/weapon/crowbar(src)
make_exact_fit()
/obj/item/weapon/storage/bag/circuits/mini
name = "circuit box"
desc = "Used to partition categories of circuits, for a neater workspace."
w_class = 2
display_contents_with_number = 1
can_hold = list(/obj/item/integrated_circuit)
var/spawn_flags_to_use = IC_SPAWN_DEFAULT
var/list/spawn_types = list()
/obj/item/weapon/storage/bag/circuits/mini/fill()
spawn_types = typecacheof(spawn_types)
for (var/thing in typecache_filter_list(SSelectronics.all_integrated_circuits, spawn_types))
var/obj/item/integrated_circuit/IC = thing
if (IC.spawn_flags & spawn_flags_to_use)
for (var/i in 1 to 4)
new IC.type(src)
make_exact_fit()
/obj/item/weapon/storage/bag/circuits/mini/arithmetic
name = "arithmetic circuit box"
desc = "Warning: Contains math."
icon_state = "box_arithmetic"
spawn_types = list(
/obj/item/integrated_circuit/arithmetic
)
/obj/item/weapon/storage/bag/circuits/mini/arithmetic/all // Don't believe this will ever be needed.
spawn_flags_to_use = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
/obj/item/weapon/storage/bag/circuits/mini/trig
name = "trig circuit box"
desc = "Danger: Contains more math."
icon_state = "box_trig"
spawn_types = list(
/obj/item/integrated_circuit/trig
)
/obj/item/weapon/storage/bag/circuits/mini/trig/all // Ditto
spawn_flags_to_use = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
/obj/item/weapon/storage/bag/circuits/mini/input
name = "input circuit box"
desc = "Tell these circuits everything you know."
icon_state = "box_input"
spawn_types = list(
/obj/item/integrated_circuit/input
)
/obj/item/weapon/storage/bag/circuits/mini/input/all
spawn_flags_to_use = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
/obj/item/weapon/storage/bag/circuits/mini/output
name = "output circuit box"
desc = "Circuits to interface with the world beyond itself."
icon_state = "box_output"
spawn_types = list(
/obj/item/integrated_circuit/output
)
/obj/item/weapon/storage/bag/circuits/mini/output/all
spawn_flags_to_use = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
/obj/item/weapon/storage/bag/circuits/mini/memory
name = "memory circuit box"
desc = "Machines can be quite forgetful without these."
icon_state = "box_memory"
spawn_types = list(
/obj/item/integrated_circuit/memory
)
/obj/item/weapon/storage/bag/circuits/mini/memory/all
spawn_flags_to_use = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
/obj/item/weapon/storage/bag/circuits/mini/logic
name = "logic circuit box"
desc = "May or may not be Turing complete."
icon_state = "box_logic"
spawn_types = list(
/obj/item/integrated_circuit/logic
)
/obj/item/weapon/storage/bag/circuits/mini/logic/all
spawn_flags_to_use = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
/obj/item/weapon/storage/bag/circuits/mini/time
name = "time circuit box"
desc = "No time machine parts, sadly."
icon_state = "box_time"
spawn_types = list(
/obj/item/integrated_circuit/time
)
/obj/item/weapon/storage/bag/circuits/mini/time/all
spawn_flags_to_use = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
/obj/item/weapon/storage/bag/circuits/mini/reagents
name = "reagent circuit box"
desc = "Unlike most electronics, these circuits are supposed to come in contact with liquids."
icon_state = "box_reagents"
spawn_types = list(
/obj/item/integrated_circuit/reagent
)
/obj/item/weapon/storage/bag/circuits/mini/reagents/all
spawn_flags_to_use = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
/obj/item/weapon/storage/bag/circuits/mini/transfer
name = "transfer circuit box"
desc = "Useful for moving data representing something arbitrary to another arbitrary virtual place."
icon_state = "box_transfer"
spawn_types = list(
/obj/item/integrated_circuit/transfer
)
/obj/item/weapon/storage/bag/circuits/mini/transfer/all
spawn_flags_to_use = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
/obj/item/weapon/storage/bag/circuits/mini/converter
name = "converter circuit box"
desc = "Transform one piece of data to another type of data with these."
icon_state = "box_converter"
spawn_types = list(
/obj/item/integrated_circuit/converter
)
/obj/item/weapon/storage/bag/circuits/mini/converter/all
spawn_flags_to_use = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
/obj/item/weapon/storage/bag/circuits/mini/smart
name = "smart box"
desc = "Sentience not included."
icon_state = "box_ai"
spawn_types = list(
/obj/item/integrated_circuit/smart
)
/obj/item/weapon/storage/bag/circuits/mini/smart/all
spawn_flags_to_use = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
/obj/item/weapon/storage/bag/circuits/mini/manipulation
name = "manipulation box"
desc = "Make your machines actually useful with these."
icon_state = "box_manipulation"
spawn_types = list(
/obj/item/integrated_circuit/manipulation
)
/obj/item/weapon/storage/bag/circuits/mini/manipulation/all
spawn_flags_to_use = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
/obj/item/weapon/storage/bag/circuits/mini/power
name = "power circuit box"
desc = "Electronics generally require electricity."
icon_state = "box_power"
spawn_types = list(
/obj/item/integrated_circuit/passive/power,
/obj/item/integrated_circuit/power
)
/obj/item/weapon/storage/bag/circuits/mini/power/all
spawn_flags_to_use = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
@@ -0,0 +1,7 @@
// '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()
outputs = list()
activators = list()
power_draw_idle = 0
power_draw_per_use = 0
@@ -0,0 +1,106 @@
/obj/item/integrated_circuit/passive/power
name = "power thingy"
desc = "Does power stuff."
complexity = 5
origin_tech = list(TECH_POWER = 2, TECH_ENGINEERING = 2, TECH_DATA = 2)
category_text = "Power - Passive"
/obj/item/integrated_circuit/passive/power/proc/make_energy()
return
// 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."
extended_desc = "The cell generates 1W of energy per second 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
var/max_power = 1
/obj/item/integrated_circuit/passive/power/solar_cell/make_energy()
var/turf/T = get_turf(src)
var/light_amount = T ? T.get_lumcount() : 0
var/adjusted_power = max(max_power * light_amount, 0)
adjusted_power = round(adjusted_power, 0.1)
if(adjusted_power && assembly)
assembly.give_power(adjusted_power)
// 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."
w_class = ITEMSIZE_NORMAL
extended_desc = "The siphon generates 250W 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."
icon_state = "power_relay"
complexity = 7
origin_tech = list(TECH_POWER = 3, TECH_ENGINEERING = 3, TECH_DATA = 2)
spawn_flags = IC_SPAWN_RESEARCH
var/power_amount = 250
// 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!"
w_class = ITEMSIZE_LARGE
extended_desc = "The siphon generates 2 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."
icon_state = "power_relay"
complexity = 15
origin_tech = list(TECH_POWER = 6, TECH_ENGINEERING = 5, TECH_DATA = 4)
spawn_flags = IC_SPAWN_RESEARCH
power_amount = 2000
/obj/item/integrated_circuit/passive/power/relay/make_energy()
if(!assembly)
return
var/area/A = get_area(src)
if(A)
if(A.powered(EQUIP) && assembly.give_power(power_amount))
A.use_power(power_amount, EQUIP)
// give_power() handles CELLRATE on its own.
// 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."
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."
icon_state = "setup_implant"
complexity = 10
origin_tech = list(TECH_POWER = 4, TECH_ENGINEERING = 4, TECH_DATA = 4, TECH_BIO = 5)
spawn_flags = IC_SPAWN_RESEARCH
/obj/item/integrated_circuit/passive/power/metabolic_siphon/proc/test_validity(var/mob/living/carbon/human/host)
if(!host || host.isSynthetic() || host.stat == DEAD || host.nutrition <= 10)
return FALSE // Robots and dead people don't have a metabolism.
return TRUE
/obj/item/integrated_circuit/passive/power/metabolic_siphon/make_energy()
var/mob/living/carbon/human/host
if(assembly && istype(assembly, /obj/item/device/electronic_assembly/implant))
var/obj/item/device/electronic_assembly/implant/implant_assembly = assembly
if(implant_assembly.implant.imp_in)
host = implant_assembly.implant.imp_in
if(test_validity(host))
assembly.give_power(10)
host.nutrition = max(host.nutrition - HUNGER_FACTOR, 0)
/obj/item/integrated_circuit/passive/power/metabolic_siphon/synthetic
name = "internal energy siphon"
desc = "A small circuit designed to be connected to an internal power wire inside a synthetic entity."
extended_desc = "The siphon generates 10W of energy, so long as the siphon exists inside a synthetic entity. The entity need to recharge \
more often due to this. This device will fail if used inside organic entities."
icon_state = "setup_implant"
complexity = 10
origin_tech = list(TECH_POWER = 3, TECH_ENGINEERING = 4, TECH_DATA = 3)
spawn_flags = IC_SPAWN_RESEARCH
/obj/item/integrated_circuit/passive/power/metabolic_siphon/synthetic/test_validity(var/mob/living/carbon/human/host)
if(!host || !host.isSynthetic() || host.stat == DEAD || host.nutrition <= 10)
return FALSE // This time we don't want a metabolism.
return TRUE
@@ -0,0 +1,314 @@
//These circuits do simple math.
/obj/item/integrated_circuit/arithmetic
complexity = 1
inputs = list(
"A" = IC_PINTYPE_NUMBER,
"B" = IC_PINTYPE_NUMBER,
"C" = IC_PINTYPE_NUMBER,
"D" = IC_PINTYPE_NUMBER,
"E" = IC_PINTYPE_NUMBER,
"F" = IC_PINTYPE_NUMBER,
"G" = IC_PINTYPE_NUMBER,
"H" = IC_PINTYPE_NUMBER
)
outputs = list("result" = IC_PINTYPE_NUMBER)
activators = list("compute" = IC_PINTYPE_PULSE_IN, "on computed" = IC_PINTYPE_PULSE_OUT)
category_text = "Arithmetic"
power_draw_per_use = 5 // Math is pretty cheap.
// +Adding+ //
/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>\
result = ((((A + B) + C) + D) ... ) and so on, until all pins have been added. \
Null pins are ignored."
icon_state = "addition"
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
/obj/item/integrated_circuit/arithmetic/addition/do_work()
var/result = 0
for(var/datum/integrated_io/I in inputs)
I.pull_data()
if(isnum(I.data))
result = result + I.data
set_pin_data(IC_OUTPUT, 1, result)
push_data()
activate_pin(2)
// -Subtracting- //
/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>\
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"
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
/obj/item/integrated_circuit/arithmetic/subtraction/do_work()
var/datum/integrated_io/A = inputs[1]
if(!isnum(A.data))
return
var/result = A.data
for(var/datum/integrated_io/I in inputs)
if(I == A)
continue
I.pull_data()
if(isnum(I.data))
result = result - I.data
set_pin_data(IC_OUTPUT, 1, result)
push_data()
activate_pin(2)
// *Multiply* //
/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>\
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"
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
/obj/item/integrated_circuit/arithmetic/multiplication/do_work()
var/datum/integrated_io/A = inputs[1]
if(!isnum(A.data))
return
var/result = A.data
for(var/datum/integrated_io/I in inputs)
if(I == A)
continue
I.pull_data()
if(isnum(I.data))
result = result * I.data
set_pin_data(IC_OUTPUT, 1, result)
push_data()
activate_pin(2)
// /Division/ //
/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>\
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"
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
/obj/item/integrated_circuit/arithmetic/division/do_work()
var/datum/integrated_io/A = inputs[1]
if(!isnum(A.data))
return
var/result = A.data
for(var/datum/integrated_io/I in inputs)
if(I == A)
continue
I.pull_data()
if(isnum(I.data) && I.data != 0) //No runtimes here.
result = result / I.data
set_pin_data(IC_OUTPUT, 1, result)
push_data()
activate_pin(2)
//^ Exponent ^//
/obj/item/integrated_circuit/arithmetic/exponent
name = "exponent circuit"
desc = "Outputs A to the power of B."
icon_state = "exponent"
inputs = list("A" = IC_PINTYPE_NUMBER, "B" = IC_PINTYPE_NUMBER)
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
/obj/item/integrated_circuit/arithmetic/exponent/do_work()
var/result = 0
var/datum/integrated_io/A = inputs[1]
var/datum/integrated_io/B = inputs[2]
if(isnum(A.data) && isnum(B.data))
result = A.data ** B.data
set_pin_data(IC_OUTPUT, 1, result)
push_data()
activate_pin(2)
// +-Sign-+ //
/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."
icon_state = "sign"
inputs = list("A" = IC_PINTYPE_NUMBER)
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
/obj/item/integrated_circuit/arithmetic/sign/do_work()
var/result = 0
var/datum/integrated_io/A = inputs[1]
if(isnum(A.data))
if(A.data > 0)
result = 1
else if (A.data < 0)
result = -1
else
result = 0
set_pin_data(IC_OUTPUT, 1, result)
push_data()
activate_pin(2)
// Round //
/obj/item/integrated_circuit/arithmetic/round
name = "round circuit"
desc = "Rounds A to the nearest B multiple of A."
extended_desc = "If B is not given a number, it will output the floor of A instead."
icon_state = "round"
inputs = list("A" = IC_PINTYPE_NUMBER, "B" = IC_PINTYPE_NUMBER)
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
/obj/item/integrated_circuit/arithmetic/round/do_work()
var/result = 0
var/datum/integrated_io/A = inputs[1]
var/datum/integrated_io/B = inputs[2]
if(isnum(A.data))
if(isnum(B.data) && B.data != 0)
result = round(A.data, B.data)
else
result = round(A.data)
set_pin_data(IC_OUTPUT, 1, result)
push_data()
activate_pin(2)
// Absolute //
/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."
icon_state = "absolute"
inputs = list("A" = IC_PINTYPE_NUMBER)
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
/obj/item/integrated_circuit/arithmetic/absolute/do_work()
var/result = 0
for(var/datum/integrated_io/I in inputs)
I.pull_data()
if(isnum(I.data))
result = abs(I.data)
set_pin_data(IC_OUTPUT, 1, result)
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."
icon_state = "average"
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
/obj/item/integrated_circuit/arithmetic/average/do_work()
var/result = 0
var/inputs_used = 0
for(var/datum/integrated_io/I in inputs)
I.pull_data()
if(isnum(I.data))
inputs_used++
result = result + I.data
if(inputs_used)
result = result / inputs_used
set_pin_data(IC_OUTPUT, 1, result)
push_data()
activate_pin(2)
// 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."
icon_state = "pi"
inputs = list()
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
/obj/item/integrated_circuit/arithmetic/pi/do_work()
set_pin_data(IC_OUTPUT, 1, M_PI)
push_data()
activate_pin(2)
// 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."
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"
inputs = list("L" = IC_PINTYPE_NUMBER,"H" = IC_PINTYPE_NUMBER)
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
/obj/item/integrated_circuit/arithmetic/random/do_work()
var/result = 0
var/L = get_pin_data(IC_INPUT, 1)
var/H = get_pin_data(IC_INPUT, 2)
if(isnum(L) && isnum(H))
result = rand(L, H)
set_pin_data(IC_OUTPUT, 1, result)
push_data()
activate_pin(2)
// Square Root //
/obj/item/integrated_circuit/arithmetic/square_root
name = "square root circuit"
desc = "This outputs the square root of a number you put in."
icon_state = "square_root"
inputs = list("A" = IC_PINTYPE_NUMBER)
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
/obj/item/integrated_circuit/arithmetic/square_root/do_work()
var/result = 0
for(var/datum/integrated_io/I in inputs)
I.pull_data()
if(isnum(I.data))
result = sqrt(I.data)
set_pin_data(IC_OUTPUT, 1, result)
push_data()
activate_pin(2)
// % Modulo % //
/obj/item/integrated_circuit/arithmetic/modulo
name = "modulo circuit"
desc = "Gets the remainder of A / B."
icon_state = "modulo"
inputs = list("A" = IC_PINTYPE_NUMBER, "B" = IC_PINTYPE_NUMBER)
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
/obj/item/integrated_circuit/arithmetic/modulo/do_work()
var/result = 0
var/A = get_pin_data(IC_INPUT, 1)
var/B = get_pin_data(IC_INPUT, 2)
if(isnum(A) && isnum(B) && B != 0)
result = A % B
set_pin_data(IC_OUTPUT, 1, result)
push_data()
activate_pin(2)
@@ -0,0 +1,28 @@
/obj/item/integrated_circuit/built_in
name = "integrated circuit"
desc = "It's a tiny chip! This one doesn't seem to do much, however."
icon = 'icons/obj/electronic_assemblies.dmi'
icon_state = "template"
size = -1
w_class = ITEMSIZE_TINY
removable = FALSE // Determines if a circuit is removable from the assembly.
/obj/item/integrated_circuit/built_in/device_input
name = "assembly input"
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)
/obj/item/integrated_circuit/built_in/device_input/do_work()
activate_pin(1)
/obj/item/integrated_circuit/built_in/device_output
name = "assembly out"
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)
/obj/item/integrated_circuit/built_in/device_output/do_work()
if(istype(assembly, /obj/item/device/electronic_assembly/device))
var/obj/item/device/electronic_assembly/device/device = assembly
device.holder.pulse()
@@ -0,0 +1,238 @@
//These circuits convert one variable to another.
/obj/item/integrated_circuit/converter
complexity = 2
inputs = list("input")
outputs = list("output")
activators = list("convert" = IC_PINTYPE_PULSE_IN, "on convert" = IC_PINTYPE_PULSE_OUT)
category_text = "Converter"
power_draw_per_use = 10
/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."
icon_state = "num-string"
inputs = list("input" = IC_PINTYPE_NUMBER)
outputs = list("output" = IC_PINTYPE_STRING)
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
/obj/item/integrated_circuit/converter/num2text/do_work()
var/result = null
pull_data()
var/incoming = get_pin_data(IC_INPUT, 1)
if(!isnull(incoming))
result = num2text(incoming)
else if(!incoming)
result = "0"
set_pin_data(IC_OUTPUT, 1, result)
push_data()
activate_pin(2)
/obj/item/integrated_circuit/converter/text2num
name = "string to number"
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)
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
/obj/item/integrated_circuit/converter/text2num/do_work()
var/result = null
pull_data()
var/incoming = get_pin_data(IC_INPUT, 1)
if(!isnull(incoming))
result = text2num(incoming)
set_pin_data(IC_OUTPUT, 1, result)
push_data()
activate_pin(2)
/obj/item/integrated_circuit/converter/ref2text
name = "reference to string"
desc = "This circuit can convert a reference to something else to a string, specifically the name of that reference."
icon_state = "ref-string"
inputs = list("input" = IC_PINTYPE_REF)
outputs = list("output" = IC_PINTYPE_STRING)
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
/obj/item/integrated_circuit/converter/ref2text/do_work()
var/result = null
pull_data()
var/atom/A = get_pin_data_as_type(IC_INPUT, 1, /atom)
if(A)
result = A.name
set_pin_data(IC_OUTPUT, 1, result)
push_data()
activate_pin(2)
/obj/item/integrated_circuit/converter/lowercase
name = "lowercase string converter"
desc = "this will cause a string to come out in all lowercase."
icon_state = "lowercase"
inputs = list("input" = IC_PINTYPE_STRING)
outputs = list("output" = IC_PINTYPE_STRING)
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
/obj/item/integrated_circuit/converter/lowercase/do_work()
var/result = null
pull_data()
var/incoming = get_pin_data(IC_INPUT, 1)
if(!isnull(incoming))
result = lowertext(incoming)
set_pin_data(IC_OUTPUT, 1, result)
push_data()
activate_pin(2)
/obj/item/integrated_circuit/converter/uppercase
name = "uppercase string converter"
desc = "THIS WILL CAUSE A STRING TO COME OUT IN ALL UPPERCASE."
icon_state = "uppercase"
inputs = list("input" = IC_PINTYPE_STRING)
outputs = list("output" = IC_PINTYPE_STRING)
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
/obj/item/integrated_circuit/converter/uppercase/do_work()
var/result = null
pull_data()
var/incoming = get_pin_data(IC_INPUT, 1)
if(!isnull(incoming))
result = uppertext(incoming)
set_pin_data(IC_OUTPUT, 1, result)
push_data()
activate_pin(2)
/obj/item/integrated_circuit/converter/concatenator
name = "concatenator"
desc = "This joins many strings together to get one big string."
complexity = 4
inputs = list(
"A" = IC_PINTYPE_STRING,
"B" = IC_PINTYPE_STRING,
"C" = IC_PINTYPE_STRING,
"D" = IC_PINTYPE_STRING,
"E" = IC_PINTYPE_STRING,
"F" = IC_PINTYPE_STRING,
"G" = IC_PINTYPE_STRING,
"H" = IC_PINTYPE_STRING
)
outputs = list("result" = IC_PINTYPE_STRING)
activators = list("concatenate" = IC_PINTYPE_PULSE_IN, "on concatenated" = IC_PINTYPE_PULSE_OUT)
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
/obj/item/integrated_circuit/converter/concatenator/do_work()
var/result = null
for(var/datum/integrated_io/I in inputs)
I.pull_data()
if(!isnull(I.data))
result = result + I.data
set_pin_data(IC_OUTPUT, 1, result)
push_data()
activate_pin(2)
/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. \
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
inputs = list(
"string to split" = IC_PINTYPE_STRING,
"index" = IC_PINTYPE_NUMBER
)
outputs = list(
"before split" = IC_PINTYPE_STRING,
"after split" = IC_PINTYPE_STRING
)
activators = list("separate" = IC_PINTYPE_PULSE_IN, "on separated" = IC_PINTYPE_PULSE_OUT)
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
/obj/item/integrated_circuit/converter/separator/do_work()
var/text = get_pin_data(IC_INPUT, 1)
var/index = get_pin_data(IC_INPUT, 2)
var/split = min(index+1, length(text))
var/before_text = copytext(text, 1, split)
var/after_text = copytext(text, split, 0)
set_pin_data(IC_OUTPUT, 1, before_text)
set_pin_data(IC_OUTPUT, 2, after_text)
push_data()
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 = ToDegrees(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 = ToRadians(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."
complexity = 4
inputs = list(
"X1" = IC_PINTYPE_NUMBER,
"Y1" = IC_PINTYPE_NUMBER,
"X2" = IC_PINTYPE_NUMBER,
"Y2" = IC_PINTYPE_NUMBER
)
outputs = list(
"X" = IC_PINTYPE_NUMBER,
"Y" = IC_PINTYPE_NUMBER
)
activators = list("compute rel coordinates" = IC_PINTYPE_PULSE_IN, "on convert" = IC_PINTYPE_PULSE_OUT)
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
/obj/item/integrated_circuit/converter/abs_to_rel_coords/do_work()
var/x1 = get_pin_data(IC_INPUT, 1)
var/y1 = get_pin_data(IC_INPUT, 2)
var/x2 = get_pin_data(IC_INPUT, 3)
var/y2 = get_pin_data(IC_INPUT, 4)
if(!isnull(x1) && !isnull(y1) && !isnull(x2) && !isnull(y2))
set_pin_data(IC_OUTPUT, 1, x1 - x2)
set_pin_data(IC_OUTPUT, 2, y1 - y2)
push_data()
activate_pin(2)
@@ -0,0 +1,165 @@
/obj/item/integrated_circuit/transfer
category_text = "Data Transfer"
power_draw_per_use = 2
/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."
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
icon_state = "mux2"
inputs = list("input selection" = IC_PINTYPE_NUMBER)
outputs = list("output" = IC_PINTYPE_ANY)
activators = list(
"select" = IC_PINTYPE_PULSE_IN,
"on select" = IC_PINTYPE_PULSE_OUT
)
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
power_draw_per_use = 4
var/number_of_inputs = 2
/obj/item/integrated_circuit/transfer/multiplexer/Initialize()
for(var/i = 1 to number_of_inputs)
inputs["input [i]"] = IC_PINTYPE_ANY // This is just a string since pins don't get built until ..() is called.
complexity = number_of_inputs
. = ..()
desc += " It has [number_of_inputs] input pins."
extended_desc += " This multiplexer has a range from 1 to [inputs.len - 1]."
/obj/item/integrated_circuit/transfer/multiplexer/do_work()
var/input_index = get_pin_data(IC_INPUT, 1)
var/output = null
if(!isnull(input_index) && (input_index >= 1 && input_index < inputs.len))
output = get_pin_data(IC_INPUT, input_index + 1)
set_pin_data(IC_OUTPUT, 1, output)
push_data()
activate_pin(2)
/obj/item/integrated_circuit/transfer/multiplexer/medium
name = "four multiplexer"
number_of_inputs = 4
icon_state = "mux4"
/obj/item/integrated_circuit/transfer/multiplexer/large
name = "eight multiplexer"
number_of_inputs = 8
w_class = ITEMSIZE_SMALL
icon_state = "mux8"
/obj/item/integrated_circuit/transfer/multiplexer/huge
name = "sixteen multiplexer"
icon_state = "mux16"
w_class = ITEMSIZE_SMALL
number_of_inputs = 16
/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."
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
icon_state = "dmux2"
inputs = list(
"output selection" = IC_PINTYPE_NUMBER,
"input" = IC_PINTYPE_ANY
)
outputs = list()
activators = list(
"select" = IC_PINTYPE_PULSE_IN,
"on select" = IC_PINTYPE_PULSE_OUT
)
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
power_draw_per_use = 4
var/number_of_outputs = 2
/obj/item/integrated_circuit/transfer/demultiplexer/Initialize()
for(var/i = 1 to number_of_outputs)
outputs["output [i]"] = IC_PINTYPE_ANY
complexity = number_of_outputs
. = ..()
desc += " It has [number_of_outputs] output pins."
extended_desc += " This demultiplexer has a range from 1 to [outputs.len]."
/obj/item/integrated_circuit/transfer/demultiplexer/do_work()
var/output_index = get_pin_data(IC_INPUT, 1)
var/output = get_pin_data(IC_INPUT, 2)
for(var/i = 1 to outputs.len)
set_pin_data(IC_OUTPUT, i, i == output_index ? output : null)
activate_pin(2)
/obj/item/integrated_circuit/transfer/demultiplexer/medium
name = "four demultiplexer"
icon_state = "dmux4"
number_of_outputs = 4
/obj/item/integrated_circuit/transfer/demultiplexer/large
name = "eight demultiplexer"
icon_state = "dmux8"
w_class = ITEMSIZE_SMALL
number_of_outputs = 8
/obj/item/integrated_circuit/transfer/demultiplexer/huge
name = "sixteen demultiplexer"
icon_state = "dmux16"
w_class = ITEMSIZE_SMALL
number_of_outputs = 16
/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."
complexity = 12
spawn_flags = IC_SPAWN_RESEARCH
icon_state = "bluespace"
power_draw_per_use = 100 // fancy subspace comms aren't cheap power-wise
w_class = ITEMSIZE_SMALL
inputs = list(
"data" = IC_PINTYPE_ANY,
"channel" = IC_PINTYPE_STRING
)
outputs = list(
"data" = IC_PINTYPE_ANY
)
activators = list(
"send" = IC_PINTYPE_PULSE_IN,
"receive" = IC_PINTYPE_PULSE_OUT
)
var/last_channel
var/listener/listener
/obj/item/integrated_circuit/transfer/wireless/do_work()
pull_data()
var/data = get_pin_data(IC_INPUT, 1)
if (data != null)
var/chan = "[WP_ELECTRONICS][get_pin_data(IC_INPUT, 2) || "default"]"
for (var/thing in GET_LISTENERS(chan))
var/listener/L = thing
var/obj/item/integrated_circuit/transfer/wireless/W = L.target
if (W != src)
W.receive(data)
/obj/item/integrated_circuit/transfer/wireless/proc/receive(datum/data)
set_pin_data(IC_OUTPUT, 1, data)
push_data()
activate_pin(2)
/obj/item/integrated_circuit/transfer/wireless/Destroy()
QDEL_NULL(listener)
return ..()
/obj/item/integrated_circuit/transfer/wireless/on_data_written()
var/chan = "[WP_ELECTRONICS][get_pin_data(IC_INPUT, 2) || "default"]"
if (chan != last_channel)
QDEL_NULL(listener)
listener = new(chan, src)
last_channel = chan
@@ -0,0 +1,381 @@
/obj/item/integrated_circuit/input
var/can_be_asked_input = 0
category_text = "Input"
power_draw_per_use = 5
/obj/item/integrated_circuit/input/proc/ask_for_input(mob/user)
return
/obj/item/integrated_circuit/input/button
name = "button"
desc = "This tiny button must do something, right?"
icon_state = "button"
complexity = 1
can_be_asked_input = 1
inputs = list()
outputs = list()
activators = list("on pressed" = IC_PINTYPE_PULSE_OUT)
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
/obj/item/integrated_circuit/input/button/ask_for_input(mob/user) //Bit misleading name for this specific use.
to_chat(user, "<span class='notice'>You press the button labeled '[src.name]'.</span>")
activate_pin(1)
/obj/item/integrated_circuit/input/toggle_button
name = "toggle button"
desc = "It toggles on, off, on, off..."
icon_state = "toggle_button"
complexity = 1
can_be_asked_input = 1
inputs = list()
outputs = list("on" = IC_PINTYPE_BOOLEAN)
activators = list("on toggle" = IC_PINTYPE_PULSE_OUT)
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
/obj/item/integrated_circuit/input/toggle_button/ask_for_input(mob/user) // Ditto.
set_pin_data(IC_OUTPUT, 1, !get_pin_data(IC_OUTPUT, 1))
push_data()
activate_pin(1)
to_chat(user, "<span class='notice'>You toggle the button labeled '[src.name]' [get_pin_data(IC_OUTPUT, 1) ? "on" : "off"].</span>")
/obj/item/integrated_circuit/input/numberpad
name = "number pad"
desc = "This small number pad allows someone to input a number into the system."
icon_state = "numberpad"
complexity = 2
can_be_asked_input = 1
inputs = list()
outputs = list("number entered" = IC_PINTYPE_NUMBER)
activators = list("on entered" = IC_PINTYPE_PULSE_OUT)
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
power_draw_per_use = 4
/obj/item/integrated_circuit/input/numberpad/ask_for_input(mob/user)
var/new_input = input(user, "Enter a number, please.","Number pad") as null|num
if(isnum(new_input) && CanInteract(user, physical_state))
set_pin_data(IC_OUTPUT, 1, new_input)
push_data()
activate_pin(1)
/obj/item/integrated_circuit/input/textpad
name = "text pad"
desc = "This small text pad allows someone to input a string into the system."
icon_state = "textpad"
complexity = 2
can_be_asked_input = 1
inputs = list()
outputs = list("string entered" = IC_PINTYPE_STRING)
activators = list("on entered" = IC_PINTYPE_PULSE_OUT)
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
power_draw_per_use = 4
/obj/item/integrated_circuit/input/textpad/ask_for_input(mob/user)
var/new_input = sanitize(input(user, "Enter some words, please.","Number pad") as null|text)
if(istext(new_input) && CanInteract(user, physical_state))
set_pin_data(IC_OUTPUT, 1, new_input)
push_data()
activate_pin(1)
/obj/item/integrated_circuit/input/med_scanner
name = "integrated medical analyser"
desc = "A very small version of the common medical analyser. This allows the machine to know how healthy someone is."
icon_state = "medscan"
complexity = 4
inputs = list("target" = IC_PINTYPE_REF)
outputs = list(
"total health %" = IC_PINTYPE_NUMBER,
"total missing health" = IC_PINTYPE_NUMBER
)
activators = list("scan" = IC_PINTYPE_PULSE_IN, "on scanned" = IC_PINTYPE_PULSE_OUT)
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
origin_tech = list(TECH_ENGINEERING = 2, TECH_DATA = 2, TECH_BIO = 2)
power_draw_per_use = 40
/obj/item/integrated_circuit/input/med_scanner/do_work()
var/mob/living/carbon/human/H = get_pin_data_as_type(IC_INPUT, 1, /mob/living/carbon/human)
if(!istype(H)) //Invalid input
return
if(H.Adjacent(get_turf(src))) // Like normal analysers, it can't be used at range.
var/total_health = round(H.health/H.getMaxHealth(), 0.01)*100
var/missing_health = H.getMaxHealth() - H.health
set_pin_data(IC_OUTPUT, 1, total_health)
set_pin_data(IC_OUTPUT, 2, missing_health)
push_data()
activate_pin(2)
/obj/item/integrated_circuit/input/adv_med_scanner
name = "integrated advanced medical analyser"
desc = "A very small version of the common medical analyser. This allows the machine to know how healthy someone is. \
This type is much more precise, allowing the machine to know much more about the target than a normal analyzer."
icon_state = "medscan_adv"
complexity = 12
inputs = list("target" = IC_PINTYPE_REF)
outputs = list(
"total health %" = IC_PINTYPE_NUMBER,
"total missing health" = IC_PINTYPE_NUMBER,
"brute damage" = IC_PINTYPE_NUMBER,
"burn damage" = IC_PINTYPE_NUMBER,
"tox damage" = IC_PINTYPE_NUMBER,
"oxy damage" = IC_PINTYPE_NUMBER,
"clone damage" = IC_PINTYPE_NUMBER
)
activators = list("scan" = IC_PINTYPE_PULSE_IN, "on scanned" = IC_PINTYPE_PULSE_OUT)
spawn_flags = IC_SPAWN_RESEARCH
origin_tech = list(TECH_ENGINEERING = 3, TECH_DATA = 3, TECH_BIO = 4)
power_draw_per_use = 80
/obj/item/integrated_circuit/input/adv_med_scanner/do_work()
var/mob/living/carbon/human/H = get_pin_data_as_type(IC_INPUT, 1, /mob/living/carbon/human)
if(!istype(H)) //Invalid input
return
if(H.Adjacent(get_turf(src))) // Like normal analysers, it can't be used at range.
var/total_health = round(H.health/H.getMaxHealth(), 0.01)*100
var/missing_health = H.getMaxHealth() - H.health
set_pin_data(IC_OUTPUT, 1, total_health)
set_pin_data(IC_OUTPUT, 2, missing_health)
set_pin_data(IC_OUTPUT, 3, H.getBruteLoss())
set_pin_data(IC_OUTPUT, 4, H.getFireLoss())
set_pin_data(IC_OUTPUT, 5, H.getToxLoss())
set_pin_data(IC_OUTPUT, 6, H.getOxyLoss())
set_pin_data(IC_OUTPUT, 7, H.getCloneLoss())
push_data()
activate_pin(2)
/obj/item/integrated_circuit/input/local_locator
name = "local locator"
desc = "This is needed for certain devices that demand a reference for a target to act upon. This type only locates something \
that is holding the machine containing it."
inputs = list()
outputs = list(
"located ref" = IC_PINTYPE_REF
)
activators = list(
"locate" = IC_PINTYPE_PULSE_IN,
"on locate" = IC_PINTYPE_PULSE_OUT
)
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
power_draw_per_use = 20
/obj/item/integrated_circuit/input/local_locator/do_work()
if(assembly && istype(assembly.loc, /mob/living))
set_pin_data(IC_OUTPUT, 1, assembly.loc)
else
set_pin_data(IC_OUTPUT, 1, null)
activate_pin(2)
/obj/item/integrated_circuit/input/adjacent_locator
name = "adjacent locator"
desc = "This is needed for certain devices that demand a reference for a target to act upon. This type only locates something \
that is standing a meter away from the machine."
extended_desc = "The first pin requires a ref to a kind of object that you want the locator to acquire. This means that it will \
give refs to nearby objects that are similar. If more than one valid object is found nearby, it will choose one of them at \
random."
inputs = list("desired type ref" = IC_PINTYPE_REF)
outputs = list("located ref" = IC_PINTYPE_REF)
activators = list("locate" = IC_PINTYPE_PULSE_IN)
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
power_draw_per_use = 30
/obj/item/integrated_circuit/input/adjacent_locator/do_work()
var/atom/A = get_pin_data_as_type(IC_INPUT, 1, /atom)
if(!A)
set_pin_data(IC_OUTPUT, 1, null)
return
var/desired_type = A.type
var/list/nearby_things = range(1, get_turf(src))
var/list/valid_things = list()
for(var/atom/thing in nearby_things)
if(thing.type != desired_type)
continue
valid_things += thing
if(valid_things.len)
set_pin_data(IC_OUTPUT, 1, pick(valid_things))
/obj/item/integrated_circuit/input/signaler
name = "integrated signaler"
desc = "Signals from a signaler can be received with this, allowing for remote control. Additionally, it can send signals as well."
extended_desc = "When a signal is received from another signaler, the 'on signal received' activator pin will be pulsed. \
The two input pins are to configure the integrated signaler's settings. Note that the frequency should not have a decimal in it. \
Meaning the default frequency is expressed as 1457, not 145.7. To send a signal, pulse the 'send signal' activator pin."
icon_state = "signal"
complexity = 4
inputs = list(
"frequency" = IC_PINTYPE_NUMBER,
"code" = IC_PINTYPE_NUMBER
)
outputs = list()
activators = list(
"send signal" = IC_PINTYPE_PULSE_IN,
"on signal sent" = IC_PINTYPE_PULSE_OUT,
"on signal received" = IC_PINTYPE_PULSE_OUT
)
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
origin_tech = list(TECH_ENGINEERING = 2, TECH_DATA = 2, TECH_MAGNET = 2)
power_draw_idle = 5
power_draw_per_use = 40
var/frequency = 1457
var/code = 30
var/datum/radio_frequency/radio_connection
/obj/item/integrated_circuit/input/signaler/Initialize()
..()
set_frequency(frequency)
// Set the pins so when someone sees them, they won't show as null
set_pin_data(IC_INPUT, 1, frequency)
set_pin_data(IC_INPUT, 2, code)
/obj/item/integrated_circuit/input/signaler/Destroy()
SSradio.remove_object(src,frequency)
frequency = 0
. = ..()
/obj/item/integrated_circuit/input/signaler/on_data_written()
var/new_freq = get_pin_data(IC_INPUT, 1)
var/new_code = get_pin_data(IC_INPUT, 2)
if(isnum(new_freq) && new_freq > 0)
set_frequency(new_freq)
if(isnum(new_code))
code = new_code
/obj/item/integrated_circuit/input/signaler/do_work() // Sends a signal.
if(!radio_connection)
return
var/datum/signal/signal = new()
signal.source = src
signal.encryption = code
signal.data["message"] = "ACTIVATE"
radio_connection.post_signal(src, signal)
activate_pin(2)
/obj/item/integrated_circuit/input/signaler/proc/set_frequency(new_frequency)
if(!frequency)
return
SSradio.remove_object(src, frequency)
frequency = new_frequency
radio_connection = SSradio.add_object(src, frequency, RADIO_CHAT)
/obj/item/integrated_circuit/input/signaler/receive_signal(datum/signal/signal)
var/new_code = get_pin_data(IC_INPUT, 2)
var/code = 0
if(isnum(new_code))
code = new_code
if(!signal)
return 0
if(signal.encryption != code)
return 0
if(signal.source == src) // Don't trigger ourselves.
return 0
activate_pin(3)
for(var/mob/O in hearers(1, get_turf(src)))
O.show_message(text("\icon[] *beep* *beep*", src), 3, "*beep* *beep*", 2)
//This circuit gives information on where the machine is.
/obj/item/integrated_circuit/input/gps
name = "global positioning system"
desc = "This allows you to easily know the position of a machine containing this device."
extended_desc = "The GPS's coordinates it gives is absolute, not relative."
icon_state = "gps"
complexity = 4
inputs = list()
outputs = list(
"X"= IC_PINTYPE_NUMBER,
"Y" = IC_PINTYPE_NUMBER
)
activators = list(
"get coordinates" = IC_PINTYPE_PULSE_IN,
"on get coordinates" = IC_PINTYPE_PULSE_OUT
)
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
power_draw_per_use = 30
/obj/item/integrated_circuit/input/gps/do_work()
var/turf/T = get_turf(src)
set_pin_data(IC_OUTPUT, 1, null)
set_pin_data(IC_OUTPUT, 2, null)
if(!T)
return
set_pin_data(IC_OUTPUT, 1, T.x)
set_pin_data(IC_OUTPUT, 2, T.y)
push_data()
activate_pin(2)
/obj/item/integrated_circuit/input/microphone
name = "microphone"
desc = "Useful for spying on people or for voice activated machines."
extended_desc = "This will automatically translate most languages it hears to Tau Ceti Basic. \
The first activation pin is always pulsed when the circuit hears someone talk, while the second one \
is only triggered if it hears someone speaking a language other than Tau Ceti Basic."
icon_state = "recorder"
complexity = 8
inputs = list()
outputs = list(
"speaker" = IC_PINTYPE_STRING,
"message" = IC_PINTYPE_STRING
)
activators = list(
"on message received" = IC_PINTYPE_PULSE_OUT,
"on translation" = IC_PINTYPE_PULSE_OUT
)
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
power_draw_per_use = 15
/obj/item/integrated_circuit/input/microphone/Initialize()
. = ..()
listening_objects |= src
/obj/item/integrated_circuit/input/microphone/Destroy()
listening_objects -= src
return ..()
/obj/item/integrated_circuit/input/microphone/hear_talk(mob/living/M, msg, var/verb="says", datum/language/speaking=null)
var/translated = FALSE
if(M && msg)
if(speaking)
if(!istype(speaking, /datum/language/common))
translated = TRUE
set_pin_data(IC_OUTPUT, 1, M.GetVoice())
set_pin_data(IC_OUTPUT, 2, msg)
push_data()
activate_pin(1)
if(translated)
activate_pin(2)
/obj/item/integrated_circuit/input/sensor
name = "sensor"
desc = "Scans and obtains a reference for any objects or persons near you. All you need to do is shove the machine in their face."
extended_desc = "If 'ignore storage' pin is set to true, the sensor will disregard scanning various storage containers such as backpacks."
icon_state = "recorder"
complexity = 12
inputs = list("ignore storage" = IC_PINTYPE_BOOLEAN)
outputs = list("scanned" = IC_PINTYPE_REF)
activators = list("on scanned" = IC_PINTYPE_PULSE_OUT)
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
power_draw_per_use = 120
/obj/item/integrated_circuit/input/sensor/proc/scan(var/atom/A)
var/ignore_bags = get_pin_data(IC_INPUT, 1)
if(ignore_bags)
if(istype(A, /obj/item/weapon/storage))
return FALSE
set_pin_data(IC_OUTPUT, 1, A)
push_data()
activate_pin(1)
return TRUE
@@ -0,0 +1,87 @@
//These circuits do things with lists, and use special list pins for stability.
/obj/item/integrated_circuit/list
complexity = 1
inputs = list(
"input" = IC_PINTYPE_LIST
)
outputs = list("result" = IC_PINTYPE_STRING)
activators = list("compute" = IC_PINTYPE_PULSE_IN, "on computed" = IC_PINTYPE_PULSE_OUT)
category_text = "Lists"
power_draw_per_use = 20
/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."
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)
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."
inputs = list(
"list to append" = IC_PINTYPE_LIST,
"input" = IC_PINTYPE_ANY
)
outputs = list(
"appended list" = IC_PINTYPE_LIST
)
icon_state = "addition"
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
/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
set_pin_data(IC_OUTPUT, 1, output_list)
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."
inputs = list(
"list to join" = IC_PINTYPE_LIST,
"delimiter" = IC_PINTYPE_CHAR,
"start" = IC_PINTYPE_NUMBER,
"end" = IC_PINTYPE_NUMBER
)
inputs_default = list(
"2" = ",",
"3" = 1,
"4" = 0
)
outputs = list(
"joined text" = IC_PINTYPE_STRING
)
icon_state = "addition"
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
/obj/item/integrated_circuit/list/jointext/do_work()
var/list/input_list = get_pin_data(IC_INPUT, 1)
var/delimiter = get_pin_data(IC_INPUT, 2)
var/start = get_pin_data(IC_INPUT, 3)
var/end = get_pin_data(IC_INPUT, 4)
var/result = null
if(input_list.len && delimiter && !isnull(start) && !isnull(end))
result = jointext(input_list, delimiter, start, end)
set_pin_data(IC_OUTPUT, 1, result)
push_data()
activate_pin(2)
@@ -0,0 +1,135 @@
/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."
complexity = 3
outputs = list("result" = IC_PINTYPE_BOOLEAN)
activators = list("compare" = IC_PINTYPE_PULSE_IN)
category_text = "Logic"
power_draw_per_use = 1
/obj/item/integrated_circuit/logic/binary
inputs = list(
"A" = IC_PINTYPE_ANY,
"B" = IC_PINTYPE_ANY
)
activators = list(
"compare" = IC_PINTYPE_PULSE_IN,
"on true result" = IC_PINTYPE_PULSE_OUT,
"on false result" = IC_PINTYPE_PULSE_OUT
)
/obj/item/integrated_circuit/logic/binary/do_work()
var/data1 = get_pin_data(IC_INPUT, 1)
var/data2 = get_pin_data(IC_INPUT, 2)
var/result = !!do_compare(data1, data2)
set_pin_data(IC_OUTPUT, 1, result)
push_data()
if (result)
activate_pin(2)
else
activate_pin(3)
/obj/item/integrated_circuit/logic/binary/proc/do_compare(A, B)
return FALSE
/obj/item/integrated_circuit/logic/unary
inputs = list(
"A" = IC_PINTYPE_ANY
)
activators = list(
"compare" = IC_PINTYPE_PULSE_IN,
"on compare" = IC_PINTYPE_PULSE_OUT
)
/obj/item/integrated_circuit/logic/unary/do_work()
var/mydata = get_pin_data(IC_INPUT, 1)
set_pin_data(IC_OUTPUT, 1, !!do_check(mydata))
push_data()
activate_pin(2)
/obj/item/integrated_circuit/logic/unary/proc/do_check(A)
return FALSE
/obj/item/integrated_circuit/logic/binary/equals
name = "equal gate"
desc = "This gate compares two values, and outputs the number one if both are the same."
icon_state = "equal"
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
/obj/item/integrated_circuit/logic/binary/equals/do_compare(A, B)
return A == B
/obj/item/integrated_circuit/logic/binary/not_equals
name = "not equal gate"
desc = "This gate compares two values, and outputs the number one if both are different."
icon_state = "not_equal"
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
/obj/item/integrated_circuit/logic/binary/not_equals/do_compare(A, B)
return A != B
/obj/item/integrated_circuit/logic/binary/and
name = "and gate"
desc = "This gate will output 'one' if both inputs evaluate to true."
icon_state = "and"
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
/obj/item/integrated_circuit/logic/binary/and/do_compare(A, B)
return A && B
/obj/item/integrated_circuit/logic/binary/or
name = "or gate"
desc = "This gate will output 'one' if one of the inputs evaluate to true."
icon_state = "or"
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
/obj/item/integrated_circuit/logic/binary/or/do_compare(A, B)
return A || B
/obj/item/integrated_circuit/logic/binary/less_than
name = "less than gate"
desc = "This will output 'one' if the first input is less than the second input."
icon_state = "less_than"
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
/obj/item/integrated_circuit/logic/binary/less_than/do_compare(A, B)
return A < B
/obj/item/integrated_circuit/logic/binary/less_than_or_equal
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"
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
/obj/item/integrated_circuit/logic/binary/less_than_or_equal/do_compare(A, B)
return A <= B
/obj/item/integrated_circuit/logic/binary/greater_than
name = "greater than gate"
desc = "This will output 'one' if the first input is greater than the second input."
icon_state = "greater_than"
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
/obj/item/integrated_circuit/logic/binary/greater_than/do_compare(A, B)
return A > B
/obj/item/integrated_circuit/logic/binary/greater_than_or_equal
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"
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
/obj/item/integrated_circuit/logic/binary/greater_than_or_equal/do_compare(A, B)
return A >= B
/obj/item/integrated_circuit/logic/unary/not
name = "not gate"
desc = "This gate inverts what's fed into it."
icon_state = "not"
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
activators = list("invert" = IC_PINTYPE_PULSE_IN, "on inverted" = IC_PINTYPE_PULSE_OUT)
/obj/item/integrated_circuit/logic/unary/not/do_check(A)
return !A
@@ -0,0 +1,188 @@
/obj/item/integrated_circuit/manipulation
category_text = "Manipulation"
/obj/item/integrated_circuit/manipulation/weapon_firing
name = "weapon firing mechanism"
desc = "This somewhat complicated system allows one to slot in a gun, direct it towards a position, and remotely fire it."
extended_desc = "The firing mechanism can slot in most ranged weapons, ballistic and energy. \
The first and second inputs need to be numbers. They are coordinates for the gun to fire at, relative to the machine itself. \
The 'fire' activator will cause the mechanism to attempt to fire the weapon at the coordinates, if possible. Note that the \
normal limitations to firearms, such as ammunition requirements and firing delays, still hold true if fired by the mechanism."
complexity = 20
w_class = ITEMSIZE_NORMAL
size = 3
inputs = list(
"target X rel" = IC_PINTYPE_NUMBER,
"target Y rel" = IC_PINTYPE_NUMBER
)
outputs = list()
activators = list(
"fire" = IC_PINTYPE_PULSE_IN
)
var/obj/item/weapon/gun/installed_gun
spawn_flags = IC_SPAWN_RESEARCH
origin_tech = list(TECH_ENGINEERING = 3, TECH_DATA = 3, TECH_COMBAT = 4)
power_draw_per_use = 50 // The targeting mechanism uses this. The actual gun uses its own cell for firing if it's an energy weapon.
/obj/item/integrated_circuit/manipulation/weapon_firing/Destroy()
QDEL_NULL(installed_gun)
. = ..()
/obj/item/integrated_circuit/manipulation/weapon_firing/attackby(var/obj/O, var/mob/user)
if(istype(O, /obj/item/weapon/gun))
var/obj/item/weapon/gun/gun = O
if(installed_gun)
user << "<span class='warning'>There's already a weapon installed.</span>"
return
user.drop_from_inventory(gun)
installed_gun = gun
size += gun.w_class
gun.forceMove(src)
user << "<span class='notice'>You slide \the [gun] into the firing mechanism.</span>"
playsound(src.loc, 'sound/items/Crowbar.ogg', 50, 1)
else
..()
/obj/item/integrated_circuit/manipulation/weapon_firing/attack_self(var/mob/user)
if(installed_gun)
installed_gun.forceMove(get_turf(src))
user << "<span class='notice'>You slide \the [installed_gun] out of the firing mechanism.</span>"
size = initial(size)
playsound(loc, 'sound/items/Crowbar.ogg', 50, 1)
installed_gun = null
else
user << "<span class='notice'>There's no weapon to remove from the mechanism.</span>"
/obj/item/integrated_circuit/manipulation/weapon_firing/do_work()
if(!installed_gun)
return
var/target_x = get_pin_data(IC_INPUT, 1)
var/target_y = get_pin_data(IC_INPUT, 2)
if (!isnum(target_x) || !isnum(target_y) || !assembly)
return
target_x = round(target_x)
target_y = round(target_y)
if(target_x == 0 && target_y == 0) // Don't shoot ourselves.
return
var/turf/T = get_turf(assembly)
var/Tx = T.x + target_x
var/Ty = T.y + target_y
if (Tx > world.maxx || Tx < 1 || Ty > world.maxy || Ty < 1)
return // Off the edge of the map.
T = locate(Tx, Ty, T.z)
if(!T)
return
installed_gun.Fire_userless(T)
/obj/item/integrated_circuit/manipulation/locomotion
name = "locomotion circuit"
desc = "This allows a machine to move in a given direction."
icon_state = "locomotion"
extended_desc = "The circuit accepts a 'dir' number as a direction to move towards.<br>\
Pulsing the 'step towards dir' activator pin will cause the machine to move a meter in that direction, assuming it is not \
being held, or anchored in some way. It should be noted that the ability to move is dependant on the type of assembly that this circuit inhabits."
w_class = ITEMSIZE_NORMAL
complexity = 20
// size = 5
inputs = list("direction" = IC_PINTYPE_DIR)
outputs = list()
activators = list("step towards dir" = IC_PINTYPE_PULSE_IN)
spawn_flags = IC_SPAWN_RESEARCH
power_draw_per_use = 100
/obj/item/integrated_circuit/manipulation/locomotion/do_work()
..()
var/turf/T = get_turf(src)
if(T && assembly)
if(assembly.anchored || !assembly.can_move())
return
if(assembly.loc == T) // Check if we're held by someone. If the loc is the floor, we're not held.
var/datum/integrated_io/wanted_dir = inputs[1]
if(isnum(wanted_dir.data))
step(assembly, wanted_dir.data)
/obj/item/integrated_circuit/manipulation/grenade
name = "grenade primer"
desc = "This circuit comes with the ability to attach most types of grenades at prime them at will."
extended_desc = "Time between priming and detonation is limited to between 1 to 12 seconds but is optional. \
If unset, not a number, or a number less than 1 then the grenade's built-in timing will be used. \
Beware: Once primed there is no aborting the process!"
icon_state = "grenade"
complexity = 30
size = 2
inputs = list("detonation time" = IC_PINTYPE_NUMBER)
outputs = list()
activators = list("prime grenade" = IC_PINTYPE_PULSE_IN)
spawn_flags = IC_SPAWN_RESEARCH
origin_tech = list(TECH_ENGINEERING = 3, TECH_DATA = 3, TECH_COMBAT = 4)
var/obj/item/weapon/grenade/attached_grenade
var/pre_attached_grenade_type
/obj/item/integrated_circuit/manipulation/grenade/Initialize()
. = ..()
if(pre_attached_grenade_type)
var/grenade = new pre_attached_grenade_type(src)
attach_grenade(grenade)
/obj/item/integrated_circuit/manipulation/grenade/Destroy()
if(attached_grenade && !attached_grenade.active)
attached_grenade.dropInto(loc)
detach_grenade()
. = ..()
/obj/item/integrated_circuit/manipulation/grenade/attackby(var/obj/item/weapon/grenade/G, var/mob/user)
if(istype(G))
if(attached_grenade)
to_chat(user, "<span class='warning'>There is already a grenade attached!</span>")
else if(user.unEquip(G, force=1))
user.visible_message("<span class='warning'>\The [user] attaches \a [G] to \the [src]!</span>", "<span class='notice'>You attach \the [G] to \the [src].</span>")
attach_grenade(G)
G.forceMove(src)
else
..()
/obj/item/integrated_circuit/manipulation/grenade/attack_self(var/mob/user)
if(attached_grenade)
user.visible_message("<span class='warning'>\The [user] removes \an [attached_grenade] from \the [src]!</span>", "<span class='notice'>You remove \the [attached_grenade] from \the [src].</span>")
user.put_in_any_hand_if_possible(attached_grenade) || attached_grenade.dropInto(loc)
detach_grenade()
else
..()
/obj/item/integrated_circuit/manipulation/grenade/do_work()
if(attached_grenade && !attached_grenade.active)
var/datum/integrated_io/detonation_time = inputs[1]
if(isnum(detonation_time.data) && detonation_time.data > 0)
attached_grenade.det_time = between(1, detonation_time.data, 12) SECONDS
attached_grenade.activate()
var/atom/holder = loc
log_and_message_admins("activated a grenade assembly. Last touches: Assembly: [holder.fingerprintslast] Circuit: [fingerprintslast] Grenade: [attached_grenade.fingerprintslast]")
// These procs do not relocate the grenade, that's the callers responsibility
/obj/item/integrated_circuit/manipulation/grenade/proc/attach_grenade(var/obj/item/weapon/grenade/G)
attached_grenade = G
attached_grenade.OnDestroy(CALLBACK(src, .proc/detach_grenade))
size += G.w_class
desc += " \An [attached_grenade] is attached to it!"
/obj/item/integrated_circuit/manipulation/grenade/proc/detach_grenade()
if(!attached_grenade)
return
attached_grenade.UnregisterOnDestroy(src)
attached_grenade = null
size = initial(size)
desc = initial(desc)
/obj/item/integrated_circuit/manipulation/grenade/frag
pre_attached_grenade_type = /obj/item/weapon/grenade/frag
origin_tech = list(TECH_ENGINEERING = 3, TECH_DATA = 3, TECH_COMBAT = 10)
spawn_flags = null // Used for world initializing, see the #defines above.
@@ -0,0 +1,125 @@
/obj/item/integrated_circuit/memory
complexity = 1
category_text = "Memory"
power_draw_per_use = 1
/obj/item/integrated_circuit/memory/storage
name = "memory chip"
icon_state = "memory"
desc = "This tiny chip can store one piece of data."
inputs = list()
outputs = list()
activators = list(
"set" = IC_PINTYPE_PULSE_IN,
"on set" = IC_PINTYPE_PULSE_OUT
)
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
var/number_of_pins = 1
/obj/item/integrated_circuit/memory/storage/Initialize()
for(var/i = 1 to number_of_pins)
inputs["input [i]"] = IC_PINTYPE_ANY // This is just a string since pins don't get built until ..() is called.
outputs["output [i]"] = IC_PINTYPE_ANY
complexity = number_of_pins
. = ..()
/obj/item/integrated_circuit/memory/storage/examine(mob/user)
..()
var/i
for (i in 1 to outputs.len)
var/datum/integrated_io/O = outputs[i]
var/data = "nothing"
if(isweakref(O.data))
var/datum/d = O.data_as_type(/datum)
if(d)
data = "[d]"
else if(!isnull(O.data))
data = O.data
to_chat(user, "\The [src] has [data] saved to address [i].")
/obj/item/integrated_circuit/memory/storage/do_work()
for(var/i = 1 to inputs.len)
var/data = get_pin_data(IC_INPUT, i)
set_pin_data(IC_OUTPUT, i, data)
activate_pin(2)
/obj/item/integrated_circuit/memory/storage/medium
name = "memory circuit"
desc = "This circuit can store four pieces of data."
icon_state = "memory4"
power_draw_per_use = 2
number_of_pins = 4
/obj/item/integrated_circuit/memory/storage/large
name = "large memory circuit"
desc = "This big circuit can hold eight pieces of data."
icon_state = "memory8"
origin_tech = list(TECH_ENGINEERING = 3, TECH_DATA = 3)
power_draw_per_use = 4
number_of_pins = 8
/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."
icon_state = "memory16"
w_class = ITEMSIZE_NORMAL
spawn_flags = IC_SPAWN_RESEARCH
origin_tech = list(TECH_ENGINEERING = 4, TECH_DATA = 4)
power_draw_per_use = 8
number_of_pins = 16
/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."
icon_state = "memory"
inputs = list()
outputs = list("output pin" = IC_PINTYPE_ANY)
activators = list(
"push data" = IC_PINTYPE_PULSE_IN,
"on push" = IC_PINTYPE_PULSE_OUT
)
var/accepting_refs = 0
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
var/data
/obj/item/integrated_circuit/memory/constant/do_work()
set_pin_data(IC_OUTPUT, 1, data)
activate_pin(2)
/obj/item/integrated_circuit/memory/constant/attack_self(mob/user)
var/datum/integrated_io/O = outputs[1]
var/type_to_use = input("Please choose a type to use.","[src] type setting") as null|anything in list("string","number","ref", "null")
if(!CanInteract(user, physical_state))
return
var/new_data = null
switch(type_to_use)
if("string")
accepting_refs = 0
new_data = sanitize(input("Now type in a string.","[src] string writing") as null|text)
if(istext(new_data) && CanInteract(user, physical_state))
data = new_data
to_chat(user, "<span class='notice'>You set \the [src]'s memory to [O.display_data(data)].</span>")
if("number")
accepting_refs = 0
new_data = input("Now type in a number.","[src] number writing") as null|num
if(isnum(new_data) && CanInteract(user, physical_state))
data = new_data
to_chat(user, "<span class='notice'>You set \the [src]'s memory to [O.display_data(data)].</span>")
if("ref")
accepting_refs = 1
to_chat(user, "<span class='notice'>You turn \the [src]'s ref scanner on. Slide it across \
an object for a ref of that object to save it in memory.</span>")
if("null")
data = null
to_chat(user, "<span class='notice'>You set \the [src]'s memory to absolutely nothing.</span>")
/obj/item/integrated_circuit/memory/constant/afterattack(atom/target, mob/living/user, proximity)
if(accepting_refs && proximity)
var/datum/integrated_io/O = outputs[1]
data = WEAKREF(target)
visible_message("<span class='notice'>[user] slides [src]'s ref scanner over \the [target].</span>")
to_chat(user, "<span class='notice'>You set \the [src]'s memory to a reference to [O.display_data(data)]. The ref scanner is \
now off.</span>")
accepting_refs = 0
@@ -0,0 +1,352 @@
/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."
icon_state = "screen"
inputs = list("displayed data" = IC_PINTYPE_ANY)
outputs = list()
activators = list("load data" = IC_PINTYPE_PULSE_IN)
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
power_draw_per_use = 10
var/stuff_to_display = null
/obj/item/integrated_circuit/output/screen/disconnect_all()
..()
stuff_to_display = null
/obj/item/integrated_circuit/output/screen/any_examine(mob/user)
if (displayed_name)
to_chat(user, "There is a little screen labeled '[displayed_name]', which displays [!isnull(stuff_to_display) ? "'[stuff_to_display]'" : "nothing"].")
else
to_chat(user, "There is an unlabelled little screen, which displays [!isnull(stuff_to_display) ? "'[stuff_to_display]'" : "nothing"].")
/obj/item/integrated_circuit/output/screen/do_work()
var/datum/integrated_io/I = inputs[1]
if(isweakref(I.data))
var/datum/d = I.data_as_type(/datum)
if(d)
stuff_to_display = "[d]"
else
stuff_to_display = I.data
/obj/item/integrated_circuit/output/screen/medium
name = "screen"
desc = "This screen allows for people holding the device to see a piece of data."
icon_state = "screen_medium"
power_draw_per_use = 20
/obj/item/integrated_circuit/output/screen/medium/do_work()
..()
var/list/nearby_things = range(0, get_turf(src))
for(var/mob/M in nearby_things)
var/obj/O = assembly ? assembly : src
to_chat(M, "<span class='notice'>\icon[O] [stuff_to_display]</span>")
/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."
icon_state = "screen_large"
power_draw_per_use = 40
/obj/item/integrated_circuit/output/screen/large/do_work()
..()
var/obj/O = assembly ? loc : assembly
O.visible_message("<span class='notice'>\icon[O] [stuff_to_display]</span>")
/obj/item/integrated_circuit/output/light
name = "light"
desc = "This light can turn on and off on command."
icon_state = "light"
complexity = 4
inputs = list()
outputs = list()
activators = list("toggle light" = IC_PINTYPE_PULSE_IN)
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
var/light_toggled = 0
var/light_brightness = 3
var/light_rgb = "#FFFFFF"
power_draw_idle = 0 // Adjusted based on brightness.
/obj/item/integrated_circuit/output/light/do_work()
light_toggled = !light_toggled
update_lighting()
/obj/item/integrated_circuit/output/light/proc/update_lighting()
if(light_toggled)
if(assembly)
assembly.set_light(l_range = light_brightness, l_power = light_brightness, l_color = light_rgb)
else
if(assembly)
assembly.set_light(0)
power_draw_idle = light_toggled ? light_brightness * 2 : 0
/obj/item/integrated_circuit/output/light/advanced/update_lighting()
var/new_color = get_pin_data(IC_INPUT, 1)
var/brightness = get_pin_data(IC_INPUT, 2)
if(new_color && isnum(brightness))
brightness = Clamp(brightness, 0, 6)
light_rgb = new_color
light_brightness = brightness
..()
/obj/item/integrated_circuit/output/light/power_fail() // Turns off the flashlight if there's no power left.
light_toggled = FALSE
update_lighting()
/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."
icon_state = "light_adv"
complexity = 8
inputs = list(
"color" = IC_PINTYPE_COLOR,
"brightness" = IC_PINTYPE_NUMBER
)
outputs = list()
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
origin_tech = list(TECH_ENGINEERING = 3, TECH_DATA = 3)
/obj/item/integrated_circuit/output/light/advanced/on_data_written()
update_lighting()
/obj/item/integrated_circuit/output/sound
name = "speaker circuit"
desc = "A miniature speaker is attached to this component."
icon_state = "speaker"
complexity = 8
cooldown_per_use = 4 SECONDS
inputs = list(
"sound ID" = IC_PINTYPE_STRING,
"volume" = IC_PINTYPE_NUMBER,
"frequency" = IC_PINTYPE_BOOLEAN
)
outputs = list()
activators = list("play sound" = IC_PINTYPE_PULSE_IN)
power_draw_per_use = 20
var/list/sounds = list()
/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."
icon_state = "speaker"
complexity = 12
cooldown_per_use = 4 SECONDS
inputs = list("text" = IC_PINTYPE_STRING)
outputs = list()
activators = list("to speech" = IC_PINTYPE_PULSE_IN)
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
power_draw_per_use = 60
/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("\icon[O] \The [O.name] states, \"[text]\"")
/obj/item/integrated_circuit/output/sound/Initialize()
. = ..()
extended_desc = list()
extended_desc += "The first input pin determines which sound is used. The choices are; "
extended_desc += jointext(sounds, ", ")
extended_desc += ". The second pin determines the volume of sound that is played"
extended_desc += ", and the third determines if the frequency of the sound will vary with each activation."
extended_desc = jointext(extended_desc, null)
/obj/item/integrated_circuit/output/sound/do_work()
var/ID = get_pin_data(IC_INPUT, 1)
var/vol = get_pin_data(IC_INPUT, 2)
var/freq = get_pin_data(IC_INPUT, 3)
if(!isnull(ID) && !isnull(vol))
var/selected_sound = sounds[ID]
if(!selected_sound)
return
vol = between(0, vol, 100)
playsound(get_turf(src), selected_sound, vol, freq, -1)
/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 \
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(
"beep" = 'sound/machines/twobeep.ogg',
"chime" = 'sound/machines/chime.ogg',
"buzz sigh" = 'sound/machines/buzz-sigh.ogg',
"buzz twice" = 'sound/machines/buzz-two.ogg',
"ping" = 'sound/machines/ping.ogg',
"synth yes" = 'sound/machines/synth_yes.ogg',
"synth no" = 'sound/machines/synth_no.ogg',
"warning buzz" = 'sound/machines/warning-buzzer.ogg'
)
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
/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."
sounds = list(
"creep" = 'sound/voice/bcreep.ogg',
"criminal" = 'sound/voice/bcriminal.ogg',
"freeze" = 'sound/voice/bfreeze.ogg',
"god" = 'sound/voice/bgod.ogg',
"i am the law" = 'sound/voice/biamthelaw.ogg',
"insult" = 'sound/voice/binsult.ogg',
"radio" = 'sound/voice/bradio.ogg',
"secure day" = 'sound/voice/bsecureday.ogg'
)
spawn_flags = IC_SPAWN_RESEARCH
origin_tech = list(TECH_ENGINEERING = 2, TECH_DATA = 2, TECH_ILLEGAL = 1)
/obj/item/integrated_circuit/output/sound/medbot
name = "medbot sound circuit"
desc = "A miniature speaker is attached to this component, used to annoy patients while they get pricked by a medbot."
sounds = list(
"surgeon" = 'sound/voice/medbot/msurgeon.ogg',
"radar" = 'sound/voice/medbot/mradar.ogg',
"feel better" = 'sound/voice/medbot/mfeelbetter.ogg',
"patched up" = 'sound/voice/medbot/mpatchedup.ogg',
"injured" = 'sound/voice/medbot/minjured.ogg',
"insult" = 'sound/voice/medbot/minsult.ogg',
"coming" = 'sound/voice/medbot/mcoming.ogg',
"help" = 'sound/voice/medbot/mhelp.ogg',
"live" = 'sound/voice/medbot/mlive.ogg',
"lost" = 'sound/voice/medbot/mlost.ogg',
"flies" = 'sound/voice/medbot/mflies.ogg',
"catch" = 'sound/voice/medbot/mcatch.ogg',
"delicious" = 'sound/voice/medbot/mdelicious.ogg',
"apple" = 'sound/voice/medbot/mapple.ogg',
"no" = 'sound/voice/medbot/mno.ogg'
)
spawn_flags = IC_SPAWN_RESEARCH
origin_tech = list(TECH_ENGINEERING = 2, TECH_DATA = 2, TECH_BIO = 1)
/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."
icon_state = "video_camera"
w_class = ITEMSIZE_SMALL
complexity = 10
inputs = list(
"camera name" = IC_PINTYPE_STRING,
"camera active" = IC_PINTYPE_BOOLEAN
)
inputs_default = list("1" = "video camera circuit")
outputs = list()
activators = list()
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
power_draw_idle = 5 // Raises to 80 when on.
var/obj/machinery/camera/network/research/camera
/obj/item/integrated_circuit/output/video_camera/Initialize()
. = ..()
camera = new(src)
on_data_written()
/obj/item/integrated_circuit/output/video_camera/Destroy()
QDEL_NULL(camera)
return ..()
/obj/item/integrated_circuit/output/video_camera/proc/set_camera_status(var/status)
if(camera)
camera.set_status(status)
power_draw_idle = camera.status ? 80 : 5
if(camera.status) // Ensure that there's actually power.
if(!draw_idle_power())
power_fail()
/obj/item/integrated_circuit/output/video_camera/on_data_written()
if(camera)
var/cam_name = get_pin_data(IC_INPUT, 1)
var/cam_active = get_pin_data(IC_INPUT, 2)
if(!isnull(cam_name))
camera.c_tag = cam_name
set_camera_status(cam_active)
/obj/item/integrated_circuit/output/video_camera/power_fail()
if(camera)
set_camera_status(0)
set_pin_data(IC_INPUT, 2, FALSE)
/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."
complexity = 0.1
icon_state = "led"
inputs = list("lit" = IC_PINTYPE_BOOLEAN)
outputs = list()
activators = list()
power_draw_idle = 0 // Raises to 1 when lit.
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
var/led_color
var/color_name
/obj/item/integrated_circuit/output/led/on_data_written()
power_draw_idle = get_pin_data(IC_INPUT, 1) ? 1 : 0
/obj/item/integrated_circuit/output/led/power_fail()
set_pin_data(IC_INPUT, 1, FALSE)
/obj/item/integrated_circuit/output/led/any_examine(mob/user)
var/text_output = list()
var/initial_name = initial(name)
// Doing all this work just to have a color-blind friendly output.
text_output += "There is "
if(name == initial_name)
text_output += "\an [name]"
else
text_output += "\an ["\improper[initial_name]"] labeled '[name]'"
text_output += " which is currently [get_pin_data(IC_INPUT, 1) ? "lit <font color=[led_color]>[color_name]</font>" : "unlit."]"
to_chat(user,jointext(text_output,null))
/obj/item/integrated_circuit/output/led/red
name = "red LED"
led_color = COLOR_RED
color_name = "red"
/obj/item/integrated_circuit/output/led/orange
name = "orange LED"
led_color = COLOR_ORANGE
color_name = "orange"
/obj/item/integrated_circuit/output/led/yellow
name = "yellow LED"
led_color = COLOR_YELLOW
color_name = "yellow"
/obj/item/integrated_circuit/output/led/green
name = "green LED"
led_color = COLOR_GREEN
color_name = "green"
/obj/item/integrated_circuit/output/led/blue
name = "blue LED"
led_color = COLOR_BLUE
color_name = "blue"
/obj/item/integrated_circuit/output/led/purple
name = "purple LED"
led_color = COLOR_PURPLE
color_name = "purple"
/obj/item/integrated_circuit/output/led/cyan
name = "cyan LED"
led_color = COLOR_CYAN
color_name = "cyan"
/obj/item/integrated_circuit/output/led/white
name = "white LED"
led_color = COLOR_WHITE
color_name = "white"
/obj/item/integrated_circuit/output/led/pink
name = "pink LED"
led_color = COLOR_PINK
color_name = "pink"
@@ -0,0 +1,88 @@
/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."
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 \
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, \
some power is lost due to ineffiency."
w_class = ITEMSIZE_SMALL
complexity = 16
inputs = list("target" = IC_PINTYPE_REF)
outputs = list(
"target cell charge" = IC_PINTYPE_NUMBER,
"target cell max charge" = IC_PINTYPE_NUMBER,
"target cell percentage" = IC_PINTYPE_NUMBER
)
activators = list("transmit" = IC_PINTYPE_PULSE_IN, "on transmit" = IC_PINTYPE_PULSE_OUT)
spawn_flags = IC_SPAWN_RESEARCH
origin_tech = list(TECH_ENGINEERING = 4, TECH_DATA = 4, TECH_POWER = 4, TECH_MAGNET = 3)
power_draw_per_use = 500 // Inefficency has to come from somewhere.
var/amount_to_move = 5000
/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."
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, \
some power is lost due to ineffiency."
w_class = ITEMSIZE_LARGE
complexity = 32
origin_tech = list(TECH_ENGINEERING = 4, TECH_DATA = 4, TECH_POWER = 6, TECH_MAGNET = 5)
power_draw_per_use = 2000
amount_to_move = 20000
/obj/item/integrated_circuit/power/transmitter/do_work()
var/atom/movable/AM = get_pin_data_as_type(IC_INPUT, 1, /atom/movable)
if(AM && assembly)
var/obj/item/weapon/cell/cell = null
if(istype(AM, /obj/item/weapon/cell)) // Is this already a cell?
cell = AM
else // If not, maybe there's a cell inside it?
for(var/obj/item/weapon/cell/C in AM.contents)
if(C) // Find one cell to charge.
cell = C
break
if(cell)
var/transfer_amount = amount_to_move
var/turf/A = get_turf(src)
var/turf/B = get_turf(AM)
if(A.Adjacent(B))
if(AM.loc != assembly)
transfer_amount *= 0.8 // Losses due to distance.
if(cell.fully_charged())
set_pin_data(IC_OUTPUT, 1, cell.charge)
set_pin_data(IC_OUTPUT, 2, cell.maxcharge)
set_pin_data(IC_OUTPUT, 3, cell.percent())
push_data()
return FALSE
if(transfer_amount && assembly.draw_power(amount_to_move)) // CELLRATE is already handled in draw_power()
cell.give(transfer_amount * CELLRATE)
AM.update_icon()
set_pin_data(IC_OUTPUT, 1, cell.charge)
set_pin_data(IC_OUTPUT, 2, cell.maxcharge)
set_pin_data(IC_OUTPUT, 3, cell.percent())
push_data()
activate_pin(2)
return TRUE
set_pin_data(IC_OUTPUT, 1, null)
set_pin_data(IC_OUTPUT, 2, null)
set_pin_data(IC_OUTPUT, 3, null)
push_data()
return FALSE
/obj/item/integrated_circuit/power/transmitter/large/do_work()
if(..()) // If the above code succeeds, do this below.
if(prob(2))
spark(src, 3)
visible_message("<span class='warning'>\The [assembly] makes some sparks!</span>")
@@ -0,0 +1,160 @@
/obj/item/integrated_circuit/reagent
category_text = "Reagent"
var/volume = 0
origin_tech = list(TECH_ENGINEERING = 2, TECH_DATA = 2, TECH_BIO = 2)
/obj/item/integrated_circuit/reagent/Initialize()
. = ..()
if(volume)
create_reagents(volume)
/obj/item/integrated_circuit/reagent/smoke
name = "smoke generator"
desc = "Unlike most electronics, creating smoke is completely intentional."
icon_state = "smoke"
extended_desc = "This smoke generator creates clouds of smoke on command. It can also hold liquids inside, which will go \
into the smoke clouds when activated. The reagents are consumed when smoke is made."
flags = OPENCONTAINER
complexity = 20
cooldown_per_use = 30 SECONDS
inputs = list()
outputs = list()
activators = list("create smoke" = IC_PINTYPE_PULSE_IN)
spawn_flags = IC_SPAWN_RESEARCH
origin_tech = list(TECH_ENGINEERING = 3, TECH_DATA = 3, TECH_BIO = 3)
volume = 100
power_draw_per_use = 20
/obj/item/integrated_circuit/reagent/smoke/do_work()
playsound(src.loc, 'sound/effects/smoke.ogg', 50, 1, -3)
var/datum/effect/effect/system/smoke_spread/chem/smoke_system = new()
smoke_system.set_up(reagents, 10, 0, get_turf(src))
spawn(0)
for(var/i = 1 to 8)
smoke_system.start()
reagents.clear_reagents()
/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."
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."
flags = OPENCONTAINER
complexity = 20
cooldown_per_use = 6 SECONDS
inputs = list("target" = IC_PINTYPE_REF, "injection amount" = IC_PINTYPE_NUMBER)
inputs_default = list("2" = 5)
outputs = list()
activators = list("inject" = IC_PINTYPE_PULSE_IN)
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
volume = 30
power_draw_per_use = 15
/obj/item/integrated_circuit/reagent/injector/proc/inject_amount()
var/amount = get_pin_data(IC_INPUT, 2)
if(isnum(amount))
return Clamp(amount, 0, 30)
/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
return
if(!reagents.total_volume) // Empty
return
if(AM.can_be_injected_by(src))
if(isliving(AM))
var/mob/living/L = AM
var/turf/T = get_turf(AM)
T.visible_message("<span class='warning'>[src] is trying to inject [L]!</span>")
sleep(3 SECONDS)
if(!L.can_be_injected_by(src))
return
var/contained = reagents.get_reagents()
var/trans = reagents.trans_to_mob(L, inject_amount(), CHEM_BLOOD)
message_admins("[src] injected \the [L] with [trans]u of [contained].")
to_chat(AM, "<span class='notice'>You feel a tiny prick!</span>")
visible_message("<span class='warning'>[src] injects [L]!</span>")
else
reagents.trans_to(AM, inject_amount())
/obj/item/integrated_circuit/reagent/pump
name = "reagent pump"
desc = "Moves liquids safely inside a machine, or even nearby it."
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 \
outside the machine if it is next to the machine. Note that this cannot be used on entities."
flags = OPENCONTAINER
complexity = 8
inputs = list(
"source" = IC_PINTYPE_REF,
"target" = IC_PINTYPE_REF,
"injection amount" = IC_PINTYPE_NUMBER
)
inputs_default = list("3" = 5)
outputs = list()
activators = list(
"transfer reagents" = IC_PINTYPE_PULSE_IN,
"on transfer" = IC_PINTYPE_PULSE_OUT
)
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
origin_tech = list(TECH_ENGINEERING = 2, TECH_DATA = 2, TECH_BIO = 2)
var/transfer_amount = 10
power_draw_per_use = 10
/obj/item/integrated_circuit/reagent/pump/on_data_written()
var/new_amount = get_pin_data(IC_INPUT, 3)
if(!isnull(new_amount))
new_amount = Clamp(new_amount, 0, 50)
transfer_amount = new_amount
/obj/item/integrated_circuit/reagent/pump/do_work()
var/atom/movable/source = get_pin_data_as_type(IC_INPUT, 1, /atom/movable)
var/atom/movable/target = get_pin_data_as_type(IC_INPUT, 2, /atom/movable)
if(!istype(source) || !istype(target)) //Invalid input
return
var/turf/T = get_turf(src)
if(source.Adjacent(T) && target.Adjacent(T))
if(!source.reagents || !target.reagents)
return
if(ismob(source) || ismob(target))
return
if(!source.is_open_container() || !target.is_open_container())
return
if(!target.reagents.get_free_space())
return
source.reagents.trans_to(target, transfer_amount)
activate_pin(2)
/obj/item/integrated_circuit/reagent/storage
name = "reagent storage"
desc = "Stores liquid inside, and away from electrical components. Can store up to 60u."
icon_state = "reagent_storage"
extended_desc = "This is effectively an internal beaker."
flags = OPENCONTAINER
complexity = 4
inputs = list()
outputs = list("volume used" = IC_PINTYPE_NUMBER)
activators = list()
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
origin_tech = list(TECH_ENGINEERING = 2, TECH_DATA = 2, TECH_BIO = 2)
volume = 60
/obj/item/integrated_circuit/reagent/storage/on_reagent_change()
set_pin_data(IC_OUTPUT, 1, reagents.total_volume)
push_data()
/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."
icon_state = "reagent_storage_cryo"
extended_desc = "This is effectively an internal cryo beaker."
flags = OPENCONTAINER | NOREACT
complexity = 8
spawn_flags = IC_SPAWN_RESEARCH
origin_tech = list(TECH_MATERIALS = 3, TECH_ENGINEERING = 2, TECH_DATA = 2, TECH_BIO = 2)
@@ -0,0 +1,33 @@
/obj/item/integrated_circuit/smart
category_text = "Smart"
/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 \
cannot see the target, it will not be able to calculate the correct direction."
icon_state = "numberpad"
complexity = 25
inputs = list("target" = IC_PINTYPE_REF)
outputs = list("dir" = IC_PINTYPE_DIR)
activators = list("calculate dir" = IC_PINTYPE_PULSE_IN, "on calculated" = IC_PINTYPE_PULSE_OUT)
spawn_flags = IC_SPAWN_RESEARCH
origin_tech = list(TECH_ENGINEERING = 4, TECH_DATA = 5)
power_draw_per_use = 40
/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))
return
var/atom/A = I.data.resolve()
if(!A)
return
if(!(A in view(get_turf(src))))
return // Can't see the target.
var/desired_dir = get_dir(get_turf(src), A)
set_pin_data(IC_OUTPUT, 1, desired_dir)
push_data()
activate_pin(2)
@@ -0,0 +1,147 @@
/obj/item/integrated_circuit/time
name = "time circuit"
desc = "Now you can build your own clock!"
complexity = 2
inputs = list()
outputs = list()
category_text = "Time"
/obj/item/integrated_circuit/time/delay
name = "two-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 two seconds."
icon_state = "delay-20"
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 = 2
/obj/item/integrated_circuit/time/delay/do_work()
addtimer(CALLBACK(src, /obj/item/integrated_circuit/.proc/activate_pin, 2), delay)
/obj/item/integrated_circuit/time/delay/five_sec
name = "five-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 five seconds."
icon_state = "delay-50"
delay = 5 SECONDS
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
/obj/item/integrated_circuit/time/delay/one_sec
name = "one-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 one second."
icon_state = "delay-10"
delay = 1 SECOND
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
/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"
delay = 5
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
/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"
delay = 1
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
/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"
inputs = list("delay time" = IC_PINTYPE_NUMBER)
spawn_flags = IC_SPAWN_RESEARCH
/obj/item/integrated_circuit/time/delay/custom/do_work()
var/delay_input = get_pin_data(IC_INPUT, 1)
if(delay_input && isnum(delay_input) )
var/new_delay = between(1, delay_input, 1 HOUR)
delay = new_delay
..()
/obj/item/integrated_circuit/time/ticker
name = "ticker circuit"
desc = "This circuit sends an automatic pulse every four seconds."
icon_state = "tick-m"
complexity = 8
var/ticks_to_pulse = 4
var/ticks_completed = 0
var/is_running = FALSE
inputs = list("enable ticking" = IC_PINTYPE_BOOLEAN)
activators = list("outgoing pulse" = IC_PINTYPE_PULSE_OUT)
spawn_flags = IC_SPAWN_RESEARCH
power_draw_per_use = 4
/obj/item/integrated_circuit/time/ticker/Destroy()
STOP_PROCESSING(SSelectronics, src)
. = ..()
/obj/item/integrated_circuit/time/ticker/on_data_written()
var/do_tick = get_pin_data(IC_INPUT, 1)
if(do_tick && !is_running)
is_running = TRUE
START_PROCESSING(SSelectronics, src)
else if(is_running)
is_running = FALSE
STOP_PROCESSING(SSelectronics, src)
ticks_completed = 0
/obj/item/integrated_circuit/time/ticker/process()
var/process_ticks = SSelectronics.wait
ticks_completed += process_ticks
if(ticks_completed >= ticks_to_pulse)
if(ticks_to_pulse >= process_ticks)
ticks_completed -= ticks_to_pulse
else
ticks_completed = 0
activate_pin(1)
/obj/item/integrated_circuit/time/ticker/fast
name = "fast ticker"
desc = "This advanced circuit sends an automatic pulse every two seconds."
icon_state = "tick-f"
complexity = 12
ticks_to_pulse = 2
spawn_flags = IC_SPAWN_RESEARCH
power_draw_per_use = 8
/obj/item/integrated_circuit/time/ticker/slow
name = "slow ticker"
desc = "This simple circuit sends an automatic pulse every six seconds."
icon_state = "tick-s"
complexity = 4
ticks_to_pulse = 6
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
power_draw_per_use = 2
/obj/item/integrated_circuit/time/clock
name = "integrated clock"
desc = "Tells you what the local time is, specific to your station, planet, or facility."
icon_state = "clock"
inputs = list()
outputs = list(
"time" = IC_PINTYPE_STRING,
"hours" = IC_PINTYPE_NUMBER,
"minutes" = IC_PINTYPE_NUMBER,
"seconds" = IC_PINTYPE_NUMBER
)
activators = list("get time" = IC_PINTYPE_PULSE_IN, "on time got" = IC_PINTYPE_PULSE_OUT)
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
power_draw_per_use = 4
/obj/item/integrated_circuit/time/clock/do_work()
set_pin_data(IC_OUTPUT, 1, time2text(station_time_in_ticks, "hh:mm:ss") )
set_pin_data(IC_OUTPUT, 2, text2num(time2text(station_time_in_ticks, "hh") ) )
set_pin_data(IC_OUTPUT, 3, text2num(time2text(station_time_in_ticks, "mm") ) )
set_pin_data(IC_OUTPUT, 4, text2num(time2text(station_time_in_ticks, "ss") ) )
push_data()
activate_pin(2)
@@ -0,0 +1,143 @@
//These circuits do not-so-simple math.
/obj/item/integrated_circuit/trig
complexity = 1
inputs = list(
"A" = IC_PINTYPE_NUMBER,
"B" = IC_PINTYPE_NUMBER,
"C" = IC_PINTYPE_NUMBER,
"D" = IC_PINTYPE_NUMBER,
"E" = IC_PINTYPE_NUMBER,
"F" = IC_PINTYPE_NUMBER,
"G" = IC_PINTYPE_NUMBER,
"H" = IC_PINTYPE_NUMBER
)
outputs = list("result" = IC_PINTYPE_NUMBER)
activators = list(
"compute" = IC_PINTYPE_PULSE_IN,
"on computed" = IC_PINTYPE_PULSE_OUT
)
category_text = "Trig"
extended_desc = "Input and output are in degrees."
power_draw_per_use = 1 // Still cheap math.
// Sine //
/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."
icon_state = "sine"
inputs = list("A" = IC_PINTYPE_NUMBER)
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
/obj/item/integrated_circuit/trig/sine/do_work()
pull_data()
var/result = null
var/A = get_pin_data(IC_INPUT, 1)
if(!isnull(A))
result = sin(A)
set_pin_data(IC_OUTPUT, 1, result)
push_data()
activate_pin(2)
// Cosine //
/obj/item/integrated_circuit/trig/cosine
name = "cos circuit"
desc = "Outputs the cosine of A."
icon_state = "cosine"
inputs = list("A" = IC_PINTYPE_NUMBER)
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
/obj/item/integrated_circuit/trig/cosine/do_work()
pull_data()
var/result = null
var/A = get_pin_data(IC_INPUT, 1)
if(!isnull(A))
result = cos(A)
set_pin_data(IC_OUTPUT, 1, result)
push_data()
activate_pin(2)
// Tangent //
/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."
icon_state = "tangent"
inputs = list("A" = IC_PINTYPE_NUMBER)
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
/obj/item/integrated_circuit/trig/tangent/do_work()
pull_data()
var/result = null
var/A = get_pin_data(IC_INPUT, 1)
if(!isnull(A))
result = Tan(A)
set_pin_data(IC_OUTPUT, 1, result)
push_data()
activate_pin(2)
// Cosecant //
/obj/item/integrated_circuit/trig/cosecant
name = "csc circuit"
desc = "Outputs the cosecant of A."
icon_state = "cosecant"
inputs = list("A" = IC_PINTYPE_NUMBER)
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
/obj/item/integrated_circuit/trig/cosecant/do_work()
pull_data()
var/result = null
var/A = get_pin_data(IC_INPUT, 1)
if(!isnull(A))
result = Csc(A)
set_pin_data(IC_OUTPUT, 1, result)
push_data()
activate_pin(2)
// Secant //
/obj/item/integrated_circuit/trig/secant
name = "sec circuit"
desc = "Outputs the secant of A. Has nothing to do with the security department."
icon_state = "secant"
inputs = list("A" = IC_PINTYPE_NUMBER)
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
/obj/item/integrated_circuit/trig/secant/do_work()
pull_data()
var/result = null
var/A = get_pin_data(IC_INPUT, 1)
if(!isnull(A))
result = Sec(A)
set_pin_data(IC_OUTPUT, 1, result)
push_data()
activate_pin(2)
// Cotangent //
/obj/item/integrated_circuit/trig/cotangent
name = "cot circuit"
desc = "Outputs the cotangent of A."
icon_state = "cotangent"
inputs = list("A" = IC_PINTYPE_NUMBER)
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
/obj/item/integrated_circuit/trig/cotangent/do_work()
pull_data()
var/result = null
var/A = get_pin_data(IC_INPUT, 1)
if(!isnull(A))
result = Cot(A)
set_pin_data(IC_OUTPUT, 1, result)
push_data()
activate_pin(2)
@@ -0,0 +1,36 @@
#undef IC_INPUT
#undef IC_OUTPUT
#undef IC_ACTIVATOR
#undef DATA_CHANNEL
#undef PULSE_CHANNEL
#undef IC_SPAWN_DEFAULT
//#undef IC_SPAWN_RESEARCH // Research designs depend on this unfortunately.
#undef IC_FORMAT_ANY
#undef IC_FORMAT_STRING
#undef IC_FORMAT_CHAR
#undef IC_FORMAT_COLOR
#undef IC_FORMAT_NUMBER
#undef IC_FORMAT_DIR
#undef IC_FORMAT_BOOLEAN
#undef IC_FORMAT_REF
#undef IC_FORMAT_LIST
#undef IC_FORMAT_PULSE
#undef IC_PINTYPE_ANY
#undef IC_PINTYPE_STRING
#undef IC_PINTYPE_CHAR
#undef IC_PINTYPE_COLOR
#undef IC_PINTYPE_NUMBER
#undef IC_PINTYPE_DIR
#undef IC_PINTYPE_BOOLEAN
#undef IC_PINTYPE_REF
#undef IC_PINTYPE_LIST
#undef IC_PINTYPE_PULSE_IN
#undef IC_PINTYPE_PULSE_OUT
#undef IC_MAX_LIST_LENGTH
+53
View File
@@ -201,6 +201,59 @@
user.setMoveCooldown(move_delay)
next_fire_time = world.time + fire_delay
// Similar to the above proc, but does not require a user, which is ideal for things like turrets.
/obj/item/weapon/gun/proc/Fire_userless(atom/target)
if(!target)
return
if(world.time < next_fire_time)
return
var/shoot_time = (burst - 1)* burst_delay
next_fire_time = world.time + shoot_time
var/turf/targloc = get_turf(target) //cache this in case target gets deleted during shooting, e.g. if it was a securitron that got destroyed.
for(var/i in 1 to burst)
var/obj/projectile = consume_next_projectile()
if(!projectile)
handle_click_empty()
break
if(istype(projectile, /obj/item/projectile))
var/obj/item/projectile/P = projectile
var/acc = burst_accuracy[min(i, burst_accuracy.len)]
var/disp = dispersion[min(i, dispersion.len)]
P.accuracy = accuracy + acc
P.dispersion = disp
P.shot_from = src.name
P.silenced = silenced
P.launch(target)
if(silenced)
playsound(src, fire_sound, 10, 1)
else
playsound(src, fire_sound, 50, 1)
if (muzzle_flash)
set_light(muzzle_flash)
addtimer(CALLBACK(src, /atom/.proc/set_light, 0), 2, TIMER_UNIQUE | TIMER_OVERRIDE)
update_icon()
if(i < burst)
sleep(burst_delay)
if(!(target && target.loc))
target = targloc
//update timing
next_fire_time = world.time + fire_delay
accuracy = initial(accuracy) //Reset the gun's accuracy
//obtains the next projectile to fire
/obj/item/weapon/gun/proc/consume_next_projectile()
return null
@@ -0,0 +1,14 @@
/atom/movable/proc/can_be_injected_by(var/atom/injector)
if(!Adjacent(get_turf(injector)))
return FALSE
if(!reagents)
return FALSE
if(!reagents.get_free_space())
return FALSE
return TRUE
/obj/can_be_injected_by(var/atom/injector)
return is_open_container() && ..()
/mob/living/can_be_injected_by(var/atom/injector)
return ..() && (can_inject(null, 0, "chest") || can_inject(null, 0, "groin"))
+89
View File
@@ -345,3 +345,92 @@ other types of metals and chemistry for reagents).
id = "cart_captain"
build_path = /obj/item/weapon/cartridge/captain
sort_string = "VBAAO"
// Integrated Electronics stuff.
/datum/design/item/wirer
name = "Custom wirer tool"
id = "wirer"
req_tech = list(TECH_MATERIAL = 2, TECH_ENGINEERING = 2)
materials = list(DEFAULT_WALL_MATERIAL = 5000, "glass" = 2500)
build_path = /obj/item/device/integrated_electronics/wirer
sort_string = "VBVAA"
/datum/design/item/debugger
name = "Custom circuit debugger tool"
id = "debugger"
req_tech = list(TECH_MATERIAL = 2, TECH_ENGINEERING = 2)
materials = list(DEFAULT_WALL_MATERIAL = 5000, "glass" = 2500)
build_path = /obj/item/device/integrated_electronics/debugger
sort_string = "VBVAB"
/datum/design/item/custom_circuit_assembly
name = "Small custom assembly"
desc = "A customizable assembly for simple, small devices."
id = "assembly-small"
req_tech = list(TECH_MATERIAL = 3, TECH_ENGINEERING = 2, TECH_POWER = 2)
materials = list(DEFAULT_WALL_MATERIAL = 10000)
build_path = /obj/item/device/electronic_assembly
sort_string = "VCAAA"
/datum/design/item/custom_circuit_assembly/medium
name = "Medium custom assembly"
desc = "A customizable assembly suited for more ambitious mechanisms."
id = "assembly-medium"
req_tech = list(TECH_MATERIAL = 4, TECH_ENGINEERING = 3, TECH_POWER = 3)
materials = list(DEFAULT_WALL_MATERIAL = 20000)
build_path = /obj/item/device/electronic_assembly/medium
sort_string = "VCAAB"
/datum/design/item/custom_circuit_assembly/drone
name = "Drone custom assembly"
desc = "A customizable assembly optimized for autonomous devices."
id = "assembly-drone"
req_tech = list(TECH_MATERIAL = 4, TECH_ENGINEERING = 4, TECH_POWER = 4)
materials = list(DEFAULT_WALL_MATERIAL = 30000)
build_path = /obj/item/device/electronic_assembly/drone
sort_string = "VCAAC"
/datum/design/item/custom_circuit_assembly/large
name = "Large custom assembly"
desc = "A customizable assembly for large machines."
id = "assembly-large"
req_tech = list(TECH_MATERIAL = 5, TECH_ENGINEERING = 4, TECH_POWER = 4)
materials = list(DEFAULT_WALL_MATERIAL = 40000)
build_path = /obj/item/device/electronic_assembly/large
sort_string = "VCAAD"
/datum/design/item/custom_circuit_assembly/implant
name = "Implant custom assembly"
desc = "An customizable assembly for very small devices, implanted into living entities."
id = "assembly-implant"
req_tech = list(TECH_MATERIAL = 5, TECH_ENGINEERING = 4, TECH_POWER = 3, TECH_BIO = 5)
materials = list(DEFAULT_WALL_MATERIAL = 2000)
build_path = /obj/item/weapon/implant/integrated_circuit
sort_string = "VCAAE"
/datum/design/item/custom_circuit_assembly/device
name = "Device custom assembly"
desc = "An customizable assembly designed to interface with other devices."
id = "assembly-device"
req_tech = list(TECH_MATERIAL = 2, TECH_ENGINEERING = 2, TECH_POWER = 2)
materials = list(DEFAULT_WALL_MATERIAL = 5000)
build_path = /obj/item/device/assembly/electronic_assembly
sort_string = "VCAAF"
/datum/design/item/custom_circuit_printer
name = "Portable integrated circuit printer"
desc = "A portable(ish) printer for modular machines."
id = "ic_printer"
req_tech = list(TECH_MATERIAL = 3, TECH_ENGINEERING = 4, TECH_DATA = 5)
materials = list(DEFAULT_WALL_MATERIAL = 10000)
build_path = /obj/item/device/integrated_circuit_printer
sort_string = "VCAAG"
/datum/design/item/custom_circuit_printer_upgrade
name = "Integrated circuit printer upgrade - advanced designs"
desc = "Allows the integrated circuit printer to create advanced circuits"
id = "ic_printer_upgrade_adv"
req_tech = list(TECH_ENGINEERING = 3, TECH_DATA = 4)
materials = list(DEFAULT_WALL_MATERIAL = 2000)
build_path = /obj/item/weapon/disk/integrated_circuit/upgrade/advanced
sort_string = "VCAAH"
+6
View File
@@ -0,0 +1,6 @@
author: Lohikar
delete-after: True
changes:
- rscadd: "NT is proud to announce general availability of modular electronics kits for Research and Engineering departments galaxy-wide, batteries not not included. (Ported from Polaris)"
- tweak: "Implants now actually bit back in the implanter that they were removed from."
- tweak: "Round duration is now actually the duration of the round, instead of time passed since last server reboot."
Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

+12 -1
View File
@@ -9518,6 +9518,8 @@
/obj/machinery/atmospherics/unary/vent_pump/on{
dir = 4
},
/obj/item/weapon/storage/bag/circuits/basic,
/obj/structure/table/reinforced,
/turf/simulated/floor/plating,
/area/engineering/storage)
"asP" = (
@@ -25432,6 +25434,8 @@
/obj/structure/closet/secure_closet/engineering_chief,
/obj/item/weapon/tank/emergency_oxygen/engi,
/obj/item/device/gps/engineering,
/obj/item/device/integrated_electronics/debugger,
/obj/item/device/integrated_electronics/wirer,
/turf/simulated/floor/carpet,
/area/crew_quarters/heads/chief)
"aSX" = (
@@ -62897,6 +62901,13 @@
/obj/machinery/light/small,
/turf/simulated/floor/tiled/dark,
/area/turbolift/cargo_station)
"cgm" = (
/obj/structure/table/reinforced,
/obj/item/weapon/storage/bag/circuits/basic,
/obj/item/device/integrated_electronics/debugger,
/obj/item/device/integrated_electronics/wirer,
/turf/simulated/floor/tiled,
/area/assembly/robotics)
(1,1,1) = {"
aaa
@@ -88477,7 +88488,7 @@ bjw
bkJ
bin
bnx
boI
cgm
aZK
brj
bsC
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.