You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1457 lines
44 KiB
1457 lines
44 KiB
-- Original code and concept by Antiarc. Used and modified with his permission.
|
|
-- First adaptation in dbm credits to VEM team. Continued on their behalf do to no time from original author to make it an external mod or DBM plugin.
|
|
|
|
---@class DBM
|
|
local DBM = DBM
|
|
|
|
---@class DBMHudMap
|
|
local mod = {
|
|
Version = 2 -- That way external usage can querie hud api feature level of of users installed mod version
|
|
}
|
|
|
|
DBM.HudMap = mod
|
|
|
|
local wipe, type, pairs, ipairs, tinsert, tremove, tonumber, setmetatable, unpack = table.wipe, type, pairs, ipairs, table.insert, table.remove, tonumber, setmetatable, unpack
|
|
local abs, pow, sqrt, sin, cos, atan2, floor, ceil, min, max, pi2 = math.abs, math.pow, math.sqrt, math.sin, math.cos, math.atan2, math.floor, math.ceil, math.min, math.max, math.pi * 2
|
|
local error = error
|
|
|
|
local CallbackHandler = _G["LibStub"]:GetLibrary("CallbackHandler-1.0")
|
|
---@class DBMMHudMapUpdateFrame: Frame
|
|
local updateFrame = CreateFrame("Frame", "DBMHudMapUpdateFrame")
|
|
local fixedOnUpdateRate = 0.03
|
|
local onUpdate, Point, Edge
|
|
local callbacks = CallbackHandler:New(mod)
|
|
local activeMarkers = 0
|
|
local hudarActive = false
|
|
local playerName = UnitName("player")
|
|
local encounterMarkers = {}
|
|
|
|
local GetNumGroupMembers, IsInRaid = GetNumGroupMembers, IsInRaid
|
|
local GetTime, WorldFrame = GetTime, WorldFrame
|
|
local UnitExists, UnitIsUnit, UnitPosition, UnitIsConnected, GetPlayerFacing = UnitExists, UnitIsUnit, UnitPosition, UnitIsConnected, GetPlayerFacing
|
|
|
|
local RAID_CLASS_COLORS = _G["CUSTOM_CLASS_COLORS"] or RAID_CLASS_COLORS
|
|
|
|
-- TAXIROUTE_LINEFACTOR_2 global is removed in legion, but TAXIROUTE_LINEFACTOR still exists, so we create our own
|
|
local TAXIROUTE_LINEFACTOR_2 = TAXIROUTE_LINEFACTOR / 2
|
|
|
|
-- Hard code STANDARD_TEXT_FONT since skinning mods like to taint it (or worse, set it to nil, wtf?)
|
|
local standardFont
|
|
if LOCALE_koKR then
|
|
standardFont = "Fonts\\2002.TTF"
|
|
elseif LOCALE_zhCN then
|
|
standardFont = "Fonts\\ARKai_T.ttf"
|
|
elseif LOCALE_zhTW then
|
|
standardFont = "Fonts\\blei00d.TTF"
|
|
elseif LOCALE_ruRU then
|
|
standardFont = "Fonts\\FRIZQT___CYR.TTF"
|
|
else
|
|
standardFont = "Fonts\\FRIZQT__.TTF"
|
|
end
|
|
|
|
local targetCanvasAlpha, supressCanvas
|
|
|
|
local textureLookup = {
|
|
star = 137001, -- [[Interface\TARGETINGFRAME\UI-RaidTargetingIcon_1.blp]]
|
|
circle = 137002, -- [[Interface\TARGETINGFRAME\UI-RaidTargetingIcon_2.blp]]
|
|
diamond = 137003, -- [[Interface\TARGETINGFRAME\UI-RaidTargetingIcon_3.BLP]]
|
|
triangle = 137004, -- [[Interface\TARGETINGFRAME\UI-RaidTargetingIcon_4.blp]]
|
|
moon = 137005, -- [[Interface\TARGETINGFRAME\UI-RaidTargetingIcon_5.blp]]
|
|
square = 137006, -- [[Interface\TARGETINGFRAME\UI-RaidTargetingIcon_6.blp]]
|
|
cross = 137007, -- [[Interface\TARGETINGFRAME\UI-RaidTargetingIcon_7.blp]]
|
|
skull = 137008, -- [[Interface\TARGETINGFRAME\UI-RaidTargetingIcon_8.blp]]
|
|
cross2 = 136813, -- [[Interface\RAIDFRAME\ReadyCheck-NotReady.blp]]
|
|
check = 136814, -- [[Interface\RAIDFRAME\ReadyCheck-Ready.blp]]
|
|
question = 136815, -- [[Interface\RAIDFRAME\ReadyCheck-Waiting.blp]]
|
|
targeting = 136439, -- [[Interface\Minimap\Ping\ping5.blp]]
|
|
highlight = "Interface\\AddOns\\DBM-Core\\textures\\alert_circle",
|
|
timer = "Interface\\AddOns\\DBM-Core\\textures\\timer",
|
|
glow = 132039, -- [[Interface\GLUES\MODELS\UI_Tauren\gradientCircle]]
|
|
party = 249183, -- [[Interface\MINIMAP\PartyRaidBlips]]
|
|
ring = 165793, -- [[SPELLS\CIRCLE]]
|
|
rune1 = 165630, -- [[SPELLS\AURARUNE256.BLP]]
|
|
rune2 = 165637, -- [[SPELLS\AURARUNE9.BLP]]
|
|
rune3 = 165638, -- [[SPELLS\AURARUNE_A.BLP]]
|
|
rune4 = 165639, -- [[SPELLS\AURARUNE_B.BLP]]
|
|
odunblue = 1323035, -- [[Interface\Icons\Boss_OdunRunes_Blue.blp]]--Blue fishies
|
|
odungreen = 1323036, -- [[Interface\Icons\Boss_OdunRunes_Green.blp]]--Green cube
|
|
odunorange = 1323039, -- [[Interface\Icons\Boss_OdunRunes_Orange.blp]]--Orange N
|
|
odunpurple = 1323037, -- [[Interface\Icons\Boss_OdunRunes_Purple.blp]]--Purple K
|
|
odunyellow = 1323038, -- [[Interface\Icons\Boss_OdunRunes_Yellow.blp]]--Yellow H
|
|
astrored = 1391537, -- [[Interface\Icons\icon_7fx_nightborn_astromancer_red.blp]]--Wolf
|
|
astroyellow = 1391538, -- [[Interface\Icons\icon_7fx_nightborn_astromancer_yellow.blp]]--Crab
|
|
astroblue = 1391535, -- [[Interface\Icons\icon_7fx_nightborn_astromancer_blue.blp]]--Dragon
|
|
astrogreen = 1391536, -- [[Interface\Icons\icon_7fx_nightborn_astromancer_green.blp]]--Hunter
|
|
paw = 165558, -- [[SPELLS\Agility_128.blp]]
|
|
cyanstar = 165860, -- [[SPELLS\CYANSTARFLASH.BLP]]
|
|
summon = 165881, -- [[SPELLS\DarkSummon.blp]]
|
|
reticle = 166706, -- [[SPELLS\Reticle_128.blp]]
|
|
fuzzyring = 167208, -- [[SPELLS\WHITERINGTHIN128.BLP]]
|
|
fatring = 167207, -- [[SPELLS\WhiteRingFat128.blp]]
|
|
swords = 166984, -- [[SPELLS\Strength_128.blp]]
|
|
beam1 = 424588 -- [[Textures\SPELLCHAINEFFECTS\Beam_01]]
|
|
}
|
|
|
|
local textureKeys, textureVals = {}, {}
|
|
mod.textureKeys, mod.textureVals = textureKeys, textureVals
|
|
|
|
local texBlending = {
|
|
highlight = "ADD",
|
|
targeting = "ADD",
|
|
glow = "ADD",
|
|
ring = "ADD",
|
|
rune1 = "ADD",
|
|
rune2 = "ADD",
|
|
rune3 = "ADD",
|
|
rune4 = "ADD",
|
|
odunblue = "ADD",
|
|
odungreen = "ADD",
|
|
odunorange = "ADD",
|
|
odunpurple = "ADD",
|
|
odunyellow = "ADD",
|
|
astrored = "ADD",
|
|
astroyellow = "ADD",
|
|
astroblue = "ADD",
|
|
astrogreen = "ADD",
|
|
paw = "ADD",
|
|
reticle = "ADD",
|
|
cyanstar = "ADD",
|
|
summon = "ADD",
|
|
fuzzyring = "ADD",
|
|
fatring = "ADD",
|
|
swords = "ADD"
|
|
-- timer = "ADD",
|
|
}
|
|
|
|
local texCoordLookup = {
|
|
party = { 0.525, 0.6, 0.04, 0.2 },
|
|
tank = { 0.5, 0.75, 0, 1 },
|
|
dps = { 0.75, 1, 0, 1 },
|
|
healer = { 0.25, 0.5, 0, 1 },
|
|
paw = { 0.124, 0.876, 0.091, 0.903 },
|
|
rune4 = { 0.032, 0.959, 0.035, 0.959 },
|
|
reticle = { 0.05, 0.95, 0.05, 0.95 }
|
|
}
|
|
|
|
local frameScalars = {
|
|
rune1 = 0.86,
|
|
rune2 = 0.86,
|
|
rune3 = 0.77,
|
|
summon = 0.86,
|
|
}
|
|
|
|
local HUDEnabled = false
|
|
|
|
local canvas = CreateFrame("Frame", "DBMHudMapCanvas", WorldFrame)
|
|
canvas:SetSize(WorldFrame:GetWidth(), WorldFrame:GetHeight())
|
|
canvas:SetPoint("CENTER")
|
|
canvas:Hide()
|
|
|
|
local function UnregisterAllCallbacks(obj)
|
|
-- Cancel all registered callbacks. CBH doesn't seem to provide a method to do this.
|
|
if obj.callbacks.insertQueue then
|
|
for _, callbacks in pairs(obj.callbacks.insertQueue) do
|
|
for k, _ in pairs(callbacks) do
|
|
callbacks[k] = nil
|
|
end
|
|
end
|
|
end
|
|
for eventname, callbacks in pairs(obj.callbacks.events) do
|
|
for k, _ in pairs(callbacks) do
|
|
callbacks[k] = nil
|
|
end
|
|
if obj.callbacks.OnUnused then
|
|
obj.callbacks.OnUnused(obj.callbacks, obj, eventname) -- Make sure this doesn't error. :)
|
|
end
|
|
end
|
|
end
|
|
|
|
function mod:RegisterTexture(_, key, tex, blend, cx1, cx2, cy1, cy2, scalar)
|
|
if key then
|
|
textureLookup[key] = tex
|
|
if blend then
|
|
texBlending[key] = blend
|
|
end
|
|
if cx1 and cx2 and cy1 and cy2 then
|
|
texCoordLookup[key] = {cx1, cx2, cy1, cy2}
|
|
end
|
|
if scalar then
|
|
frameScalars[key] = scalar
|
|
end
|
|
end
|
|
wipe(textureKeys)
|
|
for k, _ in pairs(textureLookup) do
|
|
tinsert(textureKeys, k)
|
|
end
|
|
wipe(textureVals)
|
|
for _, v in pairs(textureLookup) do
|
|
textureVals[v] = v
|
|
end
|
|
end
|
|
mod:RegisterTexture()
|
|
|
|
function mod:UnitIsMappable(unit, allowSelf)
|
|
return (allowSelf and UnitIsUnit("player", unit)) or UnitPosition(unit) or UnitIsConnected(unit)
|
|
end
|
|
|
|
function mod:Free(e, owner, id, noAnimate)
|
|
if e and not e.freed then
|
|
if owner and id then
|
|
if e:Owned(owner, id) then
|
|
e:Free(noAnimate)
|
|
else
|
|
return e
|
|
end
|
|
else
|
|
e:Free()
|
|
end
|
|
end
|
|
end
|
|
|
|
local function groupIter(_, index)
|
|
if index < 0 then
|
|
return
|
|
end
|
|
local unit = (IsInRaid() and "raid" or "party") .. index
|
|
if UnitExists(unit) then
|
|
return index + 1, unit
|
|
elseif GetNumGroupMembers() == 0 then
|
|
return -1, "player"
|
|
end
|
|
end
|
|
|
|
local function group()
|
|
return groupIter, nil, 1
|
|
end
|
|
|
|
mod.group = group
|
|
|
|
local pointCache, edgeCache = {}, {}
|
|
local activePointList, activeEdgeList = {}, {}
|
|
|
|
local zoomScale, targetZoomScale, fixedZoomScale = 45, 40, nil
|
|
local lastPlayerX, lastPlayerY
|
|
|
|
do
|
|
local fine, coarse = 1 / 60, 3
|
|
local fineTotal, coarseTotal = 0, 0
|
|
local zoomDelay, fadeInDelay, fadeOutDelay = 0.5, 0.25, 0.5
|
|
|
|
local function computeNewScale()
|
|
if fixedZoomScale then
|
|
return fixedZoomScale
|
|
end
|
|
local px, py = mod:GetUnitPosition("player")
|
|
lastPlayerX, lastPlayerY = px, py
|
|
local maxDistance = 0
|
|
for point, _ in pairs(activePointList) do
|
|
local d = point:Distance(px, py, true)
|
|
|
|
if d > 0 and d < 200 and d > maxDistance then
|
|
maxDistance = d
|
|
end
|
|
end
|
|
if maxDistance < 20 then
|
|
maxDistance = 20
|
|
end
|
|
return maxDistance
|
|
end
|
|
|
|
function onUpdate(_, t)
|
|
fineTotal = fineTotal + t
|
|
coarseTotal = coarseTotal + t
|
|
if coarseTotal > coarse then
|
|
coarseTotal = coarseTotal % coarse
|
|
end
|
|
if fineTotal > fine then
|
|
local steps = floor(fineTotal / fine)
|
|
local elapsed = fine * steps
|
|
fineTotal = fineTotal - elapsed
|
|
targetZoomScale = computeNewScale()
|
|
local currentAlpha = canvas:GetAlpha()
|
|
if not supressCanvas and targetCanvasAlpha and currentAlpha ~= targetCanvasAlpha then
|
|
local newAlpha
|
|
if targetCanvasAlpha > currentAlpha then
|
|
newAlpha = min(targetCanvasAlpha, currentAlpha + 1 * elapsed / fadeInDelay)
|
|
else
|
|
newAlpha = max(targetCanvasAlpha, currentAlpha - 1 * elapsed / fadeOutDelay)
|
|
end
|
|
if newAlpha == 0 and targetCanvasAlpha then
|
|
canvas:Hide()
|
|
end
|
|
canvas:SetAlpha(newAlpha)
|
|
elseif targetCanvasAlpha == 0 and currentAlpha == 0 then
|
|
canvas:Hide()
|
|
end
|
|
if zoomScale < targetZoomScale then
|
|
zoomScale = min(targetZoomScale, zoomScale + ceil((targetZoomScale - zoomScale) * elapsed / zoomDelay))
|
|
elseif zoomScale > targetZoomScale then
|
|
zoomScale = max(targetZoomScale, zoomScale - ceil((zoomScale - targetZoomScale) * elapsed / zoomDelay))
|
|
end
|
|
mod:Update()
|
|
callbacks:Fire("Update", mod)
|
|
end
|
|
end
|
|
end
|
|
|
|
function mod:Enable()
|
|
if DBM.Options.DontShowHudMap2 or HUDEnabled or DBM:HasMapRestrictions() then
|
|
return
|
|
end
|
|
DBM:Debug("HudMap Activating", 2)
|
|
if not supressCanvas then
|
|
canvas:Show()
|
|
end
|
|
canvas:SetAlpha(1)
|
|
self:UpdateCanvasPosition()
|
|
targetZoomScale = 6
|
|
self.pixelsPerYard = WorldFrame:GetHeight() / self:GetMinimapSize()
|
|
self:SetZoom()
|
|
HUDEnabled = true
|
|
updateFrame:Show()
|
|
if not updateFrame.ticker then
|
|
updateFrame.ticker = C_Timer.NewTicker(fixedOnUpdateRate, function()
|
|
onUpdate(updateFrame, fixedOnUpdateRate)
|
|
end)
|
|
end
|
|
end
|
|
|
|
function mod:Disable()
|
|
if not HUDEnabled then
|
|
return
|
|
end
|
|
DBM:Debug("HudMap Deactivating", 2)
|
|
self:FreeEncounterMarkers()
|
|
Edge:ClearAll()
|
|
if hudarActive then -- Don't disable if hudar is open
|
|
return
|
|
end
|
|
canvas:Hide()
|
|
updateFrame:Hide()
|
|
HUDEnabled = false
|
|
if updateFrame.ticker then
|
|
updateFrame.ticker:Cancel()
|
|
updateFrame.ticker = nil
|
|
end
|
|
end
|
|
|
|
function mod:ToggleHudar(hide)
|
|
if hudarActive or hide then
|
|
hudarActive = false
|
|
self:FreeEncounterMarkerByTarget(143430, playerName)
|
|
else
|
|
hudarActive = true
|
|
self:RegisterRangeMarkerOnPartyMember(143430, "timer", playerName, 1.5, nil, 0, 1, 0, 0.3):Appear():RegisterForAlerts("all"):Rotate(360, 9.5)
|
|
end
|
|
end
|
|
|
|
function mod:PointExists(id)
|
|
for k, _ in pairs(activePointList) do
|
|
if k.id == id then
|
|
return true
|
|
end
|
|
end
|
|
return false
|
|
end
|
|
|
|
function mod:UpdateCanvasPosition()
|
|
canvas:ClearAllPoints()
|
|
canvas:SetPoint("CENTER", WorldFrame, "CENTER")
|
|
canvas:SetSize((WorldFrame:GetHeight() * 0.48) * 2, (WorldFrame:GetHeight() * 0.48) * 2)
|
|
end
|
|
|
|
-----------------------------------
|
|
--- Points
|
|
-----------------------------------
|
|
mod.textures = textureLookup
|
|
|
|
local animations = {
|
|
onLoad = function(self)
|
|
self.regionParent = self:GetRegionParent()
|
|
end,
|
|
scale = function(self)
|
|
local p = self:GetProgress()
|
|
local progress = self:GetParent():GetLoopState() == "REVERSE" and (1 - p) or p
|
|
if progress < 0 then
|
|
progress = 0
|
|
elseif progress > 1
|
|
then progress = 1
|
|
end
|
|
self.regionParent:SetScale(1 + ((self.pulseTarget - 1) * progress))
|
|
end,
|
|
alpha = function(self)
|
|
self.regionParent:SetAlpha(self:GetProgress())
|
|
end,
|
|
fullOpacity = function(self)
|
|
self.regionParent:SetAlpha(1)
|
|
end,
|
|
scaleIn = function(self)
|
|
self.regionParent:SetScale(1 + ((1 - self:GetProgress()) * 0.5))
|
|
end,
|
|
hideParent = function(self)
|
|
self:GetRegionParent():Hide()
|
|
end,
|
|
replay = function(self)
|
|
self:Play()
|
|
end
|
|
}
|
|
|
|
local function DrawRouteLineCustom(T, C, sx, sy, ex, ey, w, relPoint)
|
|
if not relPoint then
|
|
relPoint = "BOTTOMLEFT"
|
|
end
|
|
-- Determine dimensions and center point of line
|
|
local dx, dy = ex - sx, ey - sy
|
|
local cx, cy = (sx + ex) / 2, (sy + ey) / 2
|
|
-- Normalize direction if necessary
|
|
local reverse = dx < 0 and -1 or 1
|
|
if dx < 0 then
|
|
dx, dy = -dx, -dy
|
|
end
|
|
-- Calculate actual length of line
|
|
local l = sqrt((dx * dx) + (dy * dy))
|
|
-- Quick escape if it's zero length
|
|
if l == 0 then
|
|
T:SetTexCoord(0, 0, 0, 0, 0, 0, 0, 0)
|
|
T:SetPoint("BOTTOMLEFT", C, relPoint, cx, cy)
|
|
T:SetPoint("TOPRIGHT", C, relPoint, cx, cy)
|
|
return
|
|
end
|
|
-- Sin and Cosine of rotation, and combination (for later)
|
|
local s, c = -dy / l, dx / l
|
|
local sc = s * c
|
|
-- Calculate bounding box size and texture coordinates
|
|
local Bwid, Bhgt, BLx, BLy, TLx, TLy, TRx, TRy, BRx, BRy
|
|
if dy >= 0 then
|
|
Bwid = ((l * c) - (w * s)) * TAXIROUTE_LINEFACTOR_2
|
|
Bhgt = ((w * c) - (l * s)) * TAXIROUTE_LINEFACTOR_2
|
|
BLx, BLy, BRy = (w / l) * sc, s * s, (l / w) * sc
|
|
BRx, TLx, TLy, TRx = 1 - BLy, BLy, 1 - BRy, 1 - BLx
|
|
TRy = BRx
|
|
else
|
|
Bwid = ((l * c) + (w * s)) * TAXIROUTE_LINEFACTOR_2
|
|
Bhgt = ((w * c) + (l * s)) * TAXIROUTE_LINEFACTOR_2
|
|
BLx, BLy, BRx = s * s, -(l / w) * sc, 1 + (w / l) * sc
|
|
BRy, TLx, TLy, TRy = BLx, 1 - BRx, 1 - BLx, 1 - BLy
|
|
TRx = TLy
|
|
end
|
|
Bwid = Bwid * reverse
|
|
Bhgt = Bhgt * reverse
|
|
T:ClearAllPoints()
|
|
-- Hack to fix backwards arrow since it's easier to fix here than figure out wtf is going on up above
|
|
if reverse == 1 then
|
|
T:SetTexCoord(TLx, TLy, BLx, BLy, TRx, TRy, BRx, BRy)
|
|
else
|
|
T:SetTexCoord(BRx, BRy, TRx, TRy, BLx, BLy, TLx, TLy)
|
|
end
|
|
T:SetPoint("BOTTOMLEFT", C, relPoint, cx - Bwid, cy - Bhgt)
|
|
T:SetPoint("TOPRIGHT", C, relPoint, cx + Bwid, cy + Bhgt)
|
|
end
|
|
|
|
local animationNames = { "fadeOutGroup", "fadeOut", "repeatAnimations", "pulseAnimations", "pulse", "rotate", "fadeInGroup" }
|
|
local Object = {
|
|
Serial = function(self, prefix)
|
|
self.serials = self.serials or {}
|
|
self.serials[prefix] = (self.serials[prefix] or 0) + 1
|
|
return prefix .. self.serials[prefix]
|
|
end,
|
|
OnAcquire = function(self)
|
|
if self.freed == false then
|
|
error("ERROR: Attempted to reallocate a freed object.")
|
|
end
|
|
self.radiusClipOffset = nil
|
|
self.fixedClipOffset = nil
|
|
self.ownerModule = nil
|
|
self.id = nil
|
|
self.freed = false
|
|
self.frame:Show()
|
|
self.frame:SetAlpha(1)
|
|
self.frame:StopAnimating()
|
|
for _, anim in ipairs(animationNames) do
|
|
if self[anim] then self[anim]:Stop() end
|
|
end
|
|
end,
|
|
OnFree = function(self, noAnimate)
|
|
if self.freed then
|
|
return false
|
|
end
|
|
self.freed = true
|
|
self.callbacks:Fire("Free", self)
|
|
UnregisterAllCallbacks(self)
|
|
self:Hide(noAnimate)
|
|
end,
|
|
ParseSize = function(self, size)
|
|
local yards, fixed
|
|
if type(size) == "string" then
|
|
local t = size:match("(%d+)px")
|
|
if t then
|
|
fixed = tonumber(t)
|
|
else
|
|
t = size:match("(%d+)yd")
|
|
if t then
|
|
yards = tonumber(t)
|
|
end
|
|
end
|
|
else
|
|
yards = size
|
|
end
|
|
return yards, fixed
|
|
end,
|
|
SetClipOffset = function(self, offset)
|
|
self.radiusClipOffset, self.fixedClipOffset = self:ParseSize(offset)
|
|
return self
|
|
end,
|
|
Identify = function(self, ownerModule, id)
|
|
self.ownerModule = ownerModule
|
|
self.id = id
|
|
return self
|
|
end,
|
|
Owned = function(self, ownerModule, id)
|
|
return not self.freed and ownerModule == self.ownerModule and id == self.id
|
|
end,
|
|
Show = function() end,
|
|
Hide = function(self, noAnimate)
|
|
if noAnimate then
|
|
self.frame:Hide()
|
|
self.frame:StopAnimating()
|
|
else
|
|
self.fadeOutGroup:Play()
|
|
end
|
|
end
|
|
}
|
|
|
|
local object_mt = {
|
|
__index = Object
|
|
}
|
|
local edge_mt, point_mt = {}, {}
|
|
|
|
Edge = setmetatable({
|
|
Free = function(self, noAnimate)
|
|
if self:OnFree(noAnimate) == false then
|
|
return
|
|
end
|
|
for point, _ in pairs(self.points) do
|
|
point:DetachEdge(self)
|
|
end
|
|
wipe(self.points)
|
|
self.srcPlayer, self.dstPlayer, self.sx, self.sy, self.dx, self.dy = nil, nil, nil, nil, nil, nil
|
|
activeEdgeList[self] = nil
|
|
tinsert(edgeCache, self)
|
|
activeMarkers = activeMarkers - 1
|
|
if activeMarkers == 0 then
|
|
mod:Disable()
|
|
end
|
|
end,
|
|
New = function(self, r, g, b, a, srcPlayer, dstPlayer, sx, sy, dx, dy, lifetime, texfile, w, extend)
|
|
local t = tremove(edgeCache)
|
|
if not t then
|
|
t = setmetatable({}, edge_mt)
|
|
t.points = {}
|
|
t.serial = self:Serial("Edge")
|
|
t.callbacks = CallbackHandler:New(t)
|
|
t.frame = CreateFrame("Frame", nil, canvas)
|
|
t.frame:SetFrameStrata("LOW")
|
|
t.texture = t.frame:CreateTexture()
|
|
t.texture:SetAllPoints()
|
|
t.texture:SetTexture(textureLookup[texfile] or texfile or "Interface\\AddOns\\DBM-Core\\textures\\line")
|
|
t.fadeOutGroup = t.frame:CreateAnimationGroup()
|
|
|
|
t.fadeOut = t.fadeOutGroup:CreateAnimation("alpha")
|
|
t.fadeOut:SetFromAlpha(1)
|
|
t.fadeOut:SetToAlpha(0)
|
|
t.fadeOut:SetDuration(0.25)
|
|
t.fadeOut:SetScript("OnFinished", animations.hideParent)
|
|
end
|
|
t:OnAcquire()
|
|
t.srcPoint = nil
|
|
t.dstPoint = nil
|
|
|
|
t.lifetime = type(lifetime) == "number" and GetTime() + lifetime or nil
|
|
t:SetColor(r, g, b, a)
|
|
t.srcPlayer, t.dstPlayer = srcPlayer, dstPlayer
|
|
t.sx, t.sy, t.dx, t.dy, t.w, t.extend = sx, sy, dx, dy, w, extend
|
|
activeEdgeList[t] = true
|
|
activeMarkers = activeMarkers + 1
|
|
return t
|
|
end,
|
|
SetColor = function(self, r, g, b, a)
|
|
self.r = r or 1
|
|
self.g = g or 1
|
|
self.b = b or 1
|
|
self.a = a or 1
|
|
self.texture:SetVertexColor(r, g, b, a)
|
|
end,
|
|
AttachPoint = function(self, point)
|
|
self.points[point] = true
|
|
end,
|
|
DetachPoint = function(self, point)
|
|
self.points[point] = nil
|
|
end,
|
|
TrackFrom = function(self, src_or_x, y)
|
|
if type(src_or_x) == "string" then
|
|
self.srcPlayer = src_or_x
|
|
elseif type(src_or_x) == "table" then
|
|
self.srcPoint = src_or_x
|
|
elseif src_or_x and y then
|
|
self.srcPlayer = nil
|
|
self.sx = src_or_x
|
|
self.sy = y
|
|
end
|
|
return self
|
|
end,
|
|
TrackTo = function(self, dst_or_x, y)
|
|
if type(dst_or_x) == "string" then
|
|
self.dstPlayer = dst_or_x
|
|
elseif type(dst_or_x) == "table" then
|
|
self.dstPoint = dst_or_x
|
|
elseif dst_or_x and y then
|
|
self.dstPlayer = nil
|
|
self.dx = dst_or_x
|
|
self.dy = y
|
|
end
|
|
return self
|
|
end,
|
|
ClearAll = function(self)
|
|
for t, _ in pairs(activeEdgeList) do
|
|
t:Free()
|
|
end
|
|
end,
|
|
UpdateAll = function(self)
|
|
if self ~= Edge then
|
|
return
|
|
end
|
|
for t, _ in pairs(activeEdgeList) do
|
|
t:Update()
|
|
end
|
|
end,
|
|
Update = function(self)
|
|
if self.lifetime and GetTime() > self.lifetime then
|
|
self:Free()
|
|
return
|
|
end
|
|
local sx, sy, dx, dy
|
|
if self.srcPlayer then
|
|
sx, sy = mod:GetUnitPosition(self.srcPlayer)
|
|
elseif self.srcPoint then
|
|
sx, sy = self.srcPoint:Location()
|
|
elseif self.sx and self.sy then
|
|
sx, sy = self.sx, self.sy
|
|
end
|
|
if self.dstPlayer then
|
|
if self.extend then
|
|
local destx, desty = mod:GetUnitPosition(self.dstPlayer)
|
|
local extendValue = zoomScale - mod:DistanceBetweenPoints(destx, desty, lastPlayerX, lastPlayerY)
|
|
if extendValue > 0 then
|
|
dx, dy = self:Extend(sx, sy, destx, desty, extendValue)
|
|
else
|
|
dx, dy = destx, desty
|
|
end
|
|
else
|
|
dx, dy = mod:GetUnitPosition(self.dstPlayer)
|
|
end
|
|
elseif self.dstPoint then
|
|
dx, dy = self.dstPoint:Location()
|
|
elseif self.dx and self.dy then
|
|
dx, dy = self.dx, self.dy
|
|
end
|
|
local visible
|
|
if sx and sy and dx and dy then
|
|
local px, py = mod:GetUnitPosition("player")
|
|
local radius = zoomScale * zoomScale
|
|
visible = pow(px - sx, 2) + pow(py - sy, 2) < radius or pow(px - dx, 2) + pow(py - dy, 2) < radius
|
|
sx, sy = mod:LocationToMinimapOffset(sx, sy, true, self.radiusClipOffset, self.fixedClipOffset)
|
|
dx, dy = mod:LocationToMinimapOffset(dx, dy, true, self.radiusClipOffset, self.fixedClipOffset)
|
|
end
|
|
if visible then
|
|
local ox = canvas:GetWidth() / 2
|
|
local oy = canvas:GetHeight() / 2
|
|
sx = sx + ox
|
|
dx = dx + ox
|
|
sy = sy + oy
|
|
dy = dy + oy
|
|
local ax = dx - sx
|
|
local ay = dy - sy
|
|
if pow((ax * ax) + (ay * ay), 0.5) > 15 then
|
|
self.texture:Show()
|
|
DrawRouteLineCustom(self.texture, canvas, sx, sy, dx, dy, self.w or 100, self.extend)
|
|
else
|
|
self.texture:Hide()
|
|
end
|
|
end
|
|
end,
|
|
Extend = function(self, sx, sy, dx, dy, dist)
|
|
local cx = dx - sx
|
|
local cy = dy - sy
|
|
local len = sqrt(cx * cx + cy * cy)
|
|
return ((cx / len) * dist) + dx, ((cy / len) * dist) + dy
|
|
end,
|
|
}, object_mt)
|
|
|
|
function mod:AddEdge(r, g, b, a, lifetime, srcPlayer, dstPlayer, sx, sy, dx, dy, w, texfile, extend)
|
|
if DBM.Options.DontShowHudMap2 then
|
|
return
|
|
end
|
|
if not HUDEnabled then
|
|
self:Enable()
|
|
end
|
|
return Edge:New(r, g, b, a, srcPlayer, dstPlayer, sx, sy, dx, dy, lifetime, texfile, w, extend)
|
|
end
|
|
|
|
function mod:ClearAllEdges()
|
|
Edge:ClearAll()
|
|
end
|
|
|
|
do
|
|
Point = setmetatable({
|
|
Free = function(self, noAnimate)
|
|
if self:OnFree(noAnimate) == false then
|
|
return
|
|
end
|
|
for edge, _ in pairs(self.edges) do
|
|
edge:Free()
|
|
end
|
|
wipe(self.edges)
|
|
self.stickX = nil
|
|
self.stickY = nil
|
|
self.follow = nil
|
|
self.lifetime = nil
|
|
self.lastPPY = nil
|
|
self.lastRadius = nil
|
|
activePointList[self] = nil
|
|
tinsert(pointCache, self)
|
|
end,
|
|
AttachEdge = function(self, edge)
|
|
self.edges[edge] = true
|
|
edge:AttachPoint(self)
|
|
end,
|
|
DetachEdge = function(self, edge)
|
|
self.edges[edge] = nil
|
|
edge:DetachPoint(self)
|
|
end,
|
|
Stick = function(self, map, x, y)
|
|
self.follow = nil
|
|
self.map = map
|
|
self.stickX = x
|
|
self.stickY = y
|
|
return self
|
|
end,
|
|
Follow = function(self, unit)
|
|
self.stickX = nil
|
|
self.stickY = nil
|
|
self.follow = unit
|
|
return self
|
|
end,
|
|
Location = function(self)
|
|
if self.stickX then
|
|
return self.stickX, self.stickY
|
|
elseif self.follow then
|
|
return mod:GetUnitPosition(self.follow)
|
|
end
|
|
end,
|
|
Update = function(self)
|
|
if (self.map and DBM:GetCurrentArea() ~= self.map and not self.persist) or (not self.lifetime or self.lifetime > 0 and self.lifetime < GetTime()) then
|
|
self:Free()
|
|
return
|
|
end
|
|
local x, y
|
|
self.callbacks:Fire("Update", self)
|
|
if not self.alwaysShow then
|
|
local distance
|
|
local px, py = mod:GetUnitPosition("player")
|
|
if px and py then
|
|
distance, x, y = self:Distance(px, py, true)
|
|
if distance > 200 then
|
|
self:Hide()
|
|
return
|
|
end
|
|
end
|
|
else
|
|
x, y = self:Location()
|
|
end
|
|
if not x or not y or (x == 0 and y == 0) then
|
|
self:Free()
|
|
return
|
|
elseif not self.frame:IsVisible() then
|
|
self.frame:Show()
|
|
self.fadeIn:Play()
|
|
end
|
|
x, y = mod:LocationToMinimapOffset(x, y, self.alwaysShow, self.radiusClipOffset or self.radius, self.fixedClipOffset or self.fixedSize)
|
|
local needUpdate
|
|
if self.follow == "player" then
|
|
needUpdate = not self.placed
|
|
else
|
|
needUpdate = self.lastX ~= x or self.lastY ~= y
|
|
end
|
|
self:UpdateSize()
|
|
if needUpdate then
|
|
self.frame:ClearAllPoints()
|
|
self.frame:SetPoint("CENTER", self.frame:GetParent(), "CENTER", x, y)
|
|
end
|
|
self.placed = true
|
|
self.lastX = x
|
|
self.lastY = y
|
|
if self.shouldUpdateRange then
|
|
self:UpdateAlerts()
|
|
end
|
|
end,
|
|
UpdateSize = function(self)
|
|
if self.radius then
|
|
if self.lastPPY ~= mod.pixelsPerYard or self.lastRadius ~= self.radius then
|
|
self.lastPPY = mod.pixelsPerYard
|
|
self.lastRadius = self.radius
|
|
local pixels = mod:RangeToPixels((self.radius / (frameScalars[self.texfile] or 1)) * 2)
|
|
self.frame:SetSize(pixels, pixels)
|
|
end
|
|
elseif self.fixedSize then
|
|
self.frame:SetSize(self.fixedSize, self.fixedSize)
|
|
end
|
|
end,
|
|
UpdateAll = function(self)
|
|
if self ~= Point then
|
|
return
|
|
end
|
|
for t, _ in pairs(activePointList) do
|
|
t:Update()
|
|
end
|
|
end,
|
|
Pulse = function(self, size, speed)
|
|
self.pulseSize = size
|
|
self.pulseSpeed = speed
|
|
self.pulse:SetDuration(speed)
|
|
self.pulse:SetScale(size, size)
|
|
self.pulseIn:SetDuration(speed)
|
|
self.pulseIn:SetScale(1 / size, 1 / size)
|
|
self.pulseAnimations:Play()
|
|
return self
|
|
end,
|
|
Rotate = function(self, amount, speed)
|
|
self.rotateAmount = amount
|
|
self.rotateSpeed = speed
|
|
speed = speed * (360 / amount)
|
|
amount = -360
|
|
if speed < 0 then
|
|
speed = speed * -1
|
|
amount = 360
|
|
end
|
|
self.rotate:SetDuration(speed)
|
|
self.rotate:SetDegrees(amount)
|
|
self.repeatAnimations:Play()
|
|
return self
|
|
end,
|
|
Appear = function(self)
|
|
self.fadeInGroup:Play()
|
|
return self
|
|
end,
|
|
SetTexCoords = function(self, a, b, c, d)
|
|
self.texture:SetTexCoord(a, b, c, d)
|
|
return self
|
|
end,
|
|
Alert = function(self, bool)
|
|
self.texture:SetVertexColor(
|
|
bool and self.alert.r or self.normal.r or 1,
|
|
bool and self.alert.g or self.normal.g or 1,
|
|
bool and self.alert.b or self.normal.b or 1,
|
|
bool and self.alert.a or self.normal.a or 1
|
|
)
|
|
if bool then
|
|
self:SetLabel(self.alertLabel, nil, nil, nil, nil, nil, 0.8)
|
|
end
|
|
return self
|
|
end,
|
|
RegisterForAlerts = function(self, bool, alertLabel)
|
|
self.alertLabel = alertLabel
|
|
self.shouldUpdateRange = bool == nil and true or bool
|
|
return self
|
|
end,
|
|
Distance = function(self, x2, y2, includeRadius)
|
|
local x, y = self:Location()
|
|
if not x or not y or (x == 0 and y == 0) then
|
|
return -1
|
|
end
|
|
local e = x2 - x
|
|
local f = y2 - y
|
|
return sqrt((e * e)+ (f * f)) + (includeRadius and self.radius or 0), x, y
|
|
end,
|
|
Persist = function(self, bool)
|
|
self.persist = bool == nil and true or bool
|
|
return self
|
|
end,
|
|
AlwaysShow = function(self, bool)
|
|
self.alwaysShow = bool == nil and true or bool
|
|
return self
|
|
end,
|
|
UpdateAlerts = function(self)
|
|
if not self.radius then
|
|
return
|
|
end
|
|
local x, y = self:Location()
|
|
local alert = false
|
|
if type(self.shouldUpdateRange) == "string" and self.shouldUpdateRange ~= "all" then -- Spellname passed, debuff filter
|
|
if not DBM:UnitDebuff("player", self.shouldUpdateRange) then -- Debuff faded from player, auto switch to "all" type
|
|
self.shouldUpdateRange = true
|
|
self:UpdateAlerts(self)
|
|
return
|
|
end
|
|
for _, unit in group() do
|
|
if not DBM:UnitDebuff(unit, self.shouldUpdateRange) and not UnitIsDead(unit) then
|
|
alert = mod:DistanceToPoint(unit, x, y) < self.radius
|
|
if alert then
|
|
break
|
|
end
|
|
end
|
|
end
|
|
elseif self.shouldUpdateRange == "all" or (self.follow and UnitIsUnit(self.follow, "player")) then
|
|
for _, unit in group() do
|
|
if not UnitIsUnit(unit, "player") and not UnitIsDead(unit) then
|
|
alert = mod:DistanceToPoint(unit, x, y) < self.radius
|
|
if alert then
|
|
break
|
|
end
|
|
end
|
|
end
|
|
else
|
|
alert = mod:DistanceToPoint("player", x, y) < self.radius
|
|
end
|
|
self:Alert(alert)
|
|
end,
|
|
SetColor = function(self, r, g, b, a)
|
|
self.normal.r = r or 1
|
|
self.normal.g = g or 1
|
|
self.normal.b = b or 1
|
|
self.normal.a = a or 0.5
|
|
self:Alert(false)
|
|
return self
|
|
end,
|
|
SetAlertColor = function(self, r, g, b, a)
|
|
self.alert.r = r or 1
|
|
self.alert.g = g or 0
|
|
self.alert.b = b or 0
|
|
self.alert.a = a or 0.5
|
|
return self
|
|
end,
|
|
SetTexture = function(self, texfile, blend)
|
|
local tex = self.texture
|
|
texfile = texfile or "glow"
|
|
tex:SetTexture(textureLookup[texfile] or texfile or 132039) -- [[Interface\GLUES\MODELS\UI_Tauren\gradientCircle]]
|
|
if texCoordLookup[texfile] then
|
|
tex:SetTexCoord(unpack(texCoordLookup[texfile]))
|
|
else
|
|
tex:SetTexCoord(0, 1, 0, 1)
|
|
end
|
|
blend = blend or texBlending[texfile] or "BLEND"
|
|
tex:SetBlendMode(blend)
|
|
return self
|
|
end,
|
|
SetLabel = function(self, text, anchorFrom, anchorTo, r, g, b, a, xOff, yOff, fontSize, outline)
|
|
self.text.anchorFrom = anchorFrom or self.text.anchorFrom
|
|
self.text.anchorTo = anchorTo or self.text.anchorTo
|
|
self.text:ClearAllPoints()
|
|
if not r and text then
|
|
local _, cls = UnitClass(text)
|
|
if cls and RAID_CLASS_COLORS[cls] then
|
|
r, g, b = RAID_CLASS_COLORS[cls].r, RAID_CLASS_COLORS[cls].g, RAID_CLASS_COLORS[cls].b
|
|
text = DBM:GetShortServerName(text)
|
|
end
|
|
end
|
|
self.text.r = r or self.text.r
|
|
self.text.g = g or self.text.g
|
|
self.text.b = b or self.text.b
|
|
self.text.a = a or self.text.a
|
|
self.text.xOff = xOff or self.text.xOff or 0
|
|
self.text.yOff = yOff or self.text.yOff or 0
|
|
if not text or text == "" then
|
|
self.text:SetText(nil)
|
|
self.text:Hide()
|
|
else
|
|
self.text:SetPoint(self.text.anchorFrom, self.frame, self.text.anchorTo, self.text.xOff, self.text.yOff)
|
|
self.text:SetTextColor(self.text.r, self.text.g, self.text.b, self.text.a)
|
|
self.text:Show()
|
|
local f, s, m = self.text:GetFont()
|
|
local font = f or standardFont
|
|
local size = fontSize or s or 20
|
|
outline = outline or m or "THICKOUTLINE"
|
|
self.text:SetFont(font, size, outline)
|
|
self.text:SetText(text)
|
|
end
|
|
self.labelData = self.labelData or {}
|
|
wipe(self.labelData)
|
|
self.labelData.text = text
|
|
self.labelData.anchorFrom = anchorFrom
|
|
self.labelData.anchorTo = anchorTo
|
|
self.labelData.r = r
|
|
self.labelData.g = g
|
|
self.labelData.b = b
|
|
self.labelData.a = a
|
|
self.labelData.xOff = xOff
|
|
self.labelData.yOff = yOff
|
|
self.labelData.fontSize = fontSize
|
|
self.labelData.outline = outline
|
|
return self
|
|
end,
|
|
SetSize = function(self, size)
|
|
self.lastRadius = nil
|
|
self.size = size
|
|
self.radius, self.fixedSize = self:ParseSize(size)
|
|
if not self.radius and not self.fixedSize then
|
|
self.fixedSize = 20
|
|
end
|
|
self:UpdateSize()
|
|
return self
|
|
end,
|
|
EdgeFrom = function(self, point_or_unit_or_x, to_y, lifetime, r, g, b, a, w, texfile, extend)
|
|
local fromPlayer = self.follow
|
|
local unit, x, y
|
|
if type(point_or_unit_or_x) == "table" then
|
|
unit = point_or_unit_or_x.follow
|
|
x = point_or_unit_or_x.stickX
|
|
y = point_or_unit_or_x.stickY
|
|
else
|
|
unit = to_y == nil and point_or_unit_or_x
|
|
x = to_y ~= nil and point_or_unit_or_x
|
|
y = to_y
|
|
end
|
|
local edge = Edge:New(r, g, b, a, fromPlayer, unit, self.stickX, self.stickY, x, y, lifetime, texfile, w, extend)
|
|
self:AttachEdge(edge)
|
|
if type(point_or_unit_or_x) == "table" then
|
|
point_or_unit_or_x:AttachEdge(edge)
|
|
edge:SetClipOffset(point_or_unit_or_x.fixedSize and point_or_unit_or_x.fixedSize .. "px" or point_or_unit_or_x.radius)
|
|
else
|
|
edge:SetClipOffset(self.fixedSize and self.fixedSize .. "px" or self.radius)
|
|
end
|
|
return edge
|
|
end,
|
|
EdgeTo = function(self, point_or_unit_or_x, from_y, lifetime, r, g, b, a, w, texfile, extend)
|
|
local toPlayer = self.follow
|
|
local unit, x, y
|
|
if type(point_or_unit_or_x) == "table" then
|
|
unit = point_or_unit_or_x.follow
|
|
x = point_or_unit_or_x.stickX
|
|
y = point_or_unit_or_x.stickY
|
|
else
|
|
unit = from_y == nil and point_or_unit_or_x
|
|
x = from_y ~= nil and point_or_unit_or_x
|
|
y = from_y
|
|
end
|
|
local edge = Edge:New(r, g, b, a, unit, toPlayer, x, y, self.stickX, self.stickY, lifetime, texfile, w, extend)
|
|
self:AttachEdge(edge)
|
|
if type(point_or_unit_or_x) == "table" then
|
|
point_or_unit_or_x:AttachEdge(edge)
|
|
end
|
|
edge:SetClipOffset(self.fixedSize and self.fixedSize .. "px" or self.radius)
|
|
return edge
|
|
end,
|
|
Broadcast = function(self)
|
|
local data = self.sendData or {}
|
|
wipe(data)
|
|
data.map = self.map
|
|
data.x, data.y = self:Location()
|
|
data.lifetime = self.baseLifetime
|
|
data.texfile = self.texfile
|
|
data.size = self.size
|
|
data.blend = self.blend
|
|
data.r = self.normal.r
|
|
data.g = self.normal.g
|
|
data.b = self.normal.b
|
|
data.a = self.normal.a
|
|
data.ar = self.alert.r
|
|
data.ag = self.alert.g
|
|
data.ab = self.alert.b
|
|
data.aa = self.alert.a
|
|
data.id = self.id
|
|
data.pulseSize = self.pulseSize
|
|
data.pulseSpeed = self.pulseSpeed
|
|
data.rotateAmount = self.rotateAmount
|
|
data.rotateSpeed = self.rotateSpeed
|
|
data.alertLabel = self.alertLabel
|
|
data.shouldUpdateRange = self.shouldUpdateRange
|
|
end,
|
|
New = function(self, map, x, y, follow, lifetime, texfile, size, blend, r, g, b, a)
|
|
local t = tremove(pointCache)
|
|
if not t then
|
|
t = setmetatable({}, point_mt)
|
|
t.serial = self:Serial("Circle")
|
|
t.callbacks = CallbackHandler:New(t)
|
|
t.frame = CreateFrame("Frame", nil, canvas)
|
|
t.frame:SetFrameStrata("LOW")
|
|
t.frame.owner = t ---@diagnostic disable-line: inject-field
|
|
t.text = t.frame:CreateFontString()
|
|
t.text:SetFont(standardFont, 10)
|
|
t.text:SetDrawLayer("OVERLAY")
|
|
t.text:SetPoint("BOTTOM", t.frame, "CENTER")
|
|
t.edges = {}
|
|
t.texture = t.frame:CreateTexture()
|
|
t.texture:SetAllPoints()
|
|
t.repeatAnimations = t.frame:CreateAnimationGroup()
|
|
t.repeatAnimations:SetLooping("REPEAT")
|
|
t.pulseAnimations = t.frame:CreateAnimationGroup()
|
|
t.pulseAnimations:SetScript("OnFinished", animations.replay)
|
|
t.pulse = t.pulseAnimations:CreateAnimation("scale")
|
|
t.pulse:SetOrder(1)
|
|
t.pulseIn = t.pulseAnimations:CreateAnimation("scale")
|
|
t.pulseIn:SetOrder(2)
|
|
t.pulse:SetScript("OnPlay", animations.onLoad)
|
|
t.rotate = t.repeatAnimations:CreateAnimation("rotation")
|
|
t.normal, t.alert = {}, {}
|
|
do
|
|
t.fadeInGroup = t.frame:CreateAnimationGroup()
|
|
local scaleOut = t.fadeInGroup:CreateAnimation("scale")
|
|
scaleOut:SetDuration(0)
|
|
scaleOut:SetScale(1.5, 1.5)
|
|
scaleOut:SetOrder(1)
|
|
t.fadeIn = t.fadeInGroup:CreateAnimation()
|
|
t.fadeIn:SetDuration(0.35)
|
|
t.fadeIn:SetScript("OnPlay", function(self)
|
|
animations.onLoad(self)
|
|
t.fadeOutGroup:Stop()
|
|
end)
|
|
t.fadeIn:SetScript("OnUpdate", animations.alpha)
|
|
t.fadeIn:SetScript("OnStop", animations.fullOpacity)
|
|
t.fadeIn:SetOrder(2)
|
|
local scaleIn = t.fadeInGroup:CreateAnimation("scale")
|
|
scaleIn:SetDuration(0.35)
|
|
scaleIn:SetScale(1 / 1.5, 1 / 1.5)
|
|
scaleIn:SetOrder(2)
|
|
end
|
|
t.fadeOutGroup = t.frame:CreateAnimationGroup()
|
|
t.fadeOut = t.fadeOutGroup:CreateAnimation("alpha")
|
|
t.fadeOut:SetFromAlpha(1)
|
|
t.fadeOut:SetToAlpha(0)
|
|
t.fadeOut:SetDuration(0.25)
|
|
t.fadeOut:SetScript("OnFinished", animations.hideParent)
|
|
t.fadeOutGroup:SetScript("OnPlay", function() t.fadeInGroup:Stop() end)
|
|
end
|
|
-- These need to be reset so that reconstitution via broadcasts don't get pooched up.
|
|
t.id = nil
|
|
t.shouldUpdateRange = nil
|
|
t.pulseSize = nil
|
|
t.rotateAmount = nil
|
|
t:OnAcquire()
|
|
t.texture:SetDrawLayer("ARTWORK")
|
|
t.alwaysShow = nil
|
|
t.persist = nil
|
|
t.placed = false
|
|
t:SetLabel(nil, "CENTER", "CENTER", r, g, b, a)
|
|
t.texfile = texfile
|
|
t:SetTexture(texfile, blend)
|
|
t:SetSize(size or 20)
|
|
t:SetColor(r, g, b, a)
|
|
t:SetAlertColor(1, 0, 0, a)
|
|
t:Alert(false)
|
|
t.shouldUpdateRange = false
|
|
if x and y then
|
|
t:Stick(map, x, y)
|
|
elseif follow then
|
|
t:Follow(follow)
|
|
end
|
|
t.baseLifetime = lifetime
|
|
t.lifetime = lifetime and (GetTime() + lifetime) or -1
|
|
t.map = map
|
|
activePointList[t] = true
|
|
t.callbacks:Fire("New", t)
|
|
return t
|
|
end,
|
|
}, object_mt)
|
|
end
|
|
edge_mt.__index = Edge
|
|
point_mt.__index = Point
|
|
|
|
function mod:PlaceRangeMarker(texture, x, y, radius, duration, r, g, b, a, blend)
|
|
return Point:New(DBM:GetCurrentArea(), x, y, nil, duration, texture, radius, blend, r, g, b, a)
|
|
end
|
|
|
|
function mod:PlaceStaticMarkerOnPartyMember(texture, person, radius, duration, r, g, b, a, blend)
|
|
if not r and person then -- Auto generate class color if colors were left nil
|
|
local _, cls = UnitClass(person)
|
|
if cls and RAID_CLASS_COLORS[cls] then
|
|
r, g, b = RAID_CLASS_COLORS[cls].r, RAID_CLASS_COLORS[cls].g, RAID_CLASS_COLORS[cls].b
|
|
else
|
|
DBM:Debug("HudMap Marker failed, no color defined and no unit class")
|
|
return
|
|
end
|
|
end
|
|
local x, y = self:GetUnitPosition(person)
|
|
return Point:New(DBM:GetCurrentArea(), x, y, nil, duration, texture, radius, blend, r, g, b, a)
|
|
end
|
|
|
|
function mod:PlaceRangeMarkerOnPartyMember(texture, person, radius, duration, r, g, b, a, blend)
|
|
if not r and person then -- Auto generate class color if colors were left nil
|
|
local _, cls = UnitClass(person)
|
|
if cls and RAID_CLASS_COLORS[cls] then
|
|
r, g, b = RAID_CLASS_COLORS[cls].r, RAID_CLASS_COLORS[cls].g, RAID_CLASS_COLORS[cls].b
|
|
else
|
|
DBM:Debug("HudMap Marker failed, no color defined and no unit class")
|
|
return
|
|
end
|
|
end
|
|
return Point:New(nil, nil, nil, person, duration, texture, radius, blend, r, g, b, a)
|
|
end
|
|
|
|
function mod:RegisterEncounterMarker(spellid, name, marker)
|
|
if DBM.Options.DontShowHudMap2 then return end
|
|
if not HUDEnabled then
|
|
self:Enable()
|
|
end
|
|
encounterMarkers[spellid .. name] = marker
|
|
activeMarkers = activeMarkers + 1
|
|
marker.RegisterCallback(self, "Free", "FreeEncounterMarker", spellid .. name)
|
|
end
|
|
|
|
function mod:RegisterPositionMarker(spellid, name, texture, x, y, radius, duration, r, g, b, a, blend, localMap, AreaID)
|
|
if localMap then
|
|
if x >= 0 and x <= 100 and y >= 0 and y <= 100 then
|
|
local _, temptable = C_Map.GetWorldPosFromMapPos(tonumber(AreaID) or C_Map.GetBestMapForUnit("player") or 0, CreateVector2D(x / 100, y / 100))
|
|
x, y = temptable.x, temptable.y
|
|
end
|
|
end
|
|
local marker = encounterMarkers[spellid..name]
|
|
if marker ~= nil then
|
|
return marker
|
|
end
|
|
marker = Point:New(DBM:GetCurrentArea(), x, y, nil, duration, texture, radius, blend, r, g, b, a)
|
|
self:RegisterEncounterMarker(spellid, name, marker)
|
|
return marker
|
|
end
|
|
|
|
function mod:RegisterStaticMarkerOnPartyMember(spellid, texture, person, radius, duration, r, g, b, a, blend)
|
|
if not r and person then -- Auto generate class color if colors were left nil
|
|
local _, cls = UnitClass(person)
|
|
if cls and RAID_CLASS_COLORS[cls] then
|
|
r, g, b = RAID_CLASS_COLORS[cls].r, RAID_CLASS_COLORS[cls].g, RAID_CLASS_COLORS[cls].b
|
|
else
|
|
DBM:Debug("HudMap Marker failed, no color defined and no unit class")
|
|
return
|
|
end
|
|
end
|
|
local marker = encounterMarkers[spellid .. person]
|
|
if marker ~= nil then
|
|
return marker
|
|
end
|
|
local x, y = self:GetUnitPosition(person)
|
|
marker = Point:New(DBM:GetCurrentArea(), x, y, nil, duration, texture, radius, blend, r, g, b, a)
|
|
self:RegisterEncounterMarker(spellid, person, marker)
|
|
return marker
|
|
end
|
|
|
|
function mod:RegisterRangeMarkerOnPartyMember(spellid, texture, person, radius, duration, r, g, b, a, blend)
|
|
if not r and person then -- Auto generate class color if colors were left nil
|
|
local _, cls = UnitClass(person)
|
|
if cls and RAID_CLASS_COLORS[cls] then
|
|
r, g, b = RAID_CLASS_COLORS[cls].r, RAID_CLASS_COLORS[cls].g, RAID_CLASS_COLORS[cls].b
|
|
else
|
|
DBM:Debug("HudMap Marker failed, no color defined and no unit class")
|
|
return
|
|
end
|
|
end
|
|
local marker = encounterMarkers[spellid .. person]
|
|
if marker ~= nil then
|
|
return marker
|
|
end
|
|
marker = Point:New(nil, nil, nil, person, duration, texture, radius, blend, r, g, b, a)
|
|
self:RegisterEncounterMarker(spellid, person, marker)
|
|
return marker
|
|
end
|
|
|
|
function mod:FreeEncounterMarker(key)
|
|
if not HUDEnabled or not encounterMarkers[key] then
|
|
return
|
|
end
|
|
encounterMarkers[key] = nil
|
|
activeMarkers = activeMarkers - 1
|
|
if activeMarkers == 0 then
|
|
self:Disable()
|
|
end
|
|
end
|
|
|
|
function mod:FreeEncounterMarkerByTarget(spellid, name)
|
|
if not HUDEnabled or not encounterMarkers[spellid .. name] then
|
|
return
|
|
end
|
|
self:Free(encounterMarkers[spellid .. name])
|
|
end
|
|
|
|
function mod:FreeEncounterMarkers()
|
|
if not HUDEnabled then
|
|
return
|
|
end
|
|
for k, v in pairs(encounterMarkers) do
|
|
if encounterMarkers[k] == 143430 .. playerName then
|
|
break -- Don't deactivate Hudar in this call
|
|
end
|
|
encounterMarkers[k] = v:Free()
|
|
end
|
|
end
|
|
|
|
function mod:DistanceBetweenPoints(x1, y1, x2, y2)
|
|
local dx = x2 - x1
|
|
local dy = y2 - y1
|
|
return abs(pow((dx * dx) + (dy * dy), 0.5))
|
|
end
|
|
|
|
function mod:DistanceToPoint(unit, x, y)
|
|
local x1, y1 = self:GetUnitPosition(unit)
|
|
return self:DistanceBetweenPoints(x1, y1, x, y)
|
|
end
|
|
|
|
function mod:UnitDistance(unitA, unitB)
|
|
local x1, y1 = self:GetUnitPosition(unitA)
|
|
local x2, y2 = self:GetUnitPosition(unitB)
|
|
return self:DistanceBetweenPoints(x1, y1, x2, y2)
|
|
end
|
|
|
|
function mod:GetUnitPosition(unit)
|
|
if unit then
|
|
return UnitPosition(unit)
|
|
end
|
|
end
|
|
|
|
function mod:SetZoom(zoom, zoomChange)
|
|
if zoom then
|
|
targetZoomScale = zoom
|
|
elseif zoomChange then
|
|
targetZoomScale = targetZoomScale + zoomChange
|
|
else
|
|
targetZoomScale = 100
|
|
end
|
|
if targetZoomScale < 20 then
|
|
targetZoomScale = 20
|
|
elseif targetZoomScale > 200 then
|
|
targetZoomScale = 200
|
|
end
|
|
end
|
|
|
|
function mod:SetFixedZoom(zoom)
|
|
if type(zoom) == "number" then
|
|
fixedZoomScale = zoom
|
|
else
|
|
fixedZoomScale = nil
|
|
end
|
|
end
|
|
|
|
function mod:SetFixedUpdateRate(updateRate)
|
|
if type(updateRate) == "number" and updateRate > 0 then
|
|
fixedOnUpdateRate = updateRate
|
|
else
|
|
fixedOnUpdateRate = 0.03
|
|
end
|
|
end
|
|
|
|
function mod:Update()
|
|
Point:UpdateAll()
|
|
Edge:UpdateAll()
|
|
end
|
|
|
|
function mod:GetMinimapSize()
|
|
return zoomScale
|
|
end
|
|
|
|
do
|
|
local function ClipPointToRadius(dx, dy, offset)
|
|
local e = -dx
|
|
local f = -dy
|
|
local distance = sqrt((e * e) + (f * f)) + offset
|
|
local scaleFactor
|
|
if distance ~= 0 then
|
|
scaleFactor = 1 - ((WorldFrame:GetHeight() * 0.48) / distance)
|
|
if distance > (WorldFrame:GetHeight() * 0.48) then
|
|
dx = dx + (scaleFactor * e)
|
|
dy = dy + (scaleFactor * f)
|
|
end
|
|
end
|
|
return dx, dy
|
|
end
|
|
|
|
--[[
|
|
local function ClipPointToEdges(dx, dy, offset)
|
|
local nx, ny
|
|
local z2 = (WorldFrame:GetHeight() * 0.48)
|
|
dx, dy = ClipPointToRadius(dx, dy, offset)
|
|
nx = min(max(dx, -z2 + offset), z2 - offset)
|
|
ny = min(max(dy, -z2 + offset), z2 - offset)
|
|
return nx, ny, nx ~= dx or ny ~= dy
|
|
end
|
|
--]]
|
|
|
|
function mod:GetFacing()
|
|
return GetPlayerFacing() or 0
|
|
end
|
|
|
|
function mod:LocationToMinimapOffset(x, y, alwaysShow, radiusOffset, pixelOffset)
|
|
mod.pixelsPerYard = (WorldFrame:GetHeight() * 0.48) / zoomScale
|
|
local px, py = self:GetUnitPosition("player")
|
|
local dx, dy
|
|
local nx, ny
|
|
dx = (px - x) * mod.pixelsPerYard
|
|
dy = (py - y) * mod.pixelsPerYard
|
|
-- Now adjust for rotation
|
|
local bearing = self:GetFacing()
|
|
local angle = atan2(dy, dx)
|
|
if angle <= 0 then
|
|
angle = -angle
|
|
else
|
|
angle = pi2 - angle
|
|
end
|
|
local hyp = abs(sqrt((dx * dx) + (dy * dy)))
|
|
x, y = sin(angle + bearing), cos(angle + bearing)
|
|
nx, ny = -x * hyp, -y * hyp
|
|
if alwaysShow then
|
|
local offset = (radiusOffset and radiusOffset * mod.pixelsPerYard) or (pixelOffset and pixelOffset / 2) or 0
|
|
nx, ny = ClipPointToRadius(nx, ny, offset)
|
|
end
|
|
return nx, ny
|
|
end
|
|
|
|
function mod:RangeToPixels(range)
|
|
mod.pixelsPerYard = (WorldFrame:GetHeight() * 0.48) / zoomScale
|
|
return mod.pixelsPerYard * range
|
|
end
|
|
end
|
|
|
|
----------
|
|
-- Data --
|
|
----------
|
|
function mod:ShowCanvas()
|
|
if not canvas:IsVisible() then
|
|
zoomScale = targetZoomScale
|
|
canvas:SetAlpha(0)
|
|
canvas:Show()
|
|
end
|
|
targetCanvasAlpha = 1
|
|
end
|
|
|
|
function mod:HideCanvas()
|
|
targetCanvasAlpha = 0
|
|
end
|
|
|
|
function mod:SupressCanvas()
|
|
supressCanvas = true
|
|
if HUDEnabled then
|
|
canvas:Hide()
|
|
end
|
|
end
|
|
|
|
function mod:UnSupressCanvas()
|
|
supressCanvas = nil
|
|
if HUDEnabled then
|
|
canvas:Show()
|
|
end
|
|
end
|
|
|
|
function mod:Toggle(flag)
|
|
if flag == nil then
|
|
flag = not canvas:IsVisible() or targetCanvasAlpha == 0
|
|
end
|
|
if flag then
|
|
self:ShowCanvas()
|
|
elseif not flag then
|
|
self:HideCanvas()
|
|
else
|
|
self:HideCanvas()
|
|
end
|
|
end
|
|
|
|
do
|
|
SLASH_DBMHUDAR1 = "/hudar"
|
|
SlashCmdList["DBMHUDAR"] = function()
|
|
DBM.HudMap:ToggleHudar()
|
|
end
|
|
end
|
|
|