Mercurial > wow > worldplan
view WorldQuests.lua @ 35:26dfa661daa7
WorldPlan:
- Quest pins will appear in the flight map. They follow the filter settings applied from the world map.
- Reward filter toggle changed to clear out other reward filters. The assumption being that one is most often looking only for that particular type of quest when they go to use it.
- Fixed filter bar info falling out of sync after player-triggered world map updates.
- Code stuff:
-- Quest pin shown-state management makes better use of OnShow OnHide handlers, SetShown is toggled and it all goes from there
-- WorldQuests module re-factored outside of the top level frame script.
ClassPlan:
- Available missions are now recorded; the mission list can be toggled between in-progress and available by clicking the heading.
author | Nenue |
---|---|
date | Thu, 03 Nov 2016 17:29:15 -0400 |
parents | 0100d923d8c3 |
children | 21bcff08b0f4 |
line wrap: on
line source
-- WorldPlan -- WorldQuests.lua -- Created: 11/2/2016 3:40 PM -- %file-revision% WorldPlanDataProvider = {} WorldPlanDataPinMixin = {} WorldPlanQuestsMixin = { QuestsByZone = {}, QuestsByID = {}, freePins = {}, } local WorldQuests = WorldPlanQuestsMixin local MC_GetNumZones, MC_GetZoneInfo = C_MapCanvas.GetNumZones, C_MapCanvas.GetZoneInfo local TQ_GetQuestsForPlayerByMapID = C_TaskQuest.GetQuestsForPlayerByMapID -- This function is not yet documented local TQ_GetQuestZoneID = C_TaskQuest.GetQuestZoneID local GetMapInfo = GetMapInfo local print = DEVIAN_WORKSPACE and function(...) _G.print('WP', ...) end or function() end local qprint = DEVIAN_WORKSPACE and function(...) _G.print('POI', ...) end or function() end local wqprint = DEVIAN_WORKSPACE and function(...) _G.print('WorldQuests', ...) end or function() end local wprint = DEVIAN_WORKSPACE and function(...) _G.print('WP', ...) end or function() end local mprint = DEVIAN_WORKSPACE and function(...) _G.print('Canvas', ...) end or function() end local PinBaseIndex = 1600 local BROKEN_ISLES_ID, DALARAN_ID, AZSUNA_ID, VALSHARAH_ID, HIGHMOUNTAIN_ID, STORMHEIM_ID, SURAMAR_ID, EOA_ID = 1007, 1014, 1015,1018, 1024, 1017, 1033, 1096 local WORLD_QUEST_MAPS = { [DALARAN_ID] = 'Dalaran70', [AZSUNA_ID] = 'Azsuna', [VALSHARAH_ID] = "Val'sharah", [HIGHMOUNTAIN_ID] = 'Highmountain', [STORMHEIM_ID] = 'Stormheim', [SURAMAR_ID] = 'Suramar', [EOA_ID] = 'EyeOfAszhara', } local REWARD_CASH = WORLD_QUEST_REWARD_TYPE_FLAG_GOLD local REWARD_ARTIFACT_POWER = WORLD_QUEST_REWARD_TYPE_FLAG_ARTIFACT_POWER local REWARD_GEAR = WORLD_QUEST_REWARD_TYPE_FLAG_EQUIPMENT local REWARD_CURRENCY = WORLD_QUEST_REWARD_TYPE_FLAG_ORDER_RESOURCES local REWARD_REAGENT = WORLD_QUEST_REWARD_TYPE_FLAG_MATERIALS local numPins = 0 local ZoneInfo = {} local NumPinFrames = 1 --%debug% local SetTimedCallbackForAllPins = function(seconds, callback) C_Timer.After(seconds, function() for id, pin in pairs(WorldPlanQuests.QuestsByID) do callback(pin) end end) end function WorldQuests:Setup() for mapID, mapName in pairs(WORLD_QUEST_MAPS) do self.QuestsByZone[mapID] = {} end -- refresh positions any time blizzard does so (i.e. mousewheel zoom) hooksecurefunc("WorldMapScrollFrame_ReanchorQuestPOIs", function() self:Refresh(true) end) -- hide the original world quest POIs hooksecurefunc("WorldMap_UpdateQuestBonusObjectives", function() for i = 1, NUM_WORLDMAP_TASK_POIS do local button = _G['WorldMapFrameTaskPOI'..i] if button and button.worldQuest then button:Hide() end end end) end local WorldMapPOIFrame local defaults = {} function WorldQuests:OnLoad() print('|cFF00FF88'..self:GetName()..':OnLoad') WorldPlan:AddHandler(self, defaults) local rgbWhite = {1, 1, 1} WorldPlan:AddTypeInfo(self, REWARD_REAGENT, { r = 0, g = 1, b = 1 }) WorldPlan:AddTypeInfo(self, REWARD_ARTIFACT_POWER, { r = 1, g = .25, b = .5, hasNumeric = true, numberRGB = rgbWhite }) WorldPlan:AddTypeInfo(self, REWARD_GEAR, { r = .1, g = .2, b = 1 }) WorldPlan:AddTypeInfo(self, REWARD_CURRENCY, { r = 1, g = 1, b = 0, hasNumeric = true, numberRGB = {1,1,0}, }) WorldPlan:AddTypeInfo(self, REWARD_CASH, { r = 0, g = 0, b = 0, }) for areaID, fileName in pairs(WORLD_QUEST_MAPS) do self.QuestsByZone[areaID] = {} end self:RegisterEvent('WORLD_QUEST_COMPLETED_BY_SPELL') self:RegisterEvent('SKILL_LINES_CHANGED') WorldMapPOIFrame = _G.WorldMapPOIFrame end function WorldQuests:OnEvent (event, ...) local print = wqprint print('|cFFFFFF00'..self:GetName()..':OnEvent()'..event..'|r', GetTime(), ...) if event == 'QUEST_LOG_UPDATE' then local questID, added = ... if questID and added then local questPOI = self:AcquirePin(questID) self.isStale, self.isPending = questPOI:RefreshData() else self:RefreshData() end print('WorldMapFrame', WorldMapFrame:IsVisible(), 'hasUpdates:', self.isStale) elseif event == 'WORLD_MAP_UPDATE' or event == 'PLAYER_ENTERING_WORLD' then self.isStale = true elseif event == 'WORLD_QUEST_COMPLETED_BY_SPELL' then local questID = ... if questID and self.QuestsByID[questID] then self:ReleasePin(self.QuestsByID[questID]) end elseif event == 'SKILL_LINES_CHANGED' then self.isStale = true end end local TQ_GetQuestLocation = C_TaskQuest.GetQuestLocation function WorldQuests:AcquirePin (questID, mapID) local pin = self.QuestsByID[questID] local isNew = false if not pin then isNew = true local numFree = #self.freePins if numFree >= 1 then pin = tremove(self.freePins, numFree) --print('|cFF00FF00Re-using', pin:GetName()) else local name = 'WorldPlanQuestMarker' .. NumPinFrames --print('|cFF00FF00Creating', name) pin = CreateFrame('Frame', name, WorldMapPOIFrame, 'WorldPlanQuestPin') pin:SetFrameStrata('HIGH') pin.GetTypeInfo = function(frame, typeID) return self:GetTypeInfo(typeID) end NumPinFrames = NumPinFrames + 1 --pin.iconBorder:SetVertexColor(0,0,0,1) end pin:SetID(questID) pin.isNew = true pin.currentWidth = nil -- used by TaskPOI_x scripts pin.questID = questID pin.worldQuest = true self.QuestsByID[questID] = pin else --print('|cFF00FF00Using', pin:GetName()) end mapID = mapID or TQ_GetQuestZoneID(questID) self.QuestsByZone[mapID][questID] = pin return pin, isNew end -- remove from index and add it to the recycling heap function WorldQuests:ReleasePin (pin) local id = pin.questId if id then self.QuestsByID[id] = nil for i, zone in pairs(self.QuestsByZone) do print('-', i, zone[i]) zone[id] = nil end end pin:Hide() pin:ClearAllPoints() tinsert(self.freePins, pin) print('|cFFFF4400Clearing out', pin:GetName(),id) end -- create of update quest pins for a map and its underlying zones function WorldQuests:RefreshData (mapID) local print = wqprint mapID = mapID or WorldPlan.currentMapID if not mapID then -- info not available yet return end print('|cFF00FF88'..self:GetName()..':RefreshData()|r', 'map:', mapID, 'realMap:', GetCurrentMapAreaID()) if mapID == BROKEN_ISLES_ID then self.isStale = false print('|cFF00FFFFContinent:|r', mapID, GetMapNameByID(mapID), superTrackedID) self.fullSearch = true for i = 1, MC_GetNumZones(mapID) do local submapID, name, depth = MC_GetZoneInfo(mapID, i) self:RefreshData(submapID) end self.fullSearch = nil elseif self.QuestsByZone[mapID] then local taskInfo = TQ_GetQuestsForPlayerByMapID(mapID, WorldPlan.currentMapID) local numQuests = 0 if taskInfo and #taskInfo >= 1 then print('|cFF00FFFF Zone:|r', mapID, GetMapNameByID(mapID), #taskInfo) wipe(self.QuestsByZone[mapID]) ZoneInfo[mapID] = taskInfo qprint('|cFFFF4400START of', GetMapNameByID(mapID)) for taskID, info in pairs(taskInfo) do local questID = info.questId info.mapID = mapID local questPOI = self:AcquirePin(questID, mapID) local hasUpdate, isPending = questPOI:RefreshData(info) -- WorldPlan:print('|cFF0088FF'..questPOI.title..'|r', hasUpdate) self.isStale = (self.isStale or hasUpdate) self.isPending = (self.isPending or isPending) numQuests = numQuests + 1 end qprint('|cFFFF4400END of', GetMapNameByID(mapID)) end end if not self.fullSearch then print(' hasUpdate:', self.isStale, 'isPending:', self.isPending, 'timer:', (self.OnNext and 'waiting' or '')) --WorldPlan.isStale = (self.isStale or WorldPlan.isStale) end end function WorldQuests:Refresh(forced) local print = wqprint print('|cFF00FF88'..self:GetName()..':Refresh()|r') if not self:IsVisible() then self.isStale = true print('frame closed, do it later') return end self:Reset() self:UpdateAnchors() self:Cleanup () end -- prepares elements for a map update function WorldQuests:Reset () local print = wqprint print('|cFF00FF88'..self:GetName()..':Reset()|r') for questID, pin in pairs(self.QuestsByID) do pin.used = nil end end -- update visibility states of all pins function WorldQuests:UpdateAnchors (submapID) local print = wqprint local db = WorldPlan.db local mapFileName, textureHeight, textureWidth, isMicroDungeon, microDungeonMapName = GetMapInfo() if isMicroDungeon then return end local currentMap = GetCurrentMapAreaID() local submapID = submapID or currentMap if submapID == BROKEN_ISLES_ID and (not db.DisplayContinentPins) then print('not updating map for reasons') return end print('|cFF88FF00'..self:GetName()..':UpdateAnchors|r', submapID, GetMapNameByID(submapID), 'pin count:', numPins) local numZones = MC_GetNumZones(submapID) if numZones then for i = 1, numZones do local subMapID = MC_GetZoneInfo(submapID, i) self:UpdateAnchors(subMapID) end end local pins = self.QuestsByZone[submapID] if pins then local hostFrame = WorldMapPOIFrame local mapWidth, mapHeight = hostFrame:GetSize() for questID, pin in pairs(pins) do pin:IsShowable() if pin.used then pin.isStale = true pin:SetFrameLevel(PinBaseIndex+ numPins) print('level', PinBaseIndex+ numPins) pin:SetAnchor(_G.WorldMapPOIFrame, currentMap, mapWidth, mapHeight) numPins = numPins + 1 end end end end -- shows, animates, or hides pins based on their current visibility flags local debug_show = {} local debug_animate = {} local debug_hide = {} function WorldQuests:Cleanup () local print = wqprint local showQuestPOI = WorldPlan.db.EnablePins print('|cFFFFFF00'..self:GetName()..':Cleanup()|r') -- continent or zone sizing numPins = 0 for questID, pin in pairs(self.QuestsByID) do pin:SetShown((showQuestPOI and pin.used)) end self.isStale = nil end function WorldQuests:FilterCheckByID(questID) local pin = WorldQuests:GetPinByQuestID(questID) return pin:IsShowable() end function WorldPlanDataProvider:OnShow() assert(self.ticker == nil); self.ticker = C_Timer.NewTicker(10, function() self:RefreshAllData() end); end function WorldPlanDataProvider:OnHide() self.ticker:Cancel(); self.ticker = nil; end function WorldPlanDataProvider:OnAdded(mapCanvas) self.activePins = {}; self.owningMap = mapCanvas end function WorldPlanDataProvider:RefreshAllData() local print = mprint print('|cFFFF0088'..self.owningMap:GetName()..':RefreshAllData()|r') local pinsToRemove = {}; for questId in pairs(self.activePins) do pinsToRemove[questId] = true; end SetMapZoom(8) local mapAreaID = self:GetMap():GetMapID(); for zoneIndex = 1, C_MapCanvas.GetNumZones(mapAreaID) do local zoneMapID, zoneName, zoneDepth, left, right, top, bottom = C_MapCanvas.GetZoneInfo(mapAreaID, zoneIndex); print(zoneMapID, zoneName) if zoneDepth <= 1 then -- Exclude subzones local taskInfo = C_TaskQuest.GetQuestsForPlayerByMapID(zoneMapID, mapAreaID); if taskInfo then for i, info in ipairs(taskInfo) do if HaveQuestData(info.questId) then if QuestUtils_IsQuestWorldQuest(info.questId) then local pin = WorldPlanQuests:AcquirePin(info.questId, zoneMapID) pin:RefreshData(info) pin:IsShowable() if pin.used then print(i, pin.x, pin.y, pin.used, pin.isNew, pin.isStale, pin:IsShown(), pin:GetAlpha()) pinsToRemove[info.questId] = nil; local frame = self.activePins[info.questId] if not frame then frame = self:GetMap():AcquirePin("WorldPlanPinContainer") frame:SetAlphaLimits(1, 0.7, 1) frame:SetScalingLimits(1, 3, 1.5); frame:SetFrameLevel(1000 + self:GetMap():GetNumActivePinsByTemplate("WorldPlanPinContainer")); frame:Show() self.activePins[info.questId] = frame end frame:SetPosition(info.x, info.y) frame.pin = pin pin.isStale = true pin:SetParent(frame) pin:ClearAllPoints() pin:SetPoint('CENTER', frame, 'CENTER') end pin:SetShown(pin.used) end end end end end end for questId in pairs(pinsToRemove) do self:GetMap():RemovePin(self.activePins[questId]); self.activePins[questId] = nil; end self:GetMap():RemoveAllPinsByTemplate("WorldQuestPinTemplate"); end function WorldPlanDataPinMixin:OnShow() mprint('|cFFFFFF00'..tostring(self:GetName())..':OnShow()|r') end function WorldPlanDataPinMixin:OnMouseEnter () self.pin:OnEnter() end function WorldPlanDataPinMixin:OnMouseLeave () self.pin:OnLeave() end function WorldPlanDataPinMixin:RemoveAllData() wipe(self.activePins); self:GetMap():RemoveAllPinsByTemplate("WorldQuestPinTemplate"); end