comparison Veneer_Objectives/ObjectiveTracker.lua @ 77:51f248dc0276

setup working copy dingaling
author Nenue
date Sat, 27 Aug 2016 10:51:08 -0400
parents
children 0784b87f9722
comparison
equal deleted inserted replaced
76:83b3cdaae6a5 77:51f248dc0276
1 -- Veneer
2 -- ObjectiveTracker.lua
3 -- Created: 8/16/2016 8:19 AM
4 -- %file-revision%
5 -- This is more or less a copy of the blizzard code with some customization stuff added
6
7 local plugin = VeneerObjectives
8 local vn, print = LibStub("LibKraken").register(Veneer, VeneerObjectives)
9 local ot
10 local otvn
11
12 local band, floor, min = bit.band, math.floor, math.min
13
14
15 local X_QUEST = 0x00001;
16 local X_QUEST_ADDED = 0x00002;
17 local X_TASK_ADDED = 0x00004;
18 local X_WORLD_QUEST_ADDED = 0x00008;
19 local X_SCENARIO = 0x00010;
20 local X_SCENARIO_NEW_STAGE = 0x00020;
21 local X_ACHIEVEMENT = 0x00040;
22 local X_ACHIEVEMENT_ADDED = 0x00080;
23 local X_SCENARIO_BONUS_DELAYED = 0x00100;
24 local X_SUPER_TRACK_CHANGED = 0x00200;
25 -- these are for the specific module ONLY!
26 local X_MODULE_QUEST = 0x00400;
27 local X_MODULE_AUTO_QUEST_POPUP = 0x00800;
28 local X_MODULE_BONUS_OBJECTIVE = 0x01000;
29 local X_MODULE_WORLD_QUEST = 0x02000;
30 local X_MODULE_SCENARIO = 0x04000;
31 local X_MODULE_ACHIEVEMENT = 0x08000;
32 local X_SCENARIO_SPELLS = 0x10000;
33 -- special updates
34 local X_STATIC = 0x0000;
35 local X_ALL = 0xFFFF;
36
37 -- state information
38 local X_REASON = X_ALL; -- default
39 local X_MONEY = 0
40 local X_ANIMATION = 0
41 local X_ID = 0;
42
43 local INSET_V = -20
44
45
46
47 local trackerWidth = 240
48 local blockIndent = 12
49 local blockSpacing = 3
50
51 local tracker = {
52 freeBlocks = {},
53 usedBlocks = {},
54 freeProgressBars = {},
55 usedProgressBars = {},
56 freeTimers = {},
57 usedTimers = {},
58 freeLines = {},
59
60 headerText = 'Default Header',
61 contentHeight = 0,
62 animationHeight = 0,
63 updateReasonModule = 0,
64 updateReasonEvents = 0,
65 }
66 local GetTrackerHandler = function(handler)
67 handler = handler or {}
68 setmetatable(handler, {__index=tracker})
69 return handler
70 end
71
72 local Header_OnAnimationStart = function (self, forced)
73 local header = self:GetParent()
74 header.animating = true
75 plugin:UpdateAnimation(header)
76 end
77
78 local Header_OnAnimationFinished = function (self, forced)
79 local header = self:GetParent()
80 header.animating = nil
81 plugin:Update(X_ANIMATION)
82 end
83
84 -- reset generic flags for layout compilation
85 function tracker:InitLayout (isStatic)
86 print('|cFF00FFFFlayout|r', self.headerText)
87 self.firstBlock = nil
88 self.lastBlock = nil
89 self.currentBlock = nil
90 self.oldContentHeight = self.contentHeight
91 self.oldAnimationHeight = self.animationHeight
92 self.numBlocks = 0
93 for id, block in pairs(self.usedBlocks) do
94 block.used = nil
95 end
96 if not isStatic then
97 self.hasSkippedBlocks = false
98 end
99
100 if not self.header then
101 self:SetHeader(self.headerText, X_REASON)
102 self.header:SetPoint('TOPLEFT', plugin, 'TOPLEFT', 0, -plugin.contentHeight)
103 plugin.contentHeight = plugin.contentHeight + self.header:GetHeight()
104 end
105
106
107 self.contentHeight = 0
108
109 end
110
111 -- clear out generic flags and set aside block frames for re-use
112 tracker.EndLayout = function(self)
113 self.lastBlock = self.currentBlock
114 for id, block in pairs(self.usedBlocks) do
115 if not block.used then
116 self:FreeBlock(block)
117 end
118 end
119 end
120
121 function tracker:SetHeader (text, animateReason)
122 if self.header then
123 return self.header
124 end
125
126 local block = CreateFrame('Button', nil, plugin, 'VeneerObjectiveHeader')
127 block.handler = self
128 block.text:SetText(self.headerText)
129
130 self.currentBlock = block
131 self.header = block
132 return block
133 end
134
135 function tracker:FreeBlock(block)
136 self.usedBlocks[block.id] = nil
137 print('|cFF0088FFfree|r', block:GetName())
138 tinsert(self.freeBlocks, block)
139
140 block.numLines = 0
141 block:SetHeight(0)
142 block:Hide()
143 end
144
145 -- should only be used in an N-lastN loop
146 function tracker:FreeLine(line)
147 if line.block then
148 line.block.lines[line.index] = nil
149 end
150 print('|cFF0088FFfree|r', line:GetName())
151 local freeLines = line.type or self.freeLines
152 tinsert(freeLines, line)
153 end
154
155 local blocksn = 0
156 tracker.GetBlock = function(self, id)
157 local block = self.usedBlocks[id]
158 if not block then
159 local numFree = #self.freeBlocks
160 if numFree >= 1 then
161 block = tremove(self.freeBlocks, numFree)
162 else
163 blocksn = blocksn + 1
164 block = CreateFrame('Button', 'OTVNBlock'..blocksn, plugin, 'VeneerObjectiveBlock')
165 block.lines = {}
166 end
167 self.usedBlocks[id] = block
168 block.id = id
169 block.handler = self
170 end
171
172 block.used = true
173 block.currentLine = nil
174 block.numLines = 0
175
176 if block.lines then
177 for i, line in ipairs(block.lines) do
178 line.used = nil
179 end
180 end
181
182 block.contentHeight = blockSpacing
183 block:SetWidth(trackerWidth)
184 block:SetHeight(0)
185
186 return block
187 end
188
189 -- obtain line
190 local linesn = 0
191 function tracker:GetLine(block, index, lineType)
192 local line = block.lines[index]
193 if line and line.lineType ~= lineType then
194
195 tinsert(self.freeLines, line)
196 line = nil
197 end
198
199 if not line then
200 local freeLines = (lineType and lineType.freeLines) or self.freeLines
201 local numFreeLines = #freeLines
202 if numFreeLines >= 1 then
203 line = tremove(freeLines, numFreeLines)
204 else
205 linesn = linesn + 1
206 line = CreateFrame('Frame', 'OTVNLine'.. linesn, block, (lineType and lineType.template) or 'VeneerObjectiveLine')
207 end
208 line:SetParent(block)
209 end
210
211 line.type = lineType
212 line.index = index
213 line.used = true
214 line.block = block
215 line.text:SetPoint('TOPLEFT', line, 'TOPLEFT', blockIndent, 0)
216 line:SetHeight(0) -- in order for GetStringHeight to be useful
217
218 block.lines[index] = line
219
220 return line
221 end
222
223 function tracker:AddProgressBar(block, line, questID)
224 end
225
226 function tracker:FreeProgressBar(block, line)
227 end
228
229 function tracker:AddTimerBar(block, line, duration, startTime)
230 end
231
232 function tracker:FreeTimerBar(block, line)
233 end
234
235 -- Checks for space and anchors or frees the block accordingly
236 function tracker:AddBlock (block, force)
237 local anchor = self.currentBlock or self.header
238 self.numBlocks = self.numBlocks + 1
239
240 if block.header then
241 print('header!', floor(block.contentHeight), '+', floor(block.header:GetStringHeight()))
242 block.contentHeight = block.contentHeight + block.header:GetStringHeight()
243 self.used = true
244 end
245
246
247 if self.currentBlock then
248 self.currentBlock.nextBlock = block
249 block.prevBlock = self.currentBlock
250 else
251 self.firstBlock = block
252 end
253
254 self.contentHeight = self.contentHeight + block.contentHeight
255 self.currentBlock = block
256
257 if not plugin.currentBlock then
258 plugin.firstBlock = block
259 end
260 plugin.currentBlock = block
261
262
263
264 block:SetHeight(block.contentHeight)
265 print('block|cFF88FF00', self.numBlocks, block, '|rto', anchor, 'size', block.contentHeight)
266 block:ClearAllPoints()
267 block:SetPoint('TOPLEFT', anchor, 'BOTTOMLEFT', 0, -blockSpacing)
268 block:Show()
269
270 -- free unused lines
271 local numLines = #block.lines
272 for i = 1, numLines do
273 local line = block.lines[i]
274 if not line.used or block.collapsed then
275 print('|cFFFF4400!|r')
276 self:FreeLine(line)
277 else
278 if not line:IsShown() then
279 line:Show()
280 end
281 end
282 end
283
284 return true
285 end
286
287 function tracker:SetLine(block, index, lineType, textOrFunc)
288 local anchor = block.currentLine or block.header
289 local line = self:GetLine(block, index, lineType)
290
291 if line.ticker then
292 line.ticker:Cancel()
293 line.ticker = nil
294 end
295
296 local text = textOrFunc
297 if type(textOrFunc) == 'function' then
298 text = textOrFunc()
299
300 line.ticker = C_Timer.NewTicker(10, function()
301 line.height = tracker:SetLineText(line.text, textOrTextFunc())
302 line:SetHeight(line.height)
303 end)
304 end
305 line.height = tracker:SetLineText(line.text, text)
306 line:SetHeight(line.height)
307
308 print('line|cFFFFFF00', line:GetName(), '|rto', anchor:GetName(), 'size', line.height)
309 line:SetPoint('TOPLEFT', anchor, 'BOTTOMLEFT', 0, 0)
310
311 block.contentHeight = block.contentHeight + line.height
312 block.numLines = block.numLines + 1
313
314 if block.currentLine then
315 line.prevLine = block.currentLine
316 block.currentLine.nextLine = line
317 else
318 block.firstLine = line
319 end
320
321 block.currentLine = line
322 plugin.currentLine = line
323
324 end
325
326 function tracker:SetLineText(fontString, text)
327 fontString:SetText(text)
328 return fontString:GetStringHeight()
329 end
330
331 -- Update lite
332 function tracker:ResetAnchors ()
333 self:InitLayout()
334
335 self:EndLayout()
336 end
337
338
339 local UpdateQuestTracker = function(watchIndex, logIndex)
340 return true
341 end
342
343 -- top-down updaters
344
345 local questTracker = GetTrackerHandler({
346 headerText = 'Quests',
347 updateReasonModule = X_MODULE_QUEST,
348 updateReasonEvents = (X_QUEST + X_QUEST_ADDED),
349 })
350 function questTracker:Update ()
351 self:InitLayout()
352 for watchIndex = 1, GetNumQuestWatches() do
353 local questID, title, questLogIndex, numObjectives, requiredMoney, isComplete, startEvent, isAutoComplete, failureTime, timeElapsed, questType, isTask, isBounty, isStory, isOnMap, hasLocalPOI = GetQuestWatchInfo(watchIndex)
354 if not questID then
355 -- stop parsing; end of data or variables haven't completely loaded
356 break
357 end
358 local showQuest = true
359 if isTask or (isBounty and not IsQuestComplete(questID)) then
360 -- do nothing
361 else
362 -- obtain a block
363 local block = self:GetBlock(questID)
364
365 block.header:SetText(title)
366
367 for i = 1, numObjectives do
368 local text, objectiveType, finished = GetQuestLogLeaderBoard(i, questLogIndex)
369 if text then
370 self:SetLine(block, i, nil, text)
371 end
372 end
373
374 block:SetScript('OnClick', self.OnClick)
375 block:RegisterForClicks('AnyDown')
376
377 self:AddBlock(block)
378 end
379 end
380
381 self:EndLayout()
382 end
383 questTracker.OnClick = function(block, button)
384 if button == 'RightButton' then
385 ObjectiveTracker_ToggleDropDown(block, QuestObjectiveTracker_OnOpenDropDown)
386 else
387 CloseDropDownMenus()
388
389 local questLogIndex = GetQuestLogIndexByID(block.id)
390 if ( IsModifiedClick("QUESTWATCHTOGGLE") ) then
391 QuestObjectiveTracker_UntrackQuest(nil, block.id);
392 else
393 if ( IsQuestComplete(block.id) and GetQuestLogIsAutoComplete(questLogIndex) ) then
394 AutoQuestPopupTracker_RemovePopUp(block.id);
395 ShowQuestComplete(questLogIndex);
396 else
397 QuestLogPopupDetailFrame_Show(questLogIndex);
398 end
399 end
400 end
401 end
402
403 local UpdateAchievementTracker = function() end
404 local UpdateTaskTracker = function() end
405 local UpdateScenarioTracker = function() end
406
407 function plugin:Update(reason, id)
408
409 print('update', reason, #plugin.trackers)
410
411 if plugin.minimized then
412 for i, tracker in ipairs(plugin.trackers) do
413 tracker:Hide()
414 end
415 return
416 end
417
418
419 local X_REASON = reason or X_ALL
420 local X_ID = id
421
422 plugin.maxHeight = plugin:GetHeight()
423 plugin.oldContentsHeight = plugin.contentHeight
424 plugin.contentHeight = 0
425 plugin.currentBlock = nil
426 plugin.firstBlock = nil
427 plugin:SetWidth(trackerWidth)
428
429 -- pad for header
430 plugin.contentHeight = plugin.header:GetHeight()
431
432 for i, header in ipairs(plugin.trackers) do
433 header.used = nil
434 end
435
436
437 local addedSpace = false
438 for i, tracker in ipairs(plugin.trackers) do
439 if ( band(X_REASON, tracker.updateReasonModule + tracker.updateReasonEvents ) > 0 ) then
440 print('->', tracker.headerText)
441 tracker:Update()
442 if tracker.oldContentHeight - tracker.contentHeight >= 1 then
443 addedSpace = true
444 end
445 else
446 -- if we can fit another header or an animation handler popped, contents need to be generated
447 if addedSpace or (tracker.header and tracker.header.animating) then
448 print('->', tracker.headerText, 'added space')
449 tracker:Update()
450 else
451 print('->', tracker.headerText, 'lite update')
452 -- otherwise, measure contents and hide anything that won't fit
453 tracker:ResetAnchors()
454 end
455 end
456 end
457
458 for i, tracker in ipairs(plugin.trackers) do
459 if tracker.currentBlock then
460 if not tracker.header:IsShown() then
461 tracker.header:Show()
462 end
463 else
464 if tracker.header:IsShown() then
465 tracker.header:Hide()
466 end
467 end
468 end
469
470 if VeneerBuffFrame and VeneerBuffFrame.lastBuff then
471 plugin:ClearAllPoints()
472 plugin:SetPoint('TOP', VeneerBuffFrame.lastBuff, 'BOTTOM', 0, -4)
473 plugin:SetPoint('RIGHT', UIParent, 'RIGHT', -6, 0)
474 else
475 plugin:ClearAllPoints()
476 plugin:SetPoint('TOPRIGHT', UIParent, 'TOPRIGHT', -6, -120)
477 end
478
479 plugin:Show()
480 end
481
482 plugin.init = function()
483
484 plugin:RegisterEvent("QUEST_LOG_UPDATE")
485 plugin:RegisterEvent("TRACKED_ACHIEVEMENT_LIST_CHANGED")
486 plugin:RegisterEvent("QUEST_WATCH_LIST_CHANGED")
487 plugin:RegisterEvent("QUEST_AUTOCOMPLETE")
488 plugin:RegisterEvent("QUEST_ACCEPTED")
489 plugin:RegisterEvent("SUPER_TRACKED_QUEST_CHANGED")
490 plugin:RegisterEvent("SCENARIO_UPDATE")
491 plugin:RegisterEvent("SCENARIO_CRITERIA_UPDATE")
492 plugin:RegisterEvent("SCENARIO_SPELL_UPDATE")
493 plugin:RegisterEvent("TRACKED_ACHIEVEMENT_UPDATE")
494 plugin:RegisterEvent("ZONE_CHANGED_NEW_AREA");
495 plugin:RegisterEvent("ZONE_CHANGED");
496 plugin:RegisterEvent("QUEST_POI_UPDATE");
497 plugin:RegisterEvent("VARIABLES_LOADED");
498 plugin:RegisterEvent("QUEST_TURNED_IN");
499 plugin:RegisterEvent("PLAYER_MONEY");
500
501 plugin.trackers = {
502 questTracker,
503 }
504 print('bub')
505 end
506 function plugin:event(event, ...)
507 print('|cFFFF0088' .. event, ...)
508 if event == 'QUEST_WATCH_LIST_CHANGED' then
509 local questID, added = ...
510 if added then
511 if not IsQuestBounty(questID) or IsQuestComplete(questId) then
512 print(questID, added)
513 plugin:Update(X_QUEST_ADDED, questID)
514 end
515 else
516 print()
517 plugin:Update(X_QUEST)
518 end
519 elseif event == 'QUEST_LOG_UPDATE' then
520 plugin:Update(X_MODULE_QUEST)
521 elseif event == 'QUEST_POI_UPDATE' then
522
523 if GetCVar("trackQuestSorting") == "proximity" then
524 -- todo: sort blocks
525 end
526 plugin:Update(X_MODULE_QUEST)
527 elseif event == 'PLAYER_MONEY' then
528 plugin:Update(X_MONEY)
529 end
530
531 end
532
533 -- adjusts money events bitcode when a tracker is displaying money data
534 function plugin:UpdateMoneyFlag(watchMoney, reason)
535 if watchMoney then
536 if (band(X_MONEY, reason) == 0) then
537 X_MONEY = X_MONEY - reason
538 end
539 else
540 if (band(X_MONEY, reason) > 0) then
541 X_MONEY = X_MONEY + reason
542 end
543 end
544 end
545
546 -- used by framescripts to poke the updater when an animation has ended
547 function plugin:UpdateAnimation(block)
548
549 local reason = block.handler.updateReasonEvents
550 if block.animating then
551 if (band(X_ANIMATION, reason) == 0) then
552 X_ANIMATION = X_ANIMATION - reason
553 end
554 else
555 if (band(X_ANIMATION, reason) > 0) then
556 X_ANIMATION = X_ANIMATION + reason
557 end
558 end
559 end