From 0bc337e3bc21490e53a1022aa5923749bab3a1b4 Mon Sep 17 00:00:00 2001 From: Geeves Date: Sat, 5 Jun 2021 17:00:43 +0200 Subject: [PATCH] GPS Stuff (#11692) --- aurorastation.dme | 4 + code/__defines/_layers.dm | 1 + code/_helpers/game.dm | 6 +- code/_helpers/unsorted.dm | 4 + code/game/objects/items.dm | 2 +- code/modules/compass/_compass.dm | 15 +++ code/modules/compass/compass_holder.dm | 125 +++++++++++++++++ code/modules/compass/compass_waypoint.dm | 26 ++++ code/modules/compass/~compass.dm | 3 + code/modules/mob/inventory.dm | 3 +- code/modules/telesci/gps.dm | 127 +++++++++++++++--- html/changelogs/geeves-gps_stuff.yml | 8 ++ icons/obj/telescience.dmi | Bin 7389 -> 7374 bytes vueui/src/components/view/devices/gps/gps.vue | 5 +- 14 files changed, 305 insertions(+), 24 deletions(-) create mode 100644 code/modules/compass/_compass.dm create mode 100644 code/modules/compass/compass_holder.dm create mode 100644 code/modules/compass/compass_waypoint.dm create mode 100644 code/modules/compass/~compass.dm create mode 100644 html/changelogs/geeves-gps_stuff.yml diff --git a/aurorastation.dme b/aurorastation.dme index 19a57b5831d..5dff3a36396 100644 --- a/aurorastation.dme +++ b/aurorastation.dme @@ -1592,6 +1592,10 @@ #include "code\modules\clothing\wrists\watches.dm" #include "code\modules\clothing\wrists\wrists.dm" #include "code\modules\clothing\wrists\xeno\unathi.dm" +#include "code\modules\compass\_compass.dm" +#include "code\modules\compass\compass_holder.dm" +#include "code\modules\compass\compass_waypoint.dm" +#include "code\modules\compass\~compass.dm" #include "code\modules\cooking\trays.dm" #include "code\modules\cooking\machinery\gibber.dm" #include "code\modules\cooking\machinery\icecream.dm" diff --git a/code/__defines/_layers.dm b/code/__defines/_layers.dm index a018e75bff0..e5a4670dc33 100644 --- a/code/__defines/_layers.dm +++ b/code/__defines/_layers.dm @@ -19,6 +19,7 @@ #define ABOVE_ALL_MOB_LAYER 4.5 #define LIGHTING_LAYER 11 #define EFFECTS_ABOVE_LIGHTING_LAYER 12 // For overlays you want to be above light. +#define UNDER_HUD_LAYER 19 #define HUD_LAYER 20 //Above lighting, but below obfuscation. For in-game HUD effects (whereas SCREEN_LAYER is for abstract/OOC things like inventory slots) #define OBFUSCATION_LAYER 21 //Where images covering the view for eyes are put #define SCREEN_LAYER 22 //Mob HUD/effects layer diff --git a/code/_helpers/game.dm b/code/_helpers/game.dm index a402670dcce..6fe43923af6 100644 --- a/code/_helpers/game.dm +++ b/code/_helpers/game.dm @@ -116,9 +116,9 @@ turfs += T return turfs -// Will recursively loop through an atom's locs until it finds the atom loc above a turf -/proc/recursive_loc_turf_check(var/atom/O, var/recursion_limit = 3) - if(recursion_limit <= 0 || isturf(O.loc)) +// Will recursively loop through an atom's locs until it finds the atom loc above a turf or its target_atom +/proc/recursive_loc_turf_check(var/atom/O, var/recursion_limit = 3, var/atom/target_atom) + if(recursion_limit <= 0 || isturf(O.loc) || O == target_atom) return O else O = O.loc diff --git a/code/_helpers/unsorted.dm b/code/_helpers/unsorted.dm index 2ff74f50b2e..4995a5ddc96 100644 --- a/code/_helpers/unsorted.dm +++ b/code/_helpers/unsorted.dm @@ -1027,6 +1027,10 @@ var/global/known_proc = new /proc/get_type_ref_bytes colour += temp_col return "#[colour]" +/proc/color_square(red, green, blue, hex) + var/color = hex ? hex : "#[num2hex(red, 2)][num2hex(green, 2)][num2hex(blue, 2)]" + return "___" + // call to generate a stack trace and print to runtime logs /proc/crash_with(msg) CRASH(msg) diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 13f63b251f5..0fb7554d806 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -339,7 +339,7 @@ // Called whenever an object is moved around inside the mob's contents. // Linker proc: mob/proc/prepare_for_slotmove, which is referenced in proc/handle_item_insertion and obj/item/attack_hand. // This shit exists so that dropped() could almost exclusively be called when an item is dropped. -/obj/item/proc/on_slotmove(var/mob/user) +/obj/item/proc/on_slotmove(var/mob/user, slot) if(zoom) zoom(user) diff --git a/code/modules/compass/_compass.dm b/code/modules/compass/_compass.dm new file mode 100644 index 00000000000..1ceb975b0c2 --- /dev/null +++ b/code/modules/compass/_compass.dm @@ -0,0 +1,15 @@ +#define COMPASS_INTERVAL 3 +#define COMPASS_PERIOD 15 +#define COMPASS_LABEL_OFFSET 150 + +/* + This folder contains an abstract type (/obj/compass_holder) which contains a set of + waypoints (/datum/compass_waypoint) and generates a circular compass with markers for + mobs that have the object in their screen list. See GPS for an example implementation. +*/ + +/image/compass_marker + maptext_height = 64 + maptext_width = 128 + maptext_x = -48 + maptext_y = -32 \ No newline at end of file diff --git a/code/modules/compass/compass_holder.dm b/code/modules/compass/compass_holder.dm new file mode 100644 index 00000000000..2eca5759b8d --- /dev/null +++ b/code/modules/compass/compass_holder.dm @@ -0,0 +1,125 @@ +/obj/compass_holder + name = null + icon = null + icon_state = null + screen_loc = "CENTER,CENTER" + + var/show_heading = FALSE + var/numeric_directions = FALSE + + var/image/compass_heading_marker + var/list/compass_static_labels + var/list/compass_waypoints + var/list/compass_waypoint_markers + + var/static/list/angle_step_to_dir = list( + "N", + "NE", + "E", + "SE", + "S", + "SW", + "W", + "NW", + "N" + ) + +/obj/compass_holder/Initialize(mapload, ...) + . = ..() + if(show_heading) + compass_heading_marker = new /image/compass_marker + compass_heading_marker.maptext = "
" + compass_heading_marker.filters = filter(type="drop_shadow", color = "#00ffffaa", size = 2, offset = 1,x = 0, y = 0) + compass_heading_marker.layer = UNDER_HUD_LAYER + + for(var/i in 0 to (360/(COMPASS_PERIOD))-1) + var/image/I = new /image/compass_marker + I.loc = src + var/str + var/str_col + if(i % COMPASS_INTERVAL == 0) + var/angle = (i * COMPASS_PERIOD) + if(numeric_directions) + str = "[angle]" + else + str = angle_step_to_dir[clamp(round(angle/45)+1, 1, length(angle_step_to_dir))] + str_col = "#ffffffaa" + else + str = "〡" + str_col = "#aaaaaa88" + I.maptext = "
[str]
" + var/matrix/M = matrix() + M.Translate(0, COMPASS_LABEL_OFFSET) + M.Turn(COMPASS_PERIOD * i) + I.transform = M + I.filters = filter(type="drop_shadow", color = "#77777777", size = 2, offset = 1,x = 0, y = 0) + I.layer = UNDER_HUD_LAYER + LAZYADD(compass_static_labels, I) + + rebuild_overlay_lists(TRUE) + +/obj/compass_holder/Destroy() + QDEL_NULL_LIST(compass_waypoints) + . = ..() + +/obj/compass_holder/proc/get_heading() + var/atom/A = loc?.loc // is there a get_holder_recursive() equivalent on Polaris? + if(istype(A)) + . = dir2angle(A.dir) + else + . = 0 + +/obj/compass_holder/update_icon() + var/set_overlays = (compass_static_labels | compass_waypoint_markers) + if(show_heading) + set_overlays |= compass_heading_marker + overlays = set_overlays + +/obj/compass_holder/proc/clear_waypoint(var/id) + LAZYREMOVE(compass_waypoints, id) + rebuild_overlay_lists(TRUE) + +/obj/compass_holder/proc/set_waypoint(var/id, var/label, var/heading_x, var/heading_y, var/heading_z, var/label_color) + var/datum/compass_waypoint/wp = LAZYACCESS(compass_waypoints, id) + if(!wp) + wp = new /datum/compass_waypoint() + wp.set_values(label, heading_x, heading_y, heading_z, label_color) + LAZYSET(compass_waypoints, id, wp) + rebuild_overlay_lists(TRUE) + +/obj/compass_holder/proc/recalculate_heading(var/rebuild_icon = TRUE) + if(show_heading) + var/matrix/M = matrix() + M.Translate(0, round(COMPASS_LABEL_OFFSET - 35)) + M.Turn(get_heading()) + compass_heading_marker.transform = M + if(rebuild_icon) + update_icon() + +/obj/compass_holder/proc/show_waypoint(var/id) + var/datum/compass_waypoint/wp = compass_waypoints[id] + wp.hidden = FALSE + +/obj/compass_holder/proc/hide_waypoint(var/id) + var/datum/compass_waypoint/wp = compass_waypoints[id] + wp.hidden = TRUE + +/obj/compass_holder/proc/hide_waypoints(var/rebuild_overlays = FALSE) + for(var/id in compass_waypoints) + hide_waypoint(id) + if(rebuild_overlays) + rebuild_overlay_lists(TRUE) + +/obj/compass_holder/proc/rebuild_overlay_lists(var/update_icon = FALSE) + compass_waypoint_markers = null + var/turf/T = get_turf(src) + if(istype(T)) + for(var/id in compass_waypoints) + var/datum/compass_waypoint/wp = compass_waypoints[id] + if(!wp.hidden) + wp.recalculate_heading(T.x, T.y) + LAZYADD(compass_waypoint_markers, wp.compass_overlay) + if(show_heading) + recalculate_heading(FALSE) + if(update_icon) + update_icon() diff --git a/code/modules/compass/compass_waypoint.dm b/code/modules/compass/compass_waypoint.dm new file mode 100644 index 00000000000..be9f2f7b4f9 --- /dev/null +++ b/code/modules/compass/compass_waypoint.dm @@ -0,0 +1,26 @@ +/datum/compass_waypoint + var/name + var/x + var/y + var/z + var/color + var/hidden = FALSE + var/image/compass_overlay + +/datum/compass_waypoint/proc/set_values(var/_name, var/_x, var/_y, var/_z, var/_color) + name = _name + x = _x + y = _y + z = _z + color = _color + compass_overlay = new /image/compass_marker + compass_overlay.loc = src + compass_overlay.maptext = "
|\n[name]
" + compass_overlay.filters = filter(type="drop_shadow", color = "[color]" + "aa", size = 2, offset = 1,x = 0, y = 0) + compass_overlay.layer = HUD_LAYER + +/datum/compass_waypoint/proc/recalculate_heading(var/cx, var/cy) + var/matrix/M = matrix() + M.Translate(0, (name ? COMPASS_LABEL_OFFSET-4 : COMPASS_LABEL_OFFSET)) + M.Turn(arctan(cy-y, cx-x)+180) + compass_overlay.transform = M \ No newline at end of file diff --git a/code/modules/compass/~compass.dm b/code/modules/compass/~compass.dm new file mode 100644 index 00000000000..7546d7a1e69 --- /dev/null +++ b/code/modules/compass/~compass.dm @@ -0,0 +1,3 @@ +#undef COMPASS_INTERVAL +#undef COMPASS_PERIOD +#undef COMPASS_LABEL_OFFSET \ No newline at end of file diff --git a/code/modules/mob/inventory.dm b/code/modules/mob/inventory.dm index 55160b38afb..bfc2163d539 100644 --- a/code/modules/mob/inventory.dm +++ b/code/modules/mob/inventory.dm @@ -38,8 +38,7 @@ //This is an UNSAFE proc. It merely handles the actual job of equipping. All the checks on whether you can or can't eqip need to be done before! Use mob_can_equip() for that task. //In most cases you will want to use equip_to_slot_if_possible() /mob/proc/equip_to_slot(obj/item/W, slot, redraw_mob, assisted_equip) - W.on_slotmove(src) - return + W.on_slotmove(src, slot) //This is just a commonly used configuration for the equip_to_slot_if_possible() proc, used to equip people when the rounds tarts and when events happen and such. /mob/proc/equip_to_slot_or_del(obj/item/W as obj, slot) diff --git a/code/modules/telesci/gps.dm b/code/modules/telesci/gps.dm index ea86386e881..2a12bca4360 100644 --- a/code/modules/telesci/gps.dm +++ b/code/modules/telesci/gps.dm @@ -10,19 +10,28 @@ var/list/GPS_list = list() origin_tech = list(TECH_DATA = 2, TECH_ENGINEERING = 2) var/gps_prefix = "COM" var/gpstag = "COM0" - var/emped = 0 - var/held_by = null - var/implanted_into = null + var/compass_color = "#193A7A" + + var/emped = FALSE + + var/mob/held_by = null + var/mob/implanted_into = null var/turf/locked_location + var/list/tracking = list() + var/list/tracking_compass + var/obj/compass_holder/compass var/list/static/gps_count = list() + var/process_interval = 6 SECONDS + var/last_process = 0 + /obj/item/device/gps/Initialize() . = ..() + compass = new(src) gpstag = next_initial_tag() name = "global positioning system ([gpstag])" update_position() - add_overlay("working") if(ismob(loc)) if(ishuman(loc)) @@ -32,10 +41,14 @@ var/list/GPS_list = list() else implanted_into = loc else if(issilicon(loc)) + held_by = loc implanted_into = loc else if(istype(loc, /obj/item/robot_module)) + held_by = loc.loc implanted_into = loc.loc + update_icon() + if(held_by) moved_event.register(held_by, src, /obj/item/device/gps/proc/update_position) if(implanted_into) @@ -45,6 +58,8 @@ var/list/GPS_list = list() for(var/gps in GPS_list) tracking += GPS_list[gps]["tag"] + START_PROCESSING(SSprocessing, src) + /obj/item/device/gps/Destroy() GPS_list -= GPS_list[gpstag] moved_event.unregister(src, src) @@ -54,29 +69,64 @@ var/list/GPS_list = list() if(implanted_into) moved_event.unregister(implanted_into, src) implanted_into = null + STOP_PROCESSING(SSprocessing, src) return ..() +/obj/item/device/gps/update_icon() + cut_overlays() + if(emped) + add_overlay("emp") + else if(held_by || implanted_into) + add_overlay("working") + else + add_overlay("confused") + /obj/item/device/gps/pickup(var/mob/user) ..() + if(held_by) + moved_event.unregister(held_by, src) held_by = user moved_event.register(user, src, /obj/item/device/gps/proc/update_position) + update_icon() /obj/item/device/gps/dropped(var/mob/user) ..() - held_by = null - moved_event.unregister(user, src) + if(isturf(loc)) + held_by = null + moved_event.unregister(user, src) + if(user.client) + user.client.screen -= compass + update_icon() + +/obj/item/device/gps/on_slotmove(mob/user, slot) + . = ..() + if(user.client && !(slot == slot_r_hand || slot == slot_l_hand)) + user.client.screen -= compass + +/obj/item/device/gps/equipped(mob/user, slot) + . = ..() + if(user.client && (slot == slot_r_hand || slot == slot_l_hand)) + user.client.screen |= compass + +/obj/item/device/gps/on_module_activate(mob/living/silicon/robot/R) + ..() + if(R.client) + R.client.screen |= compass + +/obj/item/device/gps/on_module_deactivate(mob/living/silicon/robot/R) + ..() + if(R.client) + R.client.screen -= compass /obj/item/device/gps/emp_act(severity) - emped = 1 - cut_overlay("working") - add_overlay("emp") - addtimer(CALLBACK(src, .proc/post_emp), 300) + emped = TRUE + addtimer(CALLBACK(src, .proc/post_emp), 30 SECONDS) + update_icon() update_position() /obj/item/device/gps/proc/post_emp() - emped = 0 - cut_overlay("emp") - add_overlay("working") + emped = FALSE + update_icon() update_position() /obj/item/device/gps/vueui_data_change(var/list/data, var/mob/user, var/datum/vueui/ui) @@ -95,6 +145,7 @@ var/list/GPS_list = list() tracking_list[tracking_tag] = (GPS_list[tracking_tag]) data["tracking_list"] = tracking_list + data["compass_list"] = tracking_compass return data // should update constantly @@ -109,6 +160,11 @@ var/list/GPS_list = list() ui.auto_update_content = TRUE ui.open() +/obj/item/device/gps/process() + if(held_by || implanted_into || (world.time < last_process + process_interval)) + return + update_position(FALSE) + /obj/item/device/gps/Topic(href, href_list) ..() @@ -144,6 +200,7 @@ var/list/GPS_list = list() if(GPS_list[new_tag]) tracking |= new_tag + update_compass(TRUE) else to_chat(usr, "Could not locate GPS tag.") @@ -151,29 +208,61 @@ var/list/GPS_list = list() if(href_list["remove_tag"]) tracking -= href_list["remove_tag"] - + update_compass(TRUE) return TRUE if(href_list["add_all"]) tracking.Cut() for(var/gps in GPS_list) tracking += GPS_list[gps]["tag"] - + update_compass(TRUE) return TRUE if(href_list["clear_all"]) tracking.Cut() tracking |= gpstag // always want to track ourselves + update_compass(TRUE) + return TRUE + if(href_list["compass"]) + var/tracking_tag = href_list["compass"] + if(LAZYISIN(tracking_compass, tracking_tag)) + LAZYREMOVE(tracking_compass, tracking_tag) + else + LAZYADD(tracking_compass, tracking_tag) + update_compass(TRUE) return TRUE return FALSE -/obj/item/device/gps/proc/update_position() +/obj/item/device/gps/proc/update_position(var/check_held_by = TRUE) var/turf/T = get_turf(src) + if(check_held_by && held_by && (held_by.x != T.x || held_by.y != T.y || held_by.z != T.z) && held_by != recursive_loc_turf_check(src, 3, held_by)) + moved_event.unregister(held_by, src) + held_by = null + update_icon() + return var/area/gpsarea = get_area(src) - GPS_list[gpstag] = list("tag" = gpstag, "pos_x" = T.x, "pos_y" = T.y, "pos_z" = T.z, "area" = "[gpsarea.name]", "emped" = emped) + GPS_list[gpstag] = list("tag" = gpstag, "pos_x" = T.x, "pos_y" = T.y, "pos_z" = T.z, "area" = "[gpsarea.name]", "emped" = emped, "compass_color" = compass_color) SSvueui.check_uis_for_change(src) + if(check_held_by && held_by && (held_by.get_active_hand() == src || held_by.get_inactive_hand() == src)) + update_compass(TRUE) + +/obj/item/device/gps/proc/update_compass(var/update_compass_icon) + compass.hide_waypoints(FALSE) + if(LAZYLEN(tracking_compass)) + for(var/tracking_tag in tracking_compass - gpstag) + if(!GPS_list[tracking_tag]) + continue + if(!(tracking_tag in tracking)) + continue + if(GPS_list[tracking_tag]["pos_x"] == GPS_list[gpstag]["pos_x"] && GPS_list[tracking_tag]["pos_y"] == GPS_list[gpstag]["pos_y"]) + continue + compass.set_waypoint(tracking_tag, tracking_tag, GPS_list[tracking_tag]["pos_x"], GPS_list[tracking_tag]["pos_y"], GPS_list[tracking_tag]["pos_z"], GPS_list[tracking_tag]["compass_color"]) + var/turf/origin = get_turf(src) + if(!emped && !GPS_list[tracking_tag]["emped"] && origin.z == GPS_list[tracking_tag]["pos_z"]) + compass.show_waypoint(tracking_tag) + compass.rebuild_overlay_lists(update_compass_icon) /obj/item/device/gps/proc/next_initial_tag() if(!LAZYACCESS(gps_count, gps_prefix)) @@ -187,20 +276,24 @@ var/list/GPS_list = list() /obj/item/device/gps/science icon_state = "gps-s" gps_prefix = "SCI" + compass_color = "#993399" gpstag = "SCI0" /obj/item/device/gps/engineering icon_state = "gps-e" gps_prefix = "ENG" + compass_color = "#A66300" gpstag = "ENG0" /obj/item/device/gps/mining icon_state = "gps-m" gps_prefix = "MIN" + compass_color = "#5F4519" gpstag = "MIN0" desc = "A positioning system helpful for rescuing trapped or injured miners, keeping one on you at all times while mining might just save your life." /obj/item/device/gps/janitor icon_state = "gps-j" gps_prefix = "JAN" + compass_color = "#6eaa2c" gpstag = "JAN0" \ No newline at end of file diff --git a/html/changelogs/geeves-gps_stuff.yml b/html/changelogs/geeves-gps_stuff.yml new file mode 100644 index 00000000000..24f76f8744a --- /dev/null +++ b/html/changelogs/geeves-gps_stuff.yml @@ -0,0 +1,8 @@ +author: Geeves + +delete-after: True + +changes: + - rscadd: "GPSs now have an idle mode, where they will update their transmitted location every six seconds. This mode activates if they're not in someone's possession." + - tweak: "You can now keep your GPS in your bag, webbing, etc. It will keep actively updating as you move. If you drop the bag, webbing, etc., it'll swap into idle mode after you move again." + - rscadd: "Ported the GPS compass, selecting a GPS to track on the C-Track column will add it to the compass. The GPS must be in your active hand/slot to show you the compass." \ No newline at end of file diff --git a/icons/obj/telescience.dmi b/icons/obj/telescience.dmi index 73b42fee305fc29c26250c54fe85a0ae28fdd763..ddcb0eb7ad3c9811eda77c685cbd5b91c219d9e8 100644 GIT binary patch literal 7374 zcmb_hcTiLDmcF6)-b(@^MG$EMijYK#LArpTAiaq64g!IQh=@QCq<29;=^)ZO2ntB= z9R#FE4}?HqaF;vhjT8?)}Wo6#)Fx6XM!j+a(!P2lkDN7rBfVhjS$! z>Ln1LE3bBHTB}?4Iz?j7zz%Bq)+vsZh;i-*>|46_4p-8Xzq>2= z6-?8;mdS~ER06(|(bxH7VngfmPSh{M=&b4%eLXXM#`2D*Qwss^XQS-*L~nf{+cLbK z3S+6+n4fJ8dB4q(n^-=_uD7jmOe@WcZIWG=V*~*1ko&544gJ&qWFWm+#^$@bkN>!}(D6*_4U$RY5aQ*$opW^CGB=A((H#%Jk~s2%EseHa-^|4;)lMf5nI& zY^}Zkzj@7C*;a}*kv&aTN+N7g`Ij0UgW}jGU9X>+Q+0P_76PB{ zoXp?x^F1jjDlH|;iP{kM3QP4EQuBco2NPf#9B{|Vsr7WmslARlj7UlHE2z&txc1NngY&b@+Rho@O!?8talQ37d{%huD$c@3d+v z?_irQV*<`JzbVBLHWEakHlN?N9wy)-@nwLS9f=*>CYZm*sLcLJb?N>x{B%HhkopH_#gH6> z?8;}K9G>8SfNcPPO)-i!=$4=Eoq&h4wje*kBc9?7G%X5#t*dL@x@LF1IMDz=MIQY5 zT!YFCfaPB{%u<~DTGSx$@bJ<~T-*-{*+-+BSAo`Dd&FYR?lh)h{LxZC7RUAqNcXJj zKq5$ls{vXL+S9vWP|6(K#GQ~M)s!sNPJPYve>~#pKc$Y-|K@1o|0#H=XJq#1vJ&g5 zj%mX16rXeN!rC$CPDuPzVSddh>^2^bFpqqlZPa@$d4S5AI$N$eK%!`sWm=-6C|FYE zfrZi(+MF}$SZoJ3ykt?Xa@VaXY0Q)AvUxH0oWGHs7K2GrF@c;98E?s{?%X1Hah7S= zB3D@U-@##2dNJX{}` zbbtTn&PK-Kky4@seR3M|y+samcWYq=qbXD3|0BCYt_roRu!{Qtiavc63WYL#e-p5s zf(1K*&-H{^GgFj6Qc@l6wWZ(@X_>tg49`V&S*Jwmp`_FXSgNV&P;nmSJ$p@H1Qw(x zg5B}(tn%Q^^#HzpFZg>+nySv=a+#vGF|!p*SLw35qv#RilR(bjP96Cwq38@|bq-^N}48>aMw z=yiHpjOM~8@|!7I?N0IBmK>!jqxtVFNy!%tu^m1b_1@(02^;y`!ozC?-o8vggzyKa z4R*;a*1ccCpG3sO4kxKdi(%Hxk<(enB`tkaUeqibZb8lrqNxZ0A$yK{77MQj+kVncB3kh#lh}J7_&rij96cekXt0g#{mCU5YcIqz`(waz*eTayLT3}$T zv1tUR8?+XGJP;p`nuFXwLJ(cz+AE;zpzNXP+=VI&kzNQp?UxyBM##O8p(Muu0j2Q} zXg}!po&M0ogoF*kj&pJvI-@J@W=-)unKixwN^Fx4g9opf znfPC8Hh~D@Jl>^a$eqeAUx!nExG3Zg>K!=49gdTSP9z~22I{R7IX6I$xwyruDoP6e zOnL;dn!jtFhf?=ww>(Y$t_|aql=mE6N8)d9O1yDnczRd9=GsKkMyJQxGC3;*0HpOG26+B z;IFh!Mz;d$`~XY-@&F|1a(K7XJJQlsV}q;!I4R+Lc%X63OpzVpg%Hjuv5#%Kq25Dx zmO>a=r@_dCXT3LdpsCHNkIy_vv+w%QRK!i5)tv2en$*XZEM%H$-z7S1Yzt>A{vgr$ zl=^9(aC0j?IGF;FjDmc>EkErUuxeL4ITt!2CSlX3`LZHdCo~_Y-;eQPD!2A~`(Z^y z+Hw?kRVw0@REu7$jB??X5iJ5DOKQ8}@SqOtJM0-EYl)m*E9|tBy|F6ynvFTv^;C4q z1I@hDVtzekI2p}VsHx-&sV3e6dyVRt4L44+E{(5a?Y+w^4|HZdPrTS&oElfL|6 zpy6ERE1i#t7_MFgbB^^7Tbmr)VxsL-e&Lcbu%dxzfivBXPZWhdnnWOnF2Ay`Rlvq4fQR%`u zpsLrat^%*D>AxQrrRbMXKMeYM^yo|nb!}oxwk{^w#7m^ zY^5oim#g~wGEonQSZg=$W^HVL$p?6Ma6TF9`;Bie5{Di>lJETe5XNBQ%d(iz9p}C_ zD?95q@Mqa`KZYpEbnHZIDV6o!=|P#Kb#G~IV->qm#0jccA3Ez&26y(fu|Fp1BRCiC zzImtXuBHypivk*jg2jl}Tbqo`GBkhNMc+214)fLR+Dy@qY+P5kZ(g_ZsKtp&&n5() zJ0yXJdz1t{{fQ~tg&&_B6up{Z@D2%Mlr+vJbcIQKw!Kl+v&z+5d9tA6fY%#EN8aTSnzfAPSBkoevpxM4z&`Sk!O&r2`6! zgGs@`pw`cm1N-hmv0xYU)>>IJ?5bh~xt;XD`QMs|=biiPaAa>(Ru+p~t07dt^uSk- zo(I?~cPOi1?GgREQ!A-|E@>Q`<2#=o3P7g`0JV)CBxYnlGgA<@oSbDgc4^U036>r) zW`O+U?z5!S-CmNT>|nMpAKMbE)owo$w6#$wkJTt$O3V`?KrzF|6eE@iK`W~Z8ub3q zq{lfeW0&ayJ073J;IuA*d3<4ke{PT^-ZCu`LtkhVbo2K4*wdUhW8=aUC3-v%y%MZL z+iwZV3h3Ri)a+&A&y0|gnoZ^~HoYKt=pscI`BjRT|8h7eu}m2%a8wgUK)Fp2;n4Q4 z6=y8pEoCx-W$Ztf@Ul(Hd6%J$0f!9=6F$(oEA6zKAXd+d1MOe7G3}?l@^%xH?U3Jh z8;K%=Q@0L{m$(;Z5lwtc%v_;l>O;C-uO@==DnRS$h;Y}DmCd&|yIDa?ZmH{UDRdnu zxB&e_#xO3C9nhIZkepyTep6Jg8QFPzA5I>*rroyJuse8#8jm|a5hT#Z#ZZ>k1?(~76xQE0pN8=|G}AN)N;?4CD9SDKr>M8~qaGi)4|iRDlf9gK zO;CQHM5nAVYPOSkIUq#!*`w>jyS%ta+Md3evS*DB_r#|rZkqc}Em-dF`#)68Uw~Nc zQ@*^ruVgv(g6_SQ2#St?4cXgpgdQj5y)5x+)h&PT`J;qy`345C8 z4IoDya9mUbpkA=^bnKX_{1HGc`7OKM7DQ9sWlj0z{w0-zty07 zy1QqdlSo_)(9BN>v{M8ylrco25rrTOib^C^p7d`zI#6hkP;pAaCrPx18n0ExOKy9G z?vbaG(lX!#Npgh#@#wVM8UB6K`WJod|FE=790%R-8Z|yD(7Fyy74vw&n3^6opB=Kd zK@BXj@FKPj8t$zxd0c#azUYI04EEn7K88!Z*d$jXS!GR)eD!OYGx4pT!;N`d6G&D$ z>{CwJO?m>S-)=t?RUC-F@yZXX4r|1)a>sV%tuUtbm(Bz(AHIWbh`qWnB-T&uR{7+x%gBAP{%>!?kg*)}0u-|yXFd|`AAJ*8Y*smOlQDeE3MOwTWxQCnn zR9wumQ@?eChUfRZk)NO6%J4_c+F-nbYr`Koz&#N5^k;f(M*LV{0X0y*HpF!!x-})8 z2L$XCl^PZQy=e<#Z`mc-zM&!XP3CC&wL~KONej~#uZ>vV&Xh>t0WbEe0{l?W$1PZE zoIZ$wp`!z(LbmnlYWWr==5PDLJ{2*8fAh&?KmJp5=3-URG)8jl3q@ zdx53<*+sn-3VwGhYv&qIV@{H8nCUA?^aa@i?8U9^-KeoU1=J=fu_*%pv3n(>Tf9L~~fWH^QD5EUy%@K_s87RAE^0dKI3l8gu#DX<>P7ZuQ9H=MzCd>x4xJZR`9B z2ySTje&mA7R>nC8iwe6UDkk=-XRD=~-59K5WtFp&U~JC#Rq=ujupHv{s_@@mj^)%< zAQ@XARZP$OgUsGy7**VfTRwva(5Z`Dk&w{!J18RZz~|gqxNDOJigqDW^j^QiKQ>>U zeXnMWh9kS_6lfUgvu~yG(pw|$L8&rCH3XtZ0z4Zzzwg`An-*#MpedjCp@^86$*iC# za3}NKy~T9LxtDR6Z*p={IT@6)j0bSZZ#D$rACpY0mNK^p6|y1}o;Uq}W553!YUGrC zV8o}Ur}LEJ{x=5wt{h2I;SijOo!BB3em^wk6J=sFBh|L5>tZlaU(A*f-k@)o}w z^NdUjrbNNQ;R^&(B~vBLhxELcxJhmtF&cz?RW8k!ySc)~Q#A?jFpofI$npwQSKfW1 zybH;q{UfJ%67^HotUfbCmhSQ6$CX)ibd*W3v&zL?y`f|a5$~zuLXXph`?v9NNF&>) z(TAU4O2UYUNSy;s!d8F4Qr0BH!cVi0PG%lRRZn=M0Mv=;=eoM1QG~ZXD3Yufv;%w_O(78_bMzY>6)1Ed6W!O z(c0Zsl-TJIJ>TBd?W*7>wvtW>tE`kp3rVJEDJS(uG6CDVZcQ6W05%hX69np=jq*+h zclm<{TR{XbYWot@6;>T&R;LH6!3#DT+%NTJ(}ErEgqPLN*bNW0&^Yu-u;7;aFQZKt zh}=uDK)UE9A&fjbtqu_+&$MZ3#&Ch1eZ*P04a;Svo?@xQfv4AlIycCN^FayFU*#hU zXQtGx=2QfG+(U%AOH6KgvNNYnm}ytgFg8agrwq9R+aIq^Wd;cnz%E2##}GlpNqWT2 z!WnBeO3->-#a%4m)3}N8@heDAGJ^fk@cau#fqM~}rU+_hUU6XY{rvDe2gsBao9?Iu-1EA+M_=6_8o>MQ>XQgT07|MiJji!L6L{ZPKPHZ}88{9MNF*2q zZzU0iZ7rer*z`j7kr<>tdVJg{klv{wBKbG}WVzML$&vg0zo#iA&v{9YgjqPt3Hj@K zS|vdpo+@gI6L3AzFk#rl`VWs=lpgr}o#nA2=}rnS!fGEC91%R+dSZ+wT=y+rVLkkb zzJb-oltjrVPJ%?FH|TX93dYA>no-Y$!2Y}kGb@oiBZwtZ^xUrfWC@(tCPCNZYGch?zVcg2A&_l85!$ClanHWbjOYOL`jE1zN?*GAF8Wa4GMI|?4Cw5BbYCa+vnBa>L5(K z6)IQOA|w*oTx&6?i=V*HipTqQ&QxpOj|?+FN9U&4X~Qtt7HUDcJ68~U=y@U4qdS{2Q}*ACZ_L3wl7@84ac z0q#tlhaPfcQ0h%ZX0CCvn``V;IIQ~Lv4uZS3{VuvC-#(azs3=m%~W8&YL#Ql1a~F- zsb}!26A}Hl5WHp*vZMX`tUJWef=hjMPPMz4GhM688AcDmD(W63eflPWLN`qWnYoAm z5b^qwea=cujnw7licL)YT;DueEEIn~Iq_K*Yo_9}IQ(IBnq4p2%`Jx@mc=n+L`>|d zzL$J2_-f<7l~Uw75z^M%-R{Tsg^(sc2_U0#Y_!-r$*6iX~$(bk|t~+O9&BC!^Vz@`>s7;2((;<5v>ovLjcp9VvpkK2TGcCgwP#Cat3qaq*^`7+Z^y1uJ#(Q+tPW9w}@Y zF$6?Y{#+ubWAV+mX+NR$)s$;2tts~)_DoXKwvjq{dQ(=C->Wb`TBKvJbDY@ zQR%V#QBn;ZiI;X7zrNqpW!*Ma^%OLjg{*w6Z3H7kNC*OX;4roe8ao#x8KkDAxRu6$ zO3MNGa&tfy-|`pd>8LjYcT|3TH5dspxnjJ}$@Z2sP2TNWQ-D&Y7|6W1p0^kLgsL@I z*ZbhteW3Ms-a8;vCR848v4!DyNYr@Y%(ccgV5nyC6IEnX5<2A^-erB))RepVkaxYn z*fU-!Cl&R8d!FnF$2UJi^91QAD$PYu=jvPwzR~bWzu-)>umd8ga_32lKgG2 z(PgvOlo-a0dvo z-Onzv%5ti{+cMerr;@&G1FEK?h{@?{9~y3a9p*>6ji2~LPgXF+BW^!q?=#I7BSaVZ z_ASzpfo_&Y#1HgjB$@x?0J71n)?FIhVQOcW5Q~9dV!L6I3eWN;_|5s&wrFvg-cuE& zbF~{aa!Z_Dmy`lcx*Kl7=B^(?bGqslOBUi^&y`;~Uo+P+s literal 7389 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 diff --git a/vueui/src/components/view/devices/gps/gps.vue b/vueui/src/components/view/devices/gps/gps.vue index dd3fcf41b82..a6252716d13 100644 --- a/vueui/src/components/view/devices/gps/gps.vue +++ b/vueui/src/components/view/devices/gps/gps.vue @@ -14,12 +14,15 @@ Location Area Remove + C-Track {{ gps.tag }} {{ gps.pos_x }}, {{ gps.pos_y }}, {{ gps.pos_z }} {{ gps.area }} - Untrack + Untrack + + Compass