|
|
|
|
local myname, ns = ...
|
|
|
|
|
|
|
|
|
|
local GetPlayerAuraBySpellID = C_UnitAuras and C_UnitAuras.GetPlayerAuraBySpellID or _G.GetPlayerAuraBySpellID
|
|
|
|
|
|
|
|
|
|
ns.defaults = {
|
|
|
|
|
profile = {
|
|
|
|
|
default_icon = "VignetteLoot",
|
|
|
|
|
show_on_world = true,
|
|
|
|
|
show_on_minimap = false,
|
|
|
|
|
show_npcs = true,
|
|
|
|
|
show_npcs_onlynotable = false,
|
|
|
|
|
show_treasure = true,
|
|
|
|
|
show_routes = true,
|
|
|
|
|
upcoming = true,
|
|
|
|
|
found = false,
|
|
|
|
|
collectablefound = true,
|
|
|
|
|
achievedfound = true,
|
|
|
|
|
questfound = true,
|
|
|
|
|
icon_scale = 1.0,
|
|
|
|
|
icon_alpha = 1.0,
|
|
|
|
|
icon_item = false,
|
|
|
|
|
tooltip_charloot = true,
|
|
|
|
|
tooltip_pointanchor = false,
|
|
|
|
|
tooltip_item = true,
|
|
|
|
|
tooltip_questid = false,
|
|
|
|
|
groupsHidden = {},
|
|
|
|
|
groupsHiddenByZone = {['*']={},},
|
|
|
|
|
zonesHidden = {},
|
|
|
|
|
achievementsHidden = {},
|
|
|
|
|
worldmapoverlay = true,
|
|
|
|
|
},
|
|
|
|
|
char = {
|
|
|
|
|
hidden = {
|
|
|
|
|
['*'] = {},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ns.options = {
|
|
|
|
|
type = "group",
|
|
|
|
|
name = myname:gsub("HandyNotes_", ""),
|
|
|
|
|
get = function(info) return ns.db[info[#info]] end,
|
|
|
|
|
set = function(info, v)
|
|
|
|
|
ns.db[info[#info]] = v
|
|
|
|
|
ns.HL:Refresh()
|
|
|
|
|
end,
|
|
|
|
|
hidden = function(info)
|
|
|
|
|
return ns.hiddenConfig[info[#info]]
|
|
|
|
|
end,
|
|
|
|
|
args = {
|
|
|
|
|
icon = {
|
|
|
|
|
type = "group",
|
|
|
|
|
name = "Icon settings",
|
|
|
|
|
inline = true,
|
|
|
|
|
order = 10,
|
|
|
|
|
args = {
|
|
|
|
|
desc = {
|
|
|
|
|
name = "These settings control the look and feel of the icon.",
|
|
|
|
|
type = "description",
|
|
|
|
|
order = 0,
|
|
|
|
|
},
|
|
|
|
|
icon_scale = {
|
|
|
|
|
type = "range",
|
|
|
|
|
name = "Icon Scale",
|
|
|
|
|
desc = "The scale of the icons",
|
|
|
|
|
min = 0.25, max = 2, step = 0.01,
|
|
|
|
|
order = 20,
|
|
|
|
|
},
|
|
|
|
|
icon_alpha = {
|
|
|
|
|
type = "range",
|
|
|
|
|
name = "Icon Alpha",
|
|
|
|
|
desc = "The alpha transparency of the icons",
|
|
|
|
|
min = 0, max = 1, step = 0.01,
|
|
|
|
|
order = 30,
|
|
|
|
|
},
|
|
|
|
|
show_on_world = {
|
|
|
|
|
type = "toggle",
|
|
|
|
|
name = "World Map",
|
|
|
|
|
desc = "Show icons on world map",
|
|
|
|
|
order = 40,
|
|
|
|
|
},
|
|
|
|
|
show_on_minimap = {
|
|
|
|
|
type = "toggle",
|
|
|
|
|
name = "Minimap",
|
|
|
|
|
desc = "Show all icons on the minimap",
|
|
|
|
|
order = 50,
|
|
|
|
|
},
|
|
|
|
|
default_icon = {
|
|
|
|
|
type = "select",
|
|
|
|
|
name = "Default Icon",
|
|
|
|
|
values = {
|
|
|
|
|
VignetteLoot = CreateAtlasMarkup("VignetteLoot", 20, 20) .. " Chest",
|
|
|
|
|
VignetteLootElite = CreateAtlasMarkup("VignetteLootElite", 20, 20) .. " Chest with star",
|
|
|
|
|
Garr_TreasureIcon = CreateAtlasMarkup("Garr_TreasureIcon", 20, 20) .. " Shiny chest",
|
|
|
|
|
},
|
|
|
|
|
order = 60,
|
|
|
|
|
},
|
|
|
|
|
worldmapoverlay = {
|
|
|
|
|
type = "toggle",
|
|
|
|
|
name = "Add button to world map",
|
|
|
|
|
desc = "Put a button on the world map for quick access to these options",
|
|
|
|
|
set = function(info, v)
|
|
|
|
|
ns.db[info[#info]] = v
|
|
|
|
|
if WorldMapFrame.RefreshOverlayFrames then
|
|
|
|
|
WorldMapFrame:RefreshOverlayFrames()
|
|
|
|
|
end
|
|
|
|
|
end,
|
|
|
|
|
hidden = function(info)
|
|
|
|
|
if not ns.SetupMapOverlay then
|
|
|
|
|
return true
|
|
|
|
|
end
|
|
|
|
|
return ns.options.hidden(info)
|
|
|
|
|
end,
|
|
|
|
|
order = 70,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
display = {
|
|
|
|
|
type = "group",
|
|
|
|
|
name = "What to display",
|
|
|
|
|
inline = true,
|
|
|
|
|
order = 20,
|
|
|
|
|
args = {
|
|
|
|
|
icon_item = {
|
|
|
|
|
type = "toggle",
|
|
|
|
|
name = "Use item icons",
|
|
|
|
|
desc = "Show the icons for items, if known; otherwise, the achievement icon will be used",
|
|
|
|
|
order = 0,
|
|
|
|
|
},
|
|
|
|
|
tooltip_item = {
|
|
|
|
|
type = "toggle",
|
|
|
|
|
name = "Use item tooltips",
|
|
|
|
|
desc = "Show the full tooltips for items",
|
|
|
|
|
order = 10,
|
|
|
|
|
},
|
|
|
|
|
tooltip_charloot = {
|
|
|
|
|
type = "toggle",
|
|
|
|
|
name = "Loot for this character only",
|
|
|
|
|
desc = "Only show loot that should drop for the current character",
|
|
|
|
|
order = 12,
|
|
|
|
|
},
|
|
|
|
|
tooltip_pointanchor = {
|
|
|
|
|
type = "toggle",
|
|
|
|
|
name = "Anchor tooltips to points",
|
|
|
|
|
desc = "Whether to anchor the tooltips to the individual points or to the map",
|
|
|
|
|
order = 15,
|
|
|
|
|
},
|
|
|
|
|
-- the "found" cluster
|
|
|
|
|
found = {
|
|
|
|
|
type = "toggle",
|
|
|
|
|
name = "Show found",
|
|
|
|
|
desc = "Show waypoints for items you've already found?",
|
|
|
|
|
order = 20,
|
|
|
|
|
},
|
|
|
|
|
achievedfound = {
|
|
|
|
|
type = "toggle",
|
|
|
|
|
name = "Count achievement-complete as found",
|
|
|
|
|
desc = "For nodes which are repeatable on a daily quest *and* tied to an achievement, only consider the achievement",
|
|
|
|
|
order = 21,
|
|
|
|
|
},
|
|
|
|
|
collectablefound = {
|
|
|
|
|
type = "toggle",
|
|
|
|
|
name = "Count collectables as found",
|
|
|
|
|
desc = "For account-level items like mounts, pets, and toys, count them being known as this being found",
|
|
|
|
|
order = 22,
|
|
|
|
|
},
|
|
|
|
|
questfound = {
|
|
|
|
|
type = "toggle",
|
|
|
|
|
name = "Count tracking quest as found",
|
|
|
|
|
desc = "Lots of things have a hidden quest that tracks whether you've looted them this day / week /ever and thus whether you can loot them again",
|
|
|
|
|
order = 23,
|
|
|
|
|
},
|
|
|
|
|
upcoming = {
|
|
|
|
|
type = "toggle",
|
|
|
|
|
name = "Show inaccessible",
|
|
|
|
|
desc = "Show waypoints for items you can't get yet (max level, gated quests, etc); they'll be tinted red to indicate this",
|
|
|
|
|
order = 25,
|
|
|
|
|
},
|
|
|
|
|
show_npcs = {
|
|
|
|
|
type = "toggle",
|
|
|
|
|
name = "Show NPCs",
|
|
|
|
|
desc = "Show rare NPCs to be killed, generally for items or achievements",
|
|
|
|
|
order = 30,
|
|
|
|
|
},
|
|
|
|
|
show_npcs_onlynotable = {
|
|
|
|
|
type = "toggle",
|
|
|
|
|
name = "...but only notable ones",
|
|
|
|
|
desc = "Only show the NPCs that you can still get something from: achievements, transmogs for the current character",
|
|
|
|
|
order = 31,
|
|
|
|
|
},
|
|
|
|
|
show_treasure = {
|
|
|
|
|
type = "toggle",
|
|
|
|
|
name = "Show treasure",
|
|
|
|
|
desc = "Show treasure that can be looted",
|
|
|
|
|
order = 35,
|
|
|
|
|
},
|
|
|
|
|
show_routes = {
|
|
|
|
|
type = "toggle",
|
|
|
|
|
name = "Show routes",
|
|
|
|
|
desc = "Show relevant routes between points ",
|
|
|
|
|
disabled = function() return not ns.RouteWorldMapDataProvider end,
|
|
|
|
|
order = 37,
|
|
|
|
|
},
|
|
|
|
|
tooltip_questid = {
|
|
|
|
|
type = "toggle",
|
|
|
|
|
name = "Show quest ids",
|
|
|
|
|
desc = "Show the internal id of the quest associated with this node. Handy if you want to report a problem with it.",
|
|
|
|
|
order = 40,
|
|
|
|
|
},
|
|
|
|
|
unhide = {
|
|
|
|
|
type = "execute",
|
|
|
|
|
name = "Reset hidden nodes",
|
|
|
|
|
desc = "Show all nodes that you manually hid by right-clicking on them and choosing \"hide\".",
|
|
|
|
|
func = function()
|
|
|
|
|
for _, coords in pairs(ns.hidden) do
|
|
|
|
|
wipe(coords)
|
|
|
|
|
end
|
|
|
|
|
ns.HL:Refresh()
|
|
|
|
|
end,
|
|
|
|
|
order = 50,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
achievementsHidden = {
|
|
|
|
|
type = "multiselect",
|
|
|
|
|
name = "Show achievements",
|
|
|
|
|
desc = "Toggle whether you want to show points for a given achievement",
|
|
|
|
|
get = function(info, key) return not ns.db[info[#info]][key] end,
|
|
|
|
|
set = function(info, key, value)
|
|
|
|
|
ns.db[info[#info]][key] = not value
|
|
|
|
|
ns.HL:Refresh()
|
|
|
|
|
end,
|
|
|
|
|
values = function(info)
|
|
|
|
|
local values = {}
|
|
|
|
|
for uiMapID, points in pairs(ns.points) do
|
|
|
|
|
for coord, point in pairs(points) do
|
|
|
|
|
if point.achievement and not values[point.achievement] then
|
|
|
|
|
local _, achievement = GetAchievementInfo(point.achievement)
|
|
|
|
|
values[point.achievement] = achievement or 'achievement:'..point.achievement
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
-- replace ourself with the built values table
|
|
|
|
|
info.option.values = values
|
|
|
|
|
return values
|
|
|
|
|
end,
|
|
|
|
|
hidden = function(info)
|
|
|
|
|
for uiMapID, points in pairs(ns.points) do
|
|
|
|
|
for coord, point in pairs(points) do
|
|
|
|
|
if point.achievement then
|
|
|
|
|
info.option.hidden = nil
|
|
|
|
|
return ns.options.hidden(info)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
info.option.hidden = true
|
|
|
|
|
return true
|
|
|
|
|
end,
|
|
|
|
|
order = 30,
|
|
|
|
|
},
|
|
|
|
|
zonesHidden = {
|
|
|
|
|
type = "multiselect",
|
|
|
|
|
name = "Show in zones",
|
|
|
|
|
desc = "Toggle whether you want to show points in a given zone",
|
|
|
|
|
get = function(info, key) return not ns.db[info[#info]][key] end,
|
|
|
|
|
set = function(info, key, value)
|
|
|
|
|
ns.db[info[#info]][key] = not value
|
|
|
|
|
ns.HL:Refresh()
|
|
|
|
|
end,
|
|
|
|
|
values = function(info)
|
|
|
|
|
local values = {}
|
|
|
|
|
for uiMapID in pairs(ns.points) do
|
|
|
|
|
if not values[uiMapID] then
|
|
|
|
|
local info = C_Map.GetMapInfo(uiMapID)
|
|
|
|
|
if info and info.mapType == 3 then
|
|
|
|
|
-- zones only
|
|
|
|
|
values[uiMapID] = info.name
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
-- replace ourself with the built values table
|
|
|
|
|
info.option.values = values
|
|
|
|
|
return values
|
|
|
|
|
end,
|
|
|
|
|
order = 35,
|
|
|
|
|
},
|
|
|
|
|
groupsHidden = {
|
|
|
|
|
type = "multiselect",
|
|
|
|
|
name = "Show groups",
|
|
|
|
|
desc = "Toggle whether to show certain groups of points",
|
|
|
|
|
get = function(info, key) return not ns.db[info[#info]][key] end,
|
|
|
|
|
set = function(info, key, value)
|
|
|
|
|
ns.db[info[#info]][key] = not value
|
|
|
|
|
ns.HL:Refresh()
|
|
|
|
|
end,
|
|
|
|
|
values = function(info)
|
|
|
|
|
local values = {}
|
|
|
|
|
for uiMapID, points in pairs(ns.points) do
|
|
|
|
|
for coord, point in pairs(points) do
|
|
|
|
|
if point.group and not values[point.group] then
|
|
|
|
|
values[point.group] = ns.groups[point.group] or point.group
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
-- replace ourself with the built values table
|
|
|
|
|
info.option.values = values
|
|
|
|
|
return values
|
|
|
|
|
end,
|
|
|
|
|
hidden = function(info)
|
|
|
|
|
for uiMapID, points in pairs(ns.points) do
|
|
|
|
|
for coord, point in pairs(points) do
|
|
|
|
|
if point.group then
|
|
|
|
|
info.option.hidden = nil
|
|
|
|
|
return ns.options.hidden(info)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
info.option.hidden = true
|
|
|
|
|
return true
|
|
|
|
|
end,
|
|
|
|
|
order = 40,
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
local function doTestAll(test, input, ...)
|
|
|
|
|
for _, value in ipairs(input) do
|
|
|
|
|
if not test(value, ...) then
|
|
|
|
|
return false
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
return true
|
|
|
|
|
end
|
|
|
|
|
local function doTestAny(test, input, ...)
|
|
|
|
|
for _, value in ipairs(input) do
|
|
|
|
|
if test(value, ...) then
|
|
|
|
|
return true
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
return false
|
|
|
|
|
end
|
|
|
|
|
local doTest, doTestDefaultAny
|
|
|
|
|
do
|
|
|
|
|
local function doTestMaker(default)
|
|
|
|
|
return function(test, input, ...)
|
|
|
|
|
if type(input) == "table" and not input.__parent then
|
|
|
|
|
if input.any then return doTestAny(test, input, ...) end
|
|
|
|
|
if input.all then return doTestAll(test, input, ...) end
|
|
|
|
|
return default(test, input, ...)
|
|
|
|
|
else
|
|
|
|
|
return test(input, ...)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
doTest = doTestMaker(doTestAll)
|
|
|
|
|
doTestDefaultAny = doTestMaker(doTestAny)
|
|
|
|
|
end
|
|
|
|
|
ns.doTest = doTest
|
|
|
|
|
ns.doTestDefaultAny = doTestDefaultAny
|
|
|
|
|
local function testMaker(test, override)
|
|
|
|
|
return function(...)
|
|
|
|
|
return (override or doTest)(test, ...)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local itemInBags = testMaker(function(item) return GetItemCount(item, true) > 0 end)
|
|
|
|
|
local allQuestsComplete = testMaker(function(quest) return C_QuestLog.IsQuestFlaggedCompleted(quest) end)
|
|
|
|
|
ns.allQuestsComplete = allQuestsComplete
|
|
|
|
|
|
|
|
|
|
local temp_criteria = {}
|
|
|
|
|
local allCriteriaComplete = testMaker(function(criteria, achievement)
|
|
|
|
|
local _, _, completed, _, _, completedBy = ns.GetCriteria(achievement, criteria)
|
|
|
|
|
if not (completed and (not completedBy or completedBy == ns.playerName)) then
|
|
|
|
|
return false
|
|
|
|
|
end
|
|
|
|
|
return true
|
|
|
|
|
end, function(test, input, achievement, ...)
|
|
|
|
|
if input == true then
|
|
|
|
|
wipe(temp_criteria)
|
|
|
|
|
for i=1,GetAchievementNumCriteria(achievement) do
|
|
|
|
|
table.insert(temp_criteria, i)
|
|
|
|
|
end
|
|
|
|
|
input = temp_criteria
|
|
|
|
|
end
|
|
|
|
|
return doTest(test, input, achievement, ...)
|
|
|
|
|
end)
|
|
|
|
|
|
|
|
|
|
local brokenItems = {
|
|
|
|
|
-- itemid : {appearanceid, sourceid}
|
|
|
|
|
[153268] = {25124, 90807}, -- Enclave Aspirant's Axe
|
|
|
|
|
[153316] = {25123, 90885}, -- Praetor's Ornamental Edge
|
|
|
|
|
}
|
|
|
|
|
local function GetAppearanceAndSource(itemLinkOrID)
|
|
|
|
|
local itemID = GetItemInfoInstant(itemLinkOrID)
|
|
|
|
|
if not itemID then return end
|
|
|
|
|
local appearanceID, sourceID = C_TransmogCollection.GetItemInfo(itemLinkOrID)
|
|
|
|
|
if not appearanceID then
|
|
|
|
|
-- sometimes the link won't actually give us an appearance, but itemID will
|
|
|
|
|
-- e.g. mythic Drape of Iron Sutures from Shadowmoon Burial Grounds
|
|
|
|
|
appearanceID, sourceID = C_TransmogCollection.GetItemInfo(itemID)
|
|
|
|
|
end
|
|
|
|
|
if not appearanceID and brokenItems[itemID] then
|
|
|
|
|
-- ...and there's a few that just need to be hardcoded
|
|
|
|
|
appearanceID, sourceID = unpack(brokenItems[itemID])
|
|
|
|
|
end
|
|
|
|
|
return appearanceID, sourceID
|
|
|
|
|
end
|
|
|
|
|
local canLearnCache = {}
|
|
|
|
|
local function CanLearnAppearance(itemLinkOrID)
|
|
|
|
|
if not _G.C_Transmog then return false end
|
|
|
|
|
local itemID = GetItemInfoInstant(itemLinkOrID)
|
|
|
|
|
if not itemID then return end
|
|
|
|
|
if canLearnCache[itemID] ~= nil then
|
|
|
|
|
return canLearnCache[itemID]
|
|
|
|
|
end
|
|
|
|
|
-- First, is this a valid source at all?
|
|
|
|
|
local canBeChanged, noChangeReason, canBeSource, noSourceReason = C_Transmog.CanTransmogItem(itemID)
|
|
|
|
|
if canBeSource == nil or noSourceReason == 'NO_ITEM' then
|
|
|
|
|
-- data loading, don't cache this
|
|
|
|
|
return
|
|
|
|
|
end
|
|
|
|
|
if not canBeSource then
|
|
|
|
|
canLearnCache[itemID] = false
|
|
|
|
|
return false
|
|
|
|
|
end
|
|
|
|
|
local appearanceID, sourceID = GetAppearanceAndSource(itemLinkOrID)
|
|
|
|
|
if not appearanceID then
|
|
|
|
|
canLearnCache[itemID] = false
|
|
|
|
|
return false
|
|
|
|
|
end
|
|
|
|
|
local hasData, canCollect = C_TransmogCollection.PlayerCanCollectSource(sourceID)
|
|
|
|
|
if hasData then
|
|
|
|
|
canLearnCache[itemID] = canCollect
|
|
|
|
|
end
|
|
|
|
|
return canLearnCache[itemID]
|
|
|
|
|
end
|
|
|
|
|
local hasAppearanceCache = {}
|
|
|
|
|
local function HasAppearance(itemLinkOrID)
|
|
|
|
|
local itemID = GetItemInfoInstant(itemLinkOrID)
|
|
|
|
|
if not itemID then return end
|
|
|
|
|
if hasAppearanceCache[itemID] ~= nil then
|
|
|
|
|
return hasAppearanceCache[itemID]
|
|
|
|
|
end
|
|
|
|
|
if C_TransmogCollection.PlayerHasTransmogByItemInfo(itemLinkOrID) then
|
|
|
|
|
-- short-circuit further checks because this specific item is known
|
|
|
|
|
hasAppearanceCache[itemID] = true
|
|
|
|
|
return true
|
|
|
|
|
end
|
|
|
|
|
-- Although this isn't known, its appearance might be known from another item
|
|
|
|
|
local appearanceID = GetAppearanceAndSource(itemLinkOrID)
|
|
|
|
|
if not appearanceID then
|
|
|
|
|
hasAppearanceCache[itemID] = false
|
|
|
|
|
return
|
|
|
|
|
end
|
|
|
|
|
local sources = C_TransmogCollection.GetAllAppearanceSources(appearanceID)
|
|
|
|
|
if not sources then return end
|
|
|
|
|
for _, sourceID in ipairs(sources) do
|
|
|
|
|
if C_TransmogCollection.PlayerHasTransmogItemModifiedAppearance(sourceID) then
|
|
|
|
|
hasAppearanceCache[itemID] = true
|
|
|
|
|
return true
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
return false
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local function PlayerHasMount(mountid)
|
|
|
|
|
if not _G.C_MountJournal then return false end
|
|
|
|
|
return (select(11, C_MountJournal.GetMountInfoByID(mountid)))
|
|
|
|
|
end
|
|
|
|
|
local function PlayerHasPet(petid)
|
|
|
|
|
return (C_PetJournal.GetNumCollectedInfo(petid) > 0)
|
|
|
|
|
end
|
|
|
|
|
ns.itemRestricted = function(item)
|
|
|
|
|
if type(item) ~= "table" then return false end
|
|
|
|
|
if item.covenant and item.covenant ~= C_Covenants.GetActiveCovenantID() then
|
|
|
|
|
return true
|
|
|
|
|
end
|
|
|
|
|
if item.class and ns.playerClass ~= item.class then
|
|
|
|
|
return true
|
|
|
|
|
end
|
|
|
|
|
if item.requires and not ns.conditions.check(item.requires) then
|
|
|
|
|
return true
|
|
|
|
|
end
|
|
|
|
|
-- TODO: profession recipes
|
|
|
|
|
return false
|
|
|
|
|
end
|
|
|
|
|
ns.itemIsKnowable = function(item)
|
|
|
|
|
if ns.CLASSIC then return false end
|
|
|
|
|
if type(item) == "table" then
|
|
|
|
|
if ns.itemRestricted(item) then
|
|
|
|
|
return false
|
|
|
|
|
end
|
|
|
|
|
if item.set and ns.playerClassMask then
|
|
|
|
|
local info = C_TransmogSets.GetSetInfo(item.set)
|
|
|
|
|
if info and info.classMask then
|
|
|
|
|
return bit.band(info.classMask, ns.playerClassMask) == ns.playerClassMask
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
return (item.toy or item.mount or item.pet or item.quest or item.questComplete or item.set or item.spell or CanLearnAppearance(item[1]))
|
|
|
|
|
end
|
|
|
|
|
return CanLearnAppearance(item)
|
|
|
|
|
end
|
|
|
|
|
ns.itemIsKnown = function(item)
|
|
|
|
|
-- returns true/false/nil for yes/no/not-knowable
|
|
|
|
|
if ns.CLASSIC then return GetItemCount(ns.lootitem(item), true) > 0 end
|
|
|
|
|
if type(item) == "table" then
|
|
|
|
|
-- TODO: could arguably do transmog here, too. Since we're mostly
|
|
|
|
|
-- considering soulbound things, the restrictions on seeing appearances
|
|
|
|
|
-- known cross-armor-type wouldn't really matter...
|
|
|
|
|
if item.toy then return PlayerHasToy(item[1]) end
|
|
|
|
|
if item.mount then return PlayerHasMount(item.mount) end
|
|
|
|
|
if item.pet then return PlayerHasPet(item.pet) end
|
|
|
|
|
if item.quest then return C_QuestLog.IsQuestFlaggedCompleted(item.quest) or C_QuestLog.IsOnQuest(item.quest) end
|
|
|
|
|
if item.questComplete then return C_QuestLog.IsQuestFlaggedCompleted(item.questComplete) end
|
|
|
|
|
if item.set then
|
|
|
|
|
local info = C_TransmogSets.GetSetInfo(item.set)
|
|
|
|
|
if info then
|
|
|
|
|
if info.collected then return true end
|
|
|
|
|
-- we want to return nil for sets the current class can't learn:
|
|
|
|
|
if info.classMask and bit.band(info.classMask, ns.playerClassMask) == ns.playerClassMask then return false end
|
|
|
|
|
end
|
|
|
|
|
return false
|
|
|
|
|
end
|
|
|
|
|
if item.spell then
|
|
|
|
|
-- can't use the tradeskill functions + the recipe-spell because that data's only available after the tradeskill window has been opened...
|
|
|
|
|
local info = C_TooltipInfo.GetItemByID(item[1])
|
|
|
|
|
if info then
|
|
|
|
|
TooltipUtil.SurfaceArgs(info)
|
|
|
|
|
for _, line in ipairs(info.lines) do
|
|
|
|
|
TooltipUtil.SurfaceArgs(line)
|
|
|
|
|
if line.leftText and string.match(line.leftText, _G.ITEM_SPELL_KNOWN) then
|
|
|
|
|
return true
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
return false
|
|
|
|
|
end
|
|
|
|
|
if CanLearnAppearance(item[1]) then return HasAppearance(item[1]) end
|
|
|
|
|
elseif CanLearnAppearance(item) then
|
|
|
|
|
return HasAppearance(item)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
local hasKnowableLoot = testMaker(ns.itemIsKnowable, doTestAny)
|
|
|
|
|
local allLootKnown = testMaker(function(item)
|
|
|
|
|
-- This returns true if all loot is known-or-unknowable
|
|
|
|
|
-- If the "no knowable loot" case matters this should be gated behind hasKnowableLoot
|
|
|
|
|
local known = ns.itemIsKnown(item)
|
|
|
|
|
if known == nil then
|
|
|
|
|
return true
|
|
|
|
|
end
|
|
|
|
|
return known
|
|
|
|
|
end)
|
|
|
|
|
|
|
|
|
|
local function isAchieved(point)
|
|
|
|
|
if point.criteria and point.criteria ~= true then
|
|
|
|
|
if not allCriteriaComplete(point.criteria, point.achievement) then
|
|
|
|
|
return false
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
local completedByMe = select(13, GetAchievementInfo(point.achievement))
|
|
|
|
|
if not completedByMe then
|
|
|
|
|
return false
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
return true
|
|
|
|
|
end
|
|
|
|
|
local function isNotable(point)
|
|
|
|
|
-- A point is notable if it has loot you can use, or is tied to an
|
|
|
|
|
-- achievement you can still earn. It ignores quest-completion, because
|
|
|
|
|
-- repeatable mobs are a nightmare here.
|
|
|
|
|
if point.achievement and not isAchieved(point) then
|
|
|
|
|
return true
|
|
|
|
|
end
|
|
|
|
|
if point.loot and hasKnowableLoot(point.loot) and not allLootKnown(point.loot) then
|
|
|
|
|
return true
|
|
|
|
|
end
|
|
|
|
|
if point.follower and not C_Garrison.IsFollowerCollected(point.follower) then
|
|
|
|
|
return true
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
local function everythingFound(point)
|
|
|
|
|
local ret
|
|
|
|
|
if ns.db.collectablefound and point.loot and hasKnowableLoot(point.loot) then
|
|
|
|
|
if not allLootKnown(point.loot) then
|
|
|
|
|
return false
|
|
|
|
|
end
|
|
|
|
|
ret = true
|
|
|
|
|
end
|
|
|
|
|
if (ns.db.achievedfound or not point.quest) and point.achievement and not point.achievementNotFound then
|
|
|
|
|
if not isAchieved(point) then
|
|
|
|
|
return false
|
|
|
|
|
end
|
|
|
|
|
ret = true
|
|
|
|
|
end
|
|
|
|
|
if point.follower then
|
|
|
|
|
if not C_Garrison.IsFollowerCollected(point.follower) then
|
|
|
|
|
return false
|
|
|
|
|
end
|
|
|
|
|
ret = true
|
|
|
|
|
end
|
|
|
|
|
return ret
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local zoneHidden
|
|
|
|
|
zoneHidden = function(uiMapID)
|
|
|
|
|
if ns.db.zonesHidden[uiMapID] then
|
|
|
|
|
return true
|
|
|
|
|
end
|
|
|
|
|
local info = C_Map.GetMapInfo(uiMapID)
|
|
|
|
|
if info and info.parentMapID then
|
|
|
|
|
return zoneHidden(info.parentMapID)
|
|
|
|
|
end
|
|
|
|
|
return false
|
|
|
|
|
end
|
|
|
|
|
local achievementHidden = function(achievement)
|
|
|
|
|
if not achievement then return false end
|
|
|
|
|
return ns.db.achievementsHidden[achievement]
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local checkPois
|
|
|
|
|
do
|
|
|
|
|
local poi_expirations = {}
|
|
|
|
|
local poi_zone_expirations = {}
|
|
|
|
|
local pois_byzone = {}
|
|
|
|
|
local function refreshPois(zone)
|
|
|
|
|
local now = time()
|
|
|
|
|
if not poi_zone_expirations[zone] or now > poi_zone_expirations[zone] then
|
|
|
|
|
pois_byzone[zone] = wipe(pois_byzone[zone] or {})
|
|
|
|
|
for _, poi in ipairs(C_AreaPoiInfo.GetAreaPOIForMap(zone)) do
|
|
|
|
|
pois_byzone[zone][poi] = true
|
|
|
|
|
poi_expirations[poi] = now + (C_AreaPoiInfo.GetAreaPOISecondsLeft(poi) or 60)
|
|
|
|
|
end
|
|
|
|
|
poi_zone_expirations[zone] = now + 1
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
function checkPois(pois)
|
|
|
|
|
for _, data in ipairs(pois) do
|
|
|
|
|
local zone, poi = unpack(data)
|
|
|
|
|
local now = time()
|
|
|
|
|
if now > (poi_expirations[poi] or 0) then
|
|
|
|
|
refreshPois(zone)
|
|
|
|
|
poi_expirations[poi] = poi_expirations[poi] or (now + 60)
|
|
|
|
|
end
|
|
|
|
|
if pois_byzone[zone][poi] then
|
|
|
|
|
return true
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local checkArt = testMaker(function(artid, uiMapID) return artid == C_Map.GetMapArtID(uiMapID) end, doTestDefaultAny)
|
|
|
|
|
|
|
|
|
|
local function showOnMapType(point, uiMapID, isMinimap)
|
|
|
|
|
-- nil means to respect the preferences, but points can override
|
|
|
|
|
if isMinimap then
|
|
|
|
|
if point.minimap ~= nil then return point.minimap end
|
|
|
|
|
if ns.map_spellids[uiMapID] then
|
|
|
|
|
if ns.map_spellids[uiMapID] == true or GetPlayerAuraBySpellID(ns.map_spellids[uiMapID]) then
|
|
|
|
|
return false
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
return ns.db.show_on_minimap
|
|
|
|
|
end
|
|
|
|
|
if point.worldmap ~= nil then return point.worldmap end
|
|
|
|
|
return ns.db.show_on_world
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
ns.should_show_point = function(coord, point, currentZone, isMinimap)
|
|
|
|
|
if not coord or coord < 0 then return false end
|
|
|
|
|
if not showOnMapType(point, currentZone, isMinimap) then
|
|
|
|
|
return false
|
|
|
|
|
end
|
|
|
|
|
if zoneHidden(currentZone) then
|
|
|
|
|
return false
|
|
|
|
|
end
|
|
|
|
|
if achievementHidden(point.achievement) then
|
|
|
|
|
return false
|
|
|
|
|
end
|
|
|
|
|
if ns.hidden[currentZone] and ns.hidden[currentZone][coord] then
|
|
|
|
|
return false
|
|
|
|
|
end
|
|
|
|
|
if point.group and ns.db.groupsHidden[point.group] or ns.db.groupsHiddenByZone[currentZone][point.group] then
|
|
|
|
|
return false
|
|
|
|
|
end
|
|
|
|
|
if point.ShouldShow then
|
|
|
|
|
local show = point:ShouldShow()
|
|
|
|
|
if show ~= nil then
|
|
|
|
|
return show
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
if point.outdoors_only and IsIndoors() then
|
|
|
|
|
return false
|
|
|
|
|
end
|
|
|
|
|
if point.art and not checkArt(point.art, currentZone) then
|
|
|
|
|
return false
|
|
|
|
|
end
|
|
|
|
|
if point.poi and not checkPois(point.poi) then
|
|
|
|
|
return false
|
|
|
|
|
end
|
|
|
|
|
if point.faction and point.faction ~= ns.playerFaction then
|
|
|
|
|
return false
|
|
|
|
|
end
|
|
|
|
|
if not ns.db.found and not point.always then
|
|
|
|
|
if everythingFound(point) == true then
|
|
|
|
|
return false
|
|
|
|
|
end
|
|
|
|
|
if ns.db.questfound and point.quest and allQuestsComplete(point.quest) then
|
|
|
|
|
return false
|
|
|
|
|
end
|
|
|
|
|
-- the rest are proxies for the actual "found" status:
|
|
|
|
|
if point.inbag and itemInBags(point.inbag) then
|
|
|
|
|
return false
|
|
|
|
|
end
|
|
|
|
|
if point.onquest and C_QuestLog.IsOnQuest(type(point.onquest) == "number" and point.onquest or point.quest) then
|
|
|
|
|
return false
|
|
|
|
|
end
|
|
|
|
|
if point.hide_quest and C_QuestLog.IsQuestFlaggedCompleted(point.hide_quest) then
|
|
|
|
|
-- This is distinct from point.quest as it's supposed to be for
|
|
|
|
|
-- other trackers that make the point not _complete_ but still
|
|
|
|
|
-- hidden (Draenor treasure maps, so far):
|
|
|
|
|
return false
|
|
|
|
|
end
|
|
|
|
|
if point.found and ns.conditions.check(point.found) then
|
|
|
|
|
return false
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
if not point.follower then
|
|
|
|
|
if point.npc then
|
|
|
|
|
if not ns.db.show_npcs then
|
|
|
|
|
return false
|
|
|
|
|
end
|
|
|
|
|
if ns.db.show_npcs_onlynotable and not isNotable(point) then
|
|
|
|
|
-- Only show "notable" npcs, which we define as "has loot you can use or has an achievement"
|
|
|
|
|
return false
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
-- Not an NPC, not a follower, must be treasure
|
|
|
|
|
if not ns.db.show_treasure then
|
|
|
|
|
return false
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
if point.requires_buff and not doTest(GetPlayerAuraBySpellID, point.requires_buff) then
|
|
|
|
|
return false
|
|
|
|
|
end
|
|
|
|
|
if point.requires_no_buff and doTest(GetPlayerAuraBySpellID, point.requires_no_buff) then
|
|
|
|
|
return false
|
|
|
|
|
end
|
|
|
|
|
if point.requires_item and not itemInBags(point.requires_item) then
|
|
|
|
|
return false
|
|
|
|
|
end
|
|
|
|
|
if point.requires_worldquest and not (C_TaskQuest.IsActive(point.requires_worldquest) or C_QuestLog.IsQuestFlaggedCompleted(point.requires_worldquest)) then
|
|
|
|
|
return false
|
|
|
|
|
end
|
|
|
|
|
if point.requires and not ns.conditions.check(point.requires) then
|
|
|
|
|
return false
|
|
|
|
|
end
|
|
|
|
|
if not ns.db.upcoming or point.upcoming == false then
|
|
|
|
|
if not ns.point_active(point) then
|
|
|
|
|
return false
|
|
|
|
|
end
|
|
|
|
|
if ns.point_upcoming(point) then
|
|
|
|
|
return false
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
return true
|
|
|
|
|
end
|