--[[-------------------------------------------------------------------------- |
-- TomTom by Cladhaire <cladhaire@gmail.com> |
----------------------------------------------------------------------------]] |
|
-- Simple localization table for messages |
local L = TomTomLocals |
local ldb = LibStub("LibDataBroker-1.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 |
if TomTom.version == "v40000-1.0.9" then TomTom.version = "SCM" end |
|
--[[-------------------------------------------------------------------------- |
-- Astrolabe compatability library |
----------------------------------------------------------------------------]] |
|
local compat = {} |
TomTom.compat = compat |
|
do |
local Astrolabe = DongleStub("Astrolabe-1.0") |
|
local orig = GetCurrentMapAreaID() |
|
-- Create a lookup table from mapID to c,z pairs |
local mapcz = {} |
for cid, zlist in ipairs{GetMapContinents()} do |
for zid, mapid in ipairs{GetMapZones(cid)} do |
SetMapZoom(cid, zid) |
local mapid = GetCurrentMapAreaID() |
mapcz[mapid] = {cid, zid} |
end |
end |
for id=1,10000 do |
if not ( mapcz[id] ) then |
if ( SetMapByID(id) ) then |
mapcz[id] = {-1, id} |
end |
end |
end |
SetMapByID(orig) |
|
-- Speed up minimap updates |
Astrolabe.MinimapUpdateTime = 0.1 |
|
-- This function takes the mapID return from the Astrolabe function |
-- and converts it to a c,z,x,y tuple |
function compat:GetCurrentPlayerPosition() |
local map, floor, x, y = Astrolabe:GetCurrentPlayerPosition() |
print("compat:GetCurrentPlayerPosition()=>",map, floor, x, y) |
local cz = mapcz[map] |
if cz then |
local c, z = unpack(cz) |
return c, z, x, y |
end |
end |
|
function compat:GetCurrentPlayerCoords() |
local map, floor, x, y = Astrolabe:GetCurrentPlayerPosition() |
return x, y |
end |
|
function compat:GetDirectionToIcon(...) |
return Astrolabe:GetDirectionToIcon(...) |
end |
|
function compat:GetDistanceToIcon(...) |
return Astrolabe:GetDistanceToIcon(...) |
end |
|
function compat:RemoveIconFromMinimap(...) |
return Astrolabe:RemoveIconFromMinimap(...) |
end |
|
function compat:IsIconOnEdge(...) |
return Astrolabe:IsIconOnEdge(...) |
end |
|
function compat:PlaceIconOnMinimap(icon, c, z, x, y) |
local mapId |
if c == -1 then |
mapId = z |
z = 0 |
else |
mapId = Astrolabe:GetMapID(c, z) |
end |
if mapId == nil then |
error("compat:PlaceIconOnMinimap() call to Astrolabe:GetMapID("..c..","..z..") failed") |
end |
local floors = Astrolabe:GetNumFloors(mapId) |
local floor = floors == 0 and 0 or 1 |
return Astrolabe:PlaceIconOnMinimap(icon, mapId, floor, x, y) |
end |
|
function compat:PlaceIconOnWorldMap(frame, icon, c, z, x, y) |
local mapId |
if c == -1 then |
mapId = z |
z = 0 |
else |
mapId = Astrolabe:GetMapID(c, z) |
end |
if mapId == nil then |
error("compat:PlaceIconOnWorldMap() call to Astrolabe:GetMapID("..c..","..z..") failed") |
|
end |
mapId = 680 |
local floors = Astrolabe:GetNumFloors(mapId) |
local floor = floors == 0 and 0 or 1 |
|
return Astrolabe:PlaceIconOnWorldMap(frame, icon, mapId, floor, x, y) |
end |
|
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, |
enablePing = false, |
}, |
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, |
}, |
poi = { |
enable = true, |
modifier = "C", |
setClosest = false, |
}, |
}, |
} |
|
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.tooltip:SetFrameStrata("DIALOG") |
|
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 |
|
coordFeedFrame:SetScript("OnUpdate", function(self, elapsed) |
counter = counter + elapsed |
if counter < throttle then |
return |
end |
|
counter = 0 |
local x,y = compat:GetCurrentPlayerCoords() |
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:UpdateCoordFeedThrottle() |
throttle = self.db.profile.feeds.coords_throttle |
end |
|
function TomTom:ReloadOptions() |
-- This handles the reloading of all options |
self.profile = self.db.profile |
|
self:ShowHideWorldCoords() |
self:ShowHideCoordBlock() |
self:ShowHideCrazyArrow() |
self:EnableDisablePOIIntegration() |
end |
|
function TomTom:ReloadWaypoints() |
local pc, pz = TomTom:WhereAmI() |
|
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 |
|
-- Hook some global functions so we know when the world map size changes |
local mapSizedUp = not (WORLDMAP_SETTINGS.size == WORLDMAP_WINDOWED_SIZE); |
hooksecurefunc("WorldMap_ToggleSizeUp", function() |
mapSizedUp = true |
TomTom:ShowHideWorldCoords() |
end) |
hooksecurefunc("WorldMap_ToggleSizeDown", function() |
mapSizedUp = false |
TomTom:ShowHideWorldCoords() |
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.Cursor = TomTomWorldFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall") |
TomTomWorldFrame:SetScript("OnUpdate", WorldMap_OnUpdate) |
end |
|
if mapSizedUp then |
TomTomWorldFrame.Player:SetPoint("RIGHT", WorldMapPositioningGuide, "BOTTOM", -15, 15) |
TomTomWorldFrame.Cursor:SetPoint("LEFT", WorldMapPositioningGuide, "BOTTOM", 15, 15) |
else |
TomTomWorldFrame.Player:SetPoint("RIGHT", WorldMapPositioningGuide, "BOTTOM", -40, 2) |
TomTomWorldFrame.Cursor:SetPoint("LEFT", WorldMapPositioningGuide, "BOTTOM", -15, 2) |
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 = TomTom:WhereAmI() |
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:GetData(uid) |
local data = waypoints[uid] |
return data |
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 _both_ping_arrival(event, uid, range, distance, lastdistance) |
if TomTom.profile.arrow.enablePing then |
PlaySoundFile("Interface\\AddOns\\TomTom\\Media\\ping.mp3") |
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 |
|
function TomTom:WhereAmI() |
local c,z = GetCurrentMapContinent(), GetCurrentMapZone() |
|
if c < 0 then |
z = GetCurrentMapAreaID() |
end |
if not c or not z then |
self:Print("Cannot find a valid zone to place the coordinates") |
end |
return c,z |
end |
|
-- TODO: Make this not suck |
function TomTom:AddWaypoint(x, y, desc, persistent, minimap, world, silent) |
local c,z = TomTom:WhereAmI() |
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) |
if type(c) ~= "number" then error("TomTom:AddZWaypoint() c was not a number, it was " .. type(c)) end |
if type(z) ~= "number" then error("TomTom:AddZWaypoint() z was not a number, it was " .. type(z)) end |
if type(x) ~= "number" then error("TomTom:AddZWaypoint() x was not a number, it was " .. type(x)) end |
if type(y) ~= "number" then error("TomTom:AddZWaypoint() y was not a number, it was " .. type(y)) end |
|
print("TomTom:AddZWaypoint("..c..","..z..","..x..","..y..","..tostring(desc)..",...)") |
|
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 |
local arrivaldistance = self.profile.arrow.arrival |
|
if cleardistance == arrivaldistance then |
callbacks.distance[cleardistance] = function(...) |
_both_clear_distance(...); |
_both_ping_arrival(...); |
end |
else |
if cleardistance > 0 then |
callbacks.distance[cleardistance] = _both_clear_distance |
end |
if arrivaldistance > 0 then |
callbacks.distance[arrivaldistance] = _both_ping_arrival |
end |
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 |
error("TomTom:AddZWaypoint() failed self:GetMapFile("..c..","..z..")") |
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:WaypointExists(c, z, x, y, desc) |
local coord = self:GetCoord(x / 100, y / 100) |
local zone = self:GetMapFile(c, z) |
|
if not zone then |
return |
end |
|
if waypoints[zone] then |
for uid in pairs(waypoints[zone]) do |
local data = waypoints[uid] |
if data.title == desc then |
return true |
else |
return false |
end |
end |
end |
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 |
|
do |
-- Code to convert between a MapFile ane a C,Z tuple |
-- This no longer can use Astrolabe to build these tables |
|
local Astrolabe = DongleStub("Astrolabe-1.0") |
-- 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", |
[4] = "Northrend", |
[5] = "TheMaelstromContinent", |
} |
local mapCZtoFile = {} |
_G.mc = mapCZtoFile |
local reverseMapFileC = {} |
local reverseMapFileZ = {} |
|
for cid, zlist in pairs{GetMapContinents()} do |
for zid, zname in pairs{GetMapZones(cid)} do |
SetMapZoom(cid, zid) |
local mapFile = GetMapInfo() |
reverseMapFileC[mapFile] = cid |
reverseMapFileZ[mapFile] = zid |
mapCZtoFile[cid] = mapCZtoFile[cid] or {} |
mapCZtoFile[cid][zid] = mapCZtoFile[cid][zid] or {} |
mapCZtoFile[cid][zid] = mapFile |
end |
end |
|
for id=1,10000 do |
if ( SetMapByID(id) ) then |
local mapFile = GetMapInfo() |
reverseMapFileC[mapFile] = reverseMapFileC[mapFile] or -1 |
reverseMapFileZ[mapFile] = reverseMapFileZ[mapFile] or id |
mapCZtoFile[-1] = mapCZtoFile[-1] or {} |
mapCZtoFile[-1][id] = mapCZtoFile[-1][id] or {} |
mapCZtoFile[-1][id] = mapFile |
end |
end |
|
for cid, mapFile in pairs(continentMapFile) do |
reverseMapFileC[mapFile] = cid |
reverseMapFileZ[mapFile] = 0 |
mapCZtoFile[cid] = mapCZtoFile[cid] or {} |
mapCZtoFile[cid][0] = mapCZtoFile[cid][0] or {} |
mapCZtoFile[cid][0] = mapFile |
end |
|
function TomTom:GetMapFile(C, Z) |
if not C or not Z then return end |
local c = mapCZtoFile[C] |
if c then |
return c[Z] |
end |
end |
function TomTom:GetCZ(mapFile) |
return reverseMapFileC[mapFile], reverseMapFileZ[mapFile] |
end |
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 x,y = compat:GetCurrentPlayerCoords() |
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 x,y = compat:GetCurrentPlayerCoords() |
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 |
|
function Block_OnClick(self, button, down) |
local c,z,x,y = compat:GetCurrentPlayerPosition() |
local zone = TomTom:GetMapFile(c, z) |
local desc = format("%s: %.2f, %.2f", zone, x*100, y*100) |
TomTom:AddZWaypoint(c, z, x*100, y*100, desc) |
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 = compat: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 = compat: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] == "lfo" then |
for x = 62,68,2 do |
for y = 10,20,5 do |
TomTom:AddWaypoint(x, y, string.format("LFO@(%d,%d)",x,y)) |
end |
end |
ChatFrame1:AddMessage("OK Boss, added them!") |
return |
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 |
elseif #matches == 0 then |
ChatFrame1:AddMessage(string.format(L["Found no matches for zone '%s'."], tokens[2])) |
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 |
|
|