Nenue@28: local B = select(2,...).frame Nenue@28: local wipe, pairs, ipairs, min, max, unpack = table.wipe, pairs, ipairs, min, max, unpack Nenue@28: local tinsert, tostring, format, mod = tinsert, tostring, format, mod Nenue@28: local GetQuestTagInfo, GetQuestLogTitle = GetQuestTagInfo, GetQuestLogTitle Nenue@28: local GetNumQuestLogEntries, GetNumQuestWatches, GetQuestLogCompletionText, IsQuestWatched, IsQuestHardWatched, GetQuestLogSpecialItemInfo, GetQuestLogSpecialItemCooldown = GetNumQuestLogEntries, GetNumQuestWatches, GetQuestLogCompletionText, IsQuestWatched, IsQuestHardWatched, GetQuestLogSpecialItemInfo, GetQuestLogSpecialItemCooldown Nenue@28: local GetNumAutoQuestPopUps, GetAutoQuestPopUp, GetTasksTable, GetNumQuestLogTasks, GetTaskInfo, GetQuestObjectiveInfo = GetNumAutoQuestPopUps, GetAutoQuestPopUp, GetTasksTable, GetNumQuestLogTasks, GetTaskInfo, GetQuestObjectiveInfo Nenue@28: local GetNumQuestLogRewardCurrencies, GetQuestLogRewardCurrencyInfo, GetNumQuestLogRewards, GetQuestLogRewardInfo, GetQuestLogRewardMoney, GetMoneyString = GetNumQuestLogRewardCurrencies, GetQuestLogRewardCurrencyInfo, GetNumQuestLogRewards, GetQuestLogRewardInfo, GetQuestLogRewardMoney, GetMoneyString Nenue@28: local GetNumQuestLeaderBoards, GetAchievementNumCriteria, GetQuestLogLeaderBoard, GetAchievementCriteriaInfo = GetNumQuestLeaderBoards, GetAchievementNumCriteria, GetQuestLogLeaderBoard, GetAchievementCriteriaInfo Nenue@28: local GetQuestWatchIndex, GetQuestLogIndexByID, GetSuperTrackedQuestID, SetSuperTrackedQuestID, GetQuestWatchInfo = GetQuestWatchIndex, GetQuestLogIndexByID, GetSuperTrackedQuestID, SetSuperTrackedQuestID, GetQuestWatchInfo Nenue@28: local QuestHasPOIInfo, GetDistanceSqToQuest, GetQuestFactionGroup = QuestHasPOIInfo, GetDistanceSqToQuest, GetQuestFactionGroup Nenue@28: local GetTrackedAchievements, GetNumTrackedAchievements, GetAchievementInfo = GetTrackedAchievements, GetNumTrackedAchievements, GetAchievementInfo Nenue@28: local GetMoney, floor = GetMoney, floor Nenue@28: local T = B:RegisterModule("ObjectiveTracker", _G.VeneerObjectiveWrapper, 'BuffFrame') Nenue@28: local print = B.print('Info') Nenue@28: local QUEST_TAG_DUNGEON = QUEST_TAG_DUNGEON Nenue@28: local QUEST_TAG_GROUP = QUEST_TAG_GROUP Nenue@28: local QUEST_TAG_ACCOUNT = QUEST_TAG_ACCOUNT Nenue@28: local QUEST_TAG_TCOORDS = QUEST_TAG_TCOORDS Nenue@28: local LE_QUEST_FREQUENCY_DAILY = LE_QUEST_FREQUENCY_DAILY Nenue@28: local LE_QUEST_FREQUENCY_WEEKLY = LE_QUEST_FREQUENCY_WEEKLY Nenue@28: local FACTION_ALLIANCE, LE_QUEST_FACTION_HORDE, FACTION_HORDE, LE_QUEST_FACTION_HORDE = FACTION_ALLIANCE, LE_QUEST_FACTION_HORDE, FACTION_HORDE, LE_QUEST_FACTION_HORDE Nenue@28: Nenue@28: local Tracker, Bonus, AutoQuest, Quest, Cheevs = T.DefaultTracker, T.Bonus, T.AutoQuest, T.Quest, T.Cheevs Nenue@28: -------------------------------------------------------------------- Nenue@28: --- Tracker-specific data retrieval functions Nenue@28: -------------------------------------------------------------------- Nenue@28: Nenue@28: Nenue@28: local DoQuestRewards= function(t, questID) Nenue@28: local rewards = {} Nenue@28: t.numCurrencies = GetNumQuestLogRewardCurrencies(questID) Nenue@28: for i = 1, t.numCurrencies do Nenue@28: local name, texture, count = GetQuestLogRewardCurrencyInfo(i, questID) Nenue@28: tinsert(rewards,{ Nenue@28: type = 'currency', Nenue@28: index = i, Nenue@28: name = name, Nenue@28: texture = texture, Nenue@28: count = count Nenue@28: }); Nenue@28: end Nenue@28: -- items Nenue@28: t.numItems = GetNumQuestLogRewards(questID) Nenue@28: for i = 1, t.numItems do Nenue@28: local name, texture, count, quality, isUsable = GetQuestLogRewardInfo(i, questID) Nenue@28: tinsert(rewards, { Nenue@28: type = 'item', Nenue@28: index = i , Nenue@28: name = name, Nenue@28: texture = texture, Nenue@28: count = count, Nenue@28: quality = quality, Nenue@28: isUsable = isUsable Nenue@28: }); Nenue@28: end Nenue@28: -- money Nenue@28: Nenue@28: local money = GetQuestLogRewardMoney(questID) Nenue@28: if ( money > 0 ) then Nenue@28: tinsert(rewards, { Nenue@28: type = 'money', Nenue@28: name = GetMoneyString(money), Nenue@28: texture = "Interface\\Icons\\inv_misc_coin_01", Nenue@28: count = 0, Nenue@28: }); Nenue@28: end Nenue@28: Nenue@28: if #rewards >= 1 then Nenue@28: t.rewardInfo = rewards Nenue@28: end Nenue@28: end Nenue@28: Nenue@28: Nenue@28: ----------------------------- Nenue@28: --- AUTO_QUEST Nenue@28: AutoQuest.LogInfo = {} Nenue@28: AutoQuest.LogBlock = {} Nenue@28: AutoQuest.QuestBlock = {} Nenue@28: AutoQuest.WatchBlock = {} Nenue@28: function AutoQuest:GetNumWatched () Nenue@28: print(self.name, self) Nenue@28: Quest:GetNumWatched() Nenue@28: self.numWatched = GetNumAutoQuestPopUps() Nenue@28: Nenue@28: return self.numWatched Nenue@28: end Nenue@28: AutoQuest.GetInfo = function(self, popupIndex) Nenue@28: Nenue@28: Nenue@28: local questID, type = GetAutoQuestPopUp(popupIndex) Nenue@28: local questLogIndex = GetQuestLogIndexByID(questID) Nenue@28: local title, level, suggestedGroup, isHeader, isCollapsed, isComplete, frequency, questID, startEvent, displayQuestID, isOnMap, hasLocalPOI, isTask, isStory = GetQuestLogTitle(questLogIndex) Nenue@28: Nenue@28: self.Info[questID] = self.Info[questID] or {} Nenue@28: local popup = self.Info[questID] Nenue@28: popup.title = title Nenue@28: popup.description = type Nenue@28: popup.popupType = type Nenue@28: popup.questID = questID Nenue@28: popup.questLogIndex = questLogIndex Nenue@28: popup.popupIndex = popupIndex Nenue@28: Nenue@28: self.Info[questID] = popup Nenue@28: self.WatchInfo[popupIndex] = popup Nenue@28: Nenue@28: Nenue@28: return self.Info[questID] Nenue@28: end Nenue@28: Nenue@28: ----------------------------- Nenue@28: --- BONUS OBJECTIVE Nenue@28: -- The default UI pops them up as you enter their relevant areas, but the data is actually available at all times. Nenue@28: -- The only requirement is that you've been to said area and progressed any of the objectives. Nenue@28: -- Blizzard deal with this fact by caching any task data collected during session and masking out whatever gets completed. Nenue@28: -- For the addon's module structure to work, GetNumWatched method also invokes a tasks table scan. Nenue@28: -- That composes the table searched by GetInfo(). Nenue@28: Nenue@28: ------------------------------------------------------------------------------------------ Nenue@28: --- These functions are copied from Blizzard_BonusObjectiveTracker.lua; Nenue@28: -- It's kind of dumb, but this avoids the risk of code taint. Nenue@28: Nenue@28: --- Returns a tasks table modified to include recently completed objectives Nenue@28: local UnitName, GetRealmName = UnitName, GetRealmName Nenue@28: local InternalGetTasksTable = function() Nenue@28: local savedTasks = T.Conf.TasksLog Nenue@28: local char = UnitName("player") Nenue@28: local realm = GetRealmName() Nenue@28: local tasks = GetTasksTable() Nenue@28: Nenue@28: for questID, data in pairs(Bonus.Info) do Nenue@28: Nenue@28: print(' -- questID:', questID, #data.objectives) Nenue@28: for i, o in ipairs(data.objectives) do Nenue@28: print(' --', i, o.text) Nenue@28: end Nenue@28: Nenue@28: end Nenue@28: Nenue@28: Nenue@28: for questID, data in pairs(savedTasks) do Nenue@28: if questID > 0 then Nenue@28: local found = false Nenue@28: for i = 1, #tasks do Nenue@28: if tasks[i] == questID then Nenue@28: found = true Nenue@28: break Nenue@28: end Nenue@28: end Nenue@28: -- if it's not part of the current table, then try to insert it where it was last found Nenue@28: if not found then Nenue@28: if data.watchIndex < #tasks then Nenue@28: tinsert(tasks, data.watchIndex, data) Nenue@28: else Nenue@28: tinsert(tasks, data) Nenue@28: end Nenue@28: end Nenue@28: end Nenue@28: end Nenue@28: return tasks Nenue@28: end Nenue@28: Nenue@28: --- Returns an entry from the composed tasks table if possible, otherwise makes an API pull Nenue@28: local InternalGetTaskInfo = function(questID) Nenue@28: local completedTasks = T.Conf.TasksLog Nenue@28: if completedTasks[questID] then Nenue@28: return true, true, #completedTasks[questID].objectives Nenue@28: else Nenue@28: return GetTaskInfo(questID) Nenue@28: end Nenue@28: end Nenue@28: Nenue@28: --- Same as above but for the objective entries Nenue@28: local InternalGetQuestObjectiveInfo = function(questID, objectiveIndex) Nenue@28: local completedTasks = T.Conf.TasksLog Nenue@28: if ( completedTasks[questID] ) then Nenue@28: print('using internal data') Nenue@28: return completedTasks[questID].objectives[objectiveIndex], completedTasks[questID].objectiveType, true; Nenue@28: else Nenue@28: return GetQuestObjectiveInfo(questID, objectiveIndex, false); Nenue@28: end Nenue@28: end Nenue@28: Nenue@28: --- end redundant copy of silliness Nenue@28: ------------------------------------------------------------------------------------------ Nenue@28: Nenue@28: Bonus.Completed = {} Nenue@28: Bonus.POI = {} Nenue@28: Bonus.Scenario = {} Nenue@28: Bonus.QuestBlock = {} Nenue@28: Bonus.WatchInfo = {} Nenue@28: function Bonus:GetNumWatched () Nenue@28: print(self.name, self) Nenue@28: Nenue@28: local tasks = InternalGetTasksTable() Nenue@28: local numWatched = 0 Nenue@28: local numAll = 0 Nenue@28: self.WatchInfo = {} Nenue@28: print('|cFFFFFF00Bonus.GetNumWatched()|r', #tasks) Nenue@28: print(' TasksTable pull:') Nenue@28: for i, questID in ipairs(tasks) do Nenue@28: local isInArea, isOnMap, numObjectives = InternalGetTaskInfo(questID) Nenue@28: local existingTask = self.QuestBlock[questID] Nenue@28: local displayObjectiveHeader = false; Nenue@28: local test = (isInArea or (isOnMap and existingTask)) Nenue@28: --local test = true Nenue@28: if test then Nenue@28: self.Info[questID] = self.Info[questID] or {} Nenue@28: Nenue@28: local t = self.Info[questID] Nenue@28: self.WatchInfo[i] = t Nenue@28: t.isInArea = isInArea Nenue@28: t.isOnMap = isOnMap Nenue@28: t.existingTask = existingTask Nenue@28: t.questID = questID Nenue@28: t.objectives = {} Nenue@28: t.taskIndex = i Nenue@28: Nenue@28: Nenue@28: DoQuestRewards(t, questID) Nenue@28: Nenue@28: local taskTitle Nenue@28: local taskFinished = true; Nenue@28: for objectiveIndex = 1, numObjectives do Nenue@28: local text, objectiveType, finished, displayAsObjective = InternalGetQuestObjectiveInfo(questID, objectiveIndex, false); Nenue@28: displayObjectiveHeader = displayObjectiveHeader or displayAsObjective; Nenue@28: if not taskTitle then Nenue@28: if objectiveType == 'progressbar' and not text:match('^%d%+\\%d+') then Nenue@28: taskTitle = text Nenue@28: text = '' Nenue@28: end Nenue@28: end Nenue@28: Nenue@28: Nenue@28: print(' --', text, objectiveType, finished, displayAsObjective) Nenue@28: t.objectives[objectiveIndex] = t.objectives[objectiveIndex] or {} Nenue@28: local o = t.objectives[objectiveIndex] Nenue@28: Nenue@28: o.objectiveIndex = objectiveIndex Nenue@28: o.text = text Nenue@28: o.objectiveType = objectiveType Nenue@28: o.finished = finished Nenue@28: o.displayAsObjective = displayAsObjective Nenue@28: print(' |cFF00FF88*', objectiveIndex, text) Nenue@28: end Nenue@28: Nenue@28: -- didn't get a name from progress bar? what about area name Nenue@28: if not taskTitle then Nenue@28: if isInArea then Nenue@28: taskTitle = GetMapNameByID(GetCurrentMapAreaID()) Nenue@28: end Nenue@28: end Nenue@28: t.title = taskTitle Nenue@28: end Nenue@28: Nenue@28: print (' |cFF00FF88#', i, 'questID', questID, 'inArea', isInArea, 'onMap', isOnMap, 'existing', (existingTask and 'Y' or 'N'), (test and '|cFF00FF00show|r' or '|cFFFF0088hide|r')) Nenue@28: end Nenue@28: Nenue@28: Nenue@28: self.numAll = #tasks Nenue@28: self.numWatched = #self.WatchInfo Nenue@28: print(' stats:', self.numAll, 'active tasks,', self.numWatched, 'nearby or animating') Nenue@28: --return #tasks Nenue@28: return #self.WatchInfo Nenue@28: end Nenue@28: Nenue@28: --- info cleanup done when turn-ins are detected Nenue@28: Bonus.OnTurnIn = function(self, questID, xp, money) Nenue@28: Nenue@28: if #self.info.rewardInfo >= 1 then Nenue@28: for i, reward in ipairs(self.info.rewardInfo) do Nenue@28: --[[ Nenue@28: type = 'item', Nenue@28: index = i , Nenue@28: name = name, Nenue@28: texture = texture, Nenue@28: count = count, Nenue@28: quality = quality, Nenue@28: isUsable = isUsable Nenue@28: ]] Nenue@28: print(' reward ', i, ' ', reward.type, reward.name, reward.count) Nenue@28: Nenue@28: end Nenue@28: end Nenue@28: Nenue@28: print('|cFFFF8800'..self.name..':OnTurnIn call', questID, xp, money) Nenue@28: local savedTasks = B.Conf.TasksLog Nenue@28: Nenue@28: self.Info[questID].completedTime = GetTime() Nenue@28: self.Info[questID].animate = true Nenue@28: T.SetAnimate(self.watchReasonModule) Nenue@28: savedTasks[questID] = self.Info[questID] Nenue@28: end Nenue@28: Nenue@28: Bonus.GetInfo = function(self, taskIndex) Nenue@28: print(self.name, self) Nenue@28: return self.WatchInfo[taskIndex] Nenue@28: end Nenue@28: Nenue@28: Nenue@28: Nenue@28: Cheevs.GetNumWatched = function(self) Nenue@28: print('|cFF00FF00' .. GetTime()) Nenue@28: Cheevs.trackedCheevs = {GetTrackedAchievements()} Nenue@28: return GetNumTrackedAchievements() Nenue@28: end Nenue@28: Cheevs.GetInfo = function(self, index) Nenue@28: local cheevID = Cheevs.trackedCheevs[index] Nenue@28: local id, name, points, completed, month, day, year, description, flags, icon, rewardText, isGuildAch, wasEarnedByMe, earnedBy = GetAchievementInfo(cheevID) Nenue@28: Nenue@28: self.Info[cheevID] = {} Nenue@28: local c = self.Info[cheevID] Nenue@28: c.type = 'Cheevs' Nenue@28: c.watchIndex = index Nenue@28: c.cheevID = cheevID Nenue@28: c.title = name Nenue@28: c.points, c.completed, c.month, c.day, c.year, c.description, c.flags, c.icon, c.rewardText, c.isGuildAch, c.wasEarnedByMe, c.earnedBy = Nenue@28: points, completed, month, day, year, description, flags, icon, rewardText, isGuildAch, wasEarnedByMe, earnedBy Nenue@28: c.numObjectives = GetAchievementNumCriteria(cheevID) Nenue@28: c.objectives = {} Nenue@28: for i = 1, c.numObjectives do Nenue@28: local description, type, completed, quantity, requiredQuantity, characterName, flags, assetID, quantityString, criteriaID = GetAchievementCriteriaInfo(cheevID, i) Nenue@28: c.objectives[i] = { Nenue@28: objectiveIndex = i, Nenue@28: cheevID = cheevID, Nenue@28: text = description, Nenue@28: type = type, Nenue@28: finished = completed, Nenue@28: value = quantity, Nenue@28: maxValue = requiredQuantity, Nenue@28: characterName = characterName, Nenue@28: flags = flags, Nenue@28: assetID = assetID, Nenue@28: quantityString = quantityString, Nenue@28: criteriaID = criteriaID, Nenue@28: } Nenue@28: end Nenue@28: print('Cheevs.|cFF0088FFGetInfo|r('..index..')', 'obj:', GetAchievementNumCriteria(cheevID), name, description) Nenue@28: Nenue@28: self.WatchInfo[index] = c Nenue@28: return self.Info[cheevID] Nenue@28: end