///Global GPS_list. All GPS components get saved in here for easy reference. GLOBAL_LIST_EMPTY(GPS_list) ///GPS component. Atoms that have this show up on gps. Pretty simple stuff. /datum/component/gps var/gpstag = "COM0" var/tracking = TRUE var/emped = FALSE /datum/component/gps/Initialize(_gpstag = "COM0") if(!isatom(parent)) return COMPONENT_INCOMPATIBLE gpstag = _gpstag GLOB.GPS_list += src /datum/component/gps/Destroy() GLOB.GPS_list -= src return ..() ///GPS component subtype. Only gps/item's can be used to open the UI. /datum/component/gps/item var/updating = TRUE //Automatic updating of GPS list. Can be set to manual by user. var/global_mode = TRUE //If disabled, only GPS signals of the same Z level are shown /datum/component/gps/item/Initialize(_gpstag = "COM0", emp_proof = FALSE) . = ..() if(. == COMPONENT_INCOMPATIBLE || !isitem(parent)) return COMPONENT_INCOMPATIBLE var/atom/A = parent A.add_overlay("working") A.name = "[initial(A.name)] ([gpstag])" RegisterSignal(parent, COMSIG_ITEM_ATTACK_SELF, .proc/interact) if(!emp_proof) RegisterSignal(parent, COMSIG_ATOM_EMP_ACT, .proc/on_emp_act) RegisterSignal(parent, COMSIG_PARENT_EXAMINE, .proc/on_examine) RegisterSignal(parent, COMSIG_CLICK_ALT, .proc/on_AltClick) ///Called on COMSIG_ITEM_ATTACK_SELF /datum/component/gps/item/proc/interact(datum/source, mob/user) if(user) nano_ui_interact(user) ///Called on COMSIG_PARENT_EXAMINE /datum/component/gps/item/proc/on_examine(datum/source, mob/user, list/examine_list) examine_list += "Alt-click to switch it [tracking ? "off":"on"]." ///Called on COMSIG_ATOM_EMP_ACT /datum/component/gps/item/proc/on_emp_act(datum/source, severity) emped = TRUE var/atom/A = parent A.cut_overlay("working") A.add_overlay("emp") addtimer(CALLBACK(src, .proc/reboot), 300, TIMER_UNIQUE|TIMER_OVERRIDE) //if a new EMP happens, remove the old timer so it doesn't reactivate early SStgui.close_uis(src) //Close the UI control if it is open. ///Restarts the GPS after getting turned off by an EMP. /datum/component/gps/item/proc/reboot() emped = FALSE var/atom/A = parent A.cut_overlay("emp") A.add_overlay("working") ///Calls toggletracking /datum/component/gps/item/proc/on_AltClick(datum/source, mob/user) toggletracking(user) ///Toggles the tracking for the gps /datum/component/gps/item/proc/toggletracking(mob/user) if(!user.canUseTopic(parent, BE_CLOSE)) return //user not valid to use gps if(emped) to_chat(user, "It's busted!") return var/atom/A = parent if(tracking) A.cut_overlay("working") to_chat(user, "[parent] is no longer tracking, or visible to other GPS devices.") tracking = FALSE else A.add_overlay("working") to_chat(user, "[parent] is now tracking, and visible to other GPS devices.") tracking = TRUE /datum/component/gps/item/nano_ui_interact(mob/user, ui_key = "gps", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) // Remember to use the appropriate state. if(emped) to_chat(user, "[parent] fizzles weakly.") return ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) var/gps_window_height = 300 + GLOB.GPS_list.len * 20 // Variable window height, depending on how many GPS units there are to show ui = new(user, src, ui_key, "gps", "Global Positioning System", 600, gps_window_height, master_ui, state) //width, height ui.open() ui.set_autoupdate(state = updating) /datum/component/gps/item/ui_data(mob/user) var/list/data = list() data["power"] = tracking data["tag"] = gpstag data["updating"] = updating data["globalmode"] = global_mode if(!tracking || emped) //Do not bother scanning if the GPS is off or EMPed return data var/turf/curr = get_turf(parent) data["current"] = "[get_area_name(curr, TRUE)] ([curr.x], [curr.y], [curr.z])" var/list/signals = list() data["signals"] = list() for(var/gps in GLOB.GPS_list) var/datum/component/gps/G = gps if(G.emped || !G.tracking || G == src) continue var/turf/pos = get_turf(G.parent) if(!pos || !global_mode && pos.z != curr.z) continue var/list/signal = list() signal["entrytag"] = G.gpstag //Name or 'tag' of the GPS signal["area"] = get_area_name(G, TRUE) signal["coord"] = "[pos.x], [pos.y], [pos.z]" if(pos.z == curr.z) //Distance/Direction calculations for same z-level only signal["dist"] = max(get_dist(curr, pos), 0) //Distance between the src and remote GPS turfs signal["degrees"] = round(Get_Angle(curr, pos)) //0-360 degree directional bearing, for more precision. var/direction = uppertext(dir2text(get_dir(curr, pos))) //Direction text (East, etc). Not as precise, but still helpful. if(!direction) direction = "CENTER" signal["degrees"] = "N/A" signal["direction"] = direction signals += list(signal) //Add this signal to the list of signals data["signals"] = signals return data /datum/component/gps/item/ui_act(action, params) if(..()) return switch(action) if("rename") var/atom/parentasatom = parent var/a = input("Please enter desired tag.", parentasatom.name, gpstag) as text|null if (!a) return a = copytext(sanitize(a), 1, 20) gpstag = a . = TRUE parentasatom.name = "global positioning system ([gpstag])" if("power") toggletracking(usr) . = TRUE if("updating") updating = !updating . = TRUE if("globalmode") global_mode = !global_mode . = TRUE