WoWInterface SVN Patches

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /
    from Rev 2 to Rev 3
    Reverse comparison

Rev 2 → Rev 3

trunk/Cladhaire/TomTom.lua New file
0,0 → 1,1321
--[[--------------------------------------------------------------------------
-- 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
 
 
Property changes : Added: svn:executable + *