mirror of
https://github.com/Bluewhale1337/ElvUIModernized.git
synced 2026-07-27 16:34:45 +00:00
548 lines
16 KiB
Lua
548 lines
16 KiB
Lua
local E, L, V, P, G = unpack(ElvUI)
|
|
local mod = E:GetModule("NamePlates")
|
|
local LSM = LibStub("LibSharedMedia-3.0")
|
|
|
|
local select, unpack, pairs = select, unpack, pairs
|
|
local tonumber = tonumber
|
|
local band = bit.band
|
|
local gsub = string.gsub
|
|
local tinsert, tremove, wipe = table.insert, table.remove, table.wipe
|
|
|
|
local CreateFrame = CreateFrame
|
|
local UnitAura = UnitAura
|
|
local UnitGUID = UnitGUID
|
|
local GetSpellTexture = GetSpellTexture
|
|
local RAID_CLASS_COLORS = RAID_CLASS_COLORS
|
|
local AURA_TYPE_BUFF = AURA_TYPE_BUFF
|
|
local AURA_TYPE_DEBUFF = AURA_TYPE_DEBUFF
|
|
|
|
local RaidIconBit = {
|
|
["STAR"] = "0x00100000",
|
|
["CIRCLE"] = "0x00200000",
|
|
["DIAMOND"] = "0x00400000",
|
|
["TRIANGLE"] = "0x00800000",
|
|
["MOON"] = "0x01000000",
|
|
["SQUARE"] = "0x02000000",
|
|
["CROSS"] = "0x04000000",
|
|
["SKULL"] = "0x08000000"
|
|
}
|
|
|
|
local RaidIconIndex = {
|
|
"STAR",
|
|
"CIRCLE",
|
|
"DIAMOND",
|
|
"TRIANGLE",
|
|
"MOON",
|
|
"SQUARE",
|
|
"CROSS",
|
|
"SKULL"
|
|
}
|
|
|
|
local ByRaidIcon = {}
|
|
local ByName = {}
|
|
|
|
local auraCache = {}
|
|
local buffCache = {}
|
|
local debuffCache = {}
|
|
|
|
local auraList = {}
|
|
local auraSpellID = {}
|
|
local auraName = {}
|
|
local auraExpiration = {}
|
|
local auraStacks = {}
|
|
local auraCaster = {}
|
|
local auraDuration = {}
|
|
local auraTexture = {}
|
|
local auraType = {}
|
|
local cachedAuraDurations = {}
|
|
|
|
local TimeColors = {
|
|
[0] = "|cffeeeeee",
|
|
[1] = "|cffeeeeee",
|
|
[2] = "|cffeeeeee",
|
|
[3] = "|cffFFEE00",
|
|
[4] = "|cfffe0000"
|
|
}
|
|
|
|
local AURA_UPDATE_INTERVAL = 0.1
|
|
|
|
local PolledHideIn
|
|
do
|
|
local Framelist = {}
|
|
local Watcherframe = CreateFrame("Frame")
|
|
local WatcherframeActive = false
|
|
local timeToUpdate = 0
|
|
|
|
local function CheckFramelist()
|
|
local curTime = GetTime()
|
|
if curTime < timeToUpdate then return end
|
|
local framecount = 0
|
|
timeToUpdate = curTime + AURA_UPDATE_INTERVAL
|
|
|
|
for frame, expiration in pairs(Framelist) do
|
|
if expiration < curTime then
|
|
frame:Hide()
|
|
Framelist[frame] = nil
|
|
else
|
|
if frame.Poll then frame:Poll(expiration) end
|
|
framecount = framecount + 1
|
|
end
|
|
end
|
|
if framecount == 0 then Watcherframe:SetScript("OnUpdate", nil); WatcherframeActive = false end
|
|
end
|
|
|
|
function PolledHideIn(frame, expiration)
|
|
if expiration == 0 then
|
|
frame:Hide()
|
|
Framelist[frame] = nil
|
|
else
|
|
Framelist[frame] = expiration
|
|
frame:Show()
|
|
|
|
if not WatcherframeActive then
|
|
Watcherframe:SetScript("OnUpdate", CheckFramelist)
|
|
WatcherframeActive = true
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
local function GetSpellDuration(spellID)
|
|
if spellID then return cachedAuraDurations[spellID] end
|
|
end
|
|
|
|
local function SetSpellDuration(spellID, duration)
|
|
if spellID then cachedAuraDurations[spellID] = duration end
|
|
end
|
|
|
|
local function UpdateAuraTime(frame, expiration)
|
|
local timeleft = expiration - GetTime()
|
|
local timervalue, formatid = E:GetTimeInfo(timeleft, 4)
|
|
local timeFormat = E.TimeFormats[3][2]
|
|
if timervalue < 4 then
|
|
timeFormat = E.TimeFormats[4][2]
|
|
end
|
|
frame.timeLeft:SetText(format("%s%s|r", TimeColors[formatid], timeFormat), timervalue)
|
|
end
|
|
|
|
local function RemoveAuraInstance(guid, spellID, caster)
|
|
if guid and spellID and auraList[guid] then
|
|
local instanceID = tostring(guid)..tostring(spellID)..(tostring(caster or "UNKNOWN_CASTER"))
|
|
local auraID = spellID..(tostring(caster or "UNKNOWN_CASTER"))
|
|
if auraList[guid][auraID] then
|
|
auraSpellID[instanceID] = nil
|
|
auraName[instanceID] = nil
|
|
auraExpiration[instanceID] = nil
|
|
auraStacks[instanceID] = nil
|
|
auraCaster[instanceID] = nil
|
|
auraDuration[instanceID] = nil
|
|
auraTexture[instanceID] = nil
|
|
auraType[instanceID] = nil
|
|
auraList[guid][auraID] = nil
|
|
end
|
|
end
|
|
end
|
|
|
|
local function GetAuraList(guid)
|
|
if guid and auraList[guid] then return auraList[guid] end
|
|
end
|
|
|
|
local function GetAuraInstance(guid, auraID)
|
|
if guid and auraID then
|
|
local instanceID = guid..auraID
|
|
local spellID, name, expiration, stacks, caster, duration, texture, type
|
|
spellID = auraSpellID[instanceID]
|
|
name = auraName[instanceID]
|
|
expiration = auraExpiration[instanceID]
|
|
stacks = auraStacks[instanceID]
|
|
caster = auraCaster[instanceID]
|
|
duration = auraDuration[instanceID]
|
|
texture = auraTexture[instanceID]
|
|
type = auraType[instanceID]
|
|
return spellID, name, expiration, stacks, caster, duration, texture, type
|
|
end
|
|
end
|
|
|
|
local function SetAuraInstance(guid, name, spellID, expiration, stacks, caster, duration, texture, type)
|
|
if guid and spellID and caster and texture then
|
|
local auraID = spellID..(tostring(caster or "UNKNOWN_CASTER"))
|
|
local instanceID = guid..auraID
|
|
auraList[guid] = auraList[guid] or {}
|
|
auraList[guid][auraID] = instanceID
|
|
auraSpellID[instanceID] = spellID
|
|
auraName[instanceID] = name
|
|
auraExpiration[instanceID] = expiration
|
|
auraStacks[instanceID] = stacks
|
|
auraCaster[instanceID] = caster
|
|
auraDuration[instanceID] = duration
|
|
auraTexture[instanceID] = texture
|
|
auraType[instanceID] = type
|
|
end
|
|
end
|
|
|
|
local function WipeAuraList(guid)
|
|
if guid and auraList[guid] then
|
|
local unitAuraList = auraList[guid]
|
|
for auraID, instanceID in pairs(unitAuraList) do
|
|
auraSpellID[instanceID] = nil
|
|
auraName[instanceID] = nil
|
|
auraExpiration[instanceID] = nil
|
|
auraStacks[instanceID] = nil
|
|
auraCaster[instanceID] = nil
|
|
auraDuration[instanceID] = nil
|
|
auraTexture[instanceID] = nil
|
|
auraType[instanceID] = nil
|
|
unitAuraList[auraID] = nil
|
|
end
|
|
end
|
|
end
|
|
|
|
function mod:CleanAuraLists()
|
|
local currentTime = GetTime()
|
|
for guid, instanceList in pairs(auraList) do
|
|
local auraCount = 0
|
|
for auraID, instanceID in pairs(instanceList) do
|
|
local expiration = auraExpiration[instanceID]
|
|
if expiration and expiration < currentTime then
|
|
auraList[guid][auraID] = nil
|
|
auraSpellID[instanceID] = nil
|
|
auraName[instanceID] = nil
|
|
auraExpiration[instanceID] = nil
|
|
auraStacks[instanceID] = nil
|
|
auraCaster[instanceID] = nil
|
|
auraDuration[instanceID] = nil
|
|
auraTexture[instanceID] = nil
|
|
auraType[instanceID] = nil
|
|
else
|
|
auraCount = auraCount + 1
|
|
end
|
|
end
|
|
if auraCount == 0 then
|
|
auraList[guid] = nil
|
|
end
|
|
end
|
|
end
|
|
|
|
function mod:SetAura(aura, icon, count, expirationTime)
|
|
aura.icon:SetTexture(icon)
|
|
if count > 1 then
|
|
aura.count:SetText(count)
|
|
else
|
|
aura.count:SetText("")
|
|
end
|
|
aura:Show()
|
|
PolledHideIn(aura, expirationTime)
|
|
end
|
|
|
|
function mod:HideAuraIcons(auras)
|
|
for i = 1, getn(auras.icons) do
|
|
PolledHideIn(auras.icons[i], 0)
|
|
end
|
|
end
|
|
|
|
local currentAura = {}
|
|
function mod:UpdateElement_Auras(frame)
|
|
if not frame.HealthBar:IsShown() then return end
|
|
|
|
local guid = frame.guid
|
|
|
|
if not guid then
|
|
if RAID_CLASS_COLORS[frame.UnitClass] then
|
|
local name = gsub(frame.oldName:GetText(), "%s%(%*%)","")
|
|
guid = ByName[name]
|
|
elseif frame.RaidIcon:IsShown() then
|
|
guid = ByRaidIcon[frame.RaidIconType]
|
|
end
|
|
|
|
if guid then
|
|
frame.guid = guid
|
|
else
|
|
return
|
|
end
|
|
end
|
|
|
|
local hasDebuffs = false
|
|
local hasBuffs = false
|
|
|
|
local numDebuff = 0
|
|
local numBuff = 0
|
|
|
|
local aurasOnUnit = GetAuraList(guid)
|
|
|
|
debuffCache = wipe(debuffCache)
|
|
buffCache = wipe(buffCache)
|
|
|
|
if aurasOnUnit then
|
|
local numAuras = 0
|
|
local aura
|
|
|
|
for instanceid in pairs(aurasOnUnit) do
|
|
numAuras = (numDebuff + numBuff) + 1
|
|
aura = wipe(currentAura[numAuras] or {})
|
|
|
|
aura.spellID, aura.name, aura.expirationTime, aura.count, aura.caster, aura.duration, aura.icon, aura.type = GetAuraInstance(guid, instanceid)
|
|
|
|
local filter = false
|
|
local db = self.db.units[frame.UnitType].buffs.filters
|
|
if aura.type == AURA_TYPE_DEBUFF then
|
|
db = self.db.units[frame.UnitType].debuffs.filters
|
|
end
|
|
|
|
if db.personal and aura.caster == UnitGUID("player") then
|
|
filter = true
|
|
end
|
|
|
|
local trackFilter = E.global["unitframe"]["aurafilters"][db.filter]
|
|
if db.filter and trackFilter then
|
|
local spell = trackFilter.spells[tonumber(aura.spellID)] or trackFilter.spells[aura.name]
|
|
if trackFilter.type == "Whitelist" then
|
|
if spell and spell.enable then
|
|
filter = true
|
|
end
|
|
elseif trackFilter.type == "Blacklist" and spell and spell.enable then
|
|
filter = false
|
|
end
|
|
end
|
|
|
|
if filter ~= true then
|
|
numAuras = numAuras - 1
|
|
RemoveAuraInstance(guid, aura.spellID, aura.caster)
|
|
wipe(aura)
|
|
end
|
|
|
|
if tonumber(aura.spellID) then
|
|
aura.unit = frame.unit
|
|
if aura.expirationTime > GetTime() then
|
|
if aura.type == "BUFF" then
|
|
numBuff = numBuff + 1
|
|
buffCache[numBuff] = aura
|
|
else
|
|
numDebuff = numDebuff + 1
|
|
debuffCache[numDebuff] = aura
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
wipe(currentAura)
|
|
end
|
|
|
|
local frameNum = 1
|
|
local maxAuras = getn(frame.Debuffs.icons)
|
|
local maxDuration = self.db.units[frame.UnitType].debuffs.filters.maxDuration
|
|
|
|
self:HideAuraIcons(frame.Debuffs)
|
|
if numDebuff > 0 and self.db.units[frame.UnitType].debuffs.enable then
|
|
for index = 1, getn(debuffCache) do
|
|
if frameNum > maxAuras then break end
|
|
local debuff = debuffCache[index]
|
|
if debuff.spellID and debuff.expirationTime and debuff.duration <= maxDuration then
|
|
self:SetAura(frame.Debuffs.icons[frameNum], debuff.icon, debuff.count, debuff.expirationTime)
|
|
frameNum = frameNum + 1
|
|
hasDebuffs = true
|
|
end
|
|
end
|
|
end
|
|
|
|
frameNum = 1
|
|
maxAuras = getn(frame.Buffs.icons)
|
|
maxDuration = self.db.units[frame.UnitType].buffs.filters.maxDuration
|
|
|
|
self:HideAuraIcons(frame.Buffs)
|
|
if numBuff > 0 and self.db.units[frame.UnitType].buffs.enable then
|
|
for index = 1, getn(buffCache) do
|
|
if frameNum > maxAuras then break end
|
|
local buff = buffCache[index]
|
|
if buff.spellID and buff.expirationTime and buff.duration <= maxDuration then
|
|
self:SetAura(frame.Buffs.icons[frameNum], buff.icon, buff.count, buff.expirationTime)
|
|
frameNum = frameNum + 1
|
|
hasBuffs = true
|
|
end
|
|
end
|
|
end
|
|
|
|
debuffCache = wipe(debuffCache)
|
|
buffCache = wipe(buffCache)
|
|
|
|
local TopLevel = frame.HealthBar
|
|
local TopOffset = ((self.db.units[frame.UnitType].showName and select(2, frame.Name:GetFont()) + 5) or 0)
|
|
if hasDebuffs then
|
|
TopOffset = TopOffset + 3
|
|
frame.Debuffs:SetPoint("BOTTOMLEFT", TopLevel, "TOPLEFT", 0, TopOffset)
|
|
frame.Debuffs:SetPoint("BOTTOMRIGHT", TopLevel, "TOPRIGHT", 0, TopOffset)
|
|
TopLevel = frame.Debuffs
|
|
TopOffset = 3
|
|
end
|
|
|
|
if hasBuffs then
|
|
if not hasDebuffs then
|
|
TopOffset = TopOffset + 3
|
|
end
|
|
frame.Buffs:SetPoint("BOTTOMLEFT", TopLevel, "TOPLEFT", 0, TopOffset)
|
|
frame.Buffs:SetPoint("BOTTOMRIGHT", TopLevel, "TOPRIGHT", 0, TopOffset)
|
|
TopLevel = frame.Buffs
|
|
TopOffset = 3
|
|
end
|
|
|
|
if frame.TopLevelFrame ~= TopLevel then
|
|
frame.TopLevelFrame = TopLevel
|
|
frame.TopOffset = TopOffset
|
|
end
|
|
end
|
|
|
|
function mod:UpdateElement_AurasByUnitID(unit)
|
|
--[[local guid = UnitGUID(unit)
|
|
WipeAuraList(guid)
|
|
|
|
local index = 1
|
|
local texture, count, debuffType = UnitAura(unit, index, "HARMFUL")
|
|
local name, duration, expirationTime, unitCaster, spellID = texture, 0, 0, nil, nil
|
|
while name do
|
|
SetSpellDuration(spellID, duration)
|
|
SetAuraInstance(guid, name, spellID, expirationTime, count, UnitGUID(unitCaster or ""), duration, texture, AURA_TYPE_DEBUFF)
|
|
index = index + 1
|
|
texture, count, debuffType = UnitAura(unit, index, "HARMFUL")
|
|
name = texture
|
|
end
|
|
|
|
index = 1
|
|
texture, count, debuffType = UnitAura(unit, index, "HELPFUL")
|
|
name = texture
|
|
while name do
|
|
SetSpellDuration(spellID, duration)
|
|
SetAuraInstance(guid, name, spellID, expirationTime, count, UnitGUID(unitCaster or ""), duration, texture, AURA_TYPE_BUFF)
|
|
index = index + 1
|
|
texture, count, debuffType = UnitAura(unit, index, "HELPFUL")
|
|
name = texture
|
|
end
|
|
|
|
local raidIcon, name
|
|
if UnitPlayerControlled(unit) then name = UnitName(unit) end
|
|
raidIcon = RaidIconIndex[GetRaidTargetIndex(unit) or ""]
|
|
if raidIcon then ByRaidIcon[raidIcon] = guid end
|
|
|
|
local frame = self:SearchForFrame(guid, raidIcon, name)
|
|
if frame then
|
|
self:UpdateElement_Auras(frame)
|
|
end]]
|
|
end
|
|
|
|
function mod:COMBAT_LOG_EVENT_UNFILTERED(_, _, event, sourceGUID, _, _, destGUID, destName, destFlags, ...)
|
|
if destGUID == UnitGUID("target") then return end
|
|
--if band(destFlags, COMBATLOG_OBJECT_REACTION_FRIENDLY) ~= 0 then then return
|
|
if not (event == "SPELL_AURA_APPLIED" or event == "SPELL_AURA_REFRESH" or event == "SPELL_AURA_APPLIED_DOSE" or event == "SPELL_AURA_REMOVED_DOSE" or event == "SPELL_AURA_BROKEN" or event == "SPELL_AURA_BROKEN_SPELL" or event == "SPELL_AURA_REMOVED") then return end
|
|
|
|
--local spellID, spellName, _, auraType, stackCount = ...
|
|
|
|
if event == "SPELL_AURA_APPLIED" or event == "SPELL_AURA_REFRESH" then
|
|
local duration = GetSpellDuration(spellID)
|
|
local texture = GetSpellTexture(spellID)
|
|
SetAuraInstance(destGUID, spellName, spellID, GetTime() + (duration or 0), 1, sourceGUID, duration, texture, auraType)
|
|
elseif event == "SPELL_AURA_APPLIED_DOSE" or event == "SPELL_AURA_REMOVED_DOSE" then
|
|
local duration = GetSpellDuration(spellID)
|
|
local texture = GetSpellTexture(spellID)
|
|
SetAuraInstance(destGUID, spellName, spellID, GetTime() + (duration or 0), stackCount, sourceGUID, duration, texture, auraType)
|
|
elseif event == "SPELL_AURA_BROKEN" or event == "SPELL_AURA_BROKEN_SPELL" or event == "SPELL_AURA_REMOVED" then
|
|
RemoveAuraInstance(destGUID, spellID, sourceGUID)
|
|
end
|
|
|
|
local name, raidIcon
|
|
if band(destFlags, COMBATLOG_OBJECT_CONTROL_PLAYER) > 0 then
|
|
local rawName = strsplit("-", destName)
|
|
ByName[rawName] = destGUID
|
|
name = rawName
|
|
end
|
|
|
|
for iconName, bitmask in pairs(RaidIconBit) do
|
|
if band(destFlags, bitmask) > 0 then
|
|
ByRaidIcon[iconName] = destGUID
|
|
raidIcon = iconName
|
|
|
|
break
|
|
end
|
|
end
|
|
|
|
local frame = self:SearchForFrame(destGUID, raidIcon, name)
|
|
if frame then
|
|
self:UpdateElement_Auras(frame)
|
|
end
|
|
end
|
|
|
|
function mod:CreateAuraIcon(parent)
|
|
local aura = CreateFrame("Frame", nil, parent)
|
|
self:StyleFrame(aura, true)
|
|
|
|
aura.icon = aura:CreateTexture(nil, "OVERLAY")
|
|
aura.icon:SetAllPoints()
|
|
aura.icon:SetTexCoord(unpack(E.TexCoords))
|
|
|
|
aura.timeLeft = aura:CreateFontString(nil, "OVERLAY")
|
|
aura.timeLeft:SetPoint("TOPLEFT", 2, 2)
|
|
aura.timeLeft:SetFont(LSM:Fetch("font", self.db.font), self.db.fontSize, self.db.fontOutline)
|
|
|
|
aura.count = aura:CreateFontString(nil, "OVERLAY")
|
|
aura.count:SetPoint("BOTTOMRIGHT", 0, 0)
|
|
aura.count:SetFont(LSM:Fetch("font", self.db.font), self.db.fontSize, self.db.fontOutline)
|
|
aura.Poll = parent.PollFunction
|
|
|
|
return aura
|
|
end
|
|
|
|
function mod:Auras_SizeChanged(width)
|
|
local numAuras = getn(self.icons)
|
|
for i = 1, numAuras do
|
|
self.icons[i]:SetWidth(((width - numAuras) / numAuras) - (E.private.general.pixelPerfect and 0 or 3))
|
|
self.icons[i]:SetHeight((self.db.baseHeight or 18) * (self:GetParent().HealthBar.currentScale or 1))
|
|
end
|
|
self:SetHeight((self.db.baseHeight or 18) * (self:GetParent().HealthBar.currentScale or 1))
|
|
end
|
|
|
|
function mod:UpdateAuraIcons(auras)
|
|
local maxAuras = auras.db.numAuras
|
|
local numCurrentAuras = getn(auras.icons)
|
|
if(numCurrentAuras > maxAuras) then
|
|
for i = maxAuras, numCurrentAuras do
|
|
tinsert(auraCache, auras.icons[i])
|
|
auras.icons[i]:Hide()
|
|
auras.icons[i] = nil
|
|
end
|
|
end
|
|
|
|
if(numCurrentAuras ~= maxAuras) then
|
|
self.Auras_SizeChanged(auras, auras:GetWidth(), auras:GetHeight())
|
|
end
|
|
|
|
for i = 1, maxAuras do
|
|
auras.icons[i] = auras.icons[i] or tremove(auraCache) or mod:CreateAuraIcon(auras)
|
|
auras.icons[i]:SetParent(auras)
|
|
auras.icons[i]:ClearAllPoints()
|
|
auras.icons[i]:Hide()
|
|
auras.icons[i]:SetHeight(auras.db.baseHeight or 18)
|
|
|
|
if(auras.side == "LEFT") then
|
|
if(i == 1) then
|
|
auras.icons[i]:SetPoint("BOTTOMLEFT", auras, "BOTTOMLEFT")
|
|
else
|
|
auras.icons[i]:SetPoint("LEFT", auras.icons[i-1], "RIGHT", E.Border + E.Spacing*3, 0)
|
|
end
|
|
else
|
|
if(i == 1) then
|
|
auras.icons[i]:SetPoint("BOTTOMRIGHT", auras, "BOTTOMRIGHT")
|
|
else
|
|
auras.icons[i]:SetPoint("RIGHT", auras.icons[i-1], "LEFT", -(E.Border + E.Spacing*3), 0)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function mod:ConstructElement_Auras(frame, side)
|
|
local auras = CreateFrame("Frame", nil, frame)
|
|
|
|
auras:SetScript("OnSizeChanged", mod.Auras_SizeChanged)
|
|
auras:SetHeight(18)
|
|
auras.side = side
|
|
auras.PollFunction = UpdateAuraTime
|
|
auras.icons = {}
|
|
|
|
return auras
|
|
end |