1388 lines
50 KiB
Lua
1388 lines
50 KiB
Lua
|
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
|
|||
|
local mod = E:GetModule('NamePlates')
|
|||
|
local LSM = E.Libs.LSM
|
|||
|
|
|||
|
local _G = _G
|
|||
|
local ipairs, next, pairs, select = ipairs, next, pairs, select
|
|||
|
local setmetatable, tostring, tonumber, type, unpack = setmetatable, tostring, tonumber, type, unpack
|
|||
|
local strmatch, tinsert, tremove, sort, wipe = strmatch, tinsert, tremove, sort, wipe
|
|||
|
|
|||
|
local GetInstanceInfo = GetInstanceInfo
|
|||
|
local GetLocale = GetLocale
|
|||
|
local GetRaidTargetIndex = GetRaidTargetIndex
|
|||
|
local GetSpecializationInfo = GetSpecializationInfo
|
|||
|
local GetSpellCharges = GetSpellCharges
|
|||
|
local GetSpellCooldown = GetSpellCooldown
|
|||
|
local GetSpellInfo = GetSpellInfo
|
|||
|
local GetTalentInfo = GetTalentInfo
|
|||
|
local GetTime = GetTime
|
|||
|
local IsResting = IsResting
|
|||
|
local UnitPlayerControlled = UnitPlayerControlled
|
|||
|
local UnitAffectingCombat = UnitAffectingCombat
|
|||
|
local UnitCanAttack = UnitCanAttack
|
|||
|
local UnitExists = UnitExists
|
|||
|
local UnitHealth = UnitHealth
|
|||
|
local UnitHealthMax = UnitHealthMax
|
|||
|
local UnitInVehicle = UnitInVehicle
|
|||
|
local UnitIsOwnerOrControllerOfUnit = UnitIsOwnerOrControllerOfUnit
|
|||
|
local UnitIsPVP = UnitIsPVP
|
|||
|
local UnitIsQuestBoss = UnitIsQuestBoss
|
|||
|
local UnitIsTapDenied = UnitIsTapDenied
|
|||
|
local UnitIsUnit = UnitIsUnit
|
|||
|
local UnitLevel = UnitLevel
|
|||
|
local UnitPower = UnitPower
|
|||
|
local UnitPowerMax = UnitPowerMax
|
|||
|
local UnitThreatSituation = UnitThreatSituation
|
|||
|
|
|||
|
local C_Timer_NewTimer = C_Timer.NewTimer
|
|||
|
local C_SpecializationInfo_GetPvpTalentSlotInfo = C_SpecializationInfo.GetPvpTalentSlotInfo
|
|||
|
|
|||
|
local FallbackColor = {r=1, b=1, g=1}
|
|||
|
|
|||
|
mod.StyleFilterStackPattern = '([^\n]+)\n?(%d*)$'
|
|||
|
mod.TriggerConditions = {
|
|||
|
reactions = {'hated', 'hostile', 'unfriendly', 'neutral', 'friendly', 'honored', 'revered', 'exalted'},
|
|||
|
raidTargets = {'star', 'circle', 'diamond', 'triangle', 'moon', 'square', 'cross', 'skull'},
|
|||
|
tankThreat = {[0] = 3, 2, 1, 0},
|
|||
|
frameTypes = {
|
|||
|
FRIENDLY_PLAYER = 'friendlyPlayer',
|
|||
|
FRIENDLY_NPC = 'friendlyNPC',
|
|||
|
ENEMY_PLAYER = 'enemyPlayer',
|
|||
|
ENEMY_NPC = 'enemyNPC',
|
|||
|
PLAYER = 'player'
|
|||
|
},
|
|||
|
roles = {
|
|||
|
TANK = 'tank',
|
|||
|
HEALER = 'healer',
|
|||
|
DAMAGER = 'damager'
|
|||
|
},
|
|||
|
keys = {
|
|||
|
Modifier = IsModifierKeyDown,
|
|||
|
Shift = IsShiftKeyDown,
|
|||
|
Alt = IsAltKeyDown,
|
|||
|
Control = IsControlKeyDown,
|
|||
|
LeftShift = IsLeftShiftKeyDown,
|
|||
|
LeftAlt = IsLeftAltKeyDown,
|
|||
|
LeftControl = IsLeftControlKeyDown,
|
|||
|
RightShift = IsRightShiftKeyDown,
|
|||
|
RightAlt = IsRightAltKeyDown,
|
|||
|
RightControl = IsRightControlKeyDown,
|
|||
|
},
|
|||
|
threat = {
|
|||
|
[-3] = 'offTank',
|
|||
|
[-2] = 'offTankBadTransition',
|
|||
|
[-1] = 'offTankGoodTransition',
|
|||
|
[0] = 'good',
|
|||
|
[1] = 'badTransition',
|
|||
|
[2] = 'goodTransition',
|
|||
|
[3] = 'bad'
|
|||
|
},
|
|||
|
difficulties = {
|
|||
|
-- dungeons
|
|||
|
[1] = 'normal',
|
|||
|
[2] = 'heroic',
|
|||
|
[8] = 'mythic+',
|
|||
|
[23] = 'mythic',
|
|||
|
[24] = 'timewalking',
|
|||
|
-- raids
|
|||
|
[7] = 'lfr',
|
|||
|
[17] = 'lfr',
|
|||
|
[14] = 'normal',
|
|||
|
[15] = 'heroic',
|
|||
|
[16] = 'mythic',
|
|||
|
[33] = 'timewalking',
|
|||
|
[3] = 'legacy10normal',
|
|||
|
[4] = 'legacy25normal',
|
|||
|
[5] = 'legacy10heroic',
|
|||
|
[6] = 'legacy25heroic',
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
do -- E.CreatureTypes; Do *not* change the value, only the key (['key'] = 'value').
|
|||
|
local c, locale = {}, GetLocale()
|
|||
|
if locale == 'frFR' then
|
|||
|
c['Aberration'] = 'Aberration'
|
|||
|
c['Bête'] = 'Beast'
|
|||
|
c['Bestiole'] = 'Critter'
|
|||
|
c['Démon'] = 'Demon'
|
|||
|
c['Draconien'] = 'Dragonkin'
|
|||
|
c['Élémentaire'] = 'Elemental'
|
|||
|
c['Nuage de gaz'] = 'Gas Cloud'
|
|||
|
c['Géant'] = 'Giant'
|
|||
|
c['Humanoïde'] = 'Humanoid'
|
|||
|
c['Machine'] = 'Mechanical'
|
|||
|
c['Non spécifié'] = 'Not specified'
|
|||
|
c['Totem'] = 'Totem'
|
|||
|
c['Mort-vivant'] = 'Undead'
|
|||
|
c['Mascotte sauvage'] = 'Wild Pet'
|
|||
|
c['Familier pacifique'] = 'Non-combat Pet'
|
|||
|
elseif locale == 'deDE' then
|
|||
|
c['Anomalie'] = 'Aberration'
|
|||
|
c['Wildtier'] = 'Beast'
|
|||
|
c['Kleintier'] = 'Critter'
|
|||
|
c['Dämon'] = 'Demon'
|
|||
|
c['Drachkin'] = 'Dragonkin'
|
|||
|
c['Elementar'] = 'Elemental'
|
|||
|
c['Gaswolke'] = 'Gas Cloud'
|
|||
|
c['Riese'] = 'Giant'
|
|||
|
c['Humanoid'] = 'Humanoid'
|
|||
|
c['Mechanisch'] = 'Mechanical'
|
|||
|
c['Nicht spezifiziert'] = 'Not specified'
|
|||
|
c['Totem'] = 'Totem'
|
|||
|
c['Untoter'] = 'Undead'
|
|||
|
c['Ungezähmtes Tier'] = 'Wild Pet'
|
|||
|
c['Haustier'] = 'Non-combat Pet'
|
|||
|
elseif locale == 'koKR' then
|
|||
|
c['돌연변이'] = 'Aberration'
|
|||
|
c['야수'] = 'Beast'
|
|||
|
c['동물'] = 'Critter'
|
|||
|
c['악마'] = 'Demon'
|
|||
|
c['용족'] = 'Dragonkin'
|
|||
|
c['정령'] = 'Elemental'
|
|||
|
c['가스'] = 'Gas Cloud'
|
|||
|
c['거인'] = 'Giant'
|
|||
|
c['인간형'] = 'Humanoid'
|
|||
|
c['기계'] = 'Mechanical'
|
|||
|
c['기타'] = 'Not specified'
|
|||
|
c['토템'] = 'Totem'
|
|||
|
c['언데드'] = 'Undead'
|
|||
|
c['야생 애완동물'] = 'Wild Pet'
|
|||
|
c['애완동물'] = 'Non-combat Pet'
|
|||
|
elseif locale == 'ruRU' then
|
|||
|
c['Аберрация'] = 'Aberration'
|
|||
|
c['Животное'] = 'Beast'
|
|||
|
c['Существо'] = 'Critter'
|
|||
|
c['Демон'] = 'Demon'
|
|||
|
c['Дракон'] = 'Dragonkin'
|
|||
|
c['Элементаль'] = 'Elemental'
|
|||
|
c['Газовое облако'] = 'Gas Cloud'
|
|||
|
c['Великан'] = 'Giant'
|
|||
|
c['Гуманоид'] = 'Humanoid'
|
|||
|
c['Механизм'] = 'Mechanical'
|
|||
|
c['Не указано'] = 'Not specified'
|
|||
|
c['Тотем'] = 'Totem'
|
|||
|
c['Нежить'] = 'Undead'
|
|||
|
c['дикий питомец'] = 'Wild Pet'
|
|||
|
c['Спутник'] = 'Non-combat Pet'
|
|||
|
elseif locale == 'zhCN' then
|
|||
|
c['畸变'] = 'Aberration'
|
|||
|
c['野兽'] = 'Beast'
|
|||
|
c['小动物'] = 'Critter'
|
|||
|
c['恶魔'] = 'Demon'
|
|||
|
c['龙类'] = 'Dragonkin'
|
|||
|
c['元素生物'] = 'Elemental'
|
|||
|
c['气体云雾'] = 'Gas Cloud'
|
|||
|
c['巨人'] = 'Giant'
|
|||
|
c['人型生物'] = 'Humanoid'
|
|||
|
c['机械'] = 'Mechanical'
|
|||
|
c['未指定'] = 'Not specified'
|
|||
|
c['图腾'] = 'Totem'
|
|||
|
c['亡灵'] = 'Undead'
|
|||
|
c['野生宠物'] = 'Wild Pet'
|
|||
|
c['非战斗宠物'] = 'Non-combat Pet'
|
|||
|
elseif locale == 'zhTW' then
|
|||
|
c['畸變'] = 'Aberration'
|
|||
|
c['野獸'] = 'Beast'
|
|||
|
c['小動物'] = 'Critter'
|
|||
|
c['惡魔'] = 'Demon'
|
|||
|
c['龍類'] = 'Dragonkin'
|
|||
|
c['元素生物'] = 'Elemental'
|
|||
|
c['氣體雲'] = 'Gas Cloud'
|
|||
|
c['巨人'] = 'Giant'
|
|||
|
c['人型生物'] = 'Humanoid'
|
|||
|
c['機械'] = 'Mechanical'
|
|||
|
c['不明'] = 'Not specified'
|
|||
|
c['圖騰'] = 'Totem'
|
|||
|
c['不死族'] = 'Undead'
|
|||
|
c['野生寵物'] = 'Wild Pet'
|
|||
|
c['非戰鬥寵物'] = 'Non-combat Pet'
|
|||
|
elseif locale == 'esES' then
|
|||
|
c['Desviación'] = 'Aberration'
|
|||
|
c['Bestia'] = 'Beast'
|
|||
|
c['Alma'] = 'Critter'
|
|||
|
c['Demonio'] = 'Demon'
|
|||
|
c['Dragon'] = 'Dragonkin'
|
|||
|
c['Elemental'] = 'Elemental'
|
|||
|
c['Nube de Gas'] = 'Gas Cloud'
|
|||
|
c['Gigante'] = 'Giant'
|
|||
|
c['Humanoide'] = 'Humanoid'
|
|||
|
c['Mecánico'] = 'Mechanical'
|
|||
|
c['No especificado'] = 'Not specified'
|
|||
|
c['Tótem'] = 'Totem'
|
|||
|
c['No-muerto'] = 'Undead'
|
|||
|
c['Mascota salvaje'] = 'Wild Pet'
|
|||
|
c['Mascota no combatiente'] = 'Non-combat Pet'
|
|||
|
elseif locale == 'esMX' then
|
|||
|
c['Desviación'] = 'Aberration'
|
|||
|
c['Bestia'] = 'Beast'
|
|||
|
c['Alma'] = 'Critter'
|
|||
|
c['Demonio'] = 'Demon'
|
|||
|
c['Dragón'] = 'Dragonkin'
|
|||
|
c['Elemental'] = 'Elemental'
|
|||
|
c['Nube de Gas'] = 'Gas Cloud'
|
|||
|
c['Gigante'] = 'Giant'
|
|||
|
c['Humanoide'] = 'Humanoid'
|
|||
|
c['Mecánico'] = 'Mechanical'
|
|||
|
c['Sin especificar'] = 'Not specified'
|
|||
|
c['Totém'] = 'Totem'
|
|||
|
c['No-muerto'] = 'Undead'
|
|||
|
c['Mascota salvaje'] = 'Wild Pet'
|
|||
|
c['Mascota mansa'] = 'Non-combat Pet'
|
|||
|
elseif locale == 'ptBR' then
|
|||
|
c['Aberração'] = 'Aberration'
|
|||
|
c['Fera'] = 'Beast'
|
|||
|
c['Bicho'] = 'Critter'
|
|||
|
c['Demônio'] = 'Demon'
|
|||
|
c['Dracônico'] = 'Dragonkin'
|
|||
|
c['Elemental'] = 'Elemental'
|
|||
|
c['Gasoso'] = 'Gas Cloud'
|
|||
|
c['Gigante'] = 'Giant'
|
|||
|
c['Humanoide'] = 'Humanoid'
|
|||
|
c['Mecânico'] = 'Mechanical'
|
|||
|
c['Não especificado'] = 'Not specified'
|
|||
|
c['Totem'] = 'Totem'
|
|||
|
c['Renegado'] = 'Undead'
|
|||
|
c['Mascote Selvagem'] = 'Wild Pet'
|
|||
|
c['Mascote não-combatente'] = 'Non-combat Pet'
|
|||
|
elseif locale == 'itIT' then
|
|||
|
c['Aberrazione'] = 'Aberration'
|
|||
|
c['Bestia'] = 'Beast'
|
|||
|
c['Animale'] = 'Critter'
|
|||
|
c['Demone'] = 'Demon'
|
|||
|
c['Dragoide'] = 'Dragonkin'
|
|||
|
c['Elementale'] = 'Elemental'
|
|||
|
c['Nube di Gas'] = 'Gas Cloud'
|
|||
|
c['Gigante'] = 'Giant'
|
|||
|
c['Umanoide'] = 'Humanoid'
|
|||
|
c['Meccanico'] = 'Mechanical'
|
|||
|
c['Non Specificato'] = 'Not specified'
|
|||
|
c['Totem'] = 'Totem'
|
|||
|
c['Non Morto'] = 'Undead'
|
|||
|
c['Mascotte selvatica'] = 'Wild Pet'
|
|||
|
c['Animale Non combattente'] = 'Non-combat Pet'
|
|||
|
else -- enUS
|
|||
|
c['Aberration'] = 'Aberration'
|
|||
|
c['Beast'] = 'Beast'
|
|||
|
c['Critter'] = 'Critter'
|
|||
|
c['Demon'] = 'Demon'
|
|||
|
c['Dragonkin'] = 'Dragonkin'
|
|||
|
c['Elemental'] = 'Elemental'
|
|||
|
c['Gas Cloud'] = 'Gas Cloud'
|
|||
|
c['Giant'] = 'Giant'
|
|||
|
c['Humanoid'] = 'Humanoid'
|
|||
|
c['Mechanical'] = 'Mechanical'
|
|||
|
c['Not specified'] = 'Not specified'
|
|||
|
c['Totem'] = 'Totem'
|
|||
|
c['Undead'] = 'Undead'
|
|||
|
c['Wild Pet'] = 'Wild Pet'
|
|||
|
c['Non-combat Pet'] = 'Non-combat Pet'
|
|||
|
end
|
|||
|
|
|||
|
E.CreatureTypes = c
|
|||
|
end
|
|||
|
|
|||
|
function mod:StyleFilterTickerCallback(frame, button, timer)
|
|||
|
if frame and frame:IsShown() then
|
|||
|
mod:StyleFilterUpdate(frame, 'FAKE_AuraWaitTimer')
|
|||
|
end
|
|||
|
|
|||
|
if button and button[timer] then
|
|||
|
button[timer]:Cancel()
|
|||
|
button[timer] = nil
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
function mod:StyleFilterTickerCreate(delay, frame, button, timer)
|
|||
|
return C_Timer_NewTimer(delay, function() mod:StyleFilterTickerCallback(frame, button, timer) end)
|
|||
|
end
|
|||
|
|
|||
|
function mod:StyleFilterAuraWait(frame, button, timer, timeLeft, mTimeLeft)
|
|||
|
if button and not button[timer] then
|
|||
|
local updateIn = timeLeft-mTimeLeft
|
|||
|
if updateIn > 0 then -- also add a tenth of a second to updateIn to prevent the timer from firing on the same second
|
|||
|
button[timer] = mod:StyleFilterTickerCreate(updateIn+0.1, frame, button, timer)
|
|||
|
end
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
function mod:StyleFilterAuraCheck(frame, names, auras, mustHaveAll, missing, minTimeLeft, maxTimeLeft)
|
|||
|
local total, count = 0, 0
|
|||
|
for name, value in pairs(names) do
|
|||
|
if value then -- only if they are turned on
|
|||
|
total = total + 1 -- keep track of the names
|
|||
|
|
|||
|
if auras.createdIcons and auras.createdIcons > 0 then
|
|||
|
for i = 1, auras.createdIcons do
|
|||
|
local button = auras[i]
|
|||
|
if button then
|
|||
|
if button:IsShown() then
|
|||
|
local spell, stacks, failed = strmatch(name, mod.StyleFilterStackPattern)
|
|||
|
if stacks ~= '' then failed = not (button.stackCount and button.stackCount >= tonumber(stacks)) end
|
|||
|
if not failed and ((button.name and button.name == spell) or (button.spellID and button.spellID == tonumber(spell))) then
|
|||
|
local hasMinTime = minTimeLeft and minTimeLeft ~= 0
|
|||
|
local hasMaxTime = maxTimeLeft and maxTimeLeft ~= 0
|
|||
|
local timeLeft = (hasMinTime or hasMaxTime) and button.expiration and (button.expiration - GetTime())
|
|||
|
local minTimeAllow = not hasMinTime or (timeLeft and timeLeft > minTimeLeft)
|
|||
|
local maxTimeAllow = not hasMaxTime or (timeLeft and timeLeft < maxTimeLeft)
|
|||
|
if timeLeft then -- if we use a min/max time setting; we must create a delay timer
|
|||
|
if hasMinTime then mod:StyleFilterAuraWait(frame, button, 'hasMinTimer', timeLeft, minTimeLeft) end
|
|||
|
if hasMaxTime then mod:StyleFilterAuraWait(frame, button, 'hasMaxTimer', timeLeft, maxTimeLeft) end
|
|||
|
end
|
|||
|
if minTimeAllow and maxTimeAllow then
|
|||
|
count = count + 1 -- keep track of how many matches we have
|
|||
|
end
|
|||
|
end
|
|||
|
else -- cancel stale timers
|
|||
|
if button.hasMinTimer then button.hasMinTimer:Cancel() button.hasMinTimer = nil end
|
|||
|
if button.hasMaxTimer then button.hasMaxTimer:Cancel() button.hasMaxTimer = nil end
|
|||
|
end end end end end end
|
|||
|
|
|||
|
if total == 0 then
|
|||
|
return nil -- If no auras are checked just pass nil, we dont need to run the filter here.
|
|||
|
else
|
|||
|
return ((mustHaveAll and not missing) and total == count) -- [x] Check for all [ ] Missing: total needs to match count
|
|||
|
or ((not mustHaveAll and not missing) and count > 0) -- [ ] Check for all [ ] Missing: count needs to be greater than zero
|
|||
|
or ((not mustHaveAll and missing) and count == 0) -- [ ] Check for all [x] Missing: count needs to be zero
|
|||
|
or ((mustHaveAll and missing) and total ~= count) -- [x] Check for all [x] Missing: count must not match total
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
function mod:StyleFilterCooldownCheck(names, mustHaveAll)
|
|||
|
local _, gcd = GetSpellCooldown(61304)
|
|||
|
local total, count = 0, 0
|
|||
|
|
|||
|
for name, value in pairs(names) do
|
|||
|
if GetSpellInfo(name) then -- check spell name valid, GetSpellCharges/GetSpellCooldown will return nil if not known by your class
|
|||
|
if value == 'ONCD' or value == 'OFFCD' then -- only if they are turned on
|
|||
|
total = total + 1 -- keep track of the names
|
|||
|
|
|||
|
local charges = GetSpellCharges(name)
|
|||
|
local _, duration = GetSpellCooldown(name)
|
|||
|
|
|||
|
if (charges and charges == 0 and value == 'ONCD') -- charges exist and the current number of charges is 0 means that it is completely on cooldown.
|
|||
|
or (charges and charges > 0 and value == 'OFFCD') -- charges exist and the current number of charges is greater than 0 means it is not on cooldown.
|
|||
|
or (charges == nil and (duration > gcd and value == 'ONCD')) -- no charges exist and the duration of the cooldown is greater than the GCD spells current cooldown then it is on cooldown.
|
|||
|
or (charges == nil and (duration <= gcd and value == 'OFFCD')) then -- no charges exist and the duration of the cooldown is at or below the current GCD cooldown spell then it is not on cooldown.
|
|||
|
count = count + 1
|
|||
|
-- print(((charges and charges == 0 and value == 'ONCD') and name..' (charge) passes because it is on cd') or ((charges and charges > 0 and value == 'OFFCD') and name..' (charge) passes because it is offcd') or ((charges == nil and (duration > gcd and value == 'ONCD')) and name..'passes because it is on cd.') or ((charges == nil and (duration <= gcd and value == 'OFFCD')) and name..' passes because it is off cd.'))
|
|||
|
end end end end
|
|||
|
|
|||
|
if total == 0 then
|
|||
|
return nil
|
|||
|
else
|
|||
|
return (mustHaveAll and total == count) or (not mustHaveAll and count > 0)
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
function mod:StyleFilterFinishedFlash(requested)
|
|||
|
if not requested then self:Play() end
|
|||
|
end
|
|||
|
|
|||
|
function mod:StyleFilterSetupFlash(FlashTexture)
|
|||
|
local anim = FlashTexture:CreateAnimationGroup('Flash')
|
|||
|
anim:SetScript('OnFinished', mod.StyleFilterFinishedFlash)
|
|||
|
FlashTexture.anim = anim
|
|||
|
|
|||
|
local fadein = anim:CreateAnimation('ALPHA', 'FadeIn')
|
|||
|
fadein:SetFromAlpha(0)
|
|||
|
fadein:SetToAlpha(1)
|
|||
|
fadein:SetOrder(2)
|
|||
|
anim.fadein = fadein
|
|||
|
|
|||
|
local fadeout = anim:CreateAnimation('ALPHA', 'FadeOut')
|
|||
|
fadeout:SetFromAlpha(1)
|
|||
|
fadeout:SetToAlpha(0)
|
|||
|
fadeout:SetOrder(1)
|
|||
|
anim.fadeout = fadeout
|
|||
|
|
|||
|
return anim
|
|||
|
end
|
|||
|
|
|||
|
function mod:StyleFilterUpdatePlate(frame, updateBase)
|
|||
|
if updateBase then
|
|||
|
mod:UpdatePlate(frame, true) -- enable elements back
|
|||
|
end
|
|||
|
|
|||
|
if frame.frameType then
|
|||
|
local db = mod:PlateDB(frame)
|
|||
|
if db.health.enable then frame.Health:ForceUpdate() end
|
|||
|
if db.power.enable then frame.Power:ForceUpdate() end
|
|||
|
end
|
|||
|
|
|||
|
if mod.db.threat.enable and mod.db.threat.useThreatColor and not UnitIsTapDenied(frame.unit) then
|
|||
|
frame.ThreatIndicator:ForceUpdate() -- this will account for the threat health color
|
|||
|
end
|
|||
|
|
|||
|
mod:PlateFade(frame, mod.db.fadeIn and 1 or 0, 0, 1) -- fade those back in so it looks clean
|
|||
|
end
|
|||
|
|
|||
|
function mod:StyleFilterBorderLock(backdrop, r, g, b, a)
|
|||
|
if r then
|
|||
|
backdrop.forcedBorderColors = {r,g,b,a}
|
|||
|
backdrop:SetBackdropBorderColor(r,g,b,a)
|
|||
|
else
|
|||
|
backdrop.forcedBorderColors = nil
|
|||
|
backdrop:SetBackdropBorderColor(unpack(E.media.bordercolor))
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
do
|
|||
|
local empty = {}
|
|||
|
function mod:StyleFilterChanges(frame)
|
|||
|
return (frame and frame.StyleFilterChanges) or empty
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
function mod:StyleFilterSetChanges(frame, actions, HealthColor, PowerColor, Borders, HealthFlash, HealthTexture, Scale, Alpha, NameTag, PowerTag, HealthTag, TitleTag, LevelTag, Portrait, NameOnly, Visibility)
|
|||
|
local c = frame.StyleFilterChanges
|
|||
|
if not c then return end
|
|||
|
|
|||
|
local db = mod:PlateDB(frame)
|
|||
|
|
|||
|
if Visibility then
|
|||
|
c.Visibility = true
|
|||
|
mod:DisablePlate(frame) -- disable the plate elements
|
|||
|
frame:ClearAllPoints() -- lets still move the frame out cause its clickable otherwise
|
|||
|
frame:Point('TOP', E.UIParent, 'BOTTOM', 0, -500)
|
|||
|
return -- We hide it. Lets not do other things (no point)
|
|||
|
end
|
|||
|
if HealthColor then
|
|||
|
local hc = actions.color.healthColor
|
|||
|
c.HealthColor = hc -- used by Health_UpdateColor
|
|||
|
|
|||
|
frame.Health:SetStatusBarColor(hc.r, hc.g, hc.b, hc.a)
|
|||
|
frame.Cutaway.Health:SetVertexColor(hc.r * 1.5, hc.g * 1.5, hc.b * 1.5, hc.a)
|
|||
|
end
|
|||
|
if PowerColor then
|
|||
|
local pc = actions.color.powerColor
|
|||
|
c.PowerColor = true
|
|||
|
|
|||
|
frame.Power:SetStatusBarColor(pc.r, pc.g, pc.b, pc.a)
|
|||
|
frame.Cutaway.Power:SetVertexColor(pc.r * 1.5, pc.g * 1.5, pc.b * 1.5, pc.a)
|
|||
|
end
|
|||
|
if Borders then
|
|||
|
local bc = actions.color.borderColor
|
|||
|
c.Borders = true
|
|||
|
|
|||
|
mod:StyleFilterBorderLock(frame.Health.backdrop, bc.r, bc.g, bc.b, bc.a)
|
|||
|
|
|||
|
if frame.Power.backdrop and (frame.frameType and db.power and db.power.enable) then
|
|||
|
mod:StyleFilterBorderLock(frame.Power.backdrop, bc.r, bc.g, bc.b, bc.a)
|
|||
|
end
|
|||
|
end
|
|||
|
if HealthFlash then
|
|||
|
local fc = actions.flash.color
|
|||
|
c.HealthFlash = true
|
|||
|
|
|||
|
if not HealthTexture then frame.HealthFlashTexture:SetTexture(LSM:Fetch('statusbar', mod.db.statusbar)) end
|
|||
|
frame.HealthFlashTexture:SetVertexColor(fc.r, fc.g, fc.b)
|
|||
|
|
|||
|
local anim = frame.HealthFlashTexture.anim or mod:StyleFilterSetupFlash(frame.HealthFlashTexture)
|
|||
|
anim.fadein:SetToAlpha(fc.a)
|
|||
|
anim.fadeout:SetFromAlpha(fc.a)
|
|||
|
|
|||
|
frame.HealthFlashTexture:Show()
|
|||
|
E:Flash(frame.HealthFlashTexture, actions.flash.speed * 0.1, true)
|
|||
|
end
|
|||
|
if HealthTexture then
|
|||
|
local tx = LSM:Fetch('statusbar', actions.texture.texture)
|
|||
|
c.HealthTexture = true
|
|||
|
|
|||
|
frame.Highlight.texture:SetTexture(tx)
|
|||
|
frame.Health:SetStatusBarTexture(tx)
|
|||
|
if HealthFlash then frame.HealthFlashTexture:SetTexture(tx) end
|
|||
|
end
|
|||
|
if Scale then
|
|||
|
c.Scale = true
|
|||
|
mod:ScalePlate(frame, actions.scale)
|
|||
|
end
|
|||
|
if Alpha then
|
|||
|
c.Alpha = true
|
|||
|
mod:PlateFade(frame, mod.db.fadeIn and 1 or 0, frame:GetAlpha(), actions.alpha / 100)
|
|||
|
end
|
|||
|
if Portrait then
|
|||
|
c.Portrait = true
|
|||
|
mod:Update_Portrait(frame)
|
|||
|
frame.Portrait:ForceUpdate()
|
|||
|
end
|
|||
|
if NameOnly then
|
|||
|
c.NameOnly = true
|
|||
|
mod:DisablePlate(frame, true)
|
|||
|
end
|
|||
|
-- Keeps Tag changes after NameOnly
|
|||
|
if NameTag then
|
|||
|
c.NameTag = true
|
|||
|
frame:Tag(frame.Name, actions.tags.name)
|
|||
|
frame.Name:UpdateTag()
|
|||
|
end
|
|||
|
if PowerTag then
|
|||
|
c.PowerTag = true
|
|||
|
frame:Tag(frame.Power.Text, actions.tags.power)
|
|||
|
frame.Power.Text:UpdateTag()
|
|||
|
end
|
|||
|
if HealthTag then
|
|||
|
c.HealthTag = true
|
|||
|
frame:Tag(frame.Health.Text, actions.tags.health)
|
|||
|
frame.Health.Text:UpdateTag()
|
|||
|
end
|
|||
|
if TitleTag then
|
|||
|
c.TitleTag = true
|
|||
|
frame:Tag(frame.Title, actions.tags.title)
|
|||
|
frame.Title:UpdateTag()
|
|||
|
end
|
|||
|
if LevelTag then
|
|||
|
c.LevelTag = true
|
|||
|
frame:Tag(frame.Level, actions.tags.level)
|
|||
|
frame.Level:UpdateTag()
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
function mod:StyleFilterClearChanges(frame, updateBase, HealthColor, PowerColor, Borders, HealthFlash, HealthTexture, Scale, Alpha, NameTag, PowerTag, HealthTag, TitleTag, LevelTag, Portrait, NameOnly, Visibility)
|
|||
|
local db = mod:PlateDB(frame)
|
|||
|
|
|||
|
if frame.StyleFilterChanges then
|
|||
|
wipe(frame.StyleFilterChanges)
|
|||
|
end
|
|||
|
|
|||
|
if Visibility then
|
|||
|
mod:StyleFilterUpdatePlate(frame, updateBase)
|
|||
|
frame:ClearAllPoints() -- pull the frame back in
|
|||
|
frame:Point('CENTER')
|
|||
|
end
|
|||
|
if HealthColor then
|
|||
|
local h = frame.Health
|
|||
|
if h.r and h.g and h.b then
|
|||
|
h:SetStatusBarColor(h.r, h.g, h.b)
|
|||
|
frame.Cutaway.Health:SetVertexColor(h.r * 1.5, h.g * 1.5, h.b * 1.5, 1)
|
|||
|
end
|
|||
|
end
|
|||
|
if PowerColor then
|
|||
|
local pc = E.db.unitframe.colors.power[frame.Power.token] or _G.PowerBarColor[frame.Power.token] or FallbackColor
|
|||
|
frame.Power:SetStatusBarColor(pc.r, pc.g, pc.b)
|
|||
|
frame.Cutaway.Power:SetVertexColor(pc.r * 1.5, pc.g * 1.5, pc.b * 1.5, 1)
|
|||
|
end
|
|||
|
if Borders then
|
|||
|
mod:StyleFilterBorderLock(frame.Health.backdrop)
|
|||
|
|
|||
|
if frame.Power.backdrop and (frame.frameType and db.power and db.power.enable) then
|
|||
|
mod:StyleFilterBorderLock(frame.Power.backdrop)
|
|||
|
end
|
|||
|
end
|
|||
|
if HealthFlash then
|
|||
|
E:StopFlash(frame.HealthFlashTexture)
|
|||
|
frame.HealthFlashTexture:Hide()
|
|||
|
end
|
|||
|
if HealthTexture then
|
|||
|
local tx = LSM:Fetch('statusbar', mod.db.statusbar)
|
|||
|
frame.Highlight.texture:SetTexture(tx)
|
|||
|
frame.Health:SetStatusBarTexture(tx)
|
|||
|
end
|
|||
|
if Scale then
|
|||
|
mod:ScalePlate(frame, frame.ThreatScale or 1)
|
|||
|
end
|
|||
|
if Alpha then
|
|||
|
mod:PlateFade(frame, mod.db.fadeIn and 1 or 0, (frame.FadeObject and frame.FadeObject.endAlpha) or 0.5, 1)
|
|||
|
end
|
|||
|
if Portrait then
|
|||
|
mod:Update_Portrait(frame)
|
|||
|
frame.Portrait:ForceUpdate()
|
|||
|
end
|
|||
|
if NameOnly then
|
|||
|
mod:StyleFilterUpdatePlate(frame, updateBase)
|
|||
|
else -- Only update these if it wasn't NameOnly. Otherwise, it leads to `Update_Tags` which does the job.
|
|||
|
if NameTag then frame:Tag(frame.Name, db.name.format) frame.Name:UpdateTag() end
|
|||
|
if PowerTag then frame:Tag(frame.Power.Text, db.power.text.format) frame.Power.Text:UpdateTag() end
|
|||
|
if HealthTag then frame:Tag(frame.Health.Text, db.health.text.format) frame.Health.Text:UpdateTag() end
|
|||
|
if TitleTag then frame:Tag(frame.Title, db.title.format) frame.Title:UpdateTag() end
|
|||
|
if LevelTag then frame:Tag(frame.Level, db.level.format) frame.Level:UpdateTag() end
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
function mod:StyleFilterThreatUpdate(frame, unit)
|
|||
|
if mod:UnitExists(unit) then
|
|||
|
local isTank, offTank, feedbackUnit = mod.ThreatIndicator_PreUpdate(frame.ThreatIndicator, unit, true)
|
|||
|
if feedbackUnit and (feedbackUnit ~= unit) and mod:UnitExists(feedbackUnit) then
|
|||
|
return isTank, offTank, UnitThreatSituation(feedbackUnit, unit)
|
|||
|
else
|
|||
|
return isTank, offTank, UnitThreatSituation(unit)
|
|||
|
end
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
function mod:StyleFilterConditionCheck(frame, filter, trigger)
|
|||
|
local passed -- skip StyleFilterPass when triggers are empty
|
|||
|
|
|||
|
-- Health
|
|||
|
if trigger.healthThreshold then
|
|||
|
local healthUnit = (trigger.healthUsePlayer and 'player') or frame.unit
|
|||
|
local health, maxHealth = UnitHealth(healthUnit), UnitHealthMax(healthUnit)
|
|||
|
local percHealth = (maxHealth and (maxHealth > 0) and health/maxHealth) or 0
|
|||
|
local underHealthThreshold = trigger.underHealthThreshold and (trigger.underHealthThreshold ~= 0) and (trigger.underHealthThreshold > percHealth)
|
|||
|
local overHealthThreshold = trigger.overHealthThreshold and (trigger.overHealthThreshold ~= 0) and (trigger.overHealthThreshold < percHealth)
|
|||
|
if underHealthThreshold or overHealthThreshold then passed = true else return end
|
|||
|
end
|
|||
|
|
|||
|
-- Power
|
|||
|
if trigger.powerThreshold then
|
|||
|
local powerUnit = (trigger.powerUsePlayer and 'player') or frame.unit
|
|||
|
local power, maxPower = UnitPower(powerUnit, frame.PowerType), UnitPowerMax(powerUnit, frame.PowerType)
|
|||
|
local percPower = (maxPower and (maxPower > 0) and power/maxPower) or 0
|
|||
|
local underPowerThreshold = trigger.underPowerThreshold and (trigger.underPowerThreshold ~= 0) and (trigger.underPowerThreshold > percPower)
|
|||
|
local overPowerThreshold = trigger.overPowerThreshold and (trigger.overPowerThreshold ~= 0) and (trigger.overPowerThreshold < percPower)
|
|||
|
if underPowerThreshold or overPowerThreshold then passed = true else return end
|
|||
|
end
|
|||
|
|
|||
|
-- Level
|
|||
|
if trigger.level then
|
|||
|
local myLevel = E.mylevel
|
|||
|
local level = (frame.unit == 'player' and myLevel) or UnitLevel(frame.unit)
|
|||
|
local curLevel = (trigger.curlevel and trigger.curlevel ~= 0 and (trigger.curlevel == level))
|
|||
|
local minLevel = (trigger.minlevel and trigger.minlevel ~= 0 and (trigger.minlevel <= level))
|
|||
|
local maxLevel = (trigger.maxlevel and trigger.maxlevel ~= 0 and (trigger.maxlevel >= level))
|
|||
|
local matchMyLevel = trigger.mylevel and (level == myLevel)
|
|||
|
if curLevel or minLevel or maxLevel or matchMyLevel then passed = true else return end
|
|||
|
end
|
|||
|
|
|||
|
-- Resting
|
|||
|
if trigger.isResting then
|
|||
|
if IsResting() then passed = true else return end
|
|||
|
end
|
|||
|
|
|||
|
-- Quest Boss
|
|||
|
if trigger.questBoss then
|
|||
|
if UnitIsQuestBoss(frame.unit) then passed = true else return end
|
|||
|
end
|
|||
|
|
|||
|
-- Quest Unit
|
|||
|
if trigger.isQuest or trigger.notQuest then
|
|||
|
local quest = E.TagFunctions.GetQuestData(frame.unit)
|
|||
|
if (trigger.isQuest and quest) or (trigger.notQuest and not quest) then passed = true else return end
|
|||
|
end
|
|||
|
|
|||
|
-- Require Target
|
|||
|
if trigger.requireTarget then
|
|||
|
if UnitExists('target') then passed = true else return end
|
|||
|
end
|
|||
|
|
|||
|
-- Player Combat
|
|||
|
if trigger.inCombat or trigger.outOfCombat then
|
|||
|
local inCombat = UnitAffectingCombat('player')
|
|||
|
if (trigger.inCombat and inCombat) or (trigger.outOfCombat and not inCombat) then passed = true else return end
|
|||
|
end
|
|||
|
|
|||
|
-- Unit Combat
|
|||
|
if trigger.inCombatUnit or trigger.outOfCombatUnit then
|
|||
|
local inCombat = UnitAffectingCombat(frame.unit)
|
|||
|
if (trigger.inCombatUnit and inCombat) or (trigger.outOfCombatUnit and not inCombat) then passed = true else return end
|
|||
|
end
|
|||
|
|
|||
|
-- Player Target
|
|||
|
if trigger.isTarget or trigger.notTarget then
|
|||
|
if (trigger.isTarget and frame.isTarget) or (trigger.notTarget and not frame.isTarget) then passed = true else return end
|
|||
|
end
|
|||
|
|
|||
|
-- Unit Target
|
|||
|
if trigger.targetMe or trigger.notTargetMe then
|
|||
|
if (trigger.targetMe and frame.isTargetingMe) or (trigger.notTargetMe and not frame.isTargetingMe) then passed = true else return end
|
|||
|
end
|
|||
|
|
|||
|
-- Unit Focus
|
|||
|
if trigger.isFocus or trigger.notFocus then
|
|||
|
if (trigger.isFocus and frame.isFocused) or (trigger.notFocus and not frame.isFocused) then passed = true else return end
|
|||
|
end
|
|||
|
|
|||
|
-- Unit Pet
|
|||
|
if trigger.isPet or trigger.isNotPet then
|
|||
|
if (trigger.isPet and frame.isPet or trigger.isNotPet and not frame.isPet) then passed = true else return end
|
|||
|
end
|
|||
|
|
|||
|
-- Unit Player Controlled
|
|||
|
if trigger.isPlayerControlled or trigger.isNotPlayerControlled then
|
|||
|
local playerControlled = UnitPlayerControlled(frame.unit) and not frame.isPlayer
|
|||
|
if (trigger.isPlayerControlled and playerControlled or trigger.isNotPlayerControlled and not playerControlled) then passed = true else return end
|
|||
|
end
|
|||
|
|
|||
|
-- Unit Owned By Player
|
|||
|
if trigger.isOwnedByPlayer or trigger.isNotOwnedByPlayer then
|
|||
|
local ownedByPlayer = UnitIsOwnerOrControllerOfUnit('player', frame.unit)
|
|||
|
if (trigger.isOwnedByPlayer and ownedByPlayer or trigger.isNotOwnedByPlayer and not ownedByPlayer) then passed = true else return end
|
|||
|
end
|
|||
|
|
|||
|
-- Unit PvP
|
|||
|
if trigger.isPvP or trigger.isNotPvP then
|
|||
|
local isPvP = UnitIsPVP(frame.unit)
|
|||
|
if (trigger.isPvP and isPvP or trigger.isNotPvP and not isPvP) then passed = true else return end
|
|||
|
end
|
|||
|
|
|||
|
-- Unit Tap Denied
|
|||
|
if trigger.isTapDenied or trigger.isNotTapDenied then
|
|||
|
local tapDenied = UnitIsTapDenied(frame.unit)
|
|||
|
if (trigger.isTapDenied and tapDenied) or (trigger.isNotTapDenied and not tapDenied) then passed = true else return end
|
|||
|
end
|
|||
|
|
|||
|
-- Player Vehicle
|
|||
|
if trigger.inVehicle or trigger.outOfVehicle then
|
|||
|
local inVehicle = UnitInVehicle('player')
|
|||
|
if (trigger.inVehicle and inVehicle) or (trigger.outOfVehicle and not inVehicle) then passed = true else return end
|
|||
|
end
|
|||
|
|
|||
|
-- Unit Vehicle
|
|||
|
if trigger.inVehicleUnit or trigger.outOfVehicleUnit then
|
|||
|
if (trigger.inVehicleUnit and frame.inVehicle) or (trigger.outOfVehicleUnit and not frame.inVehicle) then passed = true else return end
|
|||
|
end
|
|||
|
|
|||
|
-- Player Can Attack
|
|||
|
if trigger.playerCanAttack or trigger.playerCanNotAttack then
|
|||
|
local canAttack = UnitCanAttack('player', frame.unit)
|
|||
|
if (trigger.playerCanAttack and canAttack) or (trigger.playerCanNotAttack and not canAttack) then passed = true else return end
|
|||
|
end
|
|||
|
|
|||
|
-- NPC Title
|
|||
|
if trigger.hasTitleNPC or trigger.noTitleNPC then
|
|||
|
local npcTitle = E.TagFunctions.GetTitleNPC(frame.unit)
|
|||
|
if (trigger.hasTitleNPC and npcTitle) or (trigger.noTitleNPC and not npcTitle) then passed = true else return end
|
|||
|
end
|
|||
|
|
|||
|
-- Classification
|
|||
|
if trigger.classification.worldboss or trigger.classification.rareelite or trigger.classification.elite or trigger.classification.rare or trigger.classification.normal or trigger.classification.trivial or trigger.classification.minus then
|
|||
|
if trigger.classification[frame.classification] then passed = true else return end
|
|||
|
end
|
|||
|
|
|||
|
-- Group Role
|
|||
|
if trigger.role.tank or trigger.role.healer or trigger.role.damager then
|
|||
|
if trigger.role[mod.TriggerConditions.roles[E.myrole]] then passed = true else return end
|
|||
|
end
|
|||
|
|
|||
|
-- Unit Type
|
|||
|
if trigger.nameplateType and trigger.nameplateType.enable then
|
|||
|
if trigger.nameplateType[mod.TriggerConditions.frameTypes[frame.frameType]] then passed = true else return end
|
|||
|
end
|
|||
|
|
|||
|
-- Creature Type
|
|||
|
if trigger.creatureType and trigger.creatureType.enable then
|
|||
|
if trigger.creatureType[E.CreatureTypes[frame.creatureType]] then passed = true else return end
|
|||
|
end
|
|||
|
|
|||
|
-- Key Modifier
|
|||
|
if trigger.keyMod and trigger.keyMod.enable then
|
|||
|
for key, value in pairs(trigger.keyMod) do
|
|||
|
local isDown = mod.TriggerConditions.keys[key]
|
|||
|
if value and isDown then
|
|||
|
if isDown() then passed = true else return end
|
|||
|
end
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
-- Reaction (or Reputation) Type
|
|||
|
if trigger.reactionType and trigger.reactionType.enable then
|
|||
|
if trigger.reactionType[mod.TriggerConditions.reactions[(trigger.reactionType.reputation and frame.repReaction) or frame.reaction]] then passed = true else return end
|
|||
|
end
|
|||
|
|
|||
|
-- Threat
|
|||
|
if trigger.threat and trigger.threat.enable then
|
|||
|
if trigger.threat.good or trigger.threat.goodTransition or trigger.threat.badTransition or trigger.threat.bad or trigger.threat.offTank or trigger.threat.offTankGoodTransition or trigger.threat.offTankBadTransition then
|
|||
|
local isTank, offTank, threat = mod:StyleFilterThreatUpdate(frame, frame.unit)
|
|||
|
local checkOffTank = trigger.threat.offTank or trigger.threat.offTankGoodTransition or trigger.threat.offTankBadTransition
|
|||
|
local status = (checkOffTank and offTank and threat and -threat) or (not checkOffTank and ((isTank and mod.TriggerConditions.tankThreat[threat]) or threat)) or nil
|
|||
|
if trigger.threat[mod.TriggerConditions.threat[status]] then passed = true else return end
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
-- Raid Target
|
|||
|
if trigger.raidTarget.star or trigger.raidTarget.circle or trigger.raidTarget.diamond or trigger.raidTarget.triangle or trigger.raidTarget.moon or trigger.raidTarget.square or trigger.raidTarget.cross or trigger.raidTarget.skull then
|
|||
|
if trigger.raidTarget[mod.TriggerConditions.raidTargets[frame.RaidTargetIndex]] then passed = true else return end
|
|||
|
end
|
|||
|
|
|||
|
-- Class and Specialization
|
|||
|
if trigger.class and next(trigger.class) then
|
|||
|
local Class = trigger.class[E.myclass]
|
|||
|
if not Class or (Class.specs and next(Class.specs) and not Class.specs[E.myspec and GetSpecializationInfo(E.myspec)]) then
|
|||
|
return
|
|||
|
else
|
|||
|
passed = true
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
do
|
|||
|
local activeID = trigger.location.instanceIDEnabled
|
|||
|
local activeType = trigger.instanceType.none or trigger.instanceType.scenario or trigger.instanceType.party or trigger.instanceType.raid or trigger.instanceType.arena or trigger.instanceType.pvp
|
|||
|
local instanceName, instanceType, difficultyID, instanceID, _
|
|||
|
|
|||
|
-- Instance Type
|
|||
|
if activeType or activeID then
|
|||
|
instanceName, instanceType, difficultyID, _, _, _, _, instanceID = GetInstanceInfo()
|
|||
|
end
|
|||
|
|
|||
|
if activeType then
|
|||
|
if trigger.instanceType[instanceType] then
|
|||
|
passed = true
|
|||
|
|
|||
|
-- Instance Difficulty
|
|||
|
if instanceType == 'raid' or instanceType == 'party' then
|
|||
|
local D = trigger.instanceDifficulty[(instanceType == 'party' and 'dungeon') or instanceType]
|
|||
|
for _, value in pairs(D) do
|
|||
|
if value and not D[mod.TriggerConditions.difficulties[difficultyID]] then return end
|
|||
|
end
|
|||
|
end
|
|||
|
else return end
|
|||
|
end
|
|||
|
|
|||
|
-- Location
|
|||
|
if activeID or trigger.location.mapIDEnabled or trigger.location.zoneNamesEnabled or trigger.location.subZoneNamesEnabled then
|
|||
|
if activeID and next(trigger.location.instanceIDs) then
|
|||
|
if (instanceID and trigger.location.instanceIDs[tostring(instanceID)]) or trigger.location.instanceIDs[instanceName] then passed = true else return end
|
|||
|
end
|
|||
|
if trigger.location.mapIDEnabled and next(trigger.location.mapIDs) then
|
|||
|
if (E.MapInfo.mapID and trigger.location.mapIDs[tostring(E.MapInfo.mapID)]) or trigger.location.mapIDs[E.MapInfo.name] then passed = true else return end
|
|||
|
end
|
|||
|
if trigger.location.zoneNamesEnabled and next(trigger.location.zoneNames) then
|
|||
|
if trigger.location.zoneNames[E.MapInfo.realZoneText] then passed = true else return end
|
|||
|
end
|
|||
|
if trigger.location.subZoneNamesEnabled and next(trigger.location.subZoneNames) then
|
|||
|
if trigger.location.subZoneNames[E.MapInfo.subZoneText] then passed = true else return end
|
|||
|
end
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
-- Talents
|
|||
|
if trigger.talent.enabled then
|
|||
|
local pvpTalent = trigger.talent.type == 'pvp'
|
|||
|
local selected, complete
|
|||
|
|
|||
|
for i = 1, (pvpTalent and 4) or 7 do
|
|||
|
local Tier = 'tier'..i
|
|||
|
local Talent = trigger.talent[Tier]
|
|||
|
if trigger.talent[Tier..'enabled'] and Talent.column > 0 then
|
|||
|
if pvpTalent then
|
|||
|
-- column is actually the talentID for pvpTalents
|
|||
|
local slotInfo = C_SpecializationInfo_GetPvpTalentSlotInfo(i)
|
|||
|
selected = (slotInfo and slotInfo.selectedTalentID) == Talent.column
|
|||
|
else
|
|||
|
selected = select(4, GetTalentInfo(i, Talent.column, 1))
|
|||
|
end
|
|||
|
|
|||
|
if (selected and not Talent.missing) or (Talent.missing and not selected) then
|
|||
|
complete = true
|
|||
|
if not trigger.talent.requireAll then
|
|||
|
break -- break when not using requireAll because we matched one
|
|||
|
end
|
|||
|
elseif trigger.talent.requireAll then
|
|||
|
complete = false -- fail because requireAll
|
|||
|
break
|
|||
|
end end end
|
|||
|
|
|||
|
if complete then passed = true else return end
|
|||
|
end
|
|||
|
|
|||
|
-- Casting
|
|||
|
if trigger.casting then
|
|||
|
local b, c = frame.Castbar, trigger.casting
|
|||
|
|
|||
|
-- Spell
|
|||
|
if c.spells and next(c.spells) then
|
|||
|
for _, value in pairs(c.spells) do
|
|||
|
if value then -- only run if at least one is selected
|
|||
|
local castingSpell = (b.spellID and c.spells[tostring(b.spellID)]) or c.spells[b.spellName]
|
|||
|
if (c.notSpell and not castingSpell) or (castingSpell and not c.notSpell) then passed = true else return end
|
|||
|
break -- we can execute this once on the first enabled option then kill the loop
|
|||
|
end
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
-- Status
|
|||
|
if c.isCasting or c.isChanneling or c.notCasting or c.notChanneling then
|
|||
|
if (c.isCasting and b.casting) or (c.isChanneling and b.channeling)
|
|||
|
or (c.notCasting and not b.casting) or (c.notChanneling and not b.channeling) then passed = true else return end
|
|||
|
end
|
|||
|
|
|||
|
-- Interruptible
|
|||
|
if c.interruptible or c.notInterruptible then
|
|||
|
if (b.casting or b.channeling) and ((c.interruptible and not b.notInterruptible)
|
|||
|
or (c.notInterruptible and b.notInterruptible)) then passed = true else return end
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
-- Cooldown
|
|||
|
if trigger.cooldowns and trigger.cooldowns.names and next(trigger.cooldowns.names) then
|
|||
|
local cooldown = mod:StyleFilterCooldownCheck(trigger.cooldowns.names, trigger.cooldowns.mustHaveAll)
|
|||
|
if cooldown ~= nil then -- ignore if none are set to ONCD or OFFCD
|
|||
|
if cooldown then passed = true else return end
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
-- Buffs
|
|||
|
if frame.Buffs and trigger.buffs then
|
|||
|
-- Has Stealable
|
|||
|
if trigger.buffs.hasStealable or trigger.buffs.hasNoStealable then
|
|||
|
if (trigger.buffs.hasStealable and frame.Buffs.hasStealable) or (trigger.buffs.hasNoStealable and not frame.Buffs.hasStealable) then passed = true else return end
|
|||
|
end
|
|||
|
|
|||
|
-- Names / Spell IDs
|
|||
|
if trigger.buffs.names and next(trigger.buffs.names) then
|
|||
|
local buff = mod:StyleFilterAuraCheck(frame, trigger.buffs.names, frame.Buffs, trigger.buffs.mustHaveAll, trigger.buffs.missing, trigger.buffs.minTimeLeft, trigger.buffs.maxTimeLeft)
|
|||
|
if buff ~= nil then -- ignore if none are selected
|
|||
|
if buff then passed = true else return end
|
|||
|
end
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
-- Debuffs
|
|||
|
if frame.Debuffs and trigger.debuffs and trigger.debuffs.names and next(trigger.debuffs.names) then
|
|||
|
local debuff = mod:StyleFilterAuraCheck(frame, trigger.debuffs.names, frame.Debuffs, trigger.debuffs.mustHaveAll, trigger.debuffs.missing, trigger.debuffs.minTimeLeft, trigger.debuffs.maxTimeLeft)
|
|||
|
if debuff ~= nil then -- ignore if none are selected
|
|||
|
if debuff then passed = true else return end
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
-- Name or GUID
|
|||
|
if trigger.names and next(trigger.names) then
|
|||
|
for _, value in pairs(trigger.names) do
|
|||
|
if value then -- only run if at least one is selected
|
|||
|
local name = trigger.names[frame.unitName] or trigger.names[frame.npcID]
|
|||
|
if (not trigger.negativeMatch and name) or (trigger.negativeMatch and not name) then passed = true else return end
|
|||
|
break -- we can execute this once on the first enabled option then kill the loop
|
|||
|
end
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
-- Plugin Callback
|
|||
|
if mod.StyleFilterCustomChecks then
|
|||
|
for _, customCheck in pairs(mod.StyleFilterCustomChecks) do
|
|||
|
local custom = customCheck(frame, filter, trigger)
|
|||
|
if custom ~= nil then -- ignore if nil return
|
|||
|
if custom then passed = true else return end
|
|||
|
end
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
-- Pass it along
|
|||
|
if passed then
|
|||
|
mod:StyleFilterPass(frame, filter.actions)
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
function mod:StyleFilterPass(frame, actions)
|
|||
|
local db = mod:PlateDB(frame)
|
|||
|
local healthBarEnabled = (frame.frameType and db.health.enable) or (mod.db.displayStyle ~= 'ALL') or (frame.isTarget and mod.db.alwaysShowTargetHealth)
|
|||
|
local powerBarEnabled = frame.frameType and db.power and db.power.enable
|
|||
|
local healthBarShown = healthBarEnabled and frame.Health:IsShown()
|
|||
|
|
|||
|
mod:StyleFilterSetChanges(frame, actions,
|
|||
|
(healthBarShown and actions.color and actions.color.health), --HealthColor
|
|||
|
(healthBarShown and powerBarEnabled and actions.color and actions.color.power), --PowerColor
|
|||
|
(healthBarShown and actions.color and actions.color.border and frame.Health.backdrop), --Borders
|
|||
|
(healthBarShown and actions.flash and actions.flash.enable and frame.HealthFlashTexture), --HealthFlash
|
|||
|
(healthBarShown and actions.texture and actions.texture.enable), --HealthTexture
|
|||
|
(healthBarShown and actions.scale and actions.scale ~= 1), --Scale
|
|||
|
(actions.alpha and actions.alpha ~= -1), --Alpha
|
|||
|
(actions.tags and actions.tags.name and actions.tags.name ~= ''), --NameTag
|
|||
|
(actions.tags and actions.tags.power and actions.tags.power ~= ''), --PowerTag
|
|||
|
(actions.tags and actions.tags.health and actions.tags.health ~= ''), --HealthTag
|
|||
|
(actions.tags and actions.tags.title and actions.tags.title ~= ''), --TitleTag
|
|||
|
(actions.tags and actions.tags.level and actions.tags.level ~= ''), --LevelTag
|
|||
|
(actions.usePortrait), --Portrait
|
|||
|
(actions.nameOnly), --NameOnly
|
|||
|
(actions.hide) --Visibility
|
|||
|
)
|
|||
|
end
|
|||
|
|
|||
|
function mod:StyleFilterClear(frame, updateBase)
|
|||
|
if frame == _G.ElvNP_Test then return end
|
|||
|
|
|||
|
local c = frame.StyleFilterChanges
|
|||
|
if c and next(c) then
|
|||
|
local shouldUpdate = c.NameOnly or c.Visibility
|
|||
|
mod:StyleFilterClearChanges(frame, updateBase, c.HealthColor, c.PowerColor, c.Borders, c.HealthFlash, c.HealthTexture, c.Scale, c.Alpha, c.NameTag, c.PowerTag, c.HealthTag, c.TitleTag, c.LevelTag, c.Portrait, c.NameOnly, c.Visibility)
|
|||
|
return shouldUpdate
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
function mod:StyleFilterSort(place)
|
|||
|
if self[2] and place[2] then
|
|||
|
return self[2] > place[2] -- Sort by priority: 1=first, 2=second, 3=third, etc
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
function mod:StyleFilterVehicleFunction(_, unit)
|
|||
|
unit = unit or self.unit
|
|||
|
self.inVehicle = UnitInVehicle(unit) or nil
|
|||
|
end
|
|||
|
|
|||
|
mod.StyleFilterEventFunctions = { -- a prefunction to the injected ouf watch
|
|||
|
PLAYER_TARGET_CHANGED = function(self)
|
|||
|
self.isTarget = self.unit and UnitIsUnit(self.unit, 'target') or nil
|
|||
|
end,
|
|||
|
PLAYER_FOCUS_CHANGED = function(self)
|
|||
|
self.isFocused = self.unit and UnitIsUnit(self.unit, 'focus') or nil
|
|||
|
end,
|
|||
|
RAID_TARGET_UPDATE = function(self)
|
|||
|
self.RaidTargetIndex = self.unit and GetRaidTargetIndex(self.unit) or nil
|
|||
|
end,
|
|||
|
UNIT_TARGET = function(self, _, unit)
|
|||
|
unit = unit or self.unit
|
|||
|
self.isTargetingMe = UnitIsUnit(unit..'target', 'player') or nil
|
|||
|
end,
|
|||
|
UNIT_ENTERED_VEHICLE = mod.StyleFilterVehicleFunction,
|
|||
|
UNIT_EXITED_VEHICLE = mod.StyleFilterVehicleFunction,
|
|||
|
VEHICLE_UPDATE = mod.StyleFilterVehicleFunction
|
|||
|
}
|
|||
|
|
|||
|
function mod:StyleFilterSetVariables(nameplate)
|
|||
|
if nameplate == _G.ElvNP_Test then return end
|
|||
|
|
|||
|
for _, func in pairs(mod.StyleFilterEventFunctions) do
|
|||
|
func(nameplate)
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
function mod:StyleFilterClearVariables(nameplate)
|
|||
|
if nameplate == _G.ElvNP_Test then return end
|
|||
|
|
|||
|
nameplate.isTarget = nil
|
|||
|
nameplate.isFocused = nil
|
|||
|
nameplate.inVehicle = nil
|
|||
|
nameplate.isTargetingMe = nil
|
|||
|
nameplate.RaidTargetIndex = nil
|
|||
|
nameplate.ThreatScale = nil
|
|||
|
end
|
|||
|
|
|||
|
mod.StyleFilterTriggerList = {} -- configured filters enabled with sorted priority
|
|||
|
mod.StyleFilterTriggerEvents = {} -- events required by the filter that we need to watch for
|
|||
|
mod.StyleFilterPlateEvents = { -- events watched inside of ouf, which is called on the nameplate itself
|
|||
|
NAME_PLATE_UNIT_ADDED = 1 -- rest is populated from StyleFilterDefaultEvents as needed
|
|||
|
}
|
|||
|
mod.StyleFilterDefaultEvents = { -- list of events style filter uses to populate plate events
|
|||
|
-- this is a list of events already on the nameplate
|
|||
|
'UNIT_AURA',
|
|||
|
'UNIT_DISPLAYPOWER',
|
|||
|
'UNIT_FACTION',
|
|||
|
'UNIT_HEALTH',
|
|||
|
'UNIT_MAXHEALTH',
|
|||
|
'UNIT_NAME_UPDATE',
|
|||
|
'UNIT_PET',
|
|||
|
'UNIT_POWER_UPDATE',
|
|||
|
-- list of events added during StyleFilterEvents
|
|||
|
'MODIFIER_STATE_CHANGED',
|
|||
|
'PLAYER_FOCUS_CHANGED',
|
|||
|
'PLAYER_REGEN_DISABLED',
|
|||
|
'PLAYER_REGEN_ENABLED',
|
|||
|
'PLAYER_TARGET_CHANGED',
|
|||
|
'PLAYER_UPDATE_RESTING',
|
|||
|
'RAID_TARGET_UPDATE',
|
|||
|
'QUEST_LOG_UPDATE',
|
|||
|
'SPELL_UPDATE_COOLDOWN',
|
|||
|
'UNIT_ENTERED_VEHICLE',
|
|||
|
'UNIT_EXITED_VEHICLE',
|
|||
|
'UNIT_FLAGS',
|
|||
|
'UNIT_TARGET',
|
|||
|
'UNIT_THREAT_LIST_UPDATE',
|
|||
|
'UNIT_THREAT_SITUATION_UPDATE',
|
|||
|
'VEHICLE_UPDATE'
|
|||
|
}
|
|||
|
|
|||
|
function mod:StyleFilterWatchEvents()
|
|||
|
for _, event in ipairs(mod.StyleFilterDefaultEvents) do
|
|||
|
mod.StyleFilterPlateEvents[event] = mod.StyleFilterTriggerEvents[event] and true or nil
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
function mod:StyleFilterConfigure()
|
|||
|
local events = mod.StyleFilterTriggerEvents
|
|||
|
local list = mod.StyleFilterTriggerList
|
|||
|
wipe(events)
|
|||
|
wipe(list)
|
|||
|
|
|||
|
for filterName, filter in pairs(E.global.nameplate.filters) do
|
|||
|
local t = filter.triggers
|
|||
|
if t and E.db.nameplates and E.db.nameplates.filters then
|
|||
|
if E.db.nameplates.filters[filterName] and E.db.nameplates.filters[filterName].triggers and E.db.nameplates.filters[filterName].triggers.enable then
|
|||
|
tinsert(list, {filterName, t.priority or 1})
|
|||
|
|
|||
|
-- NOTE: 0 for fake events
|
|||
|
events.FAKE_AuraWaitTimer = 0 -- for minTimeLeft and maxTimeLeft aura trigger
|
|||
|
events.NAME_PLATE_UNIT_ADDED = 1
|
|||
|
events.PLAYER_TARGET_CHANGED = 1
|
|||
|
|
|||
|
if t.casting then
|
|||
|
if next(t.casting.spells) then
|
|||
|
for _, value in pairs(t.casting.spells) do
|
|||
|
if value then
|
|||
|
events.FAKE_Casting = 0
|
|||
|
break
|
|||
|
end end end
|
|||
|
|
|||
|
if (t.casting.interruptible or t.casting.notInterruptible)
|
|||
|
or (t.casting.isCasting or t.casting.isChanneling or t.casting.notCasting or t.casting.notChanneling) then
|
|||
|
events.FAKE_Casting = 0
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
if t.isTapDenied or t.isNotTapDenied then events.UNIT_FLAGS = 1 end
|
|||
|
if t.reactionType and t.reactionType.enable then events.UNIT_FACTION = 1 end
|
|||
|
if t.keyMod and t.keyMod.enable then events.MODIFIER_STATE_CHANGED = 1 end
|
|||
|
if t.targetMe or t.notTargetMe then events.UNIT_TARGET = 1 end
|
|||
|
if t.isFocus or t.notFocus then events.PLAYER_FOCUS_CHANGED = 1 end
|
|||
|
if t.isResting then events.PLAYER_UPDATE_RESTING = 1 end
|
|||
|
if t.isPet then events.UNIT_PET = 1 end
|
|||
|
|
|||
|
if t.raidTarget and (t.raidTarget.star or t.raidTarget.circle or t.raidTarget.diamond or t.raidTarget.triangle or t.raidTarget.moon or t.raidTarget.square or t.raidTarget.cross or t.raidTarget.skull) then
|
|||
|
events.RAID_TARGET_UPDATE = 1
|
|||
|
end
|
|||
|
|
|||
|
if t.unitInVehicle then
|
|||
|
events.UNIT_ENTERED_VEHICLE = 1
|
|||
|
events.UNIT_EXITED_VEHICLE = 1
|
|||
|
events.VEHICLE_UPDATE = 1
|
|||
|
end
|
|||
|
|
|||
|
if t.healthThreshold then
|
|||
|
events.UNIT_HEALTH = 1
|
|||
|
events.UNIT_MAXHEALTH = 1
|
|||
|
end
|
|||
|
|
|||
|
if t.powerThreshold then
|
|||
|
events.UNIT_POWER_UPDATE = 1
|
|||
|
events.UNIT_DISPLAYPOWER = 1
|
|||
|
end
|
|||
|
|
|||
|
if t.threat and t.threat.enable then
|
|||
|
events.UNIT_THREAT_SITUATION_UPDATE = 1
|
|||
|
events.UNIT_THREAT_LIST_UPDATE = 1
|
|||
|
end
|
|||
|
|
|||
|
if t.inCombat or t.outOfCombat or t.inCombatUnit or t.outOfCombatUnit then
|
|||
|
events.PLAYER_REGEN_DISABLED = 1
|
|||
|
events.PLAYER_REGEN_ENABLED = 1
|
|||
|
events.UNIT_THREAT_LIST_UPDATE = 1
|
|||
|
events.UNIT_FLAGS = 1
|
|||
|
end
|
|||
|
|
|||
|
if t.location then
|
|||
|
if (t.location.mapIDEnabled and next(t.location.mapIDs))
|
|||
|
or (t.location.instanceIDEnabled and next(t.location.instanceIDs))
|
|||
|
or (t.location.zoneNamesEnabled and next(t.location.zoneNames))
|
|||
|
or (t.location.subZoneNamesEnabled and next(t.location.subZoneNames)) then
|
|||
|
events.LOADING_SCREEN_DISABLED = 1
|
|||
|
events.ZONE_CHANGED_NEW_AREA = 1
|
|||
|
events.ZONE_CHANGED_INDOORS = 1
|
|||
|
events.ZONE_CHANGED = 1
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
if t.isQuest or t.notQuest then
|
|||
|
events.QUEST_LOG_UPDATE = 1
|
|||
|
end
|
|||
|
|
|||
|
if t.hasTitleNPC or t.noTitleNPC then
|
|||
|
events.UNIT_NAME_UPDATE = 1
|
|||
|
end
|
|||
|
|
|||
|
if not events.UNIT_NAME_UPDATE and t.names and next(t.names) then
|
|||
|
for _, value in pairs(t.names) do
|
|||
|
if value then
|
|||
|
events.UNIT_NAME_UPDATE = 1
|
|||
|
break
|
|||
|
end end end
|
|||
|
|
|||
|
if t.cooldowns and t.cooldowns.names and next(t.cooldowns.names) then
|
|||
|
for _, value in pairs(t.cooldowns.names) do
|
|||
|
if value == 'ONCD' or value == 'OFFCD' then
|
|||
|
events.SPELL_UPDATE_COOLDOWN = 1
|
|||
|
break
|
|||
|
end end end
|
|||
|
|
|||
|
if t.buffs and (t.buffs.hasStealable or t.buffs.hasNoStealable) then
|
|||
|
events.UNIT_AURA = 1
|
|||
|
end
|
|||
|
|
|||
|
if not events.UNIT_AURA and t.buffs and t.buffs.names and next(t.buffs.names) then
|
|||
|
for _, value in pairs(t.buffs.names) do
|
|||
|
if value then
|
|||
|
events.UNIT_AURA = 1
|
|||
|
break
|
|||
|
end end end
|
|||
|
|
|||
|
if not events.UNIT_AURA and t.debuffs and t.debuffs.names and next(t.debuffs.names) then
|
|||
|
for _, value in pairs(t.debuffs.names) do
|
|||
|
if value then
|
|||
|
events.UNIT_AURA = 1
|
|||
|
break
|
|||
|
end end end
|
|||
|
end end end
|
|||
|
|
|||
|
mod:StyleFilterWatchEvents()
|
|||
|
|
|||
|
if next(list) then
|
|||
|
sort(list, mod.StyleFilterSort) -- sort by priority
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
function mod:StyleFilterUpdate(frame, event)
|
|||
|
if frame == _G.ElvNP_Test then return end
|
|||
|
|
|||
|
if not frame.StyleFilterChanges or not mod.StyleFilterTriggerEvents[event] then return end
|
|||
|
|
|||
|
mod:StyleFilterClear(frame, true)
|
|||
|
|
|||
|
for filterNum in ipairs(mod.StyleFilterTriggerList) do
|
|||
|
local filter = E.global.nameplate.filters[mod.StyleFilterTriggerList[filterNum][1]]
|
|||
|
if filter then
|
|||
|
mod:StyleFilterConditionCheck(frame, filter, filter.triggers)
|
|||
|
end
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
do -- oUF style filter inject watch functions without actually registering any events
|
|||
|
local update = function(frame, event, ...)
|
|||
|
local eventFunc = mod.StyleFilterEventFunctions[event]
|
|||
|
if eventFunc then eventFunc(frame, event, ...) end
|
|||
|
|
|||
|
mod:StyleFilterUpdate(frame, event)
|
|||
|
end
|
|||
|
|
|||
|
local oUF_event_metatable = {
|
|||
|
__call = function(funcs, frame, ...)
|
|||
|
for _, func in next, funcs do
|
|||
|
func(frame, ...)
|
|||
|
end
|
|||
|
end,
|
|||
|
}
|
|||
|
|
|||
|
local oUF_fake_register = function(frame, event, remove)
|
|||
|
local curev = frame[event]
|
|||
|
if curev then
|
|||
|
local kind = type(curev)
|
|||
|
if kind == 'function' and curev ~= update then
|
|||
|
frame[event] = setmetatable({curev, update}, oUF_event_metatable)
|
|||
|
elseif kind == 'table' then
|
|||
|
for index, infunc in next, curev do
|
|||
|
if infunc == update then
|
|||
|
if remove then
|
|||
|
tremove(curev, index)
|
|||
|
end
|
|||
|
|
|||
|
return
|
|||
|
end end
|
|||
|
|
|||
|
tinsert(curev, update)
|
|||
|
end
|
|||
|
else
|
|||
|
frame[event] = (not remove and update) or nil
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
local styleFilterIsWatching = function(frame, event)
|
|||
|
local curev = frame[event]
|
|||
|
if curev then
|
|||
|
local kind = type(curev)
|
|||
|
if kind == 'function' and curev == update then
|
|||
|
return true
|
|||
|
elseif kind == 'table' then
|
|||
|
for _, infunc in next, curev do
|
|||
|
if infunc == update then
|
|||
|
return true
|
|||
|
end end
|
|||
|
end
|
|||
|
end end
|
|||
|
|
|||
|
function mod:StyleFilterEventWatch(frame)
|
|||
|
for _, event in ipairs(mod.StyleFilterDefaultEvents) do
|
|||
|
local holdsEvent = styleFilterIsWatching(frame, event)
|
|||
|
if mod.StyleFilterPlateEvents[event] then
|
|||
|
if not holdsEvent then
|
|||
|
oUF_fake_register(frame, event)
|
|||
|
end
|
|||
|
elseif holdsEvent then
|
|||
|
oUF_fake_register(frame, event, true)
|
|||
|
end end end
|
|||
|
|
|||
|
function mod:StyleFilterRegister(nameplate, event, unitless, func, objectEvent)
|
|||
|
if objectEvent then
|
|||
|
if not nameplate.objectEventFunc then
|
|||
|
nameplate.objectEventFunc = function(_, evnt, ...) update(nameplate, evnt, ...) end
|
|||
|
end
|
|||
|
if not E:HasFunctionForObject(event, objectEvent, nameplate.objectEventFunc) then
|
|||
|
E:RegisterEventForObject(event, objectEvent, nameplate.objectEventFunc)
|
|||
|
end
|
|||
|
elseif not nameplate:IsEventRegistered(event) then
|
|||
|
nameplate:RegisterEvent(event, func or E.noop, unitless)
|
|||
|
end
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
-- events we actually register on plates when they aren't added
|
|||
|
function mod:StyleFilterEvents(nameplate)
|
|||
|
if nameplate == _G.ElvNP_Test then return end
|
|||
|
|
|||
|
-- these events get added onto StyleFilterDefaultEvents to be watched,
|
|||
|
-- the ones added from here should not by registered already
|
|||
|
mod:StyleFilterRegister(nameplate,'MODIFIER_STATE_CHANGED', true)
|
|||
|
mod:StyleFilterRegister(nameplate,'PLAYER_FOCUS_CHANGED', true)
|
|||
|
mod:StyleFilterRegister(nameplate,'PLAYER_REGEN_DISABLED', true)
|
|||
|
mod:StyleFilterRegister(nameplate,'PLAYER_REGEN_ENABLED', true)
|
|||
|
mod:StyleFilterRegister(nameplate,'PLAYER_TARGET_CHANGED', true)
|
|||
|
mod:StyleFilterRegister(nameplate,'PLAYER_UPDATE_RESTING', true)
|
|||
|
mod:StyleFilterRegister(nameplate,'RAID_TARGET_UPDATE', true)
|
|||
|
mod:StyleFilterRegister(nameplate,'SPELL_UPDATE_COOLDOWN', true)
|
|||
|
mod:StyleFilterRegister(nameplate,'QUEST_LOG_UPDATE', true)
|
|||
|
mod:StyleFilterRegister(nameplate,'UNIT_ENTERED_VEHICLE')
|
|||
|
mod:StyleFilterRegister(nameplate,'UNIT_EXITED_VEHICLE')
|
|||
|
mod:StyleFilterRegister(nameplate,'UNIT_FLAGS')
|
|||
|
mod:StyleFilterRegister(nameplate,'UNIT_TARGET')
|
|||
|
mod:StyleFilterRegister(nameplate,'UNIT_THREAT_LIST_UPDATE')
|
|||
|
mod:StyleFilterRegister(nameplate,'UNIT_THREAT_SITUATION_UPDATE')
|
|||
|
mod:StyleFilterRegister(nameplate,'VEHICLE_UPDATE', true)
|
|||
|
|
|||
|
-- object event pathing (these update after MapInfo updates),
|
|||
|
-- these event are not added onto the nameplate itself
|
|||
|
mod:StyleFilterRegister(nameplate,'LOADING_SCREEN_DISABLED', nil, nil, E.MapInfo)
|
|||
|
mod:StyleFilterRegister(nameplate,'ZONE_CHANGED_NEW_AREA', nil, nil, E.MapInfo)
|
|||
|
mod:StyleFilterRegister(nameplate,'ZONE_CHANGED_INDOORS', nil, nil, E.MapInfo)
|
|||
|
mod:StyleFilterRegister(nameplate,'ZONE_CHANGED', nil, nil, E.MapInfo)
|
|||
|
|
|||
|
-- fire up the ouf injection watcher
|
|||
|
mod:StyleFilterEventWatch(nameplate)
|
|||
|
end
|
|||
|
|
|||
|
function mod:StyleFilterAddCustomCheck(name, func)
|
|||
|
if not mod.StyleFilterCustomChecks then
|
|||
|
mod.StyleFilterCustomChecks = {}
|
|||
|
end
|
|||
|
|
|||
|
mod.StyleFilterCustomChecks[name] = func
|
|||
|
end
|
|||
|
|
|||
|
function mod:StyleFilterRemoveCustomCheck(name)
|
|||
|
if not mod.StyleFilterCustomChecks then
|
|||
|
return
|
|||
|
end
|
|||
|
|
|||
|
mod.StyleFilterCustomChecks[name] = nil
|
|||
|
end
|
|||
|
|
|||
|
function mod:PLAYER_LOGOUT()
|
|||
|
mod:StyleFilterClearDefaults(E.global.nameplate.filters)
|
|||
|
end
|
|||
|
|
|||
|
function mod:StyleFilterClearDefaults(tbl)
|
|||
|
for filterName, filterTable in pairs(tbl) do
|
|||
|
if G.nameplate.filters[filterName] then
|
|||
|
local defaultTable = E:CopyTable({}, E.StyleFilterDefaults)
|
|||
|
E:CopyTable(defaultTable, G.nameplate.filters[filterName])
|
|||
|
E:RemoveDefaults(filterTable, defaultTable)
|
|||
|
else
|
|||
|
E:RemoveDefaults(filterTable, E.StyleFilterDefaults)
|
|||
|
end
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
function mod:StyleFilterCopyDefaults(tbl)
|
|||
|
E:CopyDefaults(tbl, E.StyleFilterDefaults)
|
|||
|
end
|
|||
|
|
|||
|
function mod:StyleFilterInitialize()
|
|||
|
for _, filterTable in pairs(E.global.nameplate.filters) do
|
|||
|
mod:StyleFilterCopyDefaults(filterTable)
|
|||
|
end
|
|||
|
end
|