view WorldPlan.lua @ 35:26dfa661daa7

WorldPlan: - Quest pins will appear in the flight map. They follow the filter settings applied from the world map. - Reward filter toggle changed to clear out other reward filters. The assumption being that one is most often looking only for that particular type of quest when they go to use it. - Fixed filter bar info falling out of sync after player-triggered world map updates. - Code stuff: -- Quest pin shown-state management makes better use of OnShow OnHide handlers, SetShown is toggled and it all goes from there -- WorldQuests module re-factored outside of the top level frame script. ClassPlan: - Available missions are now recorded; the mission list can be toggled between in-progress and available by clicking the heading.
author Nenue
date Thu, 03 Nov 2016 17:29:15 -0400
parents 0100d923d8c3
children 21bcff08b0f4
line wrap: on
line source
-- WorldPlan.lua
-- Created: 8/16/2016 8:19 AM
-- %file-revision%

WorldPlanCore = {
  defaults = {},
  modules = {},
  FilterOptions = {},
  UsedFilters = {},
  QuestsByZone = {},
  QuestsByID = {},
  TaskQueue = {},
}
WorldPlanPOIMixin = {}
local WorldPlan = WorldPlanCore

local print = DEVIAN_WORKSPACE and function(...) _G.print('WP', ...) end or function() end

local mprint = DEVIAN_WORKSPACE and function(...) _G.print('Canvas', ...) end or function() end
local WP_VERSION = "1.0"
local tinsert, pairs, floor = table.insert, pairs, floor
local ITEM_QUALITY_COLORS = ITEM_QUALITY_COLORS
local BROKEN_ISLES_ID = 1007
local GetCurrentMapAreaID, GetMapNameByID, GetSuperTrackedQuestID = GetCurrentMapAreaID, GetMapNameByID, GetSuperTrackedQuestID

-- default color templates
local DEFAULT_TYPE = {
  a = 1,
  r = 1, g = 1, b = 1,
  x = 0, y = 0,
  desaturated = true,
  pinMask = "Interface\\Minimap\\UI-Minimap-Background",
  rewardMask = "Interface\\Minimap\\UI-Minimap-Background",
  texture = "Interface\\BUTTONS\\YELLOWORANGE64",
  continent = {
    PinSize = 14,
    Border = 2,
    TrackingBorder = 1,
    TagSize = 6,
    TimeleftStage = 0,
    showNumber = true,
    numberFontObject = 'WorldPlanFont'
  },
  zone = {
    PinSize = 22,
    Border = 3,
    TrackingBorder = 2,
    TagSize = 12,
    TimeleftStage = 3,
    showNumber = true,
    numberFontObject = 'WorldPlanNumberFontThin'
  },
  minimized = {
    PinSize = 6,
    Border = 0,
    TrackingBorder = 1,
    NoIcon = true,
    TimeleftStage = 1,
    showNumber = false,
  }
}




local defaults = {
  ShowAllProfessionQuests = false,
  DisplayContinentSummary = true,
  DisplayContinentPins = true,
  NotifyWhenNewQuests = true,
  EnablePins = true,
  FadeWhileGrouped = false,
}

-- operating flags
local superTrackedID
local currentMapName
local hasNewQuestPins
local isContinentMap
local hasPendingQuestData
local notifyPlayed
local scanner, wmtt, WorldMapPOIFrame


-- tracking menu toggler
local DropDown_OnClick = function(self)
  local key = self.value
  if key then
    if WorldPlanData[key] then
      WorldPlanData[key] = nil
    else
      WorldPlanData[key] = true
    end
  end
  _G.WorldPlan:Refresh()
end

function WorldPlan:print(...)
  local msg
  for i = 1, select('#', ...) do
    msg = (msg and (msg .. ' ') or '') .. tostring(select(i, ...))
  end
  DEFAULT_CHAT_FRAME:AddMessage("|cFF0088FFWorldPlan|r: " .. msg)
end

local current_type_owner
function WorldPlan:AddHandler (frame, defaults)
  print('|cFFFFFF00'..self:GetName()..':AddHandler()', frame:GetName())
  tinsert(self.modules, frame)
  self.defaults[frame] = defaults
  frame.GetTypeInfo = function(frame, typeID)
    return self:GetTypeInfo(frame, typeID)
  end
end

function WorldPlan:OnLoad ()

  self.Types = setmetatable({}, {
    __newindex = function(t, k, v)
      if type(v) == 'table' then
        print('adding owner', k)
        v = setmetatable(v, {
          __newindex = function(t2,k2,v2)
          if type(v2) == 'table' then
            print('adding type', k2)
            v2 = setmetatable(v2, {__index = function(t3,k3)
              --print('##deferring to default key', k3)
              return  DEFAULT_TYPE[k3]
            end})
          end
          rawset(t2,k2,v2)
        end})
      end
      rawset(t,k,v)
    end
  })

  self.Types[self] = {}

  for index, color in pairs(ITEM_QUALITY_COLORS) do
    self:AddTypeInfo(self, index, { r = color.r, g = color.g, b = color.b, hex = color.hex, })
  end

  WorldPlan = self

  WorldPlan:print('v'..WP_VERSION)

  self:RegisterEvent("QUESTLINE_UPDATE")
  self:RegisterEvent("QUEST_LOG_UPDATE")
  self:RegisterEvent("WORLD_MAP_UPDATE")
  self:RegisterEvent("WORLD_QUEST_COMPLETED_BY_SPELL")
  self:RegisterEvent("SUPER_TRACKED_QUEST_CHANGED")
  self:RegisterEvent("SKILL_LINES_CHANGED")
  self:RegisterEvent("ARTIFACT_XP_UPDATE")
  self:RegisterEvent("ADDON_LOADED")
  self:SetParent(WorldMapFrame)
end

function WorldPlan:OnShow()
  print(self:GetName()..':OnShow()')
  if self.isStale then
    self:Refresh()
  end

  hooksecurefunc(self, 'SetScript', function(...) self:print('|cFFFFFF00'..self:GetName()..':SetScript()|r', ...) end)
end

function WorldPlan:OnEvent (event, ...)
  print()
  print(event, 'init:', self.initialized)
  if event == 'ADDON_LOADED' then
    local addon = ...
    if addon == "Blizzard_FlightMap" then
      mprint('sending data provider')
      local dataProvider = Mixin(MapCanvasDataProviderMixin, WorldPlanDataProvider)
      WorldPlanDataPinMixin = Mixin(MapCanvasPinMixin, WorldPlanDataPinMixin)
      for k,v in pairs(dataProvider) do
        mprint((v == WorldPlanDataProvider[k]) and ('|cFF00FF00'..tostring(k)..'|r') or ('|cFFFF4400'..tostring(k)..'|r'))
      end

      FlightMapFrame:AddDataProvider(dataProvider)
    end
    if IsLoggedIn() and not self.initialized then
      self:Setup()
    end
  else
    if event == 'WORLD_MAP_UPDATE' then
      self.currentMapID = GetCurrentMapAreaID()
      self.isContinentMap = (self.currentMapID == BROKEN_ISLES_ID)
      --self:print('|cFFFF4400currentMapID =', self.currentMapID)
      self.isStale = true
    end

    for i, module in ipairs(self.modules) do
      if module.OnEvent then
        print('  |cFF0088FF'..module:GetName() .. ':OnEvent()|r')
        module:OnEvent(event, ...)
      end
    end
  end
end

function WorldPlanCore:OnNext(func)


  tinsert(self.TaskQueue, func)
  --self:print('|cFF00FF00adding scheduled task #', #self.TaskQueue)
end

function WorldPlanCore:OnUpdate()
  if #self.TaskQueue >= 1 then
    local func = tremove(self.TaskQueue, 1)
    --self:print('|cFF00FF00running scheduled task #', #self.TaskQueue)
    func()
  end

  if self.isStale then
    print('|cFF00FF00pushing global update')
    self.isStale = nil
    self:Refresh()
  else
    for i, module in ipairs(self.modules) do
      if module.isStale then
        print('|cFF00FF00internal '..module:GetName()..':Refresh()|r')
        module:Refresh()
      end
    end
  end
end

function WorldPlan:Setup ()
  if not WorldPlanData then
    WorldPlanData = {key = 0 }
  end
  WorldPlanData.key = (WorldPlanData.key or 0) + 1
  self.db = WorldPlanData
  self.db.WorldQuests = self.db.WorldQuests or {}
  db = self.db
  for k,v in pairs(defaults) do
    --[===[@non-debug@
    if not db[k] then
      db[k] = v
    end

    --@end-non-debug@]===]
    --@debug@
    db[k] = v
    --@end-debug@
  end

  self.currentMapID = GetCurrentMapAreaID()

  for i, module in ipairs(self.modules) do
    module.db = self.db
    if module.Setup then module:Setup() end
    if not module.RegisterEvent then
      module.RegisterEvent = self.RegisterEvent
    end
  end
  self.initialized = true

  hooksecurefunc("UIDropDownMenu_Initialize", self.OnDropDownInitialize)

  hooksecurefunc("WorldMapTrackingOptionsDropDown_OnClick", function(button)
    print("|cFF0088FFWorldMapTrackingOptionsDropDown_OnClick|r")
    local value = button.value
    if (value == "worldQuestFilterOrderResources" or value == "worldQuestFilterArtifactPower" or
        value == "worldQuestFilterProfessionMaterials" or value == "worldQuestFilterGold" or
        value == "worldQuestFilterEquipment") then
      self:Refresh(true)
    end
  end)
end

function WorldPlan:AddTypeInfo(owner, id, info)
  self.Types[owner] = self.Types[owner] or {}
  self.Types[owner][id] = info
  print('Type('..owner:GetName()..')('..id..') = '.. tostring(info))
end

function WorldPlan:GetTypeInfo(owner, typeID)
  local info, extraInfo
  if not owner then
    --print('## deferring to default type list')
  else
    --print('## pulling for', owner:GetName(), 'id =', typeID)
  end

  owner = owner or self
  if (not typeID) or (not self.Types[owner][typeID]) then
    --print('## sending list default')
    info = DEFAULT_TYPE
  else
    --print('## sent list definition', typeID)
    info = self.Types[owner][typeID]
  end

  if isContinentMap then
    extraInfo = info.continent
    --print('### continent subtype', extraInfo)
  else
    extraInfo = info.zone

    --print('### zone subtype', extraInfo)
  end
  return info, extraInfo
end

do
  local timeStates = {
    {maxSeconds = 60,
      r=1, g=0.25, b =0, format = function (minutes) return '|cFFFF4400'.. minutes .. 'm' end,
    },
    {maxSeconds = 240,
      r=1, g=.5, b=0, format = function(minutes) return '|cFFFF4400'.. floor(minutes/60) .. 'h' end,
    },
    {maxSeconds = 1440,
      r=1, g=1, b=0, format = function(minutes) return '|cFFFFFF00'.. floor(minutes/60) .. 'h' end,
    },
    {maxSeconds = 10081,
      r=0, g=1, b=0,
    }, -- 7 days + 1 minute
  }
  -- Generates a timeleft string
  function WorldPlan:GetTimeInfo(timeLeft, limit)
    limit = limit or #timeStates
    for index = 1, limit do
      local state = timeStates[index]
      if timeLeft <= state.maxSeconds then
        local text
        if state.format then
          text = state.format(timeLeft)
        end
        return text, index
      end
    end
    return nil, nil
  end
end

function WorldPlan:Refresh (forced)
  print('|cFFFFFF00'..self:GetName()..':Refresh()|r forced:', forced, 'init:', self.initialized)
  if not self.initialized then
    return
  end

  for i, module in ipairs(self.modules) do
    if module.Refresh then
      print('|cFF00FF00external '..module:GetName()..':Refresh()|r')
      module:Refresh(forced)
    end
  end
end

-- insert visual options into the tracking button menu
WorldPlan.OnDropDownInitialize = function  (self, callback, dropType)
  if self ~= WorldMapFrameDropDown then
    return
  end
  local db = WorldPlan.db

  local info = UIDropDownMenu_CreateInfo()
  info.text = ""
  info.isTitle = true
  UIDropDownMenu_AddButton(info)
  info.text = "|cFF00AAFFWorldPlan|r"
  info.isTitle = true
  UIDropDownMenu_AddButton(info)
  info.isTitle = nil
  info.disabled = nil
  info.keepShownOnClick = true
  info.tooltipOnButton = 1

  info.text = "Enable"
  info.isNotRadio = true
  info.value = "EnablePins"
  info.checked = db.EnablePins
  info.tooltipTitle = "Enable World Quest Overlays"
  info.tooltipText = "Toggle the detail layers here."
  info.func = DropDown_OnClick
  UIDropDownMenu_AddButton(info)

  info.text = "Display All Profession Quests"
  info.isNotRadio = true
  info.value = "ShowAllProfessionQuests"
  info.checked = db.ShowAllProfessionQuests
  info.tooltipTitle = "Hidden Quests"
  info.tooltipText = "Display work order and profession-related quests that are skipped by the default UI."
  info.func = DropDown_OnClick
  UIDropDownMenu_AddButton(info)

  info.text = "Show Continent Pins"
  info.isNotRadio = true
  info.value = "DisplayContinentPins"
  info.checked = db.DisplayContinentPins
  info.tooltipTitle = "Continent Pins"
  info.tooltipText = "Display quest pins on the continent map (may get cramped)."
  info.func = DropDown_OnClick
  UIDropDownMenu_AddButton(info)

  info.text = "Show Summary"
  info.isNotRadio = true
  info.value = "DisplayContinentSummary"
  info.tooltipTitle = "Summary Bar"
  info.tooltipText = "Display a summary of active world quests. Note: requires directly viewing Broken Isle and Dalaran maps to gain complete info."
  info.checked = db.DisplayContinentSummary
  info.func = DropDown_OnClick
  UIDropDownMenu_AddButton(info)

  info.text = "Fade In Groups"
  info.isNotRadio = true
  info.value = "FadeWhileGrouped"
  info.tooltipTitle = "Group Fade"
  info.tooltipText = "Reduce pin alpha when grouped, so player dots are easier to see."
  info.checked = db.FadeWhileGrouped
  info.func = DropDown_OnClick
  UIDropDownMenu_AddButton(info)
end

--------------------------------------------------------------------------------------------------------------------
-------------------







SLASH_WORLDPLAN1 = "/worldplan"
SLASH_WORLDPLAN2 = "/wp"
SlashCmdList.WORLDPLAN = function()
  print('command pop')
  WorldPlan:GetPinsForMap()
  WorldPlan:RefreshPins()

  SetTimedCallbackForAllPins(0, function(self) self.FadeIn:Play() self.FlashIn:Play()  end)
  SetTimedCallbackForAllPins(5, function(self) self.PendingFade:Play() end)
  SetTimedCallbackForAllPins(8, function(self) self.PendingFade:Stop() end)
end
--%end-debug%