annotate WorldPlan.lua @ 29:c1612c2c1840

WorldPlan: - Optimizations to in a lot of areas that should lead to better load-times and snappier world map. * Responding to quest log and map events by setting flags instead of tailing into the complete works. * Using a generic getter function for resolving pin visual attributes. and making use of blizzard constants for sanity's sake.
author Nenue
date Thu, 27 Oct 2016 13:50:56 -0400
parents 4a7e89bffbcb
children 8cb750e79952
rev   line source
Nenue@0 1 -- Veneer
Nenue@0 2 -- WorldPlan.lua
Nenue@0 3 -- Created: 8/16/2016 8:19 AM
Nenue@0 4 -- %file-revision%
Nenue@0 5 --[[
Nenue@0 6 Summary:
Nenue@0 7 Adds reward icons to the world quest POI markers, and adds said markers to the continent map.
Nenue@0 8
Nenue@0 9 Issues:
Nenue@0 10 Dalaran quests aren't visible until that map has been specifically viewed by the player.
Nenue@0 11 --]]
Nenue@0 12
Nenue@29 13 local ICON_UNKNOWN = "Interface\\ICONS\\inv_misc_questionmark"
Nenue@29 14 local ICON_MONEY = "Interface\\Buttons\\UI-GroupLoot-Coin-Up"
Nenue@29 15
Nenue@29 16 local POI_BORDER_MASK = "Interface\\Minimap\\UI-Minimap-Background"
Nenue@29 17 local POI_BORDER_FILL = "Interface\\BUTTONS\\YELLOWORANGE64"
Nenue@29 18 local POI_BORDER_BLUE = "Interface\\BUTTONS\\GRADBLUE"
Nenue@29 19 local POI_BORDER_RED = "Interface\\BUTTONS\\RedGrad64"
Nenue@29 20 local POI_BORDER_YELLOW = "Interface\\BUTTONS\\YELLOWORANGE64"
Nenue@29 21 local POI_BORDER_GREEN = "Interface\\BUTTONS\\GREENGRAD64"
Nenue@29 22
Nenue@29 23 WorldPlanCore = {
Nenue@29 24 defaults = {},
Nenue@29 25
Nenue@29 26 }
Nenue@0 27 WorldPlanPOIMixin = {}
Nenue@0 28 WorldPlanFilterPinMixin = {}
Nenue@0 29 local WorldPlanFlightMapMixin = setmetatable({}, {__tostring = function() return 'FlightMapHandler' end})
Nenue@0 30 local WorldQuests = setmetatable({ QuestsByID = {}, freePins = {} }, {__tostring = function() return 'QuestHandler' end})
Nenue@0 31 local FilterBar = setmetatable({ SummaryHeaders = {} }, {__tostring = function() return 'FilterBar' end})
Nenue@0 32
Nenue@0 33 local WorldPlan = WorldPlanCore
Nenue@0 34 local QuestPOI = WorldPlanPOIMixin
Nenue@0 35 local FilterPin = WorldPlanFilterPinMixin
Nenue@0 36 local WP_VERSION = "1.0"
Nenue@0 37
Nenue@9 38 local db
Nenue@0 39 local print = DEVIAN_WORKSPACE and function(...) _G.print('WP', ...) end or function() end
Nenue@7 40 local qprint = DEVIAN_WORKSPACE and function(...) _G.print('POI', ...) end or function() end
Nenue@7 41 local iprint = DEVIAN_WORKSPACE and function(...) _G.print('ItemScan', ...) end or function() end
Nenue@9 42 local wqprint = DEVIAN_WORKSPACE and function(...) _G.print('WorldQuests', ...) end or function() end
Nenue@9 43 local fbprint = DEVIAN_WORKSPACE and function(...) _G.print('FilterBar', ...) end or function() end
Nenue@7 44
Nenue@0 45 local wipe, tremove, tinsert, pairs, floor, tContains = table.wipe, table.remove, table.insert, pairs, floor, tContains
Nenue@0 46 local TQ_GetQuestsForPlayerByMapID = C_TaskQuest.GetQuestsForPlayerByMapID -- This function is not yet documented
Nenue@29 47 local TQ_GetQuestZoneID = C_TaskQuest.GetQuestZoneID
Nenue@0 48 local TQ_IsActive = C_TaskQuest.IsActive
Nenue@0 49 local ITEM_QUALITY_COLORS = ITEM_QUALITY_COLORS
Nenue@0 50 local WorldMap_DoesWorldQuestInfoPassFilters = WorldMap_DoesWorldQuestInfoPassFilters
Nenue@0 51 local QuestMapFrame_IsQuestWorldQuest = QuestMapFrame_IsQuestWorldQuest
Nenue@0 52 local GameTooltip = GameTooltip
Nenue@0 53 local GetItemIcon = GetItemIcon
Nenue@0 54
Nenue@0 55
Nenue@0 56 local GetMapInfo, QuestPOIGetIconInfo = GetMapInfo, QuestPOIGetIconInfo
Nenue@0 57 local GetQuestTagInfo, HaveQuestData = GetQuestTagInfo, HaveQuestData
Nenue@0 58 local GetNumQuestLogRewards, GetNumQuestLogRewardCurrencies, GetQuestLogRewardMoney = GetNumQuestLogRewards, GetNumQuestLogRewardCurrencies, GetQuestLogRewardMoney
Nenue@0 59 local GetQuestLogRewardInfo, GetQuestLogRewardCurrencyInfo, GetMoneyString = GetQuestLogRewardInfo, GetQuestLogRewardCurrencyInfo, GetMoneyString
Nenue@0 60
Nenue@0 61 local GetCurrentMapAreaID, GetMapNameByID, GetSuperTrackedQuestID = GetCurrentMapAreaID, GetMapNameByID, GetSuperTrackedQuestID
Nenue@0 62 local MC_GetNumZones, MC_GetZoneInfo = C_MapCanvas.GetNumZones, C_MapCanvas.GetZoneInfo
Nenue@0 63
Nenue@0 64
Nenue@0 65 local PinBaseIndex = 1600
Nenue@0 66 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 67
Nenue@0 68 -- maps where we do our own anchors
Nenue@0 69 local CONTINENT_MAPS = { [BROKEN_ISLES_ID] = BROKEN_ISLES_ID, }
Nenue@0 70 local WORLD_QUEST_MAPS = { [DALARAN_ID] = 'Dalaran70', [AZSUNA_ID] = 'Azsuna', [VALSHARAH_ID] = "Val'sharah",
Nenue@0 71 [HIGHMOUNTAIN_ID] = 'Highmountain', [STORMHEIM_ID] = 'Stormheim', [SURAMAR_ID] = 'Suramar', [EOA_ID] = 'EyeOfAszhara', }
Nenue@0 72 -- default color templates
Nenue@0 73 local ARTIFACT_COLOR = ITEM_QUALITY_COLORS[LE_ITEM_QUALITY_ARTIFACT]
Nenue@0 74 local MONEY_COLOR = {hex ='|cFFFFFF00', r=1, g=1, b=0}
Nenue@0 75 local COMMON_COLOR = ITEM_QUALITY_COLORS[LE_ITEM_QUALITY_COMMON]
Nenue@29 76 local DEFAULT_TYPE = {
Nenue@0 77 a = 1,
Nenue@0 78 r = 1, g = 1, b = 1,
Nenue@0 79 x = 0, y = 0,
Nenue@0 80 desaturated = true,
Nenue@27 81 pinMask = POI_BORDER_MASK,
Nenue@27 82 rewardMask = POI_BORDER_MASK,
Nenue@0 83 texture = POI_BORDER_FILL,
Nenue@0 84 continent = {
Nenue@0 85 PinSize = 18,
Nenue@0 86 Border = 3,
Nenue@0 87 TrackingBorder = 2,
Nenue@0 88 TagSize = 6,
Nenue@0 89 TimeleftStage = 3,
Nenue@27 90 showNumber = true,
Nenue@0 91 },
Nenue@0 92 zone = {
Nenue@0 93 PinSize = 22,
Nenue@0 94 Border = 3,
Nenue@0 95 TrackingBorder = 2,
Nenue@0 96 TagSize = 12,
Nenue@0 97 TimeleftStage = 3,
Nenue@27 98 showNumber = true,
Nenue@0 99 },
Nenue@0 100 minimized = {
Nenue@0 101 PinSize = 4,
Nenue@0 102 Border = 1,
Nenue@0 103 TrackingBorder = 2,
Nenue@0 104 NoIcon = true,
Nenue@0 105 TimeleftStage = 1,
Nenue@27 106 showNumber = false,
Nenue@0 107 }
Nenue@0 108 }
Nenue@29 109
Nenue@29 110
Nenue@0 111 local POI_FILTER_STYLE = setmetatable({
Nenue@0 112 continentBorder = 2,
Nenue@0 113 zoneBorder = 2,
Nenue@29 114 }, {__index = DEFAULT_TYPE})
Nenue@0 115
Nenue@9 116
Nenue@9 117 local defaults = {
Nenue@9 118 defaultPinStyle = POI_DEFAULT_TYPE,
Nenue@9 119 rewardStyle = POI_REWARD_TYPE,
Nenue@9 120 filterStyle = POI_FILTER_STYLE,
Nenue@27 121 ShowAllProfessionQuests = false,
Nenue@9 122 DisplayContinentSummary = true,
Nenue@9 123 DisplayContinentPins = true,
Nenue@9 124 NotifyWhenNewQuests = true,
Nenue@9 125 EnablePins = true,
Nenue@9 126 FadeWhileGrouped = true,
Nenue@9 127 }
Nenue@9 128
Nenue@0 129 -- Summary header structure
Nenue@29 130
Nenue@29 131 local REWARD_CASH = WORLD_QUEST_REWARD_TYPE_FLAG_GOLD
Nenue@29 132 local REWARD_ARTIFACT_POWER = WORLD_QUEST_REWARD_TYPE_FLAG_ARTIFACT_POWER
Nenue@29 133 local REWARD_GEAR = WORLD_QUEST_REWARD_TYPE_FLAG_EQUIPMENT
Nenue@29 134 local REWARD_CURRENCY = WORLD_QUEST_REWARD_TYPE_FLAG_ORDER_RESOURCES
Nenue@29 135 local REWARD_REAGENT = WORLD_QUEST_REWARD_TYPE_FLAG_MATERIALS
Nenue@29 136
Nenue@29 137
Nenue@29 138 local LE_QUEST_TAG_TYPE_PVP = LE_QUEST_TAG_TYPE_PVP
Nenue@29 139 local LE_QUEST_TAG_TYPE_PET_BATTLE = LE_QUEST_TAG_TYPE_PET_BATTLE
Nenue@29 140 local LE_QUEST_TAG_TYPE_DUNGEON = LE_QUEST_TAG_TYPE_DUNGEON
Nenue@29 141 local LE_QUEST_TAG_TYPE_PROFESSION = LE_QUEST_TAG_TYPE_PROFESSION
Nenue@29 142 local LE_QUEST_TAG_TYPE_NORMAL = LE_QUEST_TAG_TYPE_NORMAL
Nenue@0 143 local POI_FILTER_OPTIONS = {
Nenue@0 144 { label = 'Filters', texture = "Interface\\WorldMap\\WorldMap-Icon" },
Nenue@0 145 { filterKey= 'rewardType', filterValue = REWARD_ARTIFACT_POWER, label = 'Artifact Power', texture = "Interface\\ICONS\\inv_7xp_inscription_talenttome01" },
Nenue@29 146 { filterKey= 'rewardType', filterValue = REWARD_CURRENCY,label = 'Order Resources', texture = "Interface\\ICONS\\inv_misc_elvencoins" },
Nenue@0 147 { filterKey= 'rewardType', filterValue = REWARD_GEAR, label = 'Equipment', texture = "Interface\\ICONS\\garrison_bluearmorupgrade" },
Nenue@29 148 { filterKey= 'rewardType', filterValue = REWARD_REAGENT, label = 'Materials', texture = 1417744 },
Nenue@29 149 { filterKey= 'rewardType', filterValue = REWARD_CASH, label = 'Gold', texture = ICON_MONEY },
Nenue@0 150 { filterKey= 'worldQuestType', filterValue = LE_QUEST_TAG_TYPE_PVP, label = 'PvP', texture = "Interface\\Icons\\Ability_PVP_GladiatorMedallion", spacing = 10 },
Nenue@0 151 { filterKey= 'worldQuestType', filterValue = LE_QUEST_TAG_TYPE_PET_BATTLE, label = 'Pet Battle', texture = "Interface\\Icons\\PetJournalPortrait", },
Nenue@0 152 { filterKey= 'worldQuestType', filterValue = LE_QUEST_TAG_TYPE_DUNGEON, label = 'Dungeon', texture = "Interface\\LFGFRAME\\UI-LFR-PORTRAIT", },
Nenue@9 153 { filterKey= 'worldQuestType', filterValue = LE_QUEST_TAG_TYPE_PROFESSION, label = 'Profession', texture = "Interface\\ICONS\\70_professions_scroll_02", },
Nenue@0 154 }
Nenue@8 155 WorldPlanCore.BrokenIsleID = BROKEN_ISLES_ID
Nenue@8 156 WorldPlanCore.FilterStyle = POI_FILTER_STYLE
Nenue@8 157
Nenue@9 158 WorldPlanCore.FilterOptions = {}
Nenue@14 159 WorldPlanCore.UsedFilters = {}
Nenue@0 160
Nenue@9 161
Nenue@9 162 -- operating flags
Nenue@9 163 local superTrackedID
Nenue@9 164 local currentMapName
Nenue@9 165 local hasNewQuestPins
Nenue@9 166 local isContinentMap
Nenue@0 167 local numPins = 0
Nenue@0 168 local QuestsByZone = {}
Nenue@0 169 local QuestsByFaction = {}
Nenue@0 170 local QuestsByReward = {}
Nenue@0 171 local QuestsByTag = {}
Nenue@0 172 local QuestsByID = {}
Nenue@0 173 local QuestPositions = {}
Nenue@9 174 local FilterInclusions = {rewardType = {}, worldQuestType = {}, factionID = {}}
Nenue@1 175 local NotificationTypes = {}
Nenue@0 176 local ZoneInfo = {}
Nenue@0 177 local SummaryHeaders = {}
Nenue@0 178
Nenue@0 179 local FreePins = {}
Nenue@0 180 local NumPinFrames = 1
Nenue@0 181
Nenue@0 182 local hasPendingQuestData
Nenue@0 183 local notifyPlayed
Nenue@0 184 local scanner, wmtt, WorldMapPOIFrame
Nenue@0 185
Nenue@9 186 WorldPlanCore.QuestsByID = QuestsByID
Nenue@9 187 WorldPlanCore.QuestsByZone = QuestsByZone
Nenue@0 188
Nenue@0 189 local tasksQueue = {}
Nenue@0 190 local function OnNext (func)
Nenue@0 191 if #tasksQueue == 0 then
Nenue@0 192 _G.WorldPlan:SetScript('OnUpdate', function()
Nenue@0 193 local func = tremove(tasksQueue, 1)
Nenue@0 194 if func then
Nenue@0 195 func()
Nenue@0 196 end
Nenue@0 197 if #tasksQueue == 0 then
Nenue@0 198 _G.WorldPlan:SetScript('OnUpdate', nil)
Nenue@0 199 end
Nenue@0 200 end)
Nenue@0 201 end
Nenue@27 202 print('inserting task #', #tasksQueue+1, func)
Nenue@0 203 tinsert(tasksQueue, func)
Nenue@0 204 end
Nenue@0 205
Nenue@0 206 -- combines templates
Nenue@0 207 local function DoMixins(frame,...)
Nenue@0 208 for i = 1, select('#', ...) do
Nenue@0 209 for k,v in pairs(select(i,...)) do
Nenue@0 210 frame[k] = v
Nenue@0 211 end
Nenue@0 212 end
Nenue@0 213 return frame
Nenue@0 214 end
Nenue@0 215
Nenue@0 216
Nenue@0 217 -- update a masked texture without messing up its blending mask
Nenue@0 218 local SetMaskedTexture = function(region, file, mask)
Nenue@0 219 mask = mask or POI_BORDER_MASK
Nenue@0 220 region:SetMask(nil)
Nenue@0 221 region:SetTexture(file)
Nenue@0 222 region:SetMask(mask)
Nenue@0 223 end
Nenue@0 224
Nenue@0 225 -- tracking menu toggler
Nenue@0 226 local DropDown_OnClick = function(self)
Nenue@0 227 local key = self.value
Nenue@0 228 if key then
Nenue@0 229 if WorldPlanData[key] then
Nenue@0 230 WorldPlanData[key] = nil
Nenue@0 231 else
Nenue@0 232 WorldPlanData[key] = true
Nenue@0 233 end
Nenue@0 234 end
Nenue@9 235 WorldPlan:RefreshAll()
Nenue@0 236 end
Nenue@0 237
Nenue@0 238 function WorldPlan:print(...)
Nenue@0 239 local msg
Nenue@0 240 for i = 1, select('#', ...) do
Nenue@0 241 msg = (msg and (msg .. ' ') or '') .. tostring(select(i, ...))
Nenue@0 242 end
Nenue@0 243 DEFAULT_CHAT_FRAME:AddMessage("|cFF0088FFWorldPlan|r: " .. msg)
Nenue@0 244 end
Nenue@0 245
Nenue@0 246 function WorldPlan:OnLoad ()
Nenue@29 247
Nenue@29 248 self.Types = setmetatable({}, {
Nenue@29 249 __newindex = function(t, k, v)
Nenue@29 250 print('adding type', k)
Nenue@29 251 if type(v) == 'table' then
Nenue@29 252 v = setmetatable(v, {__index = function(t,k)
Nenue@29 253 print('##deferring to default key', k)
Nenue@29 254 return DEFAULT_TYPE[k]
Nenue@29 255 end})
Nenue@29 256 end
Nenue@29 257 rawset(t,k,v)
Nenue@29 258 end
Nenue@29 259 })
Nenue@29 260
Nenue@29 261 local rgbWhite = {1, 1, 1}
Nenue@29 262 self.Types[REWARD_REAGENT] = { r = 0, g = 1, b = 1 }
Nenue@29 263 self.Types[REWARD_ARTIFACT_POWER] = { r = 1, g = .25, b = .5, hasNumeric = true, numberRGB = rgbWhite }
Nenue@29 264 self.Types[REWARD_GEAR] = { r = .1, g = .2, b = 1 }
Nenue@29 265 self.Types[REWARD_CURRENCY] = { r = 1, g = 1, b = 0, hasNumeric = true, numberRGB = rgbWhite, }
Nenue@29 266 self.Types[REWARD_CASH] = { r = 0, g = 0, b = 0, }
Nenue@29 267
Nenue@29 268 for index, color in pairs(ITEM_QUALITY_COLORS) do
Nenue@29 269 self.Types[(index+127)] = { r = color.r, g = color.g, b = color.b, hex = color.hex, }
Nenue@29 270 end
Nenue@29 271
Nenue@0 272 WorldPlan = self
Nenue@0 273 scanner = _G.WorldPlanTooltip
Nenue@0 274 wmtt = _G.WorldMapTooltip
Nenue@0 275 WorldMapPOIFrame = _G.WorldMapPOIFrame
Nenue@0 276
Nenue@0 277 WorldPlan:print('v'..WP_VERSION)
Nenue@0 278
Nenue@0 279 self:RegisterEvent("QUESTLINE_UPDATE")
Nenue@0 280 self:RegisterEvent("QUEST_LOG_UPDATE")
Nenue@0 281 self:RegisterEvent("WORLD_MAP_UPDATE")
Nenue@0 282 self:RegisterEvent("WORLD_QUEST_COMPLETED_BY_SPELL")
Nenue@0 283 self:RegisterEvent("SUPER_TRACKED_QUEST_CHANGED")
Nenue@0 284 self:RegisterEvent("SKILL_LINES_CHANGED")
Nenue@0 285 self:RegisterEvent("ARTIFACT_XP_UPDATE")
Nenue@0 286 self:RegisterEvent("ADDON_LOADED")
Nenue@27 287 self:SetParent(WorldMapFrame)
Nenue@0 288
Nenue@0 289 WorldPlan.modules = {
Nenue@0 290 WorldQuests, FilterBar, WorldPlanFlightMapMixin,
Nenue@0 291 }
Nenue@0 292 end
Nenue@0 293
Nenue@27 294 function WorldPlan:OnShow()
Nenue@27 295 print(self:GetName()..':OnShow()')
Nenue@27 296 if self.isStale then
Nenue@27 297 self:RefreshAll()
Nenue@27 298 end
Nenue@27 299
Nenue@27 300 end
Nenue@27 301
Nenue@0 302 function WorldPlan:OnEvent (event, ...)
Nenue@0 303 print()
Nenue@27 304 print(event, self.initialized)
Nenue@0 305 if event == 'ADDON_LOADED' then
Nenue@0 306 local addon = ...
Nenue@0 307 if addon == "Blizzard_FlightMap" then
Nenue@0 308 print('do mixin junk')
Nenue@0 309 self.OnFlightMapLoaded()
Nenue@0 310
Nenue@0 311 end
Nenue@0 312 if IsLoggedIn() and not self.initialized then
Nenue@0 313 self:Setup()
Nenue@0 314 end
Nenue@0 315 elseif event == 'WORLD_MAP_UPDATE' then
Nenue@9 316 self.currentMapID = GetCurrentMapAreaID()
Nenue@0 317 self:RefreshAll()
Nenue@27 318 else
Nenue@27 319 for i, module in ipairs(self.modules) do
Nenue@27 320 if module.OnEvent then
Nenue@27 321 print('forwarding to', tostring(module))
Nenue@27 322 module:OnEvent(event, ...)
Nenue@27 323 end
Nenue@0 324 end
Nenue@0 325 end
Nenue@0 326 end
Nenue@0 327
Nenue@0 328
Nenue@0 329 function WorldPlan:Setup ()
Nenue@0 330 if not WorldPlanData then
Nenue@0 331 WorldPlanData = {key = 0 }
Nenue@0 332 end
Nenue@0 333 WorldPlanData.key = (WorldPlanData.key or 0) + 1
Nenue@0 334 self.db = WorldPlanData
Nenue@9 335 self.db.WorldQuests = self.db.WorldQuests or {}
Nenue@9 336 db = self.db
Nenue@9 337 for k,v in pairs(defaults) do
Nenue@18 338 --[===[@non-debug@
Nenue@18 339 if not db[k] then
Nenue@18 340 db[k] = v
Nenue@18 341 end
Nenue@18 342
Nenue@18 343 --@end-non-debug@]===]
Nenue@18 344 --@debug@
Nenue@9 345 db[k] = v
Nenue@18 346 --@end-debug@
Nenue@9 347 end
Nenue@9 348
Nenue@9 349 self.currentMapID = GetCurrentMapAreaID()
Nenue@0 350
Nenue@0 351 for i, module in ipairs(self.modules) do
Nenue@9 352 module.db = self.db
Nenue@0 353 if module.Setup then module:Setup() end
Nenue@0 354 if not module.RegisterEvent then
Nenue@0 355 module.RegisterEvent = self.RegisterEvent
Nenue@0 356 end
Nenue@0 357 end
Nenue@0 358 self.initialized = true
Nenue@0 359
Nenue@9 360 hooksecurefunc("UIDropDownMenu_Initialize", self.OnDropDownInitialize)
Nenue@0 361 end
Nenue@0 362
Nenue@29 363 function WorldPlan:GetTypeInfo(typeID)
Nenue@29 364 local info, extraInfo
Nenue@29 365 if (not typeID) or (not self.Types[typeID]) then
Nenue@29 366 qprint('## sent default type')
Nenue@29 367 info = DEFAULT_TYPE
Nenue@29 368 else
Nenue@29 369 qprint('## sent defined type', typeID)
Nenue@29 370 info = self.Types[typeID]
Nenue@29 371 end
Nenue@29 372
Nenue@29 373 if isContinentMap then
Nenue@29 374 extraInfo = info.continent
Nenue@29 375 qprint('### continent subtype', extraInfo)
Nenue@29 376 else
Nenue@29 377 extraInfo = info.zone
Nenue@29 378
Nenue@29 379 qprint('### zone subtype', extraInfo)
Nenue@29 380 end
Nenue@29 381 return info, extraInfo
Nenue@29 382 end
Nenue@29 383
Nenue@29 384 do
Nenue@29 385 local timeStates = {
Nenue@29 386 {maxSeconds = 60,
Nenue@29 387 r=1, g=0.25, b =0, format = function (minutes) return '|cFFFF4400'.. minutes .. 'm' end,
Nenue@29 388 },
Nenue@29 389 {maxSeconds = 240,
Nenue@29 390 r=1, g=.5, b=0, format = function(minutes) return '|cFFFF4400'.. floor(minutes/60) .. 'h' end,
Nenue@29 391 },
Nenue@29 392 {maxSeconds = 1440,
Nenue@29 393 r=1, g=1, b=0, format = function(minutes) return '|cFFFFFF00'.. floor(minutes/60) .. 'h' end,
Nenue@29 394 },
Nenue@29 395 {maxSeconds = 10081,
Nenue@29 396 r=0, g=1, b=0,
Nenue@29 397 }, -- 7 days + 1 minute
Nenue@29 398 }
Nenue@29 399 -- Generates a timeleft string
Nenue@29 400 function WorldPlan:GetTimeInfo(timeLeft, limit)
Nenue@29 401 limit = limit or #timeStates
Nenue@29 402 for index = 1, limit do
Nenue@29 403 local state = timeStates[index]
Nenue@29 404 if timeLeft <= state.maxSeconds then
Nenue@29 405 local text
Nenue@29 406 if state.format then
Nenue@29 407 text = state.format(timeLeft)
Nenue@29 408 end
Nenue@29 409 return text, index
Nenue@29 410 end
Nenue@29 411 end
Nenue@29 412 return nil, nil
Nenue@29 413 end
Nenue@29 414 end
Nenue@29 415
Nenue@0 416 function WorldPlan:RefreshAll (forced)
Nenue@9 417 if not self.initialized then
Nenue@9 418 return
Nenue@9 419 end
Nenue@9 420
Nenue@9 421 POI_DEFAULT_TYPE = db.defaultPinStyle
Nenue@9 422 POI_REWARD_TYPE = db.rewardStyle
Nenue@9 423 POI_FILTER_STYLE = db.filterStyle
Nenue@9 424
Nenue@9 425
Nenue@9 426 for i, module in ipairs(self.modules) do
Nenue@9 427 if module.Reset then
Nenue@9 428 print(module, 'Reset()')
Nenue@9 429 module:Reset()
Nenue@9 430 end
Nenue@9 431 end
Nenue@9 432
Nenue@0 433 for i, module in ipairs(self.modules) do
Nenue@0 434 if module.Refresh then
Nenue@9 435 print(module, 'Refresh()')
Nenue@0 436 module:Refresh()
Nenue@0 437 end
Nenue@0 438 end
Nenue@9 439
Nenue@9 440 for i, module in ipairs(self.modules) do
Nenue@9 441 if module.Cleanup then
Nenue@9 442 print(module, 'Cleanup()')
Nenue@9 443 module:Cleanup()
Nenue@9 444 end
Nenue@9 445 end
Nenue@0 446 end
Nenue@0 447 function WorldPlan:UpdateAnchors ()
Nenue@0 448 for i, module in ipairs(self.modules) do
Nenue@0 449 if module.UpdateAnchors then
Nenue@0 450 module:UpdateAnchors()
Nenue@0 451 end
Nenue@0 452 end
Nenue@0 453 end
Nenue@0 454
Nenue@0 455 -- insert visual options into the tracking button menu
Nenue@0 456 WorldPlan.OnDropDownInitialize = function (self, callback, dropType)
Nenue@0 457 if self ~= WorldMapFrameDropDown then
Nenue@0 458 return
Nenue@0 459 end
Nenue@9 460 local db = WorldPlan.db
Nenue@0 461
Nenue@0 462 local info = UIDropDownMenu_CreateInfo()
Nenue@0 463 info.text = ""
Nenue@0 464 info.isTitle = true
Nenue@0 465 UIDropDownMenu_AddButton(info)
Nenue@0 466 info.text = "|cFF00AAFFWorldPlan|r"
Nenue@0 467 info.isTitle = true
Nenue@0 468 UIDropDownMenu_AddButton(info)
Nenue@0 469 info.isTitle = nil
Nenue@0 470 info.disabled = nil
Nenue@0 471 info.keepShownOnClick = true
Nenue@0 472 info.tooltipOnButton = 1
Nenue@0 473
Nenue@9 474 info.text = "Enable"
Nenue@9 475 info.isNotRadio = true
Nenue@9 476 info.value = "EnablePins"
Nenue@9 477 info.checked = db.EnablePins
Nenue@9 478 info.tooltipTitle = "Enable World Quest Overlays"
Nenue@9 479 info.tooltipText = "Toggle the detail layers here."
Nenue@9 480 info.func = DropDown_OnClick
Nenue@9 481 UIDropDownMenu_AddButton(info)
Nenue@9 482
Nenue@9 483 info.text = "Display All Profession Quests"
Nenue@0 484 info.isNotRadio = true
Nenue@0 485 info.value = "ShowAllProfessionQuests"
Nenue@9 486 info.checked = db.ShowAllProfessionQuests
Nenue@0 487 info.tooltipTitle = "Hidden Quests"
Nenue@0 488 info.tooltipText = "Display work order and profession-related quests that are skipped by the default UI."
Nenue@0 489 info.func = DropDown_OnClick
Nenue@0 490 UIDropDownMenu_AddButton(info)
Nenue@0 491
Nenue@0 492 info.text = "Show Continent Pins"
Nenue@0 493 info.isNotRadio = true
Nenue@0 494 info.value = "DisplayContinentPins"
Nenue@9 495 info.checked = db.DisplayContinentPins
Nenue@0 496 info.tooltipTitle = "Continent Pins"
Nenue@0 497 info.tooltipText = "Display quest pins on the continent map (may get cramped)."
Nenue@0 498 info.func = DropDown_OnClick
Nenue@0 499 UIDropDownMenu_AddButton(info)
Nenue@0 500
Nenue@0 501 info.text = "Show Summary"
Nenue@0 502 info.isNotRadio = true
Nenue@0 503 info.value = "DisplayContinentSummary"
Nenue@0 504 info.tooltipTitle = "Summary Bar"
Nenue@0 505 info.tooltipText = "Display a summary of active world quests. Note: requires directly viewing Broken Isle and Dalaran maps to gain complete info."
Nenue@9 506 info.checked = db.DisplayContinentSummary
Nenue@9 507 info.func = DropDown_OnClick
Nenue@9 508 UIDropDownMenu_AddButton(info)
Nenue@9 509
Nenue@9 510 info.text = "Fade In Groups"
Nenue@9 511 info.isNotRadio = true
Nenue@9 512 info.value = "FadeWhileGrouped"
Nenue@9 513 info.tooltipTitle = "Group Fade"
Nenue@9 514 info.tooltipText = "Reduce pin alpha when grouped, so player dots are easier to see."
Nenue@9 515 info.checked = db.DisplayContinentSummary
Nenue@0 516 info.func = DropDown_OnClick
Nenue@0 517 UIDropDownMenu_AddButton(info)
Nenue@0 518 end
Nenue@0 519
Nenue@0 520 function WorldQuests:Setup()
Nenue@29 521
Nenue@29 522
Nenue@29 523 for mapID, mapName in pairs(WORLD_QUEST_MAPS) do
Nenue@29 524 QuestsByZone[mapID] = {}
Nenue@29 525 end
Nenue@29 526
Nenue@29 527
Nenue@0 528 -- refresh positions any time blizzard does so (i.e. mousewheel zoom)
Nenue@0 529 hooksecurefunc("WorldMapScrollFrame_ReanchorQuestPOIs", function()
Nenue@9 530 self:Refresh(true)
Nenue@0 531 end)
Nenue@0 532
Nenue@0 533 -- hide the original world quest POIs
Nenue@0 534 hooksecurefunc("WorldMap_UpdateQuestBonusObjectives", function()
Nenue@0 535 for i = 1, NUM_WORLDMAP_TASK_POIS do
Nenue@0 536 local button = _G['WorldMapFrameTaskPOI'..i]
Nenue@0 537 if button and button.worldQuest then
Nenue@0 538 button:Hide()
Nenue@0 539 end
Nenue@0 540 end
Nenue@0 541 end)
Nenue@0 542
Nenue@0 543 end
Nenue@0 544
Nenue@0 545 function WorldQuests:OnEvent (event, ...)
Nenue@27 546 print('|cFFFFFF00'..tostring(self)..':OnEvent()'..event..'|r', GetTime(), ...)
Nenue@0 547 if event == 'QUEST_LOG_UPDATE' then
Nenue@0 548 local questID, added = ...
Nenue@0 549 if questID and added then
Nenue@29 550 local questPOI = self:AcquirePin(questID)
Nenue@29 551 self.hasUpdate, self.isPending = questPOI:RefreshData()
Nenue@0 552 else
Nenue@29 553 self:RefreshData()
Nenue@0 554 end
Nenue@27 555 print('WorldMapFrame', WorldMapFrame:IsVisible(), 'doRefresh:', hasNewQuestPins)
Nenue@27 556 if WorldMapFrame:IsVisible() and hasNewQuestPins then
Nenue@27 557 self:Refresh(true)
Nenue@27 558 end
Nenue@27 559
Nenue@0 560 elseif event == 'WORLD_QUEST_COMPLETED_BY_SPELL' then
Nenue@0 561 local questID = ...
Nenue@0 562 if questID and QuestsByID[questID] then
Nenue@0 563 self:ReleasePin(QuestsByID[questID])
Nenue@0 564 end
Nenue@0 565 elseif event == 'SKILL_LINES_CHANGED' then
Nenue@9 566 self:Refresh(true)
Nenue@0 567 end
Nenue@0 568 end
Nenue@29 569 local TQ_GetQuestLocation = C_TaskQuest.GetQuestLocation
Nenue@29 570 function WorldQuests:AcquirePin (questID, mapID)
Nenue@0 571 local pin = QuestsByID[questID]
Nenue@0 572 local isNew = false
Nenue@0 573 if not pin then
Nenue@0 574 isNew = true
Nenue@0 575 local numFree = #self.freePins
Nenue@0 576 if numFree >= 1 then
Nenue@0 577 pin = tremove(self.freePins, numFree)
Nenue@0 578 --print('|cFF00FF00Re-using', pin:GetName())
Nenue@0 579 else
Nenue@0 580 local name = 'WorldPlanQuestMarker' .. NumPinFrames
Nenue@0 581 --print('|cFF00FF00Creating', name)
Nenue@0 582 pin = CreateFrame('Frame', name, WorldMapPOIFrame, 'WorldPlanQuestPin')
Nenue@29 583
Nenue@0 584 pin:SetFrameStrata('HIGH')
Nenue@0 585 NumPinFrames = NumPinFrames + 1
Nenue@0 586 --pin.iconBorder:SetVertexColor(0,0,0,1)
Nenue@0 587 end
Nenue@29 588 pin:SetID(questID)
Nenue@0 589 pin.isNew = true
Nenue@0 590 pin.currentWidth = nil
Nenue@0 591
Nenue@0 592 -- used by TaskPOI_x scripts
Nenue@0 593 pin.questID = questID
Nenue@0 594 pin.worldQuest = true
Nenue@7 595
Nenue@29 596 QuestsByID[questID] = pin
Nenue@0 597 else
Nenue@0 598 --print('|cFF00FF00Using', pin:GetName())
Nenue@0 599 end
Nenue@29 600 mapID = mapID or TQ_GetQuestZoneID(questID)
Nenue@29 601 QuestsByZone[mapID][questID] = pin
Nenue@0 602
Nenue@0 603 return pin, isNew
Nenue@0 604 end
Nenue@0 605
Nenue@0 606 -- remove from index and add it to the recycling heap
Nenue@0 607 function WorldQuests:ReleasePin (pin)
Nenue@0 608
Nenue@0 609 local id = pin.questId
Nenue@0 610 if id then
Nenue@0 611 QuestsByID[id] = nil
Nenue@0 612 for i, zone in pairs(QuestsByZone) do
Nenue@0 613 print('-', i, zone[i])
Nenue@0 614 zone[id] = nil
Nenue@0 615 end
Nenue@0 616 end
Nenue@0 617 if pin.factionID then
Nenue@0 618 QuestsByFaction[pin.factionID][id] = nil
Nenue@0 619 end
Nenue@0 620 pin:Hide()
Nenue@0 621 pin:ClearAllPoints()
Nenue@0 622 tinsert(self.freePins, pin)
Nenue@0 623 print('|cFFFF4400Clearing out', pin:GetName(),id)
Nenue@0 624 end
Nenue@0 625
Nenue@0 626 -- create of update quest pins for a map and its underlying zones
Nenue@29 627 function WorldQuests:RefreshData (mapID)
Nenue@9 628 local print = wqprint
Nenue@0 629 mapID = mapID or GetCurrentMapAreaID()
Nenue@0 630 superTrackedID = GetSuperTrackedQuestID()
Nenue@0 631 if not mapID then
Nenue@0 632 -- info not available yet
Nenue@0 633 return
Nenue@0 634 end
Nenue@0 635 if mapID == BROKEN_ISLES_ID then
Nenue@29 636 self.hasUpdate = false
Nenue@0 637 print('|cFF00FFFFRefreshQuestsForMap|r', mapID, GetMapNameByID(mapID), superTrackedID)
Nenue@0 638 self.fullSearch = true
Nenue@0 639 for i = 1, MC_GetNumZones(mapID) do
Nenue@0 640 local submapID, name, depth = MC_GetZoneInfo(mapID, i)
Nenue@29 641 self:RefreshData(submapID)
Nenue@0 642 end
Nenue@0 643 self.fullSearch = nil
Nenue@0 644 elseif QuestsByZone[mapID] then
Nenue@0 645 local taskInfo = TQ_GetQuestsForPlayerByMapID(mapID)
Nenue@0 646 local quest = QuestsByZone[mapID]
Nenue@0 647 local numQuests = 0
Nenue@0 648 if taskInfo and #taskInfo >= 1 then
Nenue@0 649 print('|cFF00FFFFRefreshQuestsForMap|r', mapID, GetMapNameByID(mapID), #taskInfo)
Nenue@0 650 wipe(QuestsByZone[mapID])
Nenue@0 651 ZoneInfo[mapID] = taskInfo
Nenue@0 652 for taskID, info in pairs(taskInfo) do
Nenue@29 653 print('-', taskID)
Nenue@0 654 local questID = info.questId
Nenue@0 655 info.mapID = mapID
Nenue@29 656 local questPOI = self:AcquirePin(questID, mapID)
Nenue@29 657 local hasUpdate, isPending = questPOI:RefreshData(taskInfo)
Nenue@29 658 self.hasUpdate = (self.hasUpdate or hasUpdate)
Nenue@29 659 self.isPending = (self.isPending or isPending)
Nenue@0 660 numQuests = numQuests + 1
Nenue@0 661 end
Nenue@0 662 end
Nenue@0 663 end
Nenue@0 664
Nenue@29 665 print(' hasUpdate:', self.hasUpdate, 'isPending:', self.isPending, 'timer:', self.OnNext)
Nenue@29 666 if self.hasUpdate then
Nenue@29 667 self.OnNext = self.OnNext or C_Timer.NewTimer(0.25, function()
Nenue@29 668 self:Refresh(true)
Nenue@29 669 self.OnNext = nil
Nenue@29 670 end)
Nenue@0 671 end
Nenue@0 672 end
Nenue@0 673
Nenue@0 674 function WorldQuests:Refresh(forced)
Nenue@9 675 local print = wqprint
Nenue@9 676 print('|cFF00FF88'..tostring(self)..':Refresh()|r')
Nenue@0 677 if not WorldMapPOIFrame:IsVisible() then
Nenue@0 678 return
Nenue@0 679 end
Nenue@9 680 if forced then
Nenue@9 681 self:Reset()
Nenue@9 682 end
Nenue@0 683 self:UpdateAnchors()
Nenue@9 684
Nenue@9 685 if forced then
Nenue@9 686 self:Cleanup ()
Nenue@9 687 end
Nenue@0 688 end
Nenue@0 689
Nenue@0 690 -- prepares elements for a map update
Nenue@0 691 function WorldQuests:Reset ()
Nenue@9 692 local print = wqprint
Nenue@9 693 print('|cFF00FF88'..tostring(self)..':Reset()|r')
Nenue@0 694 wipe(QuestPositions)
Nenue@0 695 wipe(QuestsByReward)
Nenue@0 696 wipe(QuestsByTag)
Nenue@0 697 for questID, pin in pairs(QuestsByID) do
Nenue@0 698 pin.used = nil
Nenue@0 699 end
Nenue@0 700 end
Nenue@0 701
Nenue@0 702 -- update visibility states of all pins
Nenue@0 703 function WorldQuests:UpdateAnchors (submapID)
Nenue@9 704 local print = wqprint
Nenue@9 705 local db = WorldPlan.db
Nenue@0 706 local mapFileName, textureHeight, textureWidth, isMicroDungeon, microDungeonMapName = GetMapInfo()
Nenue@0 707 if isMicroDungeon then
Nenue@0 708 return
Nenue@0 709 end
Nenue@0 710
Nenue@0 711 local currentMap = GetCurrentMapAreaID()
Nenue@0 712 local submapID = submapID or currentMap
Nenue@0 713
Nenue@9 714 if submapID == BROKEN_ISLES_ID and (not db.DisplayContinentPins) then
Nenue@0 715 print('not updating map for reasons')
Nenue@0 716 return
Nenue@0 717 end
Nenue@0 718 print('|cFF88FF00'..tostring(self)..':UpdateAnchors|r', submapID, GetMapNameByID(submapID), 'pin count:', numPins)
Nenue@0 719 local numZones = MC_GetNumZones(submapID)
Nenue@0 720 if numZones then
Nenue@0 721 for i = 1, numZones do
Nenue@0 722 local subMapID = MC_GetZoneInfo(submapID, i)
Nenue@0 723 self:UpdateAnchors(subMapID)
Nenue@0 724 end
Nenue@0 725 end
Nenue@0 726 local pins = QuestsByZone[submapID]
Nenue@0 727
Nenue@0 728 if pins then
Nenue@0 729 local hostFrame = WorldMapPOIFrame
Nenue@0 730 local mapWidth, mapHeight = hostFrame:GetSize()
Nenue@0 731 for questID, pin in pairs(pins) do
Nenue@9 732 pin:IsShowable()
Nenue@9 733 if pin.used then
Nenue@9 734 pin:SetFrameLevel(PinBaseIndex+ (pin.whiteListed and 200 or 0) +numPins)
Nenue@9 735 print('level', PinBaseIndex+ (pin.whiteListed and 200 or 0) +numPins)
Nenue@0 736 pin:SetAnchor(WorldMapPOIFrame, currentMap, mapWidth, mapHeight)
Nenue@0 737 numPins = numPins + 1
Nenue@0 738 end
Nenue@0 739 end
Nenue@0 740 end
Nenue@0 741 end
Nenue@0 742
Nenue@0 743 -- shows, animates, or hides pins based on their current visibility flags
Nenue@0 744 local debug_show = {}
Nenue@0 745 local debug_animate = {}
Nenue@0 746 local debug_hide = {}
Nenue@0 747 function WorldQuests:Cleanup ()
Nenue@9 748 local print = wqprint
Nenue@9 749 local showQuestPOI = db.EnablePins
Nenue@0 750 print('|cFFFFFF00'..tostring(self)..':Cleanup()|r')
Nenue@9 751 local mapID = GetCurrentMapAreaID()
Nenue@9 752 isContinentMap = (mapID == BROKEN_ISLES_ID)
Nenue@9 753
Nenue@0 754 wipe(debug_show)
Nenue@0 755 wipe(debug_animate)
Nenue@0 756 wipe(debug_hide)
Nenue@0 757 -- continent or zone sizing
Nenue@9 758 local fadeGrouped = (db.FadeWhileGrouped and IsInGroup())
Nenue@0 759
Nenue@0 760 numPins = 0
Nenue@0 761 for questID, pin in pairs(QuestsByID) do
Nenue@0 762 -- can we show it?
Nenue@0 763 if showQuestPOI and (pin.used) then
Nenue@0 764
Nenue@9 765 if fadeGrouped then
Nenue@9 766 pin:SetAlpha(0.25)
Nenue@9 767 else
Nenue@9 768 pin:SetAlpha(1)
Nenue@9 769 end
Nenue@0 770 -- is it a new quest?
Nenue@0 771 if pin.isNew then
Nenue@0 772 if not pin.isAnimating then
Nenue@0 773 pin.isAnimating = true
Nenue@0 774 OnNext(function()
Nenue@27 775 pin:ShowNew()
Nenue@0 776 end)
Nenue@0 777 if not notifyPlayed then
Nenue@1 778 for k,v in pairs(NotificationTypes) do
Nenue@1 779 if v[pin[k]] then
Nenue@1 780 notifyPlayed = true
Nenue@1 781 PlaySoundKitID(23404)
Nenue@1 782 end
Nenue@1 783 end
Nenue@0 784 end
Nenue@0 785 tinsert(debug_animate,questID)
Nenue@9 786 else
Nenue@9 787
Nenue@9 788 print('animating? ', questID, 'filtered:', pin.filtered)
Nenue@0 789 end
Nenue@1 790 -- trap new but animating pins here
Nenue@0 791 else
Nenue@0 792 -- hard show existing pin
Nenue@9 793 print('refresh #', questID, 'filtered:', pin.filtered)
Nenue@27 794 pin.hasUpdate = true
Nenue@27 795 pin:Show(true)
Nenue@0 796 tinsert(debug_show,questID)
Nenue@0 797 end
Nenue@0 798 else
Nenue@9 799 if pin:IsShown() then
Nenue@9 800 tinsert(debug_hide,questID)
Nenue@9 801 end
Nenue@9 802 pin.isAnimating = nil
Nenue@9 803 pin.FadeIn:Stop()
Nenue@0 804 pin:Hide()
Nenue@0 805 end
Nenue@0 806 end
Nenue@0 807 print(' adding:', table.concat(debug_animate, ',' ))
Nenue@9 808 print(' refresh:', table.concat(debug_show, ',' ))
Nenue@9 809 print(' hiding:', table.concat(debug_hide, ',' ))
Nenue@0 810 hasNewQuestPins = nil
Nenue@1 811 notifyPlayed = nil
Nenue@0 812 end
Nenue@0 813
Nenue@0 814 -- data provider manipulations for the taxi map
Nenue@0 815 WorldPlan.OnFlightMapLoaded = function()
Nenue@0 816 if true then return end
Nenue@0 817 -- todo: figure out how to layer inside the map canvas
Nenue@0 818 local res = {}
Nenue@0 819 local t = {}
Nenue@0 820 for k,v in pairs(FlightMapFrame) do
Nenue@0 821 tinsert(res, tostring(k))
Nenue@0 822 end
Nenue@0 823
Nenue@0 824 table.sort(res)
Nenue@0 825 for i, k in ipairs(res) do
Nenue@0 826 print(k)
Nenue@0 827 end
Nenue@0 828 hooksecurefunc(FlightMapFrame, 'RefreshAll', function(self)
Nenue@0 829 print('|cFF0088FFWQDP RefreshAllData ', GetTime())
Nenue@0 830
Nenue@0 831 WorldPlan:GetPinsForMap(self:GetMapID())
Nenue@0 832
Nenue@0 833 for pin in self:EnumerateAllPins() do
Nenue@0 834 if pin.worldQuest then
Nenue@0 835 --print('got pin #', pin.questID)
Nenue@0 836 local wp = QuestsByID[pin.questID]
Nenue@0 837 if wp then
Nenue@0 838 wp:ClearAllPoints()
Nenue@0 839 wp:SetParent(FlightMapFrame.ScrollContainer)
Nenue@0 840 wp:SetFrameStrata('MEDIUM')
Nenue@0 841 wp:SetPoint('CENTER', pin, 'CENTER')
Nenue@0 842 wp:Show()
Nenue@0 843 end
Nenue@0 844 end
Nenue@0 845 end
Nenue@0 846 end)
Nenue@0 847 end
Nenue@0 848
Nenue@0 849
Nenue@0 850
Nenue@0 851 local throttle = 0
Nenue@0 852 local tooltip = CreateFrame ("GameTooltip", "VeneerWorldQuestsScanner", nil, "GameTooltipTemplate")
Nenue@0 853 local tooltipLine1 = _G['VeneerWorldQuestsScannerTextLeft1']
Nenue@0 854 local tooltipLine3 = _G['VeneerWorldQuestsScannerTextLeft3']
Nenue@0 855 local GetTime, mod = GetTime, mod
Nenue@0 856
Nenue@0 857
Nenue@0 858
Nenue@0 859
Nenue@9 860 function WorldQuests:FilterCheckByID(questID)
Nenue@9 861 local pin = WorldQuests:GetPinByQuestID(questID)
Nenue@9 862 return pin:IsShowable()
Nenue@0 863 end
Nenue@0 864
Nenue@0 865
Nenue@9 866 function QuestPOI:IsShowable ()
Nenue@9 867 local print = wqprint
Nenue@9 868 local db = WorldPlan.db
Nenue@0 869 local qType = self.worldQuestType
Nenue@0 870 local rType = self.rewardType
Nenue@0 871 self.filtered = nil
Nenue@9 872 self.used = true
Nenue@9 873
Nenue@14 874 print(' |cFFFF4400IsShowable()|r', self.title)
Nenue@14 875
Nenue@14 876 local isIncluded
Nenue@14 877 for filterKey, filterValues in pairs(WorldPlan.UsedFilters) do
Nenue@0 878 local controlValue = self[filterKey]
Nenue@13 879 if controlValue then
Nenue@14 880 local filterType = filterValues[controlValue]
Nenue@14 881 if filterType == true then
Nenue@14 882 isIncluded = true
Nenue@14 883 print(' include? ', filterKey, controlValue, filterType)
Nenue@13 884 end
Nenue@0 885 end
Nenue@16 886 self.filtered = (not isIncluded)
Nenue@0 887 end
Nenue@14 888
Nenue@0 889
Nenue@0 890 if not TQ_IsActive(self.questID) then
Nenue@9 891 self.used = nil
Nenue@0 892 end
Nenue@0 893 if qType == LE_QUEST_TAG_TYPE_PROFESSION then
Nenue@9 894 if not (db.ShowAllProfessionQuests or (self.tradeskillLineIndex and GetProfessionInfo(self.tradeskillLineIndex))) then
Nenue@9 895 self.used = nil
Nenue@0 896 end
Nenue@0 897 end
Nenue@9 898 return self.used, self.filtered
Nenue@0 899 end
Nenue@0 900
Nenue@0 901 function QuestPOI:UpdateTimer (timeLeft, timeType)
Nenue@0 902 print('|cFF0088FFUpdatePinTimer()|r')
Nenue@0 903 end
Nenue@0 904
Nenue@9 905 --- Fixes icons upon size update
Nenue@9 906 function QuestPOI:UpdateSize (style, subStyle)
Nenue@0 907 self.style = self.style or POI_DEFAULT_TYPE
Nenue@27 908 style = style or self.style
Nenue@27 909 subStyle = subStyle or self.subStyle
Nenue@0 910
Nenue@27 911 qprint('|cFF00FF88'..self:GetName()..'|r:UpdateSize()', style, subStyle)
Nenue@0 912
Nenue@0 913 self.currentWidth = subStyle.PinSize
Nenue@0 914 self.borderSize = subStyle.Border
Nenue@0 915 self.trackingBorderSize = subStyle.TrackingBorder
Nenue@0 916 self.tagSize = subStyle.TagSize
Nenue@0 917 self.TimeleftStage = subStyle.TimeleftStage
Nenue@0 918 self.NoIcon = subStyle.NoIcon
Nenue@0 919
Nenue@27 920
Nenue@0 921 self:SetSize(self.currentWidth, self.currentWidth)
Nenue@0 922
Nenue@27 923 local icon = self.icon
Nenue@0 924 local iconBorder = self.iconBorder
Nenue@0 925 local trackingBorder = self.supertrackBorder
Nenue@0 926 local tag = self.tagIcon
Nenue@27 927 local pinMask = style.pinMask
Nenue@27 928 local rewardMask = style.rewardMask
Nenue@0 929
Nenue@27 930 if self.NoIcon then
Nenue@27 931 self.icon:Hide()
Nenue@27 932 else
Nenue@27 933 self.icon:Show()
Nenue@27 934 icon:SetMask(nil)
Nenue@27 935 icon:SetMask(rewardMask)
Nenue@27 936 icon:SetTexture(self.icon:GetTexture())
Nenue@27 937 end
Nenue@27 938 iconBorder:SetMask(nil)
Nenue@27 939 trackingBorder:SetMask(nil)
Nenue@0 940
Nenue@0 941
Nenue@0 942 local borderWidth = self.borderSize
Nenue@0 943 local trackingWidth = self.trackingBorderSize
Nenue@0 944
Nenue@0 945 iconBorder:ClearAllPoints()
Nenue@0 946 iconBorder:SetPoint('BOTTOMLEFT', self, 'BOTTOMLEFT', -borderWidth + (style.x or 0), -borderWidth + (style.y or 0))
Nenue@0 947 iconBorder:SetPoint('TOPRIGHT', self, 'TOPRIGHT', borderWidth + (style.x or 0), borderWidth + (style.y or 0))
Nenue@0 948
Nenue@0 949 trackingBorder:ClearAllPoints()
Nenue@0 950 trackingBorder:SetPoint('BOTTOMLEFT', iconBorder, 'BOTTOMLEFT', -trackingWidth, -trackingWidth)
Nenue@0 951 trackingBorder:SetPoint('TOPRIGHT', iconBorder, 'TOPRIGHT', trackingWidth, trackingWidth)
Nenue@0 952
Nenue@0 953 if self.tagSize then
Nenue@0 954 tag:Show()
Nenue@0 955 tag:ClearAllPoints()
Nenue@0 956 tag:SetPoint('BOTTOMRIGHT', self, 'BOTTOMRIGHT', borderWidth, -borderWidth)
Nenue@0 957 else
Nenue@0 958 tag:Hide()
Nenue@0 959 end
Nenue@0 960
Nenue@9 961 --qprint('using mask:', mask, self.name )
Nenue@27 962 iconBorder:SetMask(pinMask)
Nenue@27 963 trackingBorder:SetMask(pinMask)
Nenue@0 964
Nenue@0 965
Nenue@0 966 end
Nenue@0 967
Nenue@0 968
Nenue@0 969 function FilterBar:OnEvent(event)
Nenue@0 970 if event == 'QUEST_LOG_UPDATE' then
Nenue@0 971 self:Refresh()
Nenue@0 972 end
Nenue@0 973 end
Nenue@0 974
Nenue@0 975 function FilterBar:PassesFilterSet(filterKey, pin)
Nenue@0 976 local passesFilter = true
Nenue@0 977 for filterKey, filters in pairs(QuestFilters) do
Nenue@0 978 for rewardType, value in pairs(QuestFilters[filterKey]) do
Nenue@0 979 if value == 1 and rewardType == pin[filterKey] then
Nenue@0 980 passesFilter = true
Nenue@0 981 elseif value == -1 and rewardType == pin[filterKey] then
Nenue@0 982 passesFilter = false
Nenue@0 983 end
Nenue@0 984 end
Nenue@0 985 end
Nenue@0 986 return passesFilter
Nenue@0 987 end
Nenue@0 988
Nenue@9 989
Nenue@9 990 local bountyIndex
Nenue@0 991 local debug_headers = {}
Nenue@9 992
Nenue@9 993 function FilterBar:Setup()
Nenue@9 994 self:GetFilters()
Nenue@9 995 end
Nenue@9 996
Nenue@9 997 function FilterBar:OnEvent(event,...)
Nenue@9 998 if event == 'QUEST_LOG_UPDATE' then
Nenue@9 999 self:Reset()
Nenue@9 1000 self:Refresh()
Nenue@9 1001 end
Nenue@9 1002 end
Nenue@9 1003
Nenue@9 1004 function FilterBar:GetFilters()
Nenue@9 1005
Nenue@9 1006 local print = fbprint
Nenue@9 1007 wipe(WorldPlan.FilterOptions)
Nenue@9 1008
Nenue@9 1009 for index, info in ipairs(POI_FILTER_OPTIONS) do
Nenue@9 1010 tinsert(WorldPlan.FilterOptions, info)
Nenue@9 1011 end
Nenue@9 1012 self.bounties, self.numBounties = GetQuestBountyInfoForMapID(WorldPlan.currentMapID)
Nenue@9 1013 self.BountyFilters = {}
Nenue@9 1014 for index, data in ipairs(self.bounties) do
Nenue@9 1015 local info = self.BountyFilters[index]
Nenue@9 1016 if not info then
Nenue@9 1017 info = {}
Nenue@9 1018 self.BountyFilters[index] = info
Nenue@9 1019 end
Nenue@9 1020
Nenue@9 1021 local questTitle = GetQuestLogTitle(GetQuestLogIndexByID(data.questID))
Nenue@9 1022
Nenue@9 1023 info.filterKey = 'factionID'
Nenue@9 1024 info.filterValue = data.factionID
Nenue@9 1025 info.label = questTitle
Nenue@9 1026 info.texture = data.icon
Nenue@9 1027 print('loading emissary', questTitle)
Nenue@9 1028 tinsert(WorldPlan.FilterOptions, info)
Nenue@9 1029 --{ filterKey= 'worldQuestType', filterValue = LE_QUEST_TAG_TYPE_PROFESSION, label = 'Profession', texture = "Interface\\LFGFRAME\\UI-LFR-PORTRAIT", },
Nenue@9 1030 end
Nenue@9 1031 end
Nenue@9 1032
Nenue@9 1033 function FilterBar:Reset()
Nenue@9 1034 self:GetFilters()
Nenue@9 1035 end
Nenue@9 1036
Nenue@9 1037 function FilterBar:Refresh(forced)
Nenue@9 1038 local print = fbprint
Nenue@0 1039 local blocks = self.SummaryHeaders
Nenue@9 1040 local relativeFrame = WorldMapFrame.UIElementsFrame.TrackingOptionsButton
Nenue@0 1041 local numHeaders = 0
Nenue@9 1042 print('|cFF00FF88'..tostring(self)..':Refresh()|r', 'currentMap=',WorldPlan.currentMapID)
Nenue@9 1043
Nenue@9 1044
Nenue@9 1045 local quests = QuestsByZone[WorldPlan.currentMapID] or QuestsByID
Nenue@9 1046
Nenue@9 1047
Nenue@9 1048 for index, info in ipairs(WorldPlan.FilterOptions) do
Nenue@0 1049 local numQuests = 0
Nenue@0 1050
Nenue@0 1051 for questID, pin in pairs(quests) do
Nenue@0 1052 if pin.used then
Nenue@0 1053 if not info.filterKey then
Nenue@0 1054 numQuests = numQuests + 1
Nenue@0 1055 elseif pin[info.filterKey] == info.filterValue then
Nenue@0 1056 numQuests = numQuests + 1
Nenue@0 1057 end
Nenue@0 1058 end
Nenue@0 1059 end
Nenue@9 1060 print(tostring(index).. ' ("'..tostring(info.label)..'" f('.. tostring(info.filterKey).. '='..tostring(info.filterValue) .. '), '..tostring(numQuests)..')')
Nenue@0 1061
Nenue@0 1062 if numQuests >= 1 then
Nenue@0 1063 numHeaders = numHeaders + 1
Nenue@0 1064 local button = blocks[numHeaders]
Nenue@0 1065 if not blocks[numHeaders] then
Nenue@0 1066 button = CreateFrame('Button', 'WorldPlanFilterButton'..numHeaders, WorldMapScrollFrame, 'WorldPlanFilterPin')
Nenue@29 1067 for k,v in pairs(info)do print(k,v) end
Nenue@0 1068 button.iconBorder:SetTexture(info.fill or POI_BORDER_FILL)
Nenue@0 1069 button.iconBorder:SetMask(info.mask or POI_BORDER_MASK)
Nenue@0 1070 button.iconBorder:SetDesaturated(info.desaturated)
Nenue@0 1071 button.supertrackBorder:SetTexture(info.fill or POI_BORDER_FILL)
Nenue@0 1072 button.supertrackBorder:SetMask(info.mask or POI_BORDER_MASK)
Nenue@0 1073 button.supertrackBorder:SetDesaturated(true)
Nenue@0 1074 blocks[numHeaders] = button
Nenue@0 1075 end
Nenue@0 1076
Nenue@0 1077 button:SetID(index)
Nenue@9 1078 button.spacing = ((info.filterKey ~= relativeFrame.filterKey) and 10) or 0
Nenue@9 1079 button.relativeFrame = relativeFrame
Nenue@0 1080 button:Refresh(info, (numHeaders == 1), numQuests)
Nenue@0 1081 button:Show()
Nenue@9 1082 relativeFrame = button
Nenue@0 1083 end
Nenue@0 1084
Nenue@0 1085 end
Nenue@9 1086
Nenue@9 1087 self.numHeaders = numHeaders
Nenue@9 1088 for i = numHeaders + 1, #WorldPlan.FilterOptions do
Nenue@9 1089 if self.SummaryHeaders[i] then
Nenue@9 1090 self.SummaryHeaders[i]:Hide()
Nenue@0 1091 end
Nenue@0 1092 end
Nenue@0 1093 end
Nenue@0 1094
Nenue@9 1095 function FilterBar:Cleanup()
Nenue@9 1096
Nenue@9 1097 -- hide trailing buttons
Nenue@9 1098 end
Nenue@9 1099
Nenue@0 1100
Nenue@0 1101 function FilterPin:Refresh(info, isFirst, numQuests)
Nenue@9 1102 local print = fbprint
Nenue@0 1103 isFirst = isFirst or self.isFirst
Nenue@0 1104 numQuests = numQuests or self.numQuests
Nenue@0 1105
Nenue@9 1106 if info then
Nenue@9 1107 self.isFirst = isFirst
Nenue@9 1108 self.numQuests = numQuests
Nenue@9 1109 self.filterKey = info.filterKey
Nenue@9 1110 self.filterValue = info.filterValue
Nenue@9 1111 self.tagID = info.tagID
Nenue@0 1112
Nenue@9 1113 self.icon:ClearAllPoints()
Nenue@9 1114 self.icon:SetTexture(info.texture)
Nenue@9 1115 self.icon:SetAllPoints(self)
Nenue@9 1116 self.supertrackBorder:Hide()
Nenue@29 1117 self.count:SetText(numQuests)
Nenue@9 1118 self:Show()
Nenue@9 1119 end
Nenue@0 1120
Nenue@0 1121
Nenue@9 1122 self.itemTexture = self.texture
Nenue@9 1123
Nenue@0 1124 if isFirst then
Nenue@9 1125 self:SetPoint('TOP', self.relativeFrame, 'BOTTOM', 0, -5)
Nenue@0 1126 else
Nenue@9 1127 self:SetPoint('TOPRIGHT', self.relativeFrame, 'BOTTOMRIGHT', 0, -(3*2 + 1 + (self.spacing or 0)))
Nenue@9 1128
Nenue@0 1129 end
Nenue@9 1130 print('anchor to', self.relativeFrame:GetName())
Nenue@0 1131
Nenue@0 1132 local r, g, b, a = 1,1,1,1
Nenue@14 1133 local used = WorldPlan.UsedFilters[self.filterKey]
Nenue@14 1134 if used and self.filterKey then
Nenue@14 1135 if used[self.filterValue] == true then
Nenue@0 1136 r, g, b = 0, 1, 0
Nenue@14 1137 elseif used[self.filterValue] == false then
Nenue@0 1138 r, g, b = 1, 0, 0
Nenue@0 1139 end
Nenue@0 1140 end
Nenue@0 1141 self.iconBorder:SetVertexColor(r, g, b, a)
Nenue@9 1142 self:UpdateSize()
Nenue@0 1143 end
Nenue@0 1144
Nenue@0 1145 function FilterPin:OnLoad()
Nenue@0 1146 self:RegisterForClicks('AnyUp')
Nenue@0 1147 self:SetFrameStrata('HIGH')
Nenue@0 1148 self:SetFrameLevel(151)
Nenue@0 1149 self:SetScript('OnUpdate', nil)
Nenue@27 1150 self.style = db.filterStyle
Nenue@27 1151 self.subStyle = db.defaultPinStyle.continent
Nenue@0 1152 end
Nenue@0 1153
Nenue@0 1154 function FilterPin:OnUpdate ()
Nenue@0 1155
Nenue@0 1156 end
Nenue@0 1157
Nenue@0 1158 function FilterPin:OnLeave ()
Nenue@0 1159 if GameTooltip:IsOwned(self) then
Nenue@0 1160 GameTooltip:Hide()
Nenue@0 1161 end
Nenue@0 1162 end
Nenue@0 1163
Nenue@0 1164 -- shift-click: reset filter
Nenue@0 1165 -- click: rotate through include(1), exclude(-1), ignore(nil)
Nenue@0 1166 function FilterPin:OnClick (button)
Nenue@9 1167 local print = fbprint
Nenue@0 1168 local filterKey = self.filterKey
Nenue@0 1169 local filterValue = self.filterValue
Nenue@0 1170
Nenue@9 1171
Nenue@9 1172 local operation = opPrefix
Nenue@13 1173 local setInclude = (button == 'LeftButton')
Nenue@9 1174
Nenue@0 1175
Nenue@0 1176 if not filterKey then
Nenue@0 1177 -- resetting
Nenue@16 1178 wipe(WorldPlan.UsedFilters)
Nenue@16 1179
Nenue@14 1180 elseif IsShiftKeyDown() then
Nenue@14 1181 WorldPlan.UsedFilters[filterKey] = nil
Nenue@0 1182 else
Nenue@14 1183 WorldPlan.UsedFilters[filterKey] = WorldPlan.UsedFilters[filterKey] or {}
Nenue@14 1184 WorldPlan.UsedFilters[filterKey][filterValue] = setInclude
Nenue@14 1185 print(filterKey, filterValue, '=', setInclude)
Nenue@14 1186
Nenue@14 1187 for index, info in ipairs(WorldPlan.FilterOptions) do
Nenue@14 1188 if info.filterKey == filterKey then
Nenue@14 1189 if (not IsControlKeyDown()) and (filterValue ~= info.filterValue) then
Nenue@14 1190 WorldPlan.UsedFilters[filterKey][info.filterValue] = (not setInclude)
Nenue@14 1191 print(filterKey, info.filterValue, '=', WorldPlan.UsedFilters[filterKey][info.filterValue])
Nenue@0 1192 end
Nenue@0 1193 end
Nenue@13 1194 end
Nenue@14 1195
Nenue@0 1196 end
Nenue@9 1197 print('|cFF00FF88Filter Update:', filterKey, filterValue, operation)
Nenue@0 1198 WorldPlan:RefreshAll()
Nenue@0 1199 end
Nenue@0 1200
Nenue@0 1201 --%debug%
Nenue@0 1202 local SetTimedCallbackForAllPins = function(seconds, callback)
Nenue@0 1203 C_Timer.After(seconds, function()
Nenue@0 1204 for id, pin in pairs(QuestsByID) do
Nenue@0 1205 callback(pin)
Nenue@0 1206 end
Nenue@0 1207 end)
Nenue@0 1208 end
Nenue@0 1209
Nenue@0 1210 SLASH_WORLDPLAN1 = "/worldplan"
Nenue@0 1211 SLASH_WORLDPLAN2 = "/wp"
Nenue@0 1212 SlashCmdList.WORLDPLAN = function()
Nenue@0 1213 print('command pop')
Nenue@0 1214 WorldPlan:GetPinsForMap()
Nenue@0 1215 WorldPlan:RefreshPins()
Nenue@0 1216
Nenue@0 1217 SetTimedCallbackForAllPins(0, function(self) self.FadeIn:Play() self.FlashIn:Play() end)
Nenue@0 1218 SetTimedCallbackForAllPins(5, function(self) self.PendingFade:Play() end)
Nenue@0 1219 SetTimedCallbackForAllPins(8, function(self) self.PendingFade:Stop() end)
Nenue@0 1220 end
Nenue@0 1221 --%end-debug%