diff WorldQuests.lua @ 33:be4db60219ca

WorldPlan: - Toggling a reward filter cancels out other types by default. Use right mouse to clear. - Fixed filter bar info falling out of sync after player-triggered world map updates. ClassPlan: - Available missions are now recorded; the mission list can be toggled between in-progress and available by clicking the heading.
author Nenue
date Wed, 02 Nov 2016 17:25:07 -0400
parents
children 0100d923d8c3
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/WorldQuests.lua	Wed Nov 02 17:25:07 2016 -0400
@@ -0,0 +1,354 @@
+-- WorldPlan
+-- WorldQuests.lua
+-- Created: 11/2/2016 3:40 PM
+-- %file-revision%
+
+WorldPlanQuestsMixin = {
+  QuestsByZone = {},
+  QuestsByID = {},
+  freePins = {},
+}
+local WorldQuests = WorldPlanQuestsMixin
+
+local MC_GetNumZones, MC_GetZoneInfo = C_MapCanvas.GetNumZones, C_MapCanvas.GetZoneInfo
+local TQ_GetQuestsForPlayerByMapID = C_TaskQuest.GetQuestsForPlayerByMapID -- This function is not yet documented
+local TQ_GetQuestZoneID = C_TaskQuest.GetQuestZoneID
+local GetMapInfo = GetMapInfo
+local print = DEVIAN_WORKSPACE and function(...) _G.print('WP', ...) end or function() end
+local qprint = DEVIAN_WORKSPACE and function(...) _G.print('POI', ...) end or function() end
+local wqprint = DEVIAN_WORKSPACE and function(...) _G.print('WorldQuests', ...) end or function() end
+local wprint = DEVIAN_WORKSPACE and function(...) _G.print('WP', ...) end or function() end
+
+
+local PinBaseIndex = 1600
+local BROKEN_ISLES_ID, DALARAN_ID, AZSUNA_ID, VALSHARAH_ID, HIGHMOUNTAIN_ID, STORMHEIM_ID, SURAMAR_ID, EOA_ID = 1007, 1014, 1015,1018, 1024, 1017, 1033, 1096
+local WORLD_QUEST_MAPS = { [DALARAN_ID] = 'Dalaran70',  [AZSUNA_ID] = 'Azsuna',  [VALSHARAH_ID] = "Val'sharah",
+  [HIGHMOUNTAIN_ID] = 'Highmountain', [STORMHEIM_ID] = 'Stormheim',  [SURAMAR_ID] = 'Suramar',  [EOA_ID] = 'EyeOfAszhara', }
+
+local REWARD_CASH = WORLD_QUEST_REWARD_TYPE_FLAG_GOLD
+local REWARD_ARTIFACT_POWER = WORLD_QUEST_REWARD_TYPE_FLAG_ARTIFACT_POWER
+local REWARD_GEAR = WORLD_QUEST_REWARD_TYPE_FLAG_EQUIPMENT
+local REWARD_CURRENCY = WORLD_QUEST_REWARD_TYPE_FLAG_ORDER_RESOURCES
+local REWARD_REAGENT = WORLD_QUEST_REWARD_TYPE_FLAG_MATERIALS
+
+
+local numPins = 0
+local ZoneInfo = {}
+local NumPinFrames = 1
+
+
+--%debug%
+local SetTimedCallbackForAllPins = function(seconds, callback)
+  C_Timer.After(seconds, function()
+    for id, pin in pairs(WorldPlanQuests.QuestsByID) do
+      callback(pin)
+    end
+  end)
+end
+
+function WorldQuests:Setup()
+
+
+  for mapID, mapName in pairs(WORLD_QUEST_MAPS) do
+    self.QuestsByZone[mapID] = {}
+  end
+
+
+  -- refresh positions any time blizzard does so (i.e. mousewheel zoom)
+  hooksecurefunc("WorldMapScrollFrame_ReanchorQuestPOIs", function()
+    self:Refresh(true)
+  end)
+
+  -- hide the original world quest POIs
+  hooksecurefunc("WorldMap_UpdateQuestBonusObjectives", function()
+    for i = 1, NUM_WORLDMAP_TASK_POIS do
+      local button = _G['WorldMapFrameTaskPOI'..i]
+      if button and button.worldQuest then
+        button:Hide()
+      end
+    end
+  end)
+end
+local WorldMapPOIFrame
+local defaults = {}
+function WorldQuests:OnLoad()
+  print('|cFF00FF88'..self:GetName()..':OnLoad')
+
+  WorldPlan:AddHandler(self, defaults)
+
+  local rgbWhite = {1, 1, 1}
+  WorldPlan:AddTypeInfo(self, REWARD_REAGENT, { r = 0, g = 1, b = 1 })
+  WorldPlan:AddTypeInfo(self, REWARD_ARTIFACT_POWER, { r = 1, g = .25, b = .5, hasNumeric = true, numberRGB = rgbWhite })
+  WorldPlan:AddTypeInfo(self, REWARD_GEAR, { r = .1, g = .2, b = 1 })
+  WorldPlan:AddTypeInfo(self, REWARD_CURRENCY, { r = 1, g = 1, b = 0, hasNumeric = true, numberRGB = {1,1,0}, })
+  WorldPlan:AddTypeInfo(self, REWARD_CASH, { r = 0, g = 0, b = 0, })
+
+  for areaID, fileName in pairs(WORLD_QUEST_MAPS) do
+    self.QuestsByZone[areaID] = {}
+  end
+
+  self:RegisterEvent('WORLD_QUEST_COMPLETED_BY_SPELL')
+  self:RegisterEvent('SKILL_LINES_CHANGED')
+
+  WorldMapPOIFrame = _G.WorldMapPOIFrame
+
+end
+
+function WorldQuests:OnEvent (event, ...)
+  local print = wqprint
+  print('|cFFFFFF00'..self:GetName()..':OnEvent()'..event..'|r', GetTime(), ...)
+  if event == 'QUEST_LOG_UPDATE' then
+    local questID, added = ...
+    if questID and added then
+      local questPOI = self:AcquirePin(questID)
+      self.isStale, self.isPending = questPOI:RefreshData()
+    else
+      self:RefreshData()
+    end
+    print('WorldMapFrame', WorldMapFrame:IsVisible(), 'hasUpdates:', self.isStale)
+  elseif event == 'WORLD_MAP_UPDATE' then
+    self.isStale = true
+  elseif event == 'WORLD_QUEST_COMPLETED_BY_SPELL' then
+    local questID = ...
+    if questID and self.QuestsByID[questID] then
+      self:ReleasePin(self.QuestsByID[questID])
+    end
+  elseif event == 'SKILL_LINES_CHANGED' then
+    self.isStale = true
+  end
+end
+
+local TQ_GetQuestLocation = C_TaskQuest.GetQuestLocation
+function WorldQuests:AcquirePin (questID, mapID)
+  local pin = self.QuestsByID[questID]
+  local isNew = false
+  if not pin then
+    isNew = true
+    local numFree = #self.freePins
+    if numFree >= 1 then
+      pin = tremove(self.freePins, numFree)
+      --print('|cFF00FF00Re-using', pin:GetName())
+    else
+      local name = 'WorldPlanQuestMarker' .. NumPinFrames
+      --print('|cFF00FF00Creating', name)
+      pin = CreateFrame('Frame', name, WorldMapPOIFrame, 'WorldPlanQuestPin')
+
+      pin:SetFrameStrata('HIGH')
+      pin.GetTypeInfo = function(frame, typeID)
+        return self:GetTypeInfo(typeID)
+      end
+      NumPinFrames = NumPinFrames + 1
+      --pin.iconBorder:SetVertexColor(0,0,0,1)
+    end
+    pin:SetID(questID)
+    pin.isNew = true
+    pin.currentWidth = nil
+
+    -- used by TaskPOI_x scripts
+    pin.questID = questID
+    pin.worldQuest = true
+
+    self.QuestsByID[questID] = pin
+  else
+    --print('|cFF00FF00Using', pin:GetName())
+  end
+  mapID = mapID or TQ_GetQuestZoneID(questID)
+  self.QuestsByZone[mapID][questID] = pin
+
+  return pin, isNew
+end
+
+-- remove from index and add it to the recycling heap
+function WorldQuests:ReleasePin (pin)
+
+  local id = pin.questId
+  if id then
+    self.QuestsByID[id] = nil
+    for i, zone in pairs(self.QuestsByZone) do
+      print('-', i, zone[i])
+      zone[id] = nil
+    end
+  end
+  pin:Hide()
+  pin:ClearAllPoints()
+  tinsert(self.freePins, pin)
+  print('|cFFFF4400Clearing out', pin:GetName(),id)
+end
+
+-- create of update quest pins for a map and its underlying zones
+function WorldQuests:RefreshData (mapID)
+  local print = wqprint
+  mapID = mapID or GetCurrentMapAreaID()
+  superTrackedID = GetSuperTrackedQuestID()
+  if not mapID then
+    -- info not available yet
+    return
+  end
+
+  print('|cFF00FF88'..self:GetName()..':RefreshData()|r', 'map:', mapID, 'realMap:', GetCurrentMapAreaID())
+
+  if mapID == BROKEN_ISLES_ID then
+    self.isStale = false
+    print('|cFF00FFFFContinent:|r', mapID, GetMapNameByID(mapID), superTrackedID)
+    self.fullSearch = true
+    for i = 1, MC_GetNumZones(mapID) do
+      local submapID, name, depth = MC_GetZoneInfo(mapID, i)
+      self:RefreshData(submapID)
+    end
+    self.fullSearch = nil
+  elseif self.QuestsByZone[mapID] then
+    local taskInfo = TQ_GetQuestsForPlayerByMapID(mapID)
+    local numQuests = 0
+    if taskInfo and #taskInfo >= 1 then
+      print('|cFF00FFFF  Zone:|r', mapID, GetMapNameByID(mapID), #taskInfo)
+      wipe(self.QuestsByZone[mapID])
+      ZoneInfo[mapID] = taskInfo
+      qprint('|cFFFF4400START of', GetMapNameByID(mapID))
+      for taskID, info in pairs(taskInfo) do
+        local questID = info.questId
+        info.mapID = mapID
+        local questPOI = self:AcquirePin(questID, mapID)
+        local hasUpdate, isPending = questPOI:RefreshData(info)
+        self.isStale = (self.isStale or hasUpdate)
+        self.isPending = (self.isPending or isPending)
+        numQuests = numQuests + 1
+      end
+      qprint('|cFFFF4400END of', GetMapNameByID(mapID))
+    end
+  end
+
+  if not self.fullSearch then
+    print('  hasUpdate:', self.isStale, 'isPending:', self.isPending, 'timer:', (self.OnNext and 'waiting' or ''))
+    --WorldPlan.isStale = (self.isStale or WorldPlan.isStale)
+  end
+
+end
+
+function WorldQuests:Refresh()
+  local print = wqprint
+  print('|cFF00FF88'..self:GetName()..':Refresh()|r')
+  self:Reset()
+  self:UpdateAnchors()
+  self:Cleanup ()
+end
+
+-- prepares elements for a map update
+function WorldQuests:Reset ()
+  local print = wqprint
+  print('|cFF00FF88'..self:GetName()..':Reset()|r')
+  for questID, pin in pairs(self.QuestsByID) do
+    pin.used = nil
+  end
+end
+
+-- update visibility states of all pins
+function WorldQuests:UpdateAnchors (submapID)
+
+  local print = wqprint
+  local db = WorldPlan.db
+  local mapFileName, textureHeight, textureWidth, isMicroDungeon, microDungeonMapName = GetMapInfo()
+  if isMicroDungeon then
+    return
+  end
+
+  local currentMap = GetCurrentMapAreaID()
+  local submapID = submapID or currentMap
+
+  if submapID == BROKEN_ISLES_ID and (not db.DisplayContinentPins) then
+    print('not updating map for reasons')
+    return
+  end
+  print('|cFF88FF00'..self:GetName()..':UpdateAnchors|r', submapID, GetMapNameByID(submapID), 'pin count:', numPins)
+  local numZones = MC_GetNumZones(submapID)
+  if numZones then
+    for i = 1, numZones do
+      local subMapID = MC_GetZoneInfo(submapID, i)
+      self:UpdateAnchors(subMapID)
+    end
+  end
+  local pins = self.QuestsByZone[submapID]
+
+  if pins then
+    local hostFrame = WorldMapPOIFrame
+    local mapWidth, mapHeight = hostFrame:GetSize()
+    for questID, pin in pairs(pins) do
+      pin:IsShowable()
+      if pin.used then
+        pin.hasUpdate = true
+        pin:SetFrameLevel(PinBaseIndex+ (pin.whiteListed and 200 or 0) +numPins)
+        print('level', PinBaseIndex+ (pin.whiteListed and 200 or 0) +numPins)
+        pin:SetAnchor(WorldMapPOIFrame, currentMap, mapWidth, mapHeight)
+        numPins = numPins + 1
+      end
+    end
+  end
+end
+
+-- shows, animates, or hides pins based on their current visibility flags
+local debug_show = {}
+local debug_animate = {}
+local debug_hide = {}
+function WorldQuests:Cleanup ()
+  local print = wqprint
+  local showQuestPOI = db.EnablePins
+  print('|cFFFFFF00'..tostring(self)..':Cleanup()|r')
+  local mapID = GetCurrentMapAreaID()
+  isContinentMap = (mapID == BROKEN_ISLES_ID)
+
+  wipe(debug_show)
+  wipe(debug_animate)
+  wipe(debug_hide)
+  -- continent or zone sizing
+  local fadeGrouped = (db.FadeWhileGrouped and IsInGroup())
+
+  numPins = 0
+  for questID, pin in pairs(self.QuestsByID) do
+    -- can we show it?
+    if showQuestPOI and (pin.used) then
+
+      pin.isStale = true
+      if fadeGrouped then
+        pin:SetAlpha(0.25)
+      else
+        pin:SetAlpha(1)
+      end
+      -- is it a new quest?
+      if pin.isNew then
+        if not pin.isAnimating then
+          pin.isAnimating = true
+          WorldPlan:OnNext(function()
+            pin:ShowNew()
+          end)
+          tinsert(debug_animate,questID)
+        else
+
+          print('animating? ', questID, 'filtered:', pin.filtered)
+        end
+        -- trap new but animating pins here
+      else
+        -- hard show existing pin
+        --print('refresh #', questID, 'filtered:', pin.filtered, 'hasUpdate', pin.hasUpdate)
+        pin:Show()
+        tinsert(debug_show,questID)
+      end
+    else
+      if pin:IsShown() then
+        tinsert(debug_hide,questID)
+      end
+      pin.isAnimating = nil
+      pin.FadeIn:Stop()
+      pin:Hide()
+    end
+  end
+  print('   adding:', table.concat(debug_animate, ',' ))
+  print('  refresh:', table.concat(debug_show, ',' ))
+  print('  hiding:', table.concat(debug_hide, ',' ))
+  hasNewQuestPins = nil
+  notifyPlayed = nil
+  self.isStale = nil
+end
+
+function WorldQuests:FilterCheckByID(questID)
+  local pin = WorldQuests:GetPinByQuestID(questID)
+  return pin:IsShowable()
+end