Mercurial > wow > worldplan
view WorldPlan.lua @ 29:c1612c2c1840
WorldPlan:
- Optimizations to in a lot of areas that should lead to better load-times and snappier world map.
* Responding to quest log and map events by setting flags instead of tailing into the complete works.
* Using a generic getter function for resolving pin visual attributes. and making use of blizzard constants for sanity's sake.
author | Nenue |
---|---|
date | Thu, 27 Oct 2016 13:50:56 -0400 |
parents | 4a7e89bffbcb |
children | 8cb750e79952 |
line wrap: on
line source
-- Veneer -- WorldPlan.lua -- Created: 8/16/2016 8:19 AM -- %file-revision% --[[ Summary: Adds reward icons to the world quest POI markers, and adds said markers to the continent map. Issues: Dalaran quests aren't visible until that map has been specifically viewed by the player. --]] local ICON_UNKNOWN = "Interface\\ICONS\\inv_misc_questionmark" local ICON_MONEY = "Interface\\Buttons\\UI-GroupLoot-Coin-Up" local POI_BORDER_MASK = "Interface\\Minimap\\UI-Minimap-Background" local POI_BORDER_FILL = "Interface\\BUTTONS\\YELLOWORANGE64" local POI_BORDER_BLUE = "Interface\\BUTTONS\\GRADBLUE" local POI_BORDER_RED = "Interface\\BUTTONS\\RedGrad64" local POI_BORDER_YELLOW = "Interface\\BUTTONS\\YELLOWORANGE64" local POI_BORDER_GREEN = "Interface\\BUTTONS\\GREENGRAD64" WorldPlanCore = { defaults = {}, } WorldPlanPOIMixin = {} WorldPlanFilterPinMixin = {} local WorldPlanFlightMapMixin = setmetatable({}, {__tostring = function() return 'FlightMapHandler' end}) local WorldQuests = setmetatable({ QuestsByID = {}, freePins = {} }, {__tostring = function() return 'QuestHandler' end}) local FilterBar = setmetatable({ SummaryHeaders = {} }, {__tostring = function() return 'FilterBar' end}) local WorldPlan = WorldPlanCore local QuestPOI = WorldPlanPOIMixin local FilterPin = WorldPlanFilterPinMixin local WP_VERSION = "1.0" local db local print = DEVIAN_WORKSPACE and function(...) _G.print('WP', ...) end or function() end local qprint = DEVIAN_WORKSPACE and function(...) _G.print('POI', ...) end or function() end local iprint = DEVIAN_WORKSPACE and function(...) _G.print('ItemScan', ...) end or function() end local wqprint = DEVIAN_WORKSPACE and function(...) _G.print('WorldQuests', ...) end or function() end local fbprint = DEVIAN_WORKSPACE and function(...) _G.print('FilterBar', ...) end or function() end local wipe, tremove, tinsert, pairs, floor, tContains = table.wipe, table.remove, table.insert, pairs, floor, tContains local TQ_GetQuestsForPlayerByMapID = C_TaskQuest.GetQuestsForPlayerByMapID -- This function is not yet documented local TQ_GetQuestZoneID = C_TaskQuest.GetQuestZoneID local TQ_IsActive = C_TaskQuest.IsActive local ITEM_QUALITY_COLORS = ITEM_QUALITY_COLORS local WorldMap_DoesWorldQuestInfoPassFilters = WorldMap_DoesWorldQuestInfoPassFilters local QuestMapFrame_IsQuestWorldQuest = QuestMapFrame_IsQuestWorldQuest local GameTooltip = GameTooltip local GetItemIcon = GetItemIcon local GetMapInfo, QuestPOIGetIconInfo = GetMapInfo, QuestPOIGetIconInfo local GetQuestTagInfo, HaveQuestData = GetQuestTagInfo, HaveQuestData local GetNumQuestLogRewards, GetNumQuestLogRewardCurrencies, GetQuestLogRewardMoney = GetNumQuestLogRewards, GetNumQuestLogRewardCurrencies, GetQuestLogRewardMoney local GetQuestLogRewardInfo, GetQuestLogRewardCurrencyInfo, GetMoneyString = GetQuestLogRewardInfo, GetQuestLogRewardCurrencyInfo, GetMoneyString local GetCurrentMapAreaID, GetMapNameByID, GetSuperTrackedQuestID = GetCurrentMapAreaID, GetMapNameByID, GetSuperTrackedQuestID local MC_GetNumZones, MC_GetZoneInfo = C_MapCanvas.GetNumZones, C_MapCanvas.GetZoneInfo local PinBaseIndex = 1600 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 -- maps where we do our own anchors local CONTINENT_MAPS = { [BROKEN_ISLES_ID] = BROKEN_ISLES_ID, } local WORLD_QUEST_MAPS = { [DALARAN_ID] = 'Dalaran70', [AZSUNA_ID] = 'Azsuna', [VALSHARAH_ID] = "Val'sharah", [HIGHMOUNTAIN_ID] = 'Highmountain', [STORMHEIM_ID] = 'Stormheim', [SURAMAR_ID] = 'Suramar', [EOA_ID] = 'EyeOfAszhara', } -- default color templates local ARTIFACT_COLOR = ITEM_QUALITY_COLORS[LE_ITEM_QUALITY_ARTIFACT] local MONEY_COLOR = {hex ='|cFFFFFF00', r=1, g=1, b=0} local COMMON_COLOR = ITEM_QUALITY_COLORS[LE_ITEM_QUALITY_COMMON] local DEFAULT_TYPE = { a = 1, r = 1, g = 1, b = 1, x = 0, y = 0, desaturated = true, pinMask = POI_BORDER_MASK, rewardMask = POI_BORDER_MASK, texture = POI_BORDER_FILL, continent = { PinSize = 18, Border = 3, TrackingBorder = 2, TagSize = 6, TimeleftStage = 3, showNumber = true, }, zone = { PinSize = 22, Border = 3, TrackingBorder = 2, TagSize = 12, TimeleftStage = 3, showNumber = true, }, minimized = { PinSize = 4, Border = 1, TrackingBorder = 2, NoIcon = true, TimeleftStage = 1, showNumber = false, } } local POI_FILTER_STYLE = setmetatable({ continentBorder = 2, zoneBorder = 2, }, {__index = DEFAULT_TYPE}) local defaults = { defaultPinStyle = POI_DEFAULT_TYPE, rewardStyle = POI_REWARD_TYPE, filterStyle = POI_FILTER_STYLE, ShowAllProfessionQuests = false, DisplayContinentSummary = true, DisplayContinentPins = true, NotifyWhenNewQuests = true, EnablePins = true, FadeWhileGrouped = true, } -- Summary header structure local REWARD_CASH = WORLD_QUEST_REWARD_TYPE_FLAG_GOLD local REWARD_ARTIFACT_POWER = WORLD_QUEST_REWARD_TYPE_FLAG_ARTIFACT_POWER local REWARD_GEAR = WORLD_QUEST_REWARD_TYPE_FLAG_EQUIPMENT local REWARD_CURRENCY = WORLD_QUEST_REWARD_TYPE_FLAG_ORDER_RESOURCES local REWARD_REAGENT = WORLD_QUEST_REWARD_TYPE_FLAG_MATERIALS local LE_QUEST_TAG_TYPE_PVP = LE_QUEST_TAG_TYPE_PVP local LE_QUEST_TAG_TYPE_PET_BATTLE = LE_QUEST_TAG_TYPE_PET_BATTLE local LE_QUEST_TAG_TYPE_DUNGEON = LE_QUEST_TAG_TYPE_DUNGEON local LE_QUEST_TAG_TYPE_PROFESSION = LE_QUEST_TAG_TYPE_PROFESSION local LE_QUEST_TAG_TYPE_NORMAL = LE_QUEST_TAG_TYPE_NORMAL local POI_FILTER_OPTIONS = { { label = 'Filters', texture = "Interface\\WorldMap\\WorldMap-Icon" }, { filterKey= 'rewardType', filterValue = REWARD_ARTIFACT_POWER, label = 'Artifact Power', texture = "Interface\\ICONS\\inv_7xp_inscription_talenttome01" }, { filterKey= 'rewardType', filterValue = REWARD_CURRENCY,label = 'Order Resources', texture = "Interface\\ICONS\\inv_misc_elvencoins" }, { filterKey= 'rewardType', filterValue = REWARD_GEAR, label = 'Equipment', texture = "Interface\\ICONS\\garrison_bluearmorupgrade" }, { filterKey= 'rewardType', filterValue = REWARD_REAGENT, label = 'Materials', texture = 1417744 }, { filterKey= 'rewardType', filterValue = REWARD_CASH, label = 'Gold', texture = ICON_MONEY }, { filterKey= 'worldQuestType', filterValue = LE_QUEST_TAG_TYPE_PVP, label = 'PvP', texture = "Interface\\Icons\\Ability_PVP_GladiatorMedallion", spacing = 10 }, { filterKey= 'worldQuestType', filterValue = LE_QUEST_TAG_TYPE_PET_BATTLE, label = 'Pet Battle', texture = "Interface\\Icons\\PetJournalPortrait", }, { filterKey= 'worldQuestType', filterValue = LE_QUEST_TAG_TYPE_DUNGEON, label = 'Dungeon', texture = "Interface\\LFGFRAME\\UI-LFR-PORTRAIT", }, { filterKey= 'worldQuestType', filterValue = LE_QUEST_TAG_TYPE_PROFESSION, label = 'Profession', texture = "Interface\\ICONS\\70_professions_scroll_02", }, } WorldPlanCore.BrokenIsleID = BROKEN_ISLES_ID WorldPlanCore.FilterStyle = POI_FILTER_STYLE WorldPlanCore.FilterOptions = {} WorldPlanCore.UsedFilters = {} -- operating flags local superTrackedID local currentMapName local hasNewQuestPins local isContinentMap local numPins = 0 local QuestsByZone = {} local QuestsByFaction = {} local QuestsByReward = {} local QuestsByTag = {} local QuestsByID = {} local QuestPositions = {} local FilterInclusions = {rewardType = {}, worldQuestType = {}, factionID = {}} local NotificationTypes = {} local ZoneInfo = {} local SummaryHeaders = {} local FreePins = {} local NumPinFrames = 1 local hasPendingQuestData local notifyPlayed local scanner, wmtt, WorldMapPOIFrame WorldPlanCore.QuestsByID = QuestsByID WorldPlanCore.QuestsByZone = QuestsByZone local tasksQueue = {} local function OnNext (func) if #tasksQueue == 0 then _G.WorldPlan:SetScript('OnUpdate', function() local func = tremove(tasksQueue, 1) if func then func() end if #tasksQueue == 0 then _G.WorldPlan:SetScript('OnUpdate', nil) end end) end print('inserting task #', #tasksQueue+1, func) tinsert(tasksQueue, func) end -- combines templates local function DoMixins(frame,...) for i = 1, select('#', ...) do for k,v in pairs(select(i,...)) do frame[k] = v end end return frame end -- update a masked texture without messing up its blending mask local SetMaskedTexture = function(region, file, mask) mask = mask or POI_BORDER_MASK region:SetMask(nil) region:SetTexture(file) region:SetMask(mask) end -- tracking menu toggler local DropDown_OnClick = function(self) local key = self.value if key then if WorldPlanData[key] then WorldPlanData[key] = nil else WorldPlanData[key] = true end end WorldPlan:RefreshAll() end function WorldPlan:print(...) local msg for i = 1, select('#', ...) do msg = (msg and (msg .. ' ') or '') .. tostring(select(i, ...)) end DEFAULT_CHAT_FRAME:AddMessage("|cFF0088FFWorldPlan|r: " .. msg) end function WorldPlan:OnLoad () self.Types = setmetatable({}, { __newindex = function(t, k, v) print('adding type', k) if type(v) == 'table' then v = setmetatable(v, {__index = function(t,k) print('##deferring to default key', k) return DEFAULT_TYPE[k] end}) end rawset(t,k,v) end }) local rgbWhite = {1, 1, 1} self.Types[REWARD_REAGENT] = { r = 0, g = 1, b = 1 } self.Types[REWARD_ARTIFACT_POWER] = { r = 1, g = .25, b = .5, hasNumeric = true, numberRGB = rgbWhite } self.Types[REWARD_GEAR] = { r = .1, g = .2, b = 1 } self.Types[REWARD_CURRENCY] = { r = 1, g = 1, b = 0, hasNumeric = true, numberRGB = rgbWhite, } self.Types[REWARD_CASH] = { r = 0, g = 0, b = 0, } for index, color in pairs(ITEM_QUALITY_COLORS) do self.Types[(index+127)] = { r = color.r, g = color.g, b = color.b, hex = color.hex, } end WorldPlan = self scanner = _G.WorldPlanTooltip wmtt = _G.WorldMapTooltip WorldMapPOIFrame = _G.WorldMapPOIFrame WorldPlan:print('v'..WP_VERSION) self:RegisterEvent("QUESTLINE_UPDATE") self:RegisterEvent("QUEST_LOG_UPDATE") self:RegisterEvent("WORLD_MAP_UPDATE") self:RegisterEvent("WORLD_QUEST_COMPLETED_BY_SPELL") self:RegisterEvent("SUPER_TRACKED_QUEST_CHANGED") self:RegisterEvent("SKILL_LINES_CHANGED") self:RegisterEvent("ARTIFACT_XP_UPDATE") self:RegisterEvent("ADDON_LOADED") self:SetParent(WorldMapFrame) WorldPlan.modules = { WorldQuests, FilterBar, WorldPlanFlightMapMixin, } end function WorldPlan:OnShow() print(self:GetName()..':OnShow()') if self.isStale then self:RefreshAll() end end function WorldPlan:OnEvent (event, ...) print() print(event, self.initialized) if event == 'ADDON_LOADED' then local addon = ... if addon == "Blizzard_FlightMap" then print('do mixin junk') self.OnFlightMapLoaded() end if IsLoggedIn() and not self.initialized then self:Setup() end elseif event == 'WORLD_MAP_UPDATE' then self.currentMapID = GetCurrentMapAreaID() self:RefreshAll() else for i, module in ipairs(self.modules) do if module.OnEvent then print('forwarding to', tostring(module)) module:OnEvent(event, ...) end end end end function WorldPlan:Setup () if not WorldPlanData then WorldPlanData = {key = 0 } end WorldPlanData.key = (WorldPlanData.key or 0) + 1 self.db = WorldPlanData self.db.WorldQuests = self.db.WorldQuests or {} db = self.db for k,v in pairs(defaults) do --[===[@non-debug@ if not db[k] then db[k] = v end --@end-non-debug@]===] --@debug@ db[k] = v --@end-debug@ end self.currentMapID = GetCurrentMapAreaID() for i, module in ipairs(self.modules) do module.db = self.db if module.Setup then module:Setup() end if not module.RegisterEvent then module.RegisterEvent = self.RegisterEvent end end self.initialized = true hooksecurefunc("UIDropDownMenu_Initialize", self.OnDropDownInitialize) end function WorldPlan:GetTypeInfo(typeID) local info, extraInfo if (not typeID) or (not self.Types[typeID]) then qprint('## sent default type') info = DEFAULT_TYPE else qprint('## sent defined type', typeID) info = self.Types[typeID] end if isContinentMap then extraInfo = info.continent qprint('### continent subtype', extraInfo) else extraInfo = info.zone qprint('### zone subtype', extraInfo) end return info, extraInfo end do local timeStates = { {maxSeconds = 60, r=1, g=0.25, b =0, format = function (minutes) return '|cFFFF4400'.. minutes .. 'm' end, }, {maxSeconds = 240, r=1, g=.5, b=0, format = function(minutes) return '|cFFFF4400'.. floor(minutes/60) .. 'h' end, }, {maxSeconds = 1440, r=1, g=1, b=0, format = function(minutes) return '|cFFFFFF00'.. floor(minutes/60) .. 'h' end, }, {maxSeconds = 10081, r=0, g=1, b=0, }, -- 7 days + 1 minute } -- Generates a timeleft string function WorldPlan:GetTimeInfo(timeLeft, limit) limit = limit or #timeStates for index = 1, limit do local state = timeStates[index] if timeLeft <= state.maxSeconds then local text if state.format then text = state.format(timeLeft) end return text, index end end return nil, nil end end function WorldPlan:RefreshAll (forced) if not self.initialized then return end POI_DEFAULT_TYPE = db.defaultPinStyle POI_REWARD_TYPE = db.rewardStyle POI_FILTER_STYLE = db.filterStyle for i, module in ipairs(self.modules) do if module.Reset then print(module, 'Reset()') module:Reset() end end for i, module in ipairs(self.modules) do if module.Refresh then print(module, 'Refresh()') module:Refresh() end end for i, module in ipairs(self.modules) do if module.Cleanup then print(module, 'Cleanup()') module:Cleanup() end end end function WorldPlan:UpdateAnchors () for i, module in ipairs(self.modules) do if module.UpdateAnchors then module:UpdateAnchors() end end end -- insert visual options into the tracking button menu WorldPlan.OnDropDownInitialize = function (self, callback, dropType) if self ~= WorldMapFrameDropDown then return end local db = WorldPlan.db local info = UIDropDownMenu_CreateInfo() info.text = "" info.isTitle = true UIDropDownMenu_AddButton(info) info.text = "|cFF00AAFFWorldPlan|r" info.isTitle = true UIDropDownMenu_AddButton(info) info.isTitle = nil info.disabled = nil info.keepShownOnClick = true info.tooltipOnButton = 1 info.text = "Enable" info.isNotRadio = true info.value = "EnablePins" info.checked = db.EnablePins info.tooltipTitle = "Enable World Quest Overlays" info.tooltipText = "Toggle the detail layers here." info.func = DropDown_OnClick UIDropDownMenu_AddButton(info) info.text = "Display All Profession Quests" info.isNotRadio = true info.value = "ShowAllProfessionQuests" info.checked = db.ShowAllProfessionQuests info.tooltipTitle = "Hidden Quests" info.tooltipText = "Display work order and profession-related quests that are skipped by the default UI." info.func = DropDown_OnClick UIDropDownMenu_AddButton(info) info.text = "Show Continent Pins" info.isNotRadio = true info.value = "DisplayContinentPins" info.checked = db.DisplayContinentPins info.tooltipTitle = "Continent Pins" info.tooltipText = "Display quest pins on the continent map (may get cramped)." info.func = DropDown_OnClick UIDropDownMenu_AddButton(info) info.text = "Show Summary" info.isNotRadio = true info.value = "DisplayContinentSummary" info.tooltipTitle = "Summary Bar" info.tooltipText = "Display a summary of active world quests. Note: requires directly viewing Broken Isle and Dalaran maps to gain complete info." info.checked = db.DisplayContinentSummary info.func = DropDown_OnClick UIDropDownMenu_AddButton(info) info.text = "Fade In Groups" info.isNotRadio = true info.value = "FadeWhileGrouped" info.tooltipTitle = "Group Fade" info.tooltipText = "Reduce pin alpha when grouped, so player dots are easier to see." info.checked = db.DisplayContinentSummary info.func = DropDown_OnClick UIDropDownMenu_AddButton(info) end function WorldQuests:Setup() for mapID, mapName in pairs(WORLD_QUEST_MAPS) do QuestsByZone[mapID] = {} end -- refresh positions any time blizzard does so (i.e. mousewheel zoom) hooksecurefunc("WorldMapScrollFrame_ReanchorQuestPOIs", function() self:Refresh(true) end) -- hide the original world quest POIs hooksecurefunc("WorldMap_UpdateQuestBonusObjectives", function() for i = 1, NUM_WORLDMAP_TASK_POIS do local button = _G['WorldMapFrameTaskPOI'..i] if button and button.worldQuest then button:Hide() end end end) end function WorldQuests:OnEvent (event, ...) print('|cFFFFFF00'..tostring(self)..':OnEvent()'..event..'|r', GetTime(), ...) if event == 'QUEST_LOG_UPDATE' then local questID, added = ... if questID and added then local questPOI = self:AcquirePin(questID) self.hasUpdate, self.isPending = questPOI:RefreshData() else self:RefreshData() end print('WorldMapFrame', WorldMapFrame:IsVisible(), 'doRefresh:', hasNewQuestPins) if WorldMapFrame:IsVisible() and hasNewQuestPins then self:Refresh(true) end elseif event == 'WORLD_QUEST_COMPLETED_BY_SPELL' then local questID = ... if questID and QuestsByID[questID] then self:ReleasePin(QuestsByID[questID]) end elseif event == 'SKILL_LINES_CHANGED' then self:Refresh(true) end end local TQ_GetQuestLocation = C_TaskQuest.GetQuestLocation function WorldQuests:AcquirePin (questID, mapID) local pin = QuestsByID[questID] local isNew = false if not pin then isNew = true local numFree = #self.freePins if numFree >= 1 then pin = tremove(self.freePins, numFree) --print('|cFF00FF00Re-using', pin:GetName()) else local name = 'WorldPlanQuestMarker' .. NumPinFrames --print('|cFF00FF00Creating', name) pin = CreateFrame('Frame', name, WorldMapPOIFrame, 'WorldPlanQuestPin') pin:SetFrameStrata('HIGH') NumPinFrames = NumPinFrames + 1 --pin.iconBorder:SetVertexColor(0,0,0,1) end pin:SetID(questID) pin.isNew = true pin.currentWidth = nil -- used by TaskPOI_x scripts pin.questID = questID pin.worldQuest = true QuestsByID[questID] = pin else --print('|cFF00FF00Using', pin:GetName()) end mapID = mapID or TQ_GetQuestZoneID(questID) QuestsByZone[mapID][questID] = pin return pin, isNew end -- remove from index and add it to the recycling heap function WorldQuests:ReleasePin (pin) local id = pin.questId if id then QuestsByID[id] = nil for i, zone in pairs(QuestsByZone) do print('-', i, zone[i]) zone[id] = nil end end if pin.factionID then QuestsByFaction[pin.factionID][id] = nil end pin:Hide() pin:ClearAllPoints() tinsert(self.freePins, pin) print('|cFFFF4400Clearing out', pin:GetName(),id) end -- create of update quest pins for a map and its underlying zones function WorldQuests:RefreshData (mapID) local print = wqprint mapID = mapID or GetCurrentMapAreaID() superTrackedID = GetSuperTrackedQuestID() if not mapID then -- info not available yet return end if mapID == BROKEN_ISLES_ID then self.hasUpdate = false print('|cFF00FFFFRefreshQuestsForMap|r', mapID, GetMapNameByID(mapID), superTrackedID) self.fullSearch = true for i = 1, MC_GetNumZones(mapID) do local submapID, name, depth = MC_GetZoneInfo(mapID, i) self:RefreshData(submapID) end self.fullSearch = nil elseif QuestsByZone[mapID] then local taskInfo = TQ_GetQuestsForPlayerByMapID(mapID) local quest = QuestsByZone[mapID] local numQuests = 0 if taskInfo and #taskInfo >= 1 then print('|cFF00FFFFRefreshQuestsForMap|r', mapID, GetMapNameByID(mapID), #taskInfo) wipe(QuestsByZone[mapID]) ZoneInfo[mapID] = taskInfo for taskID, info in pairs(taskInfo) do print('-', taskID) local questID = info.questId info.mapID = mapID local questPOI = self:AcquirePin(questID, mapID) local hasUpdate, isPending = questPOI:RefreshData(taskInfo) self.hasUpdate = (self.hasUpdate or hasUpdate) self.isPending = (self.isPending or isPending) numQuests = numQuests + 1 end end end print(' hasUpdate:', self.hasUpdate, 'isPending:', self.isPending, 'timer:', self.OnNext) if self.hasUpdate then self.OnNext = self.OnNext or C_Timer.NewTimer(0.25, function() self:Refresh(true) self.OnNext = nil end) end end function WorldQuests:Refresh(forced) local print = wqprint print('|cFF00FF88'..tostring(self)..':Refresh()|r') if not WorldMapPOIFrame:IsVisible() then return end if forced then self:Reset() end self:UpdateAnchors() if forced then self:Cleanup () end end -- prepares elements for a map update function WorldQuests:Reset () local print = wqprint print('|cFF00FF88'..tostring(self)..':Reset()|r') wipe(QuestPositions) wipe(QuestsByReward) wipe(QuestsByTag) for questID, pin in pairs(QuestsByID) do pin.used = nil end end -- update visibility states of all pins function WorldQuests:UpdateAnchors (submapID) local print = wqprint local db = WorldPlan.db local mapFileName, textureHeight, textureWidth, isMicroDungeon, microDungeonMapName = GetMapInfo() if isMicroDungeon then return end local currentMap = GetCurrentMapAreaID() local submapID = submapID or currentMap if submapID == BROKEN_ISLES_ID and (not db.DisplayContinentPins) then print('not updating map for reasons') return end print('|cFF88FF00'..tostring(self)..':UpdateAnchors|r', submapID, GetMapNameByID(submapID), 'pin count:', numPins) local numZones = MC_GetNumZones(submapID) if numZones then for i = 1, numZones do local subMapID = MC_GetZoneInfo(submapID, i) self:UpdateAnchors(subMapID) end end local pins = QuestsByZone[submapID] if pins then local hostFrame = WorldMapPOIFrame local mapWidth, mapHeight = hostFrame:GetSize() for questID, pin in pairs(pins) do pin:IsShowable() if pin.used then pin:SetFrameLevel(PinBaseIndex+ (pin.whiteListed and 200 or 0) +numPins) print('level', PinBaseIndex+ (pin.whiteListed and 200 or 0) +numPins) pin:SetAnchor(WorldMapPOIFrame, currentMap, mapWidth, mapHeight) numPins = numPins + 1 end end end end -- shows, animates, or hides pins based on their current visibility flags local debug_show = {} local debug_animate = {} local debug_hide = {} function WorldQuests:Cleanup () local print = wqprint local showQuestPOI = db.EnablePins print('|cFFFFFF00'..tostring(self)..':Cleanup()|r') local mapID = GetCurrentMapAreaID() isContinentMap = (mapID == BROKEN_ISLES_ID) wipe(debug_show) wipe(debug_animate) wipe(debug_hide) -- continent or zone sizing local fadeGrouped = (db.FadeWhileGrouped and IsInGroup()) numPins = 0 for questID, pin in pairs(QuestsByID) do -- can we show it? if showQuestPOI and (pin.used) then if fadeGrouped then pin:SetAlpha(0.25) else pin:SetAlpha(1) end -- is it a new quest? if pin.isNew then if not pin.isAnimating then pin.isAnimating = true OnNext(function() pin:ShowNew() end) if not notifyPlayed then for k,v in pairs(NotificationTypes) do if v[pin[k]] then notifyPlayed = true PlaySoundKitID(23404) end end end tinsert(debug_animate,questID) else print('animating? ', questID, 'filtered:', pin.filtered) end -- trap new but animating pins here else -- hard show existing pin print('refresh #', questID, 'filtered:', pin.filtered) pin.hasUpdate = true pin:Show(true) tinsert(debug_show,questID) end else if pin:IsShown() then tinsert(debug_hide,questID) end pin.isAnimating = nil pin.FadeIn:Stop() pin:Hide() end end print(' adding:', table.concat(debug_animate, ',' )) print(' refresh:', table.concat(debug_show, ',' )) print(' hiding:', table.concat(debug_hide, ',' )) hasNewQuestPins = nil notifyPlayed = nil end -- data provider manipulations for the taxi map WorldPlan.OnFlightMapLoaded = function() if true then return end -- todo: figure out how to layer inside the map canvas local res = {} local t = {} for k,v in pairs(FlightMapFrame) do tinsert(res, tostring(k)) end table.sort(res) for i, k in ipairs(res) do print(k) end hooksecurefunc(FlightMapFrame, 'RefreshAll', function(self) print('|cFF0088FFWQDP RefreshAllData ', GetTime()) WorldPlan:GetPinsForMap(self:GetMapID()) for pin in self:EnumerateAllPins() do if pin.worldQuest then --print('got pin #', pin.questID) local wp = QuestsByID[pin.questID] if wp then wp:ClearAllPoints() wp:SetParent(FlightMapFrame.ScrollContainer) wp:SetFrameStrata('MEDIUM') wp:SetPoint('CENTER', pin, 'CENTER') wp:Show() end end end end) end local throttle = 0 local tooltip = CreateFrame ("GameTooltip", "VeneerWorldQuestsScanner", nil, "GameTooltipTemplate") local tooltipLine1 = _G['VeneerWorldQuestsScannerTextLeft1'] local tooltipLine3 = _G['VeneerWorldQuestsScannerTextLeft3'] local GetTime, mod = GetTime, mod function WorldQuests:FilterCheckByID(questID) local pin = WorldQuests:GetPinByQuestID(questID) return pin:IsShowable() end function QuestPOI:IsShowable () local print = wqprint local db = WorldPlan.db local qType = self.worldQuestType local rType = self.rewardType self.filtered = nil self.used = true print(' |cFFFF4400IsShowable()|r', self.title) local isIncluded for filterKey, filterValues in pairs(WorldPlan.UsedFilters) do local controlValue = self[filterKey] if controlValue then local filterType = filterValues[controlValue] if filterType == true then isIncluded = true print(' include? ', filterKey, controlValue, filterType) end end self.filtered = (not isIncluded) end if not TQ_IsActive(self.questID) then self.used = nil end if qType == LE_QUEST_TAG_TYPE_PROFESSION then if not (db.ShowAllProfessionQuests or (self.tradeskillLineIndex and GetProfessionInfo(self.tradeskillLineIndex))) then self.used = nil end end return self.used, self.filtered end function QuestPOI:UpdateTimer (timeLeft, timeType) print('|cFF0088FFUpdatePinTimer()|r') end --- Fixes icons upon size update function QuestPOI:UpdateSize (style, subStyle) self.style = self.style or POI_DEFAULT_TYPE style = style or self.style subStyle = subStyle or self.subStyle qprint('|cFF00FF88'..self:GetName()..'|r:UpdateSize()', style, subStyle) self.currentWidth = subStyle.PinSize self.borderSize = subStyle.Border self.trackingBorderSize = subStyle.TrackingBorder self.tagSize = subStyle.TagSize self.TimeleftStage = subStyle.TimeleftStage self.NoIcon = subStyle.NoIcon self:SetSize(self.currentWidth, self.currentWidth) local icon = self.icon local iconBorder = self.iconBorder local trackingBorder = self.supertrackBorder local tag = self.tagIcon local pinMask = style.pinMask local rewardMask = style.rewardMask if self.NoIcon then self.icon:Hide() else self.icon:Show() icon:SetMask(nil) icon:SetMask(rewardMask) icon:SetTexture(self.icon:GetTexture()) end iconBorder:SetMask(nil) trackingBorder:SetMask(nil) local borderWidth = self.borderSize local trackingWidth = self.trackingBorderSize iconBorder:ClearAllPoints() iconBorder:SetPoint('BOTTOMLEFT', self, 'BOTTOMLEFT', -borderWidth + (style.x or 0), -borderWidth + (style.y or 0)) iconBorder:SetPoint('TOPRIGHT', self, 'TOPRIGHT', borderWidth + (style.x or 0), borderWidth + (style.y or 0)) trackingBorder:ClearAllPoints() trackingBorder:SetPoint('BOTTOMLEFT', iconBorder, 'BOTTOMLEFT', -trackingWidth, -trackingWidth) trackingBorder:SetPoint('TOPRIGHT', iconBorder, 'TOPRIGHT', trackingWidth, trackingWidth) if self.tagSize then tag:Show() tag:ClearAllPoints() tag:SetPoint('BOTTOMRIGHT', self, 'BOTTOMRIGHT', borderWidth, -borderWidth) else tag:Hide() end --qprint('using mask:', mask, self.name ) iconBorder:SetMask(pinMask) trackingBorder:SetMask(pinMask) end function FilterBar:OnEvent(event) if event == 'QUEST_LOG_UPDATE' then self:Refresh() end end function FilterBar:PassesFilterSet(filterKey, pin) local passesFilter = true for filterKey, filters in pairs(QuestFilters) do for rewardType, value in pairs(QuestFilters[filterKey]) do if value == 1 and rewardType == pin[filterKey] then passesFilter = true elseif value == -1 and rewardType == pin[filterKey] then passesFilter = false end end end return passesFilter end local bountyIndex local debug_headers = {} function FilterBar:Setup() self:GetFilters() end function FilterBar:OnEvent(event,...) if event == 'QUEST_LOG_UPDATE' then self:Reset() self:Refresh() end end function FilterBar:GetFilters() local print = fbprint wipe(WorldPlan.FilterOptions) for index, info in ipairs(POI_FILTER_OPTIONS) do tinsert(WorldPlan.FilterOptions, info) end self.bounties, self.numBounties = GetQuestBountyInfoForMapID(WorldPlan.currentMapID) self.BountyFilters = {} for index, data in ipairs(self.bounties) do local info = self.BountyFilters[index] if not info then info = {} self.BountyFilters[index] = info end local questTitle = GetQuestLogTitle(GetQuestLogIndexByID(data.questID)) info.filterKey = 'factionID' info.filterValue = data.factionID info.label = questTitle info.texture = data.icon print('loading emissary', questTitle) tinsert(WorldPlan.FilterOptions, info) --{ filterKey= 'worldQuestType', filterValue = LE_QUEST_TAG_TYPE_PROFESSION, label = 'Profession', texture = "Interface\\LFGFRAME\\UI-LFR-PORTRAIT", }, end end function FilterBar:Reset() self:GetFilters() end function FilterBar:Refresh(forced) local print = fbprint local blocks = self.SummaryHeaders local relativeFrame = WorldMapFrame.UIElementsFrame.TrackingOptionsButton local numHeaders = 0 print('|cFF00FF88'..tostring(self)..':Refresh()|r', 'currentMap=',WorldPlan.currentMapID) local quests = QuestsByZone[WorldPlan.currentMapID] or QuestsByID for index, info in ipairs(WorldPlan.FilterOptions) do local numQuests = 0 for questID, pin in pairs(quests) do if pin.used then if not info.filterKey then numQuests = numQuests + 1 elseif pin[info.filterKey] == info.filterValue then numQuests = numQuests + 1 end end end print(tostring(index).. ' ("'..tostring(info.label)..'" f('.. tostring(info.filterKey).. '='..tostring(info.filterValue) .. '), '..tostring(numQuests)..')') if numQuests >= 1 then numHeaders = numHeaders + 1 local button = blocks[numHeaders] if not blocks[numHeaders] then button = CreateFrame('Button', 'WorldPlanFilterButton'..numHeaders, WorldMapScrollFrame, 'WorldPlanFilterPin') for k,v in pairs(info)do print(k,v) end button.iconBorder:SetTexture(info.fill or POI_BORDER_FILL) button.iconBorder:SetMask(info.mask or POI_BORDER_MASK) button.iconBorder:SetDesaturated(info.desaturated) button.supertrackBorder:SetTexture(info.fill or POI_BORDER_FILL) button.supertrackBorder:SetMask(info.mask or POI_BORDER_MASK) button.supertrackBorder:SetDesaturated(true) blocks[numHeaders] = button end button:SetID(index) button.spacing = ((info.filterKey ~= relativeFrame.filterKey) and 10) or 0 button.relativeFrame = relativeFrame button:Refresh(info, (numHeaders == 1), numQuests) button:Show() relativeFrame = button end end self.numHeaders = numHeaders for i = numHeaders + 1, #WorldPlan.FilterOptions do if self.SummaryHeaders[i] then self.SummaryHeaders[i]:Hide() end end end function FilterBar:Cleanup() -- hide trailing buttons end function FilterPin:Refresh(info, isFirst, numQuests) local print = fbprint isFirst = isFirst or self.isFirst numQuests = numQuests or self.numQuests if info then self.isFirst = isFirst self.numQuests = numQuests self.filterKey = info.filterKey self.filterValue = info.filterValue self.tagID = info.tagID self.icon:ClearAllPoints() self.icon:SetTexture(info.texture) self.icon:SetAllPoints(self) self.supertrackBorder:Hide() self.count:SetText(numQuests) self:Show() end self.itemTexture = self.texture if isFirst then self:SetPoint('TOP', self.relativeFrame, 'BOTTOM', 0, -5) else self:SetPoint('TOPRIGHT', self.relativeFrame, 'BOTTOMRIGHT', 0, -(3*2 + 1 + (self.spacing or 0))) end print('anchor to', self.relativeFrame:GetName()) local r, g, b, a = 1,1,1,1 local used = WorldPlan.UsedFilters[self.filterKey] if used and self.filterKey then if used[self.filterValue] == true then r, g, b = 0, 1, 0 elseif used[self.filterValue] == false then r, g, b = 1, 0, 0 end end self.iconBorder:SetVertexColor(r, g, b, a) self:UpdateSize() end function FilterPin:OnLoad() self:RegisterForClicks('AnyUp') self:SetFrameStrata('HIGH') self:SetFrameLevel(151) self:SetScript('OnUpdate', nil) self.style = db.filterStyle self.subStyle = db.defaultPinStyle.continent end function FilterPin:OnUpdate () end function FilterPin:OnLeave () if GameTooltip:IsOwned(self) then GameTooltip:Hide() end end -- shift-click: reset filter -- click: rotate through include(1), exclude(-1), ignore(nil) function FilterPin:OnClick (button) local print = fbprint local filterKey = self.filterKey local filterValue = self.filterValue local operation = opPrefix local setInclude = (button == 'LeftButton') if not filterKey then -- resetting wipe(WorldPlan.UsedFilters) elseif IsShiftKeyDown() then WorldPlan.UsedFilters[filterKey] = nil else WorldPlan.UsedFilters[filterKey] = WorldPlan.UsedFilters[filterKey] or {} WorldPlan.UsedFilters[filterKey][filterValue] = setInclude print(filterKey, filterValue, '=', setInclude) for index, info in ipairs(WorldPlan.FilterOptions) do if info.filterKey == filterKey then if (not IsControlKeyDown()) and (filterValue ~= info.filterValue) then WorldPlan.UsedFilters[filterKey][info.filterValue] = (not setInclude) print(filterKey, info.filterValue, '=', WorldPlan.UsedFilters[filterKey][info.filterValue]) end end end end print('|cFF00FF88Filter Update:', filterKey, filterValue, operation) WorldPlan:RefreshAll() end --%debug% local SetTimedCallbackForAllPins = function(seconds, callback) C_Timer.After(seconds, function() for id, pin in pairs(QuestsByID) do callback(pin) end end) end SLASH_WORLDPLAN1 = "/worldplan" SLASH_WORLDPLAN2 = "/wp" SlashCmdList.WORLDPLAN = function() print('command pop') WorldPlan:GetPinsForMap() WorldPlan:RefreshPins() SetTimedCallbackForAllPins(0, function(self) self.FadeIn:Play() self.FlashIn:Play() end) SetTimedCallbackForAllPins(5, function(self) self.PendingFade:Play() end) SetTimedCallbackForAllPins(8, function(self) self.PendingFade:Stop() end) end --%end-debug%