Mercurial > wow > buffalo2
view ObjectiveTracker/ObjectiveCore.lua @ 88:b107b4df7eb6
- core:DynamicReanchor
- top-down evaluation of clustered frames
- core:InternalReanchor(module)
- bottom-up evaluation of target and frames anchored to it
author | Nenue |
---|---|
date | Thu, 20 Oct 2016 04:08:11 -0400 |
parents | 4b3da1b221de |
children |
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, 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 T = 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 T.strings = {} T.strings.CLICK_TO_ACCCEPT = 'Click to Accept' T.strings.CLICK_TO_COMPLETE = 'Click to complete' T.colors ={ enable = true, default = { titlebg = {'HORIZONTAL', 1, 0, .7, .25, 1, 0, .7, .125}, textbg = {'HORIZONTAL', 0, 0, 0, 0.4, 0, 0, 0, 0 }, selectionbg = {'HORIZONTAL', 1, 1, 1, 0, 1, 1, 1, 0.225}, }, daily = { titlebg = {'HORIZONTAL', 0, .7, 1, .25, 0, 1, .7, .125}, textbg = {'HORIZONTAL', 0, .7, 1, .1, 0, 1, .7, .075 }, }, weekly = { titlebg = {'HORIZONTAL', 0, .35, .7, .25, 0, .35, .7, .125}, textbg = {'HORIZONTAL', 0, .35, .7, .1, 0, .35, .7, .075 }, }, account = { titlebg = {'HORIZONTAL', .1, .1, .1, .25, .1, .1, .1, .125}, textbg = {'HORIZONTAL', .1, .1, .1, 0.4, .1, .1, .1, .085 }, }, -- alliance faction_1 = { titlebg = {'HORIZONTAL', .2, .4, 1, 0.4, .2, .4, 1, .085 }, textbg = {'HORIZONTAL', .2, .4, 1, 0.4, .2, .4, 1, .085 }, }, -- horde faction_2 = { titlebg = {'HORIZONTAL', .6, 0, 0.4, 0.4, .6, 0, 0.4, .085 }, textbg = {'HORIZONTAL', .6, 0, 0.4, 0.4, .6, 0, 0.4, .085 }, } } T.watchMoneyReasons = 0 --- Baseline defaults table; values defined in the files that they pertain to T.defaults = {} --- Tracker display order T.orderedNames = {'Bonus', 'AutoQuest', 'Quest', 'Cheevs'} --- ipairs() argument tables T.orderedHandlers = setmetatable({}, {__mode = "k"}) T.orderedTrackers = setmetatable({}, {__mode = "k"}) T.indexedTrackers = setmetatable({}, {__mode = "k"}) --- pairs() argument tables T.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 T.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 T.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 } T.AutoQuest = { name = "AutoQuest", displayName = "Notice", updateReasonModule = OBJECTIVE_TRACKER_UPDATE_MODULE_QUEST, updateReasonEvents = OBJECTIVE_TRACKER_UPDATE_QUEST + OBJECTIVE_TRACKER_UPDATE_QUEST_ADDED, } T.Quest = { name = "Quest", displayName = "Quests", updateReasonModule = OBJECTIVE_TRACKER_UPDATE_MODULE_QUEST, updateReasonEvents = OBJECTIVE_TRACKER_UPDATE_QUEST + OBJECTIVE_TRACKER_UPDATE_QUEST_ADDED, itemButtons = {}, freeButtons = {}, } T.Cheevs = { name = "Cheevs", displayName = "Achievements", updateReasonModule = OBJECTIVE_TRACKER_UPDATE_MODULE_ACHIEVEMENT, updateReasonEvents = OBJECTIVE_TRACKER_UPDATE_ACHIEVEMENT + OBJECTIVE_TRACKER_UPDATE_ACHIEVEMENT_ADDED, } T.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) local c = T.Conf.Wrapper print('Initializing |cFF00FFFF'..name..'|r module...') local handler = setmetatable(T[name] or {}, { __tostring = Tracker_string, __call = Tracker_call }) if type(T.orderedHandlers[index]) == 'table' then return T.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 T[name] = handler local trackerName = 'Veneer'..name..'Tracker' local handler = T[name] local frame = CreateFrame('Frame', trackerName, _G.VeneerObjectiveScroll, 'VeneerTrackerTemplate') frame.title:SetText(handler.displayName) frame:SetWidth(c.Width) handler.frame = frame handler.trackerName = trackerName handler.lines = {} T.orderedTrackers[index] = frame T.namedTrackers[name] = frame T.indexedTrackers[handler] = frame print('|cFFFF0088' .. trackerName .. '|r created for |cFF00FFFF' .. handler.displayName .. '|r module') T.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 ~= T.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(); T.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(); T.currentZoneArea = GetCurrentMapAreaID() print('Updating zone ID to', T.currentZoneArea, '=', GetZoneText(), GetMinimapZoneText()) return OBJECTIVE_TRACKER_UPDATE_TASK_ADDED end Event.PLAYER_MONEY = function() if T.watchMoneyReasons > 0 then return T.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 T.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 T.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 T.SetWatchMoney = function(watchMoney, reason) if watchMoney then if band(T.watchMoneyReasons, reason) == 0 then T.watchMoneyReasons = T.watchMoneyReasons + reason; end else if band(T.watchMoneyReasons, reason) > 0 then T.watchMoneyReasons = T.watchMoneyReasons - reason; end end end T.animateReasons = 0 T.SetAnimate = function(reason) print('comparing', T.animateReasons, reason) if animate then if band(T.animateReasons, reason) == 0 then T.animateReasons = T.animateReasons + reason end else if band(T.animateReasons, reason) > 0 then T.animateReasons = T.animateReasons - reason end end end local Play = function(file) if Devian and Devian.InWorkspace() then PlaySoundFile(file) end end function T: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 T: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 T:Update(reason, arg1, arg2, arg3) else print('no reason value returned') Play([[Interface\Addons\SharedMedia_MyMedia\sound\Quack.ogg]]) end end function T:OnInitialize() local c = T.Conf.Wrapper VeneerData = _G.VeneerData VeneerData.CallLog = VeneerData.CallLog or {} if not T.isHooked then T.isHooked = true for blizzFunc, veneerFunc in pairs(BlizzHooks) do if T[veneerFunc] then hooksecurefunc(blizzFunc, T[veneerFunc]) else hooksecurefunc(blizzFunc, function(...) print('|cFFFF0088securehook('..tostring(blizzFunc)..')|r args:', ...) tinsert(VeneerData.CallLog, {blizzFunc, ...}) end) end end end T.Conf.TasksLog = T.Conf.TasksLog or {} ObjectiveTrackerFrame:UnregisterAllEvents() ObjectiveTrackerFrame:Hide() for id, name in ipairs(T.orderedNames) do if not T.orderedHandlers[id] then Handler_Initialize(T.DefaultHandler, name, id) end end self:SetSize(c.Width, 40) T.InitializeWidgets() end --- Done any time the the minimize button is toggled up function T:OnEnable() print(B.Conf.VeneerObjectiveWrapper.enabled) if not B.Conf.VeneerObjectiveWrapper.enabled then return end for event, action in pairs(Event) do print('|cFFFF0088listen to', event, 'for action|r', tostring(action)) Wrapper:RegisterEvent(event) end local c = T.Conf.Wrapper Scroller:SetScrollChild(Scroll) Scroller:SetWidth(c.Width) Scroll:SetWidth(c.Width) Scroll:ClearAllPoints() Scroll:SetPoint('TOP', Scroller, 'TOP') self:SetScript('OnEvent', T.OnEvent) Scroller:Show() local from, target, to, x, y = Wrapper:GetPoint(1) print(from, target:GetName(), to, x,y) T:Update() -- run once to prime the data structure T.UpdateActionButtons() end function T:OnDisable() self:UnregisterAllEvents() Scroller:Hide() end