Revert "PLASE"

This reverts commit 8af225e6e3.
This commit is contained in:
Fermi
2019-11-24 03:06:08 +00:00
parent aeb8606ce0
commit ba4fa1ef67
2145 changed files with 1387321 additions and 5257 deletions
@@ -0,0 +1,868 @@
#define IC_MAX_SIZE_BASE 25
#define IC_COMPLEXITY_BASE 75
/obj/item/electronic_assembly
name = "electronic assembly"
obj_flags = CAN_BE_HIT | UNIQUE_RENAME
desc = "It's a case, for building small electronics with."
w_class = WEIGHT_CLASS_SMALL
icon = 'icons/obj/assemblies/electronic_setups.dmi'
icon_state = "setup_small"
item_flags = NOBLUDGEON
materials = list() // To be filled later
datum_flags = DF_USE_TAG
var/list/assembly_components = list()
var/list/ckeys_allowed_to_scan = list() // Players who built the circuit can scan it as a ghost.
var/max_components = IC_MAX_SIZE_BASE
var/max_complexity = IC_COMPLEXITY_BASE
var/opened = TRUE
var/obj/item/stock_parts/cell/battery // Internal cell which most circuits need to work.
var/cell_type = /obj/item/stock_parts/cell
var/can_charge = TRUE //Can it be charged in a recharger?
var/can_fire_equipped = FALSE //Can it fire/throw weapons when the assembly is being held?
var/charge_sections = 4
var/charge_tick = FALSE
var/charge_delay = 4
var/use_cyborg_cell = TRUE
var/ext_next_use = 0
var/atom/collw
var/obj/item/card/id/access_card
var/allowed_circuit_action_flags = IC_ACTION_COMBAT | IC_ACTION_LONG_RANGE //which circuit flags are allowed
var/combat_circuits = 0 //number of combat cicuits in the assembly, used for diagnostic hud
var/long_range_circuits = 0 //number of long range cicuits in the assembly, used for diagnostic hud
var/prefered_hud_icon = "hudstat" // Used by the AR circuit to change the hud icon.
var/creator // circuit creator if any
var/static/next_assembly_id = 0
hud_possible = list(DIAG_STAT_HUD, DIAG_BATT_HUD, DIAG_TRACK_HUD, DIAG_CIRCUIT_HUD) //diagnostic hud overlays
max_integrity = 50
pass_flags = 0
armor = list("melee" = 50, "bullet" = 70, "laser" = 70, "energy" = 100, "bomb" = 10, "bio" = 100, "rad" = 100, "fire" = 0, "acid" = 0)
anchored = FALSE
var/can_anchor = TRUE
var/detail_color = COLOR_ASSEMBLY_BLACK
var/list/color_whitelist = list( //This is just for checking that hacked colors aren't in the save data.
COLOR_ASSEMBLY_BLACK,
COLOR_FLOORTILE_GRAY,
COLOR_ASSEMBLY_BGRAY,
COLOR_ASSEMBLY_WHITE,
COLOR_ASSEMBLY_RED,
COLOR_ASSEMBLY_ORANGE,
COLOR_ASSEMBLY_BEIGE,
COLOR_ASSEMBLY_BROWN,
COLOR_ASSEMBLY_GOLD,
COLOR_ASSEMBLY_YELLOW,
COLOR_ASSEMBLY_GURKHA,
COLOR_ASSEMBLY_LGREEN,
COLOR_ASSEMBLY_GREEN,
COLOR_ASSEMBLY_LBLUE,
COLOR_ASSEMBLY_BLUE,
COLOR_ASSEMBLY_PURPLE
)
/obj/item/electronic_assembly/New()
..()
src.max_components = round(max_components)
src.max_complexity = round(max_complexity)
/obj/item/electronic_assembly/GenerateTag()
tag = "assembly_[next_assembly_id++]"
/obj/item/electronic_assembly/examine(mob/user)
. = ..()
if(can_anchor)
to_chat(user, "<span class='notice'>The anchoring bolts [anchored ? "are" : "can be"] <b>wrenched</b> in place and the maintenance panel [opened ? "can be" : "is"] <b>screwed</b> in place.</span>")
else
to_chat(user, "<span class='notice'>The maintenance panel [opened ? "can be" : "is"] <b>screwed</b> in place.</span>")
if((isobserver(user) && ckeys_allowed_to_scan[user.ckey]) || IsAdminGhost(user))
to_chat(user, "You can <a href='?src=[REF(src)];ghostscan=1'>scan</a> this circuit.")
for(var/I in assembly_components)
var/obj/item/integrated_circuit/IC = I
IC.external_examine(user)
if(opened)
interact(user)
/obj/item/electronic_assembly/proc/check_interactivity(mob/user)
return user.canUseTopic(src, BE_CLOSE)
/obj/item/electronic_assembly/Bump(atom/AM)
collw = AM
.=..()
if((istype(collw, /obj/machinery/door/airlock) || istype(collw, /obj/machinery/door/window)) && (!isnull(access_card)))
var/obj/machinery/door/D = collw
if(D.check_access(access_card))
D.open()
/obj/item/electronic_assembly/Initialize()
.=..()
START_PROCESSING(SScircuit, src)
materials[MAT_METAL] = round((max_complexity + max_components) / 4) * SScircuit.cost_multiplier
//sets up diagnostic hud view
prepare_huds()
for(var/datum/atom_hud/data/diagnostic/diag_hud in GLOB.huds)
diag_hud.add_to_hud(src)
diag_hud_set_circuithealth()
diag_hud_set_circuitcell()
diag_hud_set_circuitstat()
diag_hud_set_circuittracking()
access_card = new /obj/item/card/id(src)
/obj/item/electronic_assembly/Destroy()
STOP_PROCESSING(SScircuit, src)
for(var/datum/atom_hud/data/diagnostic/diag_hud in GLOB.huds)
diag_hud.remove_from_hud(src)
QDEL_NULL(access_card)
return ..()
/obj/item/electronic_assembly/process()
handle_idle_power()
check_pulling()
//updates diagnostic hud
diag_hud_set_circuithealth()
diag_hud_set_circuitcell()
/obj/item/electronic_assembly/proc/handle_idle_power()
// First we generate power.
for(var/obj/item/integrated_circuit/passive/power/P in assembly_components)
P.make_energy()
// Now spend it.
for(var/I in assembly_components)
var/obj/item/integrated_circuit/IC = I
if(IC.power_draw_idle)
if(!draw_power(IC.power_draw_idle))
IC.power_fail()
/obj/item/electronic_assembly/interact(mob/user)
ui_interact(user)
/obj/item/electronic_assembly/ui_interact(mob/user)
. = ..()
if(!check_interactivity(user))
return
var/total_part_size = return_total_size()
var/total_complexity = return_total_complexity()
var/HTML = ""
HTML += "<html><head><title>[name]</title></head><body>"
HTML += "<a href='?src=[REF(src)]'>\[Refresh\]</a> | <a href='?src=[REF(src)];rename=1'>\[Rename\]</a><br>"
HTML += "[total_part_size]/[max_components] ([round((total_part_size / 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 power cell detected!</span>"
HTML += "<br><br>"
HTML += "Components:"
var/builtin_components = ""
for(var/c in assembly_components)
var/obj/item/integrated_circuit/circuit = c
if(!circuit.removable)
builtin_components += "<a href='?src=[REF(circuit)];rename=1;return=1'>\[R\]</a> | "
builtin_components += "<a href='?src=[REF(circuit)]'>[circuit.displayed_name]</a>"
builtin_components += "<br>"
// Put removable circuits (if any) in separate categories from non-removable
if(builtin_components)
HTML += "<hr>"
HTML += "Built in:<br>"
HTML += builtin_components
HTML += "<hr>"
HTML += "Removable:"
HTML += "<br>"
for(var/c in assembly_components)
var/obj/item/integrated_circuit/circuit = c
if(circuit.removable)
HTML += "<a href='?src=[REF(src)];component=[REF(circuit)];up=1' style='text-decoration:none;'>&#8593;</a> "
HTML += "<a href='?src=[REF(src)];component=[REF(circuit)];down=1' style='text-decoration:none;'>&#8595;</a> "
HTML += "<a href='?src=[REF(src)];component=[REF(circuit)];top=1' style='text-decoration:none;'>&#10514;</a> "
HTML += "<a href='?src=[REF(src)];component=[REF(circuit)];bottom=1' style='text-decoration:none;'>&#10515;</a> | "
HTML += "<a href='?src=[REF(circuit)];component=[REF(circuit)];rename=1;return=1'>\[R\]</a> | "
HTML += "<a href='?src=[REF(src)];component=[REF(circuit)];remove=1'>\[-\]</a> | "
HTML += "<a href='?src=[REF(circuit)]'>[circuit.displayed_name]</a>"
HTML += "<br>"
HTML += "</body></html>"
user << browse(HTML, "window=assembly-[REF(src)];size=655x350;border=1;can_resize=1;can_close=1;can_minimize=1")
/obj/item/electronic_assembly/Topic(href, href_list)
if(..())
return 1
if(href_list["ghostscan"])
if((isobserver(usr) && ckeys_allowed_to_scan[usr.ckey]) || IsAdminGhost(usr))
if(assembly_components.len)
var/saved = "On circuit printers with cloning enabled, you may use the code below to clone the circuit:<br><br><code>[SScircuit.save_electronic_assembly(src)]</code>"
usr << browse(saved, "window=circuit_scan;size=500x600;border=1;can_resize=1;can_close=1;can_minimize=1")
else
to_chat(usr, "<span class='warning'>The circuit is empty!</span>")
return
if(!check_interactivity(usr))
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
battery.forceMove(drop_location())
playsound(src, '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
diag_hud_set_circuitstat() //update diagnostic hud
if(href_list["component"])
var/obj/item/integrated_circuit/component = locate(href_list["component"]) in assembly_components
if(component)
// Builtin components are not supposed to be removed or rearranged
if(!component.removable)
return
add_allowed_scanner(usr.ckey)
var/current_pos = assembly_components.Find(component)
// Find the position of a first removable component
var/first_removable_pos
for(var/i in 1 to assembly_components.len)
var/obj/item/integrated_circuit/temp_component = assembly_components[i]
if(temp_component.removable)
first_removable_pos = i
break
if(href_list["remove"])
try_remove_component(component, usr)
else
// Adjust the position
if(href_list["up"])
current_pos--
else if(href_list["down"])
current_pos++
else if(href_list["top"])
current_pos = first_removable_pos
else if(href_list["bottom"])
current_pos = assembly_components.len
// Wrap around nicely
if(current_pos < first_removable_pos)
current_pos = assembly_components.len
else if(current_pos > assembly_components.len)
current_pos = first_removable_pos
assembly_components.Remove(component)
assembly_components.Insert(current_pos, component)
interact(usr) // To refresh the UI.
/obj/item/electronic_assembly/pickup(mob/living/user)
. = ..()
//update diagnostic hud when picked up, true is used to force the hud to be hidden
diag_hud_set_circuithealth(TRUE)
diag_hud_set_circuitcell(TRUE)
diag_hud_set_circuitstat(TRUE)
diag_hud_set_circuittracking(TRUE)
/obj/item/electronic_assembly/dropped(mob/user)
. = ..()
//update diagnostic hud when dropped
diag_hud_set_circuithealth()
diag_hud_set_circuitcell()
diag_hud_set_circuitstat()
diag_hud_set_circuittracking()
/obj/item/electronic_assembly/proc/rename()
var/mob/M = usr
if(!check_interactivity(M))
return
var/input = reject_bad_name(input("What do you want to name this?", "Rename", src.name) as null|text, TRUE)
if(!check_interactivity(M))
return
if(src && input)
to_chat(M, "<span class='notice'>The machine now has a label reading '[input]'.</span>")
name = input
/obj/item/electronic_assembly/proc/add_allowed_scanner(ckey)
ckeys_allowed_to_scan[ckey] = TRUE
/obj/item/electronic_assembly/proc/can_move()
return FALSE
/obj/item/electronic_assembly/update_icon()
if(opened)
icon_state = initial(icon_state) + "-open"
else
icon_state = initial(icon_state)
cut_overlays()
if(detail_color == COLOR_ASSEMBLY_BLACK) //Black colored overlay looks almost but not exactly like the base sprite, so just cut the overlay and avoid it looking kinda off.
return
var/mutable_appearance/detail_overlay = mutable_appearance('icons/obj/assemblies/electronic_setups.dmi', "[icon_state]-color")
detail_overlay.color = detail_color
add_overlay(detail_overlay)
/obj/item/electronic_assembly/proc/return_total_complexity()
. = 0
var/obj/item/integrated_circuit/part
for(var/p in assembly_components)
part = p
. += part.complexity
/obj/item/electronic_assembly/proc/return_total_size()
. = 0
var/obj/item/integrated_circuit/part
for(var/p in assembly_components)
part = p
. += part.size
// Returns true if the circuit made it inside.
/obj/item/electronic_assembly/proc/try_add_component(obj/item/integrated_circuit/IC, mob/user)
if(!opened)
to_chat(user, "<span class='warning'>\The [src]'s hatch is closed, you can't put anything inside.</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 = return_total_size()
var/total_complexity = return_total_complexity()
if((total_part_size + IC.size) > max_components)
to_chat(user, "<span class='warning'>You can't seem to add the '[IC]', 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]', since this setup's too complicated for the case.</span>")
return FALSE
if((allowed_circuit_action_flags & IC.action_flags) != IC.action_flags)
to_chat(user, "<span class='warning'>You can't seem to add the '[IC]', since the case doesn't support the circuit type.</span>")
return FALSE
if(!user.transferItemToLoc(IC, src))
return FALSE
to_chat(user, "<span class='notice'>You slide [IC] inside [src].</span>")
playsound(src, 'sound/items/Deconstruct.ogg', 50, 1)
add_allowed_scanner(user.ckey)
investigate_log("had [IC]([IC.type]) inserted by [key_name(user)].", INVESTIGATE_CIRCUIT)
add_component(IC)
return TRUE
// Actually puts the circuit inside, doesn't perform any checks.
/obj/item/electronic_assembly/proc/add_component(obj/item/integrated_circuit/component)
component.forceMove(get_object())
component.assembly = src
assembly_components |= component
//increment numbers for diagnostic hud
if(component.action_flags & IC_ACTION_COMBAT)
combat_circuits += 1;
if(component.action_flags & IC_ACTION_LONG_RANGE)
long_range_circuits += 1;
//diagnostic hud update
diag_hud_set_circuitstat()
diag_hud_set_circuittracking()
/obj/item/electronic_assembly/proc/try_remove_component(obj/item/integrated_circuit/IC, mob/user, silent)
if(!opened)
if(!silent)
to_chat(user, "<span class='warning'>[src]'s hatch is closed, so you can't fiddle with the internal components.</span>")
return FALSE
if(!IC.removable)
if(!silent)
to_chat(user, "<span class='warning'>[src] is permanently attached to the case.</span>")
return FALSE
remove_component(IC)
if(!silent)
to_chat(user, "<span class='notice'>You pop \the [IC] out of the case, and slide it out.</span>")
playsound(src, 'sound/items/crowbar.ogg', 50, 1)
user.put_in_hands(IC)
add_allowed_scanner(user.ckey)
investigate_log("had [IC]([IC.type]) removed by [key_name(user)].", INVESTIGATE_CIRCUIT)
return TRUE
// Actually removes the component, doesn't perform any checks.
/obj/item/electronic_assembly/proc/remove_component(obj/item/integrated_circuit/component)
component.disconnect_all()
component.forceMove(drop_location())
component.assembly = null
assembly_components.Remove(component)
//decriment numbers for diagnostic hud
if(component.action_flags & IC_ACTION_COMBAT)
combat_circuits -= 1;
if(component.action_flags & IC_ACTION_LONG_RANGE)
long_range_circuits -= 1;
//diagnostic hud update
diag_hud_set_circuitstat()
diag_hud_set_circuittracking()
/obj/item/electronic_assembly/afterattack(atom/target, mob/user, proximity)
. = ..()
for(var/obj/item/integrated_circuit/input/S in assembly_components)
if(S.sense(target,user,proximity))
visible_message("<span class='notice'> [user] waves [src] around [target].</span>")
/obj/item/electronic_assembly/screwdriver_act(mob/living/user, obj/item/I)
if(..())
return TRUE
I.play_tool_sound(src)
opened = !opened
to_chat(user, "<span class='notice'>You [opened ? "open" : "close"] the maintenance hatch of [src].</span>")
update_icon()
return TRUE
/obj/item/electronic_assembly/attackby(obj/item/I, mob/living/user)
if(can_anchor && default_unfasten_wrench(user, I, 20))
return
if(istype(I, /obj/item/integrated_circuit))
if(!user.canUnEquip(I))
return FALSE
if(try_add_component(I, user))
return TRUE
else
for(var/obj/item/integrated_circuit/input/S in assembly_components)
S.attackby_react(I,user,user.a_intent)
return ..()
else if(istype(I, /obj/item/multitool) || istype(I, /obj/item/integrated_electronics/wirer) || istype(I, /obj/item/integrated_electronics/debugger))
if(opened)
interact(user)
return TRUE
else
to_chat(user, "<span class='warning'>[src]'s hatch is closed, so you can't fiddle with the internal components.</span>")
for(var/obj/item/integrated_circuit/input/S in assembly_components)
S.attackby_react(I,user,user.a_intent)
return ..()
else if(istype(I, /obj/item/stock_parts/cell))
if(!opened)
to_chat(user, "<span class='warning'>[src]'s hatch is closed, so you can't access \the [src]'s power supplier.</span>")
for(var/obj/item/integrated_circuit/input/S in assembly_components)
S.attackby_react(I,user,user.a_intent)
return ..()
if(battery)
to_chat(user, "<span class='warning'>[src] already has \a [battery] installed. Remove it first if you want to replace it.</span>")
for(var/obj/item/integrated_circuit/input/S in assembly_components)
S.attackby_react(I,user,user.a_intent)
return ..()
I.forceMove(src)
battery = I
diag_hud_set_circuitstat() //update diagnostic hud
playsound(get_turf(src), 'sound/items/Deconstruct.ogg', 50, 1)
to_chat(user, "<span class='notice'>You slot the [I] inside \the [src]'s power supplier.</span>")
return TRUE
else if(istype(I, /obj/item/integrated_electronics/detailer))
var/obj/item/integrated_electronics/detailer/D = I
detail_color = D.detail_color
update_icon()
else
if(user.a_intent != INTENT_HELP)
return ..()
var/list/input_selection = list()
//Check all the components asking for an input
for(var/obj/item/integrated_circuit/input in assembly_components)
if((input.demands_object_input && opened) || (input.demands_object_input && input.can_input_object_when_closed))
var/i = 0
//Check if there is another component with the same name and append a number for identification
for(var/s in input_selection)
var/obj/item/integrated_circuit/s_circuit = input_selection[s]
if(s_circuit.name == input.name && s_circuit.displayed_name == input.displayed_name && s_circuit != input)
i++
var/disp_name= "[input.displayed_name] \[[input]\]"
if(i)
disp_name += " ([i+1])"
//Associative lists prevent me from needing another list and using a Find proc
input_selection[disp_name] = input
var/obj/item/integrated_circuit/choice
if(input_selection)
if(input_selection.len == 1)
choice = input_selection[input_selection[1]]
else
var/selection = input(user, "Where do you want to insert that item?", "Interaction") as null|anything in input_selection
if(!check_interactivity(user))
return ..()
if(selection)
choice = input_selection[selection]
if(choice)
choice.additem(I, user)
for(var/obj/item/integrated_circuit/input/S in assembly_components)
S.attackby_react(I,user,user.a_intent)
return ..()
/obj/item/electronic_assembly/attack_self(mob/user)
if(!check_interactivity(user))
return
if(opened)
interact(user)
var/list/input_selection = list()
//Check all the components asking for an input
for(var/obj/item/integrated_circuit/input/input in assembly_components)
if(input.can_be_asked_input)
var/i = 0
//Check if there is another component with the same name and append a number for identification
for(var/s in input_selection)
var/obj/item/integrated_circuit/s_circuit = input_selection[s]
if(s_circuit.name == input.name && s_circuit.displayed_name == input.displayed_name && s_circuit != input)
i++
var/disp_name= "[input.displayed_name] \[[input]\]"
if(i)
disp_name += " ([i+1])"
//Associative lists prevent me from needing another list and using a Find proc
input_selection[disp_name] = input
var/obj/item/integrated_circuit/input/choice
if(input_selection)
if(input_selection.len ==1)
choice = input_selection[input_selection[1]]
else
var/selection = input(user, "What do you want to interact with?", "Interaction") as null|anything in input_selection
if(!check_interactivity(user))
return
if(selection)
choice = input_selection[selection]
if(choice)
choice.ask_for_input(user)
/obj/item/electronic_assembly/emp_act(severity)
. = ..()
if(. & EMP_PROTECT_CONTENTS)
return
for(var/I in src)
var/atom/movable/AM = I
AM.emp_act(severity)
// Returns true if power was successfully drawn.
/obj/item/electronic_assembly/proc/draw_power(amount)
if(battery && battery.use(amount * GLOB.CELLRATE))
return TRUE
return FALSE
// Ditto for giving.
/obj/item/electronic_assembly/proc/give_power(amount)
if(battery && battery.give(amount * GLOB.CELLRATE))
return TRUE
return FALSE
/obj/item/electronic_assembly/Moved(oldLoc, dir)
for(var/I in assembly_components)
var/obj/item/integrated_circuit/IC = I
IC.ext_moved(oldLoc, dir)
if(light) //Update lighting objects (From light circuits).
update_light()
/obj/item/electronic_assembly/stop_pulling()
for(var/I in assembly_components)
var/obj/item/integrated_circuit/IC = I
IC.stop_pulling()
..()
// Returns the object that is supposed to be used in attack messages, location checks, etc.
// Override in children for special behavior.
/obj/item/electronic_assembly/proc/get_object()
return src
// Returns the location to be used for dropping items.
// Same as the regular drop_location(), but with checks being run on acting_object if necessary.
/obj/item/integrated_circuit/drop_location()
var/atom/movable/acting_object = get_object()
// plz no infinite loops
if(acting_object == src)
return ..()
return acting_object.drop_location()
/obj/item/electronic_assembly/attack_tk(mob/user)
if(anchored)
return
..()
/obj/item/electronic_assembly/attack_hand(mob/user)
if(anchored)
attack_self(user)
return
..()
/obj/item/electronic_assembly/default //The /default electronic_assemblys are to allow the introduction of the new naming scheme without breaking old saves.
name = "type-a electronic assembly"
/obj/item/electronic_assembly/calc
name = "type-b electronic assembly"
icon_state = "setup_small_calc"
desc = "It's a case, for building small electronics with. This one resembles a pocket calculator."
/obj/item/electronic_assembly/clam
name = "type-c electronic assembly"
icon_state = "setup_small_clam"
desc = "It's a case, for building small electronics with. This one has a clamshell design."
/obj/item/electronic_assembly/simple
name = "type-d electronic assembly"
icon_state = "setup_small_simple"
desc = "It's a case, for building small electronics with. This one has a simple design."
/obj/item/electronic_assembly/hook
name = "type-e electronic assembly"
icon_state = "setup_small_hook"
desc = "It's a case, for building small electronics with. This one looks like it has a belt clip, but it's purely decorative."
/obj/item/electronic_assembly/pda
name = "type-f electronic assembly"
icon_state = "setup_small_pda"
desc = "It's a case, for building small electronics with. This one resembles a PDA."
/obj/item/electronic_assembly/dildo
name = "type-g electronic assembly"
icon_state = "setup_dildo_medium"
desc = "It's a case, for building small electronics with. This one has a phallic design."
/obj/item/electronic_assembly/small
name = "electronic device"
icon_state = "setup_device"
desc = "It's a case, for building tiny-sized electronics with."
w_class = WEIGHT_CLASS_TINY
max_components = IC_MAX_SIZE_BASE / 2
max_complexity = IC_COMPLEXITY_BASE / 2
/obj/item/electronic_assembly/small/default
name = "type-a electronic device"
/obj/item/electronic_assembly/small/cylinder
name = "type-b electronic device"
icon_state = "setup_device_cylinder"
desc = "It's a case, for building tiny-sized electronics with. This one has a cylindrical design."
/obj/item/electronic_assembly/small/scanner
name = "type-c electronic device"
icon_state = "setup_device_scanner"
desc = "It's a case, for building tiny-sized electronics with. This one has a scanner-like design."
/obj/item/electronic_assembly/small/hook
name = "type-d electronic device"
icon_state = "setup_device_hook"
desc = "It's a case, for building tiny-sized electronics with. This one looks like it has a belt clip, but it's purely decorative."
/obj/item/electronic_assembly/small/box
name = "type-e electronic device"
icon_state = "setup_device_box"
desc = "It's a case, for building tiny-sized electronics with. This one has a boxy design."
/obj/item/electronic_assembly/small/dildo
name = "type-f electronic device"
icon_state = "setup_dildo_small"
desc = "It's a case, for building tiny-sized electronics with. This one has a phallic design."
/obj/item/electronic_assembly/medium
name = "electronic mechanism"
icon_state = "setup_medium"
desc = "It's a case, for building medium-sized electronics with."
w_class = WEIGHT_CLASS_NORMAL
max_components = IC_MAX_SIZE_BASE * 2
max_complexity = IC_COMPLEXITY_BASE * 2
/obj/item/electronic_assembly/medium/default
name = "type-a electronic mechanism"
/obj/item/electronic_assembly/medium/box
name = "type-b electronic mechanism"
icon_state = "setup_medium_box"
desc = "It's a case, for building medium-sized electronics with. This one has a boxy design."
/obj/item/electronic_assembly/medium/clam
name = "type-c electronic mechanism"
icon_state = "setup_medium_clam"
desc = "It's a case, for building medium-sized electronics with. This one has a clamshell design."
/obj/item/electronic_assembly/medium/medical
name = "type-d electronic mechanism"
icon_state = "setup_medium_med"
desc = "It's a case, for building medium-sized electronics with. This one resembles some type of medical apparatus."
/obj/item/electronic_assembly/medium/gun
name = "type-e electronic mechanism"
icon_state = "setup_medium_gun"
item_state = "circuitgun"
desc = "It's a case, for building medium-sized electronics with. This one resembles a gun, or some type of tool, if you're feeling optimistic. It can fire guns and throw items while the user is holding it."
lefthand_file = 'icons/mob/inhands/weapons/guns_lefthand.dmi'
righthand_file = 'icons/mob/inhands/weapons/guns_righthand.dmi'
can_fire_equipped = TRUE
/obj/item/electronic_assembly/medium/radio
name = "type-f electronic mechanism"
icon_state = "setup_medium_radio"
desc = "It's a case, for building medium-sized electronics with. This one resembles an old radio."
/obj/item/electronic_assembly/medium/dildo
name = "type-g electronic mechanism"
icon_state = "setup_dildo_large"
desc = "It's a case, for building medium-sized electronics with. This one has a phallic design."
/obj/item/electronic_assembly/large
name = "electronic machine"
icon_state = "setup_large"
desc = "It's a case, for building large electronics with."
w_class = WEIGHT_CLASS_BULKY
max_components = IC_MAX_SIZE_BASE * 4
max_complexity = IC_COMPLEXITY_BASE * 4
/obj/item/electronic_assembly/large/default
name = "type-a electronic machine"
/obj/item/electronic_assembly/large/scope
name = "type-b electronic machine"
icon_state = "setup_large_scope"
desc = "It's a case, for building large electronics with. This one resembles an oscilloscope."
/obj/item/electronic_assembly/large/terminal
name = "type-c electronic machine"
icon_state = "setup_large_terminal"
desc = "It's a case, for building large electronics with. This one resembles a computer terminal."
/obj/item/electronic_assembly/large/arm
name = "type-d electronic machine"
icon_state = "setup_large_arm"
desc = "It's a case, for building large electronics with. This one resembles a robotic arm."
/obj/item/electronic_assembly/large/tall
name = "type-e electronic machine"
icon_state = "setup_large_tall"
desc = "It's a case, for building large electronics with. This one has a tall design."
/obj/item/electronic_assembly/large/industrial
name = "type-f electronic machine"
icon_state = "setup_large_industrial"
desc = "It's a case, for building large electronics with. This one resembles some kind of industrial machinery."
/obj/item/electronic_assembly/drone
name = "electronic drone"
icon_state = "setup_drone"
desc = "It's a case, for building mobile electronics with."
w_class = WEIGHT_CLASS_BULKY
max_components = IC_MAX_SIZE_BASE * 3
max_complexity = IC_COMPLEXITY_BASE * 3
allowed_circuit_action_flags = IC_ACTION_MOVEMENT | IC_ACTION_COMBAT | IC_ACTION_LONG_RANGE
can_anchor = FALSE
/obj/item/electronic_assembly/drone/can_move()
return TRUE
/obj/item/electronic_assembly/drone/default
name = "type-a electronic drone"
/obj/item/electronic_assembly/drone/arms
name = "type-b electronic drone"
icon_state = "setup_drone_arms"
desc = "It's a case, for building mobile electronics with. This one is armed and dangerous."
/obj/item/electronic_assembly/drone/secbot
name = "type-c electronic drone"
icon_state = "setup_drone_secbot"
desc = "It's a case, for building mobile electronics with. This one resembles a Securitron."
/obj/item/electronic_assembly/drone/medbot
name = "type-d electronic drone"
icon_state = "setup_drone_medbot"
desc = "It's a case, for building mobile electronics with. This one resembles a Medibot."
/obj/item/electronic_assembly/drone/genbot
name = "type-e electronic drone"
icon_state = "setup_drone_genbot"
desc = "It's a case, for building mobile electronics with. This one has a generic bot design."
/obj/item/electronic_assembly/drone/android
name = "type-f electronic drone"
icon_state = "setup_drone_android"
desc = "It's a case, for building mobile electronics with. This one has a hominoid design."
/obj/item/electronic_assembly/wallmount
name = "wall-mounted electronic assembly"
icon_state = "setup_wallmount_medium"
desc = "It's a case, for building medium-sized electronics with. It has a magnetized backing to allow it to stick to walls, but you'll still need to wrench the anchoring bolts in place to keep it on."
w_class = WEIGHT_CLASS_NORMAL
max_components = IC_MAX_SIZE_BASE * 2
max_complexity = IC_COMPLEXITY_BASE * 2
/obj/item/electronic_assembly/wallmount/heavy
name = "heavy wall-mounted electronic assembly"
icon_state = "setup_wallmount_large"
desc = "It's a case, for building large electronics with. It has a magnetized backing to allow it to stick to walls, but you'll still need to wrench the anchoring bolts in place to keep it on."
w_class = WEIGHT_CLASS_BULKY
max_components = IC_MAX_SIZE_BASE * 4
max_complexity = IC_COMPLEXITY_BASE * 4
/obj/item/electronic_assembly/wallmount/light
name = "light wall-mounted electronic assembly"
icon_state = "setup_wallmount_small"
desc = "It's a case, for building small electronics with. It has a magnetized backing to allow it to stick to walls, but you'll still need to wrench the anchoring bolts in place to keep it on."
w_class = WEIGHT_CLASS_SMALL
max_components = IC_MAX_SIZE_BASE
max_complexity = IC_COMPLEXITY_BASE
/obj/item/electronic_assembly/wallmount/tiny
name = "tiny wall-mounted electronic assembly"
icon_state = "setup_wallmount_tiny"
desc = "It's a case, for building tiny electronics with. It has a magnetized backing to allow it to stick to walls, but you'll still need to wrench the anchoring bolts in place to keep it on."
w_class = WEIGHT_CLASS_TINY
max_components = IC_MAX_SIZE_BASE / 2
max_complexity = IC_COMPLEXITY_BASE / 2
/obj/item/electronic_assembly/wallmount/proc/mount_assembly(turf/on_wall, mob/user) //Yeah, this is admittedly just an abridged and kitbashed version of the wallframe attach procs.
if(get_dist(on_wall,user)>1)
return
var/ndir = get_dir(on_wall, user)
if(!(ndir in GLOB.cardinals))
return
var/turf/T = get_turf(user)
if(!isfloorturf(T))
to_chat(user, "<span class='warning'>You cannot place [src] on this spot!</span>")
return
if(gotwallitem(T, ndir))
to_chat(user, "<span class='warning'>There's already an item on this wall!</span>")
return
playsound(src.loc, 'sound/machines/click.ogg', 75, 1)
user.visible_message("[user.name] attaches [src] to the wall.",
"<span class='notice'>You attach [src] to the wall.</span>",
"<span class='italics'>You hear clicking.</span>")
user.dropItemToGround(src)
switch(ndir)
if(NORTH)
pixel_y = -31
if(SOUTH)
pixel_y = 31
if(EAST)
pixel_x = -31
if(WEST)
pixel_x = 31
@@ -0,0 +1,154 @@
// These pins contain a list. Null is not allowed.
/datum/integrated_io/lists
name = "list pin"
data = list()
/datum/integrated_io/lists/ask_for_pin_data(mob/user)
interact(user)
/datum/integrated_io/lists/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)];remove=1'>\[Remove\]</a> | "
t += "<a href='?src=[REF(src)];edit=1'>\[Edit\]</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>"
user << browse(t, "window=list_pin_[REF(src)];size=500x400")
/datum/integrated_io/lists/proc/add_to_list(mob/user, var/new_entry)
if(!new_entry && user)
new_entry = ask_for_data_type(user)
if(is_valid(new_entry))
Add(new_entry)
/datum/integrated_io/lists/proc/Add(var/new_entry)
var/list/my_list = data
if(my_list.len > IC_MAX_LIST_LENGTH)
my_list.Cut(Start=1,End=2)
my_list.Add(new_entry)
/datum/integrated_io/lists/proc/remove_from_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 remove.</span>")
return
if(!position)
return
var/target_entry = my_list[position]
if(target_entry)
my_list.Remove(target_entry)
/datum/integrated_io/lists/proc/remove_from_list(mob/user, var/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(user, "Which piece of data do you want to remove?", "Remove") as null|anything in my_list
if(holder.check_interactivity(user) && target_entry)
my_list.Remove(target_entry)
/datum/integrated_io/lists/proc/edit_in_list(mob/user, var/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(user, "Which piece of data do you want to edit?", "Edit") as null|anything in my_list
if(holder.check_interactivity(user) && target_entry)
var/edited_entry = ask_for_data_type(user, target_entry)
if(edited_entry)
my_list[my_list.Find(target_entry)] = edited_entry
/datum/integrated_io/lists/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[position]
if(target_entry)
var/edited_entry = ask_for_data_type(user, target_entry)
if(edited_entry)
my_list[position] = edited_entry
/datum/integrated_io/lists/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(user, "Which piece of data do you want to swap? (1)", "Swap") as null|anything in my_list
if(holder.check_interactivity(user) && first_target)
if(!second_target)
second_target = input(user, "Which piece of data do you want to swap? (2)", "Swap") as null|anything in my_list - first_target
if(holder.check_interactivity(user) && 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/lists/proc/clear_list(mob/user)
var/list/my_list = data
my_list.Cut()
/datum/integrated_io/lists/scramble()
var/list/my_list = data
my_list = shuffle(my_list)
push_data()
/datum/integrated_io/lists/write_data_to_pin(var/new_data)
if(islist(new_data))
var/list/new_list = new_data
data = new_list.Copy(max(1,new_list.len - IC_MAX_LIST_LENGTH+1),0)
holder.on_data_written()
else if(isnull(new_data)) // Clear the list
var/list/my_list = data
my_list.Cut()
holder.on_data_written()
/datum/integrated_io/lists/display_pin_type()
return IC_FORMAT_LIST
/datum/integrated_io/lists/Topic(href, href_list)
if(!holder.check_interactivity(usr))
return
if(..())
return TRUE
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,139 @@
/obj/item/integrated_circuit/passive/power
name = "power thingy"
desc = "Does power stuff."
complexity = 5
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 = "This cell generates 1 W of power in optimal lighting conditions. Less light will result in less power being generated."
icon_state = "solar_cell"
complexity = 8
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
var/max_power = 30
/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)
if(assembly)
assembly.give_power(adjusted_power)
/obj/item/integrated_circuit/passive/power/starter
name = "starter"
desc = "This tiny circuit will send a pulse right after the device is turned on, or when power is restored to it."
icon_state = "led"
complexity = 1
activators = list("pulse out" = IC_PINTYPE_PULSE_OUT)
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
var/is_charge = FALSE
/obj/item/integrated_circuit/passive/power/starter/make_energy()
if(assembly.battery)
if(assembly.battery.charge)
if(!is_charge)
activate_pin(1)
is_charge = TRUE
else
is_charge = FALSE
else
is_charge=FALSE
return FALSE
// 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 = WEIGHT_CLASS_SMALL
extended_desc = "The siphon drains 50 W of power from an APC in the same room as it as long as it has charge remaining. It will always drain \
from the 'equipment' power channel."
icon_state = "power_relay"
complexity = 7
spawn_flags = IC_SPAWN_RESEARCH
var/power_amount = 50
/obj/item/integrated_circuit/passive/power/relay/make_energy()
if(!assembly)
return
var/area/A = get_area(src)
if(A && A.powered(EQUIP) && assembly.give_power(power_amount))
A.use_power(power_amount, EQUIP)
// give_power() handles CELLRATE on its own.
// 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 industrial size!"
w_class = WEIGHT_CLASS_BULKY
extended_desc = "The siphon drains 2 kW of power from an APC in the same room as it as long as it has charge remaining. It will always drain \
from the 'equipment' power channel."
icon_state = "power_relay"
complexity = 15
spawn_flags = IC_SPAWN_RESEARCH
power_amount = 1000
//fuel cell
/obj/item/integrated_circuit/passive/power/chemical_cell
name = "fuel cell"
desc = "Produces electricity from chemicals."
icon_state = "chemical_cell"
extended_desc = "This is effectively an internal beaker. It will consume and produce power from plasma, slime jelly, welding fuel, carbon,\
ethanol, nutriment, and blood in order of decreasing efficiency. It will consume fuel only if the battery can take more energy."
complexity = 4
inputs = list()
outputs = list("volume used" = IC_PINTYPE_NUMBER, "self reference" = IC_PINTYPE_SELFREF)
activators = list("push ref" = IC_PINTYPE_PULSE_IN)
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
var/volume = 60
var/list/fuel = list("plasma" = 50000, "welding_fuel" = 15000, "carbon" = 10000, "ethanol" = 10000, "nutriment" = 8000)
var/multi = 1
var/lfwb =TRUE
/obj/item/integrated_circuit/passive/power/chemical_cell/Initialize()
..()
create_reagents(volume, OPENCONTAINER)
extended_desc +="But no fuel can be compared with blood of living human."
/obj/item/integrated_circuit/passive/power/chemical_cell/interact(mob/user)
set_pin_data(IC_OUTPUT, 2, WEAKREF(src))
push_data()
..()
/obj/item/integrated_circuit/passive/power/chemical_cell/on_reagent_change(changetype)
set_pin_data(IC_OUTPUT, 1, reagents.total_volume)
push_data()
/obj/item/integrated_circuit/passive/power/chemical_cell/make_energy()
if(assembly)
if(assembly.battery)
var/bp = 5000
if(reagents.get_reagent_amount("blood")) //only blood is powerful enough to power the station(c)
var/datum/reagent/blood/B = locate() in reagents.reagent_list
if(lfwb)
if(B && B.data["cloneable"])
var/mob/M = B.data["donor"]
if(M && (M.stat != DEAD) && (M.client))
bp = 500000
if((assembly.battery.maxcharge-assembly.battery.charge) / GLOB.CELLRATE > bp)
if(reagents.remove_reagent("blood", 1))
assembly.give_power(bp)
for(var/I in fuel)
if((assembly.battery.maxcharge-assembly.battery.charge) / GLOB.CELLRATE > fuel[I])
if(reagents.remove_reagent(I, 1))
assembly.give_power(fuel[I]*multi)
/obj/item/integrated_circuit/passive/power/chemical_cell/do_work()
set_pin_data(IC_OUTPUT, 2, WEAKREF(src))
push_data()
@@ -0,0 +1,760 @@
#define SOURCE_TO_TARGET 0
#define TARGET_TO_SOURCE 1
#define PUMP_EFFICIENCY 0.6
#define TANK_FAILURE_PRESSURE (ONE_ATMOSPHERE*25)
#define PUMP_MAX_VOLUME 100
/obj/item/integrated_circuit/atmospherics
category_text = "Atmospherics"
cooldown_per_use = 2 SECONDS
complexity = 10
size = 7
outputs = list(
"self reference" = IC_PINTYPE_SELFREF,
"pressure" = IC_PINTYPE_NUMBER
)
var/datum/gas_mixture/air_contents
var/volume = 2 //Pretty small, I know
/obj/item/integrated_circuit/atmospherics/Initialize()
air_contents = new(volume)
..()
/obj/item/integrated_circuit/atmospherics/return_air()
return air_contents
//Check if the gas container is adjacent and of the right type
/obj/item/integrated_circuit/atmospherics/proc/check_gassource(atom/gasholder)
if(!gasholder)
return FALSE
if(!gasholder.Adjacent(get_object()))
return FALSE
if(!istype(gasholder, /obj/item/tank) && !istype(gasholder, /obj/machinery/portable_atmospherics) && !istype(gasholder, /obj/item/integrated_circuit/atmospherics))
return FALSE
return TRUE
//Needed in circuits where source and target types differ
/obj/item/integrated_circuit/atmospherics/proc/check_gastarget(atom/gasholder)
return check_gassource(gasholder)
// - gas pump - // **works**
/obj/item/integrated_circuit/atmospherics/pump
name = "gas pump"
desc = "Somehow moves gases between two tanks, canisters, and other gas containers."
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
inputs = list(
"source" = IC_PINTYPE_REF,
"target" = IC_PINTYPE_REF,
"target pressure" = IC_PINTYPE_NUMBER
)
activators = list(
"transfer" = IC_PINTYPE_PULSE_IN,
"on transfer" = IC_PINTYPE_PULSE_OUT
)
var/direction = SOURCE_TO_TARGET
var/target_pressure = PUMP_MAX_PRESSURE
power_draw_per_use = 20
/obj/item/integrated_circuit/atmospherics/pump/Initialize()
air_contents = new(volume)
extended_desc += " Use negative pressure to move air from target to source. \
Note that only part of the gas is moved on each transfer, \
so multiple activations will be necessary to achieve target pressure. \
The pressure limit for circuit pumps is [round(PUMP_MAX_PRESSURE)] kPa."
. = ..()
// This proc gets the direction of the gas flow depending on its value, by calling update target
/obj/item/integrated_circuit/atmospherics/pump/on_data_written()
var/amt = get_pin_data(IC_INPUT, 3)
update_target(amt)
/obj/item/integrated_circuit/atmospherics/pump/proc/update_target(new_amount)
if(!isnum(new_amount))
new_amount = 0
// See in which direction the gas moves
if(new_amount < 0)
direction = TARGET_TO_SOURCE
else
direction = SOURCE_TO_TARGET
target_pressure = min(round(PUMP_MAX_PRESSURE),abs(new_amount))
/obj/item/integrated_circuit/atmospherics/pump/do_work()
var/obj/source = get_pin_data_as_type(IC_INPUT, 1, /obj)
var/obj/target = get_pin_data_as_type(IC_INPUT, 2, /obj)
perform_magic(source, target)
activate_pin(2)
/obj/item/integrated_circuit/atmospherics/pump/proc/perform_magic(atom/source, atom/target)
//Check if both atoms are of the right type: atmos circuits/gas tanks/canisters. If one is the same, use the circuit var
if(!check_gassource(source))
source = src
if(!check_gastarget(target))
target = src
// If both are the same, this whole proc would do nothing and just waste performance
if(source == target)
return
var/datum/gas_mixture/source_air = source.return_air()
var/datum/gas_mixture/target_air = target.return_air()
if(!source_air || !target_air)
return
// Swapping both source and target
if(direction == TARGET_TO_SOURCE)
var/temp = source_air
source_air = target_air
target_air = temp
// If what you are pumping is empty, use the circuit's storage
if(source_air.total_moles() <= 0)
source_air = air_contents
// Move gas from one place to another
move_gas(source_air, target_air)
air_update_turf()
/obj/item/integrated_circuit/atmospherics/pump/proc/move_gas(datum/gas_mixture/source_air, datum/gas_mixture/target_air)
// No moles = nothing to pump
if(source_air.total_moles() <= 0 || target_air.return_pressure() >= PUMP_MAX_PRESSURE)
return
// Negative Kelvin temperatures should never happen and if they do, normalize them
if(source_air.temperature < TCMB)
source_air.temperature = TCMB
var/pressure_delta = target_pressure - target_air.return_pressure()
if(pressure_delta > 0.1)
var/transfer_moles = (pressure_delta*target_air.volume/(source_air.temperature * R_IDEAL_GAS_EQUATION))*PUMP_EFFICIENCY
var/datum/gas_mixture/removed = source_air.remove(transfer_moles)
target_air.merge(removed)
// - volume pump - // **Works**
/obj/item/integrated_circuit/atmospherics/pump/volume
name = "volume pump"
desc = "Moves gases between two tanks, canisters, and other gas containers by using their volume, up to 200 L/s."
extended_desc = " Use negative volume to move air from target to source. Note that only part of the gas is moved on each transfer. Its maximum pumping volume is capped at 1000kPa."
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
inputs = list(
"source" = IC_PINTYPE_REF,
"target" = IC_PINTYPE_REF,
"transfer volume" = IC_PINTYPE_NUMBER
)
activators = list(
"transfer" = IC_PINTYPE_PULSE_IN,
"on transfer" = IC_PINTYPE_PULSE_OUT
)
direction = SOURCE_TO_TARGET
var/transfer_rate = PUMP_MAX_VOLUME
power_draw_per_use = 20
/obj/item/integrated_circuit/atmospherics/pump/volume/update_target(new_amount)
if(!isnum(new_amount))
new_amount = 0
// See in which direction the gas moves
if(new_amount < 0)
direction = TARGET_TO_SOURCE
else
direction = SOURCE_TO_TARGET
target_pressure = min(PUMP_MAX_VOLUME,abs(new_amount))
/obj/item/integrated_circuit/atmospherics/pump/volume/move_gas(datum/gas_mixture/source_air, datum/gas_mixture/target_air)
// No moles = nothing to pump
if(source_air.total_moles() <= 0)
return
// Negative Kelvin temperatures should never happen and if they do, normalize them
if(source_air.temperature < TCMB)
source_air.temperature = TCMB
if((source_air.return_pressure() < 0.01) || (target_air.return_pressure() >= PUMP_MAX_PRESSURE))
return
//The second part of the min caps the pressure built by the volume pumps to the max pump pressure
var/transfer_ratio = min(transfer_rate,target_air.volume*PUMP_MAX_PRESSURE/source_air.return_pressure())/source_air.volume
var/datum/gas_mixture/removed = source_air.remove_ratio(transfer_ratio * PUMP_EFFICIENCY)
target_air.merge(removed)
// - gas vent - // **works**
/obj/item/integrated_circuit/atmospherics/pump/vent
name = "gas vent"
extended_desc = "Use negative volume to move air from target to environment. Note that only part of the gas is moved on each transfer. Unlike the gas pump, this one keeps pumping even further to pressures of 9000 pKa and it is not advised to use it on tank circuits."
desc = "Moves gases between the environment and adjacent gas containers."
inputs = list(
"container" = IC_PINTYPE_REF,
"target pressure" = IC_PINTYPE_NUMBER
)
/obj/item/integrated_circuit/atmospherics/pump/vent/on_data_written()
var/amt = get_pin_data(IC_INPUT, 2)
update_target(amt)
/obj/item/integrated_circuit/atmospherics/pump/vent/do_work()
var/turf/source = get_turf(src)
var/obj/target = get_pin_data_as_type(IC_INPUT, 1, /obj)
perform_magic(source, target)
activate_pin(2)
/obj/item/integrated_circuit/atmospherics/pump/vent/check_gastarget(atom/gasholder)
if(!gasholder)
return FALSE
if(!gasholder.Adjacent(get_object()))
return FALSE
if(!istype(gasholder, /obj/item/tank) && !istype(gasholder, /obj/machinery/portable_atmospherics) && !istype(gasholder, /obj/item/integrated_circuit/atmospherics))
return FALSE
return TRUE
/obj/item/integrated_circuit/atmospherics/pump/vent/check_gassource(atom/target)
if(!target)
return FALSE
if(!istype(target, /turf))
return FALSE
return TRUE
// - integrated connector - // Can connect and disconnect properly
/obj/item/integrated_circuit/atmospherics/connector
name = "integrated connector"
desc = "Creates an airtight seal with standard connectors found on the floor, \
allowing the assembly to exchange gases with a pipe network."
extended_desc = "This circuit will automatically attempt to locate and connect to ports on the floor beneath it when activated. \
You <b>must</b> set a target before connecting."
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
inputs = list(
"target" = IC_PINTYPE_REF
)
activators = list(
"toggle connection" = IC_PINTYPE_PULSE_IN,
"on connected" = IC_PINTYPE_PULSE_OUT,
"on connection failed" = IC_PINTYPE_PULSE_OUT,
"on disconnected" = IC_PINTYPE_PULSE_OUT
)
var/obj/machinery/atmospherics/components/unary/portables_connector/connector
/obj/item/integrated_circuit/atmospherics/connector/Initialize()
air_contents = new(volume)
START_PROCESSING(SSobj, src)
. = ..()
//Sucks up the gas from the connector
/obj/item/integrated_circuit/atmospherics/connector/process()
set_pin_data(IC_OUTPUT, 2, air_contents.return_pressure())
/obj/item/integrated_circuit/atmospherics/connector/check_gassource(atom/gasholder)
if(!gasholder)
return FALSE
if(!istype(gasholder,/obj/machinery/atmospherics/components/unary/portables_connector))
return FALSE
return TRUE
//If the assembly containing this is moved from the tile the connector pipe is in, the connection breaks
/obj/item/integrated_circuit/atmospherics/connector/ext_moved()
if(connector)
if(get_dist(get_object(), connector) > 0)
// The assembly is set as connected device and the connector handles the rest
connector.connected_device = null
connector = null
activate_pin(4)
/obj/item/integrated_circuit/atmospherics/connector/do_work()
// If there is a connection, disconnect
if(connector)
connector.connected_device = null
connector = null
activate_pin(4)
return
var/obj/machinery/atmospherics/components/unary/portables_connector/PC = locate() in get_turf(src)
// If no connector can't connect
if(!PC)
activate_pin(3)
return
connector = PC
connector.connected_device = src
activate_pin(2)
// Required for making the connector port script work
obj/item/integrated_circuit/atmospherics/connector/portableConnectorReturnAir()
return air_contents
// - gas filter - // **works**
/obj/item/integrated_circuit/atmospherics/pump/filter
name = "gas filter"
desc = "Filters one gas out of a mixture."
complexity = 20
size = 8
spawn_flags = IC_SPAWN_RESEARCH
inputs = list(
"source" = IC_PINTYPE_REF,
"filtered output" = IC_PINTYPE_REF,
"contaminants output" = IC_PINTYPE_REF,
"wanted gases" = IC_PINTYPE_LIST,
"target pressure" = IC_PINTYPE_NUMBER
)
power_draw_per_use = 30
/obj/item/integrated_circuit/atmospherics/pump/filter/on_data_written()
var/amt = get_pin_data(IC_INPUT, 5)
target_pressure = CLAMP(amt, 0, PUMP_MAX_PRESSURE)
/obj/item/integrated_circuit/atmospherics/pump/filter/do_work()
activate_pin(2)
var/obj/source = get_pin_data_as_type(IC_INPUT, 1, /obj)
var/obj/filtered = get_pin_data_as_type(IC_INPUT, 2, /obj)
var/obj/contaminants = get_pin_data_as_type(IC_INPUT, 3, /obj)
var/wanted = get_pin_data(IC_INPUT, 4)
// If there is no filtered output, this whole thing makes no sense
if(!check_gassource(filtered))
return
var/datum/gas_mixture/filtered_air = filtered.return_air()
if(!filtered_air)
return
// If no source is set, the source is possibly this circuit's content
if(!check_gassource(source))
source = src
var/datum/gas_mixture/source_air = source.return_air()
//No source air: source is this circuit
if(!source_air)
source_air = air_contents
// If no filtering tank is set, filter through itself
if(!check_gassource(contaminants))
contaminants = src
var/datum/gas_mixture/contaminated_air = contaminants.return_air()
//If there is no gas mixture datum for unfiltered, pump the contaminants back into the circuit
if(!contaminated_air)
contaminated_air = air_contents
if(contaminated_air.return_pressure() >= PUMP_MAX_PRESSURE || filtered_air.return_pressure() >= PUMP_MAX_PRESSURE)
return
var/pressure_delta = target_pressure - contaminated_air.return_pressure()
var/transfer_moles
//Negative Kelvins are an anomaly and should be normalized if encountered
if(source_air.temperature < TCMB)
source_air.temperature = TCMB
transfer_moles = (pressure_delta*contaminated_air.volume/(source_air.temperature * R_IDEAL_GAS_EQUATION))*PUMP_EFFICIENCY
//If there is nothing to transfer, just return
if(transfer_moles <= 0)
return
//This is the var that holds the currently filtered part of the gas
var/datum/gas_mixture/removed = source_air.remove(transfer_moles)
if(!removed)
return
//This is the gas that will be moved from source to filtered
var/datum/gas_mixture/filtered_out = new
for(var/filtered_gas in removed.gases)
//Get the name of the gas and see if it is in the list
if(GLOB.meta_gas_names[filtered_gas] in wanted)
//The gas that is put in all the filtered out gases
filtered_out.temperature = removed.temperature
filtered_out.gases[filtered_gas] = removed.gases[filtered_gas]
//The filtered out gas is entirely removed from the currently filtered gases
removed.gases[filtered_gas] = 0
GAS_GARBAGE_COLLECT(removed.gases)
//Check if the pressure is high enough to put stuff in filtered, or else just put it back in the source
var/datum/gas_mixture/target = (filtered_air.return_pressure() < target_pressure ? filtered_air : source_air)
target.merge(filtered_out)
contaminated_air.merge(removed)
/obj/item/integrated_circuit/atmospherics/pump/filter/Initialize()
air_contents = new(volume)
. = ..()
extended_desc = "Remember to properly spell and capitalize the filtered gas name. \
Note that only part of the gas is moved on each transfer, \
so multiple activations will be necessary to achieve target pressure. \
The pressure limit for circuit pumps is [round(PUMP_MAX_PRESSURE)] kPa."
// - gas mixer - // **works**
/obj/item/integrated_circuit/atmospherics/pump/mixer
name = "gas mixer"
desc = "Mixes 2 different types of gases."
complexity = 20
size = 8
spawn_flags = IC_SPAWN_RESEARCH
inputs = list(
"first source" = IC_PINTYPE_REF,
"second source" = IC_PINTYPE_REF,
"output" = IC_PINTYPE_REF,
"first source percentage" = IC_PINTYPE_NUMBER,
"target pressure" = IC_PINTYPE_NUMBER
)
power_draw_per_use = 30
/obj/item/integrated_circuit/atmospherics/pump/mixer/do_work()
activate_pin(2)
var/obj/source_1 = get_pin_data(IC_INPUT, 1)
var/obj/source_2 = get_pin_data(IC_INPUT, 2)
var/obj/gas_output = get_pin_data(IC_INPUT, 3)
if(!check_gassource(source_1))
source_1 = src
if(!check_gassource(source_2))
source_2 = src
if(!check_gassource(gas_output))
gas_output = src
if(source_1 == gas_output || source_2 == gas_output)
return
var/datum/gas_mixture/source_1_gases = source_1.return_air()
var/datum/gas_mixture/source_2_gases = source_2.return_air()
var/datum/gas_mixture/output_gases = gas_output.return_air()
if(!source_1_gases || !source_2_gases || !output_gases)
return
if(output_gases.return_pressure() >= PUMP_MAX_PRESSURE)
return
if(source_1_gases.return_pressure() <= 0 || source_2_gases.return_pressure() <= 0)
return
//This calculates how much should be sent
var/gas_percentage = round(max(min(get_pin_data(IC_INPUT, 4),100),0) / 100)
//Basically: number of moles = percentage of pressure filled up * efficiency coefficient * (pressure from both gases * volume of output) / (R * Temperature)
var/transfer_moles = (get_pin_data(IC_INPUT, 5) / max(1,output_gases.return_pressure())) * PUMP_EFFICIENCY * (source_1_gases.return_pressure() * gas_percentage + source_2_gases.return_pressure() * (1 - gas_percentage)) * output_gases.volume/ (R_IDEAL_GAS_EQUATION * max(output_gases.temperature,TCMB))
if(transfer_moles <= 0)
return
var/datum/gas_mixture/mix = source_1_gases.remove(transfer_moles * gas_percentage)
output_gases.merge(mix)
mix = source_2_gases.remove(transfer_moles * (1-gas_percentage))
output_gases.merge(mix)
// - integrated tank - // **works**
/obj/item/integrated_circuit/atmospherics/tank
name = "integrated tank"
desc = "A small tank for the storage of gases."
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
size = 4
activators = list(
"push ref" = IC_PINTYPE_PULSE_IN
)
volume = 3 //emergency tank sized
var/broken = FALSE
/obj/item/integrated_circuit/atmospherics/tank/Initialize()
air_contents = new(volume)
START_PROCESSING(SSobj, src)
extended_desc = "Take care not to pressurize it above [round(TANK_FAILURE_PRESSURE)] kPa, or else it will break."
. = ..()
/obj/item/integrated_circuit/atmospherics/tank/Destroy()
STOP_PROCESSING(SSobj, src)
. = ..()
/obj/item/integrated_circuit/atmospherics/tank/do_work()
set_pin_data(IC_OUTPUT, 1, WEAKREF(src))
push_data()
/obj/item/integrated_circuit/atmospherics/tank/process()
var/tank_pressure = air_contents.return_pressure()
set_pin_data(IC_OUTPUT, 2, tank_pressure)
push_data()
//Check if tank broken
if(!broken && tank_pressure > TANK_FAILURE_PRESSURE)
broken = TRUE
to_chat(view(2),"<span class='notice'>The [name] ruptures, releasing its gases!</span>")
if(broken)
release()
/obj/item/integrated_circuit/atmospherics/tank/proc/release()
if(air_contents.total_moles() > 0)
playsound(loc, 'sound/effects/spray.ogg', 10, 1, -3)
var/datum/gas_mixture/expelled_gas = air_contents.remove(air_contents.total_moles())
var/turf/current_turf = get_turf(src)
var/datum/gas_mixture/exterior_gas
if(!current_turf)
return
exterior_gas = current_turf.return_air()
exterior_gas.merge(expelled_gas)
// - large integrated tank - // **works**
/obj/item/integrated_circuit/atmospherics/tank/large
name = "large integrated tank"
desc = "A less small tank for the storage of gases."
volume = 9
size = 12
spawn_flags = IC_SPAWN_RESEARCH
// - freezer tank - // **works**
/obj/item/integrated_circuit/atmospherics/tank/freezer
name = "freezer tank"
desc = "Cools the gas it contains to a preset temperature."
volume = 6
size = 8
inputs = list(
"target temperature" = IC_PINTYPE_NUMBER,
"on" = IC_PINTYPE_BOOLEAN
)
inputs_default = list("1" = 300)
spawn_flags = IC_SPAWN_RESEARCH
var/temperature = 293.15
var/heater_coefficient = 0.1
/obj/item/integrated_circuit/atmospherics/tank/freezer/on_data_written()
temperature = max(73.15,min(293.15,get_pin_data(IC_INPUT, 1)))
if(get_pin_data(IC_INPUT, 2))
power_draw_idle = 30
else
power_draw_idle = 0
/obj/item/integrated_circuit/atmospherics/tank/freezer/process()
var/tank_pressure = air_contents.return_pressure()
set_pin_data(IC_OUTPUT, 2, tank_pressure)
push_data()
//Cool the tank if the power is on and the temp is above
if(!power_draw_idle || air_contents.temperature < temperature)
return
air_contents.temperature = max(73.15,air_contents.temperature - (air_contents.temperature - temperature) * heater_coefficient)
// - heater tank - // **works**
/obj/item/integrated_circuit/atmospherics/tank/freezer/heater
name = "heater tank"
desc = "Heats the gas it contains to a preset temperature."
volume = 6
inputs = list(
"target temperature" = IC_PINTYPE_NUMBER,
"on" = IC_PINTYPE_BOOLEAN
)
spawn_flags = IC_SPAWN_RESEARCH
/obj/item/integrated_circuit/atmospherics/tank/freezer/heater/on_data_written()
temperature = max(293.15,min(573.15,get_pin_data(IC_INPUT, 1)))
if(get_pin_data(IC_INPUT, 2))
power_draw_idle = 30
else
power_draw_idle = 0
/obj/item/integrated_circuit/atmospherics/tank/freezer/heater/process()
var/tank_pressure = air_contents.return_pressure()
set_pin_data(IC_OUTPUT, 2, tank_pressure)
push_data()
//Heat the tank if the power is on or its temperature is below what is set
if(!power_draw_idle || air_contents.temperature > temperature)
return
air_contents.temperature = min(573.15,air_contents.temperature + (temperature - air_contents.temperature) * heater_coefficient)
// - atmospheric cooler - // **works**
/obj/item/integrated_circuit/atmospherics/cooler
name = "atmospheric cooler circuit"
desc = "Cools the air around it."
volume = 6
size = 13
spawn_flags = IC_SPAWN_RESEARCH
inputs = list(
"target temperature" = IC_PINTYPE_NUMBER,
"on" = IC_PINTYPE_BOOLEAN
)
var/temperature = 293.15
var/heater_coefficient = 0.1
/obj/item/integrated_circuit/atmospherics/cooler/Initialize()
air_contents = new(volume)
START_PROCESSING(SSobj, src)
. = ..()
/obj/item/integrated_circuit/atmospherics/cooler/Destroy()
STOP_PROCESSING(SSobj, src)
. = ..()
/obj/item/integrated_circuit/atmospherics/cooler/on_data_written()
temperature = max(243.15,min(293.15,get_pin_data(IC_INPUT, 1)))
if(get_pin_data(IC_INPUT, 2))
power_draw_idle = 30
else
power_draw_idle = 0
/obj/item/integrated_circuit/atmospherics/cooler/process()
set_pin_data(IC_OUTPUT, 2, air_contents.return_pressure())
push_data()
//Get the turf you're on and its gas mixture
var/turf/current_turf = get_turf(src)
if(!current_turf)
return
var/datum/gas_mixture/turf_air = current_turf.return_air()
if(!power_draw_idle || turf_air.temperature < temperature)
return
//Cool the gas
turf_air.temperature = max(243.15,turf_air.temperature - (turf_air.temperature - temperature) * heater_coefficient)
// - atmospheric heater - // **works**
/obj/item/integrated_circuit/atmospherics/cooler/heater
name = "atmospheric heater circuit"
desc = "Heats the air around it."
/obj/item/integrated_circuit/atmospherics/cooler/heater/on_data_written()
temperature = max(293.15,min(323.15,get_pin_data(IC_INPUT, 1)))
if(get_pin_data(IC_INPUT, 2))
power_draw_idle = 30
else
power_draw_idle = 0
/obj/item/integrated_circuit/atmospherics/cooler/heater/process()
set_pin_data(IC_OUTPUT, 2, air_contents.return_pressure())
push_data()
//Get the turf and its air mixture
var/turf/current_turf = get_turf(src)
if(!current_turf)
return
var/datum/gas_mixture/turf_air = current_turf.return_air()
if(!power_draw_idle || turf_air.temperature > temperature)
return
//Heat the gas
turf_air.temperature = min(323.15,turf_air.temperature + (temperature - turf_air.temperature) * heater_coefficient)
// - tank slot - // **works**
/obj/item/integrated_circuit/input/tank_slot
category_text = "Atmospherics"
cooldown_per_use = 1
name = "tank slot"
desc = "Lets you add a tank to your assembly and remove it even when the assembly is closed."
extended_desc = "It can help you extract gases easier."
complexity = 25
size = 30
inputs = list()
outputs = list(
"pressure used" = IC_PINTYPE_NUMBER,
"current tank" = IC_PINTYPE_REF
)
activators = list(
"push ref" = IC_PINTYPE_PULSE_IN,
"on insert" = IC_PINTYPE_PULSE_OUT,
"on remove" = IC_PINTYPE_PULSE_OUT
)
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
can_be_asked_input = TRUE
demands_object_input = TRUE
can_input_object_when_closed = TRUE
var/obj/item/tank/internals/current_tank
/obj/item/integrated_circuit/input/tank_slot/Initialize()
START_PROCESSING(SSobj, src)
. = ..()
/obj/item/integrated_circuit/input/tank_slot/process()
push_pressure()
/obj/item/integrated_circuit/input/tank_slot/attackby(var/obj/item/tank/internals/I, var/mob/living/user)
//Check if it truly is a tank
if(!istype(I,/obj/item/tank/internals))
to_chat(user,"<span class='warning'>The [I.name] doesn't seem to fit in here.</span>")
return
//Check if there is no other tank already inside
if(current_tank)
to_chat(user,"<span class='warning'>There is already a gas tank inside.</span>")
return
//The current tank is the one we just attached, its location is inside the circuit
current_tank = I
user.transferItemToLoc(I,src)
to_chat(user,"<span class='warning'>You put the [I.name] inside the tank slot.</span>")
//Set the pin to a weak reference of the current tank
push_pressure()
set_pin_data(IC_OUTPUT, 2, WEAKREF(current_tank))
push_data()
do_work(1)
/obj/item/integrated_circuit/input/tank_slot/ask_for_input(mob/user)
attack_self(user)
/obj/item/integrated_circuit/input/tank_slot/attack_self(mob/user)
//Check if no tank attached
if(!current_tank)
to_chat(user, "<span class='notice'>There is currently no tank attached.</span>")
return
//Remove tank and put in user's hands/location
to_chat(user, "<span class='notice'>You take [current_tank] out of the tank slot.</span>")
user.put_in_hands(current_tank)
current_tank = null
//Remove tank reference
push_pressure()
set_pin_data(IC_OUTPUT, 2, null)
push_data()
do_work(2)
/obj/item/integrated_circuit/input/tank_slot/do_work()
set_pin_data(IC_OUTPUT, 2, WEAKREF(current_tank))
push_data()
/obj/item/integrated_circuit/input/tank_slot/proc/push_pressure()
if(!current_tank)
set_pin_data(IC_OUTPUT, 1, 0)
return
var/datum/gas_mixture/tank_air = current_tank.return_air()
if(!tank_air)
set_pin_data(IC_OUTPUT, 1, 0)
return
set_pin_data(IC_OUTPUT, 1, tank_air.return_pressure())
push_data()
#undef SOURCE_TO_TARGET
#undef TARGET_TO_SOURCE
#undef PUMP_EFFICIENCY
#undef TANK_FAILURE_PRESSURE
#undef PUMP_MAX_PRESSURE
#undef PUMP_MAX_VOLUME
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,612 @@
/obj/item/integrated_circuit/manipulation
category_text = "Manipulation"
/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 one step 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; only drone assemblies can move."
w_class = WEIGHT_CLASS_SMALL
complexity = 10
cooldown_per_use = 1
ext_cooldown = 2
inputs = list("direction" = IC_PINTYPE_DIR)
outputs = list("obstacle" = IC_PINTYPE_REF)
activators = list("step towards dir" = IC_PINTYPE_PULSE_IN,"on step"=IC_PINTYPE_PULSE_OUT,"blocked"=IC_PINTYPE_PULSE_OUT)
spawn_flags = IC_SPAWN_RESEARCH
action_flags = IC_ACTION_MOVEMENT
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))
if(step(assembly, wanted_dir.data))
activate_pin(2)
return
else
set_pin_data(IC_OUTPUT, 1, WEAKREF(assembly.collw))
push_data()
activate_pin(3)
return FALSE
return FALSE
/obj/item/integrated_circuit/manipulation/plant_module
name = "plant manipulation module"
desc = "Used to uproot weeds and harvest/plant trays."
icon_state = "plant_m"
extended_desc = "The circuit accepts a reference to a hydroponic tray or an item on an adjacent tile. \
Mode input (0-harvest, 1-uproot weeds, 2-uproot plant, 3-plant seed) determines action. \
Harvesting outputs a list of the harvested plants."
w_class = WEIGHT_CLASS_TINY
complexity = 10
inputs = list("tray" = IC_PINTYPE_REF,"mode" = IC_PINTYPE_NUMBER,"item" = IC_PINTYPE_REF)
outputs = list("result" = IC_PINTYPE_LIST)
activators = list("pulse in" = IC_PINTYPE_PULSE_IN,"pulse out" = IC_PINTYPE_PULSE_OUT)
spawn_flags = IC_SPAWN_RESEARCH
power_draw_per_use = 50
/obj/item/integrated_circuit/manipulation/plant_module/do_work()
..()
var/obj/acting_object = get_object()
var/obj/OM = get_pin_data_as_type(IC_INPUT, 1, /obj)
var/obj/O = get_pin_data_as_type(IC_INPUT, 3, /obj/item)
if(!check_target(OM))
push_data()
activate_pin(2)
return
if(istype(OM,/obj/structure/spacevine) && check_target(OM) && get_pin_data(IC_INPUT, 2) == 2)
qdel(OM)
push_data()
activate_pin(2)
return
var/obj/machinery/hydroponics/TR = OM
if(istype(TR))
switch(get_pin_data(IC_INPUT, 2))
if(0)
var/list/harvest_output = TR.attack_hand()
for(var/i in 1 to length(harvest_output))
harvest_output[i] = WEAKREF(harvest_output[i])
if(harvest_output.len)
set_pin_data(IC_OUTPUT, 1, harvest_output)
push_data()
if(1)
TR.weedlevel = 0
TR.update_icon()
if(2)
if(TR.myseed) //Could be that they're just using it as a de-weeder
TR.age = 0
TR.plant_health = 0
if(TR.harvest)
TR.harvest = FALSE //To make sure they can't just put in another seed and insta-harvest it
qdel(TR.myseed)
TR.myseed = null
TR.weedlevel = 0 //Has a side effect of cleaning up those nasty weeds
TR.dead = 0
TR.update_icon()
if(3)
if(!check_target(O))
activate_pin(2)
return FALSE
else if(istype(O, /obj/item/seeds) && !istype(O, /obj/item/seeds/sample))
if(!TR.myseed)
if(istype(O, /obj/item/seeds/kudzu))
investigate_log("had Kudzu planted in it by [acting_object] at [AREACOORD(src)]","kudzu")
acting_object.visible_message("<span class='notice'>[acting_object] plants [O].</span>")
TR.dead = 0
TR.myseed = O
TR.age = 1
TR.plant_health = TR.myseed.endurance
TR.lastcycle = world.time
O.forceMove(TR)
TR.update_icon()
activate_pin(2)
/obj/item/integrated_circuit/manipulation/seed_extractor
name = "seed extractor module"
desc = "Used to extract seeds from grown produce."
icon_state = "plant_m"
extended_desc = "The circuit accepts a reference to a plant item and extracts seeds from it, outputting the results to a list."
complexity = 8
inputs = list("target" = IC_PINTYPE_REF)
outputs = list("result" = IC_PINTYPE_LIST)
activators = list("pulse in" = IC_PINTYPE_PULSE_IN,"pulse out" = IC_PINTYPE_PULSE_OUT)
spawn_flags = IC_SPAWN_RESEARCH
power_draw_per_use = 50
/obj/item/integrated_circuit/manipulation/seed_extractor/do_work()
..()
var/obj/O = get_pin_data_as_type(IC_INPUT, 1, /obj/item)
if(!check_target(O))
push_data()
activate_pin(2)
return
var/list/seed_output = seedify(O, -1)
for(var/i in 1 to length(seed_output))
seed_output[i] = WEAKREF(seed_output[i])
if(seed_output.len)
set_pin_data(IC_OUTPUT, 1, seed_output)
push_data()
activate_pin(2)
/obj/item/integrated_circuit/manipulation/grabber
name = "grabber"
desc = "A circuit with its own inventory for items. Used to grab and store things."
icon_state = "grabber"
extended_desc = "This circuit accepts a reference to an object to be grabbed, and can store up to 10 objects. Modes: 1 to grab, 0 to eject the first object, -1 to eject all objects, and -2 to eject the target. If you throw something from a grabber's inventory with a thrower, the grabber will update its outputs accordingly."
w_class = WEIGHT_CLASS_SMALL
size = 3
cooldown_per_use = 5
complexity = 10
inputs = list("target" = IC_PINTYPE_REF,"mode" = IC_PINTYPE_NUMBER)
outputs = list("first" = IC_PINTYPE_REF, "last" = IC_PINTYPE_REF, "amount" = IC_PINTYPE_NUMBER,"contents" = IC_PINTYPE_LIST)
activators = list("pulse in" = IC_PINTYPE_PULSE_IN,"pulse out" = IC_PINTYPE_PULSE_OUT)
spawn_flags = IC_SPAWN_RESEARCH
action_flags = IC_ACTION_COMBAT
power_draw_per_use = 50
var/max_items = 10
/obj/item/integrated_circuit/manipulation/grabber/do_work()
var/obj/item/AM = get_pin_data_as_type(IC_INPUT, 1, /obj/item)
if(!QDELETED(AM) && !istype(AM, /obj/item/electronic_assembly) && !istype(AM, /obj/item/transfer_valve) && !istype(AM, /obj/item/twohanded) && !istype(assembly.loc, /obj/item/implant/storage))
var/mode = get_pin_data(IC_INPUT, 2)
switch(mode)
if(1)
grab(AM)
if(0)
if(contents.len)
drop(contents[1])
if(-1)
drop_all()
if(-2)
drop(AM)
update_outputs()
activate_pin(2)
/obj/item/integrated_circuit/manipulation/grabber/proc/grab(obj/item/AM)
var/max_w_class = assembly.w_class
if(check_target(AM))
if(contents.len < max_items && AM.w_class <= max_w_class)
var/atom/A = get_object()
A.investigate_log("picked up ([AM]) with [src].", INVESTIGATE_CIRCUIT)
AM.forceMove(src)
/obj/item/integrated_circuit/manipulation/grabber/proc/drop(obj/item/AM, turf/T = drop_location())
var/atom/A = get_object()
A.investigate_log("dropped ([AM]) from [src].", INVESTIGATE_CIRCUIT)
AM.forceMove(T)
/obj/item/integrated_circuit/manipulation/grabber/proc/drop_all()
if(contents.len)
var/turf/T = drop_location()
var/obj/item/U
for(U in src)
drop(U, T)
/obj/item/integrated_circuit/manipulation/grabber/proc/update_outputs()
if(contents.len)
set_pin_data(IC_OUTPUT, 1, WEAKREF(contents[1]))
set_pin_data(IC_OUTPUT, 2, WEAKREF(contents[contents.len]))
else
set_pin_data(IC_OUTPUT, 1, null)
set_pin_data(IC_OUTPUT, 2, null)
set_pin_data(IC_OUTPUT, 3, contents.len)
set_pin_data(IC_OUTPUT, 4, contents)
push_data()
/obj/item/integrated_circuit/manipulation/grabber/attack_self(var/mob/user)
drop_all()
update_outputs()
push_data()
/obj/item/integrated_circuit/manipulation/claw
name = "pulling claw"
desc = "Circuit which can pull things.."
icon_state = "pull_claw"
extended_desc = "This circuit accepts a reference to a thing to be pulled. Modes: 0 for release. 1 for pull."
w_class = WEIGHT_CLASS_SMALL
size = 3
cooldown_per_use = 5
complexity = 10
inputs = list("target" = IC_PINTYPE_REF,"mode" = IC_PINTYPE_INDEX,"dir" = IC_PINTYPE_DIR)
outputs = list("is pulling" = IC_PINTYPE_BOOLEAN)
activators = list("pulse in" = IC_PINTYPE_PULSE_IN,"pulse out" = IC_PINTYPE_PULSE_OUT,"released" = IC_PINTYPE_PULSE_OUT,"pull to dir" = IC_PINTYPE_PULSE_OUT)
spawn_flags = IC_SPAWN_RESEARCH
power_draw_per_use = 50
ext_cooldown = 1
var/max_grab = GRAB_PASSIVE
/obj/item/integrated_circuit/manipulation/claw/do_work(ord)
var/obj/acting_object = get_object()
var/atom/movable/AM = get_pin_data_as_type(IC_INPUT, 1, /atom/movable)
var/mode = get_pin_data(IC_INPUT, 2)
switch(ord)
if(1)
mode = CLAMP(mode, GRAB_PASSIVE, max_grab)
if(AM)
if(check_target(AM, exclude_contents = TRUE))
acting_object.investigate_log("grabbed ([AM]) using [src].", INVESTIGATE_CIRCUIT)
acting_object.start_pulling(AM,mode)
if(acting_object.pulling)
set_pin_data(IC_OUTPUT, 1, TRUE)
else
set_pin_data(IC_OUTPUT, 1, FALSE)
push_data()
if(4)
if(acting_object.pulling)
var/dir = get_pin_data(IC_INPUT, 3)
var/turf/G =get_step(get_turf(acting_object),dir)
var/atom/movable/pullee = acting_object.pulling
var/turf/Pl = get_turf(pullee)
var/turf/F = get_step_towards(Pl,G)
if(acting_object.Adjacent(F))
if(!step_towards(pullee, F))
F = get_step_towards2(Pl,G)
if(acting_object.Adjacent(F))
step_towards(pullee, F)
activate_pin(2)
/obj/item/integrated_circuit/manipulation/claw/stop_pulling()
set_pin_data(IC_OUTPUT, 1, FALSE)
activate_pin(3)
push_data()
..()
/obj/item/integrated_circuit/manipulation/thrower
name = "thrower"
desc = "A compact launcher to throw things from inside or nearby tiles at a low enough velocity not to harm someone."
extended_desc = "The first and second inputs need to be numbers which correspond to the coordinates to throw objects at relative to the machine itself. \
The 'fire' activator will cause the mechanism to attempt to throw objects at the coordinates, if possible. Note that the \
projectile needs to be inside the machine, or on an adjacent tile, and must be medium sized or smaller. The assembly \
must also be a gun if you wish to throw something while the assembly is in hand."
complexity = 25
w_class = WEIGHT_CLASS_SMALL
size = 2
cooldown_per_use = 10
ext_cooldown = 1
inputs = list(
"target X rel" = IC_PINTYPE_NUMBER,
"target Y rel" = IC_PINTYPE_NUMBER,
"projectile" = IC_PINTYPE_REF
)
outputs = list()
activators = list(
"fire" = IC_PINTYPE_PULSE_IN
)
spawn_flags = IC_SPAWN_RESEARCH
action_flags = IC_ACTION_COMBAT
power_draw_per_use = 50
/obj/item/integrated_circuit/manipulation/thrower/do_work()
var/max_w_class = assembly.w_class
var/target_x_rel = round(get_pin_data(IC_INPUT, 1))
var/target_y_rel = round(get_pin_data(IC_INPUT, 2))
var/obj/item/A = get_pin_data_as_type(IC_INPUT, 3, /obj/item)
if(!A || A.anchored || A.throwing || A == assembly || istype(A, /obj/item/twohanded) || istype(A, /obj/item/transfer_valve))
return
if (istype(assembly.loc, /obj/item/implant/storage)) //Prevents the more abusive form of chestgun.
return
if(max_w_class && (A.w_class > max_w_class))
return
if(!assembly.can_fire_equipped && ishuman(assembly.loc))
return
// Is the target inside the assembly or close to it?
if(!check_target(A, exclude_components = TRUE))
return
var/turf/T = get_turf(get_object())
if(!T)
return
// If the item is in mob's inventory, try to remove it from there.
if(ismob(A.loc))
var/mob/living/M = A.loc
if(!M.temporarilyRemoveItemFromInventory(A))
return
// If the item is in a grabber circuit we'll update the grabber's outputs after we've thrown it.
var/obj/item/integrated_circuit/manipulation/grabber/G = A.loc
var/x_abs = CLAMP(T.x + target_x_rel, 0, world.maxx)
var/y_abs = CLAMP(T.y + target_y_rel, 0, world.maxy)
var/range = round(CLAMP(sqrt(target_x_rel*target_x_rel+target_y_rel*target_y_rel),0,8),1)
//remove damage
A.throwforce = 0
A.embedding = list("embed_chance" = 0)
//throw it
assembly.visible_message("<span class='danger'>[assembly] has thrown [A]!</span>")
log_attack("[assembly] [REF(assembly)] has thrown [A] with non-lethal force.")
A.forceMove(drop_location())
A.throw_at(locate(x_abs, y_abs, T.z), range, 3, null, null, null, CALLBACK(src, .proc/post_throw, A))
// If the item came from a grabber now we can update the outputs since we've thrown it.
if(istype(G))
G.update_outputs()
/obj/item/integrated_circuit/manipulation/thrower/proc/post_throw(obj/item/A)
//return damage
A.throwforce = initial(A.throwforce)
A.embedding = initial(A.embedding)
/obj/item/integrated_circuit/manipulation/matman
name = "material manager"
desc = "This circuit is designed for automatic storage and distribution of materials."
extended_desc = "The first input takes a ref of a machine with a material container. \
Second input is used for inserting material stacks into the internal material storage. \
Inputs 3-13 are used to transfer materials between target machine and circuit storage. \
Positive values will take that number of materials from another machine. \
Negative values will fill another machine from internal storage. Outputs show current stored amounts of mats."
icon_state = "grabber"
complexity = 16
inputs = list(
"target" = IC_PINTYPE_REF,
"sheets to insert" = IC_PINTYPE_NUMBER,
"Metal" = IC_PINTYPE_NUMBER,
"Glass" = IC_PINTYPE_NUMBER,
"Silver" = IC_PINTYPE_NUMBER,
"Gold" = IC_PINTYPE_NUMBER,
"Diamond" = IC_PINTYPE_NUMBER,
"Uranium" = IC_PINTYPE_NUMBER,
"Solid Plasma" = IC_PINTYPE_NUMBER,
"Bluespace Mesh" = IC_PINTYPE_NUMBER,
"Bananium" = IC_PINTYPE_NUMBER,
"Titanium" = IC_PINTYPE_NUMBER,
)
outputs = list(
"self ref" = IC_PINTYPE_REF,
"Total amount" = IC_PINTYPE_NUMBER,
"Metal" = IC_PINTYPE_NUMBER,
"Glass" = IC_PINTYPE_NUMBER,
"Silver" = IC_PINTYPE_NUMBER,
"Gold" = IC_PINTYPE_NUMBER,
"Diamond" = IC_PINTYPE_NUMBER,
"Uranium" = IC_PINTYPE_NUMBER,
"Solid Plasma" = IC_PINTYPE_NUMBER,
"Bluespace Mesh" = IC_PINTYPE_NUMBER,
"Bananium" = IC_PINTYPE_NUMBER,
"Titanium" = IC_PINTYPE_NUMBER
)
activators = list(
"insert sheet" = IC_PINTYPE_PULSE_IN,
"transfer mats" = IC_PINTYPE_PULSE_IN,
"on success" = IC_PINTYPE_PULSE_OUT,
"on failure" = IC_PINTYPE_PULSE_OUT,
"push ref" = IC_PINTYPE_PULSE_IN,
"on push ref" = IC_PINTYPE_PULSE_IN
)
spawn_flags = IC_SPAWN_RESEARCH
power_draw_per_use = 40
ext_cooldown = 1
cooldown_per_use = 10
var/list/mtypes = list(MAT_METAL, MAT_GLASS, MAT_SILVER, MAT_GOLD, MAT_DIAMOND, MAT_PLASMA, MAT_URANIUM, MAT_BANANIUM, MAT_TITANIUM, MAT_BLUESPACE)
/obj/item/integrated_circuit/manipulation/matman/Initialize()
var/datum/component/material_container/materials = AddComponent(/datum/component/material_container,
list(MAT_METAL, MAT_GLASS, MAT_SILVER, MAT_GOLD, MAT_DIAMOND, MAT_PLASMA, MAT_URANIUM, MAT_BANANIUM, MAT_TITANIUM, MAT_BLUESPACE), 0,
FALSE, /obj/item/stack, CALLBACK(src, .proc/is_insertion_ready), CALLBACK(src, .proc/AfterMaterialInsert))
materials.max_amount =100000
materials.precise_insertion = TRUE
.=..()
/obj/item/integrated_circuit/manipulation/matman/proc/AfterMaterialInsert(type_inserted, id_inserted, amount_inserted)
var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
set_pin_data(IC_OUTPUT, 2, materials.total_amount)
for(var/I in 1 to mtypes.len)
var/datum/material/M = materials.materials[mtypes[I]]
if(M)
set_pin_data(IC_OUTPUT, I+2, M.amount)
push_data()
/obj/item/integrated_circuit/manipulation/matman/proc/is_insertion_ready(mob/user)
return TRUE
/obj/item/integrated_circuit/manipulation/matman/do_work(ord)
var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
var/atom/movable/H = get_pin_data_as_type(IC_INPUT, 1, /atom/movable)
if(!check_target(H))
activate_pin(4)
return
var/turf/T = get_turf(H)
switch(ord)
if(1)
var/obj/item/stack/sheet/S = H
if(!S)
activate_pin(4)
return
if(materials.insert_stack(S, CLAMP(get_pin_data(IC_INPUT, 2),0,100), multiplier = 1) )
AfterMaterialInsert()
activate_pin(3)
else
activate_pin(4)
if(2)
var/datum/component/material_container/mt = H.GetComponent(/datum/component/material_container)
var/suc
for(var/I in 1 to mtypes.len)
var/datum/material/M = materials.materials[mtypes[I]]
if(M)
var/U = CLAMP(get_pin_data(IC_INPUT, I+2),-100000,100000)
if(!U)
continue
if(!mt) //Invalid input
if(U>0)
if(materials.retrieve_amount(U, mtypes[I], T))
suc = TRUE
else
if(mt.transer_amt_to(materials, U, mtypes[I]))
suc = TRUE
if(suc)
AfterMaterialInsert()
activate_pin(3)
else
activate_pin(4)
if(5)
set_pin_data(IC_OUTPUT, 1, WEAKREF(src))
AfterMaterialInsert()
activate_pin(6)
/obj/item/integrated_circuit/manipulation/matman/Destroy()
var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
materials.retrieve_all()
.=..()
//Hippie Ported Code--------------------------------------------------------------------------------------------------------
// - inserter circuit - //
/obj/item/integrated_circuit/manipulation/inserter
name = "inserter"
desc = "A nimble circuit that puts stuff inside a storage like a backpack and can take it out aswell."
icon_state = "grabber"
extended_desc = "This circuit accepts a reference to an object to be inserted or extracted depending on mode. If a storage is given for extraction, the extracted item will be put in the new storage. Modes: 1 insert, 0 to extract."
w_class = WEIGHT_CLASS_SMALL
size = 3
cooldown_per_use = 5
complexity = 10
inputs = list("target object" = IC_PINTYPE_REF, "target container" = IC_PINTYPE_REF,"mode" = IC_PINTYPE_NUMBER)
activators = list("pulse in" = IC_PINTYPE_PULSE_IN,"pulse out" = IC_PINTYPE_PULSE_OUT)
spawn_flags = IC_SPAWN_RESEARCH
action_flags = IC_ACTION_COMBAT
power_draw_per_use = 20
var/max_items = 10
/obj/item/integrated_circuit/manipulation/inserter/do_work()
//There shouldn't be any target required to eject all contents
var/obj/item/target_obj = get_pin_data_as_type(IC_INPUT, 1, /obj/item)
if(!target_obj)
return
var/distance = get_dist(get_turf(src),get_turf(target_obj))
if(distance > 1 || distance < 0)
return
var/obj/item/storage/container = get_pin_data_as_type(IC_INPUT, 2, /obj/item)
var/mode = get_pin_data(IC_INPUT, 3)
switch(mode)
if(1) //Not working
if(!container || !istype(container,/obj/item/storage) || !Adjacent(container))
return
var/datum/component/storage/STR = container.GetComponent(/datum/component/storage)
if(!STR)
return
STR.attackby(src, target_obj)
else
var/datum/component/storage/STR = target_obj.loc.GetComponent(/datum/component/storage)
if(!STR)
return
if(!container || !istype(container,/obj/item/storage) || !Adjacent(container))
STR.remove_from_storage(target_obj,drop_location())
else
STR.remove_from_storage(target_obj,container)
// Renamer circuit. Renames the assembly it is in. Useful in cooperation with telecomms-based circuits.
/obj/item/integrated_circuit/manipulation/renamer
name = "renamer"
desc = "A small circuit that renames the assembly it is in. Useful paired with speech-based circuits."
icon_state = "internalbm"
extended_desc = "This circuit accepts a string as input, and can be pulsed to rewrite the current assembly's name with said string. On success, it pulses the default pulse-out wire."
inputs = list("name" = IC_PINTYPE_STRING)
outputs = list("current name" = IC_PINTYPE_STRING)
activators = list("rename" = IC_PINTYPE_PULSE_IN,"get name" = IC_PINTYPE_PULSE_IN,"pulse out" = IC_PINTYPE_PULSE_OUT)
power_draw_per_use = 1
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
/obj/item/integrated_circuit/manipulation/renamer/do_work(var/n)
if(!assembly)
return
switch(n)
if(1)
var/new_name = get_pin_data(IC_INPUT, 1)
if(new_name)
assembly.name = new_name
else
set_pin_data(IC_OUTPUT, 1, assembly.name)
push_data()
activate_pin(3)
// - redescribing circuit - //
/obj/item/integrated_circuit/manipulation/redescribe
name = "redescriber"
desc = "Takes any string as an input and will set it as the assembly's description."
extended_desc = "Strings should can be of any length."
icon_state = "speaker"
cooldown_per_use = 10
complexity = 3
inputs = list("text" = IC_PINTYPE_STRING)
outputs = list("description" = IC_PINTYPE_STRING)
activators = list("redescribe" = IC_PINTYPE_PULSE_IN,"get description" = IC_PINTYPE_PULSE_IN,"pulse out" = IC_PINTYPE_PULSE_OUT)
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
/obj/item/integrated_circuit/manipulation/redescribe/do_work(var/n)
if(!assembly)
return
switch(n)
if(1)
assembly.desc = get_pin_data(IC_INPUT, 1)
else
set_pin_data(IC_OUTPUT, 1, assembly.desc)
push_data()
activate_pin(3)
// - repainting circuit - //
/obj/item/integrated_circuit/manipulation/repaint
name = "auto-repainter"
desc = "There's an oddly high amount of spraying cans fitted right inside this circuit."
extended_desc = "Takes a value in hexadecimal and uses it to repaint the assembly it is in."
cooldown_per_use = 10
complexity = 3
inputs = list("color" = IC_PINTYPE_COLOR)
outputs = list("current color" = IC_PINTYPE_COLOR)
activators = list("repaint" = IC_PINTYPE_PULSE_IN,"get color" = IC_PINTYPE_PULSE_IN,"pulse out" = IC_PINTYPE_PULSE_OUT)
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
/obj/item/integrated_circuit/manipulation/repaint/do_work(var/n)
if(!assembly)
return
switch(n)
if(1)
assembly.detail_color = get_pin_data(IC_INPUT, 1)
assembly.update_icon()
else
set_pin_data(IC_OUTPUT, 1, assembly.detail_color)
push_data()
activate_pin(3)
@@ -0,0 +1,373 @@
/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 = 5
inputs = list("target" = IC_PINTYPE_REF,"ignore obstacles" = IC_PINTYPE_BOOLEAN)
outputs = list("dir" = IC_PINTYPE_DIR)
activators = list("calculate dir" = IC_PINTYPE_PULSE_IN, "on calculated" = IC_PINTYPE_PULSE_OUT,"not calculated" = IC_PINTYPE_PULSE_OUT)
spawn_flags = IC_SPAWN_RESEARCH
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
activate_pin(3)
var/atom/A = I.data.resolve()
if(!A)
activate_pin(3)
return
if(!(A in view(get_turf(src))))
push_data()
activate_pin(3)
return // Can't see the target.
if(get_pin_data(IC_INPUT, 2))
set_pin_data(IC_OUTPUT, 1, get_dir(get_turf(src), get_turf(A)))
else
set_pin_data(IC_OUTPUT, 1, get_dir(get_turf(src), get_step_towards2(get_turf(src),A)))
push_data()
activate_pin(2)
/obj/item/integrated_circuit/smart/coord_basic_pathfinder
name = "coordinate pathfinder"
desc = "This complex circuit is able to determine what direction a given target is."
extended_desc = "This circuit uses absolute coordinates to determine where the target is. If the machine \
cannot see the target, it will not be able to calculate the correct direction. \
This circuit will only work while inside an assembly."
icon_state = "numberpad"
complexity = 5
inputs = list("X" = IC_PINTYPE_NUMBER,"Y" = IC_PINTYPE_NUMBER,"ignore obstacles" = IC_PINTYPE_BOOLEAN)
outputs = list( "dir" = IC_PINTYPE_DIR,
"distance" = IC_PINTYPE_NUMBER
)
activators = list("calculate dir" = IC_PINTYPE_PULSE_IN, "on calculated" = IC_PINTYPE_PULSE_OUT,"not calculated" = IC_PINTYPE_PULSE_OUT)
spawn_flags = IC_SPAWN_RESEARCH
power_draw_per_use = 40
/obj/item/integrated_circuit/smart/coord_basic_pathfinder/do_work()
if(!assembly)
activate_pin(3)
return
var/turf/T = get_turf(assembly)
var/target_x = CLAMP(get_pin_data(IC_INPUT, 1), 0, world.maxx)
var/target_y = CLAMP(get_pin_data(IC_INPUT, 2), 0, world.maxy)
var/turf/A = locate(target_x, target_y, T.z)
set_pin_data(IC_OUTPUT, 1, null)
if(!A||A==T)
activate_pin(3)
return
if(get_pin_data(IC_INPUT, 2))
set_pin_data(IC_OUTPUT, 1, get_dir(get_turf(src), get_turf(A)))
else
set_pin_data(IC_OUTPUT, 1, get_dir(get_turf(src), get_step_towards2(get_turf(src),A)))
set_pin_data(IC_OUTPUT, 2, sqrt((A.x-T.x)*(A.x-T.x)+ (A.y-T.y)*(A.y-T.y)))
push_data()
activate_pin(2)
/obj/item/integrated_circuit/smart/advanced_pathfinder
name = "advanced pathfinder"
desc = "This circuit uses a complex processor for long-range pathfinding."
extended_desc = "This circuit uses absolute coordinates to find its target. A path will be generated to the target, taking obstacles into account, \
and pathing around any instances of said input. The passkey provided from a card reader is used to calculate a valid path through airlocks."
icon_state = "numberpad"
complexity = 40
cooldown_per_use = 50
inputs = list("X target" = IC_PINTYPE_NUMBER,"Y target" = IC_PINTYPE_NUMBER,"obstacle" = IC_PINTYPE_REF,"access" = IC_PINTYPE_STRING)
outputs = list("X" = IC_PINTYPE_LIST,"Y" = IC_PINTYPE_LIST)
activators = list("calculate path" = IC_PINTYPE_PULSE_IN, "on calculated" = IC_PINTYPE_PULSE_OUT,"not calculated" = IC_PINTYPE_PULSE_OUT)
spawn_flags = IC_SPAWN_RESEARCH
power_draw_per_use = 80
var/obj/item/card/id/idc
/obj/item/integrated_circuit/smart/advanced_pathfinder/Initialize()
.=..()
idc = new(src)
/obj/item/integrated_circuit/smart/advanced_pathfinder/do_work()
if(!assembly)
activate_pin(3)
return
idc.access = assembly.access_card.access
var/turf/a_loc = get_turf(assembly)
var/list/P = cir_get_path_to(assembly, locate(get_pin_data(IC_INPUT, 1),get_pin_data(IC_INPUT, 2),a_loc.z), /turf/proc/Distance_cardinal, 0, 200, id=idc, exclude=get_turf(get_pin_data_as_type(IC_INPUT,3, /atom)), simulated_only = 0)
if(!P)
activate_pin(3)
return
else
var/list/Xn = new/list(P.len)
var/list/Yn = new/list(P.len)
var/turf/T
for(var/i =1 to P.len)
T=P[i]
Xn[i] = T.x
Yn[i] = T.y
set_pin_data(IC_OUTPUT, 1, Xn)
set_pin_data(IC_OUTPUT, 2, Yn)
push_data()
activate_pin(2)
//Hippie Ported Code--------------------------------------------------------------------------------------------------------
// - MMI Tank - //
/obj/item/integrated_circuit/input/mmi_tank
name = "man-machine interface tank"
desc = "This circuit is just a jar filled with an artificial liquid mimicking the cerebrospinal fluid."
extended_desc = "This jar can hold 1 man-machine interface and let it take control of some basic functions of the assembly."
complexity = 60
inputs = list("laws" = IC_PINTYPE_LIST)
outputs = list(
"man-machine interface" = IC_PINTYPE_REF,
"direction" = IC_PINTYPE_DIR,
"click target" = IC_PINTYPE_REF
)
activators = list(
"move" = IC_PINTYPE_PULSE_OUT,
"left" = IC_PINTYPE_PULSE_OUT,
"right" = IC_PINTYPE_PULSE_OUT,
"up" = IC_PINTYPE_PULSE_OUT,
"down" = IC_PINTYPE_PULSE_OUT,
"leftclick" = IC_PINTYPE_PULSE_OUT,
"shiftclick" = IC_PINTYPE_PULSE_OUT,
"altclick" = IC_PINTYPE_PULSE_OUT,
"ctrlclick" = IC_PINTYPE_PULSE_OUT
)
spawn_flags = IC_SPAWN_RESEARCH
power_draw_per_use = 150
can_be_asked_input = TRUE
demands_object_input = TRUE
var/obj/item/mmi/installed_brain
/obj/item/integrated_circuit/input/mmi_tank/attackby(var/obj/item/mmi/O, var/mob/user)
if(!istype(O,/obj/item/mmi))
to_chat(user,"<span class='warning'>You can't put that inside.</span>")
return
if(installed_brain)
to_chat(user,"<span class='warning'>There's already a brain inside.</span>")
return
user.transferItemToLoc(O,src)
installed_brain = O
can_be_asked_input = FALSE
to_chat(user, "<span class='notice'>You gently place \the man-machine interface inside the tank.</span>")
to_chat(O, "<span class='notice'>You are slowly being placed inside the man-machine-interface tank.</span>")
O.brainmob.remote_control=src
set_pin_data(IC_OUTPUT, 1, O)
/obj/item/integrated_circuit/input/mmi_tank/attack_self(var/mob/user)
if(installed_brain)
RemoveBrain()
to_chat(user, "<span class='notice'>You slowly lift [installed_brain] out of the MMI tank.</span>")
playsound(src, 'sound/items/Crowbar.ogg', 50, 1)
installed_brain = null
push_data()
else
to_chat(user, "<span class='notice'>You don't see any brain swimming in the tank.</span>")
/obj/item/integrated_circuit/input/mmi_tank/Destroy()
RemoveBrain()
..()
/obj/item/integrated_circuit/input/mmi_tank/relaymove(var/n,var/dir)
set_pin_data(IC_OUTPUT, 2, dir)
do_work(1)
switch(dir)
if(8) activate_pin(2)
if(4) activate_pin(3)
if(1) activate_pin(4)
if(2) activate_pin(5)
/obj/item/integrated_circuit/input/mmi_tank/do_work(var/n)
push_data()
activate_pin(n)
/obj/item/integrated_circuit/input/mmi_tank/proc/RemoveBrain()
if(installed_brain)
can_be_asked_input = TRUE
installed_brain.forceMove(drop_location())
set_pin_data(IC_OUTPUT, 1, WEAKREF(null))
if(installed_brain.brainmob)
installed_brain.brainmob.remote_control = null
//Brain changes
/mob/living/brain/var/check_bot_self = FALSE
/mob/living/brain/ClickOn(atom/A, params)
..()
if(!istype(remote_control,/obj/item/integrated_circuit/input/mmi_tank))
return
var/obj/item/integrated_circuit/input/mmi_tank/brainholder=remote_control
brainholder.set_pin_data(IC_OUTPUT, 3, A)
var/list/modifiers = params2list(params)
if(modifiers["shift"])
brainholder.do_work(7)
return
if(modifiers["alt"])
brainholder.do_work(8)
return
if(modifiers["ctrl"])
brainholder.do_work(9)
return
if(istype(A,/obj/item/electronic_assembly))
var/obj/item/electronic_assembly/CheckedAssembly = A
if(brainholder in CheckedAssembly.assembly_components)
var/obj/item/electronic_assembly/holdingassembly=A
check_bot_self=TRUE
if(holdingassembly.opened)
holdingassembly.ui_interact(src)
holdingassembly.attack_self(src)
check_bot_self=FALSE
return
brainholder.do_work(6)
/mob/living/brain/canUseTopic(atom/movable/M, be_close=FALSE, no_dextery=FALSE, no_tk=FALSE)
return check_bot_self
/obj/item/integrated_circuit/smart/advanced_pathfinder/proc/hippie_xor_decrypt()
var/Ps = get_pin_data(IC_INPUT, 4)
if(!Ps)
return
var/list/Pl = json_decode(XorEncrypt(hextostr(Ps, TRUE), SScircuit.cipherkey))
if(Pl&&islist(Pl))
idc.access = Pl
// - pAI connector circuit - //
/obj/item/integrated_circuit/input/pAI_connector
name = "pAI connector circuit"
desc = "This circuit lets you fit in a personal artificial intelligence to give it some form of control over the bot."
extended_desc = "You can wire various functions to it."
complexity = 60
inputs = list("laws" = IC_PINTYPE_LIST)
outputs = list(
"personal artificial intelligence" = IC_PINTYPE_REF,
"direction" = IC_PINTYPE_DIR,
"click target" = IC_PINTYPE_REF
)
activators = list(
"move" = IC_PINTYPE_PULSE_OUT,
"left" = IC_PINTYPE_PULSE_OUT,
"right" = IC_PINTYPE_PULSE_OUT,
"up" = IC_PINTYPE_PULSE_OUT,
"down" = IC_PINTYPE_PULSE_OUT,
"leftclick" = IC_PINTYPE_PULSE_OUT,
"shiftclick" = IC_PINTYPE_PULSE_OUT,
"altclick" = IC_PINTYPE_PULSE_OUT,
"ctrlclick" = IC_PINTYPE_PULSE_OUT,
"shiftctrlclick" = IC_PINTYPE_PULSE_OUT
)
spawn_flags = IC_SPAWN_RESEARCH
power_draw_per_use = 150
can_be_asked_input = TRUE
demands_object_input = TRUE
var/obj/item/paicard/installed_pai
/obj/item/integrated_circuit/input/pAI_connector/attackby(var/obj/item/paicard/O, var/mob/user)
if(!istype(O,/obj/item/paicard))
to_chat(user,"<span class='warning'>You can't put that inside.</span>")
return
if(installed_pai)
to_chat(user,"<span class='warning'>There's already a pAI connected to this.</span>")
return
user.transferItemToLoc(O,src)
installed_pai = O
can_be_asked_input = FALSE
to_chat(user, "<span class='notice'>You slowly connect the circuit's pins to the [installed_pai].</span>")
to_chat(O, "<span class='notice'>You are slowly being connected to the pAI connector.</span>")
O.pai.remote_control=src
set_pin_data(IC_OUTPUT, 1, O)
/obj/item/integrated_circuit/input/pAI_connector/attack_self(var/mob/user)
if(installed_pai)
RemovepAI()
to_chat(user, "<span class='notice'>You slowly disconnect the circuit's pins from the [installed_pai].</span>")
playsound(src, 'sound/items/Crowbar.ogg', 50, 1)
installed_pai = null
push_data()
else
to_chat(user, "<span class='notice'>The connection port is empty.</span>")
/obj/item/integrated_circuit/input/pAI_connector/relaymove(var/n,var/dir)
set_pin_data(IC_OUTPUT, 2, dir)
do_work(1)
switch(dir)
if(8) activate_pin(2)
if(4) activate_pin(3)
if(1) activate_pin(4)
if(2) activate_pin(5)
/obj/item/integrated_circuit/input/pAI_connector/do_work(var/n)
push_data()
activate_pin(n)
/obj/item/integrated_circuit/input/pAI_connector/Destroy()
RemovepAI()
..()
/obj/item/integrated_circuit/input/pAI_connector/proc/RemovepAI()
if(installed_pai)
can_be_asked_input = TRUE
installed_pai.forceMove(drop_location())
set_pin_data(IC_OUTPUT, 1, WEAKREF(null))
installed_pai.pai.remote_control = null
//pAI changes
/mob/living/silicon/pai/var/check_bot_self = FALSE
/mob/living/silicon/pai/ClickOn(atom/A, params)
..()
if(!istype(remote_control,/obj/item/integrated_circuit/input/pAI_connector))
return
var/obj/item/integrated_circuit/input/pAI_connector/paiholder=remote_control
paiholder.set_pin_data(IC_OUTPUT, 3, A)
var/list/modifiers = params2list(params)
if(modifiers["shift"] && modifiers["ctrl"])
paiholder.do_work(10)
return
if(modifiers["shift"])
paiholder.do_work(7)
return
if(modifiers["alt"])
paiholder.do_work(8)
return
if(modifiers["ctrl"])
paiholder.do_work(9)
return
if(istype(A,/obj/item/electronic_assembly))
var/obj/item/electronic_assembly/CheckedAssembly = A
if(paiholder in CheckedAssembly.assembly_components)
var/obj/item/electronic_assembly/holdingassembly=A
check_bot_self=TRUE
if(holdingassembly.opened)
holdingassembly.ui_interact(src)
holdingassembly.attack_self(src)
check_bot_self=FALSE
return
paiholder.do_work(6)
/mob/living/silicon/pai/canUseTopic(atom/movable/M, be_close=FALSE, no_dextery=FALSE, no_tk=FALSE)
return check_bot_self