Files
coa-elvui/ElvUI/Libraries/LibAuraInfo-1.0/LibAuraInfo-1.0.lua
T
Andrew6810 60ef8a38af init
2022-10-21 07:09:01 -07:00

1132 lines
28 KiB
Lua

--[[
Name: LibAuraInfo-1.0
Author(s): Cyprias (cyprias@gmail.com)
Documentation: http://www.wowace.com/addons/libaurainfo-1-0/
SVN: svn://svn.wowace.com/wow/libaurainfo-1-0/mainline/trunk
Description: Database of spellID's duration and debuff type.
Dependencies: LibStub
]]
local MAJOR, MINOR = "LibAuraInfo-1.0-ElvUI", 18
if not LibStub then error(MAJOR .. " requires LibStub") return end
local lib = LibStub:NewLibrary(MAJOR, MINOR)
if not lib then return end
lib.callbacks = lib.callbacks or LibStub("CallbackHandler-1.0"):New(lib)
if not lib.callbacks then error(MAJOR .. " requires CallbackHandler-1.0") return end
local pairs = pairs
local select = select
local tonumber = tonumber
local band = bit.band
local floor = math.floor
local sub = string.sub
local tinsert, tremove = table.insert, table.remove
local UnitAura = UnitAura
local UnitIsUnit = UnitIsUnit
local UnitExists = UnitExists
local UnitName = UnitName
local UnitGUID = UnitGUID
local GetSpellInfo = GetSpellInfo
local GetSpellTexture = GetSpellTexture
local GetTime = GetTime
local COMBATLOG_OBJECT_TYPE_PLAYER = COMBATLOG_OBJECT_TYPE_PLAYER
lib.confirmedDur = {}
lib.GUIDBlackList = {}
lib.GUIDDurations = {}
lib.GUIDData_name = {}
lib.GUIDData_flags = {}
--Save debuffType as a number, then return as a string when requested.
lib.debuffTypes = {
Magic = 1,
Disease = 2,
Poison = 3,
Curse = 4,
}
for name, id in pairs(lib.debuffTypes) do
lib.debuffTypes[id] = name
end
lib.trackAuras = true
lib.callbacksUsed = {}
function lib.callbacks:OnUsed(target, eventname)
lib.callbacksUsed[eventname] = lib.callbacksUsed[eventname] or {}
tinsert(lib.callbacksUsed[eventname], #lib.callbacksUsed[eventname]+1, target)
lib.trackAuras = true
lib.frame:RegisterEvent('COMBAT_LOG_EVENT_UNFILTERED')
lib.frame:RegisterEvent('UPDATE_MOUSEOVER_UNIT')
lib.frame:RegisterEvent('PLAYER_TARGET_CHANGED')
lib.frame:RegisterEvent('UNIT_TARGET')
lib.frame:RegisterEvent('UNIT_AURA')
end
function lib.callbacks:OnUnused(target, eventname)
if lib.callbacksUsed[eventname] then
for i = #lib.callbacksUsed[eventname], 1, -1 do
if lib.callbacksUsed[eventname][i] == target then
tremove(lib.callbacksUsed[eventname], i)
end
end
end
for event, value in pairs(lib.callbacksUsed) do
if #value == 0 then
lib.callbacksUsed[event] = nil
end
end
lib.trackAuras = false
lib.frame:UnregisterEvent('COMBAT_LOG_EVENT_UNFILTERED')
lib.frame:UnregisterEvent('UPDATE_MOUSEOVER_UNIT')
lib.frame:UnregisterEvent('PLAYER_TARGET_CHANGED')
lib.frame:UnregisterEvent('UNIT_TARGET')
lib.frame:UnregisterEvent('UNIT_AURA')
end
local function Round(num)
return floor(num + .5)
end
local function ResetUnitAuras(unitID)
lib:RemoveAllAurasFromGUID(UnitGUID(unitID))
end
function lib:AddAuraFromUnitID(dstGUID, name, texture, stackCount, debuffType, duration, expirationTime, srcGUID, spellID, filter)
self.GUIDAuras[dstGUID] = self.GUIDAuras[dstGUID] or {}
self.GUIDAuras[dstGUID][filter] = self.GUIDAuras[dstGUID][filter] or {}
tinsert(self.GUIDAuras[dstGUID][filter], #self.GUIDAuras[dstGUID][filter]+1, {
name = name,
texture = texture,
stackCount = stackCount,
debuffType = debuffType,
duration = duration,
expirationTime = expirationTime,
spellID = spellID,
srcGUID = srcGUID
})
end
local CheckUnitAuras
do
local i
local _, name, texture, stackCount, dispelType, duration, expirationTime, unitCaster, spellID
local dstGUID, dstName, srcGUID
function CheckUnitAuras(unitID, filterType)
dstGUID, dstName = UnitGUID(unitID), UnitName(unitID)
if lib.GUIDData_name[dstGUID] ~= dstName then
lib.GUIDData_name[dstGUID] = dstName
end
--Since we have a unitID, lets clear our aura table and use 100% accurate aura info.
if lib.GUIDAuras[dstGUID] and lib.GUIDAuras[dstGUID][filterType] then
for j = #lib.GUIDAuras[dstGUID][filterType], 1, -1 do
tremove(lib.GUIDAuras[dstGUID][filterType], j)
end
end
i = 1
while true do
name, _, texture, stackCount, dispelType, duration, expirationTime, unitCaster, _, _, spellID = UnitAura(unitID, i, filterType)
if not name then break end
duration = Round(duration)
if not lib.spellDuration[spellID] then
lib.spellDuration[spellID] = duration
lib.spellDebuffType[spellID] = (dispelType and lib.debuffTypes[dispelType] or 0)
elseif not lib.auraInfoPvP[spellID] then
if unitCaster and UnitExists(unitCaster) then
srcGUID = UnitGUID(unitCaster)
local baseDuration = lib:GetDuration(spellID) --, nil, nil, UnitIsPlayer(unitID)
if baseDuration and baseDuration ~= duration then
if duration > 0 then -- Sometimes UnitAura says a spell has 0 duration when it realy has more.
--caster's duration doesn't match our DB, they're probably speced into something. lets remember that.
lib.GUIDDurations[srcGUID.."-"..spellID] = duration
end
end
end
end
if unitCaster and expirationTime > 0 then
srcGUID = srcGUID or UnitGUID(unitCaster)
lib:AddAuraFromUnitID(
dstGUID,
name,
texture,
stackCount and stackCount > 1 and stackCount or nil,
dispelType,
duration,
expirationTime,
srcGUID,
spellID,
filterType
)
end
i = i + 1
srcGUID = nil
end
lib.callbacks:Fire("LibAuraInfo_UNIT_AURA", dstGUID)
end
end
lib.frame = lib.frame or CreateFrame("Frame")
lib.frame:SetScript("OnEvent", function(self, event, ...)
if self[event] then
self[event](self, event, ...)
end
end)
function lib.frame:UPDATE_MOUSEOVER_UNIT()
ResetUnitAuras("mouseover")
CheckUnitAuras("mouseover", "HELPFUL")
CheckUnitAuras("mouseover", "HARMFUL")
end
function lib.frame:PLAYER_TARGET_CHANGED()
ResetUnitAuras("target")
CheckUnitAuras("target", "HELPFUL")
CheckUnitAuras("target", "HARMFUL")
end
do
local targetID
function lib.frame:UNIT_TARGET(_, unitID)
if not UnitIsUnit(unitID, "player") then
targetID = unitID.."target"
ResetUnitAuras(targetID)
CheckUnitAuras(targetID, "HELPFUL")
CheckUnitAuras(targetID, "HARMFUL")
end
end
end
function lib.frame:UNIT_AURA(_, unitID)
if not unitID then return end
ResetUnitAuras(unitID)
CheckUnitAuras(unitID, "HELPFUL")
CheckUnitAuras(unitID, "HARMFUL")
end
------------------------------------------------------------------------------------------------------
--~ Dimminshing Returns
------------------------------------------------------------------------------------------------------
lib.resetDRTime = 18 --Time it tacks for DR to reset.
--[[
List of spellID's copied from DRData-1.0 by Shadowed.
http://www.wowace.com/addons/drdata-1-0/
http://www.wowace.com/profiles/Shadowed/
]]
lib.drSpells = {
--[[ TAUNT ]]--
-- Taunt (Warrior)
[355] = "taunt",
-- Taunt (Pet)
[53477] = "taunt",
-- Mocking Blow
[694] = "taunt",
-- Growl (Druid)
[6795] = "taunt",
-- Dark Command
[56222] = "taunt",
-- Hand of Reckoning
[62124] = "taunt",
-- Righteous Defense
[31790] = "taunt",
-- Distracting Shot
[20736] = "taunt",
-- Challenging Shout
[1161] = "taunt",
-- Challenging Roar
[5209] = "taunt",
-- Death Grip
[49560] = "taunt",
-- Challenging Howl
[59671] = "taunt",
-- Angered Earth
[36213] = "taunt",
--[[ DISORIENTS ]]--
-- Dragon's Breath
[31661] = "disorient",
[33041] = "disorient",
[33042] = "disorient",
[33043] = "disorient",
[42949] = "disorient",
[42950] = "disorient",
-- Hungering Cold
[49203] = "disorient",
-- Sap
[6770] = "disorient",
[2070] = "disorient",
[11297] = "disorient",
[51724] = "disorient",
-- Gouge
[1776] = "disorient",
-- Hex (Guessing)
[51514] = "disorient",
-- Shackle
[9484] = "disorient",
[9485] = "disorient",
[10955] = "disorient",
-- Polymorph
[118] = "disorient",
[12824] = "disorient",
[12825] = "disorient",
[28272] = "disorient",
[28271] = "disorient",
[12826] = "disorient",
[61305] = "disorient",
[61025] = "disorient",
[61721] = "disorient",
[61780] = "disorient",
-- Freezing Trap
[3355] = "disorient",
[14308] = "disorient",
[14309] = "disorient",
-- Freezing Arrow
[60210] = "disorient",
-- Wyvern Sting
[19386] = "disorient",
[24132] = "disorient",
[24133] = "disorient",
[27068] = "disorient",
[49011] = "disorient",
[49012] = "disorient",
-- Repentance
[20066] = "disorient",
--[[ SILENCES ]]--
-- Nether Shock
[53588] = "silence",
[53589] = "silence",
-- Garrote
[1330] = "silence",
-- Arcane Torrent (Energy version)
[25046] = "silence",
-- Arcane Torrent (Mana version)
[28730] = "silence",
-- Arcane Torrent (Runic power version)
[50613] = "silence",
-- Silence
[15487] = "silence",
-- Silencing Shot
[34490] = "silence",
-- Improved Kick
[18425] = "silence",
-- Improved Counterspell
[18469] = "silence",
-- Spell Lock
[19244] = "silence",
[19647] = "silence",
-- Shield of the Templar
[63529] = "silence",
-- Strangulate
[47476] = "silence",
[49913] = "silence",
[49914] = "silence",
[49915] = "silence",
[49916] = "silence",
-- Gag Order (Warrior talent)
[18498] = "silence",
--[[ DISARMS ]]--
-- Snatch
[53542] = "disarm",
[53543] = "disarm",
-- Dismantle
[51722] = "disarm",
-- Disarm
[676] = "disarm",
-- Chimera Shot - Scorpid
[53359] = "disarm",
-- Psychic Horror (Disarm effect)
[64058] = "disarm",
--[[ FEARS ]]--
-- Blind
[2094] = "fear",
-- Fear (Warlock)
[5782] = "fear",
[6213] = "fear",
[6215] = "fear",
-- Seduction (Pet)
[6358] = "fear",
-- Howl of Terror
[5484] = "fear",
[17928] = "fear",
-- Psychic scream
[8122] = "fear",
[8124] = "fear",
[10888] = "fear",
[10890] = "fear",
-- Scare Beast
[1513] = "fear",
[14326] = "fear",
[14327] = "fear",
-- Turn Evil
[10326] = "fear",
-- Intimidating Shout
[5246] = "fear",
--[[ CONTROL STUNS ]]--
-- Intercept (Felguard)
[30153] = "ctrlstun",
[30195] = "ctrlstun",
[30197] = "ctrlstun",
[47995] = "ctrlstun",
-- Ravage
[50518] = "ctrlstun",
[53558] = "ctrlstun",
[53559] = "ctrlstun",
[53560] = "ctrlstun",
[53561] = "ctrlstun",
[53562] = "ctrlstun",
-- Sonic Blast
[50519] = "ctrlstun",
[53564] = "ctrlstun",
[53565] = "ctrlstun",
[53566] = "ctrlstun",
[53567] = "ctrlstun",
[53568] = "ctrlstun",
-- Concussion Blow
[12809] = "ctrlstun",
-- Shockwave
[46968] = "ctrlstun",
-- Hammer of Justice
[853] = "ctrlstun",
[5588] = "ctrlstun",
[5589] = "ctrlstun",
[10308] = "ctrlstun",
-- Bash
[5211] = "ctrlstun",
[6798] = "ctrlstun",
[8983] = "ctrlstun",
--***********************************************************
-- Intimidation
[19577] = "ctrlstun",
-- Maim
[22570] = "ctrlstun",
[49802] = "ctrlstun",
-- Kidney Shot
[408] = "ctrlstun",
[8643] = "ctrlstun",
-- War Stomp
[20549] = "ctrlstun",
-- Intercept
[20252] = "ctrlstun",
-- Deep Freeze
[44572] = "ctrlstun",
-- Shadowfury
[30283] = "ctrlstun",
[30413] = "ctrlstun",
[30414] = "ctrlstun",
-- Holy Wrath
[2812] = "ctrlstun",
-- Inferno Effect
[22703] = "ctrlstun",
-- Demon Charge
[60995] = "ctrlstun",
-- Gnaw (Ghoul)
[47481] = "ctrlstun",
--[[ RANDOM STUNS ]]--
-- Impact
[12355] = "rndstun",
-- Stoneclaw Stun
[39796] = "rndstun",
-- Seal of Justice
[20170] = "rndstun",
-- Revenge Stun
[12798] = "rndstun",
--[[ CYCLONE ]]--
-- Cyclone
[33786] = "cyclone",
--[[ ROOTS ]]--
-- Freeze (Water Elemental)
[33395] = "ctrlroot",
-- Pin (Crab)
[50245] = "ctrlroot",
[53544] = "ctrlroot",
[53545] = "ctrlroot",
[53546] = "ctrlroot",
[53547] = "ctrlroot",
[53548] = "ctrlroot",
-- Frost Nova
[122] = "ctrlroot",
[865] = "ctrlroot",
[6131] = "ctrlroot",
[10230] = "ctrlroot",
[27088] = "ctrlroot",
[42917] = "ctrlroot",
-- Entangling Roots
[339] = "ctrlroot",
[1062] = "ctrlroot",
[5195] = "ctrlroot",
[5196] = "ctrlroot",
[9852] = "ctrlroot",
[9853] = "ctrlroot",
[26989] = "ctrlroot",
[53308] = "ctrlroot",
-- Nature's Grasp (Uses different spellIDs than Entangling Roots for the same spell)
[19970] = "ctrlroot",
[19971] = "ctrlroot",
[19972] = "ctrlroot",
[19973] = "ctrlroot",
[19974] = "ctrlroot",
[19975] = "ctrlroot",
[27010] = "ctrlroot",
[53313] = "ctrlroot",
-- Earthgrab (Storm, Earth and Fire talent)
[8377] = "ctrlroot",
[31983] = "ctrlroot",
-- Web (Spider)
[4167] = "ctrlroot",
-- Venom Web Spray (Silithid)
[54706] = "ctrlroot",
[55505] = "ctrlroot",
[55506] = "ctrlroot",
[55507] = "ctrlroot",
[55508] = "ctrlroot",
[55509] = "ctrlroot",
--[[ RANDOM ROOTS ]]--
-- Improved Hamstring
[23694] = "rndroot",
-- Frostbite
[12494] = "rndroot",
-- Shattered Barrier
[55080] = "rndroot",
--[[ SLEEPS ]]--
-- Hibernate
[2637] = "sleep",
[18657] = "sleep",
[18658] = "sleep",
--[[ HORROR ]]--
-- Death Coil
[6789] = "horror",
[17925] = "horror",
[17926] = "horror",
[27223] = "horror",
[47859] = "horror",
[47860] = "horror",
-- Psychic Horror
[64044] = "horror",
--[[ MISC ]]--
-- Scatter Shot
[19503] = "scatters",
-- Cheap Shot
[1833] = "cheapshot",
-- Pounce
[9005] = "cheapshot",
[9823] = "cheapshot",
[9827] = "cheapshot",
[27006] = "cheapshot",
[49803] = "cheapshot",
-- Charge
[7922] = "charge",
-- Mind Control
[605] = "mc",
-- Banish
[710] = "banish",
[18647] = "banish",
-- Entrapment
[64804] = "entrapment",
[19185] = "entrapment",
}
lib.pveDR = {
["ctrlstun"] = true,
["rndstun"] = true,
["taunt"] = true,
["cyclone"] = true,
}
lib.GUIDDrEffects_reset = {}
lib.GUIDDrEffects_diminished = {}
do
local drType, key, reset
function lib:GUIDGainedDRAura(dstGUID, spellID, dstIsPlayer)
drType = self.drSpells[spellID]
if dstIsPlayer or self.pveDR[drType] then
key = dstGUID..drType
reset = self.GUIDDrEffects_reset[key]
if reset and reset <= GetTime() then
self.GUIDDrEffects_diminished[key] = 1
end
end
end
end
local function NextDR(diminished)
if diminished == 1 then
return 0.50
elseif diminished == 0.50 then
return 0.25
end
return 0
end
do
local drType, key
function lib:GUIDRemovedDRAura(dstGUID, spellID, dstIsPlayer)
drType = self.drSpells[spellID]
if dstIsPlayer or self.pveDR[drType] then
key = dstGUID..drType
self.GUIDDrEffects_reset[key] = GetTime() + self.resetDRTime
self.GUIDDrEffects_diminished[key] = NextDR( self.GUIDDrEffects_diminished[key] or 1.0 )
end
end
end
do
local drType, key, reset
function lib:GetDRDuration(dstGUID, spellID, duration)
duration = duration or self:GetDuration(spellID, nil, dstGUID)
drType = self.drSpells[spellID]
if drType then
key = dstGUID..drType
reset = self.GUIDDrEffects_reset[key]
if reset and GetTime() < reset then
return duration * (self.GUIDDrEffects_diminished[key] or 1)
end
end
return duration
end
end
-------------------------------------------------------------------------------------------------------
--~ Combatlog
-------------------------------------------------------------------------------------------------------
lib.GUIDAuras = lib.GUIDAuras or {}
local function SaveGUIDInfo(guid, name, flags)
lib.GUIDData_name[guid] = name
lib.GUIDData_flags[guid] = flags
end
function lib:GetSpellTexture(spellID)
return GetSpellTexture(spellID) or select(3, GetSpellInfo(spellID))
end
function lib.frame:COMBAT_LOG_EVENT_UNFILTERED(event, timestamp, eventType, srcGUID, srcName, srcFlags, dstGUID, dstName, dstFlags, ...)
if lib.GUIDBlackList[dstGUID] then return end
if srcGUID and not lib.GUIDData_flags[srcGUID] then
SaveGUIDInfo(srcGUID, srcName, srcFlags)
end
if dstGUID and not lib.GUIDData_flags[dstGUID] then
SaveGUIDInfo(dstGUID, dstName, dstFlags)
end
if self[eventType] then
self[eventType](self, eventType, timestamp, eventType, srcGUID, srcName, srcFlags, dstGUID, dstName, dstFlags, ...)
end
end
do
local data
-- Remove expired auras from a GUID
function lib:RemoveExpiredAuras(dstGUID)
if self.GUIDAuras[dstGUID] then
for filter in pairs(self.GUIDAuras[dstGUID]) do
for i = #self.GUIDAuras[dstGUID][filter], 1, -1 do
data = self.GUIDAuras[dstGUID][filter][i]
if GetTime() > data.expirationTime then
tremove(self.GUIDAuras[dstGUID][filter], i)
end
end
end
end
end
end
do
local duration
-- Add a auraID to our GUID list
function lib:AddAuraToGUID(dstGUID, name, texture, spellID, srcGUID, filter)
duration = self:GetDuration(spellID, srcGUID, dstGUID)
self.GUIDAuras[dstGUID] = self.GUIDAuras[dstGUID] or {}
self.GUIDAuras[dstGUID][filter] = self.GUIDAuras[dstGUID][filter] or {}
--[[
I didn't want to use tables this way when I started the project but due to multiple instnces of a spellID being on a GUID I couldn't do a hash table lookup.
I wanted do something like
GUIDAuras_Duration[dstGUID..spellID..srcGUID] = 30
but because UnitAura() sometimes doesn't return a unitID to get srcGUID, I had to do a index table. meh
]]
tinsert(self.GUIDAuras[dstGUID][filter], #self.GUIDAuras[dstGUID][filter] + 1, {
name = name,
texture = texture,
debuffType = self:GetDebuffType(spellID),
duration = duration,
expirationTime = duration == 0 and 0 or GetTime() + duration,
spellID = spellID,
srcGUID = srcGUID,
isDebuff = filter
})
--~ table.sort(self.GUIDAuras[dstGUID], function(a,b)
--~ return a.expirationTime < b.expirationTime
--~ end)
end
end
do
local data
-- Increase stack count of a aura
function lib:AddAuraDose(dstGUID, spellID, srcGUID, filter)
if self.GUIDAuras[dstGUID] and self.GUIDAuras[dstGUID][filter] then
if srcGUID then
for i = 1, #self.GUIDAuras[dstGUID][filter] do
data = self.GUIDAuras[dstGUID][filter][i]
if data.spellID == spellID and data.srcGUID == srcGUID then
data.stackCount = (data.stackCount or 1) + 1
data.expirationTime = data.duration + GetTime()
return true, data.stackCount, data.expirationTime
end
end
end
for i = 1, #self.GUIDAuras[dstGUID][filter] do
data = self.GUIDAuras[dstGUID][filter][i]
if data.spellID == spellID then
data.stackCount = (data.stackCount or 1) + 1
data.expirationTime = data.duration + GetTime()
return true, data.stackCount, data.expirationTime
end
end
end
return false
end
end
do
local data
-- Remove 1 stack from a aura
function lib:RemoveAuraDose(dstGUID, spellID, srcGUID, filter)
if self.GUIDAuras[dstGUID] and self.GUIDAuras[dstGUID][filter] then
if srcGUID then
for i = 1, #self.GUIDAuras[dstGUID][filter] do
data = self.GUIDAuras[dstGUID][filter][i]
if data.spellID == spellID and data.srcGUID == srcGUID then
data.stackCount = (data.stackCount or 1) - 1
-- data.expirationTime = data.duration + GetTime()
return true, data.stackCount, data.expirationTime
end
end
end
for i = 1, #self.GUIDAuras[dstGUID][filter] do
data = self.GUIDAuras[dstGUID][filter][i]
if data.spellID == spellID then
data.stackCount = (data.stackCount or 1) - 1
-- data.expirationTime = data.duration + GetTime()
return true, data.stackCount, data.expirationTime
end
end
end
return false
end
end
do
local data
-- Refresh the start and expiration time of a aura
function lib:RefreshAura(dstGUID, spellID, srcGUID, filter)
if self.GUIDAuras[dstGUID] and self.GUIDAuras[dstGUID][filter] then
if srcGUID then
for i = 1, #self.GUIDAuras[dstGUID][filter] do
data = self.GUIDAuras[dstGUID][filter][i]
if data.spellID == spellID and data.srcGUID == srcGUID then
data.expirationTime = data.duration + GetTime()
return true, data.expirationTime
end
end
end
for i = 1, #self.GUIDAuras[dstGUID][filter] do
data = self.GUIDAuras[dstGUID][filter][i]
if data.spellID == spellID then
data.expirationTime = data.duration + GetTime()
return true, data.expirationTime
end
end
end
return false
end
end
do
local data
-- Remove a aura from a GUID
function lib:RemoveAuraFromGUID(dstGUID, spellID, srcGUID, filter)
if lib.GUIDAuras[dstGUID] and lib.GUIDAuras[dstGUID][filter] then
if srcGUID then
for i = #lib.GUIDAuras[dstGUID][filter],1, -1 do
data = lib.GUIDAuras[dstGUID][filter][i]
if data.spellID == spellID and srcGUID == data.srcGUID then
tremove(lib.GUIDAuras[dstGUID][filter], i)
lib.callbacks:Fire("RemoveAuraFromGUID", dstGUID)
return
end
end
end
for i = #lib.GUIDAuras[dstGUID][filter],1, -1 do
data = lib.GUIDAuras[dstGUID][filter][i]
if data.spellID == spellID then
tremove(lib.GUIDAuras[dstGUID][filter], i)
lib.callbacks:Fire("RemoveAuraFromGUID", dstGUID)
return
end
end
end
end
end
-- Remove all auras on a GUID. They must have died
function lib:RemoveAllAurasFromGUID(dstGUID)
if self.GUIDAuras[dstGUID] then
for filter in pairs(self.GUIDAuras[dstGUID]) do
for i=#self.GUIDAuras[dstGUID][filter], 1, -1 do
tremove(self.GUIDAuras[dstGUID][filter], i)
end
end
end
end
function lib.frame:SPELL_AURA_REMOVED(event, timestamp, eventType, srcGUID, srcName, srcFlags, dstGUID, dstName, dstFlags, spellID, spellName, spellSchool, auraType)
lib:RemoveAuraFromGUID(dstGUID, spellID, srcGUID, auraType == "DEBUFF" and "HARMFUL" or "HELPFUL")
if lib.drSpells[spellID] then
lib:GUIDRemovedDRAura(dstGUID, spellID, lib:FlagIsPlayer(dstFlags))
end
lib.callbacks:Fire("LibAuraInfo_AURA_REMOVED", dstGUID, spellID, srcGUID)
end
function lib.frame:SPELL_AURA_APPLIED(event, timestamp, eventType, srcGUID, srcName, srcFlags, dstGUID, dstName, dstFlags, spellID, spellName, spellSchool, auraType)
if lib.drSpells[spellID] then
lib:GUIDGainedDRAura(dstGUID, spellID, lib:FlagIsPlayer(dstFlags))
end
if lib.spellDuration[spellID] then
lib:RemoveExpiredAuras(dstGUID)
lib:AddAuraToGUID(dstGUID, spellName, lib:GetSpellTexture(spellID), spellID, srcGUID, auraType == "DEBUFF" and "HARMFUL" or "HELPFUL")
lib.callbacks:Fire("LibAuraInfo_AURA_APPLIED", dstGUID, spellID, srcGUID, auraType)
end
end
do
local refreshed
function lib.frame:SPELL_AURA_REFRESH(event, timestamp, eventType, srcGUID, srcName, srcFlags, dstGUID, dstName, dstFlags, spellID, spellName, spellSchool, auraType)
if lib.drSpells[spellID] then
lib:GUIDRemovedDRAura(dstGUID, spellID, lib:FlagIsPlayer(dstFlags))
lib:GUIDGainedDRAura(dstGUID, spellID, lib:FlagIsPlayer(dstFlags))
end
refreshed = lib:RefreshAura(dstGUID, spellID, srcGUID, auraType == "DEBUFF" and "HARMFUL" or "HELPFUL")
if refreshed then
lib.callbacks:Fire("LibAuraInfo_AURA_REFRESH", dstGUID, spellID, srcGUID, spellSchool, auraType)
return
end
self:SPELL_AURA_APPLIED(event, timestamp, eventType, srcGUID, srcName, srcFlags, dstGUID, dstName, dstFlags, spellID, spellName, spellSchool, auraType)
end
end
do
local dosed, stackCount, expirationTime
--DOSE = spell stacking
function lib.frame:SPELL_AURA_APPLIED_DOSE(event, timestamp, eventType, srcGUID, srcName, srcFlags, dstGUID, dstName, dstFlags, spellID, spellName, spellSchool, auraType)
dosed, stackCount, expirationTime = lib:AddAuraDose(dstGUID, spellID, srcGUID, auraType == "DEBUFF" and "HARMFUL" or "HELPFUL")
if dosed then
lib.callbacks:Fire("LibAuraInfo_AURA_APPLIED_DOSE", dstGUID, spellID, srcGUID, spellSchool, auraType, stackCount, expirationTime)
return
end
--Spell isn't in our list, let's add it.
--Note this event could have fired on the 5th stack but our spell frame will only show it applied once.
self:SPELL_AURA_APPLIED(event, timestamp, eventType, srcGUID, srcName, srcFlags, dstGUID, dstName, dstFlags, spellID, spellName, spellSchool, auraType)
end
end
do
local dosed, stackCount, expirationTime
function lib.frame:SPELL_AURA_APPLIED_REMOVED_DOSE(event, timestamp, eventType, srcGUID, srcName, srcFlags, dstGUID, dstName, dstFlags, spellID, spellName, spellSchool, auraType)
dosed, stackCount, expirationTime = lib:RemoveAuraDose(dstGUID, spellID, srcGUID, auraType == "DEBUFF" and "HARMFUL" or "HELPFUL")
if dosed then
lib.callbacks:Fire("LibAuraInfo_AURA_APPLIED_DOSE", dstGUID, spellID, srcGUID, spellSchool, auraType, stackCount, expirationTime)
return
end
end
end
function lib.frame:SPELL_AURA_BROKEN_SPELL(...)
self:SPELL_AURA_REMOVED(...)
end
function lib.frame:SPELL_AURA_BROKEN(...)
self:SPELL_AURA_REMOVED(...)
end
function lib.frame:UNIT_DIED(event, timestamp, eventType, srcGUID, srcName, srcFlags, dstGUID, dstName, dstFlags, ...)
if lib.GUIDAuras[dstGUID] then
lib:RemoveAllAurasFromGUID(dstGUID)
lib.callbacks:Fire("LibAuraInfo_AURA_CLEAR", dstGUID)
end
end
function lib.frame:UNIT_DESTROYED(...)
self:UNIT_DIED(...)
end
function lib.frame:UNIT_DISSIPATES(...)
self:UNIT_DIED(...)
end
function lib.frame:PARTY_KILL(...)
self:UNIT_DIED(...)
end
function lib:FlagIsPlayer(flags)
if band(flags, COMBATLOG_OBJECT_TYPE_PLAYER) == COMBATLOG_OBJECT_TYPE_PLAYER then
return true
end
end
--------------------------------------------------------------
--~ API
--------------------------------------------------------------
local GUIDIsPlayer
do
local B, maskedB
function GUIDIsPlayer(guid)
B = tonumber(sub(guid, 5, 5), 16);
maskedB = B % 8; -- x % 8 has the same effect as x & 0x7 on numbers <= 0xf
-- local knownTypes = {[0]="player", [3]="NPC", [4]="pet", [5]="vehicle"};
-- print("Your target is a " .. (knownTypes[maskedB] or " unknown entity!"));
return maskedB == 0
end
end
do
local duration, dur
--Return the duration of a spell.
function lib:GetDuration(spellID, srcGUID, dstGUID, dstIsPlayer)
dstIsPlayer = dstIsPlayer or dstGUID and GUIDIsPlayer(dstGUID) or false
if dstIsPlayer and lib.auraInfoPvP[spellID] then
--Receiver is a player and the spell has a PvP duration. Return the pvp duration.
duration = lib.auraInfoPvP[spellID]
if dstGUID and duration then
--Check if there's dimminshing returns on the spell.
duration = self:GetDRDuration(dstGUID, spellID, duration)
end
return tonumber(duration or 0)
elseif self.spellDuration[spellID] then
--Check caster GUID was given.
if srcGUID then
--Check if we've seen that caster cast a spell with a duration that doesn't match our own (spec/glphed into something?)
if self.GUIDDurations[srcGUID.."-"..spellID] then
dur = self.GUIDDurations[srcGUID.."-"..spellID]
--Check if receiver GUID was given.
if dstGUID then
--Check if there's dimminshing returns on the spell.
dur = self:GetDRDuration(dstGUID, spellID, dur)
end
return dur
end
end
return self.spellDuration[spellID]
end
end
end
do
local debuffType
--Return the debuff type of a spell.
function lib:GetDebuffType(spellID)
if self.spellDuration[spellID] then
debuffType = self.spellDebuffType[spellID]
if debuffType then
return self.debuffTypes[debuffType] or "unknown"
end
return "none"--Lowercase because DebuffTypeColor["none"] is lowercase.
end
end
end
function lib:GetNumGUIDAuras(dstGUID)
self:RemoveExpiredAuras(dstGUID)
if self.GUIDAuras[dstGUID] then
local i = 0
for filter in pairs(self.GUIDAuras[dstGUID]) do
i = i + #self.GUIDAuras[dstGUID][filter]
end
return i
end
return 0
end
do
local data
function lib:GUIDAura(dstGUID, i, filter)
if self.GUIDAuras[dstGUID] and self.GUIDAuras[dstGUID][filter] and self.GUIDAuras[dstGUID][filter][i] then
data = self.GUIDAuras[dstGUID][filter][i]
return true, data.name, data.texture, data.stackCount or 0, data.debuffType, data.duration, data.expirationTime, data.srcGUID, data.spellID
end
return false
end
end
do
local data
function lib:GUIDAuraID(dstGUID, spellID, srcGUID, filter)
if self.GUIDAuras[dstGUID] and self.GUIDAuras[dstGUID][filter] then
if srcGUID then
for i = 1, #self.GUIDAuras[dstGUID][filter] do
data = self.GUIDAuras[dstGUID][filter][i]
if data.spellID == spellID and data.srcGUID == srcGUID then
return true, data.stackCount or 0, data.debuffType, data.duration, data.expirationTime, data.isDebuff, data.srcGUID
end
end
end
for i = 1, #self.GUIDAuras[dstGUID][filter] do
data = self.GUIDAuras[dstGUID][filter][i]
if data.spellID == spellID then
return true, data.stackCount or 0, data.debuffType, data.duration, data.expirationTime, data.isDebuff, data.srcGUID
end
end
end
return false
end
end
do
local drType, key, reset
function lib:HasDREffect(dstGUID, spellID)
drType = self.drSpells[spellID]
if drType then
key = dstGUID..drType
reset = self.GUIDDrEffects_reset[key]
if reset and GetTime() < reset then
return true, (self.GUIDDrEffects_diminished[key] or 1)
end
end
return false
end
end
function lib:GetGUIDInfo(GUID)
return self.GUIDData_name[GUID], self.GUIDData_flags[GUID]
end