You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1424 lines
56 KiB

local myname, ns = ...
local _, myfullname = GetAddOnInfo(myname)
local HandyNotes = LibStub("AceAddon-3.0"):GetAddon("HandyNotes")
local HL = LibStub("AceAddon-3.0"):NewAddon(myname, "AceEvent-3.0")
-- local L = LibStub("AceLocale-3.0"):GetLocale(myname, true)
ns.HL = HL
local HBD = LibStub("HereBeDragons-2.0")
local LibDD = LibStub:GetLibrary("LibUIDropDownMenu-4.0")
ns.DEBUG = GetAddOnMetadata(myname, "Version") == '@'..'project-version@'
ns.CLASSIC = WOW_PROJECT_ID ~= WOW_PROJECT_MAINLINE
local ATLAS_CHECK, ATLAS_CROSS = "common-icon-checkmark", "common-icon-redx"
if ns.CLASSIC then
ATLAS_CHECK, ATLAS_CROSS = "Tracker-Check", "Objective-Fail"
end
---------------------------------------------------------
-- Data model stuff:
-- flags for whether to show minimap icons in some zones, if Blizzard ever does the treasure-map thing again
ns.map_spellids = ns.map_spellids or {
-- zone = spellid
}
ns.currencies = ns.currencies or {
ANIMA = {
name = '|cffff8000' .. POWER_TYPE_ANIMA .. '|r',
texture = select(10, GetAchievementInfo(14339)),
},
ARTIFACT = {
name = '|cffff8000' .. ARTIFACT_POWER .. '|r',
texture = select(10, GetAchievementInfo(11144)),
}
}
-- for fallbacks
ns.covenants = ns.covenants or {
[Enum.CovenantType.Kyrian] = "Kyrian",
[Enum.CovenantType.Necrolord] = "Necrolords",
[Enum.CovenantType.NightFae] = "NightFae",
[Enum.CovenantType.Venthyr] = "Venthyr",
}
ns.groups = ns.groups or {}
ns.hiddenConfig = ns.hiddenConfig or {}
ns.points = {
--[[ structure:
[uiMapID] = { -- "_terrain1" etc will be stripped from attempts to fetch this
[coord] = {
label=[string], -- label: text that'll be the label, optional
loot={[id]}, -- itemids
quest=[id], -- will be checked, for whether character already has it
currency=[id], -- currencyid
achievement=[id], -- will be shown in the tooltip
criteria=[id], -- modifies achievement
junk=[bool], -- doesn't count for any achievement
npc=[id], -- related npc id, used to display names in tooltip
note=[string], -- some text which might be helpful
hide_before=[id], -- hide if quest not completed
requires_buff=[id], -- hide if player does not have buff, mostly useful for buff-based zone phasing
requires_no_buff=[id] -- hide if player has buff, mostly useful for buff-based zone phasing
},
},
--]]
}
ns.POIsToPoints = {}
ns.VignetteIDsToPoints = {}
ns.WorldQuestsToPoints = {}
local function intotable(dest, value_or_table, point)
if not value_or_table then return end
if type(value_or_table) == "table" then
for _, value in ipairs(value_or_table) do
dest[value] = point
end
return
end
dest[value_or_table] = point
end
function ns.RegisterPoints(zone, points, defaults)
if not ns.points[zone] then
ns.points[zone] = {}
end
if defaults then
local nodeType = ns.nodeMaker(defaults)
for coord, point in pairs(points) do
points[coord] = nodeType(point)
end
end
for coord, point in pairs(points) do
if ns.DEBUG and ns.points[zone][coord] then
print(myname, "point collision", zone, coord)
end
ns.points[zone][coord] = point
point._coord = coord
point._uiMapID = zone
intotable(ns.POIsToPoints, point.areaPoi, point)
intotable(ns.VignetteIDsToPoints, point.vignette, point)
intotable(ns.WorldQuestsToPoints, point.worldquest, point)
if point.route and type(point.route) == "table" then
-- avoiding a data migration
point.routes = {point.route}
point.route = nil
end
if point.atlas and point.color then
point.texture = ns.atlas_texture(point.atlas, point.color)
end
local proxy_meta
if point.path or point.nearby or point.related then
proxy_meta = {__index=point}
end
if point.path then
local route = type(point.path) == "table" and point.path or {point.path}
table.insert(route, 1, coord)
ns.points[zone][route[#route]] = setmetatable({
label=route.label or (point.npc and ("Path to {npc:%s}"):format(point.npc) or "Path to treasure"),
atlas=route.atlas or "poi-door", scale=route.scale or 0.95, minimap=true, texture=false,
note=route.note or false,
loot=route.loot,
routes={route},
_coord=route[#route], _uiMapID=zone,
}, proxy_meta)
-- highlight
point.route = point.route or route[#route]
end
if point.nearby then
local nearby = type(point.nearby) == "table" and point.nearby or {point.nearby}
for _, ncoord in ipairs(point.nearby) do
local npoint = setmetatable({
label=nearby.label or (point.npc and "Related to nearby NPC" or "Related to nearby treasure"),
atlas=nearby.atlas or "playerpartyblip",
texture=nearby.texture or false,
minimap=true, worldmap=false, scale=0.95,
note=nearby.note or false,
loot=nearby.loot, active=nearby.active,
_coord=ncoord, _uiMapID=zone,
}, proxy_meta)
if nearby.color then
npoint.texture = ns.atlas_texture(npoint.atlas, nearby.color)
end
ns.points[zone][ncoord] = npoint
end
end
if point.related then
local relatedNode = ns.nodeMaker(setmetatable({
label=point.npc and "Related to nearby NPC" or "Related to nearby treasure",
atlas="playerpartyblip",
texture=false,
note=false,
route=coord,
_uiMapID=zone,
}, proxy_meta))
for rcoord, related in pairs(point.related) do
local rpoint = relatedNode(related)
rpoint._coord = rcoord
if related.color then
rpoint.texture = ns.atlas_texture(rpoint.atlas, related.color)
end
if not point.routes then point.routes = {} end
table.insert(point.routes, {rcoord, coord, highlightOnly=true})
ns.points[zone][rcoord] = rpoint
end
end
if point.parent then
local x, y = HandyNotes:getXY(coord)
local mapinfo = C_Map.GetMapInfo(zone)
if mapinfo and mapinfo.parentMapID and mapinfo.parentMapID ~= 0 then
local pzone = mapinfo.parentMapID
local px, py = HBD:TranslateZoneCoordinates(x, y, zone, pzone)
if px and py then
if not ns.points[pzone] then
ns.points[pzone] = {}
end
local pcoord = HandyNotes:getCoord(px, py)
ns.points[pzone][pcoord] = point
end
end
end
end
end
function ns.RegisterVignettes(zone, vignettes, defaults)
if defaults then
defaults = ns.nodeMaker(defaults)
end
for vignetteID, point in pairs(vignettes) do
point._coord = point._coord or 0
point._uiMapID = zone
point.vignette = vignetteID
point.always = true
point.label = false
point = defaults and defaults(point) or point
intotable(ns.POIsToPoints, point.areaPoi, point)
intotable(ns.VignetteIDsToPoints, point.vignette, point)
intotable(ns.WorldQuestsToPoints, point.worldquest, point)
end
end
ns.merge = function(t1, t2)
if not t2 then return t1 end
for k, v in pairs(t2) do
t1[k] = v
end
return t1
end
ns.nodeMaker = function(defaults)
local meta = {__index = defaults}
return function(details)
details = details or {}
if details.note and defaults.note then
details.note = details.note .. "\n" .. defaults.note
end
local meta2 = getmetatable(details)
if meta2 and meta2.__index then
return setmetatable(details, {__index = ns.merge(CopyTable(defaults), meta2.__index)})
end
return setmetatable(details, meta)
end
end
ns.path = ns.nodeMaker{
label = "Path to treasure",
atlas = "poi-door", -- 'PortalPurple' / 'PortalRed'?
minimap = true,
scale = 0.95,
}
ns.lootitem = function(item)
return type(item) == "table" and item[1] or item
end
local playerClassLocal, playerClass = UnitClass("player")
ns.playerClass = playerClass
ns.playerClassLocal = playerClassLocal
ns.playerClassColor = RAID_CLASS_COLORS[playerClass]
ns.playerName = UnitName("player")
ns.playerFaction = UnitFactionGroup("player")
ns.playerClassMask = ({
-- this is 2^(classID - 1)
WARRIOR = 0x1,
PALADIN = 0x2,
HUNTER = 0x4,
ROGUE = 0x8,
PRIEST = 0x10,
DEATHKNIGHT = 0x20,
SHAMAN = 0x40,
MAGE = 0x80,
WARLOCK = 0x100,
MONK = 0x200,
DRUID = 0x400,
DEMONHUNTER = 0x800,
EVOKER = 0x1000,
})[playerClass] or 0
---------------------------------------------------------
-- All the utility code
function ns.GetCriteria(achievement, criteriaid)
local retOK, criteriaString, criteriaType, completed, quantity, reqQuantity, charName, flags, assetID, quantityString, criteriaID, eligible = pcall(criteriaid < 100 and GetAchievementCriteriaInfo or GetAchievementCriteriaInfoByID, achievement, criteriaid, true)
if not retOK then return end
return criteriaString, criteriaType, completed, quantity, reqQuantity, charName, flags, assetID, quantityString, criteriaID, eligible
end
local mob_name
if _G.C_TooltipInfo then
local name_cache = {}
mob_name = function(id)
if not name_cache[id] then
local info = C_TooltipInfo.GetHyperlink(("unit:Creature-0-0-0-0-%d"):format(id))
-- TooltipUtil.SurfaceArgs(info)
if info and info.lines and info.lines[1] then
TooltipUtil.SurfaceArgs(info.lines[1])
if info.lines[1].type == Enum.TooltipDataType.Unit then
name_cache[id] = info.lines[1].leftText
end
end
end
return name_cache[id]
end
else
-- pre-10.0.2
local cache_tooltip = _G["HNTreasuresCacheScanningTooltip"]
if not cache_tooltip then
cache_tooltip = CreateFrame("GameTooltip", "HNTreasuresCacheScanningTooltip")
cache_tooltip:AddFontStrings(
cache_tooltip:CreateFontString("$parentTextLeft1", nil, "GameTooltipText"),
cache_tooltip:CreateFontString("$parentTextRight1", nil, "GameTooltipText")
)
end
local name_cache = {}
mob_name = function(id)
if not name_cache[id] then
-- this doesn't work with just clearlines and the setowner outside of this, and I'm not sure why
cache_tooltip:SetOwner(WorldFrame, "ANCHOR_NONE")
cache_tooltip:SetHyperlink(("unit:Creature-0-0-0-0-%d"):format(id))
if cache_tooltip:IsShown() then
name_cache[id] = HNTreasuresCacheScanningTooltipTextLeft1:GetText()
end
end
return name_cache[id]
end
end
local function quick_texture_markup(icon)
-- needs less than CreateTextureMarkup
return icon and ('|T' .. icon .. ':0:0:1:-1|t') or ''
end
local completeColor = CreateColor(0, 1, 0, 1)
local incompleteColor = CreateColor(1, 0, 0, 1)
local function render_string(s, context)
if type(s) == "function" then s = s(context) end
return s:gsub("{(%l+):([^:}]+):?([^}]*)}", function(variant, id, fallback)
local mainid, subid = id:match("(%d+)%.(%d+)")
mainid, subid = mainid and tonumber(mainid), subid and tonumber(subid)
id = tonumber(id)
if variant == "item" then
local name, link, _, _, _, _, _, _, _, icon = GetItemInfo(id)
if link and icon then
return quick_texture_markup(icon) .. " " .. link:gsub("[%[%]]", "")
end
elseif variant == "spell" then
local name, _, icon = GetSpellInfo(id)
if name and icon then
return quick_texture_markup(icon) .. " " .. name
end
elseif variant == "quest" or variant == "worldquest" or variant == "questname" then
local name = C_QuestLog.GetTitleForQuestID(id)
if not (name and name ~= "") then
name = tostring(id)
end
if variant == "questname" then return name end
local completed = C_QuestLog.IsQuestFlaggedCompleted(id)
return CreateAtlasMarkup(variant == "worldquest" and "worldquest-tracker-questmarker" or "questnormal") ..
(completed and completeColor or incompleteColor):WrapTextInColorCode(name)
elseif variant == "questid" then
return CreateAtlasMarkup("questnormal") .. (C_QuestLog.IsQuestFlaggedCompleted(id) and completeColor or incompleteColor):WrapTextInColorCode(id)
elseif variant == "achievement" or variant == "achievementname" then
if mainid and subid then
local criteria, _, completed = ns.GetCriteria(mainid, subid)
if criteria then
if variant == "achievementname" then return criteria end
return (completed and completeColor or incompleteColor):WrapTextInColorCode(criteria)
end
id = 'achievement:'..mainid..'.'..subid
else
local _, name, _, completed = GetAchievementInfo(id)
if name and name ~= "" then
if variant == "achievementname" then return name end
return CreateAtlasMarkup("storyheader-cheevoicon") .. " " .. (completed and completeColor or incompleteColor):WrapTextInColorCode(name)
end
end
elseif variant == "npc" then
local name = mob_name(id)
if name then
return name
end
elseif variant == "currency" then
local info = C_CurrencyInfo.GetCurrencyInfo(id)
if info then
return quick_texture_markup(info.iconFileID) .. " " .. info.name
end
elseif variant == "currencyicon" then
local info = C_CurrencyInfo.GetCurrencyInfo(id)
if info then
return quick_texture_markup(info.iconFileID)
end
elseif variant == "covenant" then
local data = C_Covenants.GetCovenantData(id)
return COVENANT_COLORS[id]:WrapTextInColorCode(data and data.name or ns.covenants[id])
elseif variant == "majorfaction" then
local info = C_MajorFactions.GetMajorFactionData(id)
if info and info.name then
return CreateAtlasMarkup(("majorFactions_icons_%s512"):format(info.textureKit)) .. " " .. info.name
end
elseif variant == "faction" then
local name = GetFactionInfoByID(id)
if name then
return name
end
elseif variant == "garrisontalent" then
local info = C_Garrison.GetTalentInfo(id)
if info then
return quick_texture_markup(info.icon) .. " " .. (info.researched and completeColor or incompleteColor):WrapTextInColorCode(info.name)
end
elseif variant == "profession" then
local info = C_TradeSkillUI.GetProfessionInfoBySkillLineID(id)
if (info and info.professionName and info.professionName ~= "") then
-- there's also info.parentProfessionName for the general case ("Dragon Isles Inscription" vs "Inscription")
return info.professionName
end
end
return fallback ~= "" and fallback or (variant .. ':' .. id)
end)
end
local function cache_string(s, context)
if not s then return end
if type(s) == "function" then s = s(context) end
for variant, id, fallback in s:gmatch("{(%l+):(%d+):?([^}]*)}") do
id = tonumber(id)
if variant == "item" then
C_Item.RequestLoadItemDataByID(id)
elseif variant == "spell" then
C_Spell.RequestLoadSpellData(id)
elseif variant == "quest" or variant == "worldquest" or variant == "questname" then
C_QuestLog.RequestLoadQuestByID(id)
elseif variant == "npc" then
mob_name(id)
end
end
end
local function cache_loot(loot)
if not loot then return end
for _, item in ipairs(loot) do
C_Item.RequestLoadItemDataByID(ns.lootitem(item))
end
end
local render_string_list
do
local out = {}
function render_string_list(point, variant, ...)
if not ... then return "" end
if type(...) == "table" then return render_string_list(point, variant, unpack(...)) end
wipe(out)
for i=1,select("#", ...) do
table.insert(out, ("{%s:%d}"):format(variant, (select(i, ...))))
end
return render_string(string.join(", ", unpack(out)), point)
end
end
ns.render_string = render_string
ns.render_string_list = render_string_list
local npc_texture, follower_texture, currency_texture, junk_texture
local icon_cache = {}
local trimmed_icon = function(texture)
if not icon_cache[texture] then
icon_cache[texture] = {
icon = texture,
tCoordLeft = 0.1,
tCoordRight = 0.9,
tCoordTop = 0.1,
tCoordBottom = 0.9,
}
end
return icon_cache[texture]
end
local atlas_texture = function(atlas, extra, crop)
atlas = C_Texture.GetAtlasInfo(atlas)
if type(extra) == "number" then
extra = {scale=extra}
end
if crop then
local xcrop = (atlas.rightTexCoord - atlas.leftTexCoord) * crop
local ycrop = (atlas.bottomTexCoord - atlas.topTexCoord) * crop
atlas.rightTexCoord = atlas.rightTexCoord - xcrop
atlas.leftTexCoord = atlas.leftTexCoord + xcrop
atlas.bottomTexCoord = atlas.bottomTexCoord - ycrop
atlas.topTexCoord = atlas.topTexCoord + xcrop
end
return ns.merge({
icon = atlas.file,
tCoordLeft = atlas.leftTexCoord, tCoordRight = atlas.rightTexCoord, tCoordTop = atlas.topTexCoord, tCoordBottom = atlas.bottomTexCoord,
}, extra)
end
ns.atlas_texture = atlas_texture
local default_textures = {
VignetteLoot = atlas_texture("VignetteLoot", 1.1),
VignetteLootElite = atlas_texture("VignetteLootElite", 1.2),
Garr_TreasureIcon = atlas_texture("Garr_TreasureIcon", 2.2),
}
local function work_out_label(point)
local fallback
if point.label then
return (render_string(point.label, point))
end
if point.achievement and point.criteria and type(point.criteria) ~= "table" and point.criteria ~= true then
local criteria = ns.GetCriteria(point.achievement, point.criteria)
if criteria then
return criteria
end
fallback = 'achievement:'..point.achievement..'.'..point.criteria
end
if point.follower then
local follower = C_Garrison.GetFollowerInfo(point.follower)
if follower then
return follower.name
end
fallback = 'follower:'..point.follower
end
if point.npc then
local name = mob_name(point.npc)
if name then
return name
end
fallback = 'npc:'..point.npc
end
if point.loot and #point.loot > 0 then
-- handle multiples?
local _, link = GetItemInfo(ns.lootitem(point.loot[1]))
if link then
return link:gsub("[%[%]]", "")
end
fallback = 'item:'..ns.lootitem(point.loot[1])
end
if point.achievement and not point.criteria or point.criteria == true then
local _, achievement = GetAchievementInfo(point.achievement)
if achievement then
return achievement
end
fallback = 'achievement:'..point.achievement
end
if point.currency then
if ns.currencies[point.currency] then
return ns.currencies[point.currency].name
end
local info = C_CurrencyInfo.GetCurrencyInfo(point.currency)
if info then
return info.name
end
end
return fallback or UNKNOWN
end
local function work_out_texture(point)
if point.texture then
return point.texture
end
if point.atlas then
if not icon_cache[point.atlas] then
icon_cache[point.atlas] = atlas_texture(point.atlas, point.scale)
end
return icon_cache[point.atlas]
end
if ns.db.icon_item or point.icon then
if point.icon then
return trimmed_icon(point.icon)
end
if point.loot and #point.loot > 0 then
local texture = select(10, GetItemInfo(ns.lootitem(point.loot[1])))
if texture then
return trimmed_icon(texture)
end
end
if point.currency then
if ns.currencies[point.currency] then
local texture = ns.currencies[point.currency].texture
if texture then
return trimmed_icon(texture)
end
else
local info = C_CurrencyInfo.GetCurrencyInfo(point.currency)
if info then
return trimmed_icon(info.iconFileID)
end
end
end
if point.achievement then
local texture = select(10, GetAchievementInfo(point.achievement))
if texture then
return trimmed_icon(texture)
end
end
end
if point.follower then
if not follower_texture then
follower_texture = atlas_texture("GreenCross", 1.5)
end
return follower_texture
end
if point.npc then
if not npc_texture then
npc_texture = atlas_texture("DungeonSkull", 1)
end
return npc_texture
end
if point.currency then
if not currency_texture then
currency_texture = atlas_texture("Auctioneer", 1.3)
end
return currency_texture
end
if point.junk then
if not junk_texture then
junk_texture = atlas_texture("VignetteLoot", 1)
end
return junk_texture
end
if not default_textures[ns.db.default_icon] then
default_textures[ns.db.default_icon] = atlas_texture(ns.db.default_icon, 1.5)
end
return default_textures[ns.db.default_icon] or default_textures["VignetteLoot"]
end
ns.point_active = function(point)
if point.IsActive and not point:IsActive() then
return false
end
if not point.active then
return true
end
return ns.conditions.check(point.active)
end
ns.point_upcoming = function(point)
if point.level and UnitLevel("player") < point.level then
return true
end
if point.hide_before and not ns.conditions.check(point.hide_before) then
return true
end
if point.covenant and point.covenant ~= C_Covenants.GetActiveCovenantID() then
return true
end
return false
end
local inactive_cache = {}
local function get_inactive_texture_variant(icon)
if not inactive_cache[icon] then
inactive_cache[icon] = CopyTable(icon)
if inactive_cache[icon].r then
inactive_cache[icon].a = 0.5
else
inactive_cache[icon].r = 0.5
inactive_cache[icon].g = 0.5
inactive_cache[icon].b = 0.5
inactive_cache[icon].a = 1
end
end
return inactive_cache[icon]
end
local upcoming_cache = {}
local function get_upcoming_texture_variant(icon)
if not upcoming_cache[icon] then
upcoming_cache[icon] = CopyTable(icon)
upcoming_cache[icon].r = 1
upcoming_cache[icon].g = 0
upcoming_cache[icon].b = 0
upcoming_cache[icon].a = 0.7
end
return upcoming_cache[icon]
end
local get_point_info = function(point, isMinimap)
if point then
local label = work_out_label(point)
local icon = work_out_texture(point)
if not ns.point_active(point) then
icon = get_inactive_texture_variant(icon)
elseif ns.point_upcoming(point) then
icon = get_upcoming_texture_variant(icon)
end
local category = "treasure"
if point.npc then
category = "npc"
elseif point.junk then
category = "junk"
end
if not isMinimap then
cache_string(point.label, point)
cache_string(point.note, point)
cache_loot(point.loot, point)
end
return label, icon, category, point.quest, point.faction, point.scale, point.alpha or 1
end
end
local get_point_info_by_coord = function(uiMapID, coord)
return get_point_info(ns.points[uiMapID] and ns.points[uiMapID][coord])
end
local get_point_progress = function(point)
if type(point.progress) == "number" then
-- shortcut: if the progress is an objective of the tracking quest
return select(4, GetQuestObjectiveInfo(point.quest, point.progress, false))
elseif type(point.progress) == "table" then
for i, q in ipairs(point.progress) do
if not C_QuestLog.IsQuestFlaggedCompleted(q) then
return i - 1, #point.progress
end
end
return #point.progress, #point.progress
else
-- function
return point:progress()
end
end
local function tooltip_criteria(tooltip, achievement, criteriaid, ignore_quantityString)
local criteria, _, complete, _, _, _, flags, _, quantityString = ns.GetCriteria(achievement, criteriaid) -- include hidden
if quantityString and not ignore_quantityString then
local is_progressbar = bit.band(flags, EVALUATION_TREE_FLAG_PROGRESS_BAR) == EVALUATION_TREE_FLAG_PROGRESS_BAR
local label = (criteria and #criteria > 0 and not is_progressbar) and criteria or PVP_PROGRESS_REWARDS_HEADER
tooltip:AddDoubleLine(
label, quantityString,
complete and 0 or 1, complete and 1 or 0, 0,
complete and 0 or 1, complete and 1 or 0, 0
)
else
tooltip:AddDoubleLine(" ", criteria,
nil, nil, nil,
complete and 0 or 1, complete and 1 or 0, 0
)
end
end
local function tooltip_loot(tooltip, item)
local knownText
local r, g, b = NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b
local id = ns.lootitem(item)
local _, itemType, itemSubtype, equipLoc, icon, classID, subclassID = GetItemInfoInstant(id)
if ns.db.tooltip_charloot and not IsShiftKeyDown() then
-- show loot for the current character only
-- can't pass in a reusable table for the second argument because it changes the no-data case
local specTable = GetItemSpecInfo(id)
-- Some cosmetic items seem to be flagged as not dropping for any spec. I
-- could only confirm this for some cosmetic back items but let's play it
-- safe and say that any cosmetic item can drop regardless of what the
-- spec info says...
if specTable and #specTable == 0 and not (_G.IsCosmeticItem and IsCosmeticItem(id)) then
return true
end
-- then catch covenants / classes / etc
if ns.itemRestricted(item) then return true end
end
local _, link = GetItemInfo(ns.lootitem(item))
local label = ENCOUNTER_JOURNAL_ITEM
if classID == Enum.ItemClass.Armor and subclassID ~= Enum.ItemArmorSubclass.Shield then
label = _G[equipLoc] or label
else
label = itemSubtype
end
if link then
link = link:gsub("[%[%]]", "")
else
r, g, b = 0, 1, 1
link = SEARCH_LOADING_TEXT
end
if type(item) == "table" then
if item.mount then label = MOUNT
elseif item.toy then label = TOY
elseif item.pet then label = TOOLTIP_BATTLE_PET
elseif item.set then
label = WARDROBE_SETS
local info = C_TransmogSets.GetSetInfo(item.set)
if info then
link = info.name
if not info.collected then
local sources = C_TransmogSets.GetSetPrimaryAppearances(item.set)
if sources and #sources > 0 then
local numKnown = 0
for _, source in pairs(sources) do
if source.collected then
numKnown = numKnown + 1
end
end
knownText = RED_FONT_COLOR:WrapTextInColorCode(GENERIC_FRACTION_STRING:format(numKnown, #sources))
end
end
end
end
-- todo: faction?
if item.covenant then
local data = C_Covenants.GetCovenantData(item.covenant)
-- local active = item.covenant == C_Covenants.GetActiveCovenantID()
link = TEXT_MODE_A_STRING_VALUE_TYPE:format(link, COVENANT_COLORS[item.covenant]:WrapTextInColorCode(data and data.name or ns.covenants[item.covenant]))
end
if item.class then
link = TEXT_MODE_A_STRING_VALUE_TYPE:format(link, RAID_CLASS_COLORS[item.class]:WrapTextInColorCode(LOCALIZED_CLASS_NAMES_FEMALE[item.class]))
end
if item.note then
link = TEXT_MODE_A_STRING_VALUE_TYPE:format(link, render_string(item.note))
end
end
local known = ns.itemIsKnown(item)
if known ~= nil and (known == true or not ns.itemRestricted(item)) then
if knownText then
link = link .. " " .. knownText
else
link = link .. " " .. CreateAtlasMarkup(known and ATLAS_CHECK or ATLAS_CROSS)
end
end
tooltip:AddDoubleLine(label, quick_texture_markup(icon) .. " " .. link,
NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b,
r, g, b
)
end
local function handle_tooltip(tooltip, point, skip_label)
if not point then
tooltip:SetText(UNKNOWN)
tooltip:Show()
return
end
-- major:
if not skip_label and point.label ~= false then
tooltip:AddLine(work_out_label(point))
end
if point.OnTooltipShow then
point:OnTooltipShow(tooltip)
end
if point.follower then
local follower = C_Garrison.GetFollowerInfo(point.follower)
if follower then
local quality = BAG_ITEM_QUALITY_COLORS[follower.quality]
tooltip:AddDoubleLine(REWARD_FOLLOWER, follower.name,
0, 1, 0,
quality.r, quality.g, quality.b
)
tooltip:AddDoubleLine(follower.className, UNIT_LEVEL_TEMPLATE:format(follower.level))
end
end
if point.currency then
local name
if ns.currencies[point.currency] then
name = ns.currencies[point.currency].name
else
local info = C_CurrencyInfo.GetCurrencyInfo(point.currency)
name = info and info.name
end
tooltip:AddDoubleLine(CURRENCY, name or point.currency)
end
if point.achievement then
local _, name, _, complete = GetAchievementInfo(point.achievement)
tooltip:AddDoubleLine(BATTLE_PET_SOURCE_6, name or point.achievement,
nil, nil, nil,
complete and 0 or 1, complete and 1 or 0, 0
)
if point.criteria then
if point.criteria == true then
local numCriteria = GetAchievementNumCriteria(point.achievement, true) -- include hidden
if numCriteria > 10 then
local numComplete = 0
for criteria=1, numCriteria do
if select(3, GetAchievementCriteriaInfo(point.achievement, criteria, true)) then
numComplete = numComplete + 1
end
end
tooltip:AddDoubleLine(" ", GENERIC_FRACTION_STRING:format(numComplete, numCriteria),
nil, nil, nil,
complete and 0 or 1, complete and 1 or 0, 0
)
else
for criteria=1, numCriteria do
tooltip_criteria(tooltip, point.achievement, criteria, true)
end
end
elseif type(point.criteria) == "table" then
for _, criteria in ipairs(point.criteria) do
tooltip_criteria(tooltip, point.achievement, criteria, true)
end
elseif type(point.criteria) == "number" then
tooltip_criteria(tooltip, point.achievement, point.criteria, true)
end
elseif GetAchievementNumCriteria(point.achievement) == 1 then
tooltip_criteria(tooltip, point.achievement, 1)
end
end
if point.progress then
local fulfilled, required = get_point_progress(point)
if fulfilled and required then
tooltip:AddDoubleLine(PVP_PROGRESS_REWARDS_HEADER, GENERIC_FRACTION_STRING:format(fulfilled, required))
end
end
if point.note then
tooltip:AddLine(render_string(point.note, point), 1, 1, 1, true)
end
if point.loot then
local hidden
for _, item in ipairs(point.loot) do
hidden = tooltip_loot(tooltip, item) or hidden
end
if hidden then
tooltip:AddLine("Items for other characters hidden", 0, 1, 1)
end
end
if point.covenant then
local data = C_Covenants.GetCovenantData(point.covenant)
local active = point.covenant == C_Covenants.GetActiveCovenantID()
local cname = COVENANT_COLORS[point.covenant]:WrapTextInColorCode(data and data.name or ns.covenants[point.covenant])
tooltip:AddLine(ITEM_REQ_SKILL:format(cname), active and 0 or 1, active and 1 or 0, 0)
end
if point.level and point.level > UnitLevel("player") then
tooltip:AddLine(ITEM_MIN_LEVEL:format(point.level), 1, 0, 0)
end
if point.hide_before then
local isHidden = not ns.conditions.check(point.hide_before)
if isHidden then
tooltip:AddLine(COMMUNITY_TYPE_UNAVAILABLE, 1, 0, 0)
end
tooltip:AddLine(
ns.render_string(ns.conditions.summarize(point.hide_before), point),
isHidden and 1 or 0, isHidden and 0 or 1, 0, true
)
end
if point.requires then
local isHidden = not ns.conditions.check(point.requires)
if isHidden then
tooltip:AddLine(COMMUNITY_TYPE_UNAVAILABLE, 1, 0, 0)
end
tooltip:AddLine(
ns.render_string(ns.conditions.summarize(point.requires), point),
isHidden and 1 or 0, isHidden and 0 or 1, 0, true
)
end
if point.active then
local isActive = ns.point_active(point)
tooltip:AddLine(
ns.render_string(point.active.note or ns.conditions.summarize(point.active), point),
isActive and 0 or 1, isActive and 1 or 0, 0, true
)
end
if point.group then
tooltip:AddDoubleLine(GROUP, (render_string(ns.groups[point.group] or point.group, point)))
end
if point.quest and ns.db.tooltip_questid then
tooltip:AddDoubleLine("QuestID", render_string_list(point, "questid", point.quest), NORMAL_FONT_COLOR:GetRGB())
end
if ns.DEBUG then
tooltip:AddDoubleLine("Coord", point._coord)
end
if (ns.db.tooltip_item or IsShiftKeyDown()) and (point.loot or point.npc or point.spell) then
local comparison = _G[myname.."ComparisonTooltip"]
if not comparison then
comparison = CreateFrame("GameTooltip", myname.."ComparisonTooltip", UIParent, "ShoppingTooltipTemplate")
Mixin(comparison, GameTooltipDataMixin)
comparison:SetFrameStrata("TOOLTIP")
comparison:SetClampedToScreen(true)
end
do
local side
local leftPos = tooltip:GetLeft() or 0
local rightPos = tooltip:GetRight() or 0
local rightDist = GetScreenWidth() - rightPos
if (leftPos and (rightDist < leftPos)) then
side = "left"
else
side = "right"
end
-- see if we should slide the tooltip
if tooltip:GetAnchorType() and tooltip:GetAnchorType() ~= "ANCHOR_PRESERVE" then
local totalWidth = 0
if ( primaryItemShown ) then
totalWidth = totalWidth + comparison:GetWidth()
end
if ( (side == "left") and (totalWidth > leftPos) ) then
tooltip:SetAnchorType(tooltip:GetAnchorType(), (totalWidth - leftPos), 0)
elseif ( (side == "right") and (rightPos + totalWidth) > GetScreenWidth() ) then
tooltip:SetAnchorType(tooltip:GetAnchorType(), -((rightPos + totalWidth) - GetScreenWidth()), 0)
end
end
comparison:SetOwner(tooltip, "ANCHOR_NONE")
comparison:ClearAllPoints()
if ( side and side == "left" ) then
comparison:SetPoint("TOPRIGHT", tooltip, "TOPLEFT", 0, -10)
else
comparison:SetPoint("TOPLEFT", tooltip, "TOPRIGHT", 0, -10)
end
end
if point.loot and #point.loot > 0 then
comparison:SetItemByID(ns.lootitem(point.loot[1]))
elseif point.npc then
comparison:SetHyperlink(("unit:Creature-0-0-0-0-%d"):format(point.npc))
elseif point.spell then
comparison:SetSpellByID(point.spell)
end
comparison:Show()
end
tooltip:Show()
end
local handle_tooltip_by_coord = function(tooltip, uiMapID, coord)
return handle_tooltip(tooltip, ns.points[uiMapID] and ns.points[uiMapID][coord])
end
do
local currentZone, currentPoint
local function is_valid_related_point(basePoint, point)
if not (basePoint and point) then return false end
if basePoint.group and basePoint.group == point.group then return true end
if basePoint.achievement and basePoint.achievement == point.achievement then return true end
return false
end
local function iter(t, prestate)
if not t then return nil end
local state, point = next(t, prestate)
while state do -- Have we reached the end of this zone?
if is_valid_related_point(currentPoint, point) then
return state, point
end
state, point = next(t, state) -- Get next data
end
return
end
function ns.IterateRelatedPointsInZone(uiMapID, point)
currentPoint = point
return iter, ns.points[uiMapID], nil
end
function ns.PointHasRelatedPointsInZone(uiMapID, point)
for _, rpoint in ns.IterateRelatedPointsInZone(uiMapID, point) do
if rpoint ~= point then
return true
end
end
end
end
---------------------------------------------------------
-- Plugin Handlers to HandyNotes
local HLHandler = {}
function HLHandler:OnEnter(uiMapID, coord)
local point = ns.points[uiMapID] and ns.points[uiMapID][coord]
if ns.RouteWorldMapDataProvider and (point.route or point.routes) then
if point.route and ns.points[uiMapID][point.route] then
point = ns.points[uiMapID][point.route]
end
ns.RouteWorldMapDataProvider:HighlightRoute(point, uiMapID, coord)
end
local tooltip = GameTooltip
if ns.db.tooltip_pointanchor or self:GetParent() == Minimap then
if self:GetCenter() > UIParent:GetCenter() then -- compare X coordinate
tooltip:SetOwner(self, "ANCHOR_LEFT")
else
tooltip:SetOwner(self, "ANCHOR_RIGHT")
end
else
tooltip:SetOwner(WorldMapFrame.ScrollContainer, "ANCHOR_NONE")
local x, y = HandyNotes:getXY(coord)
if y < 0.5 then
tooltip:SetPoint("BOTTOMLEFT", WorldMapFrame.ScrollContainer)
else
tooltip:SetPoint("TOPLEFT", WorldMapFrame.ScrollContainer)
end
end
handle_tooltip_by_coord(tooltip, uiMapID, coord)
end
local function showAchievement(button, achievement)
if OpenAchievementFrameToAchievement then
OpenAchievementFrameToAchievement(achievement)
else
-- probably classic
if ( not AchievementFrame ) then
AchievementFrame_LoadUI()
end
if ( not AchievementFrame:IsShown() ) then
AchievementFrame_ToggleAchievementFrame()
end
AchievementFrame_SelectAchievement(achievement)
end
end
local function createWaypoint(button, uiMapID, coord)
local x, y = HandyNotes:getXY(coord)
if TomTom then
TomTom:AddWaypoint(uiMapID, x, y, {
title = get_point_info_by_coord(uiMapID, coord),
persistent = nil,
minimap = true,
world = true
})
elseif C_Map and C_Map.CanSetUserWaypointOnMap and C_Map.CanSetUserWaypointOnMap(uiMapID) then
local uiMapPoint = UiMapPoint.CreateFromCoordinates(uiMapID, x, y)
C_Map.SetUserWaypoint(uiMapPoint)
C_SuperTrack.SetSuperTrackedUserWaypoint(true)
end
end
local createWaypointForAll
do
local function getDistance(x1, y1, x2, y2)
local deltaX, deltaY = x2 - x1, y2 - y1
return ((deltaX ^ 2) + (deltaY ^ 2)) ^ 0.5
end
local function distanceSort(lhs, rhs)
local px, py = HBD:GetPlayerZonePosition()
return getDistance(px, py, HandyNotes:getXY(lhs)) > getDistance(px, py, HandyNotes:getXY(rhs))
end
function createWaypointForAll(button, uiMapID, coord)
if not TomTom then return end
local point = ns.points[uiMapID] and ns.points[uiMapID][coord]
if not point then return end
local points = {}
for rcoord, rpoint in ns.IterateRelatedPointsInZone(uiMapID, point) do
if ns.should_show_point(rcoord, rpoint, uiMapID, false) then
table.insert(points, rcoord)
end
end
-- Add waypoints in a useful order so we wind up with the closest one
-- on the arrow. Not just doing TomTom:SetClosestWaypoint because I
-- want to respect the crazy-arrow settings, and that forces it on.
table.sort(points, distanceSort)
for _, rcoord in ipairs(points) do
local x, y = HandyNotes:getXY(rcoord)
TomTom:AddWaypoint(uiMapID, x, y, {
title = get_point_info_by_coord(uiMapID, rcoord),
persistent = nil,
minimap = true,
world = true
})
end
end
end
local function hideNode(button, uiMapID, coord)
ns.hidden[uiMapID][coord] = true
HL:Refresh()
end
local function hideAchievement(button, achievement)
ns.db.achievementsHidden[achievement] = true
HL:Refresh()
end
local function hideGroup(button, uiMapID, coord)
local point = ns.points[uiMapID] and ns.points[uiMapID][coord]
if not (point and point.group) then return end
ns.db.groupsHidden[point.group] = true
HL:Refresh()
end
local function hideGroupZone(button, uiMapID, coord)
local point = ns.points[uiMapID] and ns.points[uiMapID][coord]
if not (point and point.group) then return end
ns.db.groupsHiddenByZone[uiMapID][point.group] = true
HL:Refresh()
end
local function sendToChat(button, uiMapID, coord)
local title = get_point_info_by_coord(uiMapID, coord)
local x, y = HandyNotes:getXY(coord)
local message = ("%s|cffffff00|Hworldmap:%d:%d:%d|h[%s]|h|r"):format(
title and (title .. " ") or "",
uiMapID,
x * 10000,
y * 10000,
-- Can't do this:
-- core:GetMobLabel(self.data.id) or UNKNOWN
-- WoW seems to filter out anything which isn't the standard MAP_PIN_HYPERLINK
MAP_PIN_HYPERLINK
)
PlaySound(SOUNDKIT.UI_MAP_WAYPOINT_CHAT_SHARE)
-- if you have an open editbox, just paste to it
if not ChatEdit_InsertLink(message) then
-- open the chat to whatever it was on and add the text
ChatFrame_OpenChat(message)
end
end
local function closeAllDropdowns()
LibDD:CloseDropDownMenus(1)
end
do
local currentZone, currentCoord
local function generateMenu(button, level)
local point = ns.points[currentZone] and ns.points[currentZone][currentCoord]
if not (level and point) then return end
local info = LibDD:UIDropDownMenu_CreateInfo()
if (level == 1) then
-- Create the title of the menu
info.isTitle = 1
info.text = myfullname
info.notCheckable = 1
LibDD:UIDropDownMenu_AddButton(info, level)
wipe(info)
if point.achievement then
-- Waypoint menu item
info.text = OBJECTIVES_VIEW_ACHIEVEMENT
info.notCheckable = 1
info.func = showAchievement
info.arg1 = point.achievement
LibDD:UIDropDownMenu_AddButton(info, level)
wipe(info)
end
if TomTom or (C_Map and C_Map.CanSetUserWaypointOnMap and C_Map.CanSetUserWaypointOnMap(currentZone)) then
-- Waypoint menu item
info.text = "Create waypoint"
info.notCheckable = 1
info.func = createWaypoint
info.arg1 = currentZone
info.arg2 = currentCoord
LibDD:UIDropDownMenu_AddButton(info, level)
wipe(info)
end
-- Specifically for TomTom, since it supports multiples:
if TomTom and ns.PointHasRelatedPointsInZone(currentZone, point) then
info.text = render_string(("Create waypoint for all %s"):format(point.group and (ns.groups[point.group] or point.group) or ("{achievement:%d}"):format(point.achievement)), point)
info.notCheckable = 1
info.func = createWaypointForAll
info.arg1 = currentZone
info.arg2 = currentCoord
LibDD:UIDropDownMenu_AddButton(info, level)
wipe(info)
end
if _G.MAP_PIN_HYPERLINK then
info.text = COMMUNITIES_INVITE_MANAGER_LINK_TO_CHAT -- Link to chat
info.notCheckable = 1
info.func = sendToChat
info.arg1 = currentZone
info.arg2 = currentCoord
LibDD:UIDropDownMenu_AddButton(info, level)
wipe(info)
end
-- Hide menu item
info.text = "Hide node"
info.notCheckable = 1
info.func = hideNode
info.arg1 = currentZone
info.arg2 = currentCoord
LibDD:UIDropDownMenu_AddButton(info, level)
wipe(info)
if point.achievement then
-- Waypoint menu item
info.text = render_string("Hide all {achievement:" .. point.achievement .. "} in all zones")
info.notCheckable = 1
info.func = hideAchievement
info.arg1 = point.achievement
LibDD:UIDropDownMenu_AddButton(info, level)
wipe(info)
end
if point.group then
if not ns.hiddenConfig.groupsHiddenByZone then
local map = C_Map.GetMapInfo(currentZone)
info.text = "Hide all " .. render_string(ns.groups[point.group] or point.group, point) .. " in " .. (map and map.name or "this zone")
info.notCheckable = 1
info.func = hideGroupZone
info.arg1 = currentZone
info.arg2 = currentCoord
LibDD:UIDropDownMenu_AddButton(info, level)
wipe(info)
end
if not ns.hiddenConfig.groupsHidden then
info.text = "Hide all " .. render_string(ns.groups[point.group] or point.group, point) .. " in all zones"
info.notCheckable = 1
info.func = hideGroup
info.arg1 = currentZone
info.arg2 = currentCoord
LibDD:UIDropDownMenu_AddButton(info, level)
wipe(info)
end
end
-- Close menu item
info.text = "Close"
info.func = closeAllDropdowns
info.notCheckable = 1
LibDD:UIDropDownMenu_AddButton(info, level)
wipe(info)
end
end
local HL_Dropdown
function HLHandler:OnClick(button, down, uiMapID, coord)
if down then return end
currentZone = uiMapID
currentCoord = coord
-- given we're in a click handler, this really *should* exist, but just in case...
local point = ns.points[currentZone] and ns.points[currentZone][currentCoord]
if point then
if button == "RightButton" then
if not HL_Dropdown then
HL_Dropdown = LibDD:Create_UIDropDownMenu(myname .. "PointDropdown")
LibDD:UIDropDownMenu_SetInitializeFunction(HL_Dropdown, generateMenu)
LibDD:UIDropDownMenu_SetDisplayMode(HL_Dropdown, "MENU")
end
LibDD:ToggleDropDownMenu(1, nil, HL_Dropdown, self, 0, 0)
return
end
if button == "LeftButton" and IsShiftKeyDown() and _G.MAP_PIN_HYPERLINK then
sendToChat(button, uiMapID, coord)
return
end
if point.OnClick then
point:OnClick(button, uiMapID, coord)
end
end
end
end
function HLHandler:OnLeave(uiMapID, coord)
GameTooltip:Hide()
if _G[myname.."ComparisonTooltip"] then _G[myname.."ComparisonTooltip"]:Hide() end
local point = ns.points[uiMapID] and ns.points[uiMapID][coord]
if ns.RouteWorldMapDataProvider and (point.route or point.routes) then
if point.route and ns.points[uiMapID][point.route] then
point = ns.points[uiMapID][point.route]
end
ns.RouteWorldMapDataProvider:UnhighlightRoute(point, uiMapID, coord)
end
end
do
-- This is a custom iterator we use to iterate over every node in a given zone
local currentZone, isMinimap
local function iter(t, prestate)
if not t then return nil end
local state, value = next(t, prestate)
while state do -- Have we reached the end of this zone?
if value and ns.should_show_point(state, value, currentZone, isMinimap) then
local label, icon, _, _, _, scale, alpha = get_point_info(value, isMinimap)
scale = (scale or 1) * (icon and icon.scale or 1) * ns.db.icon_scale
return state, nil, icon, scale, ns.db.icon_alpha * alpha
end
state, value = next(t, state) -- Get next data
end
return nil, nil, nil, nil
end
function HLHandler:GetNodes2(uiMapID, minimap)
-- Debug("GetNodes2", uiMapID, minimap)
currentZone = uiMapID
isMinimap = minimap
return iter, ns.points[uiMapID], nil
end
end
---------------------------------------------------------
-- Addon initialization, enabling and disabling
function HL:OnInitialize()
-- Set up our database
if ns.defaultsOverride then
ns.merge(ns.defaults.profile, ns.defaultsOverride)
end
self.db = LibStub("AceDB-3.0"):New(myname.."DB", ns.defaults)
ns.db = self.db.profile
ns.hidden = self.db.char.hidden
-- Initialize our database with HandyNotes
HandyNotes:RegisterPluginDB(myname:gsub("HandyNotes_", ""), HLHandler, ns.options)
-- Watch for events... but mitigate spammy events by bucketing in Refresh
self:RegisterEvent("LOOT_CLOSED", "RefreshOnEvent")
self:RegisterEvent("ZONE_CHANGED_INDOORS", "RefreshOnEvent")
self:RegisterEvent("CRITERIA_EARNED", "RefreshOnEvent")
self:RegisterEvent("BAG_UPDATE", "RefreshOnEvent")
self:RegisterEvent("QUEST_TURNED_IN", "RefreshOnEvent")
if WOW_PROJECT_ID == WOW_PROJECT_MAINLINE then
self:RegisterEvent("SHOW_LOOT_TOAST", "RefreshOnEvent")
self:RegisterEvent("GARRISON_FOLLOWER_ADDED", "RefreshOnEvent")
end
-- This is sometimes spammy, but is the only thing that tends to get us casts:
self:RegisterEvent("CRITERIA_UPDATE", "RefreshOnEvent")
if ns.SetupMapOverlay then
ns.SetupMapOverlay()
end
if ns.RouteWorldMapDataProvider then
WorldMapFrame:AddDataProvider(ns.RouteWorldMapDataProvider)
end
end
do
local bucket = CreateFrame("Frame")
bucket.elapsed = 0
bucket:SetScript("OnUpdate", function(self, elapsed)
self.elapsed = self.elapsed + elapsed
if self.elapsed > 1.5 then
self.elapsed = 0
self:Hide()
HL:Refresh()
end
end)
function HL:Refresh()
HL:SendMessage("HandyNotes_NotifyUpdate", myname:gsub("HandyNotes_", ""))
if ns.RouteWorldMapDataProvider then
ns.RouteWorldMapDataProvider:RefreshAllData()
end
if ns.RouteMiniMapDataProvider then
ns.RouteMiniMapDataProvider:UpdateMinimapRoutes()
end
end
function HL:RefreshOnEvent(event)
bucket:Show()
end
end
hooksecurefunc(AreaPOIPinMixin, "TryShowTooltip", function(self)
-- if not self.db.profile.show_on_world then return end
if not self.areaPoiID then return end
if not ns.POIsToPoints[self.areaPoiID] then return end
local point = ns.POIsToPoints[self.areaPoiID]
-- if not ns.should_show_point(point._coord, point, point._uiMapID, false) then return end
handle_tooltip(GameTooltip, point, true)
end)
hooksecurefunc(AreaPOIPinMixin, "OnMouseLeave", function(self)
if _G[myname.."ComparisonTooltip"] then _G[myname.."ComparisonTooltip"]:Hide() end
end)
hooksecurefunc(VignettePinMixin, "OnMouseEnter", function(self)
local vignetteInfo = self.vignetteInfo
if not (vignetteInfo.vignetteID and ns.VignetteIDsToPoints[vignetteInfo.vignetteID]) then return end
local point = ns.VignetteIDsToPoints[vignetteInfo.vignetteID]
-- if not ns.should_show_point(point._coord, point, point._uiMapID, false) then return end
handle_tooltip(GameTooltip, point, true)
end)
hooksecurefunc(VignettePinMixin, "OnMouseLeave", function(self)
if _G[myname.."ComparisonTooltip"] then _G[myname.."ComparisonTooltip"]:Hide() end
end)
if _G.TaskPOI_OnEnter then
hooksecurefunc("TaskPOI_OnEnter", function(self)
if not self.questID then return end
if not ns.WorldQuestsToPoints[self.questID] then return end
local point = ns.WorldQuestsToPoints[self.questID]
-- if not ns.should_show_point(point._coord, point, point._uiMapID, false) then return end
handle_tooltip(GameTooltip, point, false)
end)
hooksecurefunc("TaskPOI_OnLeave", function(self)
-- 10.0.2 doesn't hide this by default any more
if _G[myname.."ComparisonTooltip"] then _G[myname.."ComparisonTooltip"]:Hide() end
end)
end