-- HereBeDragons-Pins is a library to show pins/icons on the world map and minimap
local MAJOR , MINOR = " HereBeDragons-Pins-2.0 " , 15
assert ( LibStub , MAJOR .. " requires LibStub " )
local pins , oldversion = LibStub : NewLibrary ( MAJOR , MINOR )
if not pins then return end
local HBD = LibStub ( " HereBeDragons-2.0 " )
local MinimapRadiusAPI = C_Minimap and C_Minimap.GetViewRadius
pins.updateFrame = pins.updateFrame or CreateFrame ( " Frame " )
-- storage for minimap pins
pins.minimapPins = pins.minimapPins or { }
pins.activeMinimapPins = pins.activeMinimapPins or { }
pins.minimapPinRegistry = pins.minimapPinRegistry or { }
-- and worldmap pins
pins.worldmapPins = pins.worldmapPins or { }
pins.worldmapPinRegistry = pins.worldmapPinRegistry or { }
pins.worldmapProvider = pins.worldmapProvider or CreateFromMixins ( MapCanvasDataProviderMixin )
pins.worldmapProviderPin = pins.worldmapProviderPin or CreateFromMixins ( MapCanvasPinMixin )
-- make sure the pool is refreshed
if oldversion and oldversion < 15 and pins.worldmapProvider and CreateUnsecuredRegionPoolInstance then
pins.worldmapProvider : RemoveAllData ( )
pins.worldmapPinsPool = nil
end
if not pins.worldmapPinsPool then
-- new frame pools in WoW 11.x
if CreateUnsecuredRegionPoolInstance then
pins.worldmapPinsPool = CreateUnsecuredRegionPoolInstance ( " HereBeDragonsPinsTemplate " )
else
pins.worldmapPinsPool = CreateFramePool ( " FRAME " )
end
end
-- store a reference to the active minimap object
pins.Minimap = pins.Minimap or Minimap
-- Data Constants
local WORLD_MAP_ID = 947
-- upvalue lua api
local cos , sin , max = math.cos , math.sin , math.max
local type , pairs = type , pairs
-- upvalue wow api
local GetPlayerFacing = GetPlayerFacing
-- upvalue data tables
local minimapPins = pins.minimapPins
local activeMinimapPins = pins.activeMinimapPins
local minimapPinRegistry = pins.minimapPinRegistry
local worldmapPins = pins.worldmapPins
local worldmapPinRegistry = pins.worldmapPinRegistry
local worldmapPinsPool = pins.worldmapPinsPool
local worldmapProvider = pins.worldmapProvider
local worldmapProviderPin = pins.worldmapProviderPin
local minimap_size = {
indoor = {
[ 0 ] = 300 , -- scale
[ 1 ] = 240 , -- 1.25
[ 2 ] = 180 , -- 5/3
[ 3 ] = 120 , -- 2.5
[ 4 ] = 80 , -- 3.75
[ 5 ] = 50 , -- 6
} ,
outdoor = {
[ 0 ] = 466 + 2 / 3 , -- scale
[ 1 ] = 400 , -- 7/6
[ 2 ] = 333 + 1 / 3 , -- 1.4
[ 3 ] = 266 + 2 / 6 , -- 1.75
[ 4 ] = 200 , -- 7/3
[ 5 ] = 133 + 1 / 3 , -- 3.5
} ,
}
local minimap_shapes = {
-- { upper-left, lower-left, upper-right, lower-right }
[ " SQUARE " ] = { false , false , false , false } ,
[ " CORNER-TOPLEFT " ] = { true , false , false , false } ,
[ " CORNER-TOPRIGHT " ] = { false , false , true , false } ,
[ " CORNER-BOTTOMLEFT " ] = { false , true , false , false } ,
[ " CORNER-BOTTOMRIGHT " ] = { false , false , false , true } ,
[ " SIDE-LEFT " ] = { true , true , false , false } ,
[ " SIDE-RIGHT " ] = { false , false , true , true } ,
[ " SIDE-TOP " ] = { true , false , true , false } ,
[ " SIDE-BOTTOM " ] = { false , true , false , true } ,
[ " TRICORNER-TOPLEFT " ] = { true , true , true , false } ,
[ " TRICORNER-TOPRIGHT " ] = { true , false , true , true } ,
[ " TRICORNER-BOTTOMLEFT " ] = { true , true , false , true } ,
[ " TRICORNER-BOTTOMRIGHT " ] = { false , true , true , true } ,
}
local tableCache = setmetatable ( { } , { __mode = ' k ' } )
local function newCachedTable ( )
local t = next ( tableCache )
if t then
tableCache [ t ] = nil
else
t = { }
end
return t
end
local function recycle ( t )
tableCache [ t ] = true
end
-------------------------------------------------------------------------------------------
-- Minimap pin position logic
-- minimap rotation
local rotateMinimap = GetCVar ( " rotateMinimap " ) == " 1 "
-- is the minimap indoors or outdoors
local indoors = GetCVar ( " minimapZoom " ) + 0 == pins.Minimap : GetZoom ( ) and " outdoor " or " indoor "
local minimapPinCount , queueFullUpdate = 0 , false
local minimapScale , minimapShape , mapRadius , minimapWidth , minimapHeight , mapSin , mapCos
local lastZoom , lastFacing , lastXY , lastYY
local function drawMinimapPin ( pin , data )
local xDist , yDist = lastXY - data.x , lastYY - data.y
-- handle rotation
if rotateMinimap then
local dx , dy = xDist , yDist
xDist = dx * mapCos - dy * mapSin
yDist = dx * mapSin + dy * mapCos
end
-- adapt delta position to the map radius
local diffX = xDist / mapRadius
local diffY = yDist / mapRadius
-- different minimap shapes
local isRound = true
if minimapShape and not ( xDist == 0 or yDist == 0 ) then
isRound = ( xDist < 0 ) and 1 or 3
if yDist < 0 then
isRound = minimapShape [ isRound ]
else
isRound = minimapShape [ isRound + 1 ]
end
end
-- calculate distance from the center of the map
local dist
if isRound then
dist = ( diffX * diffX + diffY * diffY ) / 0.9 ^ 2
else
dist = max ( diffX * diffX , diffY * diffY ) / 0.9 ^ 2
end
-- if distance > 1, then adapt node position to slide on the border
if dist > 1 and data.floatOnEdge then
dist = dist ^ 0.5
diffX = diffX / dist
diffY = diffY / dist
end
if dist <= 1 or data.floatOnEdge then
pin : Show ( )
pin : ClearAllPoints ( )
pin : SetPoint ( " CENTER " , pins.Minimap , " CENTER " , diffX * minimapWidth , - diffY * minimapHeight )
data.onEdge = ( dist > 1 )
else
pin : Hide ( )
data.onEdge = nil
pin.keep = nil
end
end
local function IsParentMap ( originMapId , toCheckMapId )
local parentMapID = HBD.mapData [ originMapId ] . parent
while parentMapID and HBD.mapData [ parentMapID ] do
local mapType = HBD.mapData [ parentMapID ] . mapType
if mapType ~= Enum.UIMapType . Zone and mapType ~= Enum.UIMapType . Dungeon and mapType ~= Enum.UIMapType . Micro then
return false
end
if parentMapID == toCheckMapId then
return true
end
parentMapID = HBD.mapData [ parentMapID ] . parent
end
return false
end
local function UpdateMinimapPins ( force )
-- get the current player position
local x , y , instanceID = HBD : GetPlayerWorldPosition ( )
local mapID = HBD : GetPlayerZone ( )
-- get data from the API for calculations
local zoom = pins.Minimap : GetZoom ( )
local diffZoom = zoom ~= lastZoom
-- for rotating minimap support
local facing
if rotateMinimap then
facing = GetPlayerFacing ( )
else
facing = lastFacing
end
-- check for all values to be available (starting with 7.1.0, instances don't report coordinates)
if not x or not y or ( rotateMinimap and not facing ) then
minimapPinCount = 0
for pin in pairs ( activeMinimapPins ) do
pin : Hide ( )
activeMinimapPins [ pin ] = nil
end
return
end
local newScale = pins.Minimap : GetScale ( )
if minimapScale ~= newScale then
minimapScale = newScale
force = true
end
if x ~= lastXY or y ~= lastYY or diffZoom or facing ~= lastFacing or force then
-- minimap information
minimapShape = GetMinimapShape and minimap_shapes [ GetMinimapShape ( ) or " ROUND " ]
minimapWidth = pins.Minimap : GetWidth ( ) / 2
minimapHeight = pins.Minimap : GetHeight ( ) / 2
if MinimapRadiusAPI then
mapRadius = C_Minimap.GetViewRadius ( )
else
mapRadius = minimap_size [ indoors ] [ zoom ] / 2
end
-- update upvalues for icon placement
lastZoom = zoom
lastFacing = facing
lastXY , lastYY = x , y
if rotateMinimap then
mapSin = sin ( facing )
mapCos = cos ( facing )
end
for pin , data in pairs ( minimapPins ) do
if data.instanceID == instanceID and ( not data.uiMapID or data.uiMapID == mapID or ( data.showInParentZone and IsParentMap ( data.uiMapID , mapID ) ) ) then
activeMinimapPins [ pin ] = data
data.keep = true
-- draw the pin (this may reset data.keep if outside of the map)
drawMinimapPin ( pin , data )
end
end
minimapPinCount = 0
for pin , data in pairs ( activeMinimapPins ) do
if not data.keep then
pin : Hide ( )
activeMinimapPins [ pin ] = nil
else
minimapPinCount = minimapPinCount + 1
data.keep = nil
end
end
end
end
local function UpdateMinimapIconPosition ( )
-- get the current map zoom
local zoom = pins.Minimap : GetZoom ( )
local diffZoom = zoom ~= lastZoom
-- if the map zoom changed, run a full update sweep
if diffZoom then
UpdateMinimapPins ( )
return
end
-- we have no active minimap pins, just return early
if minimapPinCount == 0 then return end
local x , y = HBD : GetPlayerWorldPosition ( )
-- for rotating minimap support
local facing
if rotateMinimap then
facing = GetPlayerFacing ( )
else
facing = lastFacing
end
-- check for all values to be available (starting with 7.1.0, instances don't report coordinates)
if not x or not y or ( rotateMinimap and not facing ) then
UpdateMinimapPins ( )
return
end
local refresh
local newScale = pins.Minimap : GetScale ( )
if minimapScale ~= newScale then
minimapScale = newScale
refresh = true
end
if x ~= lastXY or y ~= lastYY or facing ~= lastFacing or refresh then
-- update radius of the map
if MinimapRadiusAPI then
mapRadius = C_Minimap.GetViewRadius ( )
else
mapRadius = minimap_size [ indoors ] [ zoom ] / 2
end
-- update upvalues for icon placement
lastXY , lastYY = x , y
lastFacing = facing
if rotateMinimap then
mapSin = sin ( facing )
mapCos = cos ( facing )
end
-- iterate all nodes and check if they are still in range of our minimap display
for pin , data in pairs ( activeMinimapPins ) do
-- update the position of the node
drawMinimapPin ( pin , data )
end
end
end
local function UpdateMinimapZoom ( )
if not MinimapRadiusAPI then
local zoom = pins.Minimap : GetZoom ( )
if GetCVar ( " minimapZoom " ) == GetCVar ( " minimapInsideZoom " ) then
pins.Minimap : SetZoom ( zoom < 2 and zoom + 1 or zoom - 1 )
end
indoors = GetCVar ( " minimapZoom " ) + 0 == pins.Minimap : GetZoom ( ) and " outdoor " or " indoor "
pins.Minimap : SetZoom ( zoom )
end
end
-------------------------------------------------------------------------------------------
-- WorldMap data provider
-- setup pin pool
worldmapPinsPool.parent = WorldMapFrame : GetCanvas ( )
worldmapPinsPool.createFunc = function ( )
local frame = CreateFrame ( " Frame " , nil , WorldMapFrame : GetCanvas ( ) )
frame : SetSize ( 1 , 1 )
return Mixin ( frame , worldmapProviderPin )
end
worldmapPinsPool.resetFunc = function ( pinPool , pin )
pin : Hide ( )
pin : ClearAllPoints ( )
pin : OnReleased ( )
pin.pinTemplate = nil
pin.owningMap = nil
end
-- pre-11.x func names
worldmapPinsPool.creationFunc = worldmapPinsPool.createFunc
worldmapPinsPool.resetterFunc = worldmapPinsPool.resetFunc
-- register pin pool with the world map
WorldMapFrame.pinPools [ " HereBeDragonsPinsTemplate " ] = worldmapPinsPool
-- provider base API
function worldmapProvider : RemoveAllData ( )
self : GetMap ( ) : RemoveAllPinsByTemplate ( " HereBeDragonsPinsTemplate " )
end
function worldmapProvider : RemovePinByIcon ( icon )
for pin in self : GetMap ( ) : EnumeratePinsByTemplate ( " HereBeDragonsPinsTemplate " ) do
if pin.icon == icon then
self : GetMap ( ) : RemovePin ( pin )
end
end
end
function worldmapProvider : RemovePinsByRef ( ref )
for pin in self : GetMap ( ) : EnumeratePinsByTemplate ( " HereBeDragonsPinsTemplate " ) do
if pin.icon and worldmapPinRegistry [ ref ] [ pin.icon ] then
self : GetMap ( ) : RemovePin ( pin )
end
end
end
function worldmapProvider : RefreshAllData ( fromOnShow )
self : RemoveAllData ( )
for icon , data in pairs ( worldmapPins ) do
self : HandlePin ( icon , data )
end
end
function worldmapProvider : HandlePin ( icon , data )
local uiMapID = self : GetMap ( ) : GetMapID ( )
-- check for a valid map
if not uiMapID then return end
local x , y
if uiMapID == WORLD_MAP_ID then
-- should this pin show on the world map?
if uiMapID ~= data.uiMapID and data.worldMapShowFlag ~= HBD_PINS_WORLDMAP_SHOW_WORLD then return end
-- translate to the world map
x , y = HBD : GetAzerothWorldMapCoordinatesFromWorld ( data.x , data.y , data.instanceID )
else
-- check that it matches the instance
if not HBD.mapData [ uiMapID ] or HBD.mapData [ uiMapID ] . instance ~= data.instanceID then return end
if uiMapID ~= data.uiMapID then
local mapType = HBD.mapData [ uiMapID ] . mapType
if not data.uiMapID then
if mapType == Enum.UIMapType . Continent and data.worldMapShowFlag >= HBD_PINS_WORLDMAP_SHOW_CONTINENT then
--pass
elseif mapType ~= Enum.UIMapType . Zone and mapType ~= Enum.UIMapType . Dungeon and mapType ~= Enum.UIMapType . Micro then
-- fail
return
end
else
local show = false
local parentMapID = HBD.mapData [ data.uiMapID ] . parent
while parentMapID and HBD.mapData [ parentMapID ] do
if parentMapID == uiMapID then
local parentMapType = HBD.mapData [ parentMapID ] . mapType
-- show on any parent zones if they are normal zones
if data.worldMapShowFlag >= HBD_PINS_WORLDMAP_SHOW_PARENT and
( parentMapType == Enum.UIMapType . Zone or parentMapType == Enum.UIMapType . Dungeon or parentMapType == Enum.UIMapType . Micro ) then
show = true
-- show on the continent
elseif data.worldMapShowFlag >= HBD_PINS_WORLDMAP_SHOW_CONTINENT and
parentMapType == Enum.UIMapType . Continent then
show = true
end
break
-- worldmap is handled above already
else
parentMapID = HBD.mapData [ parentMapID ] . parent
end
end
if not show then return end
end
end
-- translate coordinates
x , y = HBD : GetZoneCoordinatesFromWorld ( data.x , data.y , uiMapID )
end
if x and y then
self : GetMap ( ) : AcquirePin ( " HereBeDragonsPinsTemplate " , icon , x , y , data.frameLevelType )
end
end
-- map pin base API
function worldmapProviderPin : OnLoad ( )
self : UseFrameLevelType ( " PIN_FRAME_LEVEL_AREA_POI " )
self : SetScalingLimits ( 1 , 1.0 , 1.2 )
end
function worldmapProviderPin : OnAcquired ( icon , x , y , frameLevelType )
self : UseFrameLevelType ( frameLevelType or " PIN_FRAME_LEVEL_AREA_POI " )
self : SetPosition ( x , y )
self.icon = icon
icon : SetParent ( self )
icon : ClearAllPoints ( )
icon : SetPoint ( " CENTER " , self , " CENTER " )
icon : Show ( )
end
function worldmapProviderPin : OnReleased ( )
if self.icon then
self.icon : Hide ( )
self.icon : SetParent ( UIParent )
self.icon : ClearAllPoints ( )
self.icon = nil
end
end
-- hack to avoid in-combat error on 10.1.5
worldmapProviderPin.SetPassThroughButtons = function ( ) end
-- register with the world map
WorldMapFrame : AddDataProvider ( worldmapProvider )
-- map event handling
local function UpdateMinimap ( )
UpdateMinimapZoom ( )
UpdateMinimapPins ( )
end
local function UpdateWorldMap ( )
worldmapProvider : RefreshAllData ( )
end
local last_update = 0
local function OnUpdateHandler ( frame , elapsed )
last_update = last_update + elapsed
if last_update > 1 or queueFullUpdate then
UpdateMinimapPins ( queueFullUpdate )
last_update = 0
queueFullUpdate = false
else
UpdateMinimapIconPosition ( )
end
end
pins.updateFrame : SetScript ( " OnUpdate " , OnUpdateHandler )
local function OnEventHandler ( frame , event , ... )
if event == " CVAR_UPDATE " then
local cvar , value = ...
if cvar == " rotateMinimap " or cvar == " ROTATE_MINIMAP " then
rotateMinimap = ( value == " 1 " )
queueFullUpdate = true
end
elseif event == " MINIMAP_UPDATE_ZOOM " then
UpdateMinimap ( )
elseif event == " PLAYER_LOGIN " then
-- recheck cvars after login
rotateMinimap = GetCVar ( " rotateMinimap " ) == " 1 "
elseif event == " PLAYER_ENTERING_WORLD " then
UpdateMinimap ( )
UpdateWorldMap ( )
end
end
pins.updateFrame : SetScript ( " OnEvent " , OnEventHandler )
pins.updateFrame : UnregisterAllEvents ( )
pins.updateFrame : RegisterEvent ( " CVAR_UPDATE " )
pins.updateFrame : RegisterEvent ( " MINIMAP_UPDATE_ZOOM " )
pins.updateFrame : RegisterEvent ( " PLAYER_LOGIN " )
pins.updateFrame : RegisterEvent ( " PLAYER_ENTERING_WORLD " )
HBD.RegisterCallback ( pins , " PlayerZoneChanged " , UpdateMinimap )
--- Add a icon to the minimap (x/y world coordinate version)
-- Note: This API does not let you specify a map to limit the pin to, it'll be shown on all maps these coordinates are valid for.
-- @param ref Reference to your addon to track the icon under (ie. your "self" or string identifier)
-- @param icon Icon Frame
-- @param instanceID Instance ID of the map to add the icon to
-- @param x X position in world coordinates
-- @param y Y position in world coordinates
-- @param floatOnEdge flag if the icon should float on the edge of the minimap when going out of range, or hide immediately (default false)
function pins : AddMinimapIconWorld ( ref , icon , instanceID , x , y , floatOnEdge )
if not ref then
error ( MAJOR .. " : AddMinimapIconWorld: 'ref' must not be nil " , 2 )
end
if type ( icon ) ~= " table " or not icon.SetPoint then
error ( MAJOR .. " : AddMinimapIconWorld: 'icon' must be a frame " , 2 )
end
if type ( instanceID ) ~= " number " or type ( x ) ~= " number " or type ( y ) ~= " number " then
error ( MAJOR .. " : AddMinimapIconWorld: 'instanceID', 'x' and 'y' must be numbers " , 2 )
end
if not minimapPinRegistry [ ref ] then
minimapPinRegistry [ ref ] = { }
end
minimapPinRegistry [ ref ] [ icon ] = true
local t = minimapPins [ icon ] or newCachedTable ( )
t.instanceID = instanceID
t.x = x
t.y = y
t.floatOnEdge = floatOnEdge
t.uiMapID = nil
t.showInParentZone = nil
minimapPins [ icon ] = t
queueFullUpdate = true
icon : SetParent ( pins.Minimap )
end
--- Add a icon to the minimap (UiMapID zone coordinate version)
-- The pin will only be shown on the map specified, or optionally its parent map if specified
-- @param ref Reference to your addon to track the icon under (ie. your "self" or string identifier)
-- @param icon Icon Frame
-- @param uiMapID uiMapID of the map to place the icon on
-- @param x X position in local/point coordinates (0-1), relative to the zone
-- @param y Y position in local/point coordinates (0-1), relative to the zone
-- @param showInParentZone flag if the icon should be shown in its parent zone - ie. an icon in a microdungeon in the outdoor zone itself (default false)
-- @param floatOnEdge flag if the icon should float on the edge of the minimap when going out of range, or hide immediately (default false)
function pins : AddMinimapIconMap ( ref , icon , uiMapID , x , y , showInParentZone , floatOnEdge )
if not ref then
error ( MAJOR .. " : AddMinimapIconMap: 'ref' must not be nil " , 2 )
end
if type ( icon ) ~= " table " or not icon.SetPoint then
error ( MAJOR .. " : AddMinimapIconMap: 'icon' must be a frame " , 2 )
end
if type ( uiMapID ) ~= " number " or type ( x ) ~= " number " or type ( y ) ~= " number " then
error ( MAJOR .. " : AddMinimapIconMap: 'uiMapID', 'x' and 'y' must be numbers " , 2 )
end
-- convert to world coordinates and use our known adding function
local xCoord , yCoord , instanceID = HBD : GetWorldCoordinatesFromZone ( x , y , uiMapID )
if not xCoord then return end
self : AddMinimapIconWorld ( ref , icon , instanceID , xCoord , yCoord , floatOnEdge )
-- store extra information
minimapPins [ icon ] . uiMapID = uiMapID
minimapPins [ icon ] . showInParentZone = showInParentZone
end
--- Check if a floating minimap icon is on the edge of the map
-- @param icon the minimap icon
function pins : IsMinimapIconOnEdge ( icon )
if not icon then return false end
local data = minimapPins [ icon ]
if not data then return nil end
return data.onEdge
end
--- Remove a minimap icon
-- @param ref Reference to your addon to track the icon under (ie. your "self" or string identifier)
-- @param icon Icon Frame
function pins : RemoveMinimapIcon ( ref , icon )
if not ref or not icon or not minimapPinRegistry [ ref ] then return end
minimapPinRegistry [ ref ] [ icon ] = nil
if minimapPins [ icon ] then
recycle ( minimapPins [ icon ] )
minimapPins [ icon ] = nil
activeMinimapPins [ icon ] = nil
end
icon : Hide ( )
end
--- Remove all minimap icons belonging to your addon (as tracked by "ref")
-- @param ref Reference to your addon to track the icon under (ie. your "self" or string identifier)
function pins : RemoveAllMinimapIcons ( ref )
if not ref or not minimapPinRegistry [ ref ] then return end
for icon in pairs ( minimapPinRegistry [ ref ] ) do
recycle ( minimapPins [ icon ] )
minimapPins [ icon ] = nil
activeMinimapPins [ icon ] = nil
icon : Hide ( )
end
wipe ( minimapPinRegistry [ ref ] )
end
--- Set the minimap object to position the pins on. Needs to support the usual functions a Minimap-type object exposes.
-- @param minimapObject The new minimap object, or nil to restore the default
function pins : SetMinimapObject ( minimapObject )
pins.Minimap = minimapObject or Minimap
for pin in pairs ( minimapPins ) do
pin : SetParent ( pins.Minimap )
end
UpdateMinimapPins ( true )
end
-- world map constants
-- show worldmap pin on its parent zone map (if any)
HBD_PINS_WORLDMAP_SHOW_PARENT = 1
-- show worldmap pin on the continent map
HBD_PINS_WORLDMAP_SHOW_CONTINENT = 2
-- show worldmap pin on the continent and world map
HBD_PINS_WORLDMAP_SHOW_WORLD = 3
--- Add a icon to the world map (x/y world coordinate version)
-- Note: This API does not let you specify a map to limit the pin to, it'll be shown on all maps these coordinates are valid for.
-- @param ref Reference to your addon to track the icon under (ie. your "self" or string identifier)
-- @param icon Icon Frame
-- @param instanceID Instance ID of the map to add the icon to
-- @param x X position in world coordinates
-- @param y Y position in world coordinates
-- @param showFlag Flag to control on which maps this pin will be shown
-- @param frameLevel Optional Frame Level type registered with the WorldMapFrame, defaults to PIN_FRAME_LEVEL_AREA_POI
function pins : AddWorldMapIconWorld ( ref , icon , instanceID , x , y , showFlag , frameLevel )
if not ref then
error ( MAJOR .. " : AddWorldMapIconWorld: 'ref' must not be nil " , 2 )
end
if type ( icon ) ~= " table " or not icon.SetPoint then
error ( MAJOR .. " : AddWorldMapIconWorld: 'icon' must be a frame " , 2 )
end
if type ( instanceID ) ~= " number " or type ( x ) ~= " number " or type ( y ) ~= " number " then
error ( MAJOR .. " : AddWorldMapIconWorld: 'instanceID', 'x' and 'y' must be numbers " , 2 )
end
if showFlag ~= nil and type ( showFlag ) ~= " number " then
error ( MAJOR .. " : AddWorldMapIconWorld: 'showFlag' must be a number (or nil) " , 2 )
end
if not worldmapPinRegistry [ ref ] then
worldmapPinRegistry [ ref ] = { }
end
worldmapPinRegistry [ ref ] [ icon ] = true
local t = worldmapPins [ icon ] or newCachedTable ( )
t.instanceID = instanceID
t.x = x
t.y = y
t.uiMapID = nil
t.worldMapShowFlag = showFlag or 0
t.frameLevelType = frameLevel
worldmapPins [ icon ] = t
worldmapProvider : HandlePin ( icon , t )
end
--- Add a icon to the world map (uiMapID zone coordinate version)
-- @param ref Reference to your addon to track the icon under (ie. your "self" or string identifier)
-- @param icon Icon Frame
-- @param uiMapID uiMapID of the map to place the icon on
-- @param x X position in local/point coordinates (0-1), relative to the zone
-- @param y Y position in local/point coordinates (0-1), relative to the zone
-- @param showFlag Flag to control on which maps this pin will be shown
-- @param frameLevel Optional Frame Level type registered with the WorldMapFrame, defaults to PIN_FRAME_LEVEL_AREA_POI
function pins : AddWorldMapIconMap ( ref , icon , uiMapID , x , y , showFlag , frameLevel )
if not ref then
error ( MAJOR .. " : AddWorldMapIconMap: 'ref' must not be nil " , 2 )
end
if type ( icon ) ~= " table " or not icon.SetPoint then
error ( MAJOR .. " : AddWorldMapIconMap: 'icon' must be a frame " , 2 )
end
if type ( uiMapID ) ~= " number " or type ( x ) ~= " number " or type ( y ) ~= " number " then
error ( MAJOR .. " : AddWorldMapIconMap: 'uiMapID', 'x' and 'y' must be numbers " , 2 )
end
if showFlag ~= nil and type ( showFlag ) ~= " number " then
error ( MAJOR .. " : AddWorldMapIconMap: 'showFlag' must be a number (or nil) " , 2 )
end
-- convert to world coordinates
local xCoord , yCoord , instanceID = HBD : GetWorldCoordinatesFromZone ( x , y , uiMapID )
if not xCoord then return end
if not worldmapPinRegistry [ ref ] then
worldmapPinRegistry [ ref ] = { }
end
worldmapPinRegistry [ ref ] [ icon ] = true
local t = worldmapPins [ icon ] or newCachedTable ( )
t.instanceID = instanceID
t.x = xCoord
t.y = yCoord
t.uiMapID = uiMapID
t.worldMapShowFlag = showFlag or 0
t.frameLevelType = frameLevel
worldmapPins [ icon ] = t
worldmapProvider : HandlePin ( icon , t )
end
--- Remove a worldmap icon
-- @param ref Reference to your addon to track the icon under (ie. your "self" or string identifier)
-- @param icon Icon Frame
function pins : RemoveWorldMapIcon ( ref , icon )
if not ref or not icon or not worldmapPinRegistry [ ref ] then return end
worldmapPinRegistry [ ref ] [ icon ] = nil
if worldmapPins [ icon ] then
recycle ( worldmapPins [ icon ] )
worldmapPins [ icon ] = nil
end
worldmapProvider : RemovePinByIcon ( icon )
end
--- Remove all worldmap icons belonging to your addon (as tracked by "ref")
-- @param ref Reference to your addon to track the icon under (ie. your "self" or string identifier)
function pins : RemoveAllWorldMapIcons ( ref )
if not ref or not worldmapPinRegistry [ ref ] then return end
for icon in pairs ( worldmapPinRegistry [ ref ] ) do
recycle ( worldmapPins [ icon ] )
worldmapPins [ icon ] = nil
end
worldmapProvider : RemovePinsByRef ( ref )
wipe ( worldmapPinRegistry [ ref ] )
end
--- Return the angle and distance from the player to the specified pin
-- @param icon icon object (minimap or worldmap)
-- @return angle, distance where angle is in radians and distance in yards
function pins : GetVectorToIcon ( icon )
if not icon then return nil , nil end
local data = minimapPins [ icon ] or worldmapPins [ icon ]
if not data then return nil , nil end
local x , y , instance = HBD : GetPlayerWorldPosition ( )
if not x or not y or instance ~= data.instanceID then return nil end
return HBD : GetWorldVector ( instance , x , y , data.x , data.y )
end
if oldversion then
if WorldMapFrame : IsShown ( ) then
worldmapProvider : RefreshAllData ( false )
end
end