diff ObjectiveTracker/Quests.lua @ 30:7583684becf4

- implement procedural block contents generation - redo anchor calculations to allow for transitional animation - attempt to sort out event handling quirks related to autopopup quest completion and turn-in - revise the data structures created by the different GetInfo's - start on trimming out redundant variables
author Nenue
date Thu, 14 Apr 2016 17:11:13 -0400
parents adcd7c328d07
children 48b3e3959a0a
line wrap: on
line diff
--- a/ObjectiveTracker/Quests.lua	Wed Apr 13 21:53:24 2016 -0400
+++ b/ObjectiveTracker/Quests.lua	Thu Apr 14 17:11:13 2016 -0400
@@ -1,7 +1,13 @@
 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 GetAutoQuestPopUp, GetQuestLogCompletionText = GetAutoQuestPopUp, GetQuestLogCompletionText
+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')
@@ -10,6 +16,7 @@
 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')
@@ -91,50 +98,255 @@
   line.status:SetTextColor(r, g, b, a)
   line.displayText = data.text
 
-  return line
+  return data.text, nil
 end
 
 -----------------------------
 --- QUEST
-Quest.POI = {}
 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('|cFF00DDFFQuest|r.|cFF0088FFGetInfo(|r'.. tostring(watchIndex)..'|r)')
-  local questID, title, questIndex, numObjectives, requiredMoney, _,
-  _, isAutoComplete, failureTime, timeElapsed, questType, _, _, _, _ = GetQuestWatchInfo(watchIndex)
+  print('')
+  print('|cFF00DDFFindex: |r'.. tostring(watchIndex))
 
-  if not questIndex then
+  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)
 
-  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 showQuest = true
+  if isTask then
+    showQuest = false
+  end
+
   local q = Quest.Info[questID]
+  -- re-use Blizzard logic for consistency
+  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,
+      }
+    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,
+        }
+      end
+    end
+  end
+  q.numObjectives = numObjectives
+  q.objectives = objectives
+  q.moneyInfo = moneyInfo
+  q.timerInfo = timerInfo
+  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
+
+  -- resolved data
+
+  -- raw data
   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 = questIndex
+  q.questLogIndex = questLogIndex
   q.numObjectives = numObjectives
   q.requiredMoney = requiredMoney
   q.isComplete = isComplete
@@ -152,155 +364,53 @@
   q.isStory = isStory
   q.isTask = isTask
 
-  --- resolve icon type and template
-  local questTagID, tagName = GetQuestTagInfo(questID)
-  local tagID
+  q.selected =  (questID == superTrackQuestID) -- call directly so artifact data doesn't become an issue
+  self.WatchInfo[watchIndex] = q
+  self.LogInfo[questLogIndex] = q
 
-  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";
+  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
-      q.isFaction = true
-    else
-      tagID = QUEST_TAG_ACCOUNT;
-      q.isAccount = true
     end
-    q.typeTag = QUEST_TAG_TCOORDS[tagID]
-  elseif ( factionGroup) then
-    tagID = "ALLIANCE";
-    if ( factionGroup == LE_QUEST_FACTION_HORDE ) then
-      tagID = "HORDE";
+    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
-    q.isFaction = true
   end
 
-  if( frequency == LE_QUEST_FREQUENCY_DAILY and (not isComplete or isComplete == 0) ) then
-    tagID = "DAILY";
-    q.frequencyTag = QUEST_TAG_TCOORDS["DAILY"]
-    q.isDaily = true
-  elseif( frequency == LE_QUEST_FREQUENCY_WEEKLY and (not isComplete or isComplete == 0) )then
-    tagID = "WEEKLY";
-    q.frequencyTag = QUEST_TAG_TCOORDS["WEEKLY"]
-    q.isWeekly = true
-  elseif( questTagID ) then
-    tagID = questTagID;
-  end
+  return q
+end
 
-  if ( isComplete and isComplete < 0 ) then
-    q.completionTag = QUEST_TAG_TCOORDS["FAILED"]
-    q.isFailed = true
-  elseif isComplete then
-    q.completionTag = QUEST_TAG_TCOORDS["COMPLETED"]
-  end
-
-
-  q.tagID = questTagID
-  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)
+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)))
-    q.objectives[i] = {
+    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, 12)
-    else
-      text = '' .. GetCoinTextureString(requiredMoney, 12)
-    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)
-  for k,v in pairs(q) do
-    print('|cFFFFFF00'..k..'|r:', v)
-  end
-  return q
+  return objectives
 end
 
+local huge, sqrt = math.huge, math.sqrt
 Quest.GetClosest = function()
   local minID, minTitle
-  local minDist = math.huge
+  local minDist = huge
   local numQuests = GetNumQuestLogEntries()
   for questIndex =  1, numQuests do
     local distance, onContinent = GetDistanceSqToQuest(questIndex)
@@ -312,7 +422,7 @@
     end
   end
 
-  print('nearest quest is', minTitle, 'by', math.sqrt(minDist))
+  print('nearest quest is', minTitle, 'by', sqrt(minDist))
   return minID, minTitle, minDist
 end