424 lines
10 KiB
Lua
424 lines
10 KiB
Lua
--[[------------------------------------------------------------------------------------------------------
|
|
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.
|
|
hideCooldown
|
|
Default false
|
|
If this is true, oUF_AW will not create a cooldown frame
|
|
hideCount
|
|
Default false
|
|
If this is true, oUF_AW will not create a count fontstring
|
|
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.
|
|
decimalThreshold
|
|
Default 5
|
|
The threshold before timers go into decimal form. Set to -1 to disable decimals.
|
|
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
|
|
|
|
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
|
|
hideCooldown
|
|
hideCount
|
|
fromUnits
|
|
anyUnit
|
|
decimalThreshold
|
|
|
|
The following settings are unique to icons:
|
|
|
|
spellID
|
|
Mandatory!
|
|
The spell id of the aura, as explained above.
|
|
icon
|
|
Default aura texture
|
|
A texture value for this icon.
|
|
overlay
|
|
Default Blizzard aura overlay
|
|
An overlay for the icon. This is not created if a custom icon texture is created.
|
|
count
|
|
Default A fontstring
|
|
An fontstring to show the stack count of an aura.
|
|
|
|
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 www.wowhead.com and look at the URL
|
|
-- http://www.wowhead.com/?spell=SPELL_ID
|
|
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, auras)
|
|
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 = oUF or ns.oUF
|
|
assert(oUF, "oUF_AuraWatch was unable to locate oUF install")
|
|
|
|
local next = next
|
|
local pairs = pairs
|
|
|
|
local CreateFrame = CreateFrame
|
|
local GetSpellInfo = GetSpellInfo
|
|
local GetTime = GetTime
|
|
local UnitAura = UnitAura
|
|
local UnitGUID = 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
|
|
for a in pairs(t) do
|
|
t[a] = nil
|
|
end
|
|
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 DAY, HOUR, MINUTE = 86400, 3600, 60
|
|
local function formatTime(s, threshold)
|
|
if s >= DAY then
|
|
return format("%dd", ceil(s / HOUR))
|
|
elseif s >= HOUR then
|
|
return format("%dh", ceil(s / HOUR))
|
|
elseif s >= MINUTE then
|
|
return format("%dm", ceil(s / MINUTE))
|
|
elseif s >= threshold then
|
|
return floor(s)
|
|
end
|
|
|
|
return format("%.1f", s)
|
|
end
|
|
|
|
local function updateText(self, elapsed)
|
|
if self.timeLeft then
|
|
self.elapsed = self.elapsed + elapsed
|
|
|
|
if self.elapsed >= 0.1 then
|
|
if not self.first then
|
|
self.timeLeft = self.timeLeft - self.elapsed
|
|
else
|
|
self.timeLeft = self.timeLeft - GetTime()
|
|
self.first = false
|
|
end
|
|
|
|
if self.timeLeft > 0 then
|
|
if self.timeLeft <= self.textThreshold or self.textThreshold == -1 then
|
|
self.text:SetText(formatTime(self.timeLeft, self.decimalThreshold or 5))
|
|
else
|
|
self.text:SetText("")
|
|
end
|
|
else
|
|
self.text:SetText("")
|
|
self:SetScript("OnUpdate", nil)
|
|
end
|
|
|
|
self.elapsed = 0
|
|
end
|
|
end
|
|
end
|
|
|
|
local function resetIcon(icon, frame, count, duration, remaining)
|
|
if icon.onlyShowMissing then
|
|
icon:Hide()
|
|
else
|
|
if icon.cd then
|
|
if duration and duration > 0 and icon.style ~= "NONE" then
|
|
icon.cd:SetCooldown(remaining - duration, duration)
|
|
icon.cd:Show()
|
|
else
|
|
icon.cd:Hide()
|
|
end
|
|
end
|
|
|
|
if icon.displayText then
|
|
icon.timeLeft = remaining
|
|
icon.first = true
|
|
icon.elapsed = 0
|
|
icon:SetScript("OnUpdate", updateText)
|
|
end
|
|
|
|
if icon.count then
|
|
icon.count:SetText(count > 1 and count)
|
|
end
|
|
|
|
if icon.overlay then
|
|
icon.overlay:Hide()
|
|
end
|
|
|
|
icon:SetAlpha(icon.presentAlpha)
|
|
icon:Show()
|
|
end
|
|
end
|
|
|
|
local function expireIcon(icon, frame)
|
|
if icon.onlyShowPresent then
|
|
icon:Hide()
|
|
else
|
|
if icon.cd then
|
|
icon.cd:Hide()
|
|
end
|
|
|
|
if icon.count then
|
|
icon.count:SetText()
|
|
end
|
|
|
|
if icon.overlay then
|
|
icon.overlay:Show()
|
|
end
|
|
|
|
icon:SetAlpha(icon.missingAlpha)
|
|
icon:Show()
|
|
end
|
|
end
|
|
|
|
local found = {}
|
|
local function Update(self, event, unit)
|
|
if not unit or self.unit ~= unit then return end
|
|
|
|
local guid = UnitGUID(unit)
|
|
if not guid then return end
|
|
|
|
if not GUIDs[guid] then
|
|
setupGUID(guid)
|
|
end
|
|
|
|
local element = self.AuraWatch
|
|
local icons = element.watched
|
|
|
|
for _, icon in pairs(icons) do
|
|
if not icon.onlyShowMissing then
|
|
icon:Hide()
|
|
else
|
|
icon:Show()
|
|
end
|
|
end
|
|
|
|
local filter, index = "HELPFUL", 1
|
|
local _, name, texture, count, duration, remaining, caster, spellID
|
|
local key, icon
|
|
|
|
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 element.strictMatching then
|
|
key = spellID
|
|
else
|
|
key = name..texture
|
|
end
|
|
|
|
icon = icons[key]
|
|
|
|
if icon and (icon.anyUnit or (caster and icon.fromUnits and icon.fromUnits[caster])) then
|
|
resetIcon(icon, element, count, duration, remaining)
|
|
GUIDs[guid][key] = true
|
|
found[key] = true
|
|
end
|
|
|
|
index = index + 1
|
|
end
|
|
end
|
|
|
|
for icon in pairs(GUIDs[guid]) do
|
|
if icons[icon] and not found[icon] then
|
|
expireIcon(icons[icon], element)
|
|
end
|
|
end
|
|
|
|
for k in pairs(found) do
|
|
found[k] = nil
|
|
end
|
|
end
|
|
|
|
local function setupIcons(self)
|
|
local element = self.AuraWatch
|
|
local icons = element.icons
|
|
|
|
element.watched = {}
|
|
|
|
for _, icon in pairs(icons) do
|
|
local name, _, image = GetSpellInfo(icon.spellID)
|
|
|
|
if name then
|
|
icon.name = name
|
|
|
|
if not icon.cd and not (element.hideCooldown or icon.hideCooldown) then
|
|
local cd = CreateFrame("Cooldown", nil, icon, "CooldownFrameTemplate")
|
|
cd:SetAllPoints(icon)
|
|
icon.cd = cd
|
|
end
|
|
|
|
if not icon.icon then
|
|
local tex = icon:CreateTexture(nil, "BACKGROUND")
|
|
tex:SetAllPoints(icon)
|
|
tex:SetTexture(image)
|
|
icon.icon = tex
|
|
|
|
if not icon.overlay then
|
|
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
|
|
end
|
|
end
|
|
|
|
if not icon.count and not (element.hideCount or icon.hideCount) then
|
|
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 = element.onlyShowMissing
|
|
end
|
|
if icon.onlyShowPresent == nil then
|
|
icon.onlyShowPresent = element.onlyShowPresent
|
|
end
|
|
if icon.presentAlpha == nil then
|
|
icon.presentAlpha = element.presentAlpha
|
|
end
|
|
if icon.missingAlpha == nil then
|
|
icon.missingAlpha = element.missingAlpha
|
|
end
|
|
if icon.fromUnits == nil then
|
|
icon.fromUnits = element.fromUnits or PLAYER_UNITS
|
|
end
|
|
if icon.anyUnit == nil then
|
|
icon.anyUnit = element.anyUnit
|
|
end
|
|
|
|
if element.strictMatching then
|
|
element.watched[icon.spellID] = icon
|
|
else
|
|
element.watched[name..image] = icon
|
|
end
|
|
|
|
if element.PostCreateIcon then
|
|
element:PostCreateIcon(icon, icon.spellID, name, self)
|
|
end
|
|
else
|
|
print("oUF_AuraWatch error: no spell with "..tostring(icon.spellID).." spell ID exists")
|
|
end
|
|
end
|
|
end
|
|
|
|
local function Enable(self)
|
|
local element = self.AuraWatch
|
|
|
|
if element then
|
|
element.Update = setupIcons
|
|
self:RegisterEvent("UNIT_AURA", Update)
|
|
setupIcons(self)
|
|
|
|
return true
|
|
end
|
|
end
|
|
|
|
local function Disable(self)
|
|
local element = self.AuraWatch
|
|
|
|
if element then
|
|
self:UnregisterEvent("UNIT_AURA", Update)
|
|
|
|
for _, icon in pairs(element.icons) do
|
|
icon:Hide()
|
|
end
|
|
end
|
|
end
|
|
|
|
oUF:AddElement("AuraWatch", Update, Enable, Disable) |