ElvUI/Libraries/oUF_Plugins/oUF_AuraWatch/oUF_AuraWatch.lua

305 lines
8.5 KiB
Lua

-- Original work by Astromech
-- Rewritten based on Auras by Azilroka
local _, ns = ...
local oUF = ns.oUF
local VISIBLE = 1
local HIDDEN = 0
local min, wipe, pairs, tinsert = min, wipe, pairs, tinsert
local CreateFrame = CreateFrame
local UnitAura = UnitAura
local UnitIsUnit = UnitIsUnit
local GetSpellTexture = GetSpellTexture
local function createAuraIcon(element, index)
local button = CreateFrame('Button', element:GetName() .. 'Button' .. index, element)
button:EnableMouse(false)
button:Hide()
local cd = CreateFrame('Cooldown', '$parentCooldown', button, 'CooldownFrameTemplate')
cd:SetAllPoints()
cd:SetReverse(true)
cd:SetDrawBling(false)
cd:SetDrawEdge(false)
local icon = button:CreateTexture(nil, 'ARTWORK')
icon:SetAllPoints()
local countFrame = CreateFrame('Frame', nil, button)
countFrame:SetAllPoints(button)
countFrame:SetFrameLevel(cd:GetFrameLevel() + 1)
local count = countFrame:CreateFontString(nil, 'OVERLAY', 'NumberFontNormal')
count:SetPoint('BOTTOMRIGHT', countFrame, 'BOTTOMRIGHT', -1, 0)
local overlay = button:CreateTexture(nil, 'OVERLAY')
overlay:SetTexture([[Interface\Buttons\UI-Debuff-Overlays]])
overlay:SetAllPoints()
overlay:SetTexCoord(.296875, .5703125, 0, .515625)
button.overlay = overlay
button.icon = icon
button.count = count
button.cd = cd
if(element.PostCreateIcon) then element:PostCreateIcon(button) end
return button
end
local function customFilter(element, _, button, name, _, _, debuffType, _, _, caster, isStealable, _, spellID, canApply, isBossDebuff, casterIsPlayer)
local setting = element.watched[spellID]
if not setting then return false end
button.onlyShowMissing = setting.onlyShowMissing
button.anyUnit = setting.anyUnit
if setting.enabled then
if setting.onlyShowMissing and not setting.anyUnit and caster == 'player' then
return false
elseif setting.onlyShowMissing and setting.anyUnit and casterIsPlayer then
return true
elseif not setting.onlyShowMissing and setting.anyUnit and casterIsPlayer then
return true
elseif not setting.onlyShowMissing and not setting.anyUnit and caster == 'player' then
return true
end
end
return false
end
local function updateIcon(element, unit, index, offset, filter, isDebuff, visible)
local name, texture, count, debuffType, duration, expiration, caster, isStealable,
nameplateShowSelf, spellID, canApply, isBossDebuff, casterIsPlayer, nameplateShowAll,
timeMod, effect1, effect2, effect3 = UnitAura(unit, index, filter)
if(name) then
local position = visible + offset + 1
local button = element[position]
if(not button) then
button = (element.CreateIcon or createAuraIcon) (element, position)
tinsert(element, button)
element.createdIcons = element.createdIcons + 1
end
button.caster = caster
button.filter = filter
button.isDebuff = isDebuff
button.debuffType = debuffType
button.spellID = spellID
button.isPlayer = caster == 'player'
local show = (element.CustomFilter or customFilter) (element, unit, button, name, texture,
count, debuffType, duration, expiration, caster, isStealable, nameplateShowSelf, spellID,
canApply, isBossDebuff, casterIsPlayer, nameplateShowAll, timeMod, effect1, effect2, effect3)
if(show) then
local setting = element.watched[spellID]
if(button.cd) then
if(duration and duration > 0) then
button.cd:SetCooldown(expiration - duration, duration)
button.cd:Show()
else
button.cd:Hide()
end
end
if(button.overlay) then
if((isDebuff and element.showDebuffType) or (not isDebuff and element.showBuffType) or element.showType) then
local color = element.__owner.colors.debuff[debuffType] or element.__owner.colors.debuff.none
button.overlay:SetVertexColor(color[1], color[2], color[3])
button.overlay:Show()
else
button.overlay:Hide()
end
end
if(button.stealable) then
if(not isDebuff and isStealable and element.showStealableBuffs and not UnitIsUnit('player', unit)) then
button.stealable:Show()
else
button.stealable:Hide()
end
end
if(button.icon) then button.icon:SetTexture(texture) end
if(button.count) then button.count:SetText(count > 1 and count) end
if setting.sizeOffset == 0 then
button:SetSize(element.size, element.size)
else
button:SetSize(setting.sizeOffset + element.size, setting.sizeOffset + element.size)
end
button:SetID(index)
button:Show()
button:ClearAllPoints()
button:SetPoint(setting.point, setting.xOffset, setting.yOffset)
if(element.PostUpdateIcon) then
element:PostUpdateIcon(unit, button, index, position, duration, expiration, debuffType, isStealable)
end
return VISIBLE
else
button.isFiltered = true
return HIDDEN
end
end
end
local missing = {}
local function onlyShowMissingIcon(element, unit, offset)
wipe(missing)
for SpellID, setting in pairs(element.watched) do
if setting.onlyShowMissing then
missing[SpellID] = setting
end
end
for i = 1, #element do
local button = element[i]
if button.isFiltered and missing[button.spellID] then
missing[button.spellID] = nil
end
end
local visible = 0
for SpellID, setting in pairs(missing) do
local position = visible + offset + 1
local button = element[position]
if(not button) then
button = (element.CreateIcon or createAuraIcon) (element, position)
tinsert(element, button)
element.createdIcons = element.createdIcons + 1
end
if(button.cd) then button.cd:Hide() end
if(button.icon) then button.icon:SetTexture(GetSpellTexture(SpellID)) end
if(button.overlay) then button.overlay:Hide() end
if setting.sizeOffset == 0 then
button:SetSize(element.size, element.size)
else
button:SetSize(setting.sizeOffset + element.size, setting.sizeOffset + element.size)
end
button:SetID(position)
button.spellID = SpellID
button:Show()
button:ClearAllPoints()
button:SetPoint(setting.point, setting.xOffset, setting.yOffset)
if(element.PostUpdateIcon) then
element:PostUpdateIcon(unit, button, nil, position)
end
visible = visible + 1
end
return visible
end
local function filterIcons(element, unit, filter, limit, isDebuff, offset, dontHide)
if (not offset) then offset = 0 end
local index, visible, hidden = 1, 0, 0
while (visible < limit) do
local result = updateIcon(element, unit, index, offset, filter, isDebuff, visible)
if (not result) then
break
elseif (result == VISIBLE) then
visible = visible + 1
elseif (result == HIDDEN) then
hidden = hidden + 1
end
index = index + 1
end
if (not dontHide) then
for i = visible + offset + 1, #element do
element[i]:Hide()
end
end
return visible, hidden
end
local function UpdateAuras(self, event, unit)
if(self.unit ~= unit) then return end
local element = self.AuraWatch
if(element) then
if(element.PreUpdate) then element:PreUpdate(unit) end
local numBuffs = element.numBuffs or 32
local numDebuffs = element.numDebuffs or 16
local numAuras = element.numTotal or (numBuffs + numDebuffs)
for i = 1, #element do element[i].isFiltered = false end
local visibleBuffs, hiddenBuffs = filterIcons(element, unit, element.buffFilter or element.filter or 'HELPFUL', min(numBuffs, numAuras), nil, 0, true)
local visibleDebuffs, hiddenDebuffs = filterIcons(element, unit, element.buffFilter or element.filter or 'HARMFUL', min(numDebuffs, numAuras - visibleBuffs), true, visibleBuffs)
element.visibleDebuffs = visibleDebuffs
element.visibleBuffs = visibleBuffs
element.visibleAuras = visibleBuffs + visibleDebuffs
element.allAuras = visibleBuffs + visibleDebuffs + hiddenBuffs + hiddenDebuffs
onlyShowMissingIcon(element, unit, element.visibleAuras)
if(element.PostUpdate) then element:PostUpdate(unit) end
end
end
local function Update(self, event, unit)
if(self.unit ~= unit) then return end
UpdateAuras(self, event, unit)
end
local function ForceUpdate(element)
return Update(element.__owner, 'ForceUpdate', element.__owner.unit)
end
local function SetNewTable(element, table)
element.watched = table or {}
end
local function Enable(self)
local element = self.AuraWatch
if(element) then
element.__owner = self
element.SetNewTable = SetNewTable
element.ForceUpdate = ForceUpdate
element.watched = element.watched or {}
element.createdIcons = element.createdIcons or 0
element.anchoredIcons = 0
element.size = 8
self:RegisterEvent('UNIT_AURA', UpdateAuras)
element:Show()
return true
end
end
local function Disable(self)
if(self.AuraWatch) then
self:UnregisterEvent('UNIT_AURA', UpdateAuras)
if(self.AuraWatch) then self.AuraWatch:Hide() end
end
end
oUF:AddElement('AuraWatch', Update, Enable, Disable)