#define MAXIMUM_EMP_WIRES 3 /proc/is_wire_tool(obj/item/I) if(!I) return if(I.tool_behaviour == TOOL_WIRECUTTER || I.tool_behaviour == TOOL_MULTITOOL) return TRUE if(istype(I, /obj/item/assembly)) var/obj/item/assembly/A = I if(A.attachable) return TRUE /atom var/datum/wires/wires = null /atom/proc/attempt_wire_interaction(mob/user) if(!wires) return WIRE_INTERACTION_FAIL if(!user.CanReach(src)) return WIRE_INTERACTION_FAIL wires.interact(user) return WIRE_INTERACTION_BLOCK /datum/wires var/atom/holder = null // The holder (atom that contains these wires). var/holder_type = null // The holder's typepath (used to make wire colors common to all holders). var/proper_name = "Unknown" // The display name for the wire set shown in station blueprints. Not used if randomize is true or it's an item NT wouldn't know about (Explosives/Nuke) var/list/wires = list() // List of wires. var/list/cut_wires = list() // List of wires that have been cut. var/list/colors = list() // Dictionary of colors to wire. var/list/assemblies = list() // List of attached assemblies. var/randomize = 0 // If every instance of these wires should be random. // Prevents wires from showing up in station blueprints /datum/wires/New(atom/holder) ..() if(!istype(holder, holder_type)) CRASH("Wire holder is not of the expected type!") return src.holder = holder if(randomize) randomize() else if(!GLOB.wire_color_directory[holder_type]) randomize() GLOB.wire_color_directory[holder_type] = colors GLOB.wire_name_directory[holder_type] = proper_name else colors = GLOB.wire_color_directory[holder_type] /datum/wires/Destroy() holder = null assemblies = list() return ..() /datum/wires/proc/add_duds(duds) while(duds) var/dud = WIRE_DUD_PREFIX + "[--duds]" if(dud in wires) continue wires += dud /datum/wires/proc/randomize() var/static/list/possible_colors = list( "blue", "brown", "crimson", "cyan", "gold", "grey", "green", "magenta", "orange", "pink", "purple", "red", "silver", "violet", "white", "yellow" ) var/list/my_possible_colors = possible_colors.Copy() for(var/wire in shuffle(wires)) colors[pick_n_take(my_possible_colors)] = wire /datum/wires/proc/shuffle_wires() colors.Cut() randomize() /datum/wires/proc/repair() cut_wires.Cut() /datum/wires/proc/get_wire(color) return colors[color] /datum/wires/proc/get_attached(color) if(assemblies[color]) return assemblies[color] return null /datum/wires/proc/is_attached(color) if(assemblies[color]) return TRUE /datum/wires/proc/is_cut(wire) return (wire in cut_wires) /datum/wires/proc/is_color_cut(color) return is_cut(get_wire(color)) /datum/wires/proc/is_all_cut() if(cut_wires.len == wires.len) return TRUE /datum/wires/proc/is_dud(wire) return dd_hasprefix(wire, WIRE_DUD_PREFIX) /datum/wires/proc/is_dud_color(color) return is_dud(get_wire(color)) /datum/wires/proc/cut(wire) if(is_cut(wire)) cut_wires -= wire on_cut(wire, mend = TRUE) else cut_wires += wire on_cut(wire, mend = FALSE) /datum/wires/proc/cut_color(color) cut(get_wire(color)) /datum/wires/proc/cut_random() cut(wires[rand(1, wires.len)]) /datum/wires/proc/cut_all() for(var/wire in wires) cut(wire) /datum/wires/proc/pulse(wire, user) if(is_cut(wire)) return on_pulse(wire, user) /datum/wires/proc/pulse_color(color, mob/living/user) pulse(get_wire(color), user) /datum/wires/proc/pulse_assembly(obj/item/assembly/S) for(var/color in assemblies) if(S == assemblies[color]) pulse_color(color) return TRUE /datum/wires/proc/attach_assembly(color, obj/item/assembly/S) if(S && istype(S) && S.attachable && !is_attached(color)) assemblies[color] = S S.forceMove(holder) S.connected = src return S /datum/wires/proc/detach_assembly(color) var/obj/item/assembly/S = get_attached(color) if(S && istype(S)) assemblies -= color S.connected = null S.forceMove(holder.drop_location()) return S /datum/wires/proc/emp_pulse() var/list/possible_wires = shuffle(wires) var/remaining_pulses = MAXIMUM_EMP_WIRES for(var/wire in possible_wires) if(prob(33)) pulse(wire) remaining_pulses-- if(!remaining_pulses) break // Overridable Procs /datum/wires/proc/interactable(mob/user) return TRUE /datum/wires/proc/get_status() return list() /datum/wires/proc/on_cut(wire, mend = FALSE) return /datum/wires/proc/on_pulse(wire, user) return // End Overridable Procs /datum/wires/proc/interact(mob/user) if(!interactable(user)) return ui_interact(user) for(var/A in assemblies) var/obj/item/I = assemblies[A] if(istype(I) && I.on_found(user)) return /datum/wires/ui_host() return holder /datum/wires/ui_status(mob/user) if(interactable(user)) return ..() return UI_CLOSE /datum/wires/ui_interact(mob/user, ui_key = "wires", datum/tgui/ui = null, force_open = FALSE, \ datum/tgui/master_ui = null, datum/ui_state/state = GLOB.physical_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if (!ui) ui = new(user, src, ui_key, "wires", "[holder.name] wires", 350, 150 + wires.len * 30, master_ui, state) ui.open() /datum/wires/ui_data(mob/user) var/list/data = list() var/list/payload = list() var/reveal_wires = FALSE // Admin ghost can see a purpose of each wire. if(IsAdminGhost(user)) reveal_wires = TRUE // Same for anyone with an abductor multitool. else if(user.is_holding_item_of_type(/obj/item/multitool/abductor)) reveal_wires = TRUE // Station blueprints do that too, but only if the wires are not randomized. else if(user.is_holding_item_of_type(/obj/item/areaeditor/blueprints) && !randomize) reveal_wires = TRUE for(var/color in colors) payload.Add(list(list( "color" = color, "wire" = ((reveal_wires && !is_dud_color(color)) ? get_wire(color) : null), "cut" = is_color_cut(color), "attached" = is_attached(color) ))) data["wires"] = payload data["status"] = get_status() return data /datum/wires/ui_act(action, params) if(..() || !interactable(usr)) return var/target_wire = params["wire"] var/mob/living/L = usr var/obj/item/I switch(action) if("cut") I = L.is_holding_tool_quality(TOOL_WIRECUTTER) if(I || IsAdminGhost(usr)) if(I && holder) I.play_tool_sound(holder, 20) cut_color(target_wire) . = TRUE else to_chat(L, "You need wirecutters!") if("pulse") I = L.is_holding_tool_quality(TOOL_MULTITOOL) if(I || IsAdminGhost(usr)) if(I && holder) I.play_tool_sound(holder, 20) pulse_color(target_wire, L) . = TRUE else to_chat(L, "You need a multitool!") if("attach") if(is_attached(target_wire)) I = detach_assembly(target_wire) if(I) L.put_in_hands(I) . = TRUE else I = L.get_active_held_item() if(istype(I, /obj/item/assembly)) var/obj/item/assembly/A = I if(A.attachable) if(!L.temporarilyRemoveItemFromInventory(A)) return if(!attach_assembly(target_wire, A)) A.forceMove(L.drop_location()) . = TRUE else to_chat(L, "You need an attachable assembly!") #undef MAXIMUM_EMP_WIRES