Nenue@28: local B = select(2,...).frame Nenue@28: local T = B:RegisterModule("ObjectiveTracker", _G.VeneerObjectiveWrapper, 'BuffFrame') Nenue@28: local _G, ipairs, max, min, unpack, floor, pairs, tostring, type, band = _G, ipairs, max, min, unpack, floor, pairs, tostring, type, bit.band Nenue@30: local GetQuestWatchInfo, GetQuestLogCompletionText = GetQuestWatchInfo, GetQuestLogCompletionText Nenue@30: local GetQuestLogLeaderBoard, GetNumQuestLogEntries, GetQuestLogTitle = GetQuestLogLeaderBoard, GetNumQuestLogEntries, GetQuestLogTitle Nenue@30: local GetQuestLogSpecialItemInfo, GetQuestLogSpecialItemCooldown = GetQuestLogSpecialItemInfo, GetQuestLogSpecialItemCooldown Nenue@30: local GetSuperTrackedQuestID, GetMoney, C_Scenario, GetCVarBool, GetNumQuestWatches = GetSuperTrackedQuestID, GetMoney, C_Scenario, GetCVarBool, GetNumQuestWatches Nenue@30: local GetQuestTagInfo, GetMoneyString, GetDistanceSqToQuest, GetQuestFactionGroup = GetQuestTagInfo, GetMoneyString, GetDistanceSqToQuest, GetQuestFactionGroup Nenue@30: local QUEST_TAG_ACCOUNT, LE_QUEST_FACTION_HORDE, LE_QUEST_FREQUENCY_DAILY, LE_QUEST_FREQUENCY_WEEKLY = QUEST_TAG_ACCOUNT, LE_QUEST_FACTION_HORDE, LE_QUEST_FREQUENCY_DAILY, LE_QUEST_FREQUENCY_WEEKLY Nenue@30: local QUEST_TAG_TCOORDS, IsQuestSequenced = QUEST_TAG_TCOORDS, IsQuestSequenced Nenue@28: local Default, Quest = T.DefaultHandler, T.Quest Nenue@28: local format = format Nenue@28: local print = B.print('Tracker') Nenue@28: local lprint = B.print('Line') Nenue@28: local iprint = B.print('Info') Nenue@29: local colors = T.colors Nenue@29: local tprint = B.print('Tracker') Nenue@28: Nenue@30: local superTrackQuestID, playerMoney, inScenario, showPOIs Nenue@28: Quest.Update = function(self, reason, ...) Nenue@28: local print = tprint Nenue@28: print('QuestTracker:Update() received') Nenue@28: T.UpdateActionButtons() Nenue@28: Default.Update(self, reason, ...) Nenue@28: end Nenue@28: Nenue@28: T.Quest.numButtons = 0 Nenue@28: local usedButtons = T.Quest.itemButtons Nenue@28: local freeButtons = T.Quest.freeButtons Nenue@28: Nenue@28: Quest.UpdateObjectives = function(handler, block) Nenue@28: local print = lprint Nenue@28: print('|cFF00FFFFUpdateObjectives()') Nenue@28: local info = block.info Nenue@28: Nenue@28: local titlebg, textbg = colors.default.titlebg, colors.default.textbg Nenue@28: print((info.isAccount and 'isAccount' or ''), (info.isFaction and 'isFaction' or ''), (info.isDaily and 'isDaily' or ''), (info.isWeekly and 'isWeekly' or ''), info.tagID, info.tagName) Nenue@28: Nenue@28: if info.isAccount then Nenue@28: if info.isFaction then Nenue@28: print(' faction', info.tagID) Nenue@28: titlebg, textbg = colors['faction_'..info.tagID].titlebg, colors.default.textbg Nenue@28: else Nenue@28: print(' account', info.isAccount, info.isFaction) Nenue@28: titlebg, textbg = colors.account.titlebg, colors.account.textbg Nenue@28: end Nenue@28: elseif info.isDaily then Nenue@28: print(' daily', info.frequency) Nenue@28: titlebg, textbg = colors.daily.titlebg, colors.daily.textbg Nenue@28: elseif info.isWeekly then Nenue@28: print(' weekly', info.frequency) Nenue@28: titlebg, textbg = colors.weekly.titlebg, colors.weekly.textbg Nenue@28: end Nenue@28: Nenue@28: block.titlebg:SetGradientAlpha(unpack(titlebg)) Nenue@28: block.statusbg:SetGradientAlpha(unpack(textbg)) Nenue@28: Nenue@28: local completionText Nenue@28: if info.isComplete then Nenue@28: if info.isAutoComplete then Nenue@28: local questID, popupType = GetAutoQuestPopUp(info.questLogIndex) Nenue@28: if popupType == 'COMPLETE' then Nenue@28: print(' :: auto-complete quest :: set the message') Nenue@28: info.completionText = T.strings.CLICK_TO_COMPLETE Nenue@28: end Nenue@28: else Nenue@28: if not completionText or info.completionText then Nenue@28: info.completionText = GetQuestLogCompletionText(info.questLogIndex) Nenue@28: end Nenue@28: end Nenue@28: print(' :: complete quest :: show instruction: "'.. tostring(info.completionText) .. '"') Nenue@28: end Nenue@28: Nenue@28: Default.UpdateObjectives(handler, block) Nenue@28: end Nenue@28: Nenue@28: Quest.UpdateLine = function(handler, block, line, data) Nenue@28: local print = lprint Nenue@28: local objectiveType = data.type Nenue@28: local r, g, b, a = 0, 1, 1, 1 Nenue@28: Nenue@28: line.progress = 0 Nenue@28: if data.finished then Nenue@28: line.progress = 2 Nenue@28: r, g, b, a = 0, 1, 0, 1 Nenue@28: elseif objectiveType == 'monster' then Nenue@28: r, g, b, a = 1, .55, .2, 1 Nenue@28: elseif objectiveType == 'item' then Nenue@28: r, g, b, a = .8, .8, .8, 1 Nenue@28: elseif objectiveType == 'object' then Nenue@28: r, g, b, a = 1, 1, 1, 1 Nenue@28: elseif objectiveType == 'player' then Nenue@28: r, g, b, a = 0, 0.8, 1, 1 Nenue@28: end Nenue@28: print(format(' |cFF%02X%02X%02X%0.1f, %0.1f, %0.1f|r', (r * 255), g * 255, b * 255, r, g, b)) Nenue@28: Nenue@28: line.displayColor = {r, g, b, a} Nenue@28: line.status:SetTextColor(r, g, b, a) Nenue@28: line.displayText = data.text Nenue@28: Nenue@30: return data.text, nil Nenue@28: end Nenue@28: Nenue@28: ----------------------------- Nenue@28: --- QUEST Nenue@28: Quest.QuestBlock = {} Nenue@28: Quest.LogBlock = {} Nenue@28: Quest.LogInfo = {} Nenue@28: Nenue@28: function Quest:GetNumWatched () Nenue@28: print(self.name, self) Nenue@30: superTrackQuestID = GetSuperTrackedQuestID() Nenue@30: playerMoney = GetMoney(); Nenue@30: inScenario = C_Scenario.IsInScenario(); Nenue@30: showPOIs = GetCVarBool("questPOI"); Nenue@28: self.numAll = GetNumQuestLogEntries() Nenue@28: self.numWatched = GetNumQuestWatches() Nenue@28: return self.numWatched, self.numAll Nenue@28: end Nenue@30: Nenue@30: --- Returns an iterable table from which tracker blocks can be filled out. Data includes: Nenue@30: -- All entry-layer GetXInfo return values Nenue@30: -- Manifest of line data to be displayed in relation to the tracked object Nenue@28: Quest.GetInfo = function (self, watchIndex) Nenue@28: local print = iprint Nenue@30: print('') Nenue@30: print('|cFF00DDFFindex: |r'.. tostring(watchIndex)) Nenue@28: Nenue@30: local questID, title, questLogIndex, numObjectives, requiredMoney, isComplete, startEvent, isAutoComplete, Nenue@30: failureTime, timeElapsed, questType, isTask, isStory, isOnMap, hasLocalPOI = GetQuestWatchInfo(watchIndex) Nenue@30: if ( not questID ) then Nenue@28: return Nenue@28: end Nenue@28: Nenue@30: local _, level, suggestedGroup, isHeader, isCollapsed, isComplete, frequency, _, startEvent, displayQuestID, isOnMap, hasLocalPOI, isTask, isStory = GetQuestLogTitle(questLogIndex) Nenue@28: Nenue@28: Quest.Info[questID] = Quest.Info[questID] or {} Nenue@28: Nenue@30: local showQuest = true Nenue@30: if isTask then Nenue@30: showQuest = false Nenue@30: end Nenue@30: Nenue@28: local q = Quest.Info[questID] Nenue@30: -- re-use Blizzard logic for consistency Nenue@30: local watchMoney = false; Nenue@30: local tagID, typeTag, frequencyTag, completionTag, completionText Nenue@30: local isAccount, isFaction, isWeekly, isDaily = false, false, false, false Nenue@30: local isBreadcrumb = false Nenue@30: local questFailed = false Nenue@30: local watchMoney = false Nenue@30: local timerInfo, moneyInfo = false, false Nenue@30: local objectives = q.objectives or {} Nenue@30: Nenue@30: Nenue@30: -- Case 1: completed quest or "go to thing" breadcrumb Nenue@30: -- * 1 line containing the completion text Nenue@30: if ( isComplete and isComplete < 0 ) then Nenue@30: isComplete = false Nenue@30: questFailed = true Nenue@30: elseif ( numObjectives == 0 and playerMoney >= requiredMoney and not startEvent ) then Nenue@30: isComplete = true; Nenue@30: questFailed = false Nenue@30: if ( requiredMoney == 0 ) then Nenue@30: isBreadcrumb = true; Nenue@30: end Nenue@30: end Nenue@30: print('|cFF0088FFflags:|r', (isComplete and 'isComplete' or ''), (questFailed and 'questFailed' or ''), (isBreadcrumb and 'isBreadcrumb' or '')) Nenue@30: Nenue@30: -- completion message? Nenue@30: local isSequenced = IsQuestSequenced(questID) Nenue@30: local temp_status = '' Nenue@30: if ( isComplete ) then Nenue@30: temp_status = 'COMPLETED_OBJECTIVES' Nenue@30: objectives = Quest.GetObjectives(questLogIndex, numObjectives, true, isSequenced, isStory) Nenue@30: if ( isAutoComplete ) then Nenue@30: temp_status = 'AUTOCOMPLETE_OBJECTIVES' Nenue@30: completionText = _G.QUEST_WATCH_CLICK_TO_COMPLETE Nenue@30: else Nenue@30: if ( isBreadcrumb ) then Nenue@30: temp_status = 'COMPLETE_BREADCRUMB' Nenue@30: completionText = GetQuestLogCompletionText(questLogIndex) Nenue@30: else Nenue@30: temp_status = 'COMPLETE_READY_FOR_TURN_IN' Nenue@30: completionText = _G.QUEST_WATCH_QUEST_READY Nenue@30: end Nenue@30: end Nenue@30: elseif ( questFailed ) then Nenue@30: temp_status = 'FAILED' Nenue@30: -- Case 2: failed quest Nenue@30: -- * 1 status line; hide other info Nenue@30: completionText = _G.FAILED Nenue@30: else Nenue@30: Nenue@30: temp_status = 'PROGRESS_OBJECTIVES' Nenue@30: -- Case 3: quest in progress Nenue@30: -- * Multiple objective lines Nenue@30: -- * Possible extra lines for money and timer data respectively Nenue@30: objectives = Quest.GetObjectives(questLogIndex, numObjectives, false, isSequenced, isStory) Nenue@30: q.objectives = objectives Nenue@30: Nenue@30: --- anything past here gets appended to existing objectives Nenue@30: Nenue@30: -- money Nenue@30: if ( requiredMoney > playerMoney ) then Nenue@30: Nenue@30: temp_status = temp_status .. '_MONEY' Nenue@30: local text = GetMoneyString(playerMoney).." / "..GetMoneyString(requiredMoney); Nenue@30: moneyInfo = { Nenue@30: type = 'money', Nenue@30: text = text, Nenue@30: finished = false, Nenue@30: requiredMoney = requiredMoney, Nenue@30: playerMoney = playerMoney, Nenue@30: } Nenue@30: end Nenue@30: Nenue@30: -- time limit Nenue@30: if ( failureTime ) then Nenue@30: temp_status = temp_status .. '_TIMED' Nenue@30: if ( timeElapsed and timeElapsed <= failureTime ) then Nenue@30: timerInfo = { Nenue@30: type = 'timer', Nenue@30: finished = false, Nenue@30: timeElapsed = timeElapsed, Nenue@30: failureTime = failureTime, Nenue@30: } Nenue@30: end Nenue@30: end Nenue@30: end Nenue@30: q.numObjectives = numObjectives Nenue@30: q.objectives = objectives Nenue@30: q.moneyInfo = moneyInfo Nenue@30: q.timerInfo = timerInfo Nenue@30: q.completionText = completionText Nenue@30: Nenue@30: -- POI data Nenue@30: local POI = false Nenue@30: if ( showPOIs ) then Nenue@30: POI = { Nenue@30: questID = questID, Nenue@30: questLogIndex = questLogIndex, Nenue@30: } Nenue@30: local poiButton; Nenue@30: if ( hasLocalPOI ) then Nenue@30: Nenue@30: if ( isComplete ) then Nenue@30: POI.type = 'normal' Nenue@30: else Nenue@30: POI.type = 'numeric' Nenue@30: end Nenue@30: elseif ( isComplete ) then Nenue@30: POI.type = 'remote' Nenue@30: end Nenue@30: Nenue@30: local distance, onContinent = GetDistanceSqToQuest(questLogIndex) Nenue@30: if distance ~= nil and distance > 0 then Nenue@30: POI.distance = distance Nenue@30: POI.onContinent = onContinent Nenue@30: end Nenue@30: end Nenue@30: q.POI = POI Nenue@30: Nenue@30: --- Block Tags Nenue@30: -- completionTag - in progres, complete, failed, autocomplete Nenue@30: -- typeTag - account, faction, pvp, dungeon, group Nenue@30: -- frequencyTag - daily/weekly Nenue@30: local questTagID, tagName = GetQuestTagInfo(questID) Nenue@30: local tagInfo = {} Nenue@30: local tagCoords = {} Nenue@30: local factionGroup = GetQuestFactionGroup(questID); Nenue@30: if( questTagID and questTagID == QUEST_TAG_ACCOUNT ) then Nenue@30: if( factionGroup ) then Nenue@30: tagID = "ALLIANCE" Nenue@30: if ( factionGroup == LE_QUEST_FACTION_HORDE ) then Nenue@30: tagID = "HORDE" Nenue@30: end Nenue@30: isFaction = true Nenue@30: else Nenue@30: tagID = QUEST_TAG_ACCOUNT Nenue@30: isAccount = true Nenue@30: end Nenue@30: tagInfo['typeTag'] = tagID Nenue@30: tagCoords['typeTag'] = QUEST_TAG_TCOORDS[tagID] Nenue@30: elseif ( factionGroup) then Nenue@30: tagID = "ALLIANCE" Nenue@30: if ( factionGroup == LE_QUEST_FACTION_HORDE ) then Nenue@30: tagID = "HORDE" Nenue@30: end Nenue@30: isFaction = true Nenue@30: tagInfo['typeTag'] = tagID Nenue@30: tagCoords['typeTag'] = QUEST_TAG_TCOORDS[tagID] Nenue@30: end Nenue@30: Nenue@30: if( frequency == LE_QUEST_FREQUENCY_DAILY and (not isComplete or isComplete == 0) ) then Nenue@30: tagID = 'DAILY' Nenue@30: tagInfo['frequencyTag'] = tagID Nenue@30: tagCoords['frequencyTag'] = QUEST_TAG_TCOORDS[tagID] Nenue@30: isDaily = true Nenue@30: elseif( frequency == LE_QUEST_FREQUENCY_WEEKLY and (not isComplete or isComplete == 0) )then Nenue@30: tagID = 'WEEKLY' Nenue@30: tagInfo['frequencyTag'] = tagID Nenue@30: tagCoords['frequencyTag'] = QUEST_TAG_TCOORDS[tagID] Nenue@30: isWeekly = true Nenue@30: elseif( questTagID ) then Nenue@30: tagID = questTagID Nenue@30: end Nenue@30: Nenue@30: if( isComplete ) then Nenue@30: tagInfo['completionTag'] = 'COMPLETED' Nenue@30: elseif ( questFailed ) then Nenue@30: tagInfo['completionTag'] = 'FAILED' Nenue@30: end Nenue@30: tagCoords['completionTag'] = QUEST_TAG_TCOORDS[tagInfo['completionTag']] Nenue@30: Nenue@30: q.tagInfo = tagInfo Nenue@30: q.tagCoords = tagCoords Nenue@30: -- establishes the primary block tag for view compacting Nenue@30: q.tagID = tagID Nenue@30: q.tagName = tagName Nenue@30: Nenue@30: -- action button information Nenue@30: local link, icon, charges = GetQuestLogSpecialItemInfo(questLogIndex) Nenue@30: local start, duration, enable = GetQuestLogSpecialItemCooldown(questLogIndex) Nenue@30: if link or icon or charges then Nenue@30: q.specialItem = { Nenue@30: questID = questID, Nenue@30: questLogIndex = questLogIndex, Nenue@30: link = link, Nenue@30: charges = charges, Nenue@30: icon = icon, Nenue@30: start = start, Nenue@30: duration = duration, Nenue@30: enable = enable, Nenue@30: } Nenue@30: end Nenue@30: Nenue@30: -- resolved data Nenue@30: Nenue@30: -- raw data Nenue@28: q.watchIndex = watchIndex Nenue@28: q.type = 'Quest' Nenue@30: q.id = questID Nenue@28: q.questID = questID Nenue@28: q.title = title Nenue@28: q.level = level Nenue@28: q.displayQuestID = displayQuestID Nenue@28: q.suggestedGroup = suggestedGroup Nenue@30: q.questLogIndex = questLogIndex Nenue@28: q.numObjectives = numObjectives Nenue@28: q.requiredMoney = requiredMoney Nenue@28: q.isComplete = isComplete Nenue@28: q.startEvent = startEvent Nenue@28: q.isAutoComplete = isAutoComplete Nenue@28: q.failureTime = failureTime Nenue@28: q.timeElapsed = timeElapsed Nenue@28: q.questType = questType Nenue@28: q.isTask = isTask Nenue@28: q.isStory = isStory Nenue@28: q.isOnMap = isOnMap Nenue@28: q.hasLocalPOI = hasLocalPOI Nenue@28: q.frequency = frequency Nenue@28: q.isComplete = isComplete Nenue@28: q.isStory = isStory Nenue@28: q.isTask = isTask Nenue@28: Nenue@30: q.selected = (questID == superTrackQuestID) -- call directly so artifact data doesn't become an issue Nenue@30: self.WatchInfo[watchIndex] = q Nenue@30: self.LogInfo[questLogIndex] = q Nenue@28: Nenue@30: if Devian and Devian.InWorkspace() then Nenue@30: print('|cFF00DDFFstatus:|r', temp_status, '|cFF00FF00questLogIndex|r:', title) Nenue@30: local temp ={} Nenue@30: local data_txt = '|cFFFF4400values:|r' Nenue@30: for k,v in pairs(q) do Nenue@30: if type(v) =='number' then Nenue@30: data_txt = data_txt .. ' |cFFFFFF00'..k..'|r: ' .. tostring(v) Nenue@30: elseif type(v) == 'table' then Nenue@30: tinsert(temp, k) Nenue@28: end Nenue@28: end Nenue@30: print(data_txt) Nenue@30: sort(temp, function(a,b) return a < b end) Nenue@30: for i, k in ipairs(temp) do Nenue@30: print('|cFF00FF00'..k..'|r') Nenue@30: for kk,v in pairs(q[k]) do Nenue@30: print(' ', kk, '=', v) Nenue@30: end Nenue@28: end Nenue@28: end Nenue@28: Nenue@30: return q Nenue@30: end Nenue@28: Nenue@30: Quest.GetObjectives = function(questLogIndex, numObjectives, isComplete, isSequenced, isStory) Nenue@30: local objectives = {} Nenue@30: for i = 1, numObjectives do Nenue@30: local text, type, finished = GetQuestLogLeaderBoard(i, questLogIndex) Nenue@28: print(format(' #%d %s %s %s', i, tostring(type), tostring(text), tostring(finished))) Nenue@30: objectives[i] = { Nenue@28: index = i, Nenue@28: type = type, Nenue@28: text = text, Nenue@28: finished = finished Nenue@28: } Nenue@28: end Nenue@30: return objectives Nenue@28: end Nenue@28: Nenue@30: local huge, sqrt = math.huge, math.sqrt Nenue@28: Quest.GetClosest = function() Nenue@28: local minID, minTitle Nenue@30: local minDist = huge Nenue@28: local numQuests = GetNumQuestLogEntries() Nenue@28: for questIndex = 1, numQuests do Nenue@28: local distance, onContinent = GetDistanceSqToQuest(questIndex) Nenue@28: local title, level, _, _, _, _, _, _, questID = GetQuestLogTitle(questIndex) Nenue@28: if onContinent and distance < minDist then Nenue@28: minDist = distance Nenue@28: minTitle = title Nenue@28: minID = questID Nenue@28: end Nenue@28: end Nenue@28: Nenue@30: print('nearest quest is', minTitle, 'by', sqrt(minDist)) Nenue@28: return minID, minTitle, minDist Nenue@28: end Nenue@28: Nenue@28: Quest.OnTurnIn = function(self, questID, xp, money) Nenue@28: Nenue@28: end Nenue@28: Nenue@28: Nenue@29: Quest.Select = function (handler, block) Nenue@29: if block.info.isAutoComplete and block.info.isComplete then Nenue@29: ShowQuestComplete(block.info.questLogIndex) Nenue@28: else Nenue@29: SetSuperTrackedQuestID(block.info.questID) Nenue@28: end Nenue@28: end Nenue@28: Nenue@29: Quest.Link = function(handler, block) Nenue@28: Nenue@29: local questLink = GetQuestLink(block.info.questLogIndex); Nenue@28: if ( questLink ) then Nenue@28: ChatEdit_InsertLink(questLink); Nenue@28: end Nenue@28: end Nenue@28: Nenue@29: Quest.Open = function(handler, block) Nenue@28: Nenue@29: QuestMapFrame_OpenToQuestDetails(block.info.questID) Nenue@28: end Nenue@28: Nenue@29: Quest.Remove = function(handler, block) Nenue@28: Nenue@29: print('removing', block.info.questLogIndex, 'from watcher') Nenue@29: RemoveQuestWatch(block.info.questLogIndex) Nenue@29: end