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