vanilla-wow-addons – Rev 1
?pathlinks?
--[[
Name: SpecialEvents-Aura-2.0
Revision: $Rev: 10488 $
Author: Tekkub Stoutwrithe (tekkub@gmail.com)
Website: http://wiki.wowace.com/index.php/SpecialEvents_Addon
Documentation: http://wiki.wowace.com/index.php/SpecialEvents-Aura-2.0
SVN: svn://svn.wowace.com/root/trunk/SpecialEventsEmbed/SpecialEvents-Aura-2.0
Description: Special events for Aura's, (de)buffs gained, lost etc.
Dependencies: AceLibrary, AceEvent-2.0, Gratuity-2.0
]]
local vmajor, vminor = "SpecialEvents-Aura-2.0", "$Revision: 10488 $"
if not AceLibrary then error(vmajor .. " requires AceLibrary.") end
if not AceLibrary:HasInstance("AceEvent-2.0") then error(vmajor .. " requires AceEvent-2.0.") end
if not AceLibrary:IsNewVersion(vmajor, vminor) then return end
local lib = {}
AceLibrary("AceEvent-2.0"):embed(lib)
local gratuity = AceLibrary("Gratuity-2.0")
local RL
local debuffTextureCache = {}
local buffTextureCache = {}
----------------------------
-- Compost Heap --
----------------------------
local heap = {}
setmetatable(heap, {__mode = "kv"})
local function acquire(a1,a2,a3,a4,a5)
local t = next(heap)
if t then
heap[t] = nil
assert(not next(t), "A table in the compost heap has been modified!")
end
t = t or {}
if a1 ~= nil then table.insert(t, a1) end
if a2 ~= nil then table.insert(t, a2) end
if a3 ~= nil then table.insert(t, a3) end
if a4 ~= nil then table.insert(t, a4) end
if a5 ~= nil then table.insert(t, a5) end
return t
end
local function reclaim(t, d)
if type(t) ~= "table" then return end
if d and d > 0 then
for i in pairs(t) do
if type(t[i]) == "table" then reclaim(t[i], d - 1) end
end
end
for i in pairs(t) do t[i] = nil end
t.reset = 1
t.reset = nil
table.setn(t, 0)
heap[t] = true
end
----------------------------
-- Initialization --
----------------------------
local function registerevents(self)
self:RegisterEvent("PLAYER_LEAVING_WORLD")
self:RegisterEvent("UNIT_AURA", "AuraScan")
self:RegisterEvent("UNIT_AURASTATE", "AuraScan")
self:RegisterEvent("PLAYER_AURAS_CHANGED")
self:RegisterEvent("PLAYER_TARGET_CHANGED")
self:RegisterEvent("PLAYER_REGEN_ENABLED")
-- check if RosterLib exists. We need to do that here and not earlier.
RL = AceLibrary:HasInstance("RosterLib-2.0") and AceLibrary("RosterLib-2.0") or nil
if RL then
RL:Enable()
self:RegisterBucketEvent("RosterLib_UnitChanged",0.2)
else
self:RegisterEvent("PARTY_MEMBERS_CHANGED",1)
self:RegisterEvent("RAID_ROSTER_UPDATE",1)
end
end
-- Activate a new instance of this library
function activate(self, oldLib, oldDeactivate)
if oldLib then
self.vars = oldLib.vars
if oldLib:IsEventRegistered("UNIT_AURA") then registerevents(self) end
if oldLib:IsEventRegistered("RosterLib_UnitChanged") then
if RL then RL:Disable() end
oldLib:UnregisterAllEvents()
end
else self.vars = {buffs = {}, debuffs = {}} end
self:RegisterEvent("PLAYER_ENTERING_WORLD")
if oldDeactivate then oldDeactivate(oldLib) end
end
function lib:PLAYER_ENTERING_WORLD()
self:ScanAllAuras()
registerevents(self)
end
function lib:PLAYER_LEAVING_WORLD()
self:UnregisterAllEvents()
self:RegisterEvent("PLAYER_ENTERING_WORLD")
if RL then
RL:Disable()
end
end
--------------------------------
-- Tracking methods --
--------------------------------
function lib:PLAYER_AURAS_CHANGED()
self:AuraScan("player")
if GetNumRaidMembers() > 0 then
local u
for i=1,GetNumRaidMembers() do
if UnitIsUnit("raid"..i, "player") then u = "raid"..i end
end
self:AuraScan(u)
end
end
function lib:PLAYER_TARGET_CHANGED()
self:AuraScan("target")
self:TriggerEvent("SpecialEvents_AuraTargetChanged")
end
function lib:RosterLib_UnitChanged(units)
for unit in pairs(units) do
if unit and UnitExists(unit) then
self:AuraScan(unit)
end
end
if GetNumRaidMembers() > 0 then
self:TriggerEvent("SpecialEvents_AuraRaidRosterUpdate")
else
self:TriggerEvent("SpecialEvents_AuraPartyMembersChanged")
end
end
function lib:PARTY_MEMBERS_CHANGED()
if UnitExists("pet") then self:AuraScan("pet") end
for i=1,4 do
if UnitExists("party"..i) then self:AuraScan("party"..i) end
if UnitExists("partypet"..i) then self:AuraScan("partypet"..i) end
end
self:TriggerEvent("SpecialEvents_AuraPartyMembersChanged")
end
function lib:RAID_ROSTER_UPDATE()
for i=1,40 do
if UnitExists("raid"..i) then self:AuraScan("raid"..i) end
if UnitExists("raidpet"..i) then self:AuraScan("raidpet"..i) end
end
self:TriggerEvent("SpecialEvents_AuraRaidRosterUpdate")
end
function lib:PLAYER_REGEN_ENABLED()
reclaim(debuffTextureCache)
debuffTextureCache = acquire()
reclaim(buffTextureCache)
buffTextureCache = acquire()
end
function lib:ScanAllAuras()
if UnitExists("player") then self:AuraScan("player") end
if UnitExists("pet") then self:AuraScan("pet") end
for i=1,4 do
if UnitExists("party"..i) then self:AuraScan("party"..i) end
if UnitExists("partypet"..i) then self:AuraScan("partypet"..i) end
end
for i=1,40 do
if UnitExists("raid"..i) then self:AuraScan("raid"..i) end
if UnitExists("raidpet"..i) then self:AuraScan("raidpet"..i) end
end
if UnitExists("target") then self:AuraScan("target") end
--~~ if UnitExists("mouseover") then self:AuraScan("mouseover") end
end
function lib:AuraScan(targ)
local maxbuffs, maxdebuffs, t = 16, 16, targ or arg1
local oldd, oldb = self.vars.debuffs[t], self.vars.buffs[t]
local newd, newb = acquire(), acquire()
if t == "player" then
for i=0,(maxbuffs-1) do
local bidx = GetPlayerBuff(i, "HELPFUL")
if bidx and bidx ~= -1 then
gratuity:SetPlayerBuff(bidx)
local txt = gratuity:GetLine(1)
if txt then newb[txt] = i end
end
end
for i=0,(maxdebuffs-1) do
local didx = GetPlayerBuff(i, "HARMFUL")
if didx and didx ~= -1 then
gratuity:SetPlayerBuff(didx)
local txt, txtr = gratuity:GetLine(1)
local apps = GetPlayerBuffApplications(didx)
local texture = GetPlayerBuffTexture(didx)
local dbtype = GetPlayerBuffDispelType(didx)
if txt then
local txtindex = txt
if texture then txtindex = txtindex..texture end
newd[txtindex] = acquire(i, txt, apps, dbtype, texture)
end
end
end
else
for i=1,maxbuffs do
local txt
local texture, apps = UnitBuff (t, i)
if texture then
if not buffTextureCache[texture] then
gratuity:SetUnitBuff(t,i)
txt = gratuity:GetLine(1)
buffTextureCache[texture] = txt
else
txt = buffTextureCache[texture]
end
if txt then newb[txt] = i end
end
end
for i=1,maxdebuffs do
local txt
local texture, apps, dbtype = UnitDebuff (t, i)
if texture then
if not debuffTextureCache[texture] then
gratuity:SetUnitDebuff(t,i)
txt = gratuity:GetLine(1)
debuffTextureCache[texture] = txt
else
txt = debuffTextureCache[texture]
end
if txt then
local txtindex = txt .. texture
reclaim(newd[txtindex])
newd[txtindex] = acquire(i, txt, apps, dbtype, texture)
end
end
end
end
self.vars.buffs[t] = newb
self.vars.debuffs[t] = newd
if oldb then
for b,i in oldb do
if not newb[b] then
self:TriggerEvent("SpecialEvents_UnitBuffLost", t, b)
if t == "player" then self:TriggerEvent("SpecialEvents_PlayerBuffLost", b) end
end
end
end
if oldd then
for d,i in pairs(oldd) do
if type(i) ~= "table" then
local t = ""
for d,i in pairs(oldd) do t = t.." "..d.."="..i end
error(string.format("Debuff error! Unit: %s, Table dump:%s", targ, t))
elseif not newd[d] then
self:TriggerEvent("SpecialEvents_UnitDebuffLost", t, i[2], i[3], i[4], i[5])
if t == "player" then self:TriggerEvent("SpecialEvents_PlayerDebuffLost", i[2], i[3], i[4], i[5]) end
end
end
end
for b,i in pairs(newb) do
if (not oldb or not oldb[b]) then
self:TriggerEvent("SpecialEvents_UnitBuffGained", t, b)
if t == "player" then self:TriggerEvent("SpecialEvents_PlayerBuffGained", b, i) end
end
end
for d,i in pairs(newd) do
assert(type(i) == "table", string.format("Debuff: %s - Value not a table: %s", d, type(i) == "table" and "table" or i or "nil"))
local o2 = oldd and type(oldd[d]) == "table" and oldd[d][2]
if not o2 or o2 ~= i[2] then
self:TriggerEvent("SpecialEvents_UnitDebuffGained", t, i[2], i[3], i[4], i[5])
if t == "player" then self:TriggerEvent("SpecialEvents_PlayerDebuffGained", i[2], i[3], i[4], i[5]) end
end
end
reclaim(oldb)
reclaim(oldd, 1)
end
-----------------------------
-- Query Methods --
-----------------------------
function lib:UnitHasBuff(targ, buff)
if self.vars.buffs[targ] then return self.vars.buffs[targ][buff] end
end
function lib:UnitHasDebuff(targ, debuff)
if self.vars.debuffs[targ] then
for i, v in pairs(self.vars.debuffs[targ]) do
if v[2] == debuff then
return v[1], v[3]
end
end
end
end
function lib:UnitHasDebuffType(targ, debufftype)
if self.vars.debuffs[targ] then
for i,v in pairs(self.vars.debuffs[targ]) do
if v[4] == debufftype then return v end
end
end
end
function lib:BuffIter(unitid)
local f = function(unitid, i)
if not self.vars.buffs[unitid] then return end
local idx = next(self.vars.buffs[unitid], i)
local v = self.vars.buffs[unitid][idx]
if v then return idx, v end
end
return f, unitid, nil
end
function lib:DebuffIter(unitid)
local idx = nil
local f = function(unitid)
if not self.vars.debuffs[unitid] then return end
idx = next(self.vars.debuffs[unitid], idx)
local v = self.vars.debuffs[unitid][idx]
if v then return v[2], v[3], v[4], v[5] end
end
return f, unitid, nil
end
--------------------------------
-- Load this bitch! --
--------------------------------
AceLibrary:Register(lib, vmajor, vminor, activate)