Nenue@0: --- ${PACKAGE_NAME} Nenue@0: -- @file-author@ Nenue@0: -- @project-revision@ @project-hash@ Nenue@0: -- @file-revision@ @file-hash@ Nenue@0: -- Created: 3/26/2016 1:51 AM Nenue@0: local B = select(2,...).frame Nenue@0: local wipe, pairs, ipairs, min, max, unpack = table.wipe, pairs, ipairs, min, max, unpack Nenue@0: local setmetatable, type = setmetatable, type Nenue@0: local GetNumQuestLeaderBoards, GetAchievementNumCriteria, GetQuestLogLeaderBoard, GetAchievementCriteriaInfo = GetNumQuestLeaderBoards, GetAchievementNumCriteria, GetQuestLogLeaderBoard, GetAchievementCriteriaInfo Nenue@0: local GetQuestLogIndexByID, GetSuperTrackedQuestID, SetSuperTrackedQuestID, GetQuestWatchInfo = GetQuestLogIndexByID, GetSuperTrackedQuestID, SetSuperTrackedQuestID, GetQuestWatchInfo Nenue@0: local mod = B:RegisterModule("ObjectiveTracker", _G.VeneerObjectiveWrapper, 'BuffFrame') Nenue@0: local print = B.print('Objectives') Nenue@0: local ObjectiveTrackerFrame = ObjectiveTrackerFrame Nenue@0: Nenue@0: --[[ Nenue@0: Full quest info is available if: Nenue@0: - It's in the player quest log, or is available from the Gossip interface Nenue@0: - It's being shared from another player and is acceptible Nenue@0: - It's an auto-quest that is available in the current location Nenue@0: Partial quest info is availabe if: Nenue@0: - It's already completed (i.e. it appears in CompletedQuestInfo()). Nenue@0: - It's an scheduled interval quest (daily, weekly, etc.) Nenue@0: - It's contained in a quest link received from chat Nenue@0: Under any other circumstances, only minimal info can be pulled: Nenue@0: - Its availability to the player Nenue@0: - Its relation with the currently engaged NPC Nenue@0: - Its binary completion status Nenue@0: Nenue@0: ]] Nenue@0: --- Global Frames Nenue@0: local Wrapper = _G.VeneerObjectiveWrapper Nenue@0: local Scroller = Wrapper.scrollArea Nenue@0: local Scroll = _G.VeneerObjectiveScroll Nenue@0: Nenue@0: --- list used to make things happen Nenue@0: mod.orderedNames = {[1] = 'AutoQuest', [2] = 'Quest', [3] = 'Cheevs'} Nenue@0: Nenue@0: --- ipairs() list of handlers for wrapper update Nenue@0: mod.orderedHandlers = {} Nenue@0: mod.orderedTrackers = {} Nenue@0: mod.indexedTrackers = {} Nenue@0: --- pairs() list of handler frames for tracker updates Nenue@0: mod.namedTrackers = {} Nenue@0: Nenue@0: --- Handler stubs Nenue@0: mod.AutoQuest = { Nenue@0: name = "AutoQuest" Nenue@0: } Nenue@0: mod.Quest = { Nenue@0: name = "Quest" Nenue@0: } Nenue@0: mod.Cheevs = { Nenue@0: name = "Cheevs" Nenue@0: } Nenue@0: Nenue@0: Nenue@0: --- Temp values set during updates Nenue@0: local wrapperWidth, wrapperHeight Nenue@0: local scrollWidth, scrollHeight Nenue@0: local previousBlock Nenue@0: local currentBlock Nenue@0: Nenue@0: local frame_guide_init = function(self) Nenue@0: self.testU = self.testU or self:CreateTexture('TestU', 'OVERLAY', 'VnTestLine') Nenue@0: self.testB = self.testB or self:CreateTexture('TestB', 'OVERLAY', 'VnTestLine') Nenue@0: self.testL = self.testL or self:CreateTexture('TestL', 'OVERLAY', 'VnTestLine') Nenue@0: self.testR = self.testR or self:CreateTexture('TestR', 'OVERLAY', 'VnTestLine') Nenue@0: end Nenue@0: local frame_guide = function(self, target) Nenue@0: if not target then return end Nenue@0: if target:IsDragging() then return end Nenue@0: local thickness = 1 Nenue@0: local midX, midY = target:GetCenter() Nenue@0: local width, height = target:GetWidth() * 1.5, target:GetHeight() * 1.5 Nenue@0: --print('frame', target:GetLeft(), target:GetTop(), target:GetRight(), target:GetBottom()) Nenue@0: self.testB:ClearAllPoints() Nenue@0: self.testB:SetPoint('TOP', UIParent, 'BOTTOMLEFT', midX, target:GetBottom()) Nenue@0: self.testB:SetSize(width,thickness) Nenue@0: Nenue@0: self.testU:ClearAllPoints() Nenue@0: self.testU:SetPoint('BOTTOM', UIParent, 'BOTTOMLEFT', midX, target:GetTop()) Nenue@0: self.testU:SetSize(width,thickness) Nenue@0: Nenue@0: self.testL:ClearAllPoints() Nenue@0: self.testL:SetPoint('RIGHT', UIParent, 'BOTTOMLEFT', target:GetLeft(), midY) Nenue@0: self.testL:SetSize(thickness,height) Nenue@0: Nenue@0: self.testR:ClearAllPoints() Nenue@0: self.testR:SetPoint('LEFT', UIParent, 'BOTTOMLEFT', target:GetRight(), midY) Nenue@0: self.testR:SetSize(thickness,height) Nenue@0: end Nenue@0: Nenue@0: --- Handler template Nenue@0: local CreateHandler = function (self, name, index) Nenue@0: print(self, name) Nenue@0: local handler = setmetatable({}, { Nenue@0: __tostring = function() return name end, Nenue@0: __call = function (self) mod.UpdateTracker(self) end Nenue@0: }) Nenue@0: if type(mod.orderedHandlers[index]) == 'table' then Nenue@0: return mod.orderedHandlers[index] Nenue@0: end Nenue@0: Nenue@0: print('take up locals first') Nenue@0: local preset = {} Nenue@0: for k,v in pairs(mod[name]) do Nenue@0: preset[k] = true Nenue@0: if type(v) == 'table' then Nenue@0: handler[k] = {} Nenue@0: else Nenue@0: handler[k] = v Nenue@0: end Nenue@0: end Nenue@0: Nenue@0: print('resulting handler contents') Nenue@0: for k, v in pairs(self) do Nenue@0: if not handler[k] then Nenue@0: if type(v) == 'table' then Nenue@0: -- assume all tables to be local data; don't inherit or ref Nenue@0: handler[k] = {} Nenue@0: else Nenue@0: handler[k] = mod.Tracker[k] Nenue@0: end Nenue@0: else Nenue@0: print(name, 'has its own', k) Nenue@0: end Nenue@0: end Nenue@0: print('|cFFFF4400'..tostring(name)..'|r:') Nenue@0: for k, v in pairs(handler) do Nenue@0: print(string.format("%24s %8s %s", (preset[k] and '|cFFFFFFFF' or '|cFFFFFF00') .. k .. '|r', type(v), tostring(v))) Nenue@0: end Nenue@0: mod[name] = handler Nenue@0: mod.orderedHandlers[index] = handler Nenue@0: return true Nenue@0: end Nenue@0: Nenue@0: mod.Tracker = setmetatable({}, { Nenue@0: __call = CreateHandler, Nenue@0: __tostring = function() return 'DEFAULT_TRACKING_HANDLER' end Nenue@0: }) Nenue@0: local Tracker = mod.Tracker Nenue@0: Tracker.numWatched = 0 --- number of entries being handled Nenue@0: Tracker.numBlocks = 0 --- number of blocks created Nenue@0: Tracker.actualBlocks = 0 --- number of blocks in use Nenue@0: Nenue@0: Tracker.freeBlocks = {} --- block heap Nenue@0: Tracker.usedBlocks = {} Nenue@0: Nenue@0: Tracker.Watched = {} -- find by watchIndex Nenue@0: Tracker.Info = {} -- find by data ID Nenue@0: Tracker.BlockInfo = {} -- find by block ID Nenue@0: Tracker.LogInfo = {} -- find by log ID (quest log mainly) Nenue@0: Tracker.WatchBlock = {} Nenue@2: Tracker.WatchInfo = {} Nenue@0: Tracker.LogBlock = {} Nenue@0: Nenue@0: Nenue@0: Nenue@0: Tracker.GetBlock = function(handler, blockIndex) Nenue@0: local block = handler.usedBlocks[blockIndex] Nenue@0: if not handler.usedBlocks[blockIndex] then Nenue@0: if #handler.freeBlocks >= 1 then Nenue@0: block = handler.freeBlocks[#handler.freeBlocks] Nenue@0: handler.freeBlocks[#handler.freeBlocks] = nil Nenue@0: else Nenue@0: block = CreateFrame('Frame', 'Veneer'..tostring(handler)..'Block'..blockIndex, Scroll, 'VeneerTrackerBlock') Nenue@0: block.SetStyle = mod.SetBlockStyle Nenue@0: block:ClearAllPoints() -- making sure the anchors are clear in case they get added for some other template usage Nenue@0: end Nenue@0: Nenue@0: handler.usedBlocks[blockIndex] = block Nenue@0: end Nenue@0: return handler.usedBlocks[blockIndex] Nenue@0: end Nenue@0: local SmallEvents = { Nenue@2: QUEST_ACCEPTED = 'OnQuestAccepted', Nenue@2: QUEST_REMOVED = 'OnQuestRemoved' Nenue@0: } Nenue@0: Nenue@0: local HandlerEvents = { Nenue@0: QUEST_ACCEPTED = mod.Quest, Nenue@2: QUEST_REMOVED = mod.Quest, Nenue@0: QUEST_WATCH_LIST_CHANGED = mod.Quest, Nenue@0: SUPER_TRACKED_QUEST_CHANGED = mod.Quest, Nenue@0: QUEST_LOG_UPDATE = mod.Quest, Nenue@0: TRACKED_ACHIEVEMENT_LIST_CHANGED = mod.Cheevs, Nenue@0: TRACKED_ACHIEVEMENT_UPDATE = mod.Cheevs Nenue@0: } Nenue@0: Nenue@0: function mod:OnEvent (event, ...) Nenue@0: local isHandled Nenue@0: if SmallEvents[event] then Nenue@0: print('|cFF00FF00'..SmallEvents[event]..'(' ..event..'|r', ...) Nenue@0: mod[SmallEvents[event]](event, ...) Nenue@0: isHandled = true Nenue@0: end Nenue@0: if HandlerEvents[event] then Nenue@0: print('|cFF0088FF'..event..'|r wrapper update') Nenue@0: mod.UpdateWrapper() Nenue@0: isHandled = true Nenue@0: end Nenue@0: if not isHandled then Nenue@0: print('|cFFFF4400'..event..'|r', ...) Nenue@0: end Nenue@0: --@debug@ Nenue@0: if Devian and Devian.InWorkspace() then Nenue@0: frame_guide_init(Scroller) Nenue@0: frame_guide(Scroller, Scroller) Nenue@0: end Nenue@0: end Nenue@0: Nenue@2: mod.SetEvents = function() Nenue@2: Nenue@0: for event, _ in pairs(SmallEvents) do Nenue@2: mod:RegisterEvent(event) Nenue@0: end Nenue@1: Nenue@0: for event, _ in pairs(HandlerEvents) do Nenue@2: mod:RegisterEvent(event) Nenue@0: end Nenue@2: mod:SetScript('OnEvent', mod.OnEvent) Nenue@2: end Nenue@0: Nenue@2: function mod:OnInitialize() Nenue@2: self.InitializeTrackers() Nenue@2: Nenue@2: mod.SetEvents() Nenue@0: ObjectiveTrackerFrame:UnregisterAllEvents() Nenue@0: ObjectiveTrackerFrame:Hide() Nenue@2: Nenue@0: end Nenue@0: Nenue@0: --[[ Nenue@0: QUESTLINE_UPDATE This event is not yet documented Nenue@0: QUESTTASK_UPDATE This event is not yet documented Nenue@0: QUEST_ACCEPTED Fires when a new quest is added to the player's quest log (which is what happens after a player accepts a quest). Nenue@0: QUEST_ACCEPT_CONFIRM Fires when certain kinds of quests (e.g. NPC escort quests) are started by another member of the player's group Nenue@0: QUEST_AUTOCOMPLETE Fires when a quest is automatically completed (remote handin available) Nenue@0: QUEST_BOSS_EMOTE This event is not yet documented Nenue@0: QUEST_CHOICE_CLOSE This event is not yet documented Nenue@0: QUEST_CHOICE_UPDATE This event is not yet documented Nenue@0: QUEST_COMPLETE Fires when the player is looking at the "Complete" page for a quest, at a questgiver. Nenue@0: QUEST_DETAIL Fires when details of an available quest are presented by a questgiver Nenue@0: QUEST_FINISHED Fires when the player ends interaction with a questgiver or ends a stage of the questgiver dialog Nenue@0: QUEST_GREETING Fires when a questgiver presents a greeting along with a list of active or available quests Nenue@0: QUEST_ITEM_UPDATE Fires when information about items in a questgiver dialog is updated Nenue@0: QUEST_LOG_UPDATE Fires when the game client receives updates relating to the player's quest log (this event is not just related to the quests inside it) Nenue@0: QUEST_POI_UPDATE This event is not yet documented Nenue@0: QUEST_PROGRESS Fires when interacting with a questgiver about an active quest Nenue@0: QUEST_REMOVED This event is not yet documented Nenue@0: QUEST_TURNED_IN Fired when a quest is turned in Nenue@0: QUEST_WATCH_LIST_CHANGED This event is not yet documented Nenue@0: QUEST_WATCH_OBJECTIVES_CHANGED This event is not yet documented Nenue@0: QUEST_WATCH_UPDATE Fires when the player's status regarding a quest's objectives changes, for instance picking up a required object or killing a mob for that quest. All forms of (quest objective) progress changes will trigger this event.] Nenue@0: Nenue@0: TRACKED_ACHIEVEMENT_LIST_CHANGED This event is not yet documented Nenue@0: TRACKED_ACHIEVEMENT_UPDATE Fires when the player's progress changes on an achievement marked for watching in the objectives tracker Nenue@0: ]]