From 79b56a03e409292cc9cfb79ffb318ce484e6e03d Mon Sep 17 00:00:00 2001 From: James Whitehead II Date: Thu, 2 Dec 2010 17:29:17 +0000 Subject: [PATCH] Refactoring and adding world map icon display code --- DatabaseDefaults.lua | 2 + TomTomLite.lua | 248 +++++++++++++++++++++++++++++++++++---------- images/MapPointer.tga | Bin 0 -> 2523 bytes images/MapPointerGlow.tga | Bin 0 -> 7350 bytes 4 files changed, 196 insertions(+), 54 deletions(-) create mode 100644 images/MapPointer.tga create mode 100644 images/MapPointerGlow.tga diff --git a/DatabaseDefaults.lua b/DatabaseDefaults.lua index f237e96..20c08a0 100644 --- a/DatabaseDefaults.lua +++ b/DatabaseDefaults.lua @@ -7,6 +7,8 @@ addon.defaults = { positions = {}, trackQuestObjectives = true, + showMapIconsZone = false, + showMapIconsContinent = false, goodcolor = {0, 1, 0}, badcolor = {1, 0, 0}, diff --git a/TomTomLite.lua b/TomTomLite.lua index 1b51a4c..7b6b7ee 100644 --- a/TomTomLite.lua +++ b/TomTomLite.lua @@ -58,12 +58,18 @@ function addon:Initialize() self.arrow:SetPoint("CENTER", 0, 0) self.arrow:Hide() - self:RegisterEvent("QUEST_POI_UPDATE") - self:RegisterEvent("QUEST_LOG_UPDATE") - self:RegisterMessage("TOMTOMLITE_WAYPOINT_ADDED") + -- 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:UpdateQuestObjectives() + addon:FireMessage("OBJECTIVES_CHANGED") end) + + self:RegisterMessage("TOMTOMLITE_WAYPOINT_ADDED") + + -- Events for world map overlays + self:RegisterEvent("WORLD_MAP_UPDATE") end function addon:CreateCrazyArrow(name, parent) @@ -131,6 +137,10 @@ function addon:CreateCrazyArrow(name, parent) return frame end +--[[------------------------------------------------------------------------- +-- External API +-------------------------------------------------------------------------]]-- + function addon:AddWaypoint(map, floor, x, y, opt) assert(type(map) == "number") assert(type(floor) == "number") @@ -148,57 +158,82 @@ function addon:AddWaypoint(map, floor, x, y, opt) table.insert(self.waypoints, waypoint) self:FireMessage("TOMTOMLITE_WAYPOINT_ADDED", waypoint) -end -function addon:TOMTOMLITE_WAYPOINT_ADDED(msg, waypoint, ...) - local zone, floor, x, y = unpack(waypoint) - local lzone = self.mapdata:MapLocalize(zone) - --self:Printf("Added a waypoint at (%.2f, %.2f) in %s", x * 100, y * 100, lzone) - - self.arrow.waypoint = waypoint - self.arrow.title:SetText(waypoint.title or L["Unknown waypoint"]) - self.arrow.info:SetFormattedText("%.2f, %.2f - %s", x * 100, y * 100, lzone) - self.arrow:Show() + return waypoint end -local function POIAnchorToCoord(poiframe) - local point, relto, relpoint, x, y = poiframe:GetPoint() - local frame = WorldMapDetailFrame - local width = frame:GetWidth() - local height = frame:GetHeight() - local scale = frame:GetScale() / poiframe:GetScale() - local cx = (x / scale) / width - local cy = (-y / scale) / height - - if cx < 0 or cx > 1 or cy < 0 or cy > 1 then - return nil, nil +function addon:DeleteWaypoint(waypoint) + for idx, entry in ipairs(self.waypoints) do + if entry == waypoint then + table.remove(self.waypoints, waypoint) + break + end end - local map, floor = GetCurrentMapAreaID() - return map, floor or 0, cx, cy + self:FireMessage("TOMTOMLITE_WAYPOINT_DELETED", waypoint) end -local function findQuestFrameFromQuestIndex(index) - -- Try to find the correct quest frame - for i = 1, MAX_NUM_QUESTS do - local questFrame = _G["WorldMapQuestFrame" .. i]; - if not questFrame then - break - elseif questFrame.questLogIndex == index then - return questFrame - end - end +--[[------------------------------------------------------------------------- +-- Private implementation +-------------------------------------------------------------------------]]-- +function addon:TOMTOMLITE_WAYPOINT_ADDED(msg, waypoint, ...) + self:UpdateArrow() end -function addon:QUEST_POI_UPDATE() +function addon:OBJECTIVES_CHANGED() self:UpdateQuestObjectives() + self:UpdateArrow() end -function addon:QUEST_LOG_UPDATE() - self:UpdateQuestObjectives() +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) + local lzone = self.mapdata:MapLocalize(zone) + + self.arrow.waypoint = closest + self.arrow.title:SetText(closest.title or L["Unknown waypoint"]) + self.arrow.info:SetFormattedText("%.2f, %.2f - %s", x * 100, y * 100, lzone) + self.arrow:Show() + else + self.arrow.waypoint = nil + self.arrow:Hide() + 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.mapdata: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 @@ -206,35 +241,140 @@ function addon:UpdateQuestObjectives() 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 - -- Get the first quest item in the watch frame local questIndex = GetQuestIndexForWatch(watchIndex) if not questIndex then - self.arrow:Hide() - return + break end local title = GetQuestLogTitle(questIndex) local qid = select(9, GetQuestLogTitle(questIndex)) - local completed, x, y, objective = QuestPOIGetIconInfo(qid) - -- Check to see if there was coordinate information for the current point if x and y then - local map, floor = GetCurrentMapAreaID() - - if not floor then floor = 0 end - if completed then - title = "Turn in: " .. title - end + -- 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 - if x and y and map and floor then - self:AddWaypoint(map, floor, x, y, {title = title}) + 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 - return end watchIndex = watchIndex + 1 end + + self.arrow.waypoint = closest + + SetCVar("questPOI", cvar and 1 or 0) +end + +--[[------------------------------------------------------------------------- +-- World map support, displaying waypoint overlays +-------------------------------------------------------------------------]]-- + +-- Create an overlay that we can use to parent our world map icons +addon.overlay = CreateFrame("Frame", addonName .. "MapOverlay", WorldMapButton) +addon.overlay:SetAllPoints() +addon.overlay:Show() + +-- Metatable that stores world map icons indexed by number, in array form +local worldmapIcons = setmetatable({}, { + __index = function(t, k) + local name = addonName .. "MapIcon" .. tostring(k) + local button = CreateFrame("Button", name, addon.overlay) + button:SetSize(64, 64) + button:SetHitRectInsets(12, 12, 5, 2) + + button.icon = button:CreateTexture("BACKGROUND") + button.icon:SetTexture("Interface\\AddOns\\TomTomLite\\images\\MapPointer") + button.icon:SetVertexColor(0.3, 1.0, 0.3) + button.icon:SetAllPoints() + button.glow = button:CreateTexture("BACKGROUND") + button.glow:SetTexture("Interface\\AddOns\\TomTomLite\\images\\MapPointerGlow") + button.glow:SetAllPoints() + button.glow:Hide() + button.number = button:CreateTexture("OVERLAY", name .. "Number") + button.number:SetSize(50, 50) + button.number:SetTexture("Interface\\WorldMap\\UI-QuestPoi-NumberIcons") + button.number:SetPoint("CENTER", button, "CENTER", 0, 8) + button.number:SetDrawLayer("OVERLAY", 7) + + rawset(t, k, button) + return button + end, +}) + +function addon:WORLD_MAP_UPDATE() + -- Display any waypoints overlaid on the world map. Specifically, if + -- the map zoom is set to a continent or cosmic map, then display all + -- waypoints, otherwise display only the waypoints for the currently + -- displayed zone. If there are waypoints on a floor other than the + -- one the player is currently on, they will be displayed as well, and + -- will be distinguishable from waypoints on the current floor. + + -- If the map isn't shown, do nothing + if not addon.overlay:IsVisible() then + return + end + + -- Check the options to see what should be displayed + if not self.db.profile.showMapIconsZone then + return + end + + -- TODO: Handle 'showMapIconsContinent' option + + local continent = GetCurrentMapContinent() + local map, floor = GetCurrentMapAreaID() + local waypoints = addon.waypointsByMap[map] + + for idx = 1, math.max(#waypoints, #worldmapIcons), 1 do + local icon = worldmapIcons[idx] + local waypoint = waypoints[idx] + + if waypoint then + local width, height = addon.overlay:GetSize() + + icon:ClearAllPoints() + + local x = waypoint[3] * width + local y = waypoint[4] * height + + -- Set the number to be displayed + local buttonIndex = idx - 1 + local yOffset = 0.5 + math.floor(buttonIndex / QUEST_POI_ICONS_PER_ROW) * QUEST_POI_ICON_SIZE; + local xOffset = mod(buttonIndex, QUEST_POI_ICONS_PER_ROW) * QUEST_POI_ICON_SIZE + icon.number:SetTexCoord(xOffset, xOffset + QUEST_POI_ICON_SIZE, yOffset, yOffset + QUEST_POI_ICON_SIZE) + + -- Nudge position so arrow appears centered on POI + icon:SetPoint("BOTTOM", addon.overlay, "TOPLEFT", x + 1, -y - 5) + + if (floor or 0) == waypoint[2] then + icon:SetAlpha(1.0) + else + icon:SetAlpha(0.6) + end + + icon:Show() + else + icon:Hide() + end + end end diff --git a/images/MapPointer.tga b/images/MapPointer.tga new file mode 100644 index 0000000000000000000000000000000000000000..8df11779b62e1866bc1c10aefa8f1e185a33dd0d GIT binary patch literal 2523 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%0DviTxyIM+hyR@;3 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 literal 0 HcmV?d00001 -- 1.7.9.5