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.

287 lines
10 KiB

local Indicators = {}
ShadowUF:RegisterModule(Indicators, "auraIndicators", ShadowUF.L["Aura indicators"])
Indicators.auraFilters = {"boss", "curable"}
Indicators.auraConfig = setmetatable({}, {
__index = function(tbl, index)
local aura = ShadowUF.db.profile.auraIndicators.auras[tostring(index)]
if( not aura ) then
tbl[index] = false
else
local func, msg = loadstring("return " .. aura)
if( func ) then
func = func()
elseif( msg ) then
error(msg, 3)
end
tbl[index] = func
if( not tbl[index].group ) then tbl[index].group = "Miscellaneous" end
end
return tbl[index]
end})
local playerUnits = {player = true, vehicle = true, pet = true}
local backdropTbl = {bgFile = "Interface\\Addons\\ShadowedUnitFrames\\mediabackdrop", edgeFile = "Interface\\Addons\\ShadowedUnitFrames\\media\\backdrop", tile = true, tileSize = 1, edgeSize = 1}
function Indicators:OnEnable(frame)
-- Not going to create the indicators we want here, will do that when we do the layout stuff
frame.auraIndicators = frame.auraIndicators or CreateFrame("Frame", nil, frame)
frame.auraIndicators:SetFrameLevel(4)
frame.auraIndicators:Show()
-- Of course, watch for auras
frame:RegisterUnitEvent("UNIT_AURA", self, "UpdateAuras")
frame:RegisterUpdateFunc(self, "UpdateAuras")
end
function Indicators:OnDisable(frame)
frame:UnregisterAll(self)
frame.auraIndicators:Hide()
end
function Indicators:OnLayoutApplied(frame)
if( not frame.auraIndicators ) then return end
-- Create indicators
local id = 1
for key, indicatorConfig in pairs(ShadowUF.db.profile.auraIndicators.indicators) do
-- Create indicator as needed
local indicator = frame.auraIndicators["indicator-" .. id]
if( not indicator ) then
indicator = CreateFrame("Frame", nil, frame.auraIndicators, BackdropTemplateMixin and "BackdropTemplate" or nil)
indicator:SetFrameLevel(frame.topFrameLevel + 2)
indicator.texture = indicator:CreateTexture(nil, "OVERLAY")
indicator.texture:SetPoint("CENTER", indicator)
indicator:SetAlpha(indicatorConfig.alpha)
indicator:SetBackdrop(backdropTbl)
indicator:SetBackdropColor(0, 0, 0, 1)
indicator:SetBackdropBorderColor(0, 0, 0, 0)
indicator.cooldown = CreateFrame("Cooldown", nil, indicator, "CooldownFrameTemplate")
indicator.cooldown:SetReverse(true)
indicator.cooldown:SetPoint("CENTER", 0, -1)
indicator.cooldown:SetHideCountdownNumbers(true)
indicator.stack = indicator:CreateFontString(nil, "OVERLAY")
indicator.stack:SetFont("Interface\\AddOns\\ShadowedUnitFrames\\media\\fonts\\Myriad Condensed Web.ttf", 12, "OUTLINE")
indicator.stack:SetShadowColor(0, 0, 0, 1.0)
indicator.stack:SetShadowOffset(0.8, -0.8)
indicator.stack:SetPoint("BOTTOMRIGHT", indicator, "BOTTOMRIGHT", 1, 0)
indicator.stack:SetWidth(18)
indicator.stack:SetHeight(10)
indicator.stack:SetJustifyH("RIGHT")
frame.auraIndicators["indicator-" .. id] = indicator
end
-- Quick access
indicator.filters = ShadowUF.db.profile.auraIndicators.filters[key]
indicator.config = ShadowUF.db.profile.units[frame.unitType].auraIndicators
-- Set up the sizing options
indicator:SetHeight(indicatorConfig.height)
indicator.texture:SetWidth(indicatorConfig.width - 1)
indicator:SetWidth(indicatorConfig.width)
indicator.texture:SetHeight(indicatorConfig.height - 1)
ShadowUF.Layout:AnchorFrame(frame, indicator, indicatorConfig)
-- Let the auras module quickly access indicators without having to use index
frame.auraIndicators[key] = indicator
id = id + 1
end
end
local playerClass = select(2, UnitClass("player"))
local filterMap = {}
local canCure = ShadowUF.Units.canCure
for _, key in pairs(Indicators.auraFilters) do filterMap[key] = "filter-" .. key end
local function checkFilterAura(frame, type, isFriendly, name, texture, count, auraType, duration, endTime, caster, isRemovable, nameplateShowPersonal, spellID, canApplyAura, isBossDebuff)
local category
if( isFriendly and canCure[auraType] and type == "debuffs" ) then
category = "curable"
elseif( isBossDebuff ) then
category = "boss"
else
return
end
local applied = false
for key, config in pairs(ShadowUF.db.profile.auraIndicators.indicators) do
local indicator = frame.auraIndicators[key]
if( indicator and indicator.config.enabled and indicator.filters[category].enabled and not ShadowUF.db.profile.units[frame.unitType].auraIndicators[filterMap[category]] ) then
indicator.showStack = config.showStack
indicator.priority = indicator.filters[category].priority
indicator.showIcon = true
indicator.showDuration = indicator.filters[category].duration
indicator.spellDuration = duration
indicator.spellEnd = endTime
indicator.spellIcon = texture
indicator.spellName = name
indicator.spellStack = count
indicator.colorR = nil
indicator.colorG = nil
indicator.colorB = nil
applied = true
end
end
return applied
end
local function checkSpecificAura(frame, type, name, texture, count, auraType, duration, endTime, caster, isRemovable, nameplateShowPersonal, spellID, canApplyAura, isBossDebuff)
-- Not relevant
if( not ShadowUF.db.profile.auraIndicators.auras[name] and not ShadowUF.db.profile.auraIndicators.auras[tostring(spellID)] ) then return end
local auraConfig = Indicators.auraConfig[name] or Indicators.auraConfig[spellID]
-- Only player auras
if( auraConfig.player and not playerUnits[caster] ) then return end
local indicator = auraConfig and frame.auraIndicators[auraConfig.indicator]
-- No indicator or not enabled
if( not indicator or not indicator.enabled ) then return end
-- Missing aura only
if( auraConfig.missing ) then return end
-- Disabled on a class level
if( ShadowUF.db.profile.auraIndicators.disabled[playerClass][name] ) then return end
-- Disabled aura group by unit
if( ShadowUF.db.profile.units[frame.unitType].auraIndicators[auraConfig.group] ) then return end
-- If the indicator is not restricted to the player only, then will give the player a slightly higher priority
local priority = auraConfig.priority
local color = auraConfig
if( not auraConfig.player and playerUnits[caster] ) then
priority = priority + 0.1
color = auraConfig.selfColor or auraConfig
end
if( priority <= indicator.priority ) then return end
indicator.showStack = ShadowUF.db.profile.auraIndicators.indicators[auraConfig.indicator].showStack
indicator.priority = priority
indicator.showIcon = auraConfig.icon
indicator.showDuration = auraConfig.duration
indicator.spellDuration = duration
indicator.spellEnd = endTime
indicator.spellIcon = texture
indicator.spellName = name
indicator.spellStack = count
indicator.colorR = color.r
indicator.colorG = color.g
indicator.colorB = color.b
return true
end
local auraList = {}
local function scanAuras(frame, filter, type)
local isFriendly = not UnitIsEnemy(frame.unit, "player")
local index = 0
while( true ) do
index = index + 1
local name, texture, count, auraType, duration, endTime, caster, isRemovable, nameplateShowPersonal, spellID, canApplyAura, isBossDebuff = UnitAura(frame.unit, index, filter)
if( not name ) then return end
local result = checkFilterAura(frame, type, isFriendly, name, texture, count, auraType, duration, endTime, caster, isRemovable, nameplateShowPersonal, spellID, canApplyAura, isBossDebuff)
if( not result ) then
checkSpecificAura(frame, type, name, texture, count, auraType, duration, endTime, caster, isRemovable, nameplateShowPersonal, spellID, canApplyAura, isBossDebuff)
end
auraList[name] = true
end
end
function Indicators:UpdateIndicators(frame)
for key, indicatorConfig in pairs(ShadowUF.db.profile.auraIndicators.indicators) do
local indicator = frame.auraIndicators[key]
if( indicator and indicator.enabled and indicator.priority and indicator.priority > -1 ) then
-- Show a cooldown ring
if( indicator.showDuration and indicator.spellDuration > 0 and indicator.spellEnd > 0 ) then
indicator.cooldown:SetCooldown(indicator.spellEnd - indicator.spellDuration, indicator.spellDuration)
else
indicator.cooldown:Hide()
end
-- Show either the icon, or a solid color
if( indicator.showIcon and indicator.spellIcon ) then
indicator.texture:SetTexture(indicator.spellIcon)
indicator:SetBackdropColor(0, 0, 0, 0)
else
indicator.texture:SetColorTexture(indicator.colorR, indicator.colorG, indicator.colorB)
indicator:SetBackdropColor(0, 0, 0, 1)
end
-- Show aura stack
if( indicator.showStack and indicator.spellStack > 1 ) then
indicator.stack:SetText(indicator.spellStack)
indicator.stack:Show()
else
indicator.stack:Hide()
end
indicator:Show()
else
indicator:Hide()
end
end
end
function Indicators:UpdateAuras(frame)
for k in pairs(auraList) do auraList[k] = nil end
for key, config in pairs(ShadowUF.db.profile.auraIndicators.indicators) do
local indicator = frame.auraIndicators[key]
if( indicator ) then
indicator.priority = -1
if( UnitIsEnemy(frame.unit, "player") ) then
indicator.enabled = config.hostile
else
indicator.enabled = config.friendly
end
end
end
-- If they are dead, don't bother showing any indicators yet
if( UnitIsDeadOrGhost(frame.unit) or not UnitIsConnected(frame.unit) ) then
self:UpdateIndicators(frame)
return
end
-- Scan auras
scanAuras(frame, "HELPFUL", "buffs")
scanAuras(frame, "HARMFUL", "debuffs")
-- Check for any indicators that are triggered due to something missing
for name in pairs(ShadowUF.db.profile.auraIndicators.missing) do
if( not auraList[name] and self.auraConfig[name] ) then
local aura = self.auraConfig[name]
local indicator = frame.auraIndicators[aura.indicator]
if( indicator and indicator.enabled and aura.priority > indicator.priority and not ShadowUF.db.profile.auraIndicators.disabled[playerClass][name] ) then
indicator.priority = aura.priority or -1
indicator.showIcon = aura.icon
indicator.showDuration = aura.duration
indicator.spellDuration = 0
indicator.spellEnd = 0
indicator.spellIcon = aura.iconTexture or select(3, GetSpellInfo(name))
indicator.colorR = aura.r
indicator.colorG = aura.g
indicator.colorB = aura.b
end
end
end
-- Now force the indicators to update
self:UpdateIndicators(frame)
end