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