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.

355 lines
10 KiB

--NOBODY, except Keseva touches this file.
-- globals
DBM.Nameplate = {}
-- locals
local nameplateFrame = DBM.Nameplate
local units = {}
local num_units = 0
local playerName, playerGUID = UnitName("player"), UnitGUID("player")--Cache these, they never change
local GetNamePlateForUnit, GetNamePlates = C_NamePlate.GetNamePlateForUnit, C_NamePlate.GetNamePlates
local twipe, floor = table.wipe, math.floor
--------------------
-- Create Frame --
--------------------
local DBMNameplateFrame = CreateFrame("Frame", "DBMNameplate", UIParent)
DBMNameplateFrame:SetFrameStrata('BACKGROUND')
DBMNameplateFrame:Hide()
--------------------------
-- Aura frame functions --
--------------------------
local CreateAuraFrame
do
local function AuraFrame_CreateIcon(frame)
local icon = DBMNameplateFrame:CreateTexture(nil,'BACKGROUND',nil,0)
icon:SetSize(DBM.Options.NPAuraSize, DBM.Options.NPAuraSize)
icon:Hide()
tinsert(frame.icons,icon)
return icon
end
local function AuraFrame_GetIcon(frame,texture)
-- find unused icon or create new icon
if not frame.icons or #frame.icons == 0 then
return frame:CreateIcon()
else
if frame.texture_index[texture] then
-- return icon already used for this texture
return frame.texture_index[texture]
else
-- find unused icon:
for _, icon in ipairs(frame.icons) do
if not icon:IsShown() then
return icon
end
end
-- create new icon
return frame:CreateIcon()
end
end
end
local function AuraFrame_ArrangeIcons(frame)
if not frame.icons or #frame.icons == 0 then return end
local prev,total_width,first_icon
for _, icon in ipairs(frame.icons) do
if icon:IsShown() then
icon:ClearAllPoints()
if not prev then
total_width = 0
first_icon = icon
icon:SetPoint('BOTTOM',frame.parent,'TOP')
else
total_width = total_width + icon:GetWidth()
icon:SetPoint('LEFT',prev,'RIGHT')
end
prev = icon
end
end
if first_icon and total_width and total_width > 0 then
-- shift first icon back to centre visible row
first_icon:SetPoint('BOTTOM',frame.parent,'TOP',
-floor(total_width/2),0)
end
end
local function AuraFrame_AddAura(frame,aura_tbl)
if not frame.icons then
frame.icons = {}
end
if not frame.texture_index then
frame.texture_index = {}
end
local icon = frame:GetIcon(aura_tbl.texture)
icon:SetTexture(aura_tbl.texture)
icon:Show()
frame.texture_index[aura_tbl.texture] = icon
frame:ArrangeIcons()
end
local function AuraFrame_RemoveAura(frame,texture,batch)
if not texture then return end
if not frame.texture_index then return end
local icon = frame.texture_index[texture]
if not icon then return end
icon:Hide()
frame.texture_index[texture] = nil
if not batch then
frame:ArrangeIcons()
end
end
local function AuraFrame_RemoveAll(frame)
if not frame.icons or not frame.texture_index then return end
for texture,_ in pairs(frame.texture_index) do
frame:RemoveAura(texture,true)
end
twipe(frame.texture_index)
end
local auraframe_proto = {
CreateIcon = AuraFrame_CreateIcon,
GetIcon = AuraFrame_GetIcon,
ArrangeIcons = AuraFrame_ArrangeIcons,
AddAura = AuraFrame_AddAura,
RemoveAura = AuraFrame_RemoveAura,
RemoveAll = AuraFrame_RemoveAll,
}
auraframe_proto.__index = auraframe_proto
function CreateAuraFrame(frame)
if not frame then return end
local new_frame = {}
setmetatable(new_frame, auraframe_proto)
new_frame.parent = frame
return new_frame
end
end
-------------------------
-- Nameplate functions --
-------------------------
local function Nameplate_OnHide(frame)
if not frame then return end
frame.DBMAuraFrame:RemoveAll()
end
local function HookNameplate(frame)
if not frame then return end
frame.DBMAuraFrame = CreateAuraFrame(frame)
frame:HookScript('OnHide',Nameplate_OnHide)
end
local function Nameplate_AutoHide(self, isGUID, unit, spellId, texture)
self:Hide(isGUID, unit, spellId, texture)
end
local function Nameplate_UnitAdded(frame,unit)
if not frame or not unit then return end
if not frame.DBMAuraFrame then
-- hook as required;
HookNameplate(frame)
end
local unitName = DBM:GetUnitFullName(unit)
local guid = UnitGUID(unit)
local unit_tbl
if guid and units[guid] then
unit_tbl = units[guid]
elseif unitName and units[unitName] then
unit_tbl = units[unitName]
end
if unit_tbl and #unit_tbl > 0 then
for _,aura_tbl in ipairs(unit_tbl) do
frame.DBMAuraFrame:AddAura(aura_tbl)
end
end
end
----------------
-- On Event --
----------------
DBMNameplateFrame:SetScript("OnEvent", function(_, event, ...)
if event == 'NAME_PLATE_UNIT_ADDED' then
local unit = ...
if not unit then return end
local f = GetNamePlateForUnit(unit)
if not f then return end
Nameplate_UnitAdded(f,unit)
end
end)
-----------------
-- Functions --
-----------------
--/run DBM:FireEvent("BossMod_EnableHostileNameplates")
--/run DBM.Nameplate:Show(false, GetUnitName("target", true), 227723)--Mana tracking, easy to find in Dalaran
--/run DBM.Nameplate:Hide(true, nil, nil, nil, true)
--/run DBM.Nameplate:Hide(true, UnitGUID("target"), 227723)
--/run DBM.Nameplate:Hide(false, GetUnitName("target", true), 227723)
--Add more nameplate mods as they gain support
function nameplateFrame:SupportedNPMod()
if not DBM.Options.UseNameplateHandoff then return false end
if _G["KuiNameplates"] or _G["TidyPlatesThreatDBM"] or _G["Plater"] then return true end
return false
end
--isGUID: guid or name (bool)
--ie, anchored to UIParent Center (ie player is in center) and to bottom of nameplate aura.
function nameplateFrame:Show(isGUID, unit, spellId, texture, duration, desaturate, forceDBM)
-- nameplate icons are disabled;
if DBM.Options.DontShowNameplateIcons then return end
-- ignore player nameplate;
if playerGUID == unit or playerName == unit then return end
--Texture Id passed as string so as not to get confused with spellID for GetSpellTexture
local currentTexture = tonumber(texture) or texture or GetSpellTexture(spellId)
-- Supported by nameplate mod, passing to their handler;
if self:SupportedNPMod() and not forceDBM then
DBM:FireEvent("BossMod_ShowNameplateAura", isGUID, unit, currentTexture, duration, desaturate)
DBM:Debug("DBM.Nameplate Found supported NP mod, only sending Show callbacks", 3)
return
end
--Not running supported NP Mod, internal handling
if not self:IsShown() then
DBMNameplateFrame:Show()
DBMNameplateFrame:RegisterEvent("NAME_PLATE_UNIT_ADDED")
DBM:Debug("DBM.Nameplate Enabling", 2)
end
if not units[unit] then
units[unit] = {}
num_units = num_units + 1
end
tinsert(units[unit], {
texture = currentTexture
})
-- find frame for this unit;
if not isGUID then
local frame = GetNamePlateForUnit(unit)
if frame then
Nameplate_UnitAdded(frame, unit)
if duration then
DBM:Schedule(duration, Nameplate_AutoHide, self, isGUID, unit, spellId, texture)
end
end
else
--GUID, less efficient because it must scan all plates to find
--but supports npcs/enemies
for _, frame in pairs(GetNamePlates()) do
local foundUnit = frame.namePlateUnitToken or (frame.UnitFrame and frame.UnitFrame.unit)
if foundUnit and UnitGUID(foundUnit) == unit then
Nameplate_UnitAdded(frame, foundUnit)
if duration then
DBM:Schedule(duration, Nameplate_AutoHide, self, isGUID, unit, spellId, texture)
end
break
end
end
end
end
--Friendly is still being kept around for world bosses, for now anyways, but args being swapped.
function nameplateFrame:Hide(isGUID, unit, spellId, texture, force, isHostile, isFriendly, forceDBM)
--Texture Id passed as string so as not to get confused with spellID for GetSpellTexture
local currentTexture = tonumber(texture) or texture or GetSpellTexture(spellId)
if self:SupportedNPMod() and not forceDBM then
DBM:Debug("DBM.Nameplate Found supported NP mod, only sending Hide callbacks", 3)
if force then
if isFriendly then
DBM:FireEvent("BossMod_DisableFriendlyNameplates")
end
if isHostile then
DBM:FireEvent("BossMod_DisableHostileNameplates")
end
elseif unit then
DBM:FireEvent("BossMod_HideNameplateAura", isGUID, unit, currentTexture)
end
return
end
--Not running supported NP Mod, internal handling
if unit and units[unit] then
if currentTexture then
for i,aura_tbl in ipairs(units[unit]) do
if aura_tbl.texture == currentTexture then
tremove(units[unit],i)
break
end
end
end
if not currentTexture or #units[unit] == 0 then
units[unit] = nil
num_units = num_units - 1
end
end
-- find frame for this unit
-- (or hide all visible textures if force ~= nil)
if not isGUID and not force then--Only need to find one unit
local frame = GetNamePlateForUnit(unit)
if frame and frame.DBMAuraFrame then
if not currentTexture then
frame.DBMAuraFrame:RemoveAll()
else
frame.DBMAuraFrame:RemoveAura(currentTexture)
end
end
else
--We either passed force, or GUID,
--either way requires scanning all nameplates
for _, frame in pairs(GetNamePlates()) do
if frame.DBMAuraFrame then
if force then
frame.DBMAuraFrame:RemoveAll()
elseif isGUID then
local foundUnit = frame.namePlateUnitToken or (frame.UnitFrame and frame.UnitFrame.unit)
if foundUnit and UnitGUID(foundUnit) == unit then
if not currentTexture then
frame.DBMAuraFrame:RemoveAll()
else
frame.DBMAuraFrame:RemoveAura(currentTexture)
end
end
end
end
end
end
-- disable nameplate hooking;
if force or num_units <= 0 then
twipe(units)
num_units = 0
DBMNameplateFrame:UnregisterEvent("NAME_PLATE_UNIT_ADDED")
DBMNameplateFrame:Hide()
DBM:Debug("DBM.Nameplate Disabling", 2)
end
end
function nameplateFrame:IsShown()
return DBMNameplateFrame and DBMNameplateFrame:IsShown()
end