local Srendarr = _G['Srendarr'] -- grab addon table from global local L = Srendarr:GetLocale() -- CONSTS -- local ABILITY_TYPE_CHANGEAPPEARANCE = ABILITY_TYPE_CHANGEAPPEARANCE local ABILITY_TYPE_REGISTERTRIGGER = ABILITY_TYPE_REGISTERTRIGGER local BUFF_EFFECT_TYPE_DEBUFF = BUFF_EFFECT_TYPE_DEBUFF local GROUP_PLAYER_SHORT = Srendarr.GROUP_PLAYER_SHORT local GROUP_PLAYER_LONG = Srendarr.GROUP_PLAYER_LONG local GROUP_PLAYER_TOGGLED = Srendarr.GROUP_PLAYER_TOGGLED local GROUP_PLAYER_PASSIVE = Srendarr.GROUP_PLAYER_PASSIVE local GROUP_PLAYER_DEBUFF = Srendarr.GROUP_PLAYER_DEBUFF local GROUP_PLAYER_GROUND = Srendarr.GROUP_PLAYER_GROUND local GROUP_PLAYER_MAJOR = Srendarr.GROUP_PLAYER_MAJOR local GROUP_PLAYER_MINOR = Srendarr.GROUP_PLAYER_MINOR local GROUP_TARGET_BUFF = Srendarr.GROUP_TARGET_BUFF local GROUP_TARGET_DEBUFF = Srendarr.GROUP_TARGET_DEBUFF local GROUP_PROMINENT = Srendarr.GROUP_PROMINENT local AURA_TYPE_TIMED = Srendarr.AURA_TYPE_TIMED local AURA_TYPE_TOGGLED = Srendarr.AURA_TYPE_TOGGLED local AURA_TYPE_PASSIVE = Srendarr.AURA_TYPE_PASSIVE -- UPVALUES -- local GetGameTimeMillis = GetGameTimeMilliseconds local IsToggledAura = Srendarr.IsToggledAura local IsMajorEffect = Srendarr.IsMajorEffect -- technically only used for major|minor buffs on the player, major|minor debuffs local IsMinorEffect = Srendarr.IsMinorEffect -- are filtered to the debuff grouping before being checked for local auraLookup = Srendarr.auraLookup local filteredAuras = Srendarr.filteredAuras local prominentAuras = {} local displayFrameRef = {} local shortBuffThreshold, filterDisguisesOnPlayer, filterDisguisesOnTarget local displayFrameFake = { ['AddAuraToDisplay'] = function() -- do nothing : used to make the AuraHandler code more manageable, redirects unwanted auras to nil end, } -- ------------------------ -- AURA HANDLER -- ------------------------ local function AuraHandler(flagBurst, auraName, unitTag, start, finish, icon, effectType, abilityType, abilityID) -- d('AuraHandler ' .. auraName .. ' [' .. abilityID ..'] (' .. unitTag .. '), effectType: ' .. effectType .. ', abilityType: ' .. abilityType .. string.format(', %.3f | %.3f (%.3f)', start, finish, (finish - start))) if (start ~= finish and (finish - start) < 2.25) then return end -- abort showing any timed auras with a duration of < 2.25s if (filteredAuras[unitTag][abilityID]) then return end -- abort immediately if this is an ability we've filtered if (auraLookup[unitTag][abilityID]) then -- aura exists, update its data (assume would not exist unless passed filters earlier) auraLookup[unitTag][abilityID]:Update(start, finish) return end if (prominentAuras[abilityID] and unitTag ~= 'reticleover') then -- special case, this is a prominent aura on player or gtaoe displayFrameRef[GROUP_PROMINENT]:AddAuraToDisplay(flagBurst, GROUP_PROMINENT, AURA_TYPE_TIMED, auraName, unitTag, start, finish, icon, effectType, abilityType, abilityID) return end if (unitTag == 'reticleover') then -- new aura on target if (effectType == BUFF_EFFECT_TYPE_DEBUFF) then -- debuff on target, check for it being a passive (not sure they can be, but just to be sure as things break with a 'timed' passive) displayFrameRef[GROUP_TARGET_DEBUFF]:AddAuraToDisplay(flagBurst, GROUP_TARGET_DEBUFF, (start == finish) and AURA_TYPE_PASSIVE or AURA_TYPE_TIMED, auraName, unitTag, start, finish, icon, effectType, abilityType, abilityID) else -- buff on target, sort as passive, toggle or timed and add if (filterDisguisesOnTarget and abilityType == ABILITY_TYPE_CHANGEAPPEARANCE) then return end -- is a disguise and they are filtered if (start == finish) then -- toggled or passive displayFrameRef[GROUP_TARGET_BUFF]:AddAuraToDisplay(flagBurst, GROUP_TARGET_BUFF, (IsToggledAura(abilityID)) and AURA_TYPE_TOGGLED or AURA_TYPE_PASSIVE, auraName, unitTag, start, finish, icon, effectType, abilityType, abilityID) else -- timed buff displayFrameRef[GROUP_TARGET_BUFF]:AddAuraToDisplay(flagBurst, GROUP_TARGET_BUFF, AURA_TYPE_TIMED, auraName, unitTag, start, finish, icon, effectType, abilityType, abilityID) end end elseif (unitTag == 'player') then -- new aura on player if (effectType == BUFF_EFFECT_TYPE_DEBUFF) then -- debuff on player, check for it being a passive (not sure they can be, but just to be sure as things break with a 'timed' passive) displayFrameRef[GROUP_PLAYER_DEBUFF]:AddAuraToDisplay(flagBurst, GROUP_PLAYER_DEBUFF, (start == finish) and AURA_TYPE_PASSIVE or AURA_TYPE_TIMED, auraName, unitTag, start, finish, icon, effectType, abilityType, abilityID) else -- buff on player, sort as passive, toggled or timed and add if (filterDisguisesOnPlayer and abilityType == ABILITY_TYPE_CHANGEAPPEARANCE) then return end -- is a disguise and they are filtered if (start == finish) then -- toggled or passive if (IsToggledAura(abilityID)) then -- toggled displayFrameRef[GROUP_PLAYER_TOGGLED]:AddAuraToDisplay(flagBurst, GROUP_PLAYER_TOGGLED, AURA_TYPE_TOGGLED, auraName, unitTag, start, finish, icon, effectType, abilityType, abilityID) else -- passive displayFrameRef[GROUP_PLAYER_PASSIVE]:AddAuraToDisplay(flagBurst, GROUP_PLAYER_PASSIVE, AURA_TYPE_PASSIVE, auraName, unitTag, start, finish, icon, effectType, abilityType, abilityID) end else -- timed buff if (IsMajorEffect(abilityID)) then -- major buff on player displayFrameRef[GROUP_PLAYER_MAJOR]:AddAuraToDisplay(flagBurst, GROUP_PLAYER_MAJOR, AURA_TYPE_TIMED, auraName, unitTag, start, finish, icon, effectType, abilityType, abilityID) elseif (IsMinorEffect(abilityID)) then -- minor buff on player displayFrameRef[GROUP_PLAYER_MINOR]:AddAuraToDisplay(flagBurst, GROUP_PLAYER_MINOR, AURA_TYPE_TIMED, auraName, unitTag, start, finish, icon, effectType, abilityType, abilityID) elseif ((finish - start) > shortBuffThreshold) then -- is considered a long duration buff displayFrameRef[GROUP_PLAYER_LONG]:AddAuraToDisplay(flagBurst, GROUP_PLAYER_LONG, AURA_TYPE_TIMED, auraName, unitTag, start, finish, icon, effectType, abilityType, abilityID) else displayFrameRef[GROUP_PLAYER_SHORT]:AddAuraToDisplay(flagBurst, GROUP_PLAYER_SHORT, AURA_TYPE_TIMED, auraName, unitTag, start, finish, icon, effectType, abilityType, abilityID) end end end else -- unitTag == 'groundaoe' -- new ground aoe cast by player (assume always timed) displayFrameRef[GROUP_PLAYER_GROUND]:AddAuraToDisplay(flagBurst, GROUP_PLAYER_GROUND, AURA_TYPE_TIMED, auraName, unitTag, start, finish, icon, effectType, abilityType, abilityID) end end function Srendarr:ConfigureAuraHandler() for group, frameNum in pairs(self.db.auraGroups) do -- if a group is set to hidden, auras will be sent to a fake frame that does nothing (simplifies things) displayFrameRef[group] = (frameNum > 0) and self.displayFrames[frameNum] or displayFrameFake end shortBuffThreshold = self.db.shortBuffThreshold filterDisguisesOnPlayer = self.db.filtersPlayer.disguise filterDisguisesOnTarget = self.db.filtersTarget.disguise for id in pairs(prominentAuras) do prominentAuras[id] = nil -- clean out prominent auras list end for _, abilityIDs in pairs(self.db.prominentWhitelist) do for id in pairs(abilityIDs) do prominentAuras[id] = true -- populate promience list from saved database end end end -- ------------------------ -- EVENT: EVENT_PLAYER_ACTIVATED, EVENT_PLAYER_ALIVE do ------------------------ local GetNumBuffs = GetNumBuffs local GetUnitBuffInfo = GetUnitBuffInfo local NUM_DISPLAY_FRAMES = Srendarr.NUM_DISPLAY_FRAMES local auraLookup = Srendarr.auraLookup local numAuras, auraName, start, finish, stack, icon, effectType, abilityType, abilityID Srendarr.OnPlayerActivatedAlive = function() for _, auras in pairs(auraLookup) do -- iterate all aura lookups for _, aura in pairs(auras) do -- iterate all auras for each lookup aura:Release(true) end end numAuras = GetNumBuffs('player') if (numAuras > 0) then -- player has auras, scan and send to handle for i = 1, numAuras do auraName, start, finish, _, _, icon, _, effectType, abilityType, _, abilityID = GetUnitBuffInfo('player', i) AuraHandler(true, auraName, 'player', start, finish, icon, effectType, abilityType, abilityID) end end for x = 1, NUM_DISPLAY_FRAMES do Srendarr.displayFrames[x]:UpdateDisplay() -- update the display for all frames end end end -- ------------------------ -- EVENT: EVENT_PLAYER_DEAD do ------------------------ local NUM_DISPLAY_FRAMES = Srendarr.NUM_DISPLAY_FRAMES local auraLookup = Srendarr.auraLookup Srendarr.OnPlayerDead = function() for _, auras in pairs(auraLookup) do -- iterate all aura lookups for _, aura in pairs(auras) do -- iterate all auras for each lookup aura:Release(true) end end for x = 1, NUM_DISPLAY_FRAMES do Srendarr.displayFrames[x]:UpdateDisplay() -- update the display for all frames end end end -- ------------------------ -- EVENT: EVENT_PLAYER_COMBAT_STATE do ----------------------- local NUM_DISPLAY_FRAMES = Srendarr.NUM_DISPLAY_FRAMES local displayFramesScene = Srendarr.displayFramesScene OnCombatState = function(e, inCombat) if (inCombat) then if (Srendarr.db.combatDisplayOnly) then for x = 1, NUM_DISPLAY_FRAMES do displayFramesScene[x]:SetHiddenForReason('combatstate', false) end end else if (Srendarr.db.combatDisplayOnly) then for x = 1, NUM_DISPLAY_FRAMES do displayFramesScene[x]:SetHiddenForReason('combatstate', true) end end end end function Srendarr:ConfigureOnCombatState() if (self.db.combatDisplayOnly) then EVENT_MANAGER:RegisterForEvent(self.name, EVENT_PLAYER_COMBAT_STATE, OnCombatState) OnCombatState(nil, IsUnitInCombat('player')) -- force an update else EVENT_MANAGER:UnregisterForEvent(self.name, EVENT_PLAYER_COMBAT_STATE) if (self.displayFramesScene[1]:IsHiddenForReason('combatstate')) then -- if currently hidden due to setting, show for x = 1, NUM_DISPLAY_FRAMES do self.displayFramesScene[x]:SetHiddenForReason('combatstate', false) end end end end Srendarr.OnCombatState = OnCombatState end -- ------------------------ -- EVENT: EVENT_EFFECT_CHANGED do ------------------------ local EFFECT_RESULT_FADED = EFFECT_RESULT_FADED local ABILITY_TYPE_AREAEFFECT = ABILITY_TYPE_AREAEFFECT -- local ABILITY_TYPE_REGISTERTRIGGER = ABILITY_TYPE_REGISTERTRIGGER local AURA_TYPE_TIMED = Srendarr.AURA_TYPE_TIMED local GROUP_PLAYER_GROUND = Srendarr.GROUP_PLAYER_GROUND local GetAbilityDescription = GetAbilityDescription local crystalFragmentsPassive = Srendarr.crystalFragmentsPassive -- special case for tracking fragments proc local auraLookup = Srendarr.auraLookup local fadedAura Srendarr.OnEffectChanged = function(e, change, slot, auraName, unitTag, start, finish, stack, icon, buffType, effectType, abilityType, statusType, unitName, unitID, abilityID) -- check the aura is on either the player, the target or is a ground aoe -- the description check filters a lot of extra auras attached to many ground effects unitTag = (unitTag == 'player' or unitTag == 'reticleover') and unitTag or (abilityType == ABILITY_TYPE_AREAEFFECT and GetAbilityDescription(abilityID) ~= '') and 'groundaoe' or nil if (not unitTag) then return end -- don't care about this unit and isn't a ground aoe, abort if (change == EFFECT_RESULT_FADED) then -- aura has faded fadedAura = auraLookup[unitTag][abilityID] if (fadedAura) then -- aura exists, tell it to expire if timed, or release otherwise if (fadedAura.auraType == AURA_TYPE_TIMED) then if (fadedAura.abilityType == ABILITY_TYPE_AREAEFFECT) then return end -- gtaoes expire internally (repeated casting, only one timer) fadedAura:SetExpired() else fadedAura:Release() end end -- if (abilityType == ABILITY_TYPE_REGISTERTRIGGER and if (auraName == crystalFragmentsPassive) then -- special case for tracking fragments proc Srendarr:OnCrystalFragmentsProc(false) end else -- aura has been gained or changed, dispatch to handler AuraHandler(false, auraName, unitTag, start, finish, icon, effectType, abilityType, abilityID) -- if (abilityType == ABILITY_TYPE_REGISTERTRIGGER and if (auraName == crystalFragmentsPassive) then -- special case for tracking fragments proc Srendarr:OnCrystalFragmentsProc(true) end end end end -- ------------------------ -- EVENT: EVENT_RETICLE_TARGET_CHANGED do ------------------------ local GetNumBuffs = GetNumBuffs local GetUnitBuffInfo = GetUnitBuffInfo local DoesUnitExist = DoesUnitExist local auraLookupReticle = Srendarr.auraLookup['reticleover'] -- local ref for speed, this functions expensive local targetDisplayFrame1 = false -- local refs to frames displaying target auras (if any) local targetDisplayFrame2 = false -- local refs to frames displaying target auras (if any) local numAuras, auraName, start, finish, stack, icon, effectType, abilityType, abilityID local function OnTargetChanged() for _, aura in pairs(auraLookupReticle) do aura:Release(true) -- old auras cleaned out end if (DoesUnitExist('reticleover')) then -- have a target, scan for auras numAuras = GetNumBuffs('reticleover') if (numAuras > 0) then -- target has auras, scan and send to handler for i = 1, numAuras do auraName, start, finish, _, stack, icon, _, effectType, abilityType, _, abilityID = GetUnitBuffInfo('reticleover', i) AuraHandler(true, auraName, 'reticleover', start, finish, icon, effectType, abilityType, abilityID) end end end -- no matter, update the display of the 1-2 frames displaying targets auras if (targetDisplayFrame1) then targetDisplayFrame1:UpdateDisplay() end if (targetDisplayFrame2) then targetDisplayFrame2:UpdateDisplay() end end function Srendarr:ConfigureOnTargetChanged() -- figure out which frames currently display target auras local targetBuff = self.db.auraGroups[Srendarr.GROUP_TARGET_BUFF] local targetDebuff = self.db.auraGroups[Srendarr.GROUP_TARGET_DEBUFF] targetDisplayFrame1 = (targetBuff ~= 0) and self.displayFrames[targetBuff] or false targetDisplayFrame2 = (targetDebuff ~= 0) and self.displayFrames[targetDebuff] or false if (targetDisplayFrame1 or targetDisplayFrame2) then -- event configured and needed, start tracking EVENT_MANAGER:RegisterForEvent(self.name, EVENT_RETICLE_TARGET_CHANGED, OnTargetChanged) else -- not needed (not displaying any target auras) EVENT_MANAGER:UnregisterForEvent(self.name, EVENT_RETICLE_TARGET_CHANGED) end end Srendarr.OnTargetChanged = OnTargetChanged end -- ------------------------ -- EVENT: EVENT_ACTION_SLOT_ABILITY_USED do ------------------------ local ABILITY_TYPE_NONE = ABILITY_TYPE_NONE -- no fakes have any specifc ability type local BUFF_EFFECT_TYPE_BUFF = BUFF_EFFECT_TYPE_BUFF -- all fakes are buffs or gtaoe local GetGameTimeMillis = GetGameTimeMilliseconds local GetLatency = GetLatency local slotData = Srendarr.slotData local fakeAuras = Srendarr.fakeAuras local slotAbilityName, currentTime Srendarr.OnActionSlotAbilityUsed = function(e, slotID) if (slotID < 3 or slotID > 8) then return end -- abort if not a main ability (or ultimate) slotAbilityName = slotData[slotID].abilityName if (not fakeAuras[slotAbilityName]) then return end -- no fake aura needed for this ability (majority case) currentTime = GetGameTimeMillis() / 1000 AuraHandler( false, slotAbilityName, fakeAuras[slotAbilityName].unitTag, currentTime, currentTime + fakeAuras[slotAbilityName].duration + (GetLatency() / 1000), -- + cooldown? GetSlotCooldownInfo(slotID) slotData[slotID].abilityIcon, BUFF_EFFECT_TYPE_BUFF, ABILITY_TYPE_NONE, fakeAuras[slotAbilityName].abilityID ) end function Srendarr:ConfigureOnActionSlotAbilityUsed() if (self.db.auraFakeEnabled) then EVENT_MANAGER:RegisterForEvent(self.name, EVENT_ACTION_SLOT_ABILITY_USED, Srendarr.OnActionSlotAbilityUsed) else EVENT_MANAGER:UnregisterForEvent(self.name, EVENT_ACTION_SLOT_ABILITY_USED) end end end function Srendarr:InitializeAuraControl() -- setup event handlers EVENT_MANAGER:RegisterForEvent(self.name, EVENT_PLAYER_ACTIVATED, Srendarr.OnPlayerActivatedAlive) -- same action for both events EVENT_MANAGER:RegisterForEvent(self.name, EVENT_PLAYER_ALIVE, Srendarr.OnPlayerActivatedAlive) -- same action for both events EVENT_MANAGER:RegisterForEvent(self.name, EVENT_PLAYER_DEAD, Srendarr.OnPlayerDead) EVENT_MANAGER:RegisterForEvent(self.name, EVENT_EFFECT_CHANGED, Srendarr.OnEffectChanged) self:ConfigureOnCombatState() -- EVENT_PLAYER_COMBAT_STATE self:ConfigureOnTargetChanged() -- EVENT_RETICLE_TARGET_CHANGED self:ConfigureOnActionSlotAbilityUsed() -- EVENT_ACTION_SLOT_ABILITY_USED self:ConfigureAuraHandler() end