view WorldPlan.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 e8679ecb48d8
children 0100d923d8c3
line wrap: on
line source
-- WorldPlan.lua
-- Created: 8/16/2016 8:19 AM
-- %file-revision%

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

local print = DEVIAN_WORKSPACE and function(...) _G.print('WP', ...) 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 = true,
}

-- 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
end

function WorldPlan:OnEvent (event, ...)
  print()
  print(event, 'init:', self.initialized)
  if event == 'ADDON_LOADED' then
    local addon = ...
    if addon == "Blizzard_FlightMap" then
      print('do mixin junk')
      self.OnFlightMapLoaded()

    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)
      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)
end

function WorldPlanCore:OnUpdate()
  if #self.TaskQueue >= 1 then
  local func = tremove(self.TaskQueue, 1)
  if func then
    func()
  end

  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.DisplayContinentSummary
  info.func = DropDown_OnClick
  UIDropDownMenu_AddButton(info)
end

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


-- data provider manipulations for the taxi map
WorldPlan.OnFlightMapLoaded = function()
  if true then return end
  -- todo: figure out how to layer inside the map canvas
  local res = {}
  local t = {}
  for k,v in pairs(FlightMapFrame) do
    tinsert(res, tostring(k))
  end

  table.sort(res)
  for i, k in ipairs(res) do
    print(k)
  end
  hooksecurefunc(FlightMapFrame, 'RefreshAll', function(self)
    print('|cFF0088FFWQDP RefreshAllData ', GetTime())

    WorldPlan:GetPinsForMap(self:GetMapID())

    for pin in self:EnumerateAllPins() do
      if pin.worldQuest then
        --print('got pin #', pin.questID)
        local wp = self.QuestsByID[pin.questID]
        if wp then
          wp:ClearAllPoints()
          wp:SetParent(FlightMapFrame.ScrollContainer)
          wp:SetFrameStrata('MEDIUM')
          wp:SetPoint('CENTER', pin, 'CENTER')
          wp:Show()
        end
      end
    end
  end)
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%