Mercurial > wow > buffalo2
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 |
