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@0: WorldPlanCore = {} 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_GetQuestInfoByQuestID = C_TaskQuest.GetQuestInfoByQuestID -- Return the name of a quest with a given ID Nenue@0: local TQ_GetQuestsForPlayerByMapID = C_TaskQuest.GetQuestsForPlayerByMapID -- This function is not yet documented Nenue@0: local TQ_GetQuestTimeLeftMinutes = C_TaskQuest.GetQuestTimeLeftMinutes Nenue@0: local TQ_RequestPreloadRewardData = C_TaskQuest.RequestPreloadRewardData Nenue@0: local TQ_GetQuestLocation = C_TaskQuest.GetQuestLocation 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@0: Nenue@0: local ICON_UNKNOWN = "Interface\\ICONS\\inv_misc_questionmark" Nenue@0: local ICON_MONEY = "Interface\\Buttons\\UI-GroupLoot-Coin-Up" Nenue@0: Nenue@0: local POI_BORDER_MASK = "Interface\\Minimap\\UI-Minimap-Background" Nenue@0: local POI_BORDER_FILL = "Interface\\BUTTONS\\YELLOWORANGE64" Nenue@0: local POI_BORDER_BLUE = "Interface\\BUTTONS\\GRADBLUE" Nenue@0: local POI_BORDER_RED = "Interface\\BUTTONS\\RedGrad64" Nenue@0: local POI_BORDER_YELLOW = "Interface\\BUTTONS\\YELLOWORANGE64" Nenue@0: local POI_BORDER_GREEN = "Interface\\BUTTONS\\GREENGRAD64" Nenue@0: Nenue@0: local REWARD_CASH = 1001 Nenue@0: local REWARD_ARTIFACT_POWER = 1002 Nenue@0: local REWARD_GEAR = 1003 Nenue@0: local REWARD_CURRENCY = 1004 Nenue@0: local REWARD_ITEM = 1005 Nenue@0: local REWARD_REAGENT = 1006 Nenue@0: Nenue@0: local POI_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@0: mask = 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@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@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@0: } Nenue@0: } Nenue@0: local POI_REWARD_TYPE = setmetatable({}, { Nenue@0: __newindex = function(t, k, v) Nenue@0: if type(v) == 'table' then Nenue@0: setmetatable(v, {__index = POI_DEFAULT_TYPE}) Nenue@0: end Nenue@0: rawset(t,k,v) Nenue@0: end Nenue@0: }) Nenue@0: local POI_FILTER_STYLE = setmetatable({ Nenue@0: continentBorder = 2, Nenue@0: zoneBorder = 2, Nenue@0: }, {__index = POI_DEFAULT_TYPE}) Nenue@0: Nenue@0: local LE_QUEST_TAG_TYPE_PVP = LE_QUEST_TAG_TYPE_PVP Nenue@0: local LE_QUEST_TAG_TYPE_PET_BATTLE = LE_QUEST_TAG_TYPE_PET_BATTLE Nenue@0: local LE_QUEST_TAG_TYPE_DUNGEON = LE_QUEST_TAG_TYPE_DUNGEON Nenue@0: local LE_QUEST_TAG_TYPE_PROFESSION = LE_QUEST_TAG_TYPE_PROFESSION Nenue@0: local LE_QUEST_TAG_TYPE_NORMAL = LE_QUEST_TAG_TYPE_NORMAL Nenue@0: Nenue@0: -- Pin color/display variables Nenue@0: POI_REWARD_TYPE[REWARD_ITEM] = { Nenue@0: r = 1, g = 1, b = 1, Nenue@0: } Nenue@0: POI_REWARD_TYPE[REWARD_REAGENT] = { Nenue@0: r = 0, g = 1, b = 1, Nenue@0: } Nenue@0: POI_REWARD_TYPE[REWARD_ARTIFACT_POWER] = { Nenue@0: r = 1, g = .25, b = .5, Nenue@0: showNumber = true, Nenue@0: } Nenue@0: POI_REWARD_TYPE[REWARD_GEAR] = { Nenue@0: r = .1, g = .2, b = 1, Nenue@0: } Nenue@0: POI_REWARD_TYPE[REWARD_CURRENCY] = { Nenue@0: r = 1, g = 1, b = 0, Nenue@0: } Nenue@0: POI_REWARD_TYPE[REWARD_CASH] = { Nenue@0: r = 0, g = 0, b = 0, Nenue@0: --x = 0, y = -1, Nenue@0: --mask = ICON_MONEY, Nenue@0: --continentBorder = 1, Nenue@0: --zoneBorder = 1, Nenue@0: } Nenue@0: 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@9: ShowAllProfessionQuests = true, 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@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@0: { filterKey= 'rewardType', filterValue = REWARD_CURRENCY,label = 'Currency', texture = "Interface\\ICONS\\inv_misc_elvencoins" }, Nenue@0: { filterKey= 'rewardType', filterValue = REWARD_ITEM, label = 'Item', texture = "Interface\\ICONS\\inv_crate_01" }, Nenue@0: { filterKey= 'rewardType', filterValue = REWARD_GEAR, label = 'Equipment', texture = "Interface\\ICONS\\garrison_bluearmorupgrade" }, Nenue@0: { filterKey= 'rewardType', filterValue = REWARD_REAGENT, label = 'Reagents', texture = 1417744 }, Nenue@0: { filterKey= 'rewardType', filterValue = REWARD_CASH, label = 'Reagents', 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@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@9: local FilterExclusions = {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@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: -- use tooltip object to extract item details Nenue@0: local ParseItemReward = function(questID) Nenue@0: local rewardType = REWARD_ITEM Nenue@0: local name, icon, quantity, quality, _, itemID = GetQuestLogRewardInfo(1, questID) Nenue@0: if not itemID then Nenue@0: return REWARD_ITEM Nenue@0: end Nenue@0: Nenue@0: scanner:SetOwner(WorldPlan, "ANCHOR_NONE") Nenue@0: scanner:SetItemByID(itemID) Nenue@0: local ttl1 = _G['WorldPlanTooltipTextLeft1'] Nenue@0: local ttl2 = _G['WorldPlanTooltipTextLeft2'] Nenue@0: local ttl3 = _G['WorldPlanTooltipTextLeft3'] Nenue@0: local ttl4 = _G['WorldPlanTooltipTextLeft4'] Nenue@0: if ttl2 then Nenue@0: local text = ttl2:GetText() Nenue@0: -- Artifact Power Nenue@0: if text and text:match("|cFFE6CC80") then Nenue@0: --print('AP token!', text) Nenue@0: local power Nenue@0: if ttl4 then Nenue@0: local text = ttl4:GetText() Nenue@0: --print('tip line 4', text) Nenue@0: if text then Nenue@0: power = text:gsub("%p", ""):match("%d+") Nenue@0: power = tonumber(power) Nenue@0: end Nenue@0: Nenue@0: end Nenue@0: rewardType = REWARD_ARTIFACT_POWER Nenue@0: icon = "Interface\\ICONS\\inv_7xp_inscription_talenttome01" Nenue@0: quantity = power Nenue@0: elseif text and text:match("Item Level") then Nenue@0: --print('equipment!', text) Nenue@0: rewardType = REWARD_GEAR Nenue@0: quantity = text:match("Item Level ([%d\+]+)") Nenue@0: end Nenue@0: end Nenue@0: if ttl3 then Nenue@0: local text = ttl3:GetText() Nenue@0: -- Crafting Reagent Nenue@0: if text and text:match("Crafting Reagent") then Nenue@0: --print('reagent', text) Nenue@0: rewardType = REWARD_REAGENT Nenue@0: end Nenue@0: end Nenue@0: iprint(' item:', name, rewardType, icon, quantity) Nenue@0: return rewardType, icon, quantity, name, itemID Nenue@0: end 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@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@0: Nenue@0: WorldPlan.modules = { Nenue@0: WorldQuests, FilterBar, WorldPlanFlightMapMixin, Nenue@0: } Nenue@0: end Nenue@0: Nenue@0: function WorldPlan:OnEvent (event, ...) Nenue@0: print() Nenue@0: print(event, ...) 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@0: end Nenue@0: for i, module in ipairs(self.modules) do Nenue@0: if module.OnEvent then Nenue@0: print('forwarding to', tostring(module)) Nenue@0: module:OnEvent(event, ...) 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@9: db[k] = v 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@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@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@0: print('|cFFFFFF00'..tostring(self)..':OnEvent()'..event..'|r', ...) Nenue@0: if event == 'QUEST_LOG_UPDATE' then Nenue@0: local questID, added = ... Nenue@0: if questID and added then Nenue@0: self:GetPinByQuestID(questID) Nenue@0: else Nenue@0: self:GetPinsForMap() Nenue@0: end 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@0: Nenue@0: function WorldQuests:AcquirePin (questID, pinTable) 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@0: pin:SetFrameStrata('HIGH') Nenue@0: Nenue@0: NumPinFrames = NumPinFrames + 1 Nenue@0: Nenue@0: --pin.iconBorder:SetVertexColor(0,0,0,1) Nenue@0: Nenue@0: end Nenue@0: QuestsByID[questID] = pin 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@7: pin.Reset = function(self) Nenue@7: WorldQuests:GetPinByQuestID(questID) Nenue@7: end Nenue@0: else Nenue@0: --print('|cFF00FF00Using', pin:GetName()) Nenue@0: end Nenue@0: Nenue@0: -- set display flags accordingly Nenue@0: if pinTable then Nenue@0: for k,v in pairs(pinTable) do Nenue@0: pin[k] = v Nenue@0: end Nenue@0: end Nenue@0: pin.throttle = nil Nenue@0: pin.timeThreschold = nil 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@0: function WorldQuests:GetPinsForMap (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@0: hasPendingQuestData = nil 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@0: self:GetPinsForMap(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@0: local questID = info.questId Nenue@0: Nenue@0: info.mapID = mapID Nenue@0: QuestsByZone[mapID][questID] = self:GetPinByQuestID(questID, info) Nenue@0: numQuests = numQuests + 1 Nenue@0: end Nenue@0: end Nenue@0: end Nenue@0: if hasNewQuestPins and not self.fullSearch then Nenue@0: print('|cFF00FF00NEW PINS DO ANCHOR THINGS') Nenue@9: self:Refresh (true) Nenue@0: hasNewQuestPins = nil Nenue@0: end Nenue@0: end Nenue@0: Nenue@0: -- create or update the pin using the given questID and C_TaskQuest results Nenue@0: function WorldQuests:GetPinByQuestID (questID, taskInfo) Nenue@0: if (QuestMapFrame_IsQuestWorldQuest (questID)) then Nenue@0: local questTitle, rewardIcon, rewardName, rewardCount, rewardStyle, rewardType, itemID, quantity, quality, _ Nenue@0: local pin = self:AcquirePin(questID, taskInfo) Nenue@0: Nenue@0: if pin.isNew then Nenue@0: if not hasNewQuestPins then Nenue@0: print('triggering new quest pins event') Nenue@0: end Nenue@0: Nenue@0: hasNewQuestPins = true Nenue@0: end Nenue@0: Nenue@0: if not HaveQuestData(questID) then Nenue@0: print('|cFFFF4400Retrieval failed.') Nenue@0: TQ_RequestPreloadRewardData(questID) Nenue@0: hasPendingQuestData = true Nenue@0: else Nenue@9: wqprint('|cFF00FF88Quest Data Received|r') Nenue@0: pin.mapID = pin.mapID or C_TaskQuest.GetQuestZoneID(questID) Nenue@0: Nenue@0: -- set reward category Nenue@0: local numRewards = GetNumQuestLogRewards(questID) Nenue@0: local numCurrency = GetNumQuestLogRewardCurrencies(questID) Nenue@0: local money = GetQuestLogRewardMoney(questID) Nenue@0: if numRewards >= 1 then Nenue@0: rewardType, rewardIcon, rewardCount, rewardName, itemID = ParseItemReward(questID) Nenue@0: elseif numCurrency >= 1 then Nenue@0: rewardName, rewardIcon, rewardCount = GetQuestLogRewardCurrencyInfo(1, questID) Nenue@0: rewardType = REWARD_CURRENCY Nenue@0: elseif money >= 1 then Nenue@0: rewardIcon = ICON_MONEY Nenue@0: rewardName = GetMoneyString(money) Nenue@0: rewardType = REWARD_CASH Nenue@0: end Nenue@0: rewardStyle = POI_REWARD_TYPE[rewardType] or POI_DEFAULT_TYPE Nenue@0: Nenue@0: pin.itemNumber = rewardCount or pin.itemNumber Nenue@0: pin.rewardType = rewardType or REWARD_ITEM Nenue@0: pin.style = rewardStyle Nenue@0: QuestsByID[questID] = pin Nenue@0: Nenue@0: -- title, faction, capped state Nenue@0: local questTitle, factionID, capped = TQ_GetQuestInfoByQuestID(questID) Nenue@0: if factionID then Nenue@0: QuestsByFaction[factionID] = QuestsByFaction[factionID] or {} Nenue@0: QuestsByFaction[factionID][questID] = pin Nenue@0: end Nenue@0: pin.title = questTitle or "|cFFFF0000Retrieving..." Nenue@0: pin.factionID = factionID Nenue@0: pin.capped = capped Nenue@0: Nenue@0: -- set tag details Nenue@0: local tagID, tagName, worldQuestType, rarity, isElite, tradeskillLineIndex = GetQuestTagInfo(questID); Nenue@0: local tagAtlas Nenue@0: if worldQuestType == LE_QUEST_TAG_TYPE_PET_BATTLE then Nenue@0: tagAtlas = "worldquest-icon-petbattle" Nenue@0: elseif worldQuestType == LE_QUEST_TAG_TYPE_PVP then Nenue@0: tagAtlas = "worldquest-icon-pvp-ffa" Nenue@0: elseif worldQuestType == LE_QUEST_TAG_TYPE_PROFESSION then Nenue@0: local id = tradeskillLineIndex and select(7, GetProfessionInfo(tradeskillLineIndex)) Nenue@0: if id then Nenue@0: tagAtlas = WORLD_QUEST_ICONS_BY_PROFESSION[id] Nenue@0: end Nenue@0: elseif worldQuestType == LE_QUEST_TAG_TYPE_DUNGEON then Nenue@0: tagAtlas = "worldquest-icon-dungeon" Nenue@0: end Nenue@0: pin.tagID = tagID Nenue@0: pin.tagName = tagName Nenue@0: pin.worldQuestType = worldQuestType Nenue@0: pin.isElite = isElite Nenue@0: pin.tradeskillLineIndex = tradeskillLineIndex Nenue@0: pin.rarity = rarity Nenue@0: pin.tagAtlas = tagAtlas Nenue@0: end Nenue@0: Nenue@0: -- flag unresolved info Nenue@0: if not (rewardIcon and rewardName) then Nenue@0: if not pin.isPending then Nenue@0: pin.isPending = true Nenue@0: TQ_RequestPreloadRewardData (questID) Nenue@0: pin.rewardType = pin.rewardType or REWARD_ITEM Nenue@0: pin.style = pin.style or POI_REWARD_TYPE[REWARD_ITEM] Nenue@0: Nenue@0: if not hasPendingQuestData then Nenue@0: hasPendingQuestData = true Nenue@0: PlaySoundKitID(229) Nenue@0: end Nenue@0: --WorldPlan:print('|cFFFFFF00'..tostring(pin.title)..'|r waiting on texture info') Nenue@0: end Nenue@0: else Nenue@0: if (rewardIcon and rewardName) then Nenue@0: --WorldPlan:print('|cFF00FF00'..tostring(pin.title)..'|r has info', rewardIcon, rewardName) Nenue@0: pin.hasUpdate = true Nenue@0: end Nenue@0: pin.isPending = nil Nenue@0: end Nenue@0: pin.itemTexture = rewardIcon or pin.itemTexture Nenue@0: pin.itemName = rewardName or pin.itemName Nenue@0: Nenue@0: qprint(' |cFF00FFFF'..questID..'|r:->', (HaveQuestData(questID) and "|cFF00FF00HaveQuestData" or "-"), (C_TaskQuest.IsActive(questID) and "|cFF88FF00IsActive|r" or "")) Nenue@0: qprint(' ', pin.title, pin.itemTexture, 'rewardType:', pin.rewardType, 'tag:', pin.tagID, 'style', pin.style ) Nenue@0: end Nenue@0: return QuestsByID[questID] 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@9: pin:Refresh() 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@0: pin.isNew = nil Nenue@0: pin:Show() Nenue@0: pin.FadeIn:Play() 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@0: pin:Show() 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.whiteListed = nil Nenue@9: self.used = true Nenue@9: Nenue@0: Nenue@0: local whiteListed, blackListed Nenue@0: for filterKey, includes in pairs(FilterInclusions) do Nenue@0: local controlValue = self[filterKey] Nenue@0: if FilterInclusions[filterKey][controlValue] then Nenue@9: self.filtered = nil Nenue@9: self.whiteListed = true Nenue@0: break Nenue@0: end Nenue@0: if FilterExclusions[filterKey][controlValue] then Nenue@9: self.filtered = true Nenue@0: end Nenue@0: end 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: print(' |cFFFF4400IsShowable()|r', self.used, self.filtered, self.title) 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@0: self.subStyle = self.subStyle or 'continent' Nenue@0: Nenue@0: style = style or self.style Nenue@0: subStyle = style[subStyle or self.subStyle] Nenue@0: 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@0: self:SetSize(self.currentWidth, self.currentWidth) Nenue@0: Nenue@0: local iconBorder = self.iconBorder Nenue@0: local trackingBorder = self.supertrackBorder Nenue@0: local tag = self.tagIcon Nenue@0: local style = self.style or POI_DEFAULT_TYPE Nenue@0: local mask = style.mask or POI_BORDER_FILL Nenue@0: Nenue@0: self.icon:SetMask(nil) Nenue@0: self.iconBorder:SetMask(nil) Nenue@0: self.supertrackBorder: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@0: self.icon:SetMask(mask) Nenue@9: self.icon:SetTexture(self.icon:GetTexture()) Nenue@0: self.iconBorder:SetMask(mask) Nenue@0: self.supertrackBorder:SetMask(mask) Nenue@0: Nenue@0: if self.NoIcon then Nenue@0: self.icon:Hide() Nenue@0: else Nenue@0: self.icon:Show() Nenue@0: end 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@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: print(' using', button.label:GetText()) 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@9: self.label: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@0: if self.filterKey then Nenue@0: if FilterInclusions[self.filterKey][self.filterValue] == true then Nenue@0: r, g, b = 0, 1, 0 Nenue@0: elseif FilterExclusions[self.filterKey][self.filterValue] 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@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@9: local setExclude = (button == 'RightButton') Nenue@9: local filterTable = setExclude and FilterExclusions or FilterInclusions Nenue@9: local opposingTable = setExclude and FilterInclusions or FilterExclusions Nenue@9: Nenue@0: Nenue@0: if not filterKey then Nenue@0: -- resetting Nenue@0: for k,v in pairs(FilterInclusions) do Nenue@0: wipe(v) Nenue@0: end Nenue@0: for k,v in pairs(FilterExclusions) do Nenue@0: wipe(v) Nenue@0: end Nenue@0: else Nenue@9: Nenue@9: if filterTable[filterKey][filterValue] then Nenue@9: filterTable[filterKey][filterValue] = nil Nenue@0: else Nenue@9: filterTable[filterKey][filterValue] = true Nenue@9: opposingTable[filterKey][filterValue] = nil Nenue@9: end Nenue@9: Nenue@9: local overrideFilters = IsControlKeyDown() Nenue@9: local overrideOpposing = IsShiftKeyDown() Nenue@0: Nenue@0: for k, info in ipairs(POI_FILTER_OPTIONS) do Nenue@9: if (info.filterKey == filterKey) and (info.filterValue ~= filterValue) then Nenue@9: if overrideFilters then Nenue@9: filterTable[info.filterKey][info.filterValue] = nil Nenue@9: opposingTable[info.filterKey][info.filterValue] = true Nenue@9: elseif overrideOpposing then Nenue@9: filterTable[info.filterKey][info.filterValue] = nil Nenue@9: opposingTable[info.filterKey][info.filterValue] = nil Nenue@0: end Nenue@0: end Nenue@0: end Nenue@0: Nenue@9: Nenue@0: end Nenue@0: Nenue@9: print('|cFF00FF88Filter Update:', filterKey, filterValue, operation) Nenue@0: 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% Nenue@0: Nenue@0: for mapID, mapName in pairs(WORLD_QUEST_MAPS) do Nenue@0: QuestsByZone[mapID] = {} Nenue@0: end Nenue@0: for index, color in pairs(ITEM_QUALITY_COLORS) do Nenue@0: POI_REWARD_TYPE[index] = { Nenue@0: r = color.r, g = color.g, b = color.b, Nenue@0: hex = color.hex, Nenue@0: } Nenue@0: end