Mercurial > wow > worldplan
view WorldPlan.lua @ 23:e49efad51698 v1.0-rc7
* Run data scooping operations from the main Refresh block
author | Nenue |
---|---|
date | Mon, 24 Oct 2016 23:17:42 -0400 |
parents | 08b03bcdfeac |
children | 4a7e89bffbcb |
line wrap: on
line source
-- Veneer -- WorldPlan.lua -- Created: 8/16/2016 8:19 AM -- %file-revision% --[[ Summary: Adds reward icons to the world quest POI markers, and adds said markers to the continent map. Issues: Dalaran quests aren't visible until that map has been specifically viewed by the player. --]] WorldPlanCore = {} WorldPlanPOIMixin = {} WorldPlanFilterPinMixin = {} local WorldPlanFlightMapMixin = setmetatable({}, {__tostring = function() return 'FlightMapHandler' end}) local WorldQuests = setmetatable({ QuestsByID = {}, freePins = {} }, {__tostring = function() return 'QuestHandler' end}) local FilterBar = setmetatable({ SummaryHeaders = {} }, {__tostring = function() return 'FilterBar' end}) local WorldPlan = WorldPlanCore local QuestPOI = WorldPlanPOIMixin local FilterPin = WorldPlanFilterPinMixin local WP_VERSION = "1.0" local db local print = DEVIAN_WORKSPACE and function(...) _G.print('WP', ...) end or function() end local qprint = DEVIAN_WORKSPACE and function(...) _G.print('POI', ...) end or function() end local iprint = DEVIAN_WORKSPACE and function(...) _G.print('ItemScan', ...) end or function() end local wqprint = DEVIAN_WORKSPACE and function(...) _G.print('WorldQuests', ...) end or function() end local fbprint = DEVIAN_WORKSPACE and function(...) _G.print('FilterBar', ...) end or function() end local wipe, tremove, tinsert, pairs, floor, tContains = table.wipe, table.remove, table.insert, pairs, floor, tContains local TQ_GetQuestInfoByQuestID = C_TaskQuest.GetQuestInfoByQuestID -- Return the name of a quest with a given ID local TQ_GetQuestsForPlayerByMapID = C_TaskQuest.GetQuestsForPlayerByMapID -- This function is not yet documented local TQ_GetQuestTimeLeftMinutes = C_TaskQuest.GetQuestTimeLeftMinutes local TQ_RequestPreloadRewardData = C_TaskQuest.RequestPreloadRewardData local TQ_GetQuestLocation = C_TaskQuest.GetQuestLocation local TQ_IsActive = C_TaskQuest.IsActive local ITEM_QUALITY_COLORS = ITEM_QUALITY_COLORS local WorldMap_DoesWorldQuestInfoPassFilters = WorldMap_DoesWorldQuestInfoPassFilters local QuestMapFrame_IsQuestWorldQuest = QuestMapFrame_IsQuestWorldQuest local GameTooltip = GameTooltip local GetItemIcon = GetItemIcon local GetMapInfo, QuestPOIGetIconInfo = GetMapInfo, QuestPOIGetIconInfo local GetQuestTagInfo, HaveQuestData = GetQuestTagInfo, HaveQuestData local GetNumQuestLogRewards, GetNumQuestLogRewardCurrencies, GetQuestLogRewardMoney = GetNumQuestLogRewards, GetNumQuestLogRewardCurrencies, GetQuestLogRewardMoney local GetQuestLogRewardInfo, GetQuestLogRewardCurrencyInfo, GetMoneyString = GetQuestLogRewardInfo, GetQuestLogRewardCurrencyInfo, GetMoneyString local GetCurrentMapAreaID, GetMapNameByID, GetSuperTrackedQuestID = GetCurrentMapAreaID, GetMapNameByID, GetSuperTrackedQuestID local MC_GetNumZones, MC_GetZoneInfo = C_MapCanvas.GetNumZones, C_MapCanvas.GetZoneInfo local PinBaseIndex = 1600 local BROKEN_ISLES_ID, DALARAN_ID, AZSUNA_ID, VALSHARAH_ID, HIGHMOUNTAIN_ID, STORMHEIM_ID, SURAMAR_ID, EOA_ID = 1007, 1014, 1015,1018, 1024, 1017, 1033, 1096 -- maps where we do our own anchors local CONTINENT_MAPS = { [BROKEN_ISLES_ID] = BROKEN_ISLES_ID, } local WORLD_QUEST_MAPS = { [DALARAN_ID] = 'Dalaran70', [AZSUNA_ID] = 'Azsuna', [VALSHARAH_ID] = "Val'sharah", [HIGHMOUNTAIN_ID] = 'Highmountain', [STORMHEIM_ID] = 'Stormheim', [SURAMAR_ID] = 'Suramar', [EOA_ID] = 'EyeOfAszhara', } -- default color templates local ARTIFACT_COLOR = ITEM_QUALITY_COLORS[LE_ITEM_QUALITY_ARTIFACT] local MONEY_COLOR = {hex ='|cFFFFFF00', r=1, g=1, b=0} local COMMON_COLOR = ITEM_QUALITY_COLORS[LE_ITEM_QUALITY_COMMON] local ICON_UNKNOWN = "Interface\\ICONS\\inv_misc_questionmark" local ICON_MONEY = "Interface\\Buttons\\UI-GroupLoot-Coin-Up" local POI_BORDER_MASK = "Interface\\Minimap\\UI-Minimap-Background" local POI_BORDER_FILL = "Interface\\BUTTONS\\YELLOWORANGE64" local POI_BORDER_BLUE = "Interface\\BUTTONS\\GRADBLUE" local POI_BORDER_RED = "Interface\\BUTTONS\\RedGrad64" local POI_BORDER_YELLOW = "Interface\\BUTTONS\\YELLOWORANGE64" local POI_BORDER_GREEN = "Interface\\BUTTONS\\GREENGRAD64" local REWARD_CASH = 1001 local REWARD_ARTIFACT_POWER = 1002 local REWARD_GEAR = 1003 local REWARD_CURRENCY = 1004 local REWARD_ITEM = 1005 local REWARD_REAGENT = 1006 local POI_DEFAULT_TYPE = { a = 1, r = 1, g = 1, b = 1, x = 0, y = 0, desaturated = true, mask = POI_BORDER_MASK, texture = POI_BORDER_FILL, continent = { PinSize = 18, Border = 3, TrackingBorder = 2, TagSize = 6, TimeleftStage = 3, }, zone = { PinSize = 22, Border = 3, TrackingBorder = 2, TagSize = 12, TimeleftStage = 3, }, minimized = { PinSize = 4, Border = 1, TrackingBorder = 2, NoIcon = true, TimeleftStage = 1, } } local POI_REWARD_TYPE = setmetatable({}, { __newindex = function(t, k, v) if type(v) == 'table' then setmetatable(v, {__index = POI_DEFAULT_TYPE}) end rawset(t,k,v) end }) local POI_FILTER_STYLE = setmetatable({ continentBorder = 2, zoneBorder = 2, }, {__index = POI_DEFAULT_TYPE}) local LE_QUEST_TAG_TYPE_PVP = LE_QUEST_TAG_TYPE_PVP local LE_QUEST_TAG_TYPE_PET_BATTLE = LE_QUEST_TAG_TYPE_PET_BATTLE local LE_QUEST_TAG_TYPE_DUNGEON = LE_QUEST_TAG_TYPE_DUNGEON local LE_QUEST_TAG_TYPE_PROFESSION = LE_QUEST_TAG_TYPE_PROFESSION local LE_QUEST_TAG_TYPE_NORMAL = LE_QUEST_TAG_TYPE_NORMAL -- Pin color/display variables POI_REWARD_TYPE[REWARD_ITEM] = { r = 1, g = 1, b = 1, } POI_REWARD_TYPE[REWARD_REAGENT] = { r = 0, g = 1, b = 1, } POI_REWARD_TYPE[REWARD_ARTIFACT_POWER] = { r = 1, g = .25, b = .5, showNumber = true, } POI_REWARD_TYPE[REWARD_GEAR] = { r = .1, g = .2, b = 1, } POI_REWARD_TYPE[REWARD_CURRENCY] = { r = 1, g = 1, b = 0, } POI_REWARD_TYPE[REWARD_CASH] = { r = 0, g = 0, b = 0, --x = 0, y = -1, --mask = ICON_MONEY, --continentBorder = 1, --zoneBorder = 1, } local defaults = { defaultPinStyle = POI_DEFAULT_TYPE, rewardStyle = POI_REWARD_TYPE, filterStyle = POI_FILTER_STYLE, ShowAllProfessionQuests = true, DisplayContinentSummary = true, DisplayContinentPins = true, NotifyWhenNewQuests = true, EnablePins = true, FadeWhileGrouped = true, } -- Summary header structure local POI_FILTER_OPTIONS = { { label = 'Filters', texture = "Interface\\WorldMap\\WorldMap-Icon" }, { filterKey= 'rewardType', filterValue = REWARD_ARTIFACT_POWER, label = 'Artifact Power', texture = "Interface\\ICONS\\inv_7xp_inscription_talenttome01" }, { filterKey= 'rewardType', filterValue = REWARD_CURRENCY,label = 'Currency', texture = "Interface\\ICONS\\inv_misc_elvencoins" }, { filterKey= 'rewardType', filterValue = REWARD_ITEM, label = 'Item', texture = "Interface\\ICONS\\inv_crate_01" }, { filterKey= 'rewardType', filterValue = REWARD_GEAR, label = 'Equipment', texture = "Interface\\ICONS\\garrison_bluearmorupgrade" }, { filterKey= 'rewardType', filterValue = REWARD_REAGENT, label = 'Reagents', texture = 1417744 }, { filterKey= 'rewardType', filterValue = REWARD_CASH, label = 'Reagents', texture = ICON_MONEY }, { filterKey= 'worldQuestType', filterValue = LE_QUEST_TAG_TYPE_PVP, label = 'PvP', texture = "Interface\\Icons\\Ability_PVP_GladiatorMedallion", spacing = 10 }, { filterKey= 'worldQuestType', filterValue = LE_QUEST_TAG_TYPE_PET_BATTLE, label = 'Pet Battle', texture = "Interface\\Icons\\PetJournalPortrait", }, { filterKey= 'worldQuestType', filterValue = LE_QUEST_TAG_TYPE_DUNGEON, label = 'Dungeon', texture = "Interface\\LFGFRAME\\UI-LFR-PORTRAIT", }, { filterKey= 'worldQuestType', filterValue = LE_QUEST_TAG_TYPE_PROFESSION, label = 'Profession', texture = "Interface\\ICONS\\70_professions_scroll_02", }, } WorldPlanCore.BrokenIsleID = BROKEN_ISLES_ID WorldPlanCore.FilterStyle = POI_FILTER_STYLE WorldPlanCore.FilterOptions = {} WorldPlanCore.UsedFilters = {} -- operating flags local superTrackedID local currentMapName local hasNewQuestPins local isContinentMap local numPins = 0 local QuestsByZone = {} local QuestsByFaction = {} local QuestsByReward = {} local QuestsByTag = {} local QuestsByID = {} local QuestPositions = {} local FilterInclusions = {rewardType = {}, worldQuestType = {}, factionID = {}} local NotificationTypes = {} local ZoneInfo = {} local SummaryHeaders = {} local FreePins = {} local NumPinFrames = 1 local hasPendingQuestData local notifyPlayed local scanner, wmtt, WorldMapPOIFrame WorldPlanCore.QuestsByID = QuestsByID WorldPlanCore.QuestsByZone = QuestsByZone local tasksQueue = {} local function OnNext (func) if #tasksQueue == 0 then _G.WorldPlan:SetScript('OnUpdate', function() local func = tremove(tasksQueue, 1) if func then func() end if #tasksQueue == 0 then _G.WorldPlan:SetScript('OnUpdate', nil) end end) end tinsert(tasksQueue, func) end -- combines templates local function DoMixins(frame,...) for i = 1, select('#', ...) do for k,v in pairs(select(i,...)) do frame[k] = v end end return frame end -- use tooltip object to extract item details local ParseItemReward = function(questID) local rewardType = REWARD_ITEM local name, icon, quantity, quality, _, itemID = GetQuestLogRewardInfo(1, questID) if not itemID then return REWARD_ITEM end scanner:SetOwner(WorldPlan, "ANCHOR_NONE") scanner:SetItemByID(itemID) local ttl1 = _G['WorldPlanTooltipTextLeft1'] local ttl2 = _G['WorldPlanTooltipTextLeft2'] local ttl3 = _G['WorldPlanTooltipTextLeft3'] local ttl4 = _G['WorldPlanTooltipTextLeft4'] if ttl2 then local text = ttl2:GetText() -- Artifact Power if text and text:match("|cFFE6CC80") then --print('AP token!', text) local power if ttl4 then local text = ttl4:GetText() --print('tip line 4', text) if text then power = text:gsub("%p", ""):match("%d+") power = tonumber(power) end end rewardType = REWARD_ARTIFACT_POWER icon = "Interface\\ICONS\\inv_7xp_inscription_talenttome01" quantity = power elseif text and text:match("Item Level") then --print('equipment!', text) rewardType = REWARD_GEAR quantity = text:match("Item Level ([%d\+]+)") end end if ttl3 then local text = ttl3:GetText() -- Crafting Reagent if text and text:match("Crafting Reagent") then --print('reagent', text) rewardType = REWARD_REAGENT end end iprint(' item:', name, rewardType, icon, quantity) return rewardType, icon, quantity, name, itemID end -- update a masked texture without messing up its blending mask local SetMaskedTexture = function(region, file, mask) mask = mask or POI_BORDER_MASK region:SetMask(nil) region:SetTexture(file) region:SetMask(mask) end -- tracking menu toggler local DropDown_OnClick = function(self) local key = self.value if key then if WorldPlanData[key] then WorldPlanData[key] = nil else WorldPlanData[key] = true end end WorldPlan:RefreshAll() end function WorldPlan:print(...) local msg for i = 1, select('#', ...) do msg = (msg and (msg .. ' ') or '') .. tostring(select(i, ...)) end DEFAULT_CHAT_FRAME:AddMessage("|cFF0088FFWorldPlan|r: " .. msg) end function WorldPlan:OnLoad () WorldPlan = self scanner = _G.WorldPlanTooltip wmtt = _G.WorldMapTooltip WorldMapPOIFrame = _G.WorldMapPOIFrame WorldPlan:print('v'..WP_VERSION) self:RegisterEvent("QUESTLINE_UPDATE") self:RegisterEvent("QUEST_LOG_UPDATE") self:RegisterEvent("WORLD_MAP_UPDATE") self:RegisterEvent("WORLD_QUEST_COMPLETED_BY_SPELL") self:RegisterEvent("SUPER_TRACKED_QUEST_CHANGED") self:RegisterEvent("SKILL_LINES_CHANGED") self:RegisterEvent("ARTIFACT_XP_UPDATE") self:RegisterEvent("ADDON_LOADED") WorldPlan.modules = { WorldQuests, FilterBar, WorldPlanFlightMapMixin, } end function WorldPlan:OnEvent (event, ...) print() print(event, ...) if event == 'ADDON_LOADED' then local addon = ... if addon == "Blizzard_FlightMap" then print('do mixin junk') self.OnFlightMapLoaded() end if IsLoggedIn() and not self.initialized then self:Setup() end elseif event == 'WORLD_MAP_UPDATE' then self.currentMapID = GetCurrentMapAreaID() self:RefreshAll() end for i, module in ipairs(self.modules) do if module.OnEvent then print('forwarding to', tostring(module)) module:OnEvent(event, ...) end end end function WorldPlan:Setup () if not WorldPlanData then WorldPlanData = {key = 0 } end WorldPlanData.key = (WorldPlanData.key or 0) + 1 self.db = WorldPlanData self.db.WorldQuests = self.db.WorldQuests or {} db = self.db for k,v in pairs(defaults) do --[===[@non-debug@ if not db[k] then db[k] = v end --@end-non-debug@]===] --@debug@ db[k] = v --@end-debug@ end self.currentMapID = GetCurrentMapAreaID() for i, module in ipairs(self.modules) do module.db = self.db if module.Setup then module:Setup() end if not module.RegisterEvent then module.RegisterEvent = self.RegisterEvent end end self.initialized = true hooksecurefunc("UIDropDownMenu_Initialize", self.OnDropDownInitialize) end function WorldPlan:RefreshAll (forced) if not self.initialized then return end POI_DEFAULT_TYPE = db.defaultPinStyle POI_REWARD_TYPE = db.rewardStyle POI_FILTER_STYLE = db.filterStyle for i, module in ipairs(self.modules) do if module.Reset then print(module, 'Reset()') module:Reset() end end for i, module in ipairs(self.modules) do if module.Refresh then print(module, 'Refresh()') module:Refresh() end end for i, module in ipairs(self.modules) do if module.Cleanup then print(module, 'Cleanup()') module:Cleanup() end end end function WorldPlan:UpdateAnchors () for i, module in ipairs(self.modules) do if module.UpdateAnchors then module:UpdateAnchors() end end end -- insert visual options into the tracking button menu WorldPlan.OnDropDownInitialize = function (self, callback, dropType) if self ~= WorldMapFrameDropDown then return end local db = WorldPlan.db local info = UIDropDownMenu_CreateInfo() info.text = "" info.isTitle = true UIDropDownMenu_AddButton(info) info.text = "|cFF00AAFFWorldPlan|r" info.isTitle = true UIDropDownMenu_AddButton(info) info.isTitle = nil info.disabled = nil info.keepShownOnClick = true info.tooltipOnButton = 1 info.text = "Enable" info.isNotRadio = true info.value = "EnablePins" info.checked = db.EnablePins info.tooltipTitle = "Enable World Quest Overlays" info.tooltipText = "Toggle the detail layers here." info.func = DropDown_OnClick UIDropDownMenu_AddButton(info) info.text = "Display All Profession Quests" info.isNotRadio = true info.value = "ShowAllProfessionQuests" info.checked = db.ShowAllProfessionQuests info.tooltipTitle = "Hidden Quests" info.tooltipText = "Display work order and profession-related quests that are skipped by the default UI." info.func = DropDown_OnClick UIDropDownMenu_AddButton(info) info.text = "Show Continent Pins" info.isNotRadio = true info.value = "DisplayContinentPins" info.checked = db.DisplayContinentPins info.tooltipTitle = "Continent Pins" info.tooltipText = "Display quest pins on the continent map (may get cramped)." info.func = DropDown_OnClick UIDropDownMenu_AddButton(info) info.text = "Show Summary" info.isNotRadio = true info.value = "DisplayContinentSummary" info.tooltipTitle = "Summary Bar" info.tooltipText = "Display a summary of active world quests. Note: requires directly viewing Broken Isle and Dalaran maps to gain complete info." info.checked = db.DisplayContinentSummary info.func = DropDown_OnClick UIDropDownMenu_AddButton(info) info.text = "Fade In Groups" info.isNotRadio = true info.value = "FadeWhileGrouped" info.tooltipTitle = "Group Fade" info.tooltipText = "Reduce pin alpha when grouped, so player dots are easier to see." info.checked = db.DisplayContinentSummary info.func = DropDown_OnClick UIDropDownMenu_AddButton(info) end function WorldQuests:Setup() -- refresh positions any time blizzard does so (i.e. mousewheel zoom) hooksecurefunc("WorldMapScrollFrame_ReanchorQuestPOIs", function() self:Refresh(true) end) -- hide the original world quest POIs hooksecurefunc("WorldMap_UpdateQuestBonusObjectives", function() for i = 1, NUM_WORLDMAP_TASK_POIS do local button = _G['WorldMapFrameTaskPOI'..i] if button and button.worldQuest then button:Hide() end end end) end function WorldQuests:OnEvent (event, ...) print('|cFFFFFF00'..tostring(self)..':OnEvent()'..event..'|r', ...) if event == 'QUEST_LOG_UPDATE' then local questID, added = ... if questID and added then self:GetPinByQuestID(questID) else self:GetPinsForMap() end elseif event == 'WORLD_QUEST_COMPLETED_BY_SPELL' then local questID = ... if questID and QuestsByID[questID] then self:ReleasePin(QuestsByID[questID]) end elseif event == 'SKILL_LINES_CHANGED' then self:Refresh(true) end end function WorldQuests:AcquirePin (questID, pinTable) local pin = QuestsByID[questID] local isNew = false if not pin then isNew = true local numFree = #self.freePins if numFree >= 1 then pin = tremove(self.freePins, numFree) --print('|cFF00FF00Re-using', pin:GetName()) else local name = 'WorldPlanQuestMarker' .. NumPinFrames --print('|cFF00FF00Creating', name) pin = CreateFrame('Frame', name, WorldMapPOIFrame, 'WorldPlanQuestPin') pin:SetFrameStrata('HIGH') NumPinFrames = NumPinFrames + 1 --pin.iconBorder:SetVertexColor(0,0,0,1) end QuestsByID[questID] = pin pin.isNew = true pin.currentWidth = nil -- used by TaskPOI_x scripts pin.questID = questID pin.worldQuest = true pin.Reset = function(self) WorldQuests:GetPinByQuestID(questID) end else --print('|cFF00FF00Using', pin:GetName()) end -- set display flags accordingly if pinTable then for k,v in pairs(pinTable) do pin[k] = v end end pin.throttle = nil pin.timeThreschold = nil return pin, isNew end -- remove from index and add it to the recycling heap function WorldQuests:ReleasePin (pin) local id = pin.questId if id then QuestsByID[id] = nil for i, zone in pairs(QuestsByZone) do print('-', i, zone[i]) zone[id] = nil end end if pin.factionID then QuestsByFaction[pin.factionID][id] = nil end pin:Hide() pin:ClearAllPoints() tinsert(self.freePins, pin) print('|cFFFF4400Clearing out', pin:GetName(),id) end -- create of update quest pins for a map and its underlying zones function WorldQuests:GetPinsForMap (mapID) local print = wqprint mapID = mapID or GetCurrentMapAreaID() superTrackedID = GetSuperTrackedQuestID() if not mapID then -- info not available yet return end if mapID == BROKEN_ISLES_ID then hasPendingQuestData = nil print('|cFF00FFFFRefreshQuestsForMap|r', mapID, GetMapNameByID(mapID), superTrackedID) self.fullSearch = true for i = 1, MC_GetNumZones(mapID) do local submapID, name, depth = MC_GetZoneInfo(mapID, i) self:GetPinsForMap(submapID) end self.fullSearch = nil elseif QuestsByZone[mapID] then local taskInfo = TQ_GetQuestsForPlayerByMapID(mapID) local quest = QuestsByZone[mapID] local numQuests = 0 if taskInfo and #taskInfo >= 1 then print('|cFF00FFFFRefreshQuestsForMap|r', mapID, GetMapNameByID(mapID), #taskInfo) wipe(QuestsByZone[mapID]) ZoneInfo[mapID] = taskInfo for taskID, info in pairs(taskInfo) do local questID = info.questId info.mapID = mapID QuestsByZone[mapID][questID] = self:GetPinByQuestID(questID, info) numQuests = numQuests + 1 end end end if hasNewQuestPins and not self.fullSearch then print('|cFF00FF00NEW PINS DO ANCHOR THINGS') self:Refresh (true) hasNewQuestPins = nil end end -- create or update the pin using the given questID and C_TaskQuest results function WorldQuests:GetPinByQuestID (questID, taskInfo) if (QuestMapFrame_IsQuestWorldQuest (questID)) then local questTitle, rewardIcon, rewardName, rewardCount, rewardStyle, rewardType, itemID, quantity, quality, _ local pin = self:AcquirePin(questID, taskInfo) if pin.isNew then if not hasNewQuestPins then print('triggering new quest pins event') end hasNewQuestPins = true end if not HaveQuestData(questID) then print('|cFFFF4400Retrieval failed.') TQ_RequestPreloadRewardData(questID) hasPendingQuestData = true else wqprint('|cFF00FF88Quest Data Received|r') pin.mapID = pin.mapID or C_TaskQuest.GetQuestZoneID(questID) -- set reward category local numRewards = GetNumQuestLogRewards(questID) local numCurrency = GetNumQuestLogRewardCurrencies(questID) local money = GetQuestLogRewardMoney(questID) if numRewards >= 1 then rewardType, rewardIcon, rewardCount, rewardName, itemID = ParseItemReward(questID) elseif numCurrency >= 1 then rewardName, rewardIcon, rewardCount = GetQuestLogRewardCurrencyInfo(1, questID) rewardType = REWARD_CURRENCY elseif money >= 1 then rewardIcon = ICON_MONEY rewardName = GetMoneyString(money) rewardType = REWARD_CASH end rewardStyle = POI_REWARD_TYPE[rewardType] or POI_DEFAULT_TYPE pin.itemNumber = rewardCount or pin.itemNumber pin.rewardType = rewardType or REWARD_ITEM pin.style = rewardStyle QuestsByID[questID] = pin -- title, faction, capped state local questTitle, factionID, capped = TQ_GetQuestInfoByQuestID(questID) if factionID then QuestsByFaction[factionID] = QuestsByFaction[factionID] or {} QuestsByFaction[factionID][questID] = pin end pin.title = questTitle or "|cFFFF0000Retrieving..." pin.factionID = factionID pin.capped = capped -- set tag details local tagID, tagName, worldQuestType, rarity, isElite, tradeskillLineIndex = GetQuestTagInfo(questID); local tagAtlas if worldQuestType == LE_QUEST_TAG_TYPE_PET_BATTLE then tagAtlas = "worldquest-icon-petbattle" elseif worldQuestType == LE_QUEST_TAG_TYPE_PVP then tagAtlas = "worldquest-icon-pvp-ffa" elseif worldQuestType == LE_QUEST_TAG_TYPE_PROFESSION then local id = tradeskillLineIndex and select(7, GetProfessionInfo(tradeskillLineIndex)) if id then tagAtlas = WORLD_QUEST_ICONS_BY_PROFESSION[id] end elseif worldQuestType == LE_QUEST_TAG_TYPE_DUNGEON then tagAtlas = "worldquest-icon-dungeon" end pin.tagID = tagID pin.tagName = tagName pin.worldQuestType = worldQuestType pin.isElite = isElite pin.tradeskillLineIndex = tradeskillLineIndex pin.rarity = rarity pin.tagAtlas = tagAtlas end -- flag unresolved info if not (rewardIcon and rewardName) then if not pin.isPending then pin.isPending = true TQ_RequestPreloadRewardData (questID) pin.rewardType = pin.rewardType or REWARD_ITEM pin.style = pin.style or POI_REWARD_TYPE[REWARD_ITEM] if not hasPendingQuestData then hasPendingQuestData = true PlaySoundKitID(229) end --WorldPlan:print('|cFFFFFF00'..tostring(pin.title)..'|r waiting on texture info') end else if (rewardIcon and rewardName) then --WorldPlan:print('|cFF00FF00'..tostring(pin.title)..'|r has info', rewardIcon, rewardName) pin.hasUpdate = true end pin.isPending = nil end pin.itemTexture = rewardIcon or pin.itemTexture pin.itemName = rewardName or pin.itemName qprint(' |cFF00FFFF'..questID..'|r:->', (HaveQuestData(questID) and "|cFF00FF00HaveQuestData" or "-"), (C_TaskQuest.IsActive(questID) and "|cFF88FF00IsActive|r" or "")) qprint(' ', pin.title, pin.itemTexture, 'rewardType:', pin.rewardType, 'tag:', pin.tagID, 'style', pin.style ) end return QuestsByID[questID] end function WorldQuests:Refresh(forced) local print = wqprint print('|cFF00FF88'..tostring(self)..':Refresh()|r') if not WorldMapPOIFrame:IsVisible() then return end if forced then self:Reset() end self:UpdateAnchors() if forced then self:Cleanup () end end -- prepares elements for a map update function WorldQuests:Reset () local print = wqprint print('|cFF00FF88'..tostring(self)..':Reset()|r') wipe(QuestPositions) wipe(QuestsByReward) wipe(QuestsByTag) for questID, pin in pairs(QuestsByID) do pin.used = nil end end -- update visibility states of all pins function WorldQuests:UpdateAnchors (submapID) local print = wqprint local db = WorldPlan.db local mapFileName, textureHeight, textureWidth, isMicroDungeon, microDungeonMapName = GetMapInfo() if isMicroDungeon then return end local currentMap = GetCurrentMapAreaID() local submapID = submapID or currentMap if submapID == BROKEN_ISLES_ID and (not db.DisplayContinentPins) then print('not updating map for reasons') return end print('|cFF88FF00'..tostring(self)..':UpdateAnchors|r', submapID, GetMapNameByID(submapID), 'pin count:', numPins) local numZones = MC_GetNumZones(submapID) if numZones then for i = 1, numZones do local subMapID = MC_GetZoneInfo(submapID, i) self:UpdateAnchors(subMapID) end end local pins = QuestsByZone[submapID] if pins then local hostFrame = WorldMapPOIFrame local mapWidth, mapHeight = hostFrame:GetSize() for questID, pin in pairs(pins) do pin:IsShowable() if pin.used then pin:SetFrameLevel(PinBaseIndex+ (pin.whiteListed and 200 or 0) +numPins) print('level', PinBaseIndex+ (pin.whiteListed and 200 or 0) +numPins) pin:SetAnchor(WorldMapPOIFrame, currentMap, mapWidth, mapHeight) numPins = numPins + 1 end end end end -- shows, animates, or hides pins based on their current visibility flags local debug_show = {} local debug_animate = {} local debug_hide = {} function WorldQuests:Cleanup () local print = wqprint local showQuestPOI = db.EnablePins print('|cFFFFFF00'..tostring(self)..':Cleanup()|r') local mapID = GetCurrentMapAreaID() isContinentMap = (mapID == BROKEN_ISLES_ID) wipe(debug_show) wipe(debug_animate) wipe(debug_hide) -- continent or zone sizing local fadeGrouped = (db.FadeWhileGrouped and IsInGroup()) numPins = 0 for questID, pin in pairs(QuestsByID) do -- can we show it? if showQuestPOI and (pin.used) then pin:Refresh() if fadeGrouped then pin:SetAlpha(0.25) else pin:SetAlpha(1) end -- is it a new quest? if pin.isNew then if not pin.isAnimating then pin.isAnimating = true OnNext(function() pin.isNew = nil pin:Show() pin.FadeIn:Play() end) if not notifyPlayed then for k,v in pairs(NotificationTypes) do if v[pin[k]] then notifyPlayed = true PlaySoundKitID(23404) end end end tinsert(debug_animate,questID) else print('animating? ', questID, 'filtered:', pin.filtered) end -- trap new but animating pins here else -- hard show existing pin print('refresh #', questID, 'filtered:', pin.filtered) pin:Show() tinsert(debug_show,questID) end else if pin:IsShown() then tinsert(debug_hide,questID) end pin.isAnimating = nil pin.FadeIn:Stop() pin:Hide() end end print(' adding:', table.concat(debug_animate, ',' )) print(' refresh:', table.concat(debug_show, ',' )) print(' hiding:', table.concat(debug_hide, ',' )) hasNewQuestPins = nil notifyPlayed = nil end -- data provider manipulations for the taxi map WorldPlan.OnFlightMapLoaded = function() if true then return end -- todo: figure out how to layer inside the map canvas local res = {} local t = {} for k,v in pairs(FlightMapFrame) do tinsert(res, tostring(k)) end table.sort(res) for i, k in ipairs(res) do print(k) end hooksecurefunc(FlightMapFrame, 'RefreshAll', function(self) print('|cFF0088FFWQDP RefreshAllData ', GetTime()) WorldPlan:GetPinsForMap(self:GetMapID()) for pin in self:EnumerateAllPins() do if pin.worldQuest then --print('got pin #', pin.questID) local wp = QuestsByID[pin.questID] if wp then wp:ClearAllPoints() wp:SetParent(FlightMapFrame.ScrollContainer) wp:SetFrameStrata('MEDIUM') wp:SetPoint('CENTER', pin, 'CENTER') wp:Show() end end end end) end local throttle = 0 local tooltip = CreateFrame ("GameTooltip", "VeneerWorldQuestsScanner", nil, "GameTooltipTemplate") local tooltipLine1 = _G['VeneerWorldQuestsScannerTextLeft1'] local tooltipLine3 = _G['VeneerWorldQuestsScannerTextLeft3'] local GetTime, mod = GetTime, mod function WorldQuests:FilterCheckByID(questID) local pin = WorldQuests:GetPinByQuestID(questID) return pin:IsShowable() end function QuestPOI:IsShowable () local print = wqprint local db = WorldPlan.db local qType = self.worldQuestType local rType = self.rewardType self.filtered = nil self.used = true print(' |cFFFF4400IsShowable()|r', self.title) local isIncluded for filterKey, filterValues in pairs(WorldPlan.UsedFilters) do local controlValue = self[filterKey] if controlValue then local filterType = filterValues[controlValue] if filterType == true then isIncluded = true print(' include? ', filterKey, controlValue, filterType) end end self.filtered = (not isIncluded) end if not TQ_IsActive(self.questID) then self.used = nil end if qType == LE_QUEST_TAG_TYPE_PROFESSION then if not (db.ShowAllProfessionQuests or (self.tradeskillLineIndex and GetProfessionInfo(self.tradeskillLineIndex))) then self.used = nil end end return self.used, self.filtered end function QuestPOI:UpdateTimer (timeLeft, timeType) print('|cFF0088FFUpdatePinTimer()|r') end --- Fixes icons upon size update function QuestPOI:UpdateSize (style, subStyle) self.style = self.style or POI_DEFAULT_TYPE self.subStyle = self.subStyle or 'continent' style = style or self.style subStyle = style[subStyle or self.subStyle] self.currentWidth = subStyle.PinSize self.borderSize = subStyle.Border self.trackingBorderSize = subStyle.TrackingBorder self.tagSize = subStyle.TagSize self.TimeleftStage = subStyle.TimeleftStage self.NoIcon = subStyle.NoIcon self:SetSize(self.currentWidth, self.currentWidth) local iconBorder = self.iconBorder local trackingBorder = self.supertrackBorder local tag = self.tagIcon local style = self.style or POI_DEFAULT_TYPE local mask = style.mask or POI_BORDER_FILL self.icon:SetMask(nil) self.iconBorder:SetMask(nil) self.supertrackBorder:SetMask(nil) local borderWidth = self.borderSize local trackingWidth = self.trackingBorderSize iconBorder:ClearAllPoints() iconBorder:SetPoint('BOTTOMLEFT', self, 'BOTTOMLEFT', -borderWidth + (style.x or 0), -borderWidth + (style.y or 0)) iconBorder:SetPoint('TOPRIGHT', self, 'TOPRIGHT', borderWidth + (style.x or 0), borderWidth + (style.y or 0)) trackingBorder:ClearAllPoints() trackingBorder:SetPoint('BOTTOMLEFT', iconBorder, 'BOTTOMLEFT', -trackingWidth, -trackingWidth) trackingBorder:SetPoint('TOPRIGHT', iconBorder, 'TOPRIGHT', trackingWidth, trackingWidth) if self.tagSize then tag:Show() tag:ClearAllPoints() tag:SetPoint('BOTTOMRIGHT', self, 'BOTTOMRIGHT', borderWidth, -borderWidth) else tag:Hide() end --qprint('using mask:', mask, self.name ) self.icon:SetMask(mask) self.icon:SetTexture(self.icon:GetTexture()) self.iconBorder:SetMask(mask) self.supertrackBorder:SetMask(mask) if self.NoIcon then self.icon:Hide() else self.icon:Show() end end function FilterBar:OnEvent(event) if event == 'QUEST_LOG_UPDATE' then self:Refresh() end end function FilterBar:PassesFilterSet(filterKey, pin) local passesFilter = true for filterKey, filters in pairs(QuestFilters) do for rewardType, value in pairs(QuestFilters[filterKey]) do if value == 1 and rewardType == pin[filterKey] then passesFilter = true elseif value == -1 and rewardType == pin[filterKey] then passesFilter = false end end end return passesFilter end local bountyIndex local debug_headers = {} function FilterBar:Setup() self:GetFilters() end function FilterBar:OnEvent(event,...) if event == 'QUEST_LOG_UPDATE' then self:Reset() self:Refresh() end end function FilterBar:GetFilters() local print = fbprint wipe(WorldPlan.FilterOptions) for index, info in ipairs(POI_FILTER_OPTIONS) do tinsert(WorldPlan.FilterOptions, info) end self.bounties, self.numBounties = GetQuestBountyInfoForMapID(WorldPlan.currentMapID) self.BountyFilters = {} for index, data in ipairs(self.bounties) do local info = self.BountyFilters[index] if not info then info = {} self.BountyFilters[index] = info end local questTitle = GetQuestLogTitle(GetQuestLogIndexByID(data.questID)) info.filterKey = 'factionID' info.filterValue = data.factionID info.label = questTitle info.texture = data.icon print('loading emissary', questTitle) tinsert(WorldPlan.FilterOptions, info) --{ filterKey= 'worldQuestType', filterValue = LE_QUEST_TAG_TYPE_PROFESSION, label = 'Profession', texture = "Interface\\LFGFRAME\\UI-LFR-PORTRAIT", }, end end function FilterBar:Reset() self:GetFilters() end function FilterBar:Refresh(forced) local print = fbprint local blocks = self.SummaryHeaders local relativeFrame = WorldMapFrame.UIElementsFrame.TrackingOptionsButton local numHeaders = 0 print('|cFF00FF88'..tostring(self)..':Refresh()|r', 'currentMap=',WorldPlan.currentMapID) local quests = QuestsByZone[WorldPlan.currentMapID] or QuestsByID for index, info in ipairs(WorldPlan.FilterOptions) do local numQuests = 0 for questID, pin in pairs(quests) do if pin.used then if not info.filterKey then numQuests = numQuests + 1 elseif pin[info.filterKey] == info.filterValue then numQuests = numQuests + 1 end end end print(tostring(index).. ' ("'..tostring(info.label)..'" f('.. tostring(info.filterKey).. '='..tostring(info.filterValue) .. '), '..tostring(numQuests)..')') if numQuests >= 1 then numHeaders = numHeaders + 1 local button = blocks[numHeaders] if not blocks[numHeaders] then button = CreateFrame('Button', 'WorldPlanFilterButton'..numHeaders, WorldMapScrollFrame, 'WorldPlanFilterPin') button.iconBorder:SetTexture(info.fill or POI_BORDER_FILL) button.iconBorder:SetMask(info.mask or POI_BORDER_MASK) button.iconBorder:SetDesaturated(info.desaturated) button.supertrackBorder:SetTexture(info.fill or POI_BORDER_FILL) button.supertrackBorder:SetMask(info.mask or POI_BORDER_MASK) button.supertrackBorder:SetDesaturated(true) blocks[numHeaders] = button end button:SetID(index) button.spacing = ((info.filterKey ~= relativeFrame.filterKey) and 10) or 0 button.relativeFrame = relativeFrame button:Refresh(info, (numHeaders == 1), numQuests) button:Show() relativeFrame = button end end self.numHeaders = numHeaders for i = numHeaders + 1, #WorldPlan.FilterOptions do if self.SummaryHeaders[i] then self.SummaryHeaders[i]:Hide() end end end function FilterBar:Cleanup() -- hide trailing buttons end function FilterPin:Refresh(info, isFirst, numQuests) local print = fbprint isFirst = isFirst or self.isFirst numQuests = numQuests or self.numQuests if info then self.isFirst = isFirst self.numQuests = numQuests self.filterKey = info.filterKey self.filterValue = info.filterValue self.tagID = info.tagID self.icon:ClearAllPoints() self.icon:SetTexture(info.texture) self.icon:SetAllPoints(self) self.supertrackBorder:Hide() self.label:SetText(numQuests) self:Show() end self.itemTexture = self.texture if isFirst then self:SetPoint('TOP', self.relativeFrame, 'BOTTOM', 0, -5) else self:SetPoint('TOPRIGHT', self.relativeFrame, 'BOTTOMRIGHT', 0, -(3*2 + 1 + (self.spacing or 0))) end print('anchor to', self.relativeFrame:GetName()) local r, g, b, a = 1,1,1,1 local used = WorldPlan.UsedFilters[self.filterKey] if used and self.filterKey then if used[self.filterValue] == true then r, g, b = 0, 1, 0 elseif used[self.filterValue] == false then r, g, b = 1, 0, 0 end end self.iconBorder:SetVertexColor(r, g, b, a) self:UpdateSize() end function FilterPin:OnLoad() self:RegisterForClicks('AnyUp') self:SetFrameStrata('HIGH') self:SetFrameLevel(151) self:SetScript('OnUpdate', nil) end function FilterPin:OnUpdate () end function FilterPin:OnLeave () if GameTooltip:IsOwned(self) then GameTooltip:Hide() end end -- shift-click: reset filter -- click: rotate through include(1), exclude(-1), ignore(nil) function FilterPin:OnClick (button) local print = fbprint local filterKey = self.filterKey local filterValue = self.filterValue local operation = opPrefix local setInclude = (button == 'LeftButton') if not filterKey then -- resetting wipe(WorldPlan.UsedFilters) elseif IsShiftKeyDown() then WorldPlan.UsedFilters[filterKey] = nil else WorldPlan.UsedFilters[filterKey] = WorldPlan.UsedFilters[filterKey] or {} WorldPlan.UsedFilters[filterKey][filterValue] = setInclude print(filterKey, filterValue, '=', setInclude) for index, info in ipairs(WorldPlan.FilterOptions) do if info.filterKey == filterKey then if (not IsControlKeyDown()) and (filterValue ~= info.filterValue) then WorldPlan.UsedFilters[filterKey][info.filterValue] = (not setInclude) print(filterKey, info.filterValue, '=', WorldPlan.UsedFilters[filterKey][info.filterValue]) end end end end print('|cFF00FF88Filter Update:', filterKey, filterValue, operation) WorldPlan:RefreshAll() end --%debug% local SetTimedCallbackForAllPins = function(seconds, callback) C_Timer.After(seconds, function() for id, pin in pairs(QuestsByID) do callback(pin) end end) end SLASH_WORLDPLAN1 = "/worldplan" SLASH_WORLDPLAN2 = "/wp" SlashCmdList.WORLDPLAN = function() print('command pop') WorldPlan:GetPinsForMap() WorldPlan:RefreshPins() SetTimedCallbackForAllPins(0, function(self) self.FadeIn:Play() self.FlashIn:Play() end) SetTimedCallbackForAllPins(5, function(self) self.PendingFade:Play() end) SetTimedCallbackForAllPins(8, function(self) self.PendingFade:Stop() end) end --%end-debug% for mapID, mapName in pairs(WORLD_QUEST_MAPS) do QuestsByZone[mapID] = {} end for index, color in pairs(ITEM_QUALITY_COLORS) do POI_REWARD_TYPE[index] = { r = color.r, g = color.g, b = color.b, hex = color.hex, } end