view ObjectiveCore.lua @ 20:6bd2102d340b

ObjectiveCore - sorting out oddball events
author Nenue
date Wed, 06 Apr 2016 07:54:19 -0400
parents 605e8f0e46db
children d5ee940de273
line wrap: on
line source
--- ${PACKAGE_NAME}
-- @file-author@
-- @project-revision@ @project-hash@
-- @file-revision@ @file-hash@
-- Created: 3/26/2016 1:51 AM
local B, _G = select(2,...).frame, _G
local pairs, setmetatable, type, tostring = _G.pairs, _G.setmetatable, _G.type, _G.tostring
local format = _G.format
local mod = B:RegisterModule("ObjectiveTracker", _G.VeneerObjectiveWrapper, 'BuffFrame')
local print = B.print('Objectives')
local ObjectiveTrackerFrame, VeneerObjectiveScroll, CreateFrame = _G.ObjectiveTrackerFrame, _G.VeneerObjectiveScroll, _G.CreateFrame
local Wrapper = _G.VeneerObjectiveWrapper
local ipairs, tinsert, hooksecurefunc = _G.ipairs, _G.tinsert, _G.hooksecurefunc
local Scroller = VeneerObjectiveWrapper.scrollArea
local Scroll = _G.VeneerObjectiveScroll

--- Performance values
--[[
  self:RegisterEvent("QUEST_LOG_UPDATE");
	self:RegisterEvent("TRACKED_ACHIEVEMENT_LIST_CHANGED");
	self:RegisterEvent("QUEST_WATCH_LIST_CHANGED");
	self:RegisterEvent("QUEST_AUTOCOMPLETE");
	self:RegisterEvent("QUEST_ACCEPTED");
	self:RegisterEvent("SUPER_TRACKED_QUEST_CHANGED");
	self:RegisterEvent("SCENARIO_UPDATE");
	self:RegisterEvent("SCENARIO_CRITERIA_UPDATE");
	self:RegisterEvent("TRACKED_ACHIEVEMENT_UPDATE");
	self:RegisterEvent("ZONE_CHANGED_NEW_AREA");
	self:RegisterEvent("ZONE_CHANGED");
	self:RegisterEvent("QUEST_POI_UPDATE");
	self:RegisterEvent("VARIABLES_LOADED");
	self:RegisterEvent("QUEST_TURNED_IN");
	self:RegisterEvent("PLAYER_MONEY");
 ]]


--- These are the bitfields used by Blizzard_ObjectiveTracker to determine which segments get parsed.
--- They are replicated here so that plugins can make use of any securehook args involving this info.
local OBJECTIVE_TRACKER_UPDATE_MODULE_QUEST = OBJECTIVE_TRACKER_UPDATE_MODULE_QUEST                       -- 0x0100
local OBJECTIVE_TRACKER_UPDATE_MODULE_AUTO_QUEST_POPUP = OBJECTIVE_TRACKER_UPDATE_MODULE_AUTO_QUEST_POPUP	-- 0x0200
local OBJECTIVE_TRACKER_UPDATE_MODULE_BONUS_OBJECTIVE = OBJECTIVE_TRACKER_UPDATE_MODULE_BONUS_OBJECTIVE		-- 0x0400
local OBJECTIVE_TRACKER_UPDATE_MODULE_SCENARIO = OBJECTIVE_TRACKER_UPDATE_MODULE_SCENARIO	    		        -- 0x0800
local OBJECTIVE_TRACKER_UPDATE_MODULE_ACHIEVEMENT	= OBJECTIVE_TRACKER_UPDATE_MODULE_ACHIEVEMENT           -- 0x1000


local OBJECTIVE_TRACKER_UPDATE_STATIC = OBJECTIVE_TRACKER_UPDATE_STATIC					                         	-- 0x0000
local OBJECTIVE_TRACKER_UPDATE_ALL = OBJECTIVE_TRACKER_UPDATE_ALL			                    	          		-- 0xFFFF
local OBJECTIVE_TRACKER_UPDATE_ID = OBJECTIVE_TRACKER_UPDATE_ID                                           -- 0

local OBJECTIVE_TRACKER_UPDATE_QUEST = OBJECTIVE_TRACKER_UPDATE_QUEST				        	                  	-- 0x0001
local OBJECTIVE_TRACKER_UPDATE_QUEST_ADDED = OBJECTIVE_TRACKER_UPDATE_QUEST_ADDED		               		    -- 0x0002
local OBJECTIVE_TRACKER_UPDATE_TASK_ADDED = OBJECTIVE_TRACKER_UPDATE_TASK_ADDED		    	              		-- 0x0004
local OBJECTIVE_TRACKER_UPDATE_SCENARIO = OBJECTIVE_TRACKER_UPDATE_SCENARIO			      	                 	-- 0x0008
local OBJECTIVE_TRACKER_UPDATE_SCENARIO_NEW_STAGE = OBJECTIVE_TRACKER_UPDATE_SCENARIO_NEW_STAGE		       	-- 0x0010
local OBJECTIVE_TRACKER_UPDATE_ACHIEVEMENT = OBJECTIVE_TRACKER_UPDATE_ACHIEVEMENT			                   	-- 0x0020
local OBJECTIVE_TRACKER_UPDATE_ACHIEVEMENT_ADDED = OBJECTIVE_TRACKER_UPDATE_ACHIEVEMENT_ADDED		  	      -- 0x0040
local OBJECTIVE_TRACKER_UPDATE_SCENARIO_BONUS_DELAYED = OBJECTIVE_TRACKER_UPDATE_SCENARIO_BONUS_DELAYED		-- 0x0080

local OBJECTIVE_TRACKER_UPDATE_REASON = OBJECTIVE_TRACKER_UPDATE_ALL -- default
--- Used to determine which trackers are listening for money events
mod.MoneyReasons = 0

--- Baseline defaults table; values defined in the files that they pertain to
mod.defaults = {}

--- Tracker display order
mod.orderedNames = {'Bonus', 'AutoQuest', 'Quest', 'Cheevs'}

--- ipairs() argument tables
mod.orderedHandlers = setmetatable({}, {__mode = "k"})
mod.orderedTrackers = setmetatable({}, {__mode = "k"})
mod.indexedTrackers = setmetatable({}, {__mode = "k"})

--- pairs() argument tables
mod.namedTrackers = setmetatable({}, {__mode = "k"})

local WRAPPER_ANCHOR_POINT = 'TOPRIGHT'
local WRAPPER_OFFSET_X = 0
local WRAPPER_OFFSET_Y = -200
local WRAPPER_MAX_HEIGHT = 670
local WRAPPER_WIDTH = 280
local WRAPPER_HEADER_HEIGHT = 24

mod.defaults.Wrapper = {
  AnchorPoint = WRAPPER_ANCHOR_POINT,
  OffsetX = WRAPPER_OFFSET_X,
  OffsetY = WRAPPER_OFFSET_Y,
  Height = WRAPPER_MAX_HEIGHT,
  Width = WRAPPER_WIDTH,
  HeaderHeight = WRAPPER_HEADER_HEIGHT
}
--- Tracker module definitions begin here; innards dealing with data retreival and output are defined further in
mod.DefaultTracker = {
  previousHeight = 0,

  name = "temp",
  displayName = "temp",
  updateReasonModule = 0xFF00,
  updateReasonEvent  = 0x00FF,

  numWatched = 0,   --- number of entries being handled
  numBlocks = 0,    --- number of blocks created
  actualBlocks = 0, --- number of blocks in use

  freeBlocks = {},  --- block heap
  usedBlocks = {},

  Info = {},        -- find data by ID
  BlockInfo = {},   -- find data by block ID
  Watched = {},     -- find watchIndex by data ID
  WatchInfo = {},   -- find data by watch index
  WatchBlock = {},  -- find block by watch index
}

mod.AutoQuest = {
  name = "AutoQuest",
  displayName = "Notice",
  updateReasonModule = OBJECTIVE_TRACKER_UPDATE_MODULE_QUEST,
  updateReasonEvents = OBJECTIVE_TRACKER_UPDATE_QUEST +
      OBJECTIVE_TRACKER_UPDATE_QUEST_ADDED,
}
mod.Quest = {
  name = "Quest",
  displayName = "Quests",
  updateReasonModule = OBJECTIVE_TRACKER_UPDATE_MODULE_QUEST,
  updateReasonEvents = OBJECTIVE_TRACKER_UPDATE_QUEST +
      OBJECTIVE_TRACKER_UPDATE_QUEST_ADDED,
}
mod.Cheevs = {
  name = "Cheevs",
  displayName = "Achievements",
  updateReasonModule = OBJECTIVE_TRACKER_UPDATE_MODULE_ACHIEVEMENT,
  updateReasonEvents = OBJECTIVE_TRACKER_UPDATE_ACHIEVEMENT +
      OBJECTIVE_TRACKER_UPDATE_ACHIEVEMENT_ADDED,
}
mod.Bonus = {
  name = "Bonus",
  displayName = "Bonus Objectives",
  updateReasonModule = OBJECTIVE_TRACKER_UPDATE_MODULE_BONUS_OBJECTIVE,
  updateReasonEvents = OBJECTIVE_TRACKER_UPDATE_QUEST +
        OBJECTIVE_TRACKER_UPDATE_TASK_ADDED +
        OBJECTIVE_TRACKER_UPDATE_SCENARIO +
        OBJECTIVE_TRACKER_UPDATE_SCENARIO_NEW_STAGE +
        OBJECTIVE_TRACKER_UPDATE_SCENARIO_BONUS_DELAYED
}

local Tracker_string = function (self)
  return self.name
end
local Tracker_call = function (self, reason)
  self:Update(reason)
end

local Tracker_Initialize = function (self, name, index)
  print('Initializing |cFF00FFFF'..name..'|r module...')

  local handler = setmetatable(mod[name] or {}, {
    __tostring = Tracker_string,
    __call = Tracker_call
  })
  if type(mod.orderedHandlers[index]) == 'table' then
    return mod.orderedHandlers[index]
  end

  print('|cFFFFFF00Acquiring locals')
  local preset = {}
  for k, _ in pairs(handler) do
    preset[k] = true
  end


  print('|cFFFF8800Inheriting')
  for k, v in pairs(self) do
    if not handler[k] then
      if type(v) == 'table' then
        -- assume all tables to be local data; don't inherit or ref
        handler[k] = {}
      else
        handler[k] = self[k]
      end
      print('copying', k)
    end
  end
  print('|cFFFF4400'..tostring(name)..'|r:')
  for k, v in pairs(handler) do
    print(format("%32s %8s %s", (preset[k] and '|cFFFFFFFF' or '|cFFFFFF00') .. k .. '|r', type(v), tostring(v)))
  end

  mod[name] = handler

  local trackerName = 'Veneer'..name..'Tracker'
  local handler = mod[name]
  local frame = CreateFrame('Frame', trackerName, _G.VeneerObjectiveScroll, 'VeneerTrackerTemplate')
  frame.title:SetText(handler.displayName)
  mod.SetBlockStyle(frame, 'Tracker', 'Normal')
  handler.frame = frame
  handler.trackerName = trackerName
  mod.orderedTrackers[index] = frame
  mod.namedTrackers[name] = frame
  mod.indexedTrackers[handler] = frame
  print('|cFFFF0088' .. trackerName .. '|r created for |cFF00FFFF' .. handler.displayName .. '|r module')

  mod.orderedHandlers[index] = handler
  return true
end

function mod:OnEvent (event, ...)
  local isHandled
  print('|cFF00FF00'.. event ..'|r', ...)
  if ( event == "QUEST_LOG_UPDATE" ) then
    mod:Update(OBJECTIVE_TRACKER_UPDATE_QUEST);
  elseif ( event == "TRACKED_ACHIEVEMENT_UPDATE" ) then
    --AchievementObjectiveTracker_OnAchievementUpdate(...);
    mod.Cheevs:Update(OBJECTIVE_TRACKER_UPDATE_ACHIEVEMENT)
  elseif ( event == "QUEST_ACCEPTED" ) then
    local questLogIndex, questID = ...;
    if ( IsQuestTask(questID) ) then
      mod:Update(OBJECTIVE_TRACKER_UPDATE_TASK_ADDED, questID);
    else
      if ( AUTO_QUEST_WATCH == "1" and GetNumQuestWatches() < MAX_WATCHABLE_QUESTS ) then
        AddQuestWatch(questLogIndex);
        SetSuperTrackedQuestID(questID);
      end
    end
  elseif ( event == "TRACKED_ACHIEVEMENT_LIST_CHANGED" ) then
    local achievementID, added = ...;
    if ( added ) then
      mod:Update(OBJECTIVE_TRACKER_UPDATE_ACHIEVEMENT_ADDED, achievementID);
    else
      mod:Update(OBJECTIVE_TRACKER_UPDATE_ACHIEVEMENT);
    end
  elseif ( event == "QUEST_WATCH_LIST_CHANGED" ) then
    local questID, added = ...;
    if ( added ) then
      if ( not IsQuestTask(questID) ) then
        mod:Update(OBJECTIVE_TRACKER_UPDATE_QUEST_ADDED, questID);
      end
    else
      mod:Update(OBJECTIVE_TRACKER_UPDATE_QUEST);
    end
  elseif ( event == "QUEST_POI_UPDATE" ) then
    QuestPOIUpdateIcons();
    if ( GetCVar("trackQuestSorting") == "proximity" ) then
      SortQuestWatches();
    end

    mod:Update(OBJECTIVE_TRACKER_UPDATE_MODULE_QUEST);

  elseif ( event == "SCENARIO_CRITERIA_UPDATE" ) then
    mod:Update(OBJECTIVE_TRACKER_UPDATE_SCENARIO);
  elseif ( event == "SUPER_TRACKED_QUEST_CHANGED" ) then
    mod:Update(OBJECTIVE_TRACKER_UPDATE_QUEST)
  elseif ( event == "ZONE_CHANGED" ) then
    local inMicroDungeon = IsPlayerInMicroDungeon();
    if ( inMicroDungeon ~= self.inMicroDungeon ) then
      if ( not WorldMapFrame:IsShown() and GetCVarBool("questPOI") ) then
        SetMapToCurrentZone();			-- update the zone to get the right POI numbers for the tracker
      end
      --SortQuestWatches();
      self.inMicroDungeon = inMicroDungeon;
    end
  elseif ( event == "QUEST_AUTOCOMPLETE" ) then
    local questId = ...;
    AddAutoQuestPopUp(questId, "COMPLETE");
    mod:Update(OBJECTIVE_TRACKER_UPDATE_STATIC)
  elseif ( event == "SCENARIO_UPDATE" ) then
    local newStage = ...;
    if ( newStage ) then
      mod:Update(OBJECTIVE_TRACKER_UPDATE_SCENARIO_NEW_STAGE);
    else
      mod:Update(OBJECTIVE_TRACKER_UPDATE_SCENARIO);
    end
  elseif ( event == "ZONE_CHANGED_NEW_AREA" ) then
    if ( not WorldMapFrame:IsShown() and GetCVarBool("questPOI") ) then
      SetMapToCurrentZone();			-- update the zone to get the right POI numbers for the tracker
    end
    SortQuestWatches();
  elseif ( event == "QUEST_TURNED_IN" ) then
    local questID, xp, money = ...;
    if ( IsQuestTask(questID) ) then
      mod:Update(OBJECTIVE_TRACKER_UPDATE_MODULE_BONUS_OBJECTIVE)
    end
  elseif ( event == "PLAYER_MONEY" and self.watchMoneyReasons > 0 ) then
    mod:Update(self.watchMoneyReasons);
  end
end

--- Done once per ui load
local BlizzHooks = {
  ['AddQuestWatch'] = 'AddQuestWatch',
  ['RemoveQuestWatch'] = 'RemoveQuestWatch',
  ['AbandonQuest'] = 'AbandonQuest',
  ['AcknowledgeAutoAcceptQuest'] = 'AcknowledgeAutoAcceptQuest',
  ['AddAutoQuestPopUp'] = 'AddAutoQuestPopUp',
  ['RemoveAutoQuestPopUp'] = 'RemoveAutoQuestPopUp',
  ['AddTrackedAchievement'] = 'AddTrackedAchievement',
  ['RemoveTrackedAchievement'] = 'RemoveTrackedAchievement',
  ['SetSuperTrackedQuestID'] = 'SetSuperTrackedQuestID'
}
local VeneerData
function mod:OnInitialize()
  local c = mod.Conf.Wrapper
  VeneerData = _G.VeneerData
  VeneerData.CallLog = VeneerData.CallLog or {}
  if not mod.isHooked then
    mod.isHooked = true
    for blizzFunc, veneerFunc in pairs(BlizzHooks) do
      if mod[veneerFunc] then
        hooksecurefunc(blizzFunc, mod[veneerFunc])
      else
        hooksecurefunc(blizzFunc, function(...)
          print('|cFFFF0088securehook('..tostring(blizzFunc)..')|r args:', ...)
          tinsert(VeneerData.CallLog, {blizzFunc, ...})
        end)
      end
    end
  end
  Scroller:SetScrollChild(Scroll)
  Scroller:SetWidth(c.Width)
  Scroll:SetPoint('TOPLEFT', Scroller, 'TOPLEFT')
  Scroll:SetWidth(c.Width)
  ObjectiveTrackerFrame:UnregisterAllEvents()
  ObjectiveTrackerFrame:Hide()
end

--- Done any time the the minimize button is toggled up

function mod:OnEnable()
  for id, name in ipairs(mod.orderedNames) do
    if not mod.orderedHandlers[id] then
      Tracker_Initialize(mod.DefaultTracker, name, id)
    end
  end

  for event, func in pairs(mod) do
    if type(func) == 'function' and event:match('^[A-Z_]+$') then
      print('|cFFFF44FFlistening to', event)
      Wrapper:RegisterEvent(event)
    end
  end

  local c = mod.Conf.Wrapper
  Wrapper:SetPoint(c.AnchorPoint, UIParent, c.AnchorPoint, c.OffsetX, c.OffsetY)
  B.Conf.FramePosition[Wrapper:GetName()] = {c.AnchorPoint, c.AnchorPoint, c.OffsetX, c.OffsetY}
  Wrapper:SetWidth(c.Width)


  mod.InitializeWidgets()
  mod:Update()
end

function mod:OnDisable()

end