v9.7.2: Ebonhold Database integration and core logic refinements
This commit is contained in:
+869
@@ -0,0 +1,869 @@
|
||||
---@type QuestieMap
|
||||
local QuestieMap = QuestieLoader:ImportModule("QuestieMap");
|
||||
|
||||
local mapData = QuestieCompat.UiMapData -- table { width, height, left, top, .instance, .name, .mapType }
|
||||
local worldMapData = QuestieCompat.worldMapData -- table { width, height, left, top }
|
||||
|
||||
local HBD = {mapData = mapData}
|
||||
QuestieCompat.HBD = HBD
|
||||
|
||||
--- Convert local/point coordinates to world coordinates in yards
|
||||
-- @param x X position in 0-1 point coordinates
|
||||
-- @param y Y position in 0-1 point coordinates
|
||||
-- @param zone uiMapID of the zone
|
||||
function HBD:GetWorldCoordinatesFromZone(x, y, zone)
|
||||
local data = mapData[zone]
|
||||
if not data or data[1] == 0 or data[2] == 0 then return nil, nil, nil end
|
||||
if not x or not y then return nil, nil, nil end
|
||||
|
||||
local width, height, left, top = data[1], data[2], data[3], data[4]
|
||||
x, y = left - width * x, top - height * y
|
||||
|
||||
return x, y, data.instance
|
||||
end
|
||||
|
||||
--- Convert world coordinates to local/point zone coordinates
|
||||
-- @param x Global X position
|
||||
-- @param y Global Y position
|
||||
-- @param zone uiMapID of the zone
|
||||
-- @param allowOutOfBounds Allow coordinates to go beyond the current map (ie. outside of the 0-1 range), otherwise nil will be returned
|
||||
function HBD:GetZoneCoordinatesFromWorld(x, y, zone, allowOutOfBounds)
|
||||
local data = mapData[zone]
|
||||
if not data or data[1] == 0 or data[2] == 0 then return nil, nil end
|
||||
if not x or not y then return nil, nil end
|
||||
|
||||
local width, height, left, top = data[1], data[2], data[3], data[4]
|
||||
x, y = (left - x) / width, (top - y) / height
|
||||
|
||||
-- verify the coordinates fall into the zone
|
||||
if not allowOutOfBounds and (x < 0 or x > 1 or y < 0 or y > 1) then return nil, nil end
|
||||
|
||||
return x, y
|
||||
end
|
||||
|
||||
--- Convert world coordinates to local/point zone coordinates on the azeroth world map
|
||||
-- @param x Global X position
|
||||
-- @param y Global Y position
|
||||
-- @param instance Instance to translate coordinates from
|
||||
-- @param allowOutOfBounds Allow coordinates to go beyond the current map (ie. outside of the 0-1 range), otherwise nil will be returned
|
||||
function HBD:GetAzerothWorldMapCoordinatesFromWorld(x, y, instance, allowOutOfBounds)
|
||||
local data = worldMapData[instance]
|
||||
if not data or data[1] == 0 or data[2] == 0 then return nil, nil end
|
||||
if not x or not y then return nil, nil end
|
||||
|
||||
local width, height, left, top = data[1], data[2], data[3], data[4]
|
||||
x, y = (left - x) / width, (top - y) / height
|
||||
|
||||
-- verify the coordinates fall into the zone
|
||||
if not allowOutOfBounds and (x < 0 or x > 1 or y < 0 or y > 1) then return nil, nil end
|
||||
|
||||
return x, y
|
||||
end
|
||||
|
||||
--- Return the distance from an origin position to a destination position in the same instance/continent.
|
||||
-- @param instanceID instance ID
|
||||
-- @param oX origin X
|
||||
-- @param oY origin Y
|
||||
-- @param dX destination X
|
||||
-- @param dY destination Y
|
||||
-- @return distance, deltaX, deltaY
|
||||
function HBD:GetWorldDistance(instanceID, oX, oY, dX, dY)
|
||||
if not oX or not oY or not dX or not dY then return nil, nil, nil end
|
||||
local deltaX, deltaY = dX - oX, dY - oY
|
||||
return (deltaX * deltaX + deltaY * deltaY)^0.5, deltaX, deltaY
|
||||
end
|
||||
|
||||
--- Return the distance between two points on the same continent
|
||||
-- @param oZone origin zone uiMapID
|
||||
-- @param oX origin X, in local zone/point coordinates
|
||||
-- @param oY origin Y, in local zone/point coordinates
|
||||
-- @param dZone destination zone uiMapID
|
||||
-- @param dX destination X, in local zone/point coordinates
|
||||
-- @param dY destination Y, in local zone/point coordinates
|
||||
-- @return distance, deltaX, deltaY in yards
|
||||
function HBD:GetZoneDistance(oZone, oX, oY, dZone, dX, dY)
|
||||
local oInstance, dInstance
|
||||
oX, oY, oInstance = self:GetWorldCoordinatesFromZone(oX, oY, oZone)
|
||||
if not oX then return nil, nil, nil end
|
||||
|
||||
-- translate dX, dY to the origin zone
|
||||
dX, dY, dInstance = self:GetWorldCoordinatesFromZone(dX, dY, dZone)
|
||||
if not dX then return nil, nil, nil end
|
||||
|
||||
if oInstance ~= dInstance then return nil, nil, nil end
|
||||
|
||||
return self:GetWorldDistance(oInstance, oX, oY, dX, dY)
|
||||
end
|
||||
|
||||
--- Get the current world position of the player
|
||||
-- The position is transformed to the current continent, if applicable
|
||||
-- @return x, y, instanceID
|
||||
function HBD:GetPlayerWorldPosition()
|
||||
local x, y, uiMapID = HBD:GetPlayerZonePosition()
|
||||
if not x or not y then return nil, nil, nil end
|
||||
|
||||
x, y, instanceID = HBD:GetWorldCoordinatesFromZone(x, y, uiMapID)
|
||||
if x and y then
|
||||
return x, y, instanceID
|
||||
end
|
||||
return nil, nil, nil
|
||||
end
|
||||
|
||||
--- Get the current zone and level of the player
|
||||
-- The returned mapFile can represent a micro dungeon, if the player currently is inside one.
|
||||
-- @return uiMapID, mapType
|
||||
function HBD:GetPlayerZone()
|
||||
return QuestieCompat.GetCurrentPlayerPosition()
|
||||
end
|
||||
|
||||
--- Get the current position of the player on a zone level
|
||||
-- The returned values are local point coordinates, 0-1. The mapFile can represent a micro dungeon.
|
||||
-- @param allowOutOfBounds Allow coordinates to go beyond the current map (ie. outside of the 0-1 range), otherwise nil will be returned
|
||||
-- @return x, y, uiMapID, mapType
|
||||
function HBD:GetPlayerZonePosition(allowOutOfBounds)
|
||||
-- get the current position
|
||||
local uiMapID, x, y = QuestieCompat.GetCurrentPlayerPosition()
|
||||
|
||||
if uiMapID and x and y then
|
||||
return x, y, uiMapID
|
||||
end
|
||||
return nil, nil, nil, nil
|
||||
end
|
||||
|
||||
-- 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
|
||||
|
||||
-- storage for minimap pins
|
||||
local minimapPins = {}
|
||||
local activeMinimapPins = {}
|
||||
local minimapPinRegistry = {}
|
||||
|
||||
-- and worldmap pins
|
||||
local worldmapPins = {}
|
||||
local worldmapPinRegistry = {}
|
||||
|
||||
local pins = {
|
||||
Minimap = Minimap,
|
||||
updateFrame = CreateFrame("Frame"),
|
||||
activeMinimapPins = activeMinimapPins,
|
||||
worldmapPins = worldmapPins,
|
||||
worldmapProvider = {
|
||||
GetMap = function(self) return QuestieCompat.WorldMapFrame end,
|
||||
},
|
||||
}
|
||||
QuestieCompat.HBDPins = pins
|
||||
|
||||
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
|
||||
},
|
||||
}
|
||||
|
||||
---@class MinimapShapes
|
||||
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
|
||||
---@type unknown, MinimapShapes?
|
||||
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
|
||||
---@type boolean|number
|
||||
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
|
||||
|
||||
-- Questie Modification.
|
||||
-- data.floatOnEdge is replaced by (data.floatOnEdge and ((pin.texture and pin.texture.a and pin.texture.a ~= 0) or pin.texture == nil))
|
||||
-- icons will now only float on edge if they have an opacity which is not 0 or if no texture exist.
|
||||
data.distanceFromMinimapCenter = dist
|
||||
if dist <= 1 or (data.floatOnEdge and ((pin.texture and pin.texture.a and pin.texture.a ~= 0) or pin.texture == nil)) 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 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
|
||||
local sizeTable = minimap_size[indoors] or minimap_size.outdoor
|
||||
local size = sizeTable[zoom]
|
||||
or sizeTable[5]
|
||||
or sizeTable[4]
|
||||
or sizeTable[3]
|
||||
or sizeTable[2]
|
||||
or sizeTable[1]
|
||||
or sizeTable[0]
|
||||
|
||||
mapRadius = size / 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 instanceID == data.instanceID and math.abs(x-data.x) + math.abs(y-data.y) < 500 then -- questie specific fix
|
||||
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
|
||||
local sizeTable = minimap_size[indoors] or minimap_size.outdoor
|
||||
local size = sizeTable[zoom]
|
||||
or sizeTable[5]
|
||||
or sizeTable[4]
|
||||
or sizeTable[3]
|
||||
or sizeTable[2]
|
||||
or sizeTable[1]
|
||||
or sizeTable[0]
|
||||
|
||||
mapRadius = size / 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
|
||||
|
||||
local Enum = {
|
||||
-- https://wowpedia.fandom.com/wiki/Enum.UIMapType
|
||||
UIMapType = {
|
||||
Cosmic = 0,
|
||||
World = 1,
|
||||
Continent = 2,
|
||||
Zone = 3,
|
||||
Dungeon = 4,
|
||||
Micro = 5,
|
||||
Orphan = 6
|
||||
}
|
||||
}
|
||||
|
||||
local worldmapWidth, worldmapHeight
|
||||
|
||||
local function HandleWorldMapPin(icon, data)
|
||||
if not WorldMapFrame:IsVisible() then return end
|
||||
|
||||
local uiMapID = QuestieCompat.GetCurrentUiMapID()
|
||||
|
||||
-- check for a valid map
|
||||
if not uiMapID then return end
|
||||
|
||||
--Questie Modification
|
||||
if (Questie.db.profile.hideIconsOnContinents == true) and (HBD.mapData[uiMapID].mapType == Enum.UIMapType.Continent or uiMapID == 947) or (uiMapID ~= data.uiMapID and data.worldMapShowFlag == HBD_PINS_WORLDMAP_SHOW_CURRENT) then
|
||||
icon:Hide();
|
||||
return;
|
||||
elseif(uiMapID == data.uiMapID and data.worldMapShowFlag == HBD_PINS_WORLDMAP_SHOW_CURRENT) then
|
||||
icon:Show();
|
||||
end
|
||||
|
||||
if icon.type == "line" 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 = true -- Questie fix to show icons in neighbour areas
|
||||
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
|
||||
elseif data.worldMapShowFlag == HBD_PINS_WORLDMAP_SHOW_CURRENT then
|
||||
-- Questie modifications!
|
||||
show = false
|
||||
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
|
||||
icon:ClearAllPoints()
|
||||
icon:SetPoint("CENTER", WorldMapButton, "TOPLEFT", x * worldmapWidth, -y * worldmapHeight)
|
||||
icon:Show()
|
||||
else
|
||||
icon:Hide()
|
||||
end
|
||||
end
|
||||
|
||||
-- map event handling
|
||||
local function UpdateMinimap()
|
||||
UpdateMinimapZoom()
|
||||
UpdateMinimapPins()
|
||||
end
|
||||
|
||||
local function UpdateWorldMap()
|
||||
if not WorldMapFrame:IsVisible() then return end
|
||||
|
||||
local scale = WorldMapButton:GetScale()
|
||||
worldmapWidth = WorldMapButton:GetWidth()*scale
|
||||
worldmapHeight = WorldMapButton:GetHeight()*scale
|
||||
|
||||
local mapScale = QuestieMap.GetScaleValue()
|
||||
|
||||
for icon, data in pairs(worldmapPins) do
|
||||
icon:Hide()
|
||||
--icon:ClearAllPoints()
|
||||
|
||||
QuestieMap.utils:RescaleIcon(icon, mapScale)
|
||||
HandleWorldMapPin(icon, data)
|
||||
end
|
||||
end
|
||||
pins.UpdateWorldMap = UpdateWorldMap
|
||||
|
||||
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 == "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()
|
||||
elseif event == "WORLD_MAP_UPDATE" then
|
||||
UpdateWorldMap()
|
||||
elseif string.find(event, "ZONE_CHANGED") then
|
||||
UpdateMinimap()
|
||||
UpdateWorldMap()
|
||||
end
|
||||
end
|
||||
|
||||
pins.updateFrame:SetScript("OnEvent", OnEventHandler)
|
||||
pins.updateFrame:RegisterEvent("CVAR_UPDATE")
|
||||
pins.updateFrame:RegisterEvent("MINIMAP_UPDATE_ZOOM")
|
||||
pins.updateFrame:RegisterEvent("WORLD_MAP_UPDATE")
|
||||
pins.updateFrame:RegisterEvent("ZONE_CHANGED_NEW_AREA")
|
||||
pins.updateFrame:RegisterEvent("ZONE_CHANGED")
|
||||
pins.updateFrame:RegisterEvent("ZONE_CHANGED_INDOORS")
|
||||
pins.updateFrame:RegisterEvent("PLAYER_LOGIN")
|
||||
pins.updateFrame:RegisterEvent("PLAYER_ENTERING_WORLD")
|
||||
|
||||
-- Showing quest objectives does not trigger WORLD_MAP_UPDATE event
|
||||
hooksecurefunc("WorldMapFrame_DisplayQuests", UpdateWorldMap)
|
||||
|
||||
--- 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.MinimapGroup or 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 only on zone map (Questie modification)
|
||||
HBD_PINS_WORLDMAP_SHOW_CURRENT = -1
|
||||
-- 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
|
||||
|
||||
icon.icon = icon --LOL!
|
||||
icon:SetParent(WorldMapButton)
|
||||
HandleWorldMapPin(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
|
||||
|
||||
icon.icon = icon --LOL!
|
||||
icon:SetParent(WorldMapButton)
|
||||
HandleWorldMapPin(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
|
||||
icon:Hide()
|
||||
icon:ClearAllPoints()
|
||||
icon:SetParent(UiParent)
|
||||
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
|
||||
icon:Hide()
|
||||
icon:ClearAllPoints()
|
||||
icon:SetParent(UiParent)
|
||||
end
|
||||
wipe(worldmapPinRegistry[ref])
|
||||
end
|
||||
Reference in New Issue
Block a user