local myname , ns = ...
local _ , myfullname = C_AddOns.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 = C_AddOns.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
if point.additional then
-- Extra coordinates to register. This is equivalent to just
-- registering the same table multiple times on the input, and
-- should only be used for simple cases -- related points are
-- going to fall apart here.
for _ , acoord in pairs ( point.additional ) do
if ns.DEBUG and ns.points [ zone ] [ acoord ] then
print ( myname , " point collision " , zone , acoord )
end
ns.points [ zone ] [ acoord ] = point
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 ) )
if info and info.lines and info.lines [ 1 ] then
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 = C_Item.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
-- we bypass the normal fallback mechanism because we want the quest completion status
name = fallback ~= " " and fallback or ( variant .. ' : ' .. 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
elseif variant == " zone " then
local info = C_Map.GetMapInfo ( id )
if info and info.name then
return info.name
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 = C_Item.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 , C_Item.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 = C_Item.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 = C_Item.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 " )
if _G.GameTooltipDataMixin then Mixin ( comparison , GameTooltipDataMixin ) end
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