#define IC_MAX_SIZE_BASE 25 #define IC_COMPLEXITY_BASE 75 /obj/item/device/electronic_assembly name = "electronic assembly" 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" flags_1 = NOBLUDGEON_1 materials = list() // To be filled later var/list/assembly_components = list() var/max_components = IC_MAX_SIZE_BASE var/max_complexity = IC_COMPLEXITY_BASE var/opened = FALSE 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/charge_sections = 4 var/charge_tick = FALSE var/charge_delay = 4 var/use_cyborg_cell = TRUE 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. hud_possible = list(DIAG_STAT_HUD, DIAG_BATT_HUD, DIAG_TRACK_HUD, DIAG_CIRCUIT_HUD) //diagnostic hud overlays max_integrity = 50 armor = list("melee" = 50, "bullet" = 70, "laser" = 70, "energy" = 100, "bomb" = 10, "bio" = 100, "rad" = 100, "fire" = 0, "acid" = 0) /obj/item/device/electronic_assembly/proc/check_interactivity(mob/user) return user.canUseTopic(src, BE_CLOSE) /obj/item/device/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() /obj/item/device/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) return ..() /obj/item/device/electronic_assembly/process() handle_idle_power() check_pulling() //updates diagnostic hud diag_hud_set_circuithealth() diag_hud_set_circuitcell() /obj/item/device/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/device/electronic_assembly/interact(mob/user) if(!check_interactivity(user)) return var/total_part_size = return_total_size() var/total_complexity = return_total_complexity() var/HTML = "" HTML += "[name]" HTML += "\[Refresh\] | \[Rename\]
" HTML += "[total_part_size]/[max_components] ([round((total_part_size / max_components) * 100, 0.1)]%) space taken up in the assembly.
" HTML += "[total_complexity]/[max_complexity] ([round((total_complexity / max_complexity) * 100, 0.1)]%) maximum complexity.
" if(battery) HTML += "[round(battery.charge, 0.1)]/[battery.maxcharge] ([round(battery.percent(), 0.1)]%) cell charge. \[Remove\]" else HTML += "No power cell detected!" HTML += "

" HTML += "Components:" var/builtin_components = "" for(var/c in assembly_components) var/obj/item/integrated_circuit/circuit = c if(!circuit.removable) builtin_components += "[circuit.displayed_name] | " builtin_components += "\[Rename\] | " builtin_components += "\[Copy Ref\]" builtin_components += "
" // Put removable circuits (if any) in separate categories from non-removable if(builtin_components) HTML += "
" HTML += "Built in:
" HTML += builtin_components HTML += "
" HTML += "Removable:" HTML += "
" for(var/c in assembly_components) var/obj/item/integrated_circuit/circuit = c if(circuit.removable) HTML += "[circuit.displayed_name] | " HTML += "\[Rename\] | " HTML += "\[Copy Ref\] | " HTML += "\[Remove\] | " HTML += " " HTML += " " HTML += " " HTML += "" HTML += "
" HTML += "" user << browse(HTML, "window=assembly-[REF(src)];size=655x350;border=1;can_resize=1;can_close=1;can_minimize=1") /obj/item/device/electronic_assembly/Topic(href, href_list) if(..()) return 1 if(href_list["rename"]) rename(usr) if(href_list["remove_cell"]) if(!battery) to_chat(usr, "There's no power cell to remove from \the [src].") else battery.forceMove(drop_location()) playsound(src, 'sound/items/Crowbar.ogg', 50, 1) to_chat(usr, "You pull \the [battery] out of \the [src]'s power supplier.") 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 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/device/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/device/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/device/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, "The machine now has a label reading '[input]'.") name = input /obj/item/device/electronic_assembly/proc/can_move() return FALSE /obj/item/device/electronic_assembly/update_icon() if(opened) icon_state = initial(icon_state) + "-open" else icon_state = initial(icon_state) /obj/item/device/electronic_assembly/examine(mob/user) ..() for(var/I in assembly_components) var/obj/item/integrated_circuit/IC = I IC.external_examine(user) if(opened) interact(user) /obj/item/device/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/device/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/device/electronic_assembly/proc/try_add_component(obj/item/integrated_circuit/IC, mob/user) if(!opened) to_chat(user, "\The [src]'s hatch is closed, you can't put anything inside.") return FALSE if(IC.w_class > w_class) to_chat(user, "\The [IC] is way too big to fit into \the [src].") 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, "You can't seem to add the '[IC]', as there's insufficient space.") return FALSE if((total_complexity + IC.complexity) > max_complexity) to_chat(user, "You can't seem to add the '[IC]', since this setup's too complicated for the case.") return FALSE if((allowed_circuit_action_flags & IC.action_flags) != IC.action_flags) to_chat(user, "You can't seem to add the '[IC]', since the case doesn't support the circuit type.") return FALSE if(!user.transferItemToLoc(IC, src)) return FALSE to_chat(user, "You slide [IC] inside [src].") playsound(src, 'sound/items/Deconstruct.ogg', 50, 1) add_component(IC) return TRUE // Actually puts the circuit inside, doesn't perform any checks. /obj/item/device/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/device/electronic_assembly/proc/try_remove_component(obj/item/integrated_circuit/IC, mob/user, silent) if(!opened) if(!silent) to_chat(user, "[src]'s hatch is closed, so you can't fiddle with the internal components.") return FALSE if(!IC.removable) if(!silent) to_chat(user, "[src] is permanently attached to the case.") return FALSE remove_component(IC) if(!silent) to_chat(user, "You pop \the [IC] out of the case, and slide it out.") playsound(src, 'sound/items/crowbar.ogg', 50, 1) user.put_in_hands(IC) return TRUE // Actually removes the component, doesn't perform any checks. /obj/item/device/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/device/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(" [user] waves [src] around [target].") /obj/item/device/electronic_assembly/screwdriver_act(mob/living/user, obj/item/I) I.play_tool_sound(src) opened = !opened to_chat(user, "You [opened ? "open" : "close"] the maintenance hatch of [src].") update_icon() return TRUE /obj/item/device/electronic_assembly/attackby(obj/item/I, mob/living/user) if(istype(I, /obj/item/integrated_circuit)) if(!user.canUnEquip(I)) return FALSE if(try_add_component(I, user)) interact(user) return TRUE else if(istype(I, /obj/item/device/multitool) || istype(I, /obj/item/device/integrated_electronics/wirer) || istype(I, /obj/item/device/integrated_electronics/debugger)) if(opened) interact(user) else to_chat(user, "[src]'s hatch is closed, so you can't fiddle with the internal components.") else if(istype(I, /obj/item/stock_parts/cell)) if(!opened) to_chat(user, "[src]'s hatch is closed, so you can't put anything inside.") return FALSE if(battery) to_chat(user, "[src] already has \a [battery] installed. Remove it first if you want to replace it.") return FALSE var/obj/item/stock_parts/cell = I user.transferItemToLoc(I, loc) cell.forceMove(src) battery = cell diag_hud_set_circuitstat() //update diagnostic hud playsound(get_turf(src), 'sound/items/Deconstruct.ogg', 50, 1) to_chat(user, "You slot \the [cell] inside \the [src]'s power supplier.") interact(user) return TRUE else for(var/obj/item/integrated_circuit/input/S in assembly_components) S.attackby_react(I,user,user.a_intent) return ..() /obj/item/device/electronic_assembly/attack_self(mob/user) if(!check_interactivity(user)) return if(opened) interact(user) var/list/input_selection = list() var/list/available_inputs = list() for(var/obj/item/integrated_circuit/input/input in assembly_components) if(input.can_be_asked_input) available_inputs.Add(input) var/i = 0 for(var/obj/item/integrated_circuit/s in available_inputs) if(s.name == input.name && s.displayed_name == input.displayed_name && s != input) i++ var/disp_name= "[input.displayed_name] \[[input]\]" if(i) disp_name += " ([i+1])" input_selection.Add(disp_name) var/obj/item/integrated_circuit/input/choice if(available_inputs) if(available_inputs.len ==1) choice = available_inputs[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) var/index = input_selection.Find(selection) choice = available_inputs[index] if(choice) choice.ask_for_input(user) /obj/item/device/electronic_assembly/emp_act(severity) ..() for(var/i in 1 to contents.len) var/atom/movable/AM = contents[i] AM.emp_act(severity) // Returns true if power was successfully drawn. /obj/item/device/electronic_assembly/proc/draw_power(amount) if(battery && battery.use(amount * GLOB.CELLRATE)) return TRUE return FALSE // Ditto for giving. /obj/item/device/electronic_assembly/proc/give_power(amount) if(battery && battery.give(amount * GLOB.CELLRATE)) return TRUE return FALSE /obj/item/device/electronic_assembly/Moved(oldLoc, dir) for(var/I in assembly_components) var/obj/item/integrated_circuit/IC = I IC.ext_moved(oldLoc, dir) /obj/item/device/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/device/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/device/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/device/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/device/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/device/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/device/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/device/electronic_assembly/medium/default name = "type-a electronic mechanism" /obj/item/device/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/device/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/device/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/device/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 anchored = FALSE /obj/item/device/electronic_assembly/large/attackby(obj/item/O, mob/user) if(default_unfasten_wrench(user, O, 20)) return ..() /obj/item/device/electronic_assembly/large/attack_tk(mob/user) if(anchored) return ..() /obj/item/device/electronic_assembly/large/attack_hand(mob/user) if(anchored) attack_self(user) return ..() /obj/item/device/electronic_assembly/large/default name = "type-a electronic machine" /obj/item/device/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/device/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/device/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/device/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 /obj/item/device/electronic_assembly/drone/can_move() return TRUE /obj/item/device/electronic_assembly/drone/default name = "type-a electronic drone" /obj/item/device/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."