annotate WorldQuests.lua @ 34:0100d923d8c3

WorldPlan: - 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 Wed, 02 Nov 2016 19:04:47 -0400
parents be4db60219ca
children 26dfa661daa7
rev   line source
Nenue@33 1 -- WorldPlan
Nenue@33 2 -- WorldQuests.lua
Nenue@33 3 -- Created: 11/2/2016 3:40 PM
Nenue@33 4 -- %file-revision%
Nenue@33 5
Nenue@33 6 WorldPlanQuestsMixin = {
Nenue@33 7 QuestsByZone = {},
Nenue@33 8 QuestsByID = {},
Nenue@33 9 freePins = {},
Nenue@33 10 }
Nenue@33 11 local WorldQuests = WorldPlanQuestsMixin
Nenue@33 12
Nenue@33 13 local MC_GetNumZones, MC_GetZoneInfo = C_MapCanvas.GetNumZones, C_MapCanvas.GetZoneInfo
Nenue@33 14 local TQ_GetQuestsForPlayerByMapID = C_TaskQuest.GetQuestsForPlayerByMapID -- This function is not yet documented
Nenue@33 15 local TQ_GetQuestZoneID = C_TaskQuest.GetQuestZoneID
Nenue@33 16 local GetMapInfo = GetMapInfo
Nenue@33 17 local print = DEVIAN_WORKSPACE and function(...) _G.print('WP', ...) end or function() end
Nenue@33 18 local qprint = DEVIAN_WORKSPACE and function(...) _G.print('POI', ...) end or function() end
Nenue@33 19 local wqprint = DEVIAN_WORKSPACE and function(...) _G.print('WorldQuests', ...) end or function() end
Nenue@33 20 local wprint = DEVIAN_WORKSPACE and function(...) _G.print('WP', ...) end or function() end
Nenue@33 21
Nenue@33 22
Nenue@33 23 local PinBaseIndex = 1600
Nenue@33 24 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
Nenue@33 25 local WORLD_QUEST_MAPS = { [DALARAN_ID] = 'Dalaran70', [AZSUNA_ID] = 'Azsuna', [VALSHARAH_ID] = "Val'sharah",
Nenue@33 26 [HIGHMOUNTAIN_ID] = 'Highmountain', [STORMHEIM_ID] = 'Stormheim', [SURAMAR_ID] = 'Suramar', [EOA_ID] = 'EyeOfAszhara', }
Nenue@33 27
Nenue@33 28 local REWARD_CASH = WORLD_QUEST_REWARD_TYPE_FLAG_GOLD
Nenue@33 29 local REWARD_ARTIFACT_POWER = WORLD_QUEST_REWARD_TYPE_FLAG_ARTIFACT_POWER
Nenue@33 30 local REWARD_GEAR = WORLD_QUEST_REWARD_TYPE_FLAG_EQUIPMENT
Nenue@33 31 local REWARD_CURRENCY = WORLD_QUEST_REWARD_TYPE_FLAG_ORDER_RESOURCES
Nenue@33 32 local REWARD_REAGENT = WORLD_QUEST_REWARD_TYPE_FLAG_MATERIALS
Nenue@33 33
Nenue@33 34
Nenue@33 35 local numPins = 0
Nenue@33 36 local ZoneInfo = {}
Nenue@33 37 local NumPinFrames = 1
Nenue@33 38
Nenue@33 39
Nenue@33 40 --%debug%
Nenue@33 41 local SetTimedCallbackForAllPins = function(seconds, callback)
Nenue@33 42 C_Timer.After(seconds, function()
Nenue@33 43 for id, pin in pairs(WorldPlanQuests.QuestsByID) do
Nenue@33 44 callback(pin)
Nenue@33 45 end
Nenue@33 46 end)
Nenue@33 47 end
Nenue@33 48
Nenue@33 49 function WorldQuests:Setup()
Nenue@33 50
Nenue@33 51
Nenue@33 52 for mapID, mapName in pairs(WORLD_QUEST_MAPS) do
Nenue@33 53 self.QuestsByZone[mapID] = {}
Nenue@33 54 end
Nenue@33 55
Nenue@33 56
Nenue@33 57 -- refresh positions any time blizzard does so (i.e. mousewheel zoom)
Nenue@33 58 hooksecurefunc("WorldMapScrollFrame_ReanchorQuestPOIs", function()
Nenue@33 59 self:Refresh(true)
Nenue@33 60 end)
Nenue@33 61
Nenue@33 62 -- hide the original world quest POIs
Nenue@33 63 hooksecurefunc("WorldMap_UpdateQuestBonusObjectives", function()
Nenue@33 64 for i = 1, NUM_WORLDMAP_TASK_POIS do
Nenue@33 65 local button = _G['WorldMapFrameTaskPOI'..i]
Nenue@33 66 if button and button.worldQuest then
Nenue@33 67 button:Hide()
Nenue@33 68 end
Nenue@33 69 end
Nenue@33 70 end)
Nenue@33 71 end
Nenue@33 72 local WorldMapPOIFrame
Nenue@33 73 local defaults = {}
Nenue@33 74 function WorldQuests:OnLoad()
Nenue@33 75 print('|cFF00FF88'..self:GetName()..':OnLoad')
Nenue@33 76
Nenue@33 77 WorldPlan:AddHandler(self, defaults)
Nenue@33 78
Nenue@33 79 local rgbWhite = {1, 1, 1}
Nenue@33 80 WorldPlan:AddTypeInfo(self, REWARD_REAGENT, { r = 0, g = 1, b = 1 })
Nenue@33 81 WorldPlan:AddTypeInfo(self, REWARD_ARTIFACT_POWER, { r = 1, g = .25, b = .5, hasNumeric = true, numberRGB = rgbWhite })
Nenue@33 82 WorldPlan:AddTypeInfo(self, REWARD_GEAR, { r = .1, g = .2, b = 1 })
Nenue@33 83 WorldPlan:AddTypeInfo(self, REWARD_CURRENCY, { r = 1, g = 1, b = 0, hasNumeric = true, numberRGB = {1,1,0}, })
Nenue@33 84 WorldPlan:AddTypeInfo(self, REWARD_CASH, { r = 0, g = 0, b = 0, })
Nenue@33 85
Nenue@33 86 for areaID, fileName in pairs(WORLD_QUEST_MAPS) do
Nenue@33 87 self.QuestsByZone[areaID] = {}
Nenue@33 88 end
Nenue@33 89
Nenue@33 90 self:RegisterEvent('WORLD_QUEST_COMPLETED_BY_SPELL')
Nenue@33 91 self:RegisterEvent('SKILL_LINES_CHANGED')
Nenue@33 92
Nenue@33 93 WorldMapPOIFrame = _G.WorldMapPOIFrame
Nenue@33 94
Nenue@33 95 end
Nenue@33 96
Nenue@33 97 function WorldQuests:OnEvent (event, ...)
Nenue@33 98 local print = wqprint
Nenue@33 99 print('|cFFFFFF00'..self:GetName()..':OnEvent()'..event..'|r', GetTime(), ...)
Nenue@33 100 if event == 'QUEST_LOG_UPDATE' then
Nenue@33 101 local questID, added = ...
Nenue@33 102 if questID and added then
Nenue@33 103 local questPOI = self:AcquirePin(questID)
Nenue@33 104 self.isStale, self.isPending = questPOI:RefreshData()
Nenue@33 105 else
Nenue@33 106 self:RefreshData()
Nenue@33 107 end
Nenue@33 108 print('WorldMapFrame', WorldMapFrame:IsVisible(), 'hasUpdates:', self.isStale)
Nenue@34 109 elseif event == 'WORLD_MAP_UPDATE' or event == 'PLAYER_ENTERING_WORLD' then
Nenue@33 110 self.isStale = true
Nenue@33 111 elseif event == 'WORLD_QUEST_COMPLETED_BY_SPELL' then
Nenue@33 112 local questID = ...
Nenue@33 113 if questID and self.QuestsByID[questID] then
Nenue@33 114 self:ReleasePin(self.QuestsByID[questID])
Nenue@33 115 end
Nenue@33 116 elseif event == 'SKILL_LINES_CHANGED' then
Nenue@33 117 self.isStale = true
Nenue@33 118 end
Nenue@33 119 end
Nenue@33 120
Nenue@33 121 local TQ_GetQuestLocation = C_TaskQuest.GetQuestLocation
Nenue@33 122 function WorldQuests:AcquirePin (questID, mapID)
Nenue@33 123 local pin = self.QuestsByID[questID]
Nenue@33 124 local isNew = false
Nenue@33 125 if not pin then
Nenue@33 126 isNew = true
Nenue@33 127 local numFree = #self.freePins
Nenue@33 128 if numFree >= 1 then
Nenue@33 129 pin = tremove(self.freePins, numFree)
Nenue@33 130 --print('|cFF00FF00Re-using', pin:GetName())
Nenue@33 131 else
Nenue@33 132 local name = 'WorldPlanQuestMarker' .. NumPinFrames
Nenue@33 133 --print('|cFF00FF00Creating', name)
Nenue@33 134 pin = CreateFrame('Frame', name, WorldMapPOIFrame, 'WorldPlanQuestPin')
Nenue@33 135
Nenue@33 136 pin:SetFrameStrata('HIGH')
Nenue@33 137 pin.GetTypeInfo = function(frame, typeID)
Nenue@33 138 return self:GetTypeInfo(typeID)
Nenue@33 139 end
Nenue@33 140 NumPinFrames = NumPinFrames + 1
Nenue@33 141 --pin.iconBorder:SetVertexColor(0,0,0,1)
Nenue@33 142 end
Nenue@33 143 pin:SetID(questID)
Nenue@33 144 pin.isNew = true
Nenue@33 145 pin.currentWidth = nil
Nenue@33 146
Nenue@33 147 -- used by TaskPOI_x scripts
Nenue@33 148 pin.questID = questID
Nenue@33 149 pin.worldQuest = true
Nenue@33 150
Nenue@33 151 self.QuestsByID[questID] = pin
Nenue@33 152 else
Nenue@33 153 --print('|cFF00FF00Using', pin:GetName())
Nenue@33 154 end
Nenue@33 155 mapID = mapID or TQ_GetQuestZoneID(questID)
Nenue@33 156 self.QuestsByZone[mapID][questID] = pin
Nenue@33 157
Nenue@33 158 return pin, isNew
Nenue@33 159 end
Nenue@33 160
Nenue@33 161 -- remove from index and add it to the recycling heap
Nenue@33 162 function WorldQuests:ReleasePin (pin)
Nenue@33 163
Nenue@33 164 local id = pin.questId
Nenue@33 165 if id then
Nenue@33 166 self.QuestsByID[id] = nil
Nenue@33 167 for i, zone in pairs(self.QuestsByZone) do
Nenue@33 168 print('-', i, zone[i])
Nenue@33 169 zone[id] = nil
Nenue@33 170 end
Nenue@33 171 end
Nenue@33 172 pin:Hide()
Nenue@33 173 pin:ClearAllPoints()
Nenue@33 174 tinsert(self.freePins, pin)
Nenue@33 175 print('|cFFFF4400Clearing out', pin:GetName(),id)
Nenue@33 176 end
Nenue@33 177
Nenue@33 178 -- create of update quest pins for a map and its underlying zones
Nenue@33 179 function WorldQuests:RefreshData (mapID)
Nenue@33 180 local print = wqprint
Nenue@33 181 mapID = mapID or GetCurrentMapAreaID()
Nenue@33 182 superTrackedID = GetSuperTrackedQuestID()
Nenue@33 183 if not mapID then
Nenue@33 184 -- info not available yet
Nenue@33 185 return
Nenue@33 186 end
Nenue@33 187
Nenue@34 188 if not self:IsVisible() then
Nenue@34 189 self.isStale = true
Nenue@34 190 print('frame closed, do it later')
Nenue@34 191 return
Nenue@34 192 end
Nenue@34 193
Nenue@34 194
Nenue@34 195 print('|cFF00FF88'..self:GetName()..':RefreshData()|r', 'map:', mapID, 'realMap:', GetCurrentMapAreaID())
Nenue@33 196
Nenue@33 197 if mapID == BROKEN_ISLES_ID then
Nenue@33 198 self.isStale = false
Nenue@33 199 print('|cFF00FFFFContinent:|r', mapID, GetMapNameByID(mapID), superTrackedID)
Nenue@33 200 self.fullSearch = true
Nenue@33 201 for i = 1, MC_GetNumZones(mapID) do
Nenue@33 202 local submapID, name, depth = MC_GetZoneInfo(mapID, i)
Nenue@33 203 self:RefreshData(submapID)
Nenue@33 204 end
Nenue@33 205 self.fullSearch = nil
Nenue@33 206 elseif self.QuestsByZone[mapID] then
Nenue@33 207 local taskInfo = TQ_GetQuestsForPlayerByMapID(mapID)
Nenue@33 208 local numQuests = 0
Nenue@33 209 if taskInfo and #taskInfo >= 1 then
Nenue@33 210 print('|cFF00FFFF Zone:|r', mapID, GetMapNameByID(mapID), #taskInfo)
Nenue@33 211 wipe(self.QuestsByZone[mapID])
Nenue@33 212 ZoneInfo[mapID] = taskInfo
Nenue@33 213 qprint('|cFFFF4400START of', GetMapNameByID(mapID))
Nenue@33 214 for taskID, info in pairs(taskInfo) do
Nenue@33 215 local questID = info.questId
Nenue@33 216 info.mapID = mapID
Nenue@33 217 local questPOI = self:AcquirePin(questID, mapID)
Nenue@33 218 local hasUpdate, isPending = questPOI:RefreshData(info)
Nenue@34 219 -- WorldPlan:print('|cFF0088FF'..questPOI.title..'|r', hasUpdate)
Nenue@33 220 self.isStale = (self.isStale or hasUpdate)
Nenue@33 221 self.isPending = (self.isPending or isPending)
Nenue@33 222 numQuests = numQuests + 1
Nenue@33 223 end
Nenue@33 224 qprint('|cFFFF4400END of', GetMapNameByID(mapID))
Nenue@33 225 end
Nenue@33 226 end
Nenue@33 227
Nenue@33 228 if not self.fullSearch then
Nenue@33 229 print(' hasUpdate:', self.isStale, 'isPending:', self.isPending, 'timer:', (self.OnNext and 'waiting' or ''))
Nenue@33 230 --WorldPlan.isStale = (self.isStale or WorldPlan.isStale)
Nenue@33 231 end
Nenue@33 232
Nenue@33 233 end
Nenue@33 234
Nenue@33 235 function WorldQuests:Refresh()
Nenue@33 236 local print = wqprint
Nenue@33 237 print('|cFF00FF88'..self:GetName()..':Refresh()|r')
Nenue@34 238 if not self:IsVisible() then
Nenue@34 239 self.isStale = true
Nenue@34 240 print('frame closed, do it later')
Nenue@34 241 return
Nenue@34 242 end
Nenue@34 243
Nenue@33 244 self:Reset()
Nenue@33 245 self:UpdateAnchors()
Nenue@33 246 self:Cleanup ()
Nenue@33 247 end
Nenue@33 248
Nenue@33 249 -- prepares elements for a map update
Nenue@33 250 function WorldQuests:Reset ()
Nenue@33 251 local print = wqprint
Nenue@33 252 print('|cFF00FF88'..self:GetName()..':Reset()|r')
Nenue@33 253 for questID, pin in pairs(self.QuestsByID) do
Nenue@33 254 pin.used = nil
Nenue@33 255 end
Nenue@33 256 end
Nenue@33 257
Nenue@33 258 -- update visibility states of all pins
Nenue@33 259 function WorldQuests:UpdateAnchors (submapID)
Nenue@33 260
Nenue@33 261 local print = wqprint
Nenue@33 262 local db = WorldPlan.db
Nenue@33 263 local mapFileName, textureHeight, textureWidth, isMicroDungeon, microDungeonMapName = GetMapInfo()
Nenue@33 264 if isMicroDungeon then
Nenue@33 265 return
Nenue@33 266 end
Nenue@33 267
Nenue@33 268 local currentMap = GetCurrentMapAreaID()
Nenue@33 269 local submapID = submapID or currentMap
Nenue@33 270
Nenue@33 271 if submapID == BROKEN_ISLES_ID and (not db.DisplayContinentPins) then
Nenue@33 272 print('not updating map for reasons')
Nenue@33 273 return
Nenue@33 274 end
Nenue@33 275 print('|cFF88FF00'..self:GetName()..':UpdateAnchors|r', submapID, GetMapNameByID(submapID), 'pin count:', numPins)
Nenue@33 276 local numZones = MC_GetNumZones(submapID)
Nenue@33 277 if numZones then
Nenue@33 278 for i = 1, numZones do
Nenue@33 279 local subMapID = MC_GetZoneInfo(submapID, i)
Nenue@33 280 self:UpdateAnchors(subMapID)
Nenue@33 281 end
Nenue@33 282 end
Nenue@33 283 local pins = self.QuestsByZone[submapID]
Nenue@33 284
Nenue@33 285 if pins then
Nenue@33 286 local hostFrame = WorldMapPOIFrame
Nenue@33 287 local mapWidth, mapHeight = hostFrame:GetSize()
Nenue@33 288 for questID, pin in pairs(pins) do
Nenue@33 289 pin:IsShowable()
Nenue@33 290 if pin.used then
Nenue@33 291 pin.hasUpdate = true
Nenue@33 292 pin:SetFrameLevel(PinBaseIndex+ (pin.whiteListed and 200 or 0) +numPins)
Nenue@33 293 print('level', PinBaseIndex+ (pin.whiteListed and 200 or 0) +numPins)
Nenue@34 294 pin:SetAnchor(_G.WorldMapPOIFrame, currentMap, mapWidth, mapHeight)
Nenue@33 295 numPins = numPins + 1
Nenue@33 296 end
Nenue@33 297 end
Nenue@33 298 end
Nenue@33 299 end
Nenue@33 300
Nenue@33 301 -- shows, animates, or hides pins based on their current visibility flags
Nenue@33 302 local debug_show = {}
Nenue@33 303 local debug_animate = {}
Nenue@33 304 local debug_hide = {}
Nenue@33 305 function WorldQuests:Cleanup ()
Nenue@33 306 local print = wqprint
Nenue@34 307 local showQuestPOI = WorldPlan.db.EnablePins
Nenue@34 308 WorldPlan:print('|cFFFFFF00'..self:GetName()..':Cleanup()|r')
Nenue@34 309 -- continent or zone sizing
Nenue@33 310
Nenue@33 311
Nenue@33 312 numPins = 0
Nenue@33 313 for questID, pin in pairs(self.QuestsByID) do
Nenue@33 314 -- can we show it?
Nenue@34 315 pin:SetShown((showQuestPOI and pin.used))
Nenue@33 316 end
Nenue@33 317 print(' adding:', table.concat(debug_animate, ',' ))
Nenue@33 318 print(' refresh:', table.concat(debug_show, ',' ))
Nenue@33 319 print(' hiding:', table.concat(debug_hide, ',' ))
Nenue@33 320 self.isStale = nil
Nenue@33 321 end
Nenue@33 322
Nenue@33 323 function WorldQuests:FilterCheckByID(questID)
Nenue@33 324 local pin = WorldQuests:GetPinByQuestID(questID)
Nenue@33 325 return pin:IsShowable()
Nenue@33 326 end