annotate WorldQuests.lua @ 33:be4db60219ca

WorldPlan: - Toggling a reward filter cancels out other types by default. Use right mouse to clear. - Fixed filter bar info falling out of sync after player-triggered world map updates. 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 17:25:07 -0400
parents
children 0100d923d8c3
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@33 109 elseif event == 'WORLD_MAP_UPDATE' 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@33 188 print('|cFF00FF88'..self:GetName()..':RefreshData()|r', 'map:', mapID, 'realMap:', GetCurrentMapAreaID())
Nenue@33 189
Nenue@33 190 if mapID == BROKEN_ISLES_ID then
Nenue@33 191 self.isStale = false
Nenue@33 192 print('|cFF00FFFFContinent:|r', mapID, GetMapNameByID(mapID), superTrackedID)
Nenue@33 193 self.fullSearch = true
Nenue@33 194 for i = 1, MC_GetNumZones(mapID) do
Nenue@33 195 local submapID, name, depth = MC_GetZoneInfo(mapID, i)
Nenue@33 196 self:RefreshData(submapID)
Nenue@33 197 end
Nenue@33 198 self.fullSearch = nil
Nenue@33 199 elseif self.QuestsByZone[mapID] then
Nenue@33 200 local taskInfo = TQ_GetQuestsForPlayerByMapID(mapID)
Nenue@33 201 local numQuests = 0
Nenue@33 202 if taskInfo and #taskInfo >= 1 then
Nenue@33 203 print('|cFF00FFFF Zone:|r', mapID, GetMapNameByID(mapID), #taskInfo)
Nenue@33 204 wipe(self.QuestsByZone[mapID])
Nenue@33 205 ZoneInfo[mapID] = taskInfo
Nenue@33 206 qprint('|cFFFF4400START of', GetMapNameByID(mapID))
Nenue@33 207 for taskID, info in pairs(taskInfo) do
Nenue@33 208 local questID = info.questId
Nenue@33 209 info.mapID = mapID
Nenue@33 210 local questPOI = self:AcquirePin(questID, mapID)
Nenue@33 211 local hasUpdate, isPending = questPOI:RefreshData(info)
Nenue@33 212 self.isStale = (self.isStale or hasUpdate)
Nenue@33 213 self.isPending = (self.isPending or isPending)
Nenue@33 214 numQuests = numQuests + 1
Nenue@33 215 end
Nenue@33 216 qprint('|cFFFF4400END of', GetMapNameByID(mapID))
Nenue@33 217 end
Nenue@33 218 end
Nenue@33 219
Nenue@33 220 if not self.fullSearch then
Nenue@33 221 print(' hasUpdate:', self.isStale, 'isPending:', self.isPending, 'timer:', (self.OnNext and 'waiting' or ''))
Nenue@33 222 --WorldPlan.isStale = (self.isStale or WorldPlan.isStale)
Nenue@33 223 end
Nenue@33 224
Nenue@33 225 end
Nenue@33 226
Nenue@33 227 function WorldQuests:Refresh()
Nenue@33 228 local print = wqprint
Nenue@33 229 print('|cFF00FF88'..self:GetName()..':Refresh()|r')
Nenue@33 230 self:Reset()
Nenue@33 231 self:UpdateAnchors()
Nenue@33 232 self:Cleanup ()
Nenue@33 233 end
Nenue@33 234
Nenue@33 235 -- prepares elements for a map update
Nenue@33 236 function WorldQuests:Reset ()
Nenue@33 237 local print = wqprint
Nenue@33 238 print('|cFF00FF88'..self:GetName()..':Reset()|r')
Nenue@33 239 for questID, pin in pairs(self.QuestsByID) do
Nenue@33 240 pin.used = nil
Nenue@33 241 end
Nenue@33 242 end
Nenue@33 243
Nenue@33 244 -- update visibility states of all pins
Nenue@33 245 function WorldQuests:UpdateAnchors (submapID)
Nenue@33 246
Nenue@33 247 local print = wqprint
Nenue@33 248 local db = WorldPlan.db
Nenue@33 249 local mapFileName, textureHeight, textureWidth, isMicroDungeon, microDungeonMapName = GetMapInfo()
Nenue@33 250 if isMicroDungeon then
Nenue@33 251 return
Nenue@33 252 end
Nenue@33 253
Nenue@33 254 local currentMap = GetCurrentMapAreaID()
Nenue@33 255 local submapID = submapID or currentMap
Nenue@33 256
Nenue@33 257 if submapID == BROKEN_ISLES_ID and (not db.DisplayContinentPins) then
Nenue@33 258 print('not updating map for reasons')
Nenue@33 259 return
Nenue@33 260 end
Nenue@33 261 print('|cFF88FF00'..self:GetName()..':UpdateAnchors|r', submapID, GetMapNameByID(submapID), 'pin count:', numPins)
Nenue@33 262 local numZones = MC_GetNumZones(submapID)
Nenue@33 263 if numZones then
Nenue@33 264 for i = 1, numZones do
Nenue@33 265 local subMapID = MC_GetZoneInfo(submapID, i)
Nenue@33 266 self:UpdateAnchors(subMapID)
Nenue@33 267 end
Nenue@33 268 end
Nenue@33 269 local pins = self.QuestsByZone[submapID]
Nenue@33 270
Nenue@33 271 if pins then
Nenue@33 272 local hostFrame = WorldMapPOIFrame
Nenue@33 273 local mapWidth, mapHeight = hostFrame:GetSize()
Nenue@33 274 for questID, pin in pairs(pins) do
Nenue@33 275 pin:IsShowable()
Nenue@33 276 if pin.used then
Nenue@33 277 pin.hasUpdate = true
Nenue@33 278 pin:SetFrameLevel(PinBaseIndex+ (pin.whiteListed and 200 or 0) +numPins)
Nenue@33 279 print('level', PinBaseIndex+ (pin.whiteListed and 200 or 0) +numPins)
Nenue@33 280 pin:SetAnchor(WorldMapPOIFrame, currentMap, mapWidth, mapHeight)
Nenue@33 281 numPins = numPins + 1
Nenue@33 282 end
Nenue@33 283 end
Nenue@33 284 end
Nenue@33 285 end
Nenue@33 286
Nenue@33 287 -- shows, animates, or hides pins based on their current visibility flags
Nenue@33 288 local debug_show = {}
Nenue@33 289 local debug_animate = {}
Nenue@33 290 local debug_hide = {}
Nenue@33 291 function WorldQuests:Cleanup ()
Nenue@33 292 local print = wqprint
Nenue@33 293 local showQuestPOI = db.EnablePins
Nenue@33 294 print('|cFFFFFF00'..tostring(self)..':Cleanup()|r')
Nenue@33 295 local mapID = GetCurrentMapAreaID()
Nenue@33 296 isContinentMap = (mapID == BROKEN_ISLES_ID)
Nenue@33 297
Nenue@33 298 wipe(debug_show)
Nenue@33 299 wipe(debug_animate)
Nenue@33 300 wipe(debug_hide)
Nenue@33 301 -- continent or zone sizing
Nenue@33 302 local fadeGrouped = (db.FadeWhileGrouped and IsInGroup())
Nenue@33 303
Nenue@33 304 numPins = 0
Nenue@33 305 for questID, pin in pairs(self.QuestsByID) do
Nenue@33 306 -- can we show it?
Nenue@33 307 if showQuestPOI and (pin.used) then
Nenue@33 308
Nenue@33 309 pin.isStale = true
Nenue@33 310 if fadeGrouped then
Nenue@33 311 pin:SetAlpha(0.25)
Nenue@33 312 else
Nenue@33 313 pin:SetAlpha(1)
Nenue@33 314 end
Nenue@33 315 -- is it a new quest?
Nenue@33 316 if pin.isNew then
Nenue@33 317 if not pin.isAnimating then
Nenue@33 318 pin.isAnimating = true
Nenue@33 319 WorldPlan:OnNext(function()
Nenue@33 320 pin:ShowNew()
Nenue@33 321 end)
Nenue@33 322 tinsert(debug_animate,questID)
Nenue@33 323 else
Nenue@33 324
Nenue@33 325 print('animating? ', questID, 'filtered:', pin.filtered)
Nenue@33 326 end
Nenue@33 327 -- trap new but animating pins here
Nenue@33 328 else
Nenue@33 329 -- hard show existing pin
Nenue@33 330 --print('refresh #', questID, 'filtered:', pin.filtered, 'hasUpdate', pin.hasUpdate)
Nenue@33 331 pin:Show()
Nenue@33 332 tinsert(debug_show,questID)
Nenue@33 333 end
Nenue@33 334 else
Nenue@33 335 if pin:IsShown() then
Nenue@33 336 tinsert(debug_hide,questID)
Nenue@33 337 end
Nenue@33 338 pin.isAnimating = nil
Nenue@33 339 pin.FadeIn:Stop()
Nenue@33 340 pin:Hide()
Nenue@33 341 end
Nenue@33 342 end
Nenue@33 343 print(' adding:', table.concat(debug_animate, ',' ))
Nenue@33 344 print(' refresh:', table.concat(debug_show, ',' ))
Nenue@33 345 print(' hiding:', table.concat(debug_hide, ',' ))
Nenue@33 346 hasNewQuestPins = nil
Nenue@33 347 notifyPlayed = nil
Nenue@33 348 self.isStale = nil
Nenue@33 349 end
Nenue@33 350
Nenue@33 351 function WorldQuests:FilterCheckByID(questID)
Nenue@33 352 local pin = WorldQuests:GetPinByQuestID(questID)
Nenue@33 353 return pin:IsShowable()
Nenue@33 354 end