view ObjectiveTracker/Quests.lua @ 33:64f2a9bbea79

- implementing structural revisions in bonus objectives - prevent instances of nil arithmetic - decide on where to keep style values - start widgets with dummy values for operability
author Nenue
date Fri, 15 Apr 2016 17:01:06 -0400
parents a3afe6c3771e
children 9856ebc63fa4
line wrap: on
line source
local B = select(2,...).frame
local T = B:RegisterModule("ObjectiveTracker", _G.VeneerObjectiveWrapper, 'BuffFrame')
local _G, ipairs, max, min, unpack, floor, pairs, tostring, type, band = _G, ipairs, max, min, unpack, floor, pairs, tostring, type, bit.band
local GetQuestWatchInfo, GetQuestLogCompletionText = GetQuestWatchInfo, GetQuestLogCompletionText
local GetQuestLogLeaderBoard, GetNumQuestLogEntries, GetQuestLogTitle = GetQuestLogLeaderBoard, GetNumQuestLogEntries, GetQuestLogTitle
local GetQuestLogSpecialItemInfo, GetQuestLogSpecialItemCooldown = GetQuestLogSpecialItemInfo, GetQuestLogSpecialItemCooldown
local GetSuperTrackedQuestID, GetMoney, C_Scenario, GetCVarBool, GetNumQuestWatches = GetSuperTrackedQuestID, GetMoney, C_Scenario, GetCVarBool, GetNumQuestWatches
local GetQuestTagInfo, GetMoneyString, GetDistanceSqToQuest, GetQuestFactionGroup = GetQuestTagInfo, GetMoneyString, GetDistanceSqToQuest, GetQuestFactionGroup
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
local QUEST_TAG_TCOORDS, IsQuestSequenced = QUEST_TAG_TCOORDS, IsQuestSequenced
local Default, Quest = T.DefaultHandler, T.Quest
local format = format
local print = B.print('Tracker')
local lprint = B.print('Line')
local iprint = B.print('Info')
local colors = T.colors
local tprint = B.print('Tracker')

local superTrackQuestID, playerMoney, inScenario, showPOIs
Quest.Update = function(self, reason, ...)
  local print = tprint
  print('QuestTracker:Update() received')
  T.UpdateActionButtons()
  Default.Update(self, reason, ...)
end

T.Quest.numButtons = 0
local usedButtons = T.Quest.itemButtons
local freeButtons = T.Quest.freeButtons

Quest.UpdateObjectives = function(handler, block)
  local print = lprint
  print('|cFF00FFFFUpdateObjectives()')
  local info = block.info

  local titlebg, textbg = colors.default.titlebg, colors.default.textbg
  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)

  if info.isAccount then
    if info.isFaction then
      print('     faction', info.tagID)
      titlebg, textbg = colors['faction_'..info.tagID].titlebg, colors.default.textbg
    else
      print('     account', info.isAccount, info.isFaction)
      titlebg, textbg = colors.account.titlebg, colors.account.textbg
    end
  elseif info.isDaily then
    print('     daily', info.frequency)
    titlebg, textbg = colors.daily.titlebg, colors.daily.textbg
  elseif info.isWeekly then
    print('     weekly', info.frequency)
    titlebg, textbg = colors.weekly.titlebg, colors.weekly.textbg
  end

  block.titlebg:SetGradientAlpha(unpack(titlebg))
  block.statusbg:SetGradientAlpha(unpack(textbg))

  local completionText
  if info.isComplete then
    if info.isAutoComplete then
      local questID, popupType = GetAutoQuestPopUp(info.questLogIndex)
      if popupType == 'COMPLETE' then
        print('    :: auto-complete quest :: set the message')
        info.completionText = T.strings.CLICK_TO_COMPLETE
      end
    else
      if not completionText or info.completionText then
        info.completionText = GetQuestLogCompletionText(info.questLogIndex)
      end
    end
    print('    :: complete quest :: show instruction: "'.. tostring(info.completionText) .. '"')
  end

  Default.UpdateObjectives(handler, block)
end

Quest.UpdateLine = function(handler, block, line, data)
  local print = lprint
  local objectiveType = data.type
  return data.text, nil, objectiveType
end

-----------------------------
--- QUEST
Quest.QuestBlock = {}
Quest.LogBlock = {}
Quest.LogInfo = {}

function Quest:GetNumWatched ()
  print(self.name, self)
  superTrackQuestID = GetSuperTrackedQuestID()
  playerMoney = GetMoney();
  inScenario = C_Scenario.IsInScenario();
  showPOIs = GetCVarBool("questPOI");
  self.numAll = GetNumQuestLogEntries()
  self.numWatched = GetNumQuestWatches()
  return self.numWatched, self.numAll
end

--- Returns an iterable table from which tracker blocks can be filled out. Data includes:
-- All entry-layer GetXInfo return values
-- Manifest of line data to be displayed in relation to the tracked object
Quest.GetInfo = function (self, watchIndex)
  local print = iprint
  print('')
  print('|cFF00DDFFindex: |r'.. tostring(watchIndex))

  local questID, title, questLogIndex, numObjectives, requiredMoney, isComplete, startEvent, isAutoComplete,
    failureTime, timeElapsed, questType, isTask, isStory, isOnMap, hasLocalPOI = GetQuestWatchInfo(watchIndex)
  if ( not questID ) then
    return
  end

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

  Quest.Info[questID] = Quest.Info[questID] or {}


  local q = Quest.Info[questID]
  q.watchIndex = watchIndex
  q.type = 'Quest'
  q.id = questID
  q.questID = questID
  q.title = title
  q.level = level
  q.displayQuestID = displayQuestID
  q.suggestedGroup = suggestedGroup
  q.questLogIndex = questLogIndex

  -- re-use Blizzard logic for consistency
  local showQuest = true
  if isTask then showQuest = false end
  local watchMoney = false;
  local tagID, typeTag, frequencyTag, completionTag, completionText
  local isAccount, isFaction, isWeekly, isDaily = false, false, false, false
  local isBreadcrumb = false
  local questFailed = false
  local watchMoney = false
  local timerInfo, moneyInfo = false, false
  local objectives = q.objectives or {}


  -- Case 1: completed quest or "go to thing" breadcrumb
  -- * 1 line containing the completion text
  if ( isComplete and isComplete < 0 ) then
    isComplete = false
    questFailed = true
  elseif ( numObjectives == 0 and playerMoney >= requiredMoney and not startEvent ) then
    isComplete = true;
    questFailed = false
    if ( requiredMoney == 0 ) then
      isBreadcrumb = true;
    end
  end
  print('|cFF0088FFflags:|r', (isComplete and 'isComplete' or ''), (questFailed and 'questFailed' or ''), (isBreadcrumb and 'isBreadcrumb' or ''))

  -- completion message?
  local isSequenced = IsQuestSequenced(questID)
  local temp_status = ''
  if ( isComplete ) then
    temp_status = 'COMPLETED_OBJECTIVES'
    objectives = Quest.GetObjectives(questLogIndex, numObjectives, true, isSequenced, isStory)
    if ( isAutoComplete ) then
      temp_status = 'AUTOCOMPLETE_OBJECTIVES'
      completionText = _G.QUEST_WATCH_CLICK_TO_COMPLETE
    else
      if ( isBreadcrumb ) then
        temp_status = 'COMPLETE_BREADCRUMB'
        completionText = GetQuestLogCompletionText(questLogIndex)
      else
        temp_status = 'COMPLETE_READY_FOR_TURN_IN'
        completionText = _G.QUEST_WATCH_QUEST_READY
      end
    end
  elseif ( questFailed ) then
    temp_status = 'FAILED'
    -- Case 2: failed quest
    -- * 1 status line; hide other info
    completionText = _G.FAILED
  else

    temp_status = 'PROGRESS_OBJECTIVES'
    -- Case 3: quest in progress
    -- * Multiple objective lines
    -- * Possible extra lines for money and timer data respectively
    objectives = Quest.GetObjectives(questLogIndex, numObjectives, false, isSequenced, isStory)
    q.objectives = objectives

    --- anything past here gets appended to existing objectives

    -- money
    if ( requiredMoney > playerMoney ) then

      temp_status = temp_status .. '_MONEY'
      local text = GetMoneyString(playerMoney).." / "..GetMoneyString(requiredMoney);
      moneyInfo = {
        type = 'money',
        text = text,
        finished = false,
        requiredMoney = requiredMoney,
        playerMoney = playerMoney,
      }
      tinsert(objectives, moneyInfo)
    end

    -- time limit
    if ( failureTime ) then
      temp_status = temp_status .. '_TIMED'
      if ( timeElapsed and timeElapsed <= failureTime ) then
        timerInfo = {
          type = 'timer',
          finished = false,
          timeElapsed = timeElapsed,
          failureTime = failureTime,
        }
        tinsert(objectives, timerInfo)
      end
    end
  end
  q.numObjectives = numObjectives
  q.objectives = objectives
  q.requiredMoney = requiredMoney
  q.moneyInfo = moneyInfo
  q.timerInfo = timerInfo
  q.failureTime = failureTime
  q.timeElapsed = timeElapsed
  q.completionText = completionText

  -- POI data
  local POI = false
  if ( showPOIs ) then
    POI = {
      questID = questID,
      questLogIndex = questLogIndex,
    }
    local poiButton;
    if ( hasLocalPOI ) then

      if ( isComplete ) then
        POI.type = 'normal'
      else
        POI.type = 'numeric'
      end
    elseif ( isComplete ) then
      POI.type = 'remote'
    end

    local distance, onContinent = GetDistanceSqToQuest(questLogIndex)
    if distance ~= nil and distance > 0 then
      POI.distance = distance
      POI.onContinent = onContinent
    end
  end
  q.POI = POI

  --- Block Tags
  -- completionTag  - in progres, complete, failed, autocomplete
  -- typeTag        - account, faction, pvp, dungeon, group
  -- frequencyTag   - daily/weekly
  local questTagID, tagName = GetQuestTagInfo(questID)
  local tagInfo = {}
  local tagCoords = {}
  local factionGroup = GetQuestFactionGroup(questID);
  if( questTagID and questTagID == QUEST_TAG_ACCOUNT ) then
    if( factionGroup ) then
      tagID = "ALLIANCE"
      if ( factionGroup == LE_QUEST_FACTION_HORDE ) then
        tagID = "HORDE"
      end
      isFaction = true
    else
      tagID = QUEST_TAG_ACCOUNT
      isAccount = true
    end
    tagInfo['typeTag'] = tagID
    tagCoords['typeTag'] = QUEST_TAG_TCOORDS[tagID]
  elseif ( factionGroup) then
    tagID = "ALLIANCE"
    if ( factionGroup == LE_QUEST_FACTION_HORDE ) then
      tagID = "HORDE"
    end
    isFaction = true
    tagInfo['typeTag'] = tagID
    tagCoords['typeTag'] = QUEST_TAG_TCOORDS[tagID]
  end

  if( frequency == LE_QUEST_FREQUENCY_DAILY and (not isComplete or isComplete == 0) ) then
    tagID = 'DAILY'
    tagInfo['frequencyTag'] = tagID
    tagCoords['frequencyTag'] = QUEST_TAG_TCOORDS[tagID]
    isDaily = true
  elseif( frequency == LE_QUEST_FREQUENCY_WEEKLY and (not isComplete or isComplete == 0) )then
    tagID = 'WEEKLY'
    tagInfo['frequencyTag'] = tagID
    tagCoords['frequencyTag'] = QUEST_TAG_TCOORDS[tagID]
    isWeekly = true
  elseif( questTagID ) then
    tagID = questTagID
  end

  if( isComplete ) then
    tagInfo['completionTag'] = 'COMPLETED'
  elseif ( questFailed ) then
    tagInfo['completionTag'] = 'FAILED'
  end
  tagCoords['completionTag'] = QUEST_TAG_TCOORDS[tagInfo['completionTag']]

  q.tagInfo = tagInfo
  q.tagCoords = tagCoords
  -- establishes the primary block tag for view compacting
  q.tagID = tagID
  q.tagName = tagName

  -- action button information
  local link, icon, charges = GetQuestLogSpecialItemInfo(questLogIndex)
  local start, duration, enable = GetQuestLogSpecialItemCooldown(questLogIndex)
  if link or icon or charges then
    q.specialItem = {
      questID = questID,
      questLogIndex = questLogIndex,
      link = link,
      charges = charges,
      icon = icon,
      start = start,
      duration = duration,
      enable = enable,
    }
  end

  if moneyInfo or timerInfo then
    numObjectives = #objectives
  end

  -- raw data
  q.isComplete = isComplete
  q.startEvent = startEvent
  q.isAutoComplete = isAutoComplete
  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
  q.statusKey = temp_status
  q.selected =  (questID == superTrackQuestID)

  T.SetRewards(q, questID)

  self.WatchInfo[watchIndex] = q
  self.LogInfo[questLogIndex] = q

  if Devian and Devian.InWorkspace() then
    print('|cFF00DDFFstatus:|r', temp_status, '|cFF00FF00questLogIndex|r:', title)
    local temp  ={}
    local data_txt = '|cFFFF4400values:|r'
    for k,v in pairs(q) do
      if type(v) =='number' then
        data_txt = data_txt .. ' |cFFFFFF00'..k..'|r: ' .. tostring(v)
      elseif type(v) == 'table' then
        tinsert(temp, k)
      end
    end
    print(data_txt)
    sort(temp, function(a,b) return a < b end)
    for i, k in ipairs(temp) do
      print('|cFF00FF00'..k..'|r')
      for kk,v in pairs(q[k]) do
        print('  ', kk, '=', v)
      end
    end
  end

  return q
end

Quest.GetObjectives = function(questLogIndex, numObjectives, isComplete, isSequenced, isStory)
  local objectives = {}
  for i = 1, numObjectives do
    local text, type, finished = GetQuestLogLeaderBoard(i, questLogIndex)
    print(format('   #%d %s %s %s', i, tostring(type), tostring(text), tostring(finished)))
    objectives[i] = {
      index = i,
      type = type,
      text = text,
      finished = finished
    }
  end
  return objectives
end

local huge, sqrt = math.huge, math.sqrt
Quest.GetClosest = function()
  local minID, minTitle
  local minDist = huge
  local numQuests = GetNumQuestLogEntries()
  for questIndex =  1, numQuests do
    local distance, onContinent = GetDistanceSqToQuest(questIndex)
    local title, level, _, _, _, _, _, _, questID = GetQuestLogTitle(questIndex)
    if onContinent and distance < minDist then
      minDist = distance
      minTitle = title
      minID = questID
    end
  end

  print('nearest quest is', minTitle, 'by', sqrt(minDist))
  return minID, minTitle, minDist
end

Quest.OnTurnIn = function(self, questID, xp, money)

end


Quest.Select = function (handler, block)
  if block.info.isAutoComplete and block.info.isComplete then
    ShowQuestComplete(block.info.questLogIndex)
  else
    SetSuperTrackedQuestID(block.info.questID)
  end
end

Quest.Link = function(handler, block)

  local questLink = GetQuestLink(block.info.questLogIndex);
  if ( questLink ) then
    ChatEdit_InsertLink(questLink);
  end
end

Quest.Open = function(handler, block)

  QuestMapFrame_OpenToQuestDetails(block.info.questID)
end

Quest.Remove = function(handler, block)

  print('removing', block.info.questLogIndex, 'from watcher')
  RemoveQuestWatch(block.info.questLogIndex)
end