--[[-------------------------------------------------------------------------- -- TomTom by Cladhaire <cladhaire@gmail.com> ----------------------------------------------------------------------------]] -- Simple localization table for messages local L = TomTomLocals local Astrolabe = DongleStub("Astrolabe-0.4") local ldb = LibStub("LibDataBroker-1.1") -- Speed up minimap updates Astrolabe.MinimapUpdateTime = 0.1 -- Create the addon object TomTom = { events = {}, eventFrame = CreateFrame("Frame"), RegisterEvent = function(self, event, method) self.eventFrame:RegisterEvent(event) self.events[event] = method or event end, UnregisterEvent = function(self, event) self.eventFrame:UnregisterEvent(event) self.events[event] = nil end, version = GetAddOnMetadata("TomTom", "Version") } if TomTom.version == "wowi:revision" then TomTom.version = "SVN" end TomTom.eventFrame:SetScript("OnEvent", function(self, event, ...) local method = TomTom.events[event] if method and TomTom[method] then TomTom[method](TomTom, event, ...) end end) TomTom:RegisterEvent("ADDON_LOADED") -- Local definitions local GetCurrentCursorPosition local WorldMap_OnUpdate local Block_OnClick,Block_OnUpdate,BlockOnEnter,BlockOnLeave local Block_OnDragStart,Block_OnDragStop local callbackTbl local RoundCoords local waypoints = {} function TomTom:ADDON_LOADED(event, addon) if addon == "TomTom" then self:UnregisterEvent("ADDON_LOADED") self.defaults = { profile = { general = { confirmremoveall = true, announce = false, corpse_arrow = true, }, block = { enable = true, accuracy = 2, bordercolor = {1, 0.8, 0, 0.8}, bgcolor = {0, 0, 0, 0.4}, lock = false, height = 30, width = 100, fontsize = 12, }, mapcoords = { playerenable = true, playeraccuracy = 2, cursorenable = true, cursoraccuracy = 2, }, arrow = { enable = true, goodcolor = {0, 1, 0}, badcolor = {1, 0, 0}, middlecolor = {1, 1, 0}, arrival = 15, lock = false, noclick = false, showtta = true, autoqueue = true, menu = true, scale = 1.0, alpha = 1.0, title_width = 0, title_height = 0, title_scale = 1, title_alpha = 1, setclosest = true, }, minimap = { enable = true, otherzone = true, tooltip = true, menu = true, }, worldmap = { enable = true, tooltip = true, otherzone = true, clickcreate = true, menu = true, create_modifier = "C", }, comm = { enable = true, prompt = false, }, persistence = { cleardistance = 10, savewaypoints = true, }, feeds = { coords = false, coords_throttle = 0.3, coords_accuracy = 2, arrow = false, arrow_throttle = 0.1, }, }, } self.waydefaults = { profile = { ["*"] = {}, }, } self.db = LibStub("AceDB-3.0"):New("TomTomDB", self.defaults, "Default") self.waydb = LibStub("AceDB-3.0"):New("TomTomWaypoints", self.waydefaults) self.db.RegisterCallback(self, "OnProfileChanged", "ReloadOptions") self.db.RegisterCallback(self, "OnProfileCopied", "ReloadOptions") self.db.RegisterCallback(self, "OnProfileReset", "ReloadOptions") self.waydb.RegisterCallback(self, "OnProfileChanged", "ReloadWaypoints") self.waydb.RegisterCallback(self, "OnProfileCopied", "ReloadWaypoints") self.waydb.RegisterCallback(self, "OnProfileReset", "ReloadWaypoints") self.tooltip = CreateFrame("GameTooltip", "TomTomTooltip", nil, "GameTooltipTemplate") self.dropdown = CreateFrame("Frame", "TomTomDropdown", nil, "UIDropDownMenuTemplate") self.waypoints = waypoints self.waypointprofile = self.waydb.profile self:RegisterEvent("PLAYER_LEAVING_WORLD") self:RegisterEvent("PLAYER_ENTERING_WORLD", "ZoneChanged") self:RegisterEvent("ZONE_CHANGED_NEW_AREA", "ZoneChanged") self:RegisterEvent("WORLD_MAP_UPDATE", "ZoneChanged") self:RegisterEvent("CHAT_MSG_ADDON") self:ReloadOptions() self:ReloadWaypoints() if self.db.profile.feeds.coords then -- Create a data feed for coordinates local feed_coords = ldb:NewDataObject("TomTom_Coords", { type = "data source", icon = "Interface\\Icons\\INV_Misc_Map_01", text = "", }) local coordFeedFrame = CreateFrame("Frame") local throttle, counter = self.db.profile.feeds.coords_throttle, 0 function TomTom:UpdateCoordFeedThrottle() throttle = self.db.profile.feeds.coords_throttle end coordFeedFrame:SetScript("OnUpdate", function(self, elapsed) counter = counter + elapsed if counter < throttle then return end counter = 0 local c,z,x,y = Astrolabe:GetCurrentPlayerPosition() local opt = TomTom.db.profile if x and y then feed_coords.text = string.format("%s", RoundCoords(x, y, opt.feeds.coords_accuracy)) end end) end end end function TomTom:ReloadOptions() -- This handles the reloading of all options self.profile = self.db.profile self:ShowHideWorldCoords() self:ShowHideCoordBlock() self:ShowHideCrazyArrow() end function TomTom:ReloadWaypoints() local pc, pz = GetCurrentMapContinent(), GetCurrentMapZone() for uid,value in pairs(waypoints) do self:ClearWaypoint(uid) end waypoints = {} self.waypoints = waypoints self.waypointprofile = self.waydb.profile for zone,data in pairs(self.waypointprofile) do local c,z = self:GetCZ(zone) local same = (c == pc) and (z == pz) local minimap = self.profile.minimap.enable and (self.profile.minimap.otherzone or same) local world = self.profile.worldmap.enable and (self.profile.worldmap.otherzone or same) for idx,waypoint in ipairs(data) do local coord,title = waypoint:match("^(%d+):(.*)$") if not title:match("%S") then title = nil end local x,y = self:GetXY(coord) self:AddZWaypoint(c, z, x*100, y*100, title, false, minimap, world, nil, true) end end end function TomTom:ZoneChanged() -- Update the visibility of the coordinate box self:ShowHideCoordBlock() end function TomTom:ShowHideWorldCoords() -- Bail out if we're not supposed to be showing this frame if self.profile.mapcoords.playerenable or self.db.profile.mapcoords.cursorenable then -- Create the frame if it doesn't exist if not TomTomWorldFrame then TomTomWorldFrame = CreateFrame("Frame", nil, WorldMapFrame) TomTomWorldFrame.Player = TomTomWorldFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall") TomTomWorldFrame.Player:SetPoint("BOTTOM", WorldMapPositioningGuide, "BOTTOM", -100, 11) TomTomWorldFrame.Cursor = TomTomWorldFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall") TomTomWorldFrame.Cursor:SetPoint("BOTTOM", WorldMapPositioningGuide, "BOTTOM", 100, 11) TomTomWorldFrame:SetScript("OnUpdate", WorldMap_OnUpdate) end TomTomWorldFrame.Player:Hide() TomTomWorldFrame.Cursor:Hide() if self.profile.mapcoords.playerenable then TomTomWorldFrame.Player:Show() end if self.profile.mapcoords.cursorenable then TomTomWorldFrame.Cursor:Show() end -- Show the frame TomTomWorldFrame:Show() elseif TomTomWorldFrame then TomTomWorldFrame:Hide() end end function TomTom:ShowHideCoordBlock() -- Bail out if we're not supposed to be showing this frame if self.profile.block.enable then -- Create the frame if it doesn't exist if not TomTomBlock then -- Create the coordinate display TomTomBlock = CreateFrame("Button", "TomTomBlock", UIParent) TomTomBlock:SetWidth(120) TomTomBlock:SetHeight(32) TomTomBlock:SetToplevel(1) TomTomBlock:SetFrameStrata("LOW") TomTomBlock:SetMovable(true) TomTomBlock:EnableMouse(true) TomTomBlock:SetClampedToScreen() TomTomBlock:RegisterForDrag("LeftButton") TomTomBlock:RegisterForClicks("RightButtonUp") TomTomBlock:SetPoint("TOP", Minimap, "BOTTOM", -20, -10) TomTomBlock.Text = TomTomBlock:CreateFontString(nil, "OVERLAY", "GameFontNormal") TomTomBlock.Text:SetJustifyH("CENTER") TomTomBlock.Text:SetPoint("CENTER", 0, 0) TomTomBlock:SetBackdrop({ bgFile = "Interface\\ChatFrame\\ChatFrameBackground", edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border", edgeSize = 16, insets = {left = 4, right = 4, top = 4, bottom = 4}, }) TomTomBlock:SetBackdropColor(0,0,0,0.4) TomTomBlock:SetBackdropBorderColor(1,0.8,0,0.8) -- Set behavior scripts TomTomBlock:SetScript("OnUpdate", Block_OnUpdate) TomTomBlock:SetScript("OnClick", Block_OnClick) TomTomBlock:SetScript("OnEnter", Block_OnEnter) TomTomBlock:SetScript("OnLeave", Block_OnLeave) TomTomBlock:SetScript("OnDragStop", Block_OnDragStop) TomTomBlock:SetScript("OnDragStart", Block_OnDragStart) end -- Show the frame TomTomBlock:Show() local opt = self.profile.block -- Update the backdrop color, and border color TomTomBlock:SetBackdropColor(unpack(opt.bgcolor)) TomTomBlock:SetBackdropBorderColor(unpack(opt.bordercolor)) -- Update the height and width TomTomBlock:SetHeight(opt.height) TomTomBlock:SetWidth(opt.width) -- Update the font size local font,height = TomTomBlock.Text:GetFont() TomTomBlock.Text:SetFont(font, opt.fontsize, select(3, TomTomBlock.Text:GetFont())) elseif TomTomBlock then TomTomBlock:Hide() end end -- Hook the WorldMap OnClick local world_click_verify = { ["A"] = function() return IsAltKeyDown() end, ["C"] = function() return IsControlKeyDown() end, ["S"] = function() return IsShiftKeyDown() end, } local origScript = WorldMapButton_OnClick WorldMapButton_OnClick = function(self, ...) local mouseButton, button = ... if mouseButton == "RightButton" then -- Check for all the modifiers that are currently set for mod in TomTom.db.profile.worldmap.create_modifier:gmatch("[ACS]") do if not world_click_verify[mod] or not world_click_verify[mod]() then return origScript and origScript(self, ...) or true end end -- Actually try to add a note local c,z = GetCurrentMapContinent(), GetCurrentMapZone() local x,y = GetCurrentCursorPosition() if z == 0 then return origScript and origScript(self, ...) or true end local uid = TomTom:AddZWaypoint(c,z,x*100,y*100) else return origScript and origScript(self, ...) or true end end if WorldMapButton:GetScript("OnMouseUp") == origScript then WorldMapButton:SetScript("OnMouseUp", WorldMapButton_OnClick) end local function WaypointCallback(event, arg1, arg2, arg3) if event == "OnDistanceArrive" then TomTom:ClearWaypoint(arg1) elseif event == "OnTooltipShown" then local tooltip = arg1 if arg3 then tooltip:SetText(L["TomTom waypoint"]) tooltip:AddLine(string.format(L["%s yards away"], math.floor(arg2)), 1, 1 ,1) tooltip:Show() else tooltip.lines[2]:SetFormattedText(L["%s yards away"], math.floor(arg2), 1, 1, 1) end end end --[[------------------------------------------------------------------- -- Dropdown menu code -------------------------------------------------------------------]]-- StaticPopupDialogs["TOMTOM_REMOVE_ALL_CONFIRM"] = { text = L["Are you sure you would like to remove ALL TomTom waypoints?"], button1 = L["Yes"], button2 = L["No"], OnAccept = function() TomTom.waydb:ResetProfile() TomTom:ReloadWaypoints() end, timeout = 30, whileDead = 1, hideOnEscape = 1, } local dropdown_info = { -- Define level one elements here [1] = { { -- Title text = L["Waypoint Options"], isTitle = 1, }, { -- set as crazy arrow text = L["Set as waypoint arrow"], func = function() local uid = TomTom.dropdown.uid local data = waypoints[uid] TomTom:SetCrazyArrow(uid, TomTom.profile.arrow.arrival, data.title or L["TomTom waypoint"]) end, }, { -- Send waypoint text = L["Send waypoint to"], hasArrow = true, value = "send", }, { -- Remove waypoint text = L["Remove waypoint"], func = function() local uid = TomTom.dropdown.uid local data = waypoints[uid] TomTom:RemoveWaypoint(uid) --TomTom:PrintF("Removing waypoint %0.2f, %0.2f in %s", data.x, data.y, data.zone) end, }, { -- Remove all waypoints from this zone text = L["Remove all waypoints from this zone"], func = function() local uid = TomTom.dropdown.uid local data = waypoints[uid] for uid in pairs(waypoints[data.zone]) do TomTom:RemoveWaypoint(uid) end end, }, { -- Remove ALL waypoints text = L["Remove all waypoints"], func = function() if TomTom.db.profile.general.confirmremoveall then StaticPopup_Show("TOMTOM_REMOVE_ALL_CONFIRM") else StaticPopupDialogs["TOMTOM_REMOVE_ALL_CONFIRM"].OnAccept() return end end, }, { -- Save this waypoint text = L["Save this waypoint between sessions"], checked = function() return TomTom:UIDIsSaved(TomTom.dropdown.uid) end, func = function() -- Check to see if it's already saved local uid = TomTom.dropdown.uid if TomTom:UIDIsSaved(uid) then local data = waypoints[uid] if data then local key = string.format("%d:%s", data.coord, data.title or "") local zone = data.zone local sv = TomTom.waypointprofile[zone] -- Find the entry in the saved variable for idx,entry in ipairs(sv) do if entry == key then table.remove(sv, idx) return end end end else local data = waypoints[uid] if data then local key = string.format("%d:%s", data.coord, data.title or "") local zone = data.zone local sv = TomTom.waypointprofile[zone] table.insert(sv, key) end end end, }, }, [2] = { send = { { -- Title text = L["Waypoint communication"], isTitle = true, }, { -- Party text = L["Send to party"], func = function() TomTom:SendWaypoint(TomTom.dropdown.uid, "PARTY") end }, { -- Raid text = L["Send to raid"], func = function() TomTom:SendWaypoint(TomTom.dropdown.uid, "RAID") end }, { -- Battleground text = L["Send to battleground"], func = function() TomTom:SendWaypoint(TomTom.dropdown.uid, "BATTLEGROUND") end }, { -- Guild text = L["Send to guild"], func = function() TomTom:SendWaypoint(TomTom.dropdown.uid, "GUILD") end }, }, }, } local function init_dropdown(self, level) -- Make sure level is set to 1, if not supplied level = level or 1 -- Get the current level from the info table local info = dropdown_info[level] -- If a value has been set, try to find it at the current level if level > 1 and UIDROPDOWNMENU_MENU_VALUE then if info[UIDROPDOWNMENU_MENU_VALUE] then info = info[UIDROPDOWNMENU_MENU_VALUE] end end -- Add the buttons to the menu for idx,entry in ipairs(info) do if type(entry.checked) == "function" then -- Make this button dynamic local new = {} for k,v in pairs(entry) do new[k] = v end new.checked = new.checked() entry = new else entry.checked = nil end UIDropDownMenu_AddButton(entry, level) end end function TomTom:InitializeDropdown(uid) self.dropdown.uid = uid UIDropDownMenu_Initialize(self.dropdown, init_dropdown) end function TomTom:UIDIsSaved(uid) local data = waypoints[uid] if data then local key = string.format("%d:%s", data.coord, data.title or "") local zone = data.zone local sv = TomTom.waypointprofile[zone] -- Find the entry in the saved variable for idx,entry in ipairs(sv) do if entry == key then return true end end end return false end function TomTom:SendWaypoint(uid, channel) local data = waypoints[uid] local msg = string.format("%s:%d:%s", data.zone, data.coord, data.title or "") SendAddonMessage("TOMTOM2", msg, channel) end function TomTom:CHAT_MSG_ADDON(event, prefix, data, channel, sender) if prefix ~= "TOMTOM2" then return end if sender == UnitName("player") then return end local zone,coord,title = string.split(":", data) if not title:match("%S") then title = string.format(L["Waypoint from %s"], sender) end local c,z = self:GetCZ(zone) local x,y = self:GetXY(tonumber(coord)) self:AddZWaypoint(c, z, x*100, y*100, title) local msg = string.format(L["|cffffff78TomTom|r: Added '%s' (sent from %s) to zone %s"], title, sender, zone) ChatFrame1:AddMessage(msg) end --[[------------------------------------------------------------------- -- Define callback functions -------------------------------------------------------------------]]-- local function _minimap_onclick(event, uid, self, button) if TomTom.db.profile.minimap.menu then TomTom:InitializeDropdown(uid) ToggleDropDownMenu(1, nil, TomTom.dropdown, "cursor", 0, 0) end end local function _world_onclick(event, uid, self, button) if TomTom.db.profile.worldmap.menu then TomTom:InitializeDropdown(uid) ToggleDropDownMenu(1, nil, TomTom.dropdown, "cursor", 0, 0) end end local function _both_tooltip_show(event, tooltip, uid, dist) local data = waypoints[uid] tooltip:SetText(data.title or L["TomTom waypoint"]) if dist and tonumber(dist) then tooltip:AddLine(string.format(L["%s yards away"], math.floor(dist)), 1, 1, 1) else tooltip:AddLine(L["Unknown distance"]) end tooltip:AddLine(string.format(L["%s (%.2f, %.2f)"], data.zone, data.x, data.y), 0.7, 0.7, 0.7) tooltip:Show() end local function _minimap_tooltip_show(event, tooltip, uid, dist) if not TomTom.db.profile.minimap.tooltip then tooltip:Hide() return end return _both_tooltip_show(event, tooltip, uid, dist) end local function _world_tooltip_show(event, tooltip, uid, dist) if not TomTom.db.profile.worldmap.tooltip then tooltip:Hide() return end return _both_tooltip_show(event, tooltip, uid, dist) end local function _both_tooltip_update(event, tooltip, uid, dist) if dist and tonumber(dist) then tooltip.lines[2]:SetFormattedText(L["%s yards away"], math.floor(dist), 1, 1, 1) else tooltip.lines[2]:SetText(L["Unknown distance"]) end end local function _both_clear_distance(event, uid, range, distance, lastdistance) if not UnitOnTaxi("player") then TomTom:RemoveWaypoint(uid) end end local function _remove(event, uid) local data = waypoints[uid] local key = string.format("%d:%s", data.coord, data.title or "") local zone = data.zone local sv = TomTom.waypointprofile[zone] -- Find the entry in the saved variable for idx,entry in ipairs(sv) do if entry == key then table.remove(sv, idx) break end end -- Remove this entry from the waypoints table waypoints[uid] = nil if waypoints[zone] then waypoints[zone][uid] = nil end end local function noop() end function TomTom:RemoveWaypoint(uid) local data = waypoints[uid] self:ClearWaypoint(uid) if data then local key = string.format("%d:%s", data.coord, data.title or "") local zone = data.zone local sv = TomTom.waypointprofile[zone] -- Find the entry in the saved variable for idx,entry in ipairs(sv) do if entry == key then table.remove(sv, idx) break end end end -- Remove this entry from the waypoints table waypoints[uid] = nil if data and data.zone and waypoints[data.zone] then waypoints[data.zone][uid] = nil end end -- TODO: Make this not suck function TomTom:AddWaypoint(x, y, desc, persistent, minimap, world, silent) local c,z = GetCurrentMapContinent(), GetCurrentMapZone() if not c or not z or c < 1 then --self:Print("Cannot find a valid zone to place the coordinates") return end return self:AddZWaypoint(c, z, x, y, desc, persistent, minimap, world, silent) end function TomTom:AddZWaypoint(c, z, x, y, desc, persistent, minimap, world, custom_callbacks, silent, crazy) local callbacks if custom_callbacks then callbacks = custom_callbacks else callbacks = { minimap = { onclick = _minimap_onclick, tooltip_show = _minimap_tooltip_show, tooltip_update = _both_tooltip_update, }, world = { onclick = _world_onclick, tooltip_show = _world_tooltip_show, tooltip_update = _both_tooltip_show, }, distance = { }, } end local cleardistance = self.profile.persistence.cleardistance if cleardistance > 0 then callbacks.distance[cleardistance] = _both_clear_distance end -- Default values if persistent == nil then persistent = self.profile.persistence.savewaypoints end if minimap == nil then minimap = self.profile.minimap.enable end if world == nil then world = self.profile.worldmap.enable end if crazy == nil then crazy = self.profile.arrow.autoqueue end local coord = self:GetCoord(x / 100, y / 100) local zone = self:GetMapFile(c, z) if not zone then return end -- Ensure there isn't already a waypoint at this location if waypoints[zone] then for uid in pairs(waypoints[zone]) do local data = waypoints[uid] if data.title == desc and data.coord == coord then -- This is a duplicate waypoint, so return that uid return uid end end end local uid = self:SetWaypoint(c,z,x/100,y/100, callbacks, minimap, world) if crazy then self:SetCrazyArrow(uid, self.profile.arrow.arrival, desc) end waypoints[uid] = { title = desc, coord = coord, x = x, y = y, zone = zone, } if not waypoints[zone] then waypoints[zone] = {} end waypoints[zone][uid] = true -- If this is a persistent waypoint, then add it to the waypoints table if persistent then local data = string.format("%d:%s", coord, desc or "") table.insert(self.waypointprofile[zone], data) end if not silent and self.profile.general.announce then local ctxt = RoundCoords(x/100, y/100, 2) local msg = string.format(L["|cffffff78TomTom:|r Added a waypoint (%s%s%s) in %s"], desc and desc or "", desc and " - " or "", ctxt, zone) ChatFrame1:AddMessage(msg) end return uid end function TomTom:SetCustomWaypoint(c,z,x,y,callback,minimap,world, silent) return self:AddZWaypoint(c, z, x, y, desc, false, minimap, world, callback, silent) end -- Code taken from HandyNotes, thanks Xinhuan --------------------------------------------------------- -- Public functions for plugins to convert between MapFile <-> C,Z -- local continentMapFile = { [WORLDMAP_COSMIC_ID] = "Cosmic", -- That constant is -1 [0] = "World", [1] = "Kalimdor", [2] = "Azeroth", [3] = "Expansion01", } local reverseMapFileC = {} local reverseMapFileZ = {} for C = 1, #Astrolabe.ContinentList do for Z = 1, #Astrolabe.ContinentList[C] do local mapFile = Astrolabe.ContinentList[C][Z] reverseMapFileC[mapFile] = C reverseMapFileZ[mapFile] = Z end end for C = -1, 3 do local mapFile = continentMapFile[C] reverseMapFileC[mapFile] = C reverseMapFileZ[mapFile] = 0 end function TomTom:GetMapFile(C, Z) if not C or not Z then return end if Z == 0 then return continentMapFile[C] elseif C > 0 then return Astrolabe.ContinentList[C][Z] end end function TomTom:GetCZ(mapFile) return reverseMapFileC[mapFile], reverseMapFileZ[mapFile] end -- Public functions for plugins to convert between coords <--> x,y function TomTom:GetCoord(x, y) return floor(x * 10000 + 0.5) * 10000 + floor(y * 10000 + 0.5) end function TomTom:GetXY(id) return floor(id / 10000) / 10000, (id % 10000) / 10000 end do -- Code courtesy ckknight function GetCurrentCursorPosition() local x, y = GetCursorPosition() local left, top = WorldMapDetailFrame:GetLeft(), WorldMapDetailFrame:GetTop() local width = WorldMapDetailFrame:GetWidth() local height = WorldMapDetailFrame:GetHeight() local scale = WorldMapDetailFrame:GetEffectiveScale() local cx = (x/scale - left) / width local cy = (top - y/scale) / height if cx < 0 or cx > 1 or cy < 0 or cy > 1 then return nil, nil end return cx, cy end local coord_fmt = "%%.%df, %%.%df" function RoundCoords(x,y,prec) local fmt = coord_fmt:format(prec, prec) return fmt:format(x*100, y*100) end function WorldMap_OnUpdate(self, elapsed) local c,z,x,y = Astrolabe:GetCurrentPlayerPosition() local opt = TomTom.db.profile if not x or not y then self.Player:SetText("Player: ---") else self.Player:SetFormattedText("Player: %s", RoundCoords(x, y, opt.mapcoords.playeraccuracy)) end local cX, cY = GetCurrentCursorPosition() if not cX or not cY then self.Cursor:SetText("Cursor: ---") else self.Cursor:SetFormattedText("Cursor: %s", RoundCoords(cX, cY, opt.mapcoords.cursoraccuracy)) end end end do function Block_OnUpdate(self, elapsed) local c,z,x,y = Astrolabe:GetCurrentPlayerPosition() local opt = TomTom.db.profile if not x or not y then -- Hide the frame when we have no coordinates self:Hide() else self.Text:SetFormattedText("%s", RoundCoords(x, y, opt.block.accuracy)) end end function Block_OnDragStart(self, button, down) if not TomTom.db.profile.block.lock then self:StartMoving() end end function Block_OnDragStop(self, button, down) self:StopMovingOrSizing() end end local function usage() ChatFrame1:AddMessage(L["|cffffff78TomTom |r/way |cffffff78Usage:|r"]) ChatFrame1:AddMessage(L["|cffffff78/way <x> <y> [desc]|r - Adds a waypoint at x,y with descrtiption desc"]) ChatFrame1:AddMessage(L["|cffffff78/way <zone> <x> <y> [desc]|r - Adds a waypoint at x,y in zone with description desc"]) ChatFrame1:AddMessage(L["|cffffff78/way reset all|r - Resets all waypoints"]) ChatFrame1:AddMessage(L["|cffffff78/way reset <zone>|r - Resets all waypoints in zone"]) end local zlist = {} for cidx,c in ipairs{GetMapContinents()} do for zidx,z in ipairs{GetMapZones(cidx)} do zlist[z:lower():gsub("[%L]", "")] = {cidx, zidx, z} end end function TomTom:GetClosestWaypoint() local c,z,x,y = Astrolabe:GetCurrentPlayerPosition() local zone = TomTom:GetMapFile(c, z) local closest_uid = nil local closest_dist = nil if waypoints[zone] then for uid in pairs(waypoints[zone]) do local dist,x,y = TomTom:GetDistanceToWaypoint(uid) if (dist and closest_dist == nil) or (dist and dist < closest_dist) then closest_dist = dist closest_uid = uid end end end if closest_dist then return closest_uid end end function TomTom:SetClosestWaypoint() local uid = self:GetClosestWaypoint() if uid then local data = waypoints[uid] TomTom:SetCrazyArrow(uid, TomTom.profile.arrow.arrival, data.title) end end SLASH_TOMTOM_CLOSEST_WAYPOINT1 = "/cway" SLASH_TOMTOM_CLOSEST_WAYPOINT2 = "/closestway" SlashCmdList["TOMTOM_CLOSEST_WAYPOINT"] = function(msg) TomTom:SetClosestWaypoint() end SLASH_TOMTOM_WAYBACK1 = "/wayb" SLASH_TOMTOM_WAYBACK2 = "/wayback" SlashCmdList["TOMTOM_WAYBACK"] = function(msg) local backc,backz,backx,backy = Astrolabe:GetCurrentPlayerPosition() TomTom:AddZWaypoint(backc, backz, backx*100, backy*100, L["Wayback"]) end SLASH_TOMTOM_WAY1 = "/way" SLASH_TOMTOM_WAY2 = "/tway" SLASH_TOMTOM_WAY3 = "/tomtomway" SlashCmdList["TOMTOM_WAY"] = function(msg) local tokens = {} for token in msg:gmatch("%S+") do table.insert(tokens, token) end -- Lower the first token if tokens[1] then tokens[1] = tokens[1]:lower() end if tokens[1] == "reset" then if tokens[2] == "all" then if TomTom.db.profile.general.confirmremoveall then StaticPopup_Show("TOMTOM_REMOVE_ALL_CONFIRM") else StaticPopupDialogs["TOMTOM_REMOVE_ALL_CONFIRM"].OnAccept() return end elseif tokens[2] then -- Reset the named zone local zone = table.concat(tokens, " ", 2) -- Find a fuzzy match for the zone local matches = {} zone = zone:lower():gsub("[%L]", "") for z,entry in pairs(zlist) do if z:match(zone) then table.insert(matches, entry) end end if #matches > 5 then local msg = string.format(L["Found %d possible matches for zone %s. Please be more specific"], #matches, tokens[2]) ChatFrame1:AddMessage(msg) return elseif #matches > 1 then local poss = {} for k,v in pairs(matches) do table.insert(poss, v[3]) end table.sort(poss) ChatFrame1:AddMessage(string.format(L["Found multiple matches for zone '%s'. Did you mean: %s"], tokens[2], table.concat(poss, ", "))) return end local c,z,name = unpack(matches[1]) local zone = TomTom:GetMapFile(c, z) if waypoints[zone] then for uid in pairs(waypoints[zone]) do TomTom:RemoveWaypoint(uid) end else ChatFrame1:AddMessage(L["There were no waypoints to remove in %s"]:format(name)) end end elseif tokens[1] and not tonumber(tokens[1]) then -- Find the first numeric token local zoneEnd = 1 for idx,token in ipairs(tokens) do if tonumber(token) then zoneEnd = idx - 1 break end end -- This is a waypoint set, with a zone before the coords local zone = table.concat(tokens, " ", 1, zoneEnd) local x,y,desc = select(zoneEnd + 1, unpack(tokens)) if desc then desc = table.concat(tokens, " ", zoneEnd + 3) end -- Find a fuzzy match for the zone local matches = {} zone = zone:lower():gsub("[%L]", "") for z,entry in pairs(zlist) do if z:match(zone) then table.insert(matches, entry) end end if #matches ~= 1 then local msg = string.format(L["Found %d possible matches for zone %s. Please be more specific"], #matches, tokens[1]) ChatFrame1:AddMessage(msg) return end local c,z,name = unpack(matches[1]) if not x or not tonumber(x) then return usage() elseif not y or not tonumber(y) then return usage() end x = tonumber(x) y = tonumber(y) TomTom:AddZWaypoint(c, z, x, y, desc) elseif tonumber(tokens[1]) then -- A vanilla set command local x,y,desc = unpack(tokens) if not x or not tonumber(x) then return usage() elseif not y or not tonumber(y) then return usage() end if desc then desc = table.concat(tokens, " ", 3) end x = tonumber(x) y = tonumber(y) TomTom:AddWaypoint(x, y, desc) else return usage() end end