--[[------------------------------------------------------------------------------------------------------
oUF_AuraWatch by Astromech
Please leave comments, suggestions, and bug reports on this addon's WoWInterface page
To setup, create a table named AuraWatch in your unit frame. There are several options
you can specify, as explained below.
icons
Mandatory!
A table of frames to be used as icons. oUF_Aurawatch does not position
these frames, so you must do so yourself. Each icon needs a spellID entry,
which is the spell ID of the aura to watch. Table should be set up
such that values are icon frames, but the keys can be anything.
Note each icon can have several options set as well. See below.
strictMatching
Default: false
If true, AuraWatch will only show an icon if the specific aura
with the specified spell id is on the unit. If false, AuraWatch
will show the icon if any aura with the same name and icon texture
is on the unit. Strict matching can be undesireable because most
ranks of an aura have different spell ids.
missingAlpha
Default 0.75
The alpha value for icons of auras which have faded from the unit.
presentAlpha
Default 1
The alpha value for icons or auras present on the unit.
onlyShowMissing
Default false
If this is true, oUF_AW will hide icons if they are present on the unit.
onlyShowPresent
Default false
If this is true, oUF_AW will hide icons if they have expired from the unit.
customIcons
Default false
If this is true, oUF_AW will not create any frames or textures for your
icons. It assumes you will handle it.
fromUnits
Default {["player"] = true, ["pet"] = true, ["vehicle"] = true}
A table of units from which auras can originate. Have the units be the keys
and "true" be the values.
anyUnit
Default false
Set to true for oUF_AW to to show an aura no matter what unit it
originates from. This will override any fromUnits setting.
PostCreateIcon
Default nil
A function to call when an icon is created to modify it, such as adding
a border or repositioning the count fontstring. Leave as nil to ignore.
The arguements are: AuraWatch table, icon, auraSpellID, auraName, unitFrame
PostResetIcon
Default nil
A function to call when an icon is reset, that is an aura has been applied
or refreshed. This is passed the AuraWatch frame, the icon, aura stack count,
duration, and remaining time, as per a UnitAura call.
PostExpireIcon
Default nil
A function to call when an icon is expired, that is an aura has disappeared.
This is passed the AuraWatch frame and the icon.
OverrideResetIcon
Default nil
Provide this function to handle the ResetIcon process yourself.
OverrideExpireIcon
Default nil
Provide this function to handle the ExpireIcon process yourself.
Below are options set on a per icon basis. Set these as fields in the icon frames.
The following settings can be overridden from the AuraWatch table on a per-aura basis:
onlyShowMissing
onlyShowPresent
fromUnits
anyUnit
The following settings are unique to icons:
spellID
Mandatory!
The spell id of the aura, as explained above.
Here is an example of how to set oUF_AW up:
local createAuraWatch = function(self, unit)
local auras = {}
-- A table of spellIDs to create icons for
-- To find spellIDs, look up a spell on [url]www.wowhead.com[/url] and look at the URL
-- [url]http://www.wowhead.com/?spell=SPELL_ID[/url]
local spellIDs = { ... }
auras.presentAlpha = 1
auras.missingAlpha = .7
auras.PostCreateIcon = myCustomIconSkinnerFunction
-- Set any other AuraWatch settings
auras.icons = {}
for i, sid in pairs(spellIDs) do
local icon = CreateFrame("Frame", nil, self)
icon.spellID = sid
-- set the dimensions and positions
icon:SetWidth(24)
icon:SetHeight(24)
icon:SetPoint("BOTTOM", self, "BOTTOM", 0, 28 * i)
auras.icons[sid] = icon
-- Set any other AuraWatch icon settings
end
self.AuraWatch = auras
end
-----------------------------------------------------------------------------------------------------------]]
local _, ns = ...
local oUF = ns.oUF or _G.oUF
assert(oUF, "oUF_AuraWatch cannot find an instance of oUF. If your oUF is embedded into a layout, it may not be embedded properly.")
local UnitAura, UnitGUID = UnitAura, UnitGUID
local GUIDs = {}
local PLAYER_UNITS = {
player = true,
vehicle = true,
pet = true,
}
local SetupGUID
do
local cache = setmetatable({}, {__type = "k"})
local frame = CreateFrame"Frame"
frame:SetScript("OnEvent", function(self, event)
for k,t in pairs(GUIDs) do
GUIDs[k] = nil
wipe(t)
cache[t] = true
end
end)
frame:RegisterEvent"PLAYER_REGEN_ENABLED"
frame:RegisterEvent"PLAYER_ENTERING_WORLD"
function SetupGUID(guid)
local t = next(cache)
if t then
cache[t] = nil
else
t = {}
end
GUIDs[guid] = t
end
end
local function DefaultResetIcon(watch, icon, count, duration, remaining)
if not icon.onlyShowMissing then
if icon.cd then
if duration and duration > 0 then
icon.cd:SetCooldown(remaining - duration, duration)
icon.cd:Show()
else
icon.cd:Hide()
end
end
if icon.count then
icon.count:SetText(count > 1 and count)
end
if icon.overlay then
icon.overlay:Hide()
end
icon:SetAlpha(watch.presentAlpha)
icon:Show()
if watch.PostResetIcon then watch.PostResetIcon(watch, icon) end
end
end
local function ResetIcon(watch, icon, ...)
if watch.OverrideResetIcon then
watch.OverrideResetIcon(watch, icon, ...)
else
DefaultResetIcon(watch, icon, ...)
end
end
local function DefaultExpireIcon(watch, icon)
if not icon.onlyShowPresent then
if icon.cd then
icon.cd:Hide()
end
if icon.count then
icon.count:SetText()
end
icon:SetAlpha(watch.missingAlpha)
if icon.overlay then
icon.overlay:Show()
end
icon:Show()
if watch.PostExpireIcon then watch.PostExpireIcon(watch, icon) end
end
end
local function ExpireIcon(watch, icon, ...)
if watch.OverrideExpireIcon then
watch.OverrideExpireIcon(watch, icon, ...)
else
DefaultExpireIcon(watch, icon, ...)
end
end
local Update
do
local found = {}
function Update(frame, event, unit)
if frame.unit ~= unit then return end
local watch = frame.AuraWatch
local index, icons = 1, watch.watched
local _, name, texture, count, duration, remaining, caster, key, icon, spellid
local filter = "HELPFUL"
local guid = UnitGUID(unit)
if not GUIDs[guid] then SetupGUID(guid) end
for key, icon in pairs(icons) do
icon:Hide()
end
while true do
name, _, texture, count, _, duration, remaining, caster, _, _, spellid = UnitAura(unit, index, filter)
if not name then
if filter == "HELPFUL" then
filter = "HARMFUL"
index = 1
else
break
end
else
if watch.strictMatching then
key = spellid
else
key = name..texture
end
icon = icons[key]
if icon and (icon.anyUnit or (caster and icon.fromUnits[caster])) then
ResetIcon(watch, icon, count, duration, remaining)
GUIDs[guid][key] = true
found[key] = true
end
index = index + 1
end
end
for key in pairs(GUIDs[guid]) do
if icons[key] and not found[key] then
ExpireIcon(watch, icons[key])
end
end
wipe(found)
end
end
local function SetupIcons(self)
local watch = self.AuraWatch
local icons = watch.icons
watch.watched = {}
if not watch.missingAlpha then watch.missingAlpha = 0.75 end
if not watch.presentAlpha then watch.presentAlpha = 1 end
for _,icon in pairs(icons) do
local name, _, image = GetSpellInfo(icon.spellID)
if not name then error("oUF_AuraWatch error: no spell with "..tostring(icon.spellID).." spell ID exists") end
icon.name = name
if not watch.customIcons then
local cd = CreateFrame("Cooldown", nil, icon)
cd:SetAllPoints(icon)
icon.cd = cd
local tex = icon:CreateTexture(nil, "BACKGROUND")
tex:SetAllPoints(icon)
tex:SetTexture(image)
icon.icon = tex
local overlay = icon:CreateTexture(nil, "OVERLAY")
overlay:SetTexture"Interface\\Buttons\\UI-Debuff-Overlays"
overlay:SetAllPoints(icon)
overlay:SetTexCoord(.296875, .5703125, 0, .515625)
overlay:SetVertexColor(1, 0, 0)
icon.overlay = overlay
local count = icon:CreateFontString(nil, "OVERLAY")
count:SetFontObject(NumberFontNormal)
count:SetPoint("BOTTOMRIGHT", icon, "BOTTOMRIGHT", -1, 0)
icon.count = count
end
if icon.onlyShowMissing == nil then
icon.onlyShowMissing = watch.onlyShowMissing
end
if icon.onlyShowPresent == nil then
icon.onlyShowPresent = watch.onlyShowPresent
end
if icon.fromUnits == nil then
icon.fromUnits = watch.fromUnits or PLAYER_UNITS
end
if icon.anyUnit == nil then
icon.anyUnit = watch.anyUnit
end
if watch.strictMatching then
watch.watched[icon.spellID] = icon
else
watch.watched[name..image] = icon
end
if watch.PostCreateIcon then watch:PostCreateIcon(icon, icon.spellID, name, self) end
end
end
local function ForceUpdate(element)
return Update(element.__owner, 'ForceUpdate', element.__owner.unit)
end
local function Enable(self)
if self.AuraWatch then
self.AuraWatch.__owner = self
self.AuraWatch.ForceUpdate = ForceUpdate
self:RegisterEvent("UNIT_AURA", Update)
SetupIcons(self)
return true
else
return false
end
end
local function Disable(self)
if self.AuraWatch then
self:UnregisterEvent("UNIT_AURA", Update)
for _,icon in pairs(self.AuraWatch.icons) do
icon:Hide()
end
end
end
oUF:AddElement("AuraWatch", Update, Enable, Disable)