diff ObjectiveTracker/ObjectiveCore.lua @ 23:e837384ac363

Separating objective tracker module
author Nenue
date Sun, 10 Apr 2016 04:35:32 -0400
parents ObjectiveCore.lua@9b3fa734abff
children 66b927b46776
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ObjectiveTracker/ObjectiveCore.lua	Sun Apr 10 04:35:32 2016 -0400
@@ -0,0 +1,451 @@
+--- ${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, band, format = _G.pairs, _G.setmetatable, _G.type, _G.tostring, bit.band, string.format
+local ipairs, tinsert, hooksecurefunc = _G.ipairs, _G.tinsert, _G.hooksecurefunc
+local PlaySoundFile, IsQuestTask, SortQuestWatches, GetCurrentMapAreaID, GetZoneText, GetMinimapZoneText = PlaySoundFile, IsQuestTask, SortQuestWatches, GetCurrentMapAreaID, GetZoneText, GetMinimapZoneText
+local AddQuestWatch, SetSuperTrackedQuestID, GetNumQuestWatches, AUTO_QUEST_WATCH, MAX_WATCHABLE_QUESTS = AddQuestWatch, SetSuperTrackedQuestID, GetNumQuestWatches, AUTO_QUEST_WATCH, MAX_WATCHABLE_QUESTS
+local QuestPOIUpdateIcons, GetCVar, IsPlayerInMicroDungeon, WorldMapFrame, GetCVarBool, SetMapToCurrentZone = QuestPOIUpdateIcons, GetCVar, IsPlayerInMicroDungeon, WorldMapFrame, GetCVarBool, SetMapToCurrentZone
+local AddAutoQuestPopUp = AddAutoQuestPopUp
+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 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.watchMoneyReasons = 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,
+  TextSpacing = 3,
+  TitleSpacing = 3,
+}
+
+
+
+--- Tracker module definitions begin here; innards dealing with data retreival and output are defined further in
+mod.DefaultHandler = {
+  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
+}
+
+local Tracker_string = function (self)
+  return self.name
+end
+local Tracker_call = function (self, reason)
+  self:Update(reason)
+end
+local Handler_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
+  handler.lines = {}
+  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
+
+local Event = {}
+Event.QUEST_LOG_UPDATE =  function()
+  return OBJECTIVE_TRACKER_UPDATE_MODULE_QUEST + OBJECTIVE_TRACKER_UPDATE_MODULE_BONUS_OBJECTIVE
+end
+Event.QUEST_ACCEPTED = function(questLogIndex, questID)
+  if ( IsQuestTask(questID) ) then
+    return OBJECTIVE_TRACKER_UPDATE_TASK_ADDED, questID
+  else
+    if ( AUTO_QUEST_WATCH == "1" and GetNumQuestWatches() < MAX_WATCHABLE_QUESTS ) then
+      AddQuestWatch(questLogIndex);
+      SetSuperTrackedQuestID(questID);
+    end
+    return OBJECTIVE_TRACKER_UPDATE_MODULE_QUEST
+  end
+end
+
+Event.QUEST_WATCH_LIST_CHANGED = function(questID, added)
+  if ( added ) then
+    if ( not IsQuestTask(questID) ) then
+      return OBJECTIVE_TRACKER_UPDATE_QUEST_ADDED, questID, added
+    end
+  else
+    return OBJECTIVE_TRACKER_UPDATE_QUEST, questID, added
+  end
+end
+
+Event.QUEST_POI_UPDATE = function()
+  QuestPOIUpdateIcons();
+  if ( GetCVar("trackQuestSorting") == "proximity" ) then
+    SortQuestWatches();
+  end
+  return OBJECTIVE_TRACKER_UPDATE_ALL
+end
+Event.SUPER_TRACKED_QUEST_CHANGED = function()
+  return OBJECTIVE_TRACKER_UPDATE_QUEST
+end
+Event.ZONE_CHANGED = function()
+
+  local inMicroDungeon = IsPlayerInMicroDungeon();
+  if ( inMicroDungeon ~= mod.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();
+    mod.inMicroDungeon = inMicroDungeon;
+  end
+end
+Event.QUEST_AUTOCOMPLETE = function(questId)
+  AddAutoQuestPopUp(questId, "COMPLETE");
+  return OBJECTIVE_TRACKER_UPDATE_MODULE_QUEST + OBJECTIVE_TRACKER_UPDATE_MODULE_AUTO_QUEST_POPUP
+end
+Event.SCENARIO_CRITERIA_UPDATE =  function()
+  return OBJECTIVE_TRACKER_UPDATE_SCENARIO
+end
+Event.SCENARIO_UPDATE = function(newStage)
+  if ( newStage ) then
+    return OBJECTIVE_TRACKER_UPDATE_SCENARIO_NEW_STAGE
+  else
+    return OBJECTIVE_TRACKER_UPDATE_SCENARIO
+  end
+end
+Event.TRACKED_ACHIEVEMENT_UPDATE = function()
+  return OBJECTIVE_TRACKER_UPDATE_ACHIEVEMENT
+end
+Event.TRACKED_ACHIEVEMENT_LIST_CHANGED = function(achievementID, added)
+  if ( added ) then
+    return OBJECTIVE_TRACKER_UPDATE_ACHIEVEMENT_ADDED, achievementID
+  else
+    return OBJECTIVE_TRACKER_UPDATE_ACHIEVEMENT
+  end
+end
+Event.ZONE_CHANGED_NEW_AREA = function ()
+  if ( not WorldMapFrame:IsShown() and GetCVarBool("questPOI") ) then
+    SetMapToCurrentZone();			-- update the zone to get the right POI numbers for the tracker
+  end
+  SortQuestWatches();
+  mod.currentZoneArea = GetCurrentMapAreaID()
+  print('Updating zone ID to', mod.currentZoneArea, '=', GetZoneText(), GetMinimapZoneText())
+
+
+  return OBJECTIVE_TRACKER_UPDATE_TASK_ADDED
+end
+
+
+Event.PLAYER_MONEY = function()
+  if mod.watchMoneyReasons > 0 then
+    return mod.watchMoneyReasons
+  end
+end
+Event.CRITERIA_COMPLETE = function()
+  return OBJECTIVE_TRACKER_UPDATE_MODULE_BONUS_OBJECTIVE
+end
+Event.QUEST_TURN_IN = function(questID, xp, money)
+  if ( IsQuestTask(questID) ) then
+    mod.Bonus:OnTurnIn(questID, xp, money)
+    print('updating bonus modules (code', OBJECTIVE_TRACKER_UPDATE_MODULE_BONUS_OBJECTIVE, ',', questID, xp, money)
+    return OBJECTIVE_TRACKER_UPDATE_MODULE_BONUS_OBJECTIVE, questID, xp, money
+  else
+    return OBJECTIVE_TRACKER_UPDATE_MODULE_QUEST, questID, xp, money
+  end
+end
+mod.Event = Event
+
+--- 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
+
+mod.SetWatchMoney = function(watchMoney, reason)
+  if watchMoney then
+    if band(mod.watchMoneyReasons, reason) == 0 then
+      mod.watchMoneyReasons = mod.watchMoneyReasons + reason;
+    end
+  else
+    if band(mod.watchMoneyReasons, reason) > 0 then
+      mod.watchMoneyReasons = mod.watchMoneyReasons - reason;
+    end
+  end
+end
+mod.animateReasons = 0
+mod.SetAnimate = function(animate, reason)
+  if animate then
+    if band(mod.animateReasons, reason) == 0 then
+      mod.animateReasons = mod.animateReasons + reason
+    end
+  else
+    if band(mod.animateReasons, reason) > 0 then
+      mod.animateReasons = mod.animateReasons - reason
+    end
+  end
+end
+
+
+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
+
+  mod.Conf.TasksLog = mod.Conf.TasksLog or {}
+
+  Scroller:SetScrollChild(Scroll)
+  Scroller:SetWidth(c.Width)
+  Scroll:SetWidth(c.Width)
+  Scroll:ClearAllPoints()
+  Scroll:SetPoint('TOP', Scroller, 'TOP')
+  ObjectiveTrackerFrame:UnregisterAllEvents()
+  ObjectiveTrackerFrame:Hide()
+
+  if B.Conf.FrameState[Wrapper:GetName()] == 0 then
+    Scroller:Hide()
+  end
+end
+
+local Play = function(file) if Devian and Devian.InWorkspace() then PlaySoundFile(file) end end
+
+function mod:OnEvent (event, ...)
+  local isHandled
+  print('OnEvent(|cFF00FF00'.. event ..'|r):', ...)
+  local reason, arg1, arg2, arg3
+  if Event[event] then
+    if type(Event[event]) == 'function' then
+      Play([[Interface\Addons\SharedMedia_MyMedia\sound\Info.ogg]])
+      reason, arg1, arg2, arg3 = Event[event](...)
+    elseif type(Event[event]) == 'table' then
+      Play([[Interface\Addons\SharedMedia_MyMedia\sound\Link.ogg]])
+      for i, action in ipairs(Event[event]) do
+        if type(action) == 'function' then
+          reason, arg1, arg2, arg3 = action(event, ...)
+        else
+          reason = action
+        end
+
+        if reason then
+          mod:Update(reason, arg1, arg2, arg3)
+        end
+      end
+    else
+      Play([[Interface\Addons\SharedMedia_MyMedia\sound\Heart.ogg]])
+      reason = Event[event]
+    end
+  else
+    Play([[Interface\Addons\SharedMedia_MyMedia\sound\Quack.ogg]])
+  end
+  if reason then
+    mod:Update(reason, arg1, arg2, arg3)
+  else
+    print('no reason value returned')
+    Play([[Interface\Addons\SharedMedia_MyMedia\sound\Quack.ogg]])
+  end
+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
+      Handler_Initialize(mod.DefaultHandler, name, id)
+    end
+  end
+
+  for event, action in pairs(Event) do
+    print('|cFFFF0088listen to', event, 'for action|r', tostring(action))
+    Wrapper:RegisterEvent(event)
+  end
+
+  Wrapper:SetScript('OnEvent', mod.OnEvent)
+  local c = mod.Conf.Wrapper
+  Wrapper:SetWidth(c.Width)
+
+  mod.InitializeWidgets()
+  mod:Update()
+
+
+end
+
+function mod:OnDisable()
+  Wrapper:UnregisterAllEvents()
+end
+
+