comparison ObjectiveTracker/ObjectiveCore.lua @ 23:e837384ac363

Separating objective tracker module
author Nenue
date Sun, 10 Apr 2016 04:35:32 -0400
parents ObjectiveCore.lua@9b3fa734abff
children 66b927b46776
comparison
equal deleted inserted replaced
22:9b3fa734abff 23:e837384ac363
1 --- ${PACKAGE_NAME}
2 -- @file-author@
3 -- @project-revision@ @project-hash@
4 -- @file-revision@ @file-hash@
5 -- Created: 3/26/2016 1:51 AM
6 local B, _G = select(2,...).frame, _G
7 local pairs, setmetatable, type, tostring, band, format = _G.pairs, _G.setmetatable, _G.type, _G.tostring, bit.band, string.format
8 local ipairs, tinsert, hooksecurefunc = _G.ipairs, _G.tinsert, _G.hooksecurefunc
9 local PlaySoundFile, IsQuestTask, SortQuestWatches, GetCurrentMapAreaID, GetZoneText, GetMinimapZoneText = PlaySoundFile, IsQuestTask, SortQuestWatches, GetCurrentMapAreaID, GetZoneText, GetMinimapZoneText
10 local AddQuestWatch, SetSuperTrackedQuestID, GetNumQuestWatches, AUTO_QUEST_WATCH, MAX_WATCHABLE_QUESTS = AddQuestWatch, SetSuperTrackedQuestID, GetNumQuestWatches, AUTO_QUEST_WATCH, MAX_WATCHABLE_QUESTS
11 local QuestPOIUpdateIcons, GetCVar, IsPlayerInMicroDungeon, WorldMapFrame, GetCVarBool, SetMapToCurrentZone = QuestPOIUpdateIcons, GetCVar, IsPlayerInMicroDungeon, WorldMapFrame, GetCVarBool, SetMapToCurrentZone
12 local AddAutoQuestPopUp = AddAutoQuestPopUp
13 local mod = B:RegisterModule("ObjectiveTracker", _G.VeneerObjectiveWrapper, 'BuffFrame')
14 local print = B.print('Objectives')
15 local ObjectiveTrackerFrame, VeneerObjectiveScroll, CreateFrame = _G.ObjectiveTrackerFrame, _G.VeneerObjectiveScroll, _G.CreateFrame
16 local Wrapper = _G.VeneerObjectiveWrapper
17 local Scroller = VeneerObjectiveWrapper.scrollArea
18 local Scroll = _G.VeneerObjectiveScroll
19
20 --- Performance values
21 --[[
22 self:RegisterEvent("QUEST_LOG_UPDATE");
23 self:RegisterEvent("TRACKED_ACHIEVEMENT_LIST_CHANGED");
24 self:RegisterEvent("QUEST_WATCH_LIST_CHANGED");
25 self:RegisterEvent("QUEST_AUTOCOMPLETE");
26 self:RegisterEvent("QUEST_ACCEPTED");
27 self:RegisterEvent("SUPER_TRACKED_QUEST_CHANGED");
28 self:RegisterEvent("SCENARIO_UPDATE");
29 self:RegisterEvent("SCENARIO_CRITERIA_UPDATE");
30 self:RegisterEvent("TRACKED_ACHIEVEMENT_UPDATE");
31 self:RegisterEvent("ZONE_CHANGED_NEW_AREA");
32 self:RegisterEvent("ZONE_CHANGED");
33 self:RegisterEvent("QUEST_POI_UPDATE");
34 self:RegisterEvent("VARIABLES_LOADED");
35 self:RegisterEvent("QUEST_TURNED_IN");
36 self:RegisterEvent("PLAYER_MONEY");
37 ]]
38
39
40 --- These are the bitfields used by Blizzard_ObjectiveTracker to determine which segments get parsed.
41 --- They are replicated here so that plugins can make use of any securehook args involving this info.
42 local OBJECTIVE_TRACKER_UPDATE_MODULE_QUEST = OBJECTIVE_TRACKER_UPDATE_MODULE_QUEST -- 0x0100
43 local OBJECTIVE_TRACKER_UPDATE_MODULE_AUTO_QUEST_POPUP = OBJECTIVE_TRACKER_UPDATE_MODULE_AUTO_QUEST_POPUP -- 0x0200
44 local OBJECTIVE_TRACKER_UPDATE_MODULE_BONUS_OBJECTIVE = OBJECTIVE_TRACKER_UPDATE_MODULE_BONUS_OBJECTIVE -- 0x0400
45 local OBJECTIVE_TRACKER_UPDATE_MODULE_SCENARIO = OBJECTIVE_TRACKER_UPDATE_MODULE_SCENARIO -- 0x0800
46 local OBJECTIVE_TRACKER_UPDATE_MODULE_ACHIEVEMENT = OBJECTIVE_TRACKER_UPDATE_MODULE_ACHIEVEMENT -- 0x1000
47
48
49 local OBJECTIVE_TRACKER_UPDATE_STATIC = OBJECTIVE_TRACKER_UPDATE_STATIC -- 0x0000
50 local OBJECTIVE_TRACKER_UPDATE_ALL = OBJECTIVE_TRACKER_UPDATE_ALL -- 0xFFFF
51 local OBJECTIVE_TRACKER_UPDATE_ID = OBJECTIVE_TRACKER_UPDATE_ID -- 0
52
53 local OBJECTIVE_TRACKER_UPDATE_QUEST = OBJECTIVE_TRACKER_UPDATE_QUEST -- 0x0001
54 local OBJECTIVE_TRACKER_UPDATE_QUEST_ADDED = OBJECTIVE_TRACKER_UPDATE_QUEST_ADDED -- 0x0002
55 local OBJECTIVE_TRACKER_UPDATE_TASK_ADDED = OBJECTIVE_TRACKER_UPDATE_TASK_ADDED -- 0x0004
56 local OBJECTIVE_TRACKER_UPDATE_SCENARIO = OBJECTIVE_TRACKER_UPDATE_SCENARIO -- 0x0008
57 local OBJECTIVE_TRACKER_UPDATE_SCENARIO_NEW_STAGE = OBJECTIVE_TRACKER_UPDATE_SCENARIO_NEW_STAGE -- 0x0010
58 local OBJECTIVE_TRACKER_UPDATE_ACHIEVEMENT = OBJECTIVE_TRACKER_UPDATE_ACHIEVEMENT -- 0x0020
59 local OBJECTIVE_TRACKER_UPDATE_ACHIEVEMENT_ADDED = OBJECTIVE_TRACKER_UPDATE_ACHIEVEMENT_ADDED -- 0x0040
60 local OBJECTIVE_TRACKER_UPDATE_SCENARIO_BONUS_DELAYED = OBJECTIVE_TRACKER_UPDATE_SCENARIO_BONUS_DELAYED -- 0x0080
61
62 local OBJECTIVE_TRACKER_UPDATE_REASON = OBJECTIVE_TRACKER_UPDATE_ALL -- default
63 --- Used to determine which trackers are listening for money events
64 mod.watchMoneyReasons = 0
65
66 --- Baseline defaults table; values defined in the files that they pertain to
67 mod.defaults = {}
68
69 --- Tracker display order
70 mod.orderedNames = {'Bonus', 'AutoQuest', 'Quest', 'Cheevs'}
71
72 --- ipairs() argument tables
73 mod.orderedHandlers = setmetatable({}, {__mode = "k"})
74 mod.orderedTrackers = setmetatable({}, {__mode = "k"})
75 mod.indexedTrackers = setmetatable({}, {__mode = "k"})
76
77 --- pairs() argument tables
78 mod.namedTrackers = setmetatable({}, {__mode = "k"})
79
80 local WRAPPER_ANCHOR_POINT = 'TOPRIGHT'
81 local WRAPPER_OFFSET_X = 0
82 local WRAPPER_OFFSET_Y = -200
83 local WRAPPER_MAX_HEIGHT = 670
84 local WRAPPER_WIDTH = 280
85 local WRAPPER_HEADER_HEIGHT = 24
86
87 mod.defaults.Wrapper = {
88 AnchorPoint = WRAPPER_ANCHOR_POINT,
89 OffsetX = WRAPPER_OFFSET_X,
90 OffsetY = WRAPPER_OFFSET_Y,
91 Height = WRAPPER_MAX_HEIGHT,
92 Width = WRAPPER_WIDTH,
93 HeaderHeight = WRAPPER_HEADER_HEIGHT,
94 TextSpacing = 3,
95 TitleSpacing = 3,
96 }
97
98
99
100 --- Tracker module definitions begin here; innards dealing with data retreival and output are defined further in
101 mod.DefaultHandler = {
102 previousHeight = 0,
103
104 name = "temp",
105 displayName = "temp",
106 updateReasonModule = 0xFF00,
107 updateReasonEvent = 0x00FF,
108
109 numWatched = 0, --- number of entries being handled
110 numBlocks = 0, --- number of blocks created
111 actualBlocks = 0, --- number of blocks in use
112
113 freeBlocks = {}, --- block heap
114 usedBlocks = {},
115
116 Info = {}, -- find data by ID
117 BlockInfo = {}, -- find data by block ID
118 Watched = {}, -- find watchIndex by data ID
119 WatchInfo = {}, -- find data by watch index
120 WatchBlock = {}, -- find block by watch index
121 }
122
123 mod.AutoQuest = {
124 name = "AutoQuest",
125 displayName = "Notice",
126 updateReasonModule = OBJECTIVE_TRACKER_UPDATE_MODULE_QUEST,
127 updateReasonEvents = OBJECTIVE_TRACKER_UPDATE_QUEST +
128 OBJECTIVE_TRACKER_UPDATE_QUEST_ADDED,
129 }
130 mod.Quest = {
131 name = "Quest",
132 displayName = "Quests",
133 updateReasonModule = OBJECTIVE_TRACKER_UPDATE_MODULE_QUEST,
134 updateReasonEvents = OBJECTIVE_TRACKER_UPDATE_QUEST +
135 OBJECTIVE_TRACKER_UPDATE_QUEST_ADDED,
136 }
137 mod.Cheevs = {
138 name = "Cheevs",
139 displayName = "Achievements",
140 updateReasonModule = OBJECTIVE_TRACKER_UPDATE_MODULE_ACHIEVEMENT,
141 updateReasonEvents = OBJECTIVE_TRACKER_UPDATE_ACHIEVEMENT +
142 OBJECTIVE_TRACKER_UPDATE_ACHIEVEMENT_ADDED,
143 }
144 mod.Bonus = {
145 name = "Bonus",
146 displayName = "Bonus Objectives",
147 updateReasonModule = OBJECTIVE_TRACKER_UPDATE_MODULE_BONUS_OBJECTIVE,
148 updateReasonEvents = OBJECTIVE_TRACKER_UPDATE_QUEST + OBJECTIVE_TRACKER_UPDATE_TASK_ADDED
149 }
150
151 local Tracker_string = function (self)
152 return self.name
153 end
154 local Tracker_call = function (self, reason)
155 self:Update(reason)
156 end
157 local Handler_Initialize = function (self, name, index)
158 print('Initializing |cFF00FFFF'..name..'|r module...')
159
160 local handler = setmetatable(mod[name] or {}, {
161 __tostring = Tracker_string,
162 __call = Tracker_call
163 })
164 if type(mod.orderedHandlers[index]) == 'table' then
165 return mod.orderedHandlers[index]
166 end
167
168 print('|cFFFFFF00Acquiring locals')
169 local preset = {}
170 for k, _ in pairs(handler) do
171 preset[k] = true
172 end
173
174
175 print('|cFFFF8800Inheriting')
176 for k, v in pairs(self) do
177 if not handler[k] then
178 if type(v) == 'table' then
179 -- assume all tables to be local data; don't inherit or ref
180 handler[k] = {}
181 else
182 handler[k] = self[k]
183 end
184 print('copying', k)
185 end
186 end
187 print('|cFFFF4400'..tostring(name)..'|r:')
188 for k, v in pairs(handler) do
189 print(format("%32s %8s %s", (preset[k] and '|cFFFFFFFF' or '|cFFFFFF00') .. k .. '|r', type(v), tostring(v)))
190 end
191
192 mod[name] = handler
193
194 local trackerName = 'Veneer'..name..'Tracker'
195 local handler = mod[name]
196 local frame = CreateFrame('Frame', trackerName, _G.VeneerObjectiveScroll, 'VeneerTrackerTemplate')
197 frame.title:SetText(handler.displayName)
198 mod.SetBlockStyle(frame, 'Tracker', 'Normal')
199 handler.frame = frame
200 handler.trackerName = trackerName
201 handler.lines = {}
202 mod.orderedTrackers[index] = frame
203 mod.namedTrackers[name] = frame
204 mod.indexedTrackers[handler] = frame
205 print('|cFFFF0088' .. trackerName .. '|r created for |cFF00FFFF' .. handler.displayName .. '|r module')
206
207 mod.orderedHandlers[index] = handler
208 return true
209 end
210
211 local Event = {}
212 Event.QUEST_LOG_UPDATE = function()
213 return OBJECTIVE_TRACKER_UPDATE_MODULE_QUEST + OBJECTIVE_TRACKER_UPDATE_MODULE_BONUS_OBJECTIVE
214 end
215 Event.QUEST_ACCEPTED = function(questLogIndex, questID)
216 if ( IsQuestTask(questID) ) then
217 return OBJECTIVE_TRACKER_UPDATE_TASK_ADDED, questID
218 else
219 if ( AUTO_QUEST_WATCH == "1" and GetNumQuestWatches() < MAX_WATCHABLE_QUESTS ) then
220 AddQuestWatch(questLogIndex);
221 SetSuperTrackedQuestID(questID);
222 end
223 return OBJECTIVE_TRACKER_UPDATE_MODULE_QUEST
224 end
225 end
226
227 Event.QUEST_WATCH_LIST_CHANGED = function(questID, added)
228 if ( added ) then
229 if ( not IsQuestTask(questID) ) then
230 return OBJECTIVE_TRACKER_UPDATE_QUEST_ADDED, questID, added
231 end
232 else
233 return OBJECTIVE_TRACKER_UPDATE_QUEST, questID, added
234 end
235 end
236
237 Event.QUEST_POI_UPDATE = function()
238 QuestPOIUpdateIcons();
239 if ( GetCVar("trackQuestSorting") == "proximity" ) then
240 SortQuestWatches();
241 end
242 return OBJECTIVE_TRACKER_UPDATE_ALL
243 end
244 Event.SUPER_TRACKED_QUEST_CHANGED = function()
245 return OBJECTIVE_TRACKER_UPDATE_QUEST
246 end
247 Event.ZONE_CHANGED = function()
248
249 local inMicroDungeon = IsPlayerInMicroDungeon();
250 if ( inMicroDungeon ~= mod.inMicroDungeon ) then
251 if ( not WorldMapFrame:IsShown() and GetCVarBool("questPOI") ) then
252 SetMapToCurrentZone(); -- update the zone to get the right POI numbers for the tracker
253 end
254 --SortQuestWatches();
255 mod.inMicroDungeon = inMicroDungeon;
256 end
257 end
258 Event.QUEST_AUTOCOMPLETE = function(questId)
259 AddAutoQuestPopUp(questId, "COMPLETE");
260 return OBJECTIVE_TRACKER_UPDATE_MODULE_QUEST + OBJECTIVE_TRACKER_UPDATE_MODULE_AUTO_QUEST_POPUP
261 end
262 Event.SCENARIO_CRITERIA_UPDATE = function()
263 return OBJECTIVE_TRACKER_UPDATE_SCENARIO
264 end
265 Event.SCENARIO_UPDATE = function(newStage)
266 if ( newStage ) then
267 return OBJECTIVE_TRACKER_UPDATE_SCENARIO_NEW_STAGE
268 else
269 return OBJECTIVE_TRACKER_UPDATE_SCENARIO
270 end
271 end
272 Event.TRACKED_ACHIEVEMENT_UPDATE = function()
273 return OBJECTIVE_TRACKER_UPDATE_ACHIEVEMENT
274 end
275 Event.TRACKED_ACHIEVEMENT_LIST_CHANGED = function(achievementID, added)
276 if ( added ) then
277 return OBJECTIVE_TRACKER_UPDATE_ACHIEVEMENT_ADDED, achievementID
278 else
279 return OBJECTIVE_TRACKER_UPDATE_ACHIEVEMENT
280 end
281 end
282 Event.ZONE_CHANGED_NEW_AREA = function ()
283 if ( not WorldMapFrame:IsShown() and GetCVarBool("questPOI") ) then
284 SetMapToCurrentZone(); -- update the zone to get the right POI numbers for the tracker
285 end
286 SortQuestWatches();
287 mod.currentZoneArea = GetCurrentMapAreaID()
288 print('Updating zone ID to', mod.currentZoneArea, '=', GetZoneText(), GetMinimapZoneText())
289
290
291 return OBJECTIVE_TRACKER_UPDATE_TASK_ADDED
292 end
293
294
295 Event.PLAYER_MONEY = function()
296 if mod.watchMoneyReasons > 0 then
297 return mod.watchMoneyReasons
298 end
299 end
300 Event.CRITERIA_COMPLETE = function()
301 return OBJECTIVE_TRACKER_UPDATE_MODULE_BONUS_OBJECTIVE
302 end
303 Event.QUEST_TURN_IN = function(questID, xp, money)
304 if ( IsQuestTask(questID) ) then
305 mod.Bonus:OnTurnIn(questID, xp, money)
306 print('updating bonus modules (code', OBJECTIVE_TRACKER_UPDATE_MODULE_BONUS_OBJECTIVE, ',', questID, xp, money)
307 return OBJECTIVE_TRACKER_UPDATE_MODULE_BONUS_OBJECTIVE, questID, xp, money
308 else
309 return OBJECTIVE_TRACKER_UPDATE_MODULE_QUEST, questID, xp, money
310 end
311 end
312 mod.Event = Event
313
314 --- Done once per ui load
315 local BlizzHooks = {
316 ['AddQuestWatch'] = 'AddQuestWatch',
317 ['RemoveQuestWatch'] = 'RemoveQuestWatch',
318 ['AbandonQuest'] = 'AbandonQuest',
319 ['AcknowledgeAutoAcceptQuest'] = 'AcknowledgeAutoAcceptQuest',
320 ['AddAutoQuestPopUp'] = 'AddAutoQuestPopUp',
321 ['RemoveAutoQuestPopUp'] = 'RemoveAutoQuestPopUp',
322 ['AddTrackedAchievement'] = 'AddTrackedAchievement',
323 ['RemoveTrackedAchievement'] = 'RemoveTrackedAchievement',
324 ['SetSuperTrackedQuestID'] = 'SetSuperTrackedQuestID'
325 }
326 local VeneerData
327
328 mod.SetWatchMoney = function(watchMoney, reason)
329 if watchMoney then
330 if band(mod.watchMoneyReasons, reason) == 0 then
331 mod.watchMoneyReasons = mod.watchMoneyReasons + reason;
332 end
333 else
334 if band(mod.watchMoneyReasons, reason) > 0 then
335 mod.watchMoneyReasons = mod.watchMoneyReasons - reason;
336 end
337 end
338 end
339 mod.animateReasons = 0
340 mod.SetAnimate = function(animate, reason)
341 if animate then
342 if band(mod.animateReasons, reason) == 0 then
343 mod.animateReasons = mod.animateReasons + reason
344 end
345 else
346 if band(mod.animateReasons, reason) > 0 then
347 mod.animateReasons = mod.animateReasons - reason
348 end
349 end
350 end
351
352
353 function mod:OnInitialize()
354 local c = mod.Conf.Wrapper
355 VeneerData = _G.VeneerData
356 VeneerData.CallLog = VeneerData.CallLog or {}
357 if not mod.isHooked then
358 mod.isHooked = true
359 for blizzFunc, veneerFunc in pairs(BlizzHooks) do
360 if mod[veneerFunc] then
361 hooksecurefunc(blizzFunc, mod[veneerFunc])
362 else
363 hooksecurefunc(blizzFunc, function(...)
364 print('|cFFFF0088securehook('..tostring(blizzFunc)..')|r args:', ...)
365 tinsert(VeneerData.CallLog, {blizzFunc, ...})
366 end)
367 end
368 end
369 end
370
371 mod.Conf.TasksLog = mod.Conf.TasksLog or {}
372
373 Scroller:SetScrollChild(Scroll)
374 Scroller:SetWidth(c.Width)
375 Scroll:SetWidth(c.Width)
376 Scroll:ClearAllPoints()
377 Scroll:SetPoint('TOP', Scroller, 'TOP')
378 ObjectiveTrackerFrame:UnregisterAllEvents()
379 ObjectiveTrackerFrame:Hide()
380
381 if B.Conf.FrameState[Wrapper:GetName()] == 0 then
382 Scroller:Hide()
383 end
384 end
385
386 local Play = function(file) if Devian and Devian.InWorkspace() then PlaySoundFile(file) end end
387
388 function mod:OnEvent (event, ...)
389 local isHandled
390 print('OnEvent(|cFF00FF00'.. event ..'|r):', ...)
391 local reason, arg1, arg2, arg3
392 if Event[event] then
393 if type(Event[event]) == 'function' then
394 Play([[Interface\Addons\SharedMedia_MyMedia\sound\Info.ogg]])
395 reason, arg1, arg2, arg3 = Event[event](...)
396 elseif type(Event[event]) == 'table' then
397 Play([[Interface\Addons\SharedMedia_MyMedia\sound\Link.ogg]])
398 for i, action in ipairs(Event[event]) do
399 if type(action) == 'function' then
400 reason, arg1, arg2, arg3 = action(event, ...)
401 else
402 reason = action
403 end
404
405 if reason then
406 mod:Update(reason, arg1, arg2, arg3)
407 end
408 end
409 else
410 Play([[Interface\Addons\SharedMedia_MyMedia\sound\Heart.ogg]])
411 reason = Event[event]
412 end
413 else
414 Play([[Interface\Addons\SharedMedia_MyMedia\sound\Quack.ogg]])
415 end
416 if reason then
417 mod:Update(reason, arg1, arg2, arg3)
418 else
419 print('no reason value returned')
420 Play([[Interface\Addons\SharedMedia_MyMedia\sound\Quack.ogg]])
421 end
422 end
423
424 --- Done any time the the minimize button is toggled up
425 function mod:OnEnable()
426 for id, name in ipairs(mod.orderedNames) do
427 if not mod.orderedHandlers[id] then
428 Handler_Initialize(mod.DefaultHandler, name, id)
429 end
430 end
431
432 for event, action in pairs(Event) do
433 print('|cFFFF0088listen to', event, 'for action|r', tostring(action))
434 Wrapper:RegisterEvent(event)
435 end
436
437 Wrapper:SetScript('OnEvent', mod.OnEvent)
438 local c = mod.Conf.Wrapper
439 Wrapper:SetWidth(c.Width)
440
441 mod.InitializeWidgets()
442 mod:Update()
443
444
445 end
446
447 function mod:OnDisable()
448 Wrapper:UnregisterAllEvents()
449 end
450
451