view ObjectiveInfo.lua @ 22:9b3fa734abff

ObjectiveFrame - polish quest rewards display - implement money objectives - set line metrics in UpdateLine - set block metrics in UpdateBlock (sum of line metrics)
author Nenue
date Sat, 09 Apr 2016 07:32:45 -0400
parents d5ee940de273
children
line wrap: on
line source
local B = select(2,...).frame
local wipe, pairs, ipairs, min, max, unpack, format, mod = table.wipe, pairs, ipairs, min, max, unpack, format, mod
local tinsert, tostring = tinsert, tostring
local GetQuestTagInfo, GetQuestLogTitle = GetQuestTagInfo, GetQuestLogTitle
local GetNumQuestLogEntries, GetNumQuestWatches, GetQuestLogCompletionText, IsQuestWatched, IsQuestHardWatched, GetQuestLogSpecialItemInfo, GetQuestLogSpecialItemCooldown = GetNumQuestLogEntries, GetNumQuestWatches, GetQuestLogCompletionText, IsQuestWatched, IsQuestHardWatched, GetQuestLogSpecialItemInfo, GetQuestLogSpecialItemCooldown
local GetNumAutoQuestPopUps, GetAutoQuestPopUp, GetTasksTable, GetNumQuestLogTasks, GetTaskInfo, GetQuestObjectiveInfo = GetNumAutoQuestPopUps, GetAutoQuestPopUp, GetTasksTable, GetNumQuestLogTasks, GetTaskInfo, GetQuestObjectiveInfo
local GetNumQuestLogRewardCurrencies, GetQuestLogRewardCurrencyInfo, GetNumQuestLogRewards, GetQuestLogRewardInfo, GetQuestLogRewardMoney, GetMoneyString = GetNumQuestLogRewardCurrencies, GetQuestLogRewardCurrencyInfo, GetNumQuestLogRewards, GetQuestLogRewardInfo, GetQuestLogRewardMoney, GetMoneyString
local GetNumQuestLeaderBoards, GetAchievementNumCriteria, GetQuestLogLeaderBoard, GetAchievementCriteriaInfo = GetNumQuestLeaderBoards, GetAchievementNumCriteria, GetQuestLogLeaderBoard, GetAchievementCriteriaInfo
local GetQuestWatchIndex, GetQuestLogIndexByID, GetSuperTrackedQuestID, SetSuperTrackedQuestID, GetQuestWatchInfo = GetQuestWatchIndex, GetQuestLogIndexByID, GetSuperTrackedQuestID, SetSuperTrackedQuestID, GetQuestWatchInfo
local QuestHasPOIInfo, GetDistanceSqToQuest, GetQuestFactionGroup = QuestHasPOIInfo, GetDistanceSqToQuest, GetQuestFactionGroup
local GetTrackedAchievements, GetNumTrackedAchievements, GetAchievementInfo = GetTrackedAchievements, GetNumTrackedAchievements, GetAchievementInfo
local GetMoney, floor = GetMoney, floor
local T = B:RegisterModule("ObjectiveTracker", _G.VeneerObjectiveWrapper, 'BuffFrame')
local print = B.print('Info')
local QUEST_TAG_DUNGEON = QUEST_TAG_DUNGEON
local QUEST_TAG_GROUP = QUEST_TAG_GROUP
local QUEST_TAG_ACCOUNT = QUEST_TAG_ACCOUNT
local QUEST_TAG_TCOORDS = QUEST_TAG_TCOORDS
local LE_QUEST_FREQUENCY_DAILY = LE_QUEST_FREQUENCY_DAILY
local LE_QUEST_FREQUENCY_WEEKLY = LE_QUEST_FREQUENCY_WEEKLY
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

local Tracker, Bonus, AutoQuest, Quest, Cheevs = T.DefaultTracker, T.Bonus, T.AutoQuest, T.Quest, T.Cheevs
--------------------------------------------------------------------
--- Tracker-specific data retrieval functions
--------------------------------------------------------------------


local DoQuestRewards= function(t, questID)
  local rewards = {}
  t.numCurrencies = GetNumQuestLogRewardCurrencies(questID)
  for i = 1, t.numCurrencies do
    local name, texture, count = GetQuestLogRewardCurrencyInfo(i, questID)
    tinsert(rewards,{
      type = 'currency',
      index = i,
      name = name,
      texture = texture,
      count = count
    });
  end
  -- items
  t.numItems = GetNumQuestLogRewards(questID)
  for i = 1, t.numItems do
    local name, texture, count, quality, isUsable = GetQuestLogRewardInfo(i, questID)
    tinsert(rewards, {
      type = 'item',
      index = i ,
      name = name,
      texture = texture,
      count = count,
      quality = quality,
      isUsable = isUsable
    });
  end
  -- money

  local money = GetQuestLogRewardMoney(questID)
  if ( money > 0 ) then
    tinsert(rewards, {
      type = 'money',
      name = GetMoneyString(money),
      texture = "Interface\\Icons\\inv_misc_coin_01",
      count = 0,
    });
  end

  if #rewards >= 1 then
    t.rewardInfo = rewards
  end
end


-----------------------------
--- AUTO_QUEST
AutoQuest.LogInfo = {}
AutoQuest.LogBlock = {}
AutoQuest.QuestBlock = {}
AutoQuest.WatchBlock = {}
function AutoQuest:GetNumWatched ()
  print(self.name, self)
  Quest:GetNumWatched()
  self.numWatched = GetNumAutoQuestPopUps()

  return self.numWatched
end
AutoQuest.GetInfo = function(self, popupIndex)


  local questID, type = GetAutoQuestPopUp(popupIndex)
  local questIndex = GetQuestLogIndexByID(questID)
  local title, level, suggestedGroup, isHeader, isCollapsed, isComplete, frequency, questID, startEvent, displayQuestID, isOnMap, hasLocalPOI, isTask, isStory = GetQuestLogTitle(questIndex)

  self.Info[questID] = self.Info[questID] or {}
  local popup = self.Info[questID]
  popup.title = title
  popup.description = type
  popup.popupType = type
  popup.questID = questID
  popup.questIndex = questIndex
  popup.popupIndex = popupIndex

  self.Info[questID] = popup
  self.WatchInfo[popupIndex] = popup


  return self.Info[questID]
end

-----------------------------
--- BONUS OBJECTIVE
-- The default UI pops them up as you enter their relevant areas, but the data is actually available at all times.
-- The only requirement is that you've been to said area and progressed any of the objectives.
-- Blizzard deal with this fact by caching any task data collected during session and masking out whatever gets completed.
-- For the addon's module structure to work, GetNumWatched method also invokes a tasks table scan.
-- That composes the table searched by GetInfo().

------------------------------------------------------------------------------------------
--- These functions are copied from Blizzard_BonusObjectiveTracker.lua;
-- It's kind of dumb, but this avoids the risk of code taint.

--- Returns a tasks table modified to include recently completed objectives
local UnitName, GetRealmName = UnitName, GetRealmName
local InternalGetTasksTable = function()
  local completedTasks = T.Conf.TasksLog
  local char = UnitName("player")
  local realm = GetRealmName()
  local tasks = GetTasksTable()

  for questID, data in pairs(Bonus.Info) do

    print('  -- questID:', questID, #data.objectives)
      for i, o in ipairs(data.objectives) do
        print('    --', i, o.text)
      end

  end


  for questID, data in pairs(completedTasks) do
    if questID > 0  then
      local found = false
      for i = 1, #tasks do
        if tasks[i] == questID then
          found = true
          break
        end
      end
      -- if it's not part of the current table, then try to insert it where it was last found
      if not found then
        if data.watchIndex < #tasks then
          tinsert(tasks, data.watchIndex, data)
        else
          tinsert(tasks, data)
        end
      end
    end
  end
  return tasks
end

--- Returns an entry from the composed tasks table if possible, otherwise makes an API pull
local InternalGetTaskInfo = function(questID)
  local completedTasks = T.Conf.TasksLog
  if completedTasks[questID] then
    return true, true, #completedTasks[questID].objectives
  else
    return GetTaskInfo(questID)
  end
end

--- Same as above but for the objective entries
local InternalGetQuestObjectiveInfo = function(questID, objectiveIndex)
  local completedTasks = T.Conf.TasksLog
  if ( completedTasks[questID] ) then
    print('using internal data')
    return completedTasks[questID].objectives[objectiveIndex], completedTasks[questID].objectiveType, true;
  else
    return GetQuestObjectiveInfo(questID, objectiveIndex, false);
  end
end

--- end redundant copy of silliness
------------------------------------------------------------------------------------------

Bonus.Completed = {}
Bonus.POI = {}
Bonus.Scenario = {}
Bonus.QuestBlock = {}
Bonus.WatchInfo = {}
function Bonus:GetNumWatched ()
  print(self.name, self)

  local tasks = InternalGetTasksTable()
  local numWatched = 0
  local numAll = 0
  self.WatchInfo = {}
  print('|cFFFFFF00Bonus.GetNumWatched()|r', #tasks)
  print('  TasksTable pull:')
  for i, questID in ipairs(tasks) do
    local isInArea, isOnMap, numObjectives = InternalGetTaskInfo(questID)
    local existingTask = self.QuestBlock[questID]
    local displayObjectiveHeader = false;
    local test = (isInArea or (isOnMap and existingTask))
    --local test = true
    if test then
      self.Info[questID] = self.Info[questID] or {}

      local t = self.Info[questID]
      self.WatchInfo[i] = t
      t.isInArea = isInArea
      t.isOnMap = isOnMap
      t.existingTask = existingTask
      t.questID = questID
      t.objectives = {}
      t.taskIndex = i


      DoQuestRewards(t, questID)

      local taskTitle
      local taskFinished = true;
      for objectiveIndex = 1, numObjectives do
        local text, objectiveType, finished, displayAsObjective = InternalGetQuestObjectiveInfo(questID, objectiveIndex, false);
        displayObjectiveHeader = displayObjectiveHeader or displayAsObjective;
        if not taskTitle then
          if objectiveType == 'progressbar' and not text:match('^%d%+\\%d+') then
            taskTitle = text
            text = ''
          end
        end


        print('  --', text, objectiveType, finished, displayAsObjective)
        t.objectives[objectiveIndex] = t.objectives[objectiveIndex] or  {}
        local  o = t.objectives[objectiveIndex]

        o.objectiveIndex = objectiveIndex
        o.text = text
        o.objectiveType = objectiveType
        o.finished = finished
        o.displayAsObjective = displayAsObjective
        print('     |cFF00FF88*', objectiveIndex, text)
      end

      -- didn't get a name from progress bar? what about area name
      if not taskTitle then
        if isInArea then
          taskTitle = GetMapNameByID(GetCurrentMapAreaID())
        end
      end
      t.title = taskTitle
    end

    print ('    |cFF00FF88#', i, 'questID', questID, 'inArea', isInArea, 'onMap', isOnMap, 'existing', (existingTask and 'Y' or 'N'), (test and '|cFF00FF00show|r' or '|cFFFF0088hide|r'))
  end


  self.numAll = #tasks
  self.numWatched = #self.WatchInfo
  print('  stats:', self.numAll, 'active tasks,', self.numWatched, 'nearby or animating')
  --return #tasks
  return #self.WatchInfo
end

--- info cleanup done when  turn-ins are detected
Bonus.OnTurnIn = function(self, questID, xp, money)
  print('|cFFFF8800'..self.name..':OnTurnIn call', questID, xp, money)



end

Bonus.GetInfo = function(self, taskIndex)
  print(self.name, self)
  return self.WatchInfo[taskIndex]
end

Bonus.Store = function(questID)

  if not questID then
    print('|cFFFF4400invalid quest ID', questID)
    return
  end

  Bonus.Info[questID] = Bonus.Info[questID] or {}
  local t = Bonus.Info[questID]
  local isInArea, isOnMap, numObjectives = GetTaskInfo(questID)
  t.questID = questID
  t.numObjectives = numObjectives
  t.isInArea  = isInArea
  t.isOnMap = isOnMap

  print('    isInArea', isInArea, 'isOnMap', isOnMap, 'numObj', numObjectives)
  local displayObjectives = false
  local isComplete = true
  if numObjectives >= 1 then
    print('     ', numObjectives,'objective rows')
    t.objectives = {}
    for i = 1, t.numObjectives do
      t.objectives[i] = {}
      local o = t.objectives[i]
      o.index = i
      --local text, objectiveType, finished, displayAsObjective =
      o.text, o.objectiveType, o.finished, o.displayAsObjective = GetQuestObjectiveInfo(questID, i, false)

      print(i, '==>', o.text, o.objectiveType, o.finished, o.displayAsObjective)
      t.displayObjectives = t.displayObjectives or o.displayAsObjective
      t.isComplete = t.isComplete and o.finished

    end
  end

  t.displayObjectives = displayObjectives

  DoQuestRewards(t, questID)

  Bonus.TasksTable[questID] = t

  return t
end

-----------------------------
--- QUEST
Quest.itemButtons = {}
Quest.freeButtons = {}
Quest.POI = {}
Quest.QuestBlock = {}
Quest.LogBlock = {}
Quest.LogInfo = {}

function Quest:GetNumWatched ()
  print(self.name, self)
  self.numAll = GetNumQuestLogEntries()
  self.numWatched = GetNumQuestWatches()
  return self.numWatched, self.numAll
end
Quest.GetInfo = function (self, watchIndex)
  print('|cFF00DDFFQuest|r.|cFF0088FFGetInfo(|r'.. tostring(watchIndex)..'|r)')
  local questID, title, questIndex, numObjectives, requiredMoney, isComplete,
  startEvent, isAutoComplete, failureTime, timeElapsed, questType, isTask, isStory, isOnMap, hasLocalPOI = GetQuestWatchInfo(watchIndex)

  if not questIndex then
    return
  end

  local _, level, suggestedGroup, isHeader, isCollapsed, isComplete, frequency, _, startEvent, displayQuestID, isOnMap, hasLocalPOI, isTask, isStory = GetQuestLogTitle(questIndex)


  if not questID then
    return
  end
  Quest.Info[questID] = Quest.Info[questID] or {}

  local q = Quest.Info[questID]
  q.watchIndex = watchIndex
  q.type = 'Quest'
  q.questID = questID
  q.title = title
  q.level = level
  q.displayQuestID = displayQuestID
  q.suggestedGroup = suggestedGroup
  q.questLogIndex = questIndex
  q.numObjectives = numObjectives
  q.requiredMoney = requiredMoney
  q.isComplete = isComplete
  q.startEvent = startEvent
  q.isAutoComplete = isAutoComplete
  q.failureTime = failureTime
  q.timeElapsed = timeElapsed
  q.questType = questType
  q.isTask = isTask
  q.isStory = isStory
  q.isOnMap = isOnMap
  q.hasLocalPOI = hasLocalPOI
  q.frequency = frequency
  q.isComplete = isComplete
  q.isStory = isStory
  q.isTask = isTask

  --- resolve icon type and template
  local tagID, tagName = GetQuestTagInfo(questID)
  if ( tagName ) then
    local factionGroup = GetQuestFactionGroup(questID);
    -- Faction-specific account quests have additional info in the tooltip
    if ( tagID == QUEST_TAG_ACCOUNT and factionGroup ) then
      local factionString = FACTION_ALLIANCE;
      if ( factionGroup == LE_QUEST_FACTION_HORDE ) then
        factionString = FACTION_HORDE;
      end
      tagName = format("%s (%s)", tagName, factionString);
    end
    if ( QUEST_TAG_TCOORDS[tagID] ) then
      local questTypeIcon;
      if ( tagID == QUEST_TAG_ACCOUNT and factionGroup ) then
        q.typeTag = QUEST_TAG_TCOORDS["ALLIANCE"];
        if ( factionGroup == LE_QUEST_FACTION_HORDE ) then
          q.typeTag= QUEST_TAG_TCOORDS["HORDE"];
        end
      else
        q.typeTag = QUEST_TAG_TCOORDS[tagID];
      end
    end
  end

  if ( frequency == LE_QUEST_FREQUENCY_DAILY ) then
    q.frequencyTag = QUEST_TAG_TCOORDS["DAILY"]
    q.mainStyle = 'Daily'
  elseif ( frequency == LE_QUEST_FREQUENCY_WEEKLY ) then
    q.frequencyTag = QUEST_TAG_TCOORDS["WEEKLY"]
    q.mainStyle = 'Daily'
  end
  if ( isComplete and isComplete < 0 ) then
    q.completionTag = QUEST_TAG_TCOORDS["FAILED"]
    q.subStyle = 'Failed'
  elseif isComplete then
    q.completionTag = QUEST_TAG_TCOORDS["COMPLETED"]
    q.subStyle = 'Complete'
  end
  q.tagID = tagID
  q.tagName = tagName



  --q.isBreadCrumb = isBreadCrumb
  q.completionText= GetQuestLogCompletionText(questIndex)
  q.numObjectives = GetNumQuestLeaderBoards(questIndex)
  q.objectives = {}
  for i = 1, q.numObjectives do
    local text, type, finished = GetQuestLogLeaderBoard(i, questIndex)
    print(format('   #%d %s %s %s', i, tostring(type), tostring(text), tostring(finished)))
    q.objectives[i] = {
      index = i,
      type = type,
      text = text,
      finished = finished
    }
    if type == 'event' then
    elseif type == 'monster' then
    elseif type == 'object' then
    elseif type == 'reputation' then
    elseif type == 'item' then
    end
  end

  if requiredMoney >= 1 then
    local money = GetMoney()
    local moneyText = money
    local requiredSilver, requiredCopper
    local requiredGold = (requiredMoney > 10000) and (floor(requiredMoney/10000)) or nil
    if mod(requiredMoney, 10000) ~= 0 then
      requiredSilver = (requiredMoney > 100) and (mod(requiredMoney, 10000) / 100) or nil
      if mod(requiredMoney, 100) ~= 0 then
        requiredCopper = mod(requiredMoney, 100)
      end
    end

    -- round the money value down
    if requiredMoney > 9999 and not (requiredSilver or requiredCopper) then
      moneyText = floor(money/10000)
    elseif requiredMoney < 10000 and mod(requiredMoney,100) == 0 then
      moneyText = floor(money/100)
    end

    local text = moneyText
    local index = #q.objectives + 1
    local finished = (GetMoney() >= requiredMoney)

    if not finished then
      text = text .. ' / ' .. GetCoinTextureString(requiredMoney, 15)
    else
      text = '' .. GetCoinTextureString(requiredMoney, 15)
    end
    q.objectives[index] = {
      index = index,
      type = 'progressbar',
      quantity = money,
      requiredQuantity = requiredMoney,
      text = text,
      finished = finished
    }
    print(format('   #%d %s %s %s', index, 'money', text, tostring(finished)))
  end


  local link, icon, charges = GetQuestLogSpecialItemInfo(questIndex)
  local start, duration, enable = GetQuestLogSpecialItemCooldown(questIndex)
  if link or icon or charges then
    q.specialItem = {
      questID = questID,
      questIndex = questIndex,
      link = link,
      charges = charges,
      icon = icon,
      start = start,
      duration = duration,
      enable = enable,
    }
  end

  if QuestHasPOIInfo(questID) then
    local distance, onContinent = GetDistanceSqToQuest(questIndex)
      if distance ~= nil and distance > 0 then
      self.POI[questIndex] = {
        questIndex = questIndex,
        questID = questID,
        distance = distance,
        onContinent = onContinent
      }
    end
  end


  q.selected =  (questID == GetSuperTrackedQuestID()) -- call directly so artifact data doesn't become an issue
  self.WatchInfo[watchIndex] = q
  self.LogInfo[questIndex] = q
  print('- logIndex =', questIndex, 'title =', title)
  return q
end

Quest.GetClosest = function()
  local minID
  local minDist = math.huge
  for i =  1, Quest.GetNumWatched() do
      local info = Quest.GetInfo(i)
      if info.hasLocalPOI then
        local distance, onContinent = GetDistanceSqToQuest(info.questIndex)
      end
  end
end


Cheevs.GetNumWatched = function(self)
  print('|cFF00FF00' .. GetTime())
  Cheevs.trackedCheevs = {GetTrackedAchievements()}
  return GetNumTrackedAchievements()
end
Cheevs.GetInfo = function(self, index)
  local cheevID = Cheevs.trackedCheevs[index]
  local id, name, points, completed, month, day, year, description, flags, icon, rewardText, isGuildAch, wasEarnedByMe, earnedBy = GetAchievementInfo(cheevID)

  self.Info[cheevID] = {}
  local c = self.Info[cheevID]
  c.type = 'Cheevs'
  c.watchIndex = index
  c.cheevID = cheevID
  c.title = name
  c.points, c.completed, c.month, c.day, c.year, c.description, c.flags, c.icon, c.rewardText, c.isGuildAch, c.wasEarnedByMe, c.earnedBy =
  points, completed, month, day, year, description, flags, icon, rewardText, isGuildAch, wasEarnedByMe, earnedBy
  c.numObjectives = GetAchievementNumCriteria(cheevID)
  c.objectives = {}
  for i = 1, c.numObjectives do
    local description, type, completed, quantity, requiredQuantity, characterName, flags, assetID, quantityString, criteriaID = GetAchievementCriteriaInfo(cheevID, i)
    c.objectives[i] = {
      objectiveIndex = i,
      cheevID = cheevID,
      text = description,
      type = type,
      finished = completed,
      value = quantity,
      maxValue = requiredQuantity,
      characterName = characterName,
      flags = flags,
      assetID = assetID,
      quantityString = quantityString,
      criteriaID = criteriaID,
    }
  end
  print('Cheevs.|cFF0088FFGetInfo|r('..index..')', 'obj:', GetAchievementNumCriteria(cheevID), name, description)

  self.WatchInfo[index] = c
  return self.Info[cheevID]
end