Nenue@33: -- WorldPlan Nenue@33: -- WorldQuests.lua Nenue@33: -- Created: 11/2/2016 3:40 PM Nenue@33: -- %file-revision% Nenue@72: Nenue@72: local print = DEVIAN_WORKSPACE and function(...) _G.print('WorldQuests', ...) end or function() end Nenue@72: local rprint = DEVIAN_WORKSPACE and function(...) _G.print('WQRefresh', ...) end or function() end Nenue@72: local qprint = DEVIAN_WORKSPACE and function(...) _G.print('POI', ...) end or function() end Nenue@72: local wprint = DEVIAN_WORKSPACE and function(...) _G.print('WP', ...) end or function() end Nenue@72: local mprint = DEVIAN_WORKSPACE and function(...) _G.print('Canvas', ...) end or function() end Nenue@40: local _, db = ... Nenue@45: local Module = WorldPlanQuestsMixin Nenue@33: Nick@64: local _G = _G Nenue@72: local type, tostring, tonumber, pairs, ipairs = type, tostring, tonumber, pairs, ipairs Nenue@33: local MC_GetNumZones, MC_GetZoneInfo = C_MapCanvas.GetNumZones, C_MapCanvas.GetZoneInfo Nenue@33: local TQ_GetQuestsForPlayerByMapID = C_TaskQuest.GetQuestsForPlayerByMapID -- This function is not yet documented Nenue@33: local TQ_GetQuestZoneID = C_TaskQuest.GetQuestZoneID Nick@64: local TQ_IsActive = C_TaskQuest.IsActive Nick@64: local pairs, ipairs, tinsert, tremove, wipe = pairs, ipairs, tinsert, tremove, table.wipe Nick@64: local GetTaskInfo, GetTasksTable, HaveQuestData = GetTaskInfo, GetTasksTable, HaveQuestData Nick@64: local GetTime = GetTime Nenue@69: local SpellCanTargetQuest, IsQuestIDValidSpellTarget = SpellCanTargetQuest, IsQuestIDValidSpellTarget Nick@64: local tonumber, abs = tonumber, math.abs Nick@64: local GetQuestLogRewardInfo = GetQuestLogRewardInfo Nick@64: local GetCurrentMapAreaID, GetMapInfo, GetMapNameByID = GetCurrentMapAreaID, GetMapInfo, GetMapNameByID Nenue@72: local GetQuestBountyInfoForMapID, GetQuestLogTitle, GetQuestLogIndexByID, IsQuestComplete = GetQuestBountyInfoForMapID, GetQuestLogTitle, GetQuestLogIndexByID, IsQuestComplete Nenue@72: local IsQuestCriteriaForBounty = IsQuestCriteriaForBounty Nenue@33: Nenue@69: local ToggleButton = {} Nenue@69: local callbacks = {} Nenue@40: local PinBaseIndex = 1200 Nenue@33: local BROKEN_ISLES_ID, DALARAN_ID, AZSUNA_ID, VALSHARAH_ID, HIGHMOUNTAIN_ID, STORMHEIM_ID, SURAMAR_ID, EOA_ID = 1007, 1014, 1015,1018, 1024, 1017, 1033, 1096 Nenue@33: local WORLD_QUEST_MAPS = { [DALARAN_ID] = 'Dalaran70', [AZSUNA_ID] = 'Azsuna', [VALSHARAH_ID] = "Val'sharah", Nenue@33: [HIGHMOUNTAIN_ID] = 'Highmountain', [STORMHEIM_ID] = 'Stormheim', [SURAMAR_ID] = 'Suramar', [EOA_ID] = 'EyeOfAszhara', } Nenue@33: Nenue@33: local REWARD_CASH = WORLD_QUEST_REWARD_TYPE_FLAG_GOLD Nenue@33: local REWARD_ARTIFACT_POWER = WORLD_QUEST_REWARD_TYPE_FLAG_ARTIFACT_POWER Nenue@33: local REWARD_GEAR = WORLD_QUEST_REWARD_TYPE_FLAG_EQUIPMENT Nenue@33: local REWARD_CURRENCY = WORLD_QUEST_REWARD_TYPE_FLAG_ORDER_RESOURCES Nenue@33: local REWARD_REAGENT = WORLD_QUEST_REWARD_TYPE_FLAG_MATERIALS Nenue@72: local SCALE_FACTORS = { 0.25, 0.7, 1 } Nenue@33: Nenue@72: local BountyBoard = WorldMapFrame.UIElementsFrame.BountyBoard Nenue@72: local ActionButton = WorldMapFrame.UIElementsFrame.ActionButton Nenue@72: Nenue@72: local layoutDirty = true Nenue@72: local bountiesDirty = true Nenue@69: local currentScale = WorldMapDetailFrame:GetScale() Nenue@69: local canTargetQuests Nenue@65: local numShown = 0 Nenue@65: local numLoaded = 0 Nenue@69: local isDataLoaded = true Nenue@69: local numOverlays = 1 Nenue@66: local scaleConstant = 1 Nenue@45: Module.TasksByID = {} Nenue@33: Nenue@33: --%debug% Nenue@33: local SetTimedCallbackForAllPins = function(seconds, callback) Nenue@33: C_Timer.After(seconds, function() Nenue@33: for id, pin in pairs(WorldPlanQuests.QuestsByID) do Nenue@33: callback(pin) Nenue@33: end Nenue@33: end) Nenue@33: end Nenue@33: Nenue@45: function Module:OnUpdate(sinceLast) Nenue@67: Nenue@67: if self.filtersDirty or self.isStale then Nenue@40: self:Refresh() Nenue@40: end Nenue@67: if #db.UpdatedPins >= 1 then Nenue@67: print('|cFF00FF88pending updates', #db.UpdatedPins) Nenue@72: self:RefreshIfQueued() Nenue@67: end Nenue@67: Nenue@40: end Nenue@40: Nenue@52: Nenue@45: function Module:Setup() Nenue@40: print('|cFFFF4400'..self:GetName()..':Setup()') Nenue@33: for mapID, mapName in pairs(WORLD_QUEST_MAPS) do Nenue@40: db.QuestsByZone[mapID] = {} Nenue@33: end Nenue@69: for target, arg in pairs(callbacks) do Nenue@69: print(type(target)) Nenue@69: if type(target) == 'table' then Nenue@71: local callerName = target:GetName() or tostring(target) Nenue@69: for name, method in pairs(arg) do Nenue@69: print(callerName, arg) Nenue@69: hooksecurefunc(target, name, function(...) Nenue@71: self:OnSecureHook(callerName .. '.' .. name, method, ...) Nenue@69: end) Nenue@69: end Nenue@69: else Nenue@69: hooksecurefunc(target, function(...) Nenue@69: self:OnSecureHook(target, arg, ...) Nenue@69: end) Nenue@69: end Nenue@69: end Nenue@65: Nenue@65: self.Status = CreateFrame('Frame', nil, self) Nenue@65: self.Status:SetPoint('TOPLEFT', WorldMapPOIFrame, 'TOPLEFT', 0, 0) Nenue@65: self.Status:SetPoint('BOTTOMRIGHT', WorldMapPOIFrame, 'TOPRIGHT', 0, -4) Nenue@65: self.Status.t = self.Status:CreateTexture(nil, 'OVERLAY') Nenue@65: self.Status.b = self.Status:CreateTexture(nil, 'BACKGROUND') Nenue@65: self.Status.b:SetColorTexture(0,0,0,.25) Nenue@65: self.Status.b:SetAllPoints(self.Status) Nenue@65: self.Status.t:SetColorTexture(1,1,1,.5) Nenue@65: self.Status.t:SetPoint('TOP') Nenue@65: self.Status.t:SetPoint('BOTTOM') Nenue@65: self.Status.t:SetPoint('LEFT') Nenue@65: local translationEnd, translationStart Nenue@65: self.Status:SetScript('OnUpdate', function(status) Nenue@65: local translateTo Nenue@65: if numLoaded < numShown then Nenue@65: translateTo = numLoaded/numShown * status:GetWidth() Nenue@65: status.t:SetWidth(translateTo) Nenue@65: else Nenue@65: translateTo = numShown * status:GetWidth() Nenue@65: status.t:SetWidth(translateTo) Nenue@65: end Nenue@65: end) Nenue@67: Nenue@67: self:SetAllPoints(WorldMapPOIFrame) Nenue@67: for k,v in pairs( ToggleButton) do Nenue@67: self.Toggle:SetScript(k,v) Nenue@67: end Nenue@72: Nenue@72: self:UpdateBounties('SETUP') Nenue@72: Nenue@67: self:Show() Nenue@67: end Nenue@69: callbacks.ClickWorldMapActionButton = function(WorldQuests) Nenue@69: WorldQuests:GetUsedPOIs() Nenue@69: end Nenue@69: callbacks.WorldMap_UpdateQuestBonusObjectives = function(WorldQuests) Nenue@69: WorldQuests:GetUsedPOIs() Nenue@69: end Nenue@69: callbacks.WorldMapFrame_UpdateMap = function(WorldQuests) Nenue@69: WorldQuests:RefreshIfChanged() Nenue@69: end Nenue@69: callbacks.WorldMapScrollFrame_ReanchorQuestPOIs = function (WorldQuests) Nenue@69: WorldQuests:RefreshIfChanged() Nenue@69: end Nenue@69: Nenue@72: callbacks[BountyBoard] = {} Nenue@72: callbacks[BountyBoard].SetSelectedBountyIndex = function(WorldQuests) Nenue@72: WorldQuests:UpdateBounties('BOUNTY_SELECTED') Nenue@72: WorldQuests:RefreshIfChanged() Nenue@72: end Nenue@67: Nenue@72: callbacks[ActionButton] = {} Nenue@72: callbacks[ActionButton].UpdateCastingState = function(WorldQuests) Nenue@72: WorldQuests:Refresh(true) Nenue@67: end Nenue@67: Nenue@49: function Module:OnConfigUpdate() Nenue@67: print('|cFFFFFF00OnConfigUpdate()|r') Nenue@49: if db.Config.FadeWhileGrouped then Nenue@49: db.PinAlpha = 0.15 Nenue@49: else Nenue@49: db.PinAlpha = 1 Nenue@49: end Nenue@67: Nenue@67: if not db.Config.EnablePins then Nenue@67: for _, pin in pairs(db.QuestsByID) do Nenue@67: pin:SetShown(false) Nenue@67: end Nenue@67: end Nenue@67: Nenue@67: ToggleButton.OnShow(self.Toggle) Nenue@49: end Nenue@49: Nenue@45: local InternalHideButton = function(button, index) Nenue@45: button:Hide() Nenue@45: if button.questID and db.QuestsByID[button.questID] then Nenue@45: if db.QuestsByID[button.questID].used and not db.QuestsByID[button.questID].filtered then Nenue@45: db.QuestsByID[button.questID]:SetShown(true) Nenue@45: end Nenue@45: end Nenue@45: end Nenue@45: local InternalShowButton = function(button, index) Nenue@45: button:Show() Nenue@45: if button.questID and db.QuestsByID[button.questID] then Nenue@45: db.QuestsByID[button.questID]:SetShown(false) Nenue@45: end Nenue@45: end Nenue@33: Nenue@69: db.UsedPOIs = {} Nenue@69: function Module:GetUsedPOIs() Nenue@69: db.canTargetQuests = SpellCanTargetQuest() Nenue@69: local func = db.canTargetQuests and InternalShowButton or InternalHideButton Nenue@69: wipe(db.UsedPOIs) Nenue@45: for i = 1, NUM_WORLDMAP_TASK_POIS do Nenue@45: local button = _G['WorldMapFrameTaskPOI'..i] Nenue@45: if button and button.worldQuest then Nenue@45: func(button, i) Nenue@69: db.UsedPOIs[button.questID] = button Nenue@45: end Nenue@45: end Nenue@45: end Nenue@40: Nenue@69: function Module:OnSecureHook(callbackName, func, ...) Nenue@69: rprint('|cFFFF4400'..callbackName..'|r', ...) Nenue@69: func(self, ...) Nenue@45: end Nenue@40: Nenue@33: local defaults = {} Nenue@40: local REWARD_UNKNOWN = 768 Nenue@45: function Module:OnLoad() Nenue@40: print('|cFFFF4400'..self:GetName()..':OnLoad()') Nenue@33: Nenue@48: self:SetParent(WorldMapPOIFrame) Nenue@33: WorldPlan:AddHandler(self, defaults) Nenue@33: Nenue@33: for areaID, fileName in pairs(WORLD_QUEST_MAPS) do Nenue@40: db.QuestsByZone[areaID] = {} Nenue@33: end Nenue@33: Nenue@41: -- WORLD_MAP_UPDATE and PLAYER_ENTERING_WORLD are passed down from a higher level Nenue@33: self:RegisterEvent('WORLD_QUEST_COMPLETED_BY_SPELL') Nenue@55: self:RegisterEvent('SUPER_TRACKED_QUEST_CHANGED') Nenue@33: self:RegisterEvent('SKILL_LINES_CHANGED') Nick@62: self:RegisterEvent('CURRENT_SPELL_CAST_CHANGED') Nenue@69: self:RegisterEvent('ARTIFACT_UPDATE') Nenue@33: end Nenue@33: Nenue@72: local artifactKnowledgeMultiplier Nenue@65: local superTrackedQuestID Nenue@45: function Module:OnEvent (event, ...) Nenue@40: Nenue@40: print('|cFFFFFF00'..self:GetName()..':OnEvent() '..event..'|r', GetTime(), ...) Nenue@69: if (event == 'QUEST_LOG_UPDATE') then Nenue@69: if self:IsVisible() then Nenue@69: self:Refresh() Nenue@69: else Nenue@40: self.isStale = true Nenue@33: end Nenue@72: Nenue@33: print('WorldMapFrame', WorldMapFrame:IsVisible(), 'hasUpdates:', self.isStale) Nenue@33: elseif event == 'WORLD_QUEST_COMPLETED_BY_SPELL' then Nenue@33: local questID = ... Nenue@40: if questID and db.QuestsByID[questID] then Nenue@40: self:ReleasePin(db.QuestsByID[questID]) Nenue@40: rprint('|cFFFF4400release|r', questID) Nenue@33: end Nenue@65: elseif event == 'SKILL_LINES_CHANGED' or event == 'CURRENT_SPELL_CAST_CHANGED' then Nenue@72: self:Refresh(event) Nenue@59: elseif event == 'ARTIFACT_UPDATE' then Nenue@72: local akCheck = C_ArtifactUI.GetArtifactKnowledgeMultiplier() Nenue@72: if akCheck and (akCheck ~= artifactKnowledgeMultiplier) then Nenue@72: if artifactKnowledgeMultiplier then Nenue@72: print('push artifact knowledge update', artifactKnowledgeMultiplier, 'to', akCheck) Nenue@72: for index, pin in pairs( db.QuestsByID) do Nenue@72: if pin.rewardType == REWARD_ARTIFACT_POWER then Nenue@72: db.log(pin.questID .. ' ' .. tostring(pin.title) .. ' Flagged for artifact power.') Nenue@72: pin.itemNumber = 0 Nenue@72: pin.dataLoaded = nil Nenue@72: end Nenue@69: end Nenue@72: else Nenue@72: Nenue@72: print('artifact knowledge multiplier is known', akCheck) Nick@62: end Nenue@72: artifactKnowledgeMultiplier = akCheck Nenue@59: end Nenue@65: elseif event == 'SUPER_TRACKED_QUEST_CHANGED' then Nenue@65: if superTrackedQuestID and db.QuestsByID[superTrackedQuestID] then Nenue@65: db.QuestsByID[superTrackedQuestID].isStale = true Nenue@65: end Nenue@65: local newID = GetSuperTrackedQuestID() Nenue@65: if newID and db.QuestsByID[newID] then Nenue@65: db.QuestsByID[newID].isStale = true Nenue@65: end Nenue@33: end Nenue@33: end Nenue@33: Nenue@72: Nenue@72: Nenue@72: Nenue@72: local bountyInfo = {} Nenue@72: local bountyDisplayLocation, bountyLockedQuestID, selectedBountyIndex, selectedBountyQuestID Nenue@72: function Module:UpdateBounties(...) Nenue@72: print('|cFF00FF88BountyInfo()|r', ...) Nenue@72: wipe(db.BountiesByFactionID) Nenue@72: Nenue@72: bountiesDirty = nil Nenue@72: db.selectedBounty = nil Nenue@72: selectedBountyIndex = BountyBoard:GetSelectedBountyIndex() Nenue@72: bountyInfo, bountyDisplayLocation, bountyLockedQuestID = GetQuestBountyInfoForMapID(db.currentMapID, bountyInfo) Nenue@72: local numBounties = 0 Nenue@72: for index, data in ipairs(bountyInfo) do Nenue@72: if data.factionID then Nenue@72: numBounties = numBounties + 1 Nenue@72: data.index = index Nenue@72: data.complete = IsQuestComplete(data.questID) Nenue@72: if not data.complete then Nenue@72: db.BountiesByFactionID[data.factionID] = data Nenue@72: if index == selectedBountyIndex then Nenue@72: db.selectedBounty = data Nenue@72: selectedBountyQuestID = data.questID Nenue@72: end Nenue@72: print(' ', index, data.factionID, GetQuestLogTitle(GetQuestLogIndexByID(data.questID)), data.complete, (index == selectedBountyIndex) and 'SELECTED' or '') Nenue@72: end Nenue@72: end Nenue@72: end Nenue@72: Nenue@72: local numUpdated = 0 Nenue@72: local numHidden = 0 Nenue@72: for questID, pin in pairs(db.QuestsByID) do Nenue@72: end Nenue@72: --print(numUpdated, 'changes from Bounty Board ('..tostring(numHidden)..' hidden)') Nenue@72: end Nenue@72: Nenue@72: function Module:OnMapInfo(isBrokenIsle, isZoomedOut, mapAreaID, isNewMap, isMapOpen) Nenue@72: if isNewMap then Nenue@72: print('|cFF00FF88'..self:GetName()..':OnMapInfo()|r, mapAreaID =', mapAreaID,'visible =', isMapOpen, 'changed =', isNewMap) Nenue@72: if isMapOpen then Nenue@72: self:Refresh(true) Nenue@72: else Nenue@72: self.isStale = true Nenue@72: end Nenue@72: else Nenue@72: Nenue@72: rprint('|cFFFFFF00'..self:GetName()..':OnMapInfo()|r, mapAreaID =', mapAreaID,'visible =', isMapOpen, 'changed =', isNewMap) Nenue@72: end Nenue@72: end Nenue@72: Nenue@72: Nenue@40: local totalPins = 0 Nenue@33: local TQ_GetQuestLocation = C_TaskQuest.GetQuestLocation Nenue@45: function Module:AcquirePin (info) Nenue@40: local questID = info.questId Nenue@40: if not questID then Nenue@40: return nil Nenue@40: end Nenue@40: Nenue@40: if not QuestUtils_IsQuestWorldQuest(questID) then Nenue@40: return nil Nenue@40: end Nenue@40: Nenue@49: -- if we're grabbing a pin, the filters need to be checked Nenue@40: local pin = db.QuestsByID[questID] Nenue@33: if not pin then Nenue@40: local numFree = #db.FreePins Nenue@33: if numFree >= 1 then Nenue@40: pin = tremove(db.FreePins, numFree) Nenue@33: --print('|cFF00FF00Re-using', pin:GetName()) Nenue@33: else Nenue@40: totalPins = totalPins + 1 Nenue@69: local name = 'WorldPlanQuestMarker' .. numOverlays Nenue@33: --print('|cFF00FF00Creating', name) Nenue@33: pin = CreateFrame('Frame', name, WorldMapPOIFrame, 'WorldPlanQuestPin') Nenue@33: Nenue@33: pin:SetFrameStrata('HIGH') Nenue@33: pin.GetTypeInfo = function(frame, typeID) Nenue@33: return self:GetTypeInfo(typeID) Nenue@33: end Nenue@40: pin:SetID(totalPins) Nenue@69: numOverlays = numOverlays + 1 Nenue@33: --pin.iconBorder:SetVertexColor(0,0,0,1) Nenue@33: end Nenue@40: pin.questID = questID Nenue@40: pin.worldQuest = true Nenue@40: pin.throttle = 1 Nenue@33: pin.isNew = true Nenue@33: pin.currentWidth = nil Nenue@40: db.QuestsByID[questID] = pin Nenue@40: tinsert(db.UsedPins, pin) Nenue@40: end Nenue@33: Nenue@40: if pin and info then Nenue@40: pin.inProgress = info.inProgress Nenue@40: pin.floor = info.floor Nenue@40: pin.numObjectives = info.numObjectives or 0 Nenue@40: if info.x and info.y then Nenue@40: pin.x = info.x or pin.x Nenue@40: pin.y = info.y or pin.y Nenue@40: rprint('|cFFFF4400coords|r', info.x, info.y) Nenue@40: end Nenue@40: end Nenue@33: Nick@62: if (not pin.dataLoaded) then Nenue@65: local dataLoaded = pin:GetData() Nenue@65: isDataLoaded = (isDataLoaded and dataLoaded) Nick@63: WorldPlan.dataFlush = true Nenue@49: end Nenue@49: Nenue@66: Nick@64: pin.isActive = TQ_IsActive(questID) Nenue@57: pin:CheckFilterRules() Nenue@49: rprint(pin:GetID(), pin.filtered, pin.used) Nenue@49: Nenue@40: return pin Nenue@33: end Nenue@33: Nenue@33: -- remove from index and add it to the recycling heap Nenue@45: function Module:ReleasePin (pin) Nenue@33: Nenue@40: local id = pin.questID Nenue@33: if id then Nenue@40: db.QuestsByID[id] = nil Nenue@40: Nenue@40: for i, zone in pairs(db.QuestsByZone) do Nenue@33: print('-', i, zone[i]) Nenue@33: zone[id] = nil Nenue@33: end Nenue@40: db.TasksByID[id] = nil Nenue@33: end Nick@64: pin.isActive = nil Nick@64: pin.dataLoaded = nil Nick@62: pin:HideFrames() Nenue@40: tinsert(db.FreePins, pin) Nenue@40: Nick@63: WorldPlan.dataFlush = true Nenue@40: print('|cFF00FF00-'.. (pin.mapID and GetMapNameByID(pin.mapID) or '???') ..'|r', id, pin.title) Nenue@33: end Nenue@33: Nenue@72: -- re-anchors and scales pins that have had either of these changed due to data loading delays Nenue@72: function Module:RefreshIfQueued() Nenue@72: print('|cFF00FF88RefreshIfQueued()') Nenue@67: local pin = tremove(db.UpdatedPins) Nenue@67: while pin do Nenue@67: pin:CheckFilterRules() Nenue@67: Nenue@67: local scaleFactor = SCALE_FACTORS[(pin.dataLoaded and not pin.filtered) and scaleConstant or 1] Nenue@67: print(pin.title, pin.dataLoaded and not pin.filtered, scaleFactor) Nenue@71: if pin.used then Nenue@71: pin:SetAnchor(nil, pin.x, pin.y, self.hostWidth, self.hostHeight, scaleFactor) Nenue@71: if pin.isNew then Nenue@71: pin:OnShow() Nenue@71: end Nenue@69: end Nenue@69: Nenue@67: pin = tremove(db.UpdatedPins) Nenue@69: Nenue@67: end Nenue@67: end Nenue@67: Nenue@40: Nenue@72: local msg = '|cFF00FF88WorldQuests:Refresh()|r|cFF00FFFF' Nenue@72: function Module:Refresh(...) Nenue@33: Nenue@72: rprint(msg, ...) Nenue@72: print('|cFF00FF88WorldQuests:Refresh()|r', ...) Nenue@34: if not self:IsVisible() then Nenue@40: print(' not visible, flag for later') Nenue@34: self.isStale = true Nenue@57: return self:MarkAllPins() Nenue@40: end Nenue@67: if not db.Config.EnablePins then Nenue@69: numShown = 0 Nenue@67: return Nenue@67: end Nenue@72: wprint(' '..msg) Nenue@67: Nenue@72: layoutDirty = nil Nenue@72: scaleConstant = db.isContinentMap and 2 or 3 Nenue@72: canTargetQuests = SpellCanTargetQuest() Nenue@67: Nenue@40: for index, pin in pairs(db.QuestsByID) do Nenue@40: pin.used = nil Nenue@40: end Nenue@40: Nenue@69: self:UpdateAnchors() Nenue@72: if bountiesDirty then Nenue@72: print(' bounties dirty, pushing that') Nenue@72: self:UpdateBounties() Nenue@72: bountiesDirty = nil Nenue@72: end Nenue@72: Nick@60: Nenue@69: -- calculate quests shown Nenue@65: numShown = 0 Nenue@65: numLoaded = 0 Nick@60: for questID, pin in pairs(db.QuestsByID) do Nick@60: local oV = pin:IsShown() Nick@60: if pin.used then Nick@60: pin.throttle = 1 Nick@60: if oV == false then Nenue@67: rprint('|cFF00FF00cleanup +|r', questID, pin.title) Nick@60: end Nick@60: pin:SetShown(true) Nenue@65: numShown = numShown + 1 Nenue@65: if pin.dataLoaded then Nenue@65: numLoaded = numLoaded + 1 Nenue@65: end Nenue@65: Nick@60: else Nick@60: if oV == true then Nenue@67: rprint('|cFFFF4400 -|r', questID, pin.title) Nick@60: end Nenue@69: pin.hideReason = "Not used in map area " .. (db.currentMapID) Nick@62: pin:HideFrames() Nick@60: end Nick@60: end Nick@60: Nenue@71: Nenue@71: Nenue@72: print(numShown, 'shown,', numLoaded, 'with data') Nenue@65: if numShown > numLoaded then Nenue@65: self.Status:Show() Nenue@65: end Nenue@65: Nenue@65: Nenue@40: self.isStale = nil Nenue@54: self.sizesDirty = nil Nenue@66: self.isZoomDirty = nil Nenue@40: end Nenue@40: Nenue@69: function Module:RefreshIfChanged() Nenue@69: local scaleCheck = WorldMapDetailFrame:GetScale() Nenue@69: if scaleCheck ~= currentScale then Nenue@72: print('|cFF00FF88RefreshIfChanged()|r map scale updated') Nenue@72: self:Refresh('WORLD_MAP_SCALE_CHANGED') Nenue@69: currentScale = scaleCheck Nenue@72: elseif self.isStale or layoutDirty then Nenue@72: print('|cFF00FF88RefreshIfChanged()|r layout is dirty') Nenue@69: self:Refresh() Nenue@69: end Nenue@69: end Nenue@69: Nenue@40: -- update visibility states of all pins Nenue@57: function Module:MarkAllPins(pins) Nenue@57: print(' |cFFFFFF00'..self:GetName()..':MarkAllPins()|r', pins) Nenue@40: pins = pins or db.QuestsByID Nenue@40: for questID, pin in pairs(pins) do Nenue@40: pin.isStale = true Nenue@40: rprint('|cFF00FF00filter', pin.questID, pin.filtered, 'used:', pin.used) Nenue@40: end Nenue@40: end Nenue@40: Nenue@45: function Module:UpdateQuestButton(info, mapID) Nenue@40: local questID, x, y = info.questId, info.x, info.y Nenue@40: local pin = self:AcquirePin(info) Nenue@40: if not pin then Nenue@34: return Nenue@34: end Nenue@34: Nenue@67: --print(' |- ', pin.questID, pin.title) Nenue@57: rprint('|cFF00FF00update|r', pin.questID, pin.title) Nenue@40: if x and y then Nenue@66: local scaleFactor = SCALE_FACTORS[(pin.dataLoaded and not pin.filtered) and scaleConstant or 1] Nenue@49: pin:SetFrameLevel(PinBaseIndex+pin:GetID()) Nenue@57: pin.owningFrame = WorldMapFrame Nenue@66: pin:SetAnchor(WorldMapPOIFrame, x, y, self.hostWidth, self.hostHeight, scaleFactor) Nenue@54: --tinsert(self.UsedPositions, pin) Nenue@40: end Nenue@66: Nenue@72: Nenue@72: local isCriteria, isBounty Nenue@72: if pin.factionID then Nenue@72: if db.BountiesByFactionID[pin.factionID] then Nenue@72: isCriteria = true Nenue@72: end Nenue@72: if selectedBountyQuestID then Nenue@72: isBounty = IsQuestCriteriaForBounty(pin.questID, selectedBountyQuestID) and true or nil Nenue@72: end Nenue@72: end Nenue@72: Nenue@72: if (pin.isBounty ~= isBounty) or (pin.isCriteria ~= isCriteria) then Nenue@72: print(pin.isBounty, '~=', isBounty) Nenue@72: print(pin.isCriteria, '~=', isCriteria) Nenue@72: pin.isBounty = isBounty Nenue@72: pin.isCriteria = isCriteria Nenue@72: if pin:IsVisible() then Nenue@72: --print(' changed', pin.title) Nenue@72: --numUpdated = numUpdated + 1 Nenue@72: pin:Refresh('BOUNTY_UPDATE') Nenue@72: else Nenue@72: --numHidden = numHidden + 1 Nenue@72: pin.isStale = true Nenue@72: end Nenue@72: layoutDirty = true Nenue@72: end Nenue@72: Nenue@66: if self:IsVisible() and (pin.isStale) then Nenue@57: pin:Refresh() Nenue@54: end Nenue@69: Nenue@40: if mapID then Nenue@40: if not db.QuestsByZone[mapID] then Nenue@40: db.QuestsByZone[mapID] = {} Nenue@40: end Nenue@40: db.QuestsByZone[mapID][questID] = pin Nenue@33: end Nenue@33: end Nenue@33: Nenue@69: -- Updates quest markers in taskInfo while associating them with the given map Nenue@69: function Module:UpdateQuestsForMap(taskInfo, mapID) Nenue@49: rprint('Map', GetMapNameByID(mapID), GetMapNameByID(db.currentMapID)) Nenue@40: for index, info in pairs(taskInfo) do Nenue@40: self:UpdateQuestButton(info, mapID) Nenue@40: end Nenue@40: end Nenue@33: Nenue@69: -- Used to refresh the visible quest markers Nick@60: function Module:UpdateAnchors () Nenue@40: wipe(self.UsedPositions) Nick@60: print(' |cFF00FF00'..self:GetName()..':UpdateAnchors()') Nenue@57: self.hostWidth, self.hostHeight = WorldMapPOIFrame:GetSize() Nenue@40: self.nudgeThrescholdX = 16/self.hostWidth Nenue@40: self.nudgeThrescholdY = 16/self.hostHeight Nenue@67: Nenue@67: rprint('|cFF00FF00'..self:GetName()..':UpdateAnchors()') Nenue@33: local mapFileName, textureHeight, textureWidth, isMicroDungeon, microDungeonMapName = GetMapInfo() Nenue@33: if isMicroDungeon then Nenue@33: return Nenue@33: end Nenue@69: Nenue@65: isDataLoaded = true Nenue@67: local taskInfo = TQ_GetQuestsForPlayerByMapID(db.currentMapID) Nenue@40: if taskInfo then Nenue@69: self:UpdateQuestsForMap(taskInfo, db.currentMapID) Nenue@33: end Nenue@67: local numZones = MC_GetNumZones(db.currentMapID) Nenue@33: if numZones then Nenue@33: for i = 1, numZones do Nenue@67: local mapAreaID = MC_GetZoneInfo(db.currentMapID, i) Nenue@67: local taskInfo = TQ_GetQuestsForPlayerByMapID(mapAreaID, db.currentMapID) Nenue@40: if taskInfo then Nenue@69: self:UpdateQuestsForMap(taskInfo, mapAreaID) Nenue@40: end Nenue@33: end Nenue@33: end Nenue@33: end Nenue@33: Nenue@67: function ToggleButton:OnShow() Nenue@67: self:SetChecked(db.Config.EnablePins and true or false) Nenue@67: end Nenue@67: function ToggleButton:OnClick() Nenue@67: print(self:GetChecked()) Nenue@67: db.Config.EnablePins = self:GetChecked() Nenue@67: _G.WorldPlan:OnConfigUpdate() Nenue@67: end