Merge pull request #2957 from Neerti/1/19/2017_more_circuits

Electrical Revolution Circuit DLC
This commit is contained in:
Anewbe
2017-01-26 21:46:44 -06:00
committed by GitHub
29 changed files with 1478 additions and 535 deletions
+16 -367
View File
@@ -8,6 +8,13 @@
#define IC_SPAWN_DEFAULT 1 // If the circuit comes in the default circuit box.
#define IC_SPAWN_RESEARCH 2 // If the circuit design will be autogenerated for RnD.
#define IC_FORMAT_STRING "\<STRING\>"
#define IC_FORMAT_NUMBER "\<NUM\>"
#define IC_FORMAT_REF "\<REF\>"
#define IC_FORMAT_LIST "\<LIST\>"
#define IC_FORMAT_ANY "\<ANY\>"
#define IC_FORMAT_PULSE "\<PULSE\>"
var/list/all_integrated_circuits = list()
/proc/initialize_integrated_circuits_list()
@@ -20,377 +27,19 @@ var/list/all_integrated_circuits = list()
icon = 'icons/obj/electronic_assemblies.dmi'
icon_state = "template"
w_class = ITEMSIZE_TINY
var/obj/item/device/electronic_assembly/assembly = null // Reference to the assembly holding this circuit, if any.
var/extended_desc = null
var/list/inputs = list()
var/list/outputs = list()
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/cooldown_per_use = 1 SECOND
var/spawn_flags = null // Used for world initializing, see the #defines above.
var/category_text = "NO CATEGORY" // To show up on circuit printer, and perhaps other places.
var/autopulse = -1 // When input is received, the circuit will pulse itself if set to 1. 0 means it won't. -1 means it is permanently off.
/obj/item/integrated_circuit/examine(mob/user)
..()
to_chat(user, "This board has [inputs.len] input pin\s and [outputs.len] output pin\s.")
for(var/datum/integrated_io/input/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/output/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()].")
interact(user)
/obj/item/integrated_circuit/New()
setup_io(inputs, /datum/integrated_io/input)
setup_io(outputs, /datum/integrated_io/output)
setup_io(activators, /datum/integrated_io/activate)
..()
/obj/item/integrated_circuit/proc/setup_io(var/list/io_list, var/io_type)
var/list/io_list_copy = io_list.Copy()
io_list.Cut()
for(var/io_entry in io_list_copy)
io_list.Add(new io_type(src, io_entry, io_list_copy[io_entry]))
/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/verb/rename_component()
set name = "Rename Circuit"
set category = "Object"
set desc = "Rename your circuit, useful to stay organized."
var/mob/M = usr
if(!CanInteract(M, physical_state))
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 && CanInteract(M, physical_state))
to_chat(M, "<span class='notice'>The circuit '[src.name]' is now labeled '[input]'.</span>")
name = input
/obj/item/integrated_circuit/proc/get_pin_ref(var/pin_type, var/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/interact(mob/user)
if(!CanInteract(user, physical_state))
return
var/window_height = 350
var/window_width = 600
//var/table_edge_width = "[(window_width - window_width * 0.1) / 4]px"
//var/table_middle_width = "[(window_width - window_width * 0.1) - (table_edge_width * 2)]px"
var/table_edge_width = "30%"
var/table_middle_width = "40%"
var/HTML = list()
HTML += "<html><head><title>[src.name]</title></head><body>"
HTML += "<div align='center'>"
HTML += "<table border='1' style='undefined;table-layout: fixed; width: 424px'>"
HTML += "<br><a href='?src=\ref[src];'>\[Refresh\]</a> | "
HTML += "<a href='?src=\ref[src];rename=1'>\[Rename\]</a> | "
HTML += "<a href='?src=\ref[src];remove=1'>\[Remove\]</a><br>"
HTML += "<colgroup>"
//HTML += "<col style='width: 121px'>"
//HTML += "<col style='width: 181px'>"
//HTML += "<col style='width: 122px'>"
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)
if(io.linked.len)
words += "<a href=?src=\ref[src];wire=1;pin=\ref[io]><b>[io.name] [io.display_data()]</b></a><br>"
for(var/datum/integrated_io/linked in io.linked)
words += "<a href=?src=\ref[src];wire=1;pin=\ref[io]>\[[linked.name]\]</a> \
@ <a href=?src=\ref[linked.holder];examine=1;>[linked.holder]</a><br>"
else
words += "<a href=?src=\ref[src];wire=1;pin=\ref[io]>[io.name] [io.display_data()]</a><br>"
for(var/datum/integrated_io/linked in io.linked)
words += "<a href=?src=\ref[src];wire=1;pin=\ref[io]>\[[linked.name]\]</a> \
@ <a href=?src=\ref[linked.holder];examine=1;>[linked.holder]</a><br>"
if(outputs.len > inputs.len)
height = 1
if(2)
if(i == 1)
words += "[src.name]<br><br>[src.desc]"
height = row_height
else
continue
if(3)
io = get_pin_ref(IC_OUTPUT, i)
if(io)
if(io.linked.len)
words += "<a href=?src=\ref[src];wire=1;pin=\ref[io]><b>[io.name] [io.display_data()]</b></a><br>"
for(var/datum/integrated_io/linked in io.linked)
words += "<a href=?src=\ref[src];wire=1;pin=\ref[io]>\[[linked.name]\]</a> \
@ <a href=?src=\ref[linked.holder];examine=1;user=\ref[user]>[linked.holder]</a><br>"
else
words += "<a href=?src=\ref[src];wire=1;pin=\ref[io]>[io.name] [io.display_data()]</a><br>"
for(var/datum/integrated_io/linked in io.linked)
words += "<a href=?src=\ref[src];wire=1;pin=\ref[io]>\[[linked.name]\]</a> \
@ <a href=?src=\ref[linked.holder];examine=1;>[linked.holder]</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()
if(io.linked.len)
words += "<a href=?src=\ref[src];wire=1;pin=\ref[io]><font color='FF0000'><b>[io.name]</b></font></a><br>"
for(var/datum/integrated_io/linked in io.linked)
words += "<a href=?src=\ref[src];wire=1;pin=\ref[io]>\[[linked.name]\]</a> \
@ <a href=?src[src];examine=1;user=\ref[user]>[linked.holder]</a><br>"
else
words += "<a href=?src=\ref[src];wire=1;pin=\ref[io]><font color='FF0000'>[io.name]</font></a><br>"
for(var/datum/integrated_io/linked in io.linked)
words += "<a href=?src=\ref[src];wire=1;pin=\ref[io]>\[[linked.name]\]</a> \
@ <a href=?src=\ref[linked.holder];examine=1;>[linked.holder]</a><br>"
HTML += "<tr>"
HTML += "<td colspan='3' align='center'>[jointext(words, null)]</td>"
HTML += "</tr>"
HTML += "</table>"
HTML += "</div>"
if(autopulse != -1)
HTML += "<br><font color='33CC33'>Meta Variables;</font>"
HTML += "<br><font color='33CC33'><a href='?src=\ref[src];autopulse=1'>\[Autopulse\]</a> = <b>[autopulse ? "ON" : "OFF"]</b></font>"
HTML += "<br>"
HTML += "<br><font color='0000AA'>Complexity: [complexity]</font>"
HTML += "<br><font color='0000AA'>[extended_desc]</font>"
HTML += "</body></html>"
user << browse(jointext(HTML, null), "window=circuit-\ref[src];size=[window_width]x[window_height];border=1;can_resize=1;can_close=1;can_minimize=1")
onclose(user, "circuit-\ref[src]")
/obj/item/integrated_circuit/Topic(href, href_list, state = physical_state)
if(..())
return 1
var/pin = locate(href_list["pin"]) in inputs + outputs + activators
var/obj/held_item = usr.get_active_hand()
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(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"])
examine(usr)
if(href_list["rename"])
rename_component(usr)
if(href_list["autopulse"])
if(autopulse != -1)
autopulse = !autopulse
if(href_list["remove"])
if(istype(held_item, /obj/item/weapon/screwdriver))
disconnect_all()
var/turf/T = get_turf(src)
forceMove(T)
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>")
else
to_chat(usr, "<span class='warning'>You need a screwdriver to remove components.</span>")
var/obj/item/device/electronic_assembly/ea = loc
if(istype(ea))
ea.interact(usr)
return
interact(usr) // To refresh the UI.
/datum/integrated_io
var/name = "input/output"
var/obj/item/integrated_circuit/holder = null
var/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/data)
..()
src.name = name
src.data = data
holder = newloc
if(!istype(holder))
message_admins("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()
var/complexity = 1 //This acts as a limitation on building machines, more resource-intensive components cost more 'space'.
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 = null // 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/autopulse = -1 // When input is received, the circuit will pulse itself if set to 1. 0 means it won't. -1 means it is permanently off.
var/removable = TRUE // Determines if a circuit is removable from the assembly.
/datum/integrated_io/proc/data_as_type(var/as_type)
if(!isweakref(data))
return
var/weakref/w = data
var/output = w.resolve()
return istype(output, as_type) ? output : null
/datum/integrated_io/proc/display_data()
if(isnull(data))
return "(null)" // Empty data means nothing to show.
if(istext(data))
return "(\"[data]\")" // Wraps the 'string' in escaped quotes, so that people know it's a 'string'.
if(isweakref(data))
var/weakref/w = data
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 "([data])" // Nothing special needed for numbers or other stuff.
/datum/integrated_io/activate/display_data()
return "(\[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.Remove(src)
else
continue
//Now that we're removed from them, we gotta remove them from us.
src.linked.Remove(their_io)
/datum/integrated_io/input
name = "input pin"
/datum/integrated_io/output
name = "output pin"
/datum/integrated_io/activate
name = "activation pin"
io_type = PULSE_CHANNEL
/obj/item/integrated_circuit/proc/push_data()
for(var/datum/integrated_io/output/O in outputs)
O.push_data()
/obj/item/integrated_circuit/proc/pull_data()
for(var/datum/integrated_io/input/I in inputs)
I.push_data()
/obj/item/integrated_circuit/proc/check_then_do_work()
if(world.time < next_use) // All intergrated circuits have an internal cooldown, to protect from spam.
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/input/I in inputs)
I.disconnect()
for(var/datum/integrated_io/output/O in outputs)
O.disconnect()
for(var/datum/integrated_io/activate/A in activators)
A.disconnect()
@@ -11,6 +11,7 @@
var/max_components = IC_COMPONENTS_BASE
var/max_complexity = IC_COMPLEXITY_BASE
var/opened = 0
var/obj/item/weapon/cell/device/battery = null // Internal cell which most circuits need to work.
/obj/item/device/electronic_assembly/medium
name = "electronic mechanism"
@@ -23,8 +24,8 @@
name = "electronic machine"
icon_state = "setup_large"
w_class = ITEMSIZE_LARGE
max_components = IC_COMPONENTS_BASE * 3
max_complexity = IC_COMPLEXITY_BASE * 3
max_components = IC_COMPONENTS_BASE * 4
max_complexity = IC_COMPLEXITY_BASE * 4
/obj/item/device/electronic_assembly/drone
name = "electronic drone"
@@ -41,6 +42,32 @@
max_complexity = IC_COMPLEXITY_BASE / 2
var/obj/item/weapon/implant/integrated_circuit/implant = null
/obj/item/device/electronic_assembly/New()
..()
battery = new(src)
processing_objects |= src
/obj/item/device/electronic_assembly/Destroy()
battery = null
processing_objects -= src
for(var/atom/movable/AM in contents)
qdel(AM)
..()
/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)
if(!draw_power(IC.power_draw_idle))
IC.power_fail()
/obj/item/device/electronic_assembly/implant/update_icon()
..()
implant.icon_state = icon_state
@@ -70,13 +97,18 @@
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."
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;<br>"
for(var/obj/item/integrated_circuit/circuit in contents)
HTML += "<a href=?src=\ref[circuit];examine=1>[circuit.name]</a> | "
HTML += "<a href=?src=\ref[circuit];rename=1>\[Rename\]</a> | "
HTML += "<a href=?src=\ref[circuit];remove=1>\[Remove\]</a>"
if(circuit.removable)
HTML += "<a href=?src=\ref[circuit];remove=1>\[Remove\]</a>"
HTML += "<br>"
HTML += "</body></html>"
@@ -89,6 +121,16 @@
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 supplier.</span>")
battery = null
interact(usr) // To refresh the UI.
/obj/item/device/electronic_assembly/verb/rename()
@@ -117,39 +159,84 @@
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/GetIdCard()
. = list()
for(var/obj/item/integrated_circuit/part in contents)
var/id_card = part.GetIdCard()
if(id_card)
return id_card
/obj/item/device/electronic_assembly/examine(mob/user)
. = ..(user, 1)
if(.)
for(var/obj/item/integrated_circuit/output/screen/S in contents)
if(S.stuff_to_display)
to_chat(user, "There's a little screen labeled '[S.name]', which displays '[S.stuff_to_display]'.")
for(var/obj/item/integrated_circuit/IC in contents)
IC.external_examine(user)
// for(var/obj/item/integrated_circuit/output/screen/S in contents)
// if(S.stuff_to_display)
// to_chat(user, "There's a little screen labeled '[S.name]', which displays '[S.stuff_to_display]'.")
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.w_class
// Returns true if the circuit made it inside.
/obj/item/device/electronic_assembly/proc/add_circuit(var/obj/item/integrated_circuit/IC, var/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 > src.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.w_class) > 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)
S.set_pin_data(IC_OUTPUT, 1, weakref(target))
S.check_then_do_work()
scanned = TRUE
if(scanned)
visible_message("<span class='notice'>\The [user] waves \the [src] around [target].</span>")
/obj/item/device/electronic_assembly/attackby(var/obj/item/I, var/mob/user)
if(istype(I, /obj/item/integrated_circuit))
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>")
if(!user.unEquip(I))
return 0
var/obj/item/integrated_circuit/IC = I
var/total_parts = 0
var/total_complexity = 0
for(var/obj/item/integrated_circuit/part in contents)
total_parts++
total_complexity = total_complexity + part.complexity
if( (total_parts + 1) > max_components)
to_chat(user, "<span class='warning'>You can't seem to add this [IC.name], since there's no more room.</span>")
return 0
if( (total_complexity + IC.complexity) > max_complexity)
to_chat(user, "<span class='warning'>You can't seem to add this [IC.name], since this setup's too complicated for the case.</span>")
return 0
to_chat(user, "<span class='notice'>You slide \the [IC] inside \the [src].</span>")
user.drop_item()
IC.forceMove(src)
playsound(get_turf(src), 'sound/items/Deconstruct.ogg', 50, 1)
interact(user)
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)
else if(istype(I, /obj/item/weapon/crowbar))
playsound(get_turf(src), 'sound/items/Crowbar.ogg', 50, 1)
opened = !opened
@@ -161,6 +248,21 @@
else
to_chat(user, "<span class='warning'>\The [src] isn't opened, 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 opened, 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 supplier.</span>")
interact(user)
else
return ..()
@@ -179,4 +281,16 @@
/obj/item/device/electronic_assembly/emp_act(severity)
..()
for(var/atom/movable/AM in contents)
AM.emp_act(severity)
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,44 @@
/obj/item/integrated_circuit/proc/setup_io(var/list/io_list, var/io_type)
var/list/io_list_copy = io_list.Copy()
io_list.Cut()
for(var/io_entry in io_list_copy)
io_list.Add(new io_type(src, io_entry, io_list_copy[io_entry]))
/obj/item/integrated_circuit/proc/set_pin_data(var/pin_type, var/pin_number, var/new_data)
var/datum/integrated_io/pin = get_pin_ref(pin_type, pin_number)
return pin.write_data_to_pin(new_data)
/obj/item/integrated_circuit/proc/get_pin_data(var/pin_type, var/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(var/pin_type, var/pin_number, var/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(var/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(var/pin_type, var/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
@@ -0,0 +1,282 @@
/*
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)
. = ..()
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/input/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/output/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/New()
setup_io(inputs, /datum/integrated_io/input)
setup_io(outputs, /datum/integrated_io/output)
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/verb/rename_component()
set name = "Rename Circuit"
set category = "Object"
set desc = "Rename your circuit, useful to stay organized."
var/mob/M = usr
if(!CanInteract(M, physical_state))
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 && CanInteract(M, physical_state))
to_chat(M, "<span class='notice'>The circuit '[src.name]' is now labeled '[input]'.</span>")
name = input
/obj/item/integrated_circuit/interact(mob/user)
if(!CanInteract(user, physical_state))
return
var/window_height = 350
var/window_width = 600
//var/table_edge_width = "[(window_width - window_width * 0.1) / 4]px"
//var/table_middle_width = "[(window_width - window_width * 0.1) - (table_edge_width * 2)]px"
var/table_edge_width = "30%"
var/table_middle_width = "40%"
var/HTML = list()
HTML += "<html><head><title>[src.name]</title></head><body>"
HTML += "<div align='center'>"
HTML += "<table border='1' style='undefined;table-layout: fixed; width: 424px'>"
HTML += "<br><a href='?src=\ref[src];'>\[Refresh\]</a> | "
HTML += "<a href='?src=\ref[src];rename=1'>\[Rename\]</a> | "
HTML += "<a href='?src=\ref[src];remove=1'>\[Remove\]</a><br>"
HTML += "<colgroup>"
//HTML += "<col style='width: 121px'>"
//HTML += "<col style='width: 181px'>"
//HTML += "<col style='width: 122px'>"
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)
if(io.linked.len)
words += "<a href=?src=\ref[src];wire=1;pin=\ref[io]><b>[io.name] [io.display_data()]</b></a><br>"
for(var/datum/integrated_io/linked in io.linked)
words += "<a href=?src=\ref[src];wire=1;pin=\ref[io]>\[[linked.name]\]</a> \
@ <a href=?src=\ref[linked.holder];examine=1;>[linked.holder]</a><br>"
else
words += "<a href=?src=\ref[src];wire=1;pin=\ref[io]>[io.name] [io.display_data()]</a><br>"
for(var/datum/integrated_io/linked in io.linked)
words += "<a href=?src=\ref[src];wire=1;pin=\ref[io]>\[[linked.name]\]</a> \
@ <a href=?src=\ref[linked.holder];examine=1;>[linked.holder]</a><br>"
if(outputs.len > inputs.len)
height = 1
if(2)
if(i == 1)
words += "[src.name]<br><br>[src.desc]"
height = row_height
else
continue
if(3)
io = get_pin_ref(IC_OUTPUT, i)
if(io)
if(io.linked.len)
words += "<a href=?src=\ref[src];wire=1;pin=\ref[io]><b>[io.name] [io.display_data()]</b></a><br>"
for(var/datum/integrated_io/linked in io.linked)
words += "<a href=?src=\ref[src];wire=1;pin=\ref[io]>\[[linked.name]\]</a> \
@ <a href=?src=\ref[linked.holder];examine=1;user=\ref[user]>[linked.holder]</a><br>"
else
words += "<a href=?src=\ref[src];wire=1;pin=\ref[io]>[io.name] [io.display_data()]</a><br>"
for(var/datum/integrated_io/linked in io.linked)
words += "<a href=?src=\ref[src];wire=1;pin=\ref[io]>\[[linked.name]\]</a> \
@ <a href=?src=\ref[linked.holder];examine=1;>[linked.holder]</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()
if(io.linked.len)
words += "<a href=?src=\ref[src];wire=1;pin=\ref[io]><font color='FF0000'><b>[io.name]</b></font></a><br>"
for(var/datum/integrated_io/linked in io.linked)
words += "<a href=?src=\ref[src];wire=1;pin=\ref[io]>\[[linked.name]\]</a> \
@ <a href=?src[src];examine=1;user=\ref[user]>[linked.holder]</a><br>"
else
words += "<a href=?src=\ref[src];wire=1;pin=\ref[io]><font color='FF0000'>[io.name]</font></a><br>"
for(var/datum/integrated_io/linked in io.linked)
words += "<a href=?src=\ref[src];wire=1;pin=\ref[io]>\[[linked.name]\]</a> \
@ <a href=?src=\ref[linked.holder];examine=1;>[linked.holder]</a><br>"
HTML += "<tr>"
HTML += "<td colspan='3' align='center'>[jointext(words, null)]</td>"
HTML += "</tr>"
HTML += "</table>"
HTML += "</div>"
if(autopulse != -1)
HTML += "<br><font color='33CC33'>Meta Variables;</font>"
HTML += "<br><font color='33CC33'><a href='?src=\ref[src];autopulse=1'>\[Autopulse\]</a> = <b>[autopulse ? "ON" : "OFF"]</b></font>"
HTML += "<br>"
HTML += "<br><font color='0000AA'>Complexity: [complexity]</font>"
if(power_draw_idle)
HTML += "<br><font color='0000AA'>Power Draw: [power_draw_idle] W (Idle)</font>"
if(power_draw_per_use)
HTML += "<br><font color='0000AA'>Power Draw: [power_draw_per_use] W (Active)</font>" // Borgcode says that powercells' checked_use() takes joules as input.
HTML += "<br><font color='0000AA'>[extended_desc]</font>"
HTML += "</body></html>"
user << browse(jointext(HTML, null), "window=circuit-\ref[src];size=[window_width]x[window_height];border=1;can_resize=1;can_close=1;can_minimize=1")
onclose(user, "circuit-\ref[src]")
/obj/item/integrated_circuit/Topic(href, href_list, state = physical_state)
if(..())
return 1
var/pin = locate(href_list["pin"]) in inputs + outputs + activators
var/obj/held_item = usr.get_active_hand()
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(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"])
examine(usr)
if(href_list["rename"])
rename_component(usr)
if(href_list["autopulse"])
if(autopulse != -1)
autopulse = !autopulse
if(href_list["remove"])
if(istype(held_item, /obj/item/weapon/screwdriver))
if(!removable)
to_chat(usr, "<span class='warning'>\The [src] seems to be permanently attached to the case.</span>")
return
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>")
else
to_chat(usr, "<span class='warning'>You need a screwdriver to remove components.</span>")
var/obj/item/device/electronic_assembly/ea = loc
if(istype(ea))
ea.interact(usr)
return
interact(usr) // To refresh the UI.
/obj/item/integrated_circuit/proc/push_data()
for(var/datum/integrated_io/output/O in outputs)
O.push_data()
/obj/item/integrated_circuit/proc/pull_data()
for(var/datum/integrated_io/input/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()
if(world.time < next_use) // All intergrated circuits have an internal cooldown, to protect from spam.
return
if(power_draw_per_use)
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/input/I in inputs)
I.disconnect()
for(var/datum/integrated_io/output/O in outputs)
O.disconnect()
for(var/datum/integrated_io/activate/A in activators)
A.disconnect()
@@ -0,0 +1,139 @@
/*
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/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/data)
..()
src.name = name
src.data = data
holder = newloc
if(!istype(holder))
message_admins("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/weakref/w = data
var/output = w.resolve()
return istype(output, as_type) ? output : null
/datum/integrated_io/proc/display_data()
if(isnull(data))
return "(null)" // Empty data means nothing to show.
if(istext(data))
return "(\"[data]\")" // Wraps the 'string' in escaped quotes, so that people know it's a 'string'.
if(isweakref(data))
var/weakref/w = data
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 "([data])" // 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.Remove(src)
else
continue
//Now that we're removed from them, we gotta remove them from us.
src.linked.Remove(their_io)
/datum/integrated_io/input
name = "input pin"
/datum/integrated_io/output
name = "output pin"
/datum/integrated_io/activate
name = "activation pin"
io_type = PULSE_CHANNEL
/datum/integrated_io/list
name = "list pin"
/datum/integrated_io/list/write_data_to_pin(var/new_data)
if(islist(new_data))
data = new_data
holder.on_data_written()
/datum/integrated_io/list/display_pin_type()
return IC_FORMAT_LIST
@@ -20,6 +20,9 @@
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
if(mode == 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>")
@@ -33,6 +36,9 @@
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
@@ -191,6 +197,7 @@
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/integrated_electronics/wirer(src)
@@ -202,11 +209,24 @@
/obj/item/weapon/storage/bag/circuits/all/New()
..()
spawn(2 SECONDS) // So the list has time to initialize.
for(var/obj/item/integrated_circuit/IC in all_integrated_circuits)
for(var/i = 1 to 10)
new IC.type(src)
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)
@@ -219,16 +239,20 @@
w_class = 2
display_contents_with_number = 1
can_hold = list(/obj/item/integrated_circuit)
var/spawn_flags_to_use = IC_SPAWN_DEFAULT
/obj/item/weapon/storage/bag/circuits/mini/arithmetic
name = "arithmetic circuit box"
desc = "Warning: Contains math."
icon_state = "box_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/arithmetic/New()
..()
for(var/obj/item/integrated_circuit/arithmetic/IC in all_integrated_circuits)
if(IC.spawn_flags & IC_SPAWN_DEFAULT)
if(IC.spawn_flags & spawn_flags_to_use)
for(var/i = 1 to 3)
new IC.type(src)
make_exact_fit()
@@ -239,10 +263,13 @@
desc = "Danger: Contains more math."
icon_state = "box_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/trig/New()
..()
for(var/obj/item/integrated_circuit/trig/IC in all_integrated_circuits)
if(IC.spawn_flags & IC_SPAWN_DEFAULT)
if(IC.spawn_flags & spawn_flags_to_use)
for(var/i = 1 to 3)
new IC.type(src)
make_exact_fit()
@@ -253,10 +280,13 @@
desc = "Tell these circuits everything you know."
icon_state = "box_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/input/New()
..()
for(var/obj/item/integrated_circuit/input/IC in all_integrated_circuits)
if(IC.spawn_flags & IC_SPAWN_DEFAULT)
if(IC.spawn_flags & spawn_flags_to_use)
for(var/i = 1 to 3)
new IC.type(src)
make_exact_fit()
@@ -267,10 +297,13 @@
desc = "Circuits to interface with the world beyond itself."
icon_state = "box_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/output/New()
..()
for(var/obj/item/integrated_circuit/output/IC in all_integrated_circuits)
if(IC.spawn_flags & IC_SPAWN_DEFAULT)
if(IC.spawn_flags & spawn_flags_to_use)
for(var/i = 1 to 3)
new IC.type(src)
make_exact_fit()
@@ -281,25 +314,30 @@
desc = "Machines can be quite forgetful without these."
icon_state = "box_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/memory/New()
..()
for(var/obj/item/integrated_circuit/memory/IC in all_integrated_circuits)
if(IC.spawn_flags & IC_SPAWN_DEFAULT)
if(IC.spawn_flags & spawn_flags_to_use)
for(var/i = 1 to 3)
new IC.type(src)
make_exact_fit()
/obj/item/weapon/storage/bag/circuits/mini/logic
name = "logic circuit box"
desc = "May or may not be Turing complete."
icon_state = "box_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/logic/New()
..()
for(var/obj/item/integrated_circuit/logic/IC in all_integrated_circuits)
if(IC.spawn_flags & IC_SPAWN_DEFAULT)
if(IC.spawn_flags & spawn_flags_to_use)
for(var/i = 1 to 3)
new IC.type(src)
make_exact_fit()
@@ -310,10 +348,13 @@
desc = "No time machine parts, sadly."
icon_state = "box_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/time/New()
..()
for(var/obj/item/integrated_circuit/time/IC in all_integrated_circuits)
if(IC.spawn_flags & IC_SPAWN_DEFAULT)
if(IC.spawn_flags & spawn_flags_to_use)
for(var/i = 1 to 3)
new IC.type(src)
make_exact_fit()
@@ -324,10 +365,13 @@
desc = "Unlike most electronics, these circuits are supposed to come in contact with liquids."
icon_state = "box_reagents"
/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/reagents/New()
..()
for(var/obj/item/integrated_circuit/reagent/IC in all_integrated_circuits)
if(IC.spawn_flags & IC_SPAWN_DEFAULT)
if(IC.spawn_flags & spawn_flags_to_use)
for(var/i = 1 to 3)
new IC.type(src)
make_exact_fit()
@@ -338,10 +382,13 @@
desc = "Useful for moving data representing something arbitrary to another arbitrary virtual place."
icon_state = "box_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/transfer/New()
..()
for(var/obj/item/integrated_circuit/transfer/IC in all_integrated_circuits)
if(IC.spawn_flags & IC_SPAWN_DEFAULT)
if(IC.spawn_flags & spawn_flags_to_use)
for(var/i = 1 to 3)
new IC.type(src)
make_exact_fit()
@@ -352,10 +399,66 @@
desc = "Transform one piece of data to another type of data with these."
icon_state = "box_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/converter/New()
..()
for(var/obj/item/integrated_circuit/converter/IC in all_integrated_circuits)
if(IC.spawn_flags & IC_SPAWN_DEFAULT)
if(IC.spawn_flags & spawn_flags_to_use)
for(var/i = 1 to 3)
new IC.type(src)
make_exact_fit()
/obj/item/weapon/storage/bag/circuits/mini/smart
name = "smart box"
desc = "Sentience not included."
icon_state = "box_ai"
/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/smart/New()
..()
for(var/obj/item/integrated_circuit/smart/IC in all_integrated_circuits)
if(IC.spawn_flags & spawn_flags_to_use)
for(var/i = 1 to 3)
new IC.type(src)
make_exact_fit()
/obj/item/weapon/storage/bag/circuits/mini/manipulation
name = "manipulation box"
desc = "Make your machines actually useful with these."
icon_state = "box_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/manipulation/New()
..()
for(var/obj/item/integrated_circuit/manipulation/IC in all_integrated_circuits)
if(IC.spawn_flags & spawn_flags_to_use)
for(var/i = 1 to 3)
new IC.type(src)
make_exact_fit()
/obj/item/weapon/storage/bag/circuits/mini/power
name = "power circuit box"
desc = "Electronics generally require electricity."
icon_state = "box_power"
/obj/item/weapon/storage/bag/circuits/mini/power/all
spawn_flags_to_use = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
/obj/item/weapon/storage/bag/circuits/mini/power/New()
..()
for(var/obj/item/integrated_circuit/passive/power/IC in all_integrated_circuits)
if(IC.spawn_flags & spawn_flags_to_use)
for(var/i = 1 to 3)
new IC.type(src)
for(var/obj/item/integrated_circuit/power/IC in all_integrated_circuits)
if(IC.spawn_flags & spawn_flags_to_use)
for(var/i = 1 to 3)
new IC.type(src)
make_exact_fit()
@@ -1,85 +0,0 @@
/obj/item/integrated_circuit/transfer
category_text = "Data Transfer"
autopulse = 1
/obj/item/integrated_circuit/transfer/on_data_written()
if(autopulse == 1)
check_then_do_work()
/obj/item/integrated_circuit/transfer/splitter
name = "splitter"
desc = "Splits incoming data into all of the output pins."
icon_state = "splitter"
complexity = 3
inputs = list("data to split")
outputs = list("A","B")
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
/obj/item/integrated_circuit/transfer/splitter/medium
name = "four splitter"
icon_state = "splitter4"
complexity = 5
outputs = list("A","B","C","D")
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
/obj/item/integrated_circuit/transfer/splitter/large
name = "eight splitter"
icon_state = "splitter8"
complexity = 9
outputs = list("A","B","C","D","E","F","G","H")
spawn_flags = IC_SPAWN_RESEARCH
/obj/item/integrated_circuit/transfer/splitter/do_work()
var/datum/integrated_io/I = inputs[1]
for(var/datum/integrated_io/output/O in outputs)
O.data = I.data
/obj/item/integrated_circuit/transfer/activator_splitter
name = "activator splitter"
desc = "Splits incoming activation pulses into all of the output pins."
icon_state = "splitter"
complexity = 3
activators = list(
"incoming pulse",
"outgoing pulse A",
"outgoing pulse B"
)
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
/obj/item/integrated_circuit/transfer/activator_splitter/do_work()
for(var/datum/integrated_io/activate/A in outputs)
if(A == activators[1])
continue
if(A.linked.len)
for(var/datum/integrated_io/activate/target in A.linked)
target.holder.check_then_do_work()
/obj/item/integrated_circuit/transfer/activator_splitter/medium
name = "four activator splitter"
icon_state = "splitter4"
complexity = 5
activators = list(
"incoming pulse",
"outgoing pulse A",
"outgoing pulse B",
"outgoing pulse C",
"outgoing pulse D"
)
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
/obj/item/integrated_circuit/transfer/activator_splitter/large
name = "eight activator splitter"
icon_state = "splitter4"
complexity = 9
activators = list(
"incoming pulse",
"outgoing pulse A",
"outgoing pulse B",
"outgoing pulse C",
"outgoing pulse D",
"outgoing pulse E",
"outgoing pulse F",
"outgoing pulse G",
"outgoing pulse H"
)
spawn_flags = 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,109 @@
/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/atom/movable/lighting_overlay/light = locate(/atom/movable/lighting_overlay) in get_turf(src)
var/light_amount = 1 // Unsimulated tiles are pretend-lit, so we need to be pretend too if that somehow happens.
if(light)
light_amount = (light.lum_r + light.lum_g + light.lum_b) / 3
var/adjusted_power = max(max_power * light_amount, 0)
adjusted_power = round(adjusted_power, 0.1)
if(adjusted_power)
if(assembly)
assembly.give_power(adjusted_power)
// 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 = null
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(host && test_validity(host))
assembly.give_power(10)
host.nutrition = max(host.nutrition - DEFAULT_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
// 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))
A.use_power(power_amount, EQUIP)
assembly.give_power(power_amount) // give_power() handles CELLRATE on its own.
@@ -6,6 +6,7 @@
activators = list("compute")
category_text = "Arithmetic"
autopulse = 1
power_draw_per_use = 5 // Math is pretty cheap.
/obj/item/integrated_circuit/arithmetic/on_data_written()
if(autopulse == 1)
@@ -6,6 +6,7 @@
activators = list("convert")
category_text = "Converter"
autopulse = 1
power_draw_per_use = 10
/obj/item/integrated_circuit/converter/on_data_written()
if(autopulse == 1)
@@ -0,0 +1,186 @@
/obj/item/integrated_circuit/transfer
category_text = "Data Transfer"
autopulse = 1
power_draw_per_use = 2
/obj/item/integrated_circuit/transfer/on_data_written()
if(autopulse == 1)
check_then_do_work()
/obj/item/integrated_circuit/transfer/splitter
name = "splitter"
desc = "Splits incoming data into all of the output pins."
icon_state = "splitter"
complexity = 3
inputs = list("data to split")
outputs = list("A","B")
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
/obj/item/integrated_circuit/transfer/splitter/medium
name = "four splitter"
icon_state = "splitter4"
complexity = 5
outputs = list("A","B","C","D")
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
power_draw_per_use = 4
/obj/item/integrated_circuit/transfer/splitter/large
name = "eight splitter"
icon_state = "splitter8"
w_class = ITEMSIZE_SMALL
complexity = 9
outputs = list("A","B","C","D","E","F","G","H")
spawn_flags = IC_SPAWN_RESEARCH
power_draw_per_use = 8
/obj/item/integrated_circuit/transfer/splitter/do_work()
var/datum/integrated_io/I = inputs[1]
for(var/datum/integrated_io/output/O in outputs)
O.data = I.data
/obj/item/integrated_circuit/transfer/activator_splitter
name = "activator splitter"
desc = "Splits incoming activation pulses into all of the output pins."
icon_state = "splitter"
complexity = 3
activators = list(
"incoming pulse",
"outgoing pulse A",
"outgoing pulse B"
)
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
power_draw_per_use = 2
/obj/item/integrated_circuit/transfer/activator_splitter/do_work()
for(var/datum/integrated_io/activate/A in outputs)
if(A == activators[1])
continue
if(A.linked.len)
for(var/datum/integrated_io/activate/target in A.linked)
target.holder.check_then_do_work()
/obj/item/integrated_circuit/transfer/activator_splitter/medium
name = "four activator splitter"
icon_state = "splitter4"
complexity = 5
activators = list(
"incoming pulse",
"outgoing pulse A",
"outgoing pulse B",
"outgoing pulse C",
"outgoing pulse D"
)
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
power_draw_per_use = 4
/obj/item/integrated_circuit/transfer/activator_splitter/large
name = "eight activator splitter"
icon_state = "splitter4"
w_class = ITEMSIZE_SMALL
complexity = 9
activators = list(
"incoming pulse",
"outgoing pulse A",
"outgoing pulse B",
"outgoing pulse C",
"outgoing pulse D",
"outgoing pulse E",
"outgoing pulse F",
"outgoing pulse G",
"outgoing pulse H"
)
spawn_flags = IC_SPAWN_RESEARCH
power_draw_per_use = 8
/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")
outputs = list("output")
activators = list("select")
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
power_draw_per_use = 4
var/number_of_inputs = 2
/obj/item/integrated_circuit/transfer/multiplexer/New()
for(var/i = 1 to number_of_inputs)
inputs += "input [i]"
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(isnum(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)
/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","input")
outputs = list()
activators = list("select")
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
power_draw_per_use = 4
var/number_of_outputs = 2
/obj/item/integrated_circuit/transfer/demultiplexer/New()
for(var/i = 1 to number_of_outputs)
outputs += "output [i]"
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)
/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
@@ -1,6 +1,7 @@
/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
@@ -23,6 +24,21 @@
target.holder.check_then_do_work()
to_chat(user, "<span class='notice'>You press the button labeled '[src.name]'.</span>")
/obj/item/integrated_circuit/input/toggle_button
name = "toggle button"
desc = "It toggles on, off, on, off..."
icon_state = "toggle_button"
complexity = 1
inputs = list()
outputs = list("on" = 0)
activators = list("on toggle")
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))
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."
@@ -33,6 +49,7 @@
outputs = list("number entered")
activators = list("on entered")
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
@@ -53,6 +70,7 @@
outputs = list("string entered")
activators = list("on entered")
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 = input(user, "Enter some words, please.","Number pad") as null|text
@@ -73,6 +91,7 @@
activators = list("scan")
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/datum/integrated_io/I = inputs[1]
@@ -111,6 +130,7 @@
activators = list("scan")
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/datum/integrated_io/I = inputs[1]
@@ -148,12 +168,12 @@
outputs = list("located ref")
activators = list("locate")
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
power_draw_per_use = 20
/obj/item/integrated_circuit/input/local_locator/do_work()
var/datum/integrated_io/O = outputs[1]
O.data = null
if(istype(src.loc, /obj/item/device/electronic_assembly)) // Check to make sure we're actually in a machine.
var/obj/item/device/electronic_assembly/assembly = src.loc
if(assembly)
if(istype(assembly.loc, /mob/living)) // Now check if someone's holding us.
O.data = weakref(assembly.loc)
@@ -170,6 +190,7 @@
outputs = list("located ref")
activators = list("locate")
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
power_draw_per_use = 30
/obj/item/integrated_circuit/input/adjacent_locator/do_work()
var/datum/integrated_io/I = inputs[1]
@@ -206,6 +227,8 @@
activators = list("send signal","on signal received")
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
origin_tech = list(TECH_ENGINEERING = 2, TECH_DATA = 2, TECH_MAGNETS = 2)
power_draw_idle = 5
power_draw_per_use = 40
var/frequency = 1457
var/code = 30
@@ -288,6 +311,7 @@
activators = list("send data", "on data received")
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
origin_tech = list(TECH_ENGINEERING = 2, TECH_DATA = 2, TECH_MAGNETS = 2, TECH_BLUESPACE = 2)
power_draw_per_use = 50
var/datum/exonet_protocol/exonet = null
/obj/item/integrated_circuit/input/EPv2/New()
@@ -334,6 +358,7 @@
outputs = list("X (abs)", "Y (abs)")
activators = list("get coordinates")
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)
@@ -361,6 +386,7 @@
outputs = list("speaker \<String\>", "message \<String\>")
activators = list("on message received")
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
power_draw_per_use = 15
/obj/item/integrated_circuit/input/microphone/New()
..()
@@ -385,9 +411,27 @@
for(var/datum/integrated_io/output/out in outputs)
out.push_data()
A.push_data()
/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."
icon_state = "recorder"
complexity = 12
inputs = list()
outputs = list("scanned ref \<Ref\>")
activators = list("on scanned")
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
power_draw_per_use = 120
/obj/item/integrated_circuit/input/sensor/do_work()
// Because this gets called by attack(), all this needs to do is pulse the activator.
for(var/datum/integrated_io/output/O in outputs)
O.push_data()
var/datum/integrated_io/activate/A = activators[1]
A.push_data()
/obj/item/integrated_circuit/output
@@ -401,8 +445,18 @@
outputs = list()
activators = list("load data")
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
power_draw_per_use = 10
autopulse = 1
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)
to_chat(user, "There is a little screen labeled '[name]', which displays [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))
@@ -416,22 +470,24 @@
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 = istype(loc, /obj/item/device/electronic_assembly) ? loc : src
var/obj/O = assembly ? assembly : src
visible_message("<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 = istype(loc, /obj/item/device/electronic_assembly) ? loc : src
var/obj/O = assembly ? loc : assembly
O.visible_message("<span class='notice'>\icon[O] [stuff_to_display]</span>")
/obj/item/integrated_circuit/output/light
@@ -446,6 +502,10 @@
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/Destroy()
..()
/obj/item/integrated_circuit/output/light/do_work()
light_toggled = !light_toggled
@@ -456,6 +516,7 @@
set_light(l_range = light_brightness, l_power = light_brightness, l_color = light_rgb)
else
set_light(0)
power_draw_idle = light_toggled ? light_brightness * 2 : 0
/obj/item/integrated_circuit/output/light/advanced/update_lighting()
var/datum/integrated_io/R = inputs[1]
@@ -473,6 +534,10 @@
..()
/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."
@@ -504,6 +569,7 @@
)
outputs = list()
activators = list("play sound")
power_draw_per_use = 20
var/list/sounds = list()
/obj/item/integrated_circuit/output/text_to_speech
@@ -517,11 +583,12 @@
outputs = list()
activators = list("to speech")
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
power_draw_per_use = 60
/obj/item/integrated_circuit/output/text_to_speech/do_work()
var/datum/integrated_io/text = inputs[1]
if(istext(text.data))
var/obj/O = istype(loc, /obj/item/device/electronic_assembly) ? loc : src
var/obj/O = assembly ? loc : assembly
audible_message("\icon[O] \The [O.name] states, \"[text.data]\"")
/obj/item/integrated_circuit/output/sound/New()
@@ -576,4 +643,118 @@
"secure day" = 'sound/voice/bsecureday.ogg',
)
spawn_flags = IC_SPAWN_RESEARCH
origin_tech = list(TECH_ENGINEERING = 2, TECH_DATA = 2, TECH_ILLEGAL = 1)
origin_tech = list(TECH_ENGINEERING = 2, TECH_DATA = 2, TECH_ILLEGAL = 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" = "video camera circuit", "camera active" = 0)
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/New()
..()
camera = new(src)
on_data_written()
/obj/item/integrated_circuit/output/video_camera/Destroy()
qdel(camera)
..()
/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/datum/integrated_io/cam_name = inputs[1]
var/datum/integrated_io/cam_active = inputs[2]
if(istext(cam_name.data))
camera.c_tag = cam_name.data
if(isnum(cam_active.data))
set_camera_status(cam_active.data)
/obj/item/integrated_circuit/output/video_camera/power_fail()
if(camera)
set_camera_status(0)
var/datum/integrated_io/cam_active = inputs[2]
cam_active.data = 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")
outputs = list()
activators = list()
power_draw_idle = 0 // Raises to 1 when lit.
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
var/led_color
/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]>¤</font>" : "unlit."]"
to_chat(user,jointext(text_output,null))
/obj/item/integrated_circuit/output/led/red
name = "red LED"
led_color = COLOR_RED
/obj/item/integrated_circuit/output/led/orange
name = "orange LED"
led_color = COLOR_ORANGE
/obj/item/integrated_circuit/output/led/yellow
name = "yellow LED"
led_color = COLOR_YELLOW
/obj/item/integrated_circuit/output/led/green
name = "green LED"
led_color = COLOR_GREEN
/obj/item/integrated_circuit/output/led/blue
name = "blue LED"
led_color = COLOR_BLUE
/obj/item/integrated_circuit/output/led/purple
name = "purple LED"
led_color = COLOR_PURPLE
/obj/item/integrated_circuit/output/led/cyan
name = "cyan LED"
led_color = COLOR_CYAN
/obj/item/integrated_circuit/output/led/white
name = "white LED"
led_color = COLOR_WHITE
/obj/item/integrated_circuit/output/led/pink
name = "pink LED"
led_color = COLOR_PINK
@@ -4,9 +4,10 @@
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")
activators = list("compare", "on true result")
activators = list("compare", "on true result", "on false result")
category_text = "Logic"
autopulse = 1
power_draw_per_use = 1
/obj/item/integrated_circuit/logic/on_data_written()
if(autopulse == 1)
@@ -14,10 +15,13 @@
/obj/item/integrated_circuit/logic/do_work()
var/datum/integrated_io/O = outputs[1]
var/datum/integrated_io/P = activators[2]
var/datum/integrated_io/T = activators[2]
var/datum/integrated_io/F = activators[3]
O.push_data()
if(O.data)
P.push_data()
T.push_data()
else
F.push_data()
/obj/item/integrated_circuit/logic/binary
inputs = list("A","B")
@@ -53,6 +57,15 @@
/obj/item/integrated_circuit/logic/binary/equals/do_compare(var/datum/integrated_io/A, var/datum/integrated_io/B)
return A.data == B.data
/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(var/datum/integrated_io/A, var/datum/integrated_io/B)
return A.data != B.data
/obj/item/integrated_circuit/logic/binary/and
name = "and gate"
desc = "This gate will output 'one' if both inputs evaluate to true."
@@ -114,4 +127,4 @@
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
/obj/item/integrated_circuit/logic/unary/not/do_check(var/datum/integrated_io/A)
return !A.data
return !A.data
@@ -9,6 +9,7 @@
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
inputs = list(
"target X rel",
"target Y rel"
@@ -20,6 +21,7 @@
var/obj/item/weapon/gun/installed_gun = null
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(installed_gun)
@@ -106,20 +108,21 @@
<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
inputs = list("dir num")
outputs = list()
activators = list("step towards dir")
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 && istype(loc, /obj/item/device/electronic_assembly))
var/obj/item/device/electronic_assembly/machine = loc
if(machine.anchored || !machine.can_move())
if(T && assembly)
if(assembly.anchored || !assembly.can_move())
return
if(machine.loc == T) // Check if we're held by someone. If the loc is the floor, we're not held.
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(machine, wanted_dir.data)
step(assembly, wanted_dir.data)
@@ -8,6 +8,7 @@
activators = list("set")
category_text = "Memory"
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
power_draw_per_use = 1
/obj/item/integrated_circuit/memory/examine(mob/user)
..()
@@ -33,15 +34,18 @@
name = "memory circuit"
desc = "This circuit can store four pieces of data."
icon_state = "memory4"
w_class = ITEMSIZE_SMALL
complexity = 4
inputs = list("input pin 1","input pin 2","input pin 3","input pin 4")
outputs = list("output pin 1","output pin 2","output pin 3","output pin 4")
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
power_draw_per_use = 2
/obj/item/integrated_circuit/memory/large
name = "large memory circuit"
desc = "This big circuit can hold eight pieces of data."
icon_state = "memory8"
w_class = ITEMSIZE_SMALL
complexity = 8
inputs = list(
"input pin 1",
@@ -63,11 +67,13 @@
"output pin 8")
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
origin_tech = list(TECH_ENGINEERING = 3, TECH_DATA = 3)
power_draw_per_use = 4
/obj/item/integrated_circuit/memory/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
complexity = 16
inputs = list(
"input pin 1",
@@ -106,6 +112,7 @@
"output pin 16")
spawn_flags = IC_SPAWN_RESEARCH
origin_tech = list(TECH_ENGINEERING = 4, TECH_DATA = 4)
power_draw_per_use = 8
/obj/item/integrated_circuit/memory/constant
name = "constant chip"
@@ -0,0 +1,80 @@
/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 ref")
outputs = list("target cell charge", "target cell max charge", "target cell percentage")
activators = list("transmit")
spawn_flags = IC_SPAWN_RESEARCH
origin_tech = list(TECH_ENGINEERING = 4, TECH_DATA = 4, TECH_POWER = 4, TECH_MAGNETS = 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_MAGNETS = 5)
power_draw_per_use = 2000
amount_to_move = 20000
/obj/item/integrated_circuit/power/transmitter/do_work()
set_pin_data(IC_OUTPUT, 1, null)
set_pin_data(IC_OUTPUT, 2, null)
set_pin_data(IC_OUTPUT, 3, null)
var/atom/movable/AM = get_pin_data_as_type(IC_INPUT, 1, /atom/movable)
if(AM)
if(!assembly)
return FALSE // Pointless to do everything else if there's no battery to draw from.
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())
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())
return TRUE
return FALSE
/obj/item/integrated_circuit/power/transmitter/large/do_work()
if(..()) // If the above code succeeds, do this below.
if(prob(2))
var/datum/effect/effect/system/spark_spread/sparks = new /datum/effect/effect/system/spark_spread()
sparks.set_up(3, 0, get_turf(src))
sparks.start()
visible_message("<span class='warning'>\The [assembly] makes some sparks!</span>")
qdel(sparks)
@@ -23,6 +23,7 @@
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)
@@ -47,6 +48,7 @@
activators = list("inject")
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/datum/integrated_io/amount = inputs[2]
@@ -92,6 +94,7 @@
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/datum/integrated_io/amount = inputs[3]
@@ -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 ref")
outputs = list("dir")
activators = list("calculate dir")
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]
var/datum/integrated_io/O = outputs[1]
O.data = 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)
if(desired_dir)
O.data = desired_dir
O.push_data()
@@ -14,6 +14,7 @@
var/delay = 2 SECONDS
activators = list("incoming pulse","outgoing pulse")
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
power_draw_per_use = 2
/obj/item/integrated_circuit/time/delay/do_work()
set waitfor = 0 // Don't sleep in a proc that is called by a processor. It'll delay the entire thing
@@ -82,6 +83,7 @@
inputs = list("enable ticking")
activators = list("outgoing pulse")
spawn_flags = IC_SPAWN_RESEARCH
power_draw_per_use = 4
/obj/item/integrated_circuit/time/ticker/Destroy()
if(is_running)
@@ -116,6 +118,7 @@
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"
@@ -124,6 +127,7 @@
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"
@@ -132,6 +136,7 @@
inputs = list()
outputs = list("time (string)", "hours (number)", "minutes (number)", "seconds (number)")
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
power_draw_per_use = 4
/obj/item/integrated_circuit/time/clock/do_work()
var/datum/integrated_io/time = outputs[1]
@@ -7,6 +7,7 @@
category_text = "Trig"
extended_desc = "Input and output are in degrees."
autopulse = 1
power_draw_per_use = 1 // Still cheap math.
/obj/item/integrated_circuit/trig/on_data_written()
if(autopulse == 1)
@@ -118,7 +119,7 @@
/obj/item/integrated_circuit/trig/cotangent
name = "cot circuit"
desc = "Outputs the cotangent of A. Has nothing to do with the security department."
desc = "Outputs the cotangent of A."
icon_state = "cotangent"
inputs = list("A")
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
@@ -1,6 +0,0 @@
#undef IC_INPUT
#undef IC_OUTPUT
#undef IC_ACTIVATOR
#undef DATA_CHANNEL
#undef PULSE_CHANNEL
@@ -0,0 +1,16 @@
#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_STRING
#undef IC_FORMAT_NUMBER
#undef IC_FORMAT_REF
#undef IC_FORMAT_LIST
#undef IC_FORMAT_ANY
#undef IC_FORMAT_PULSE