diff --git a/AddonCore.lua b/AddonCore.lua
index a765133..aa37464 100644
--- a/AddonCore.lua
+++ b/AddonCore.lua
@@ -127,6 +127,16 @@ end
-- Setup Initialize/Enable support
-------------------------------------------------------------------------]]--
+local initFuncs = {}
+function addon:RunAtInitialize(func)
+ initFuncs[#initFuncs + 1] = func
+end
+
+local enableFuncs = {}
+function addon:RunAtEnable(func)
+ enableFuncs[#enableFuncs + 1] = func
+end
+
addon:RegisterEvent("PLAYER_LOGIN", "Enable")
addon:RegisterEvent("ADDON_LOADED", function(event, ...)
if ... == addonName then
@@ -135,10 +145,20 @@ addon:RegisterEvent("ADDON_LOADED", function(event, ...)
addon["Initialize"](addon)
end
+ -- Run any registered init functions
+ for idx, func in ipairs(initFuncs) do
+ func()
+ end
+
-- If this addon was loaded-on-demand, trigger 'Enable' as well
if IsLoggedIn() and type(addon["Enable"]) == "function" then
addon["Enable"](addon)
end
+
+ -- Run any registered enable functions
+ for idx, func in ipairs(enableFuncs) do
+ func()
+ end
end
end)
diff --git a/DatabaseDefaults.lua b/DatabaseDefaults.lua
index 20c08a0..d9b3eaf 100644
--- a/DatabaseDefaults.lua
+++ b/DatabaseDefaults.lua
@@ -10,6 +10,8 @@ addon.defaults = {
showMapIconsZone = false,
showMapIconsContinent = false,
+ corpseArrow = true,
+
goodcolor = {0, 1, 0},
badcolor = {1, 0, 0},
middlecolor = {1, 1, 0},
diff --git a/MapUtils.lua b/MapUtils.lua
index 1edecb5..cc68db7 100644
--- a/MapUtils.lua
+++ b/MapUtils.lua
@@ -34,7 +34,7 @@ end
-- return nil
function addon:GetVector(sm, sf, sx, sy, dm, df, dx, dy)
- if smap == dmap and sfloor == dfloor then
+ if sm == dm and sf == df then
-- The waypoints are on the same map, so calculate directly using map data
if mapdata then
@@ -74,17 +74,45 @@ function addon:GetVector(sm, sf, sx, sy, dm, df, dx, dy)
end
end
+-- Returns the player's current map, floor and position. This information isn't
+-- directly available if the world map is open and the player has navigated to
+-- another map.
+
+function addon:GetPlayerPosition()
+ -- Attempt to get the player's position on the current map
+ local x, y = GetPlayerMapPosition("player")
+ if x and y and x > 0 and y > 0 then
+ local map, floor = GetCurrentMapAreaID()
+ return map, floor, x, y
+ end
+
+ -- At this point, we were unable to get the position information
+ if WorldMapFrame:IsVisible() then
+ -- The map is open and we cannot change the map being displayed
+ return
+ end
+
+ -- Flip the map to the current zone and get the position. We do not change
+ -- the map zoom back at the end of this function to avoid getting into any
+ -- nasty race conditions, it's bad enough that we need to set it currently.
+ SetMapToCurrentZone()
+ local x, y = GetPlayerMapPosition("player")
+
+ if x <= 0 and y <= 0 then
+ -- Coordinate information not available for wherever the player is
+ return
+ end
+
+ -- Fetch the map and floor and return the information that we have
+ local map, floor = GetCurrentMapAreaID()
+ return map, floor, x, y
+end
+
-- Get the distance (in yards) and angle (in radians) from the player's current
-- position to a position on the map.
function addon:GetVectorFromCurrent(map, floor, x, y)
-
- -- First we need to obtain the player's current position. Attempt, at all
- -- costs to do this without changing the map zoom, as it shouldn't be
- -- necessary.
-
- local cmap, cfloor = GetCurrentMapAreaID()
- local cx, cy = GetPlayerMapPosition("player")
+ local cmap, cfloor, cx, cy = self:GetPlayerPosition()
if map and floor and x and y then
return self:GetVector(cmap, cfloor, cx, cy, map, floor, x, y)
@@ -115,11 +143,11 @@ local continents = {
[751] = 5, -- Maelstrom (5)
-- Map from continentIndex to mapId
- [1] = 13,
- [2] = 14,
- [3] = 466,
- [4] = 485,
- [5] = 751,
+ [1] = 13, -- Kalimdor (13)
+ [2] = 14, -- Eastern Kingdoms (14)
+ [3] = 466, -- Outland (466)
+ [4] = 485, -- Northrend (485)
+ [5] = 751, -- Maelstrom (751)
}
-- Returns if a given map file is a continent map
@@ -137,3 +165,13 @@ function addon:GetMapContinentMap(map)
elseif astrolabe then
end
end
+
+function addon:GetNumMapFloors(map)
+ if mapdata then
+ local floors = mapdata:MapFloors(map) == 0 and 0 or 1
+ return floors
+ elseif astrolabe then
+ local floors = astrolabe:GetNumFloors(map) == 0 and 0 or 1
+ return floors
+ end
+end
diff --git a/TomTomLite.lua b/TomTomLite.lua
index 110d7fa..1939222 100644
--- a/TomTomLite.lua
+++ b/TomTomLite.lua
@@ -57,15 +57,8 @@ function addon:Initialize()
self.arrow:SetPoint("CENTER", 0, 0)
self.arrow:Hide()
- -- Events for objective tracking
- self:RegisterEvent("QUEST_POI_UPDATE", "OBJECTIVES_CHANGED")
- self:RegisterEvent("QUEST_LOG_UPDATE", "OBJECTIVES_CHANGED")
- self:RegisterMessage("OBJECTIVES_CHANGED")
- hooksecurefunc("WatchFrame_Update", function(self)
- addon:FireMessage("OBJECTIVES_CHANGED")
- end)
-
self:RegisterMessage("TOMTOMLITE_WAYPOINT_ADDED")
+ self:RegisterMessage("TOMTOMLITE_WAYPOINTS_CHANGED")
-- Events for world map overlays
self:RegisterEvent("WORLD_MAP_UPDATE")
@@ -76,10 +69,15 @@ function addon:CreateCrazyArrow(name, parent)
local frame = CreateFrame("Button", name, parent)
frame:SetSize(128, 128)
- frame.arrow = frame:CreateTexture("OVERLAY")
+ frame.arrow = frame:CreateTexture(name .. "Icon", "BACKGROUND")
frame.arrow:SetAllPoints()
frame.arrow:SetTexture("Interface\\Addons\\TomTomLite\\images\\BevArrow")
+ frame.glow = frame:CreateTexture(name .. "Glow", "OVERLAY")
+ frame.glow:SetAllPoints()
+ frame.glow:SetTexture("Interface\\Addons\\TomTomLite\\images\\BevArrowGlow")
+ frame.glow:SetVertexColor(1.0, 0.8, 0.0)
+
frame.title = frame:CreateFontString("OVERLAY", name .. "Title", "GameFontHighlight")
frame.info = frame:CreateFontString("OVERLAY", name .. "Info", "GameFontHighlight")
frame.subtitle = frame:CreateFontString("OVERLAY", name .. "Subtitle", "GameFontHighlight")
@@ -109,6 +107,31 @@ function addon:CreateCrazyArrow(name, parent)
self.arrow:SetVertexColor(r,g,b)
self.arrow:SetRotation(faceangle)
+ -- This code is not quite correct, needs to be 'fixed'
+
+ local lowlimit = 20.0
+ local highlimit = 360.0 - lowlimit
+
+ local angle = math.abs(deg(faceangle)) % 360
+
+ if angle <= lowlimit then
+ -- Determine what alpha to show
+ local perc = angle / lowlimit
+
+ self.glow:Show()
+ self.glow:SetRotation(faceangle)
+ self.glow:SetAlpha(1.0 - perc)
+ elseif angle >= highlimit then
+ -- Determine what alpha to show
+ local perc = angle / (360 - lowlimit)
+
+ self.glow:Show()
+ self.glow:SetRotation(faceangle)
+ self.glow:SetAlpha(1.0 - perc)
+ else
+ self.glow:Hide()
+ end
+
self.subtitle:SetFormattedText("%.1f yards", distance)
end)
@@ -127,10 +150,14 @@ end
function addon:AddWaypoint(map, floor, x, y, opt)
assert(type(map) == "number")
- assert(type(floor) == "number")
+ assert(type(floor) == "number" or floor == nil)
assert(type(x) == "number")
assert(type(y) == "number")
+ if floor == nil then
+ floor = addon:GetNumMapFloors(map)
+ end
+
local waypoint = {map, floor, x, y}
if type(opt) == "table" then
for k, v in pairs(opt) do
@@ -146,10 +173,10 @@ function addon:AddWaypoint(map, floor, x, y, opt)
return waypoint
end
-function addon:DeleteWaypoint(waypoint)
+function addon:RemoveWaypoint(waypoint)
for idx, entry in ipairs(self.waypoints) do
if entry == waypoint then
- table.remove(self.waypoints, waypoint)
+ table.remove(self.waypoints, idx)
break
end
end
@@ -161,42 +188,37 @@ end
-- Private implementation
-------------------------------------------------------------------------]]--
function addon:TOMTOMLITE_WAYPOINT_ADDED(msg, waypoint, ...)
- self:UpdateArrow()
+ self:FireMessage("TOMTOMLITE_WAYPOINTS_CHANGED")
+ self:Printf("Waypoint '%s' added at %.2f, %.2f", waypoint.title, waypoint[3], waypoint[4])
+end
+
+function addon:TOMTOMLITE_WAYPOINT_DELETED(msg, waypoint, ...)
+ self:FireMessage("TOMTOMLITE_WAYPOINTS_CHANGED")
+ self:Printf("Waypoint '%s' REMOVED at %.2f, %.2f", waypoint.title, waypoint[3], waypoint[4])
end
-function addon:OBJECTIVES_CHANGED()
- self:UpdateQuestObjectives()
+function addon:TOMTOMLITE_WAYPOINTS_CHANGED(msg, ...)
self:UpdateArrow()
end
function addon:UpdateArrow()
- -- local cmap, cfloor = GetCurrentMapAreaID()
- -- local cx, cy = GetPlayerMapPosition("player")
-
- -- -- Scan the current waypoints and determine which one is closest, regardless
- -- -- of which zone the waypoint is in. This could be altered to only consider
- -- -- waypoints in the current zone, quite easily.
- -- local mindist = math.huge
- -- local closest
-
- -- for idx, waypoint in ipairs(self.waypoints) do
- -- local map, floor, x, y = unpack(waypoint)
- -- local distance = addon.mapdata:DistanceWithinContinent(cmap, cfloor or 0, cx, cy, map, floor, x, y)
- -- if distance < mindist then
- -- mindist = distance
- -- closest = waypoint
- -- end
- -- end
-
- local closest = self.arrow.waypoint
-
- if closest then
- -- Set the crazy arrow to display this waypoint
- local zone, floor, x, y = unpack(closest)
+ -- This naive sort function will sort all waypoints so the highest
+ -- priority waypoint is first. This is the waypoint that will be
+ -- displayed on the arrow.
+
+ table.sort(self.waypoints, function(a, b)
+ local apri = a.priority or 0
+ local bpri = b.priority or 0
+ return bpri < apri
+ end)
+
+ local highest = self.waypoints[1]
+ if highest then
+ local zone, floor, x, y = unpack(highest)
local lzone = self:GetMapDisplayName(zone)
- self.arrow.waypoint = closest
- self.arrow.title:SetText(closest.title or L["Unknown waypoint"])
+ self.arrow.waypoint = highest
+ self.arrow.title:SetText(highest.title or L["Unknown waypoint"])
self.arrow.info:SetFormattedText("%.2f, %.2f - %s", x * 100, y * 100, lzone)
self.arrow:Show()
else
@@ -205,70 +227,6 @@ function addon:UpdateArrow()
end
end
-local objectiveWaypoints = {}
-function addon:UpdateQuestObjectives()
- local map, floor = GetCurrentMapAreaID()
- floor = floor or 0
-
- -- Do not set any NEW waypoints if we're on the continent map
- if self:IsContinentMap(map) then
- return
- end
-
- local cvar = GetCVarBool("questPOI")
- SetCVar("questPOI", 1)
-
- -- Only do an objective scan if the option is enabled
- if not self.db.profile.trackQuestObjectives then
- return
- end
-
- QuestPOIUpdateIcons()
-
- -- Scan through every quest that is being tracked, and create a waypoint
- -- for each of the objectives that are being tracked. These waypoints will
- -- be unordered, and will be sorted or ordered by the user/algorithm
- local closest
- local watchIndex = 1
- while true do
- local questIndex = GetQuestIndexForWatch(watchIndex)
- if not questIndex then
- break
- end
-
- local title = GetQuestLogTitle(questIndex)
- local qid = select(9, GetQuestLogTitle(questIndex))
- local completed, x, y, objective = QuestPOIGetIconInfo(qid)
-
- if x and y then
- -- For two waypoints to be equal, their map, floor, x, y should all be
- -- the same, as well as the title and completion set.
- local key = qid + (x * 100) * (y * 100) * map * (floor + 1)
- if not objectiveWaypoints[key] then
- if completed then
- title = "Turn in: " .. title
- end
-
- local waypoint = self:AddWaypoint(map, floor, x, y, {title = title})
- objectiveWaypoints[key] = waypoint
- if not closest then
- closest = objectiveWaypoints[key]
- end
- else
- if not closest then
- closest = objectiveWaypoints[key]
- end
- end
- end
-
- watchIndex = watchIndex + 1
- end
-
- self.arrow.waypoint = closest
-
- SetCVar("questPOI", cvar and 1 or 0)
-end
-
--[[-------------------------------------------------------------------------
-- World map support, displaying waypoint overlays
-------------------------------------------------------------------------]]--
@@ -323,9 +281,6 @@ function addon:WORLD_MAP_UPDATE()
return
end
- -- TODO: Handle 'showMapIconsContinent' option
-
- local continent = GetCurrentMapContinent()
local map, floor = GetCurrentMapAreaID()
local waypoints = addon.waypointsByMap[map]
diff --git a/TomTomLite.toc b/TomTomLite.toc
index ae036a0..7449561 100755
--- a/TomTomLite.toc
+++ b/TomTomLite.toc
@@ -22,3 +22,7 @@ Utils.lua
DatabaseDefaults.lua
TomTomLite.lua
+
+sources\ArchaeologyDigSites.lua
+sources\Corpse.lua
+sources\QuestObjectives.lua
diff --git a/sources/ArchaeologyDigSites.lua b/sources/ArchaeologyDigSites.lua
new file mode 100644
index 0000000..e69de29
diff --git a/sources/Corpse.lua b/sources/Corpse.lua
new file mode 100644
index 0000000..3d28b02
--- /dev/null
+++ b/sources/Corpse.lua
@@ -0,0 +1,133 @@
+local addonName, addon = ...
+local L = addon.L
+
+--[[-------------------------------------------------------------------
+-- Corpse arrow module for TomTomLite, example reference module
+-------------------------------------------------------------------]]--
+
+local eventFrame = CreateFrame("Frame")
+eventFrame:RegisterEvent("ADDON_LOADED")
+eventFrame:RegisterEvent("PLAYER_ALIVE")
+eventFrame:RegisterEvent("PLAYER_DEAD")
+eventFrame:RegisterEvent("PLAYER_UNGHOST")
+eventFrame:RegisterEvent("PLAYER_ENTERING_WORLD")
+eventFrame:Hide()
+
+local waypoint
+local map, floor, x, y
+
+local function GetCorpseLocation()
+ if map and x and y then
+ return map, floor, x, y
+ end
+
+ local oldmap, oldfloor = GetCurrentMapAreaID()
+
+ local cont
+ -- Scan the all of the continent maps in order to find the corpse arrow
+ for i=1, select("#", GetMapContinents()) do
+ SetMapZoom(i)
+ local cx, cy = GetCorpseMapPosition()
+ if cx ~= 0 and cy ~= 0 then
+ cont = i
+ break
+ end
+ end
+
+ -- If we found the corpse on a continent, find out which zone it is in
+ if cont and cont ~= -1 then
+ for i = 1, select("#", GetMapZones(cont)) do
+ SetMapZoom(cont, i)
+ local cx, cy = GetCorpseMapPosition()
+ if cx > 0 and cy > 0 then
+ map, floor = GetCurrentMapAreaID()
+ x, y = cx, cy
+ break
+ end
+ end
+ end
+
+ -- Restore the map to its previous map
+ SetMapByID(oldmap, oldfloor)
+
+ if map and x and y then
+ return map, floor, x, y
+ else
+ -- Now handle the case where the corpse is on the current map
+ local cx, cy = GetCorpseMapPosition()
+ if cx ~= 0 and cy ~= 0 then
+ map, floor = oldmap, oldfloor
+ x, y = cx, cy
+ return map, floor, x, y
+ end
+ end
+end
+
+local function SetCorpseArrow()
+ if map and x and y and x > 0 and y > 0 then
+ waypoint = addon:AddWaypoint(map, floor, x, y, {
+ title = "Your corpse",
+ priority = 100,
+ })
+ return waypoint
+ end
+end
+
+local function StartCorpseSearch()
+ if not IsInInstance() then
+ eventFrame:Show()
+ end
+end
+
+local function ClearCorpseArrow()
+ if waypoint then
+ addon:RemoveWaypoint(waypoint)
+
+ waypoint = nil
+ map, floor, x, y = nil, nil, nil, nil
+ end
+end
+
+local counter, throttle = 0, 0.5
+eventFrame:SetScript("OnUpdate", function(self, elapsed)
+ counter = counter + elapsed
+ if counter < throttle then
+ return
+ else
+ counter = 0
+ if addon.db.profile.corpseArrow then
+ if GetCorpseLocation() then
+ if SetCorpseArrow() then
+ self:Hide()
+ end
+ end
+ else
+ self:Hide()
+ end
+ end
+end)
+
+eventFrame:SetScript("OnEvent", function(self, event, arg1, ...)
+ if event == "ADDON_LOADED" and arg1 == addonName then
+ self:UnregisterEvent("ADDON_LOADED")
+ if UnitIsDeadOrGhost("player") then
+ StartCorpseSearch()
+ end
+ end
+
+ if event == "PLAYER_ALIVE" or event == "PLAYER_ENTERING_WORLD" then
+ if UnitIsDeadOrGhost("player") then
+ StartCorpseSearch()
+ else
+ ClearCorpseArrow()
+ end
+ elseif event == "PLAYER_DEAD" then
+ StartCorpseSearch()
+ elseif event == "PLAYER_UNGHOST" then
+ ClearCorpseArrow()
+ end
+end)
+
+if IsLoggedIn() then
+ eventFrame:GetScript("OnEvent")(eventFrame, "ADDON_LOADED", addonName)
+end
diff --git a/sources/QuestObjectives.lua b/sources/QuestObjectives.lua
new file mode 100644
index 0000000..f670c71
--- /dev/null
+++ b/sources/QuestObjectives.lua
@@ -0,0 +1,134 @@
+local addonName, addon = ...
+local L = addon.L
+
+--[[-------------------------------------------------------------------
+-- Quest objective waypoint source for TomTomLite
+--
+-- Anytime the quest log or objective POI information changes, the
+-- objective tracker is scanned for all objectives and waypoints are
+-- created for each of them. The priority of the first waypoint, i.e.
+-- the first one in the objectives tracker, is set higher than the
+-- rest. This of course can be overridden by the user
+-------------------------------------------------------------------]]--
+
+local PRI_FIRST = 15
+local PRI_OTHER = 0
+
+local eventFrame = CreateFrame("Frame")
+eventFrame:RegisterEvent("QUEST_POI_UPDATE")
+eventFrame:RegisterEvent("QUEST_LOG_UPDATE")
+hooksecurefunc("WatchFrame_Update", function(self)
+ addon:OBJECTIVES_CHANGED()
+end)
+
+eventFrame:SetScript("OnEvent", function(self, event, ...)
+ if event == "QUEST_POI_UPDATE" then
+ addon:OBJECTIVES_CHANGED()
+ elseif event == "QUEST_LOG_UPDATE" and (...) == "player" then
+ addon:OBJECTIVES_CHANGED()
+ end
+end)
+
+-- This function scans the current set of objectives, adding and removing
+-- waypoints to reflect the current state of the tracker.
+
+local waypoints = {}
+function addon:OBJECTIVES_CHANGED()
+ local map, floor = GetCurrentMapAreaID()
+ floor = floor or 0
+
+ -- Do not set any NEW waypoints if we're on the continent map
+ if self:IsContinentMap(map) then
+ return
+ end
+
+ local cvar = GetCVarBool("questPOI")
+ SetCVar("questPOI", 1)
+
+ -- Only do an objective scan if the option is enabled
+ if not self.db.profile.trackQuestObjectives then
+ return
+ end
+
+ local newWaypoints = {}
+ local changed = false
+
+ -- This function relies on the above CVar being set, and updates the icon
+ -- position information so it can be queries via the API
+ QuestPOIUpdateIcons()
+
+ -- Scan through every quest that is being tracked, and create a waypoint
+ -- for each of the objectives that are being tracked. These waypoints will
+ -- be unordered, and will be sorted or ordered by the user/algorithm
+ local watchIndex = 1
+ while true do
+ local questIndex = GetQuestIndexForWatch(watchIndex)
+ if not questIndex then
+ break
+ end
+
+ local title = GetQuestLogTitle(questIndex)
+ local qid = select(9, GetQuestLogTitle(questIndex))
+ local completed, x, y, objective = QuestPOIGetIconInfo(qid)
+
+ if x and y then
+ -- Try to uniquely identify objective waypoints using qid, x, y along
+ -- with map and floor. This may not always work, but its the best we
+ -- can do right now. This allows us to ensure we don't double-set a
+ -- waypoint.
+
+ if completed then
+ title = "Turn in: " .. title
+ end
+
+ local key = title .. tostring(qid + (x * 100) * (y * 100) * map * (floor + 1))
+
+ if waypoints[key] then
+ -- This waypoint already exists, no need to do anything, except
+ -- possibly change the priority
+
+ local waypoint = waypoints[key]
+ local newpri = (watchIndex == 1) and PRI_FIRST or PRI_OTHER
+ if waypoint.priority ~= newpri then
+ changed = true
+ waypoint.priority = newpri
+ end
+
+ newWaypoints[key] = waypoint
+ else
+ -- Create the waypoint, setting priority
+ local waypoint = self:AddWaypoint(map, floor, x, y, {
+ title = title,
+ priority = (watchIndex == 1) and PRI_FIRST or PRI_OTHER,
+ })
+
+ newWaypoints[key] = waypoint
+ end
+ end
+
+ watchIndex = watchIndex + 1
+ end
+
+ SetCVar("questPOI", cvar and 1 or 0)
+
+ -- Check to see if there are any waypoints that are in 'waypoints' but
+ -- not in 'newWaypoints' so we can remove them. Additionally, we may have
+ -- changed a waypoint's priority during the scan, so trigger an update in
+ -- that case.
+
+ for k, waypoint in pairs(newWaypoints) do
+ waypoints[k] = nil
+ end
+
+ for k, waypoint in pairs(waypoints) do
+ -- This waypoint is no longer being tracked
+ addon:RemoveWaypoint(waypoint)
+ end
+
+ -- Swap the arrays
+ waypoints = newWaypoints
+
+ if changed then
+ addon:FireMessage("TOMTOMLITE_WAYPOINTS_CHANGED")
+ end
+end