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