@@ -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;'>↑</a> "
|
||||
HTML += "<a href='?src=[REF(src)];component=[REF(circuit)];down=1' style='text-decoration:none;'>↓</a> "
|
||||
HTML += "<a href='?src=[REF(src)];component=[REF(circuit)];top=1' style='text-decoration:none;'>⤒</a> "
|
||||
HTML += "<a href='?src=[REF(src)];component=[REF(circuit)];bottom=1' style='text-decoration:none;'>⤓</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
|
||||
Reference in New Issue
Block a user