diff --git a/XanBuffTimers.lua b/XanBuffTimers.lua
index daa8c93..f4e3837 100644
--- a/XanBuffTimers.lua
+++ b/XanBuffTimers.lua
@@ -1,22 +1,23 @@
---Inspired by TextTimers
local timers = {}
local timersFocus = {}
-local timersPlayer = {}
-local math_max = _G.math.max
-local math_min = _G.math.min
local MAX_TIMERS = 15
local ICON_SIZE = 20
local BAR_ADJUST = 25
local BAR_TEXT = "llllllllllllllllllllllllllllllllllllllll"
+local band = bit.band
local targetGUID = 0
local focusGUID = 0
-local playerGUID = 0
local UnitAura = UnitAura
local UnitIsUnit = UnitIsUnit
-local f = CreateFrame("frame","XanBuffTimers",UIParent)
+local pointT = {
+ ["target"] = "XBT_Anchor",
+ ["focus"] = "XBT_FocusAnchor",
+}
+
+local f = CreateFrame("frame","xanBuffTimers",UIParent)
f:SetScript("OnEvent", function(self, event, ...) if self[event] then return self[event](self, event, ...) end end)
----------------------
@@ -27,33 +28,30 @@ function f:PLAYER_LOGIN()
if not XBT_DB then XBT_DB = {} end
if XBT_DB.scale == nil then XBT_DB.scale = 1 end
- if XBT_DB.grow == nil then XBT_DB.grow = true end
+ if XBT_DB.grow == nil then XBT_DB.grow = false end
+ if XBT_DB.sort == nil then XBT_DB.sort = false end
+ if XBT_DB.auras == nil then XBT_DB.auras = false end
- playerGUID = UnitGUID("player")
-
--create our anchors
f:CreateAnchor("XBT_Anchor", UIParent)
f:CreateAnchor("XBT_FocusAnchor", UIParent)
- f:CreateAnchor("XBT_PlayerAnchor", UIParent)
--create our timers
for i=1,MAX_TIMERS do
timers[i] = f:CreateBuffTimers()
timersFocus[i] = f:CreateBuffTimers()
- timersPlayer[i] = f:CreateBuffTimers()
end
- --do our growth process for the buff bars (SETPOINT)
- f:ProcessGrowth()
-
+ f:UnregisterEvent("PLAYER_LOGIN")
+ f.PLAYER_LOGIN = nil
+
f:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED")
f:RegisterEvent("PLAYER_TARGET_CHANGED")
f:RegisterEvent("PLAYER_FOCUS_CHANGED")
- f:RegisterEvent("UNIT_AURA")
-
+
SLASH_XANBUFFTIMERS1 = "/xanbufftimers"
SLASH_XANBUFFTIMERS2 = "/xbt"
- SLASH_XANBUFFTIMERS3 = "/xanbt"
+ SLASH_XANBUFFTIMERS3 = "/xandt"
SlashCmdList["XANBUFFTIMERS"] = function(msg)
local a,b,c=strfind(msg, "(%S+)"); --contiguous string of non-space characters
@@ -63,11 +61,9 @@ function f:PLAYER_LOGIN()
if XBT_Anchor:IsVisible() then
XBT_Anchor:Hide()
XBT_FocusAnchor:Hide()
- XBT_PlayerAnchor:Hide()
else
XBT_Anchor:Show()
XBT_FocusAnchor:Show()
- XBT_PlayerAnchor:Show()
end
return true
elseif c and c:lower() == "scale" then
@@ -78,47 +74,51 @@ function f:PLAYER_LOGIN()
for i=1, MAX_TIMERS do
timers[i]:SetScale(tonumber(scalenum))
timersFocus[i]:SetScale(tonumber(scalenum))
- timersPlayer[i]:SetScale(tonumber(scalenum))
end
- DEFAULT_CHAT_FRAME:AddMessage("XanBuffTimers: Scale has been set to ["..tonumber(scalenum).."]")
+ DEFAULT_CHAT_FRAME:AddMessage("xanBuffTimers: Scale has been set to ["..tonumber(scalenum).."]")
return true
end
end
elseif c and c:lower() == "grow" then
if XBT_DB.grow then
XBT_DB.grow = false
- DEFAULT_CHAT_FRAME:AddMessage("XanBuffTimers: Bars will now grow [|cFF99CC33UP|r]")
+ DEFAULT_CHAT_FRAME:AddMessage("xanBuffTimers: Bars will now grow [|cFF99CC33UP|r]")
else
XBT_DB.grow = true
- DEFAULT_CHAT_FRAME:AddMessage("XanBuffTimers: Bars will now grow [|cFF99CC33DOWN|r]")
+ DEFAULT_CHAT_FRAME:AddMessage("xanBuffTimers: Bars will now grow [|cFF99CC33DOWN|r]")
+ end
+ return true
+ elseif c and c:lower() == "sort" then
+ if XBT_DB.sort then
+ XBT_DB.sort = false
+ DEFAULT_CHAT_FRAME:AddMessage("xanBuffTimers: Bars sort [|cFF99CC33DESCENDING|r]")
+ else
+ XBT_DB.sort = true
+ DEFAULT_CHAT_FRAME:AddMessage("xanBuffTimers: Bars sort [|cFF99CC33ASCENDING|r]")
+ end
+ return true
+ elseif c and c:lower() == "auras" then
+ if XBT_DB.auras then
+ XBT_DB.auras = false
+ DEFAULT_CHAT_FRAME:AddMessage("xanBuffTimers: Buff Auras [|cFF99CC33OFF|r]")
+ else
+ XBT_DB.auras = true
+ DEFAULT_CHAT_FRAME:AddMessage("xanBuffTimers: Buff Auras [|cFF99CC33ON|r]")
end
- f:ProcessGrowth()
return true
end
end
- DEFAULT_CHAT_FRAME:AddMessage("XanBuffTimers")
+ DEFAULT_CHAT_FRAME:AddMessage("xanBuffTimers")
DEFAULT_CHAT_FRAME:AddMessage("/xbt anchor - toggles a movable anchor")
DEFAULT_CHAT_FRAME:AddMessage("/xbt scale # - sets the scale size of the bars")
DEFAULT_CHAT_FRAME:AddMessage("/xbt grow - changes the direction in which the bars grow (UP/DOWN)")
+ DEFAULT_CHAT_FRAME:AddMessage("/xbt sort - changes the sorting of the bars. (ASCENDING/DESCENDING)")
+ DEFAULT_CHAT_FRAME:AddMessage("/xbt auras - toggles the display of permenate/non-cancel auras (ON/OFF)")
end
- local ver = tonumber(GetAddOnMetadata("XanBuffTimers","Version")) or 'Unknown'
- DEFAULT_CHAT_FRAME:AddMessage("|cFF99CC33XanBuffTimers|r [v|cFFDF2B2B"..ver.."|r] loaded: /XBT")
-
- f:UnregisterEvent("PLAYER_LOGIN")
- f.PLAYER_LOGIN = nil
-end
-
-function f:UNIT_AURA(event, unit)
- if not unit then return end
- if unit == "target" and UnitGUID(unit) and UnitGUID(unit) == targetGUID then
- f:ProcessBuffs("target", timers)
- elseif unit == "focus" and UnitGUID(unit) and UnitGUID(unit) == focusGUID then
- f:ProcessBuffs("focus", timersFocus)
- elseif unit == "player" and UnitGUID(unit) and UnitGUID(unit) == playerGUID then
- f:ProcessBuffs("player", timersPlayer)
- end
+ local ver = tonumber(GetAddOnMetadata("xanBuffTimers","Version")) or 'Unknown'
+ DEFAULT_CHAT_FRAME:AddMessage("|cFF99CC33xanBuffTimers|r [v|cFFDF2B2B"..ver.."|r] loaded: /xbt")
end
function f:PLAYER_TARGET_CHANGED()
@@ -141,6 +141,14 @@ function f:PLAYER_FOCUS_CHANGED()
end
end
+local eventSwitch = {
+ ["SPELL_AURA_APPLIED"] = true,
+ ["SPELL_AURA_REMOVED"] = true,
+ ["SPELL_AURA_REFRESH"] = true,
+ ["SPELL_AURA_APPLIED_DOSE"] = true,
+ ["SPELL_AURA_APPLIED_REMOVED_DOSE"] = true,
+}
+
function f:COMBAT_LOG_EVENT_UNFILTERED(event, timestamp, eventType, srcGUID, srcName, srcFlags, dstGUID, dstName, dstFlags, spellID, spellName, spellSchool, auraType, amount)
if eventType == "UNIT_DIED" or eventType == "UNIT_DESTROYED" then
@@ -155,6 +163,15 @@ function f:COMBAT_LOG_EVENT_UNFILTERED(event, timestamp, eventType, srcGUID, src
f:ClearBuffs(timersFocus)
focusGUID = 0
end
+
+ elseif eventSwitch[eventType] and band(srcFlags, COMBATLOG_OBJECT_AFFILIATION_MINE) ~= 0 then
+ --process the spells based on GUID
+ if dstGUID == targetGUID then
+ f:ProcessBuffs("target", timers)
+ end
+ if dstGUID == focusGUID then
+ f:ProcessBuffs("focus", timersFocus)
+ end
end
end
@@ -237,19 +254,21 @@ local TimerOnUpdate = function(self, time)
if self.OnUpdateCounter < 0.05 then return end
self.OnUpdateCounter = 0
- local beforeEnd = self.expiryTime - GetTime()
- local barLength = ceil( string.len(BAR_TEXT) * (beforeEnd / self.durationTime) )
+ --we need to check for noncanceling auras if on
+ local beforeEnd
+ local barLength
- --self.timeleft = math_max(0, self.timeleft - (GetTime() - self.lastUpdate))
- --self.lastUpdate = GetTime()
- --local fraction = math_max(0, math_min(self.timeleft / self.durationTime, 1))
- --local barwidth = string.len(BAR_TEXT) * fraction
-
- --correct for buffs with no expiration
- if self.durationTime == 0 then
+ if XBT_DB.auras and self.durationTime <= 0 then
+ beforeEnd = 0
barLength = string.len(BAR_TEXT)
+ else
+ beforeEnd = self.endTime - GetTime()
+ barLength = ceil( string.len(BAR_TEXT) * (beforeEnd / self.durationTime) )
end
+ --check the string length JUST in case for errors
+ if barLength > string.len(BAR_TEXT) then barLength = string.len(BAR_TEXT) end
+
if barLength <= 0 then
self.active = false
self:Hide()
@@ -257,18 +276,13 @@ local TimerOnUpdate = function(self, time)
return
end
- if self.durationTime == 0 then
- self.tmpBL = string.len(BAR_TEXT)
- else
- self.tmpBL = barLength
- end
-
+ self.tmpBL = barLength
self.Bar:SetText( string.sub(BAR_TEXT, 1, barLength) )
- self.Bar:SetTextColor(f:getBarColor(self.durationTime, beforeEnd, false))
+ self.Bar:SetTextColor(f:getBarColor(self.durationTime, beforeEnd))
if self.stacks > 0 then
self.stacktext:SetText(self.stacks)
else
- self.stacktext:SetText('')
+ self.stacktext:SetText(nil)
end
self.timetext:SetText(f:GetTimeText(ceil(beforeEnd)))
f:ArrangeBuffs(true, self.id)
@@ -307,7 +321,7 @@ function f:CreateBuffTimers()
Frm.timetext:SetPoint("RIGHT", Frm.icon, "LEFT" , -5, 0)
Frm.Bar = Frm:CreateFontString(nil, "GameFontNormal")
- Frm.Bar:SetFont(STANDARD_TEXT_FONT, 14, "OUTLINE")
+ Frm.Bar:SetFont(STANDARD_TEXT_FONT, 14, "OUTLINE, MONOCHROME")
Frm.Bar:SetText(BAR_TEXT)
Frm.Bar:SetPoint("LEFT", Frm.icon, "RIGHT", 1, 0)
@@ -319,99 +333,85 @@ function f:CreateBuffTimers()
end
-function f:ProcessGrowth()
- local adj = 0
- for i=1,MAX_TIMERS do
- if XBT_DB.grow then
- timers[i]:ClearAllPoints()
- timers[i]:SetPoint("TOPLEFT", "XBT_Anchor", "BOTTOMRIGHT", 0, adj)
- --FOCUS
- timersFocus[i]:ClearAllPoints()
- timersFocus[i]:SetPoint("TOPLEFT", "XBT_FocusAnchor", "BOTTOMRIGHT", 0, adj)
- --PLAYER
- timersPlayer[i]:ClearAllPoints()
- timersPlayer[i]:SetPoint("TOPLEFT", "XBT_PlayerAnchor", "BOTTOMRIGHT", 0, adj)
- else
- timers[i]:ClearAllPoints()
- timers[i]:SetPoint("BOTTOMLEFT", "XBT_Anchor", "TOPRIGHT", 0, (adj * -1))
- --FOCUS
- timersFocus[i]:ClearAllPoints()
- timersFocus[i]:SetPoint("BOTTOMLEFT", "XBT_FocusAnchor", "TOPRIGHT", 0, (adj * -1))
- --PLAYER
- timersPlayer[i]:ClearAllPoints()
- timersPlayer[i]:SetPoint("BOTTOMLEFT", "XBT_PlayerAnchor", "TOPRIGHT", 0, (adj * -1))
- end
- adj = adj - BAR_ADJUST
- end
-end
----------------------
-- Buff Functions --
----------------------
function f:ProcessBuffs(sT, sdTimer)
- if f.selfProcessingBuffs then return end
- f.selfProcessingBuffs = true
-
--only process for as many timers as we are using
local countBuffs = 0
+
for i=1, MAX_TIMERS do
- local name, _, icon, count, _, duration, expiryTime, unitCaster, _, _, spellId = UnitAura(sT, i, 'HELPFUL')
- if name then
+
+ local name, _, icon, count, _, duration, expTime, unitCaster, _, _, spellId = UnitAura(sT, i, 'HELPFUL|PLAYER')
+ local passChk = false
+
+ --only allow non-cancel auras if the user allowed it
+ if XBT_DB.auras then
+ --auras are on so basically were allowing everything
+ passChk = true
+ elseif not XBT_DB.auras and duration > 0 then
+ --auras are not on but the duration is greater then zero, so allow
+ passChk = true
+ end
+
+ --UnitIsUnit is used JUST IN CASE (you never know lol)
+ if passChk and name and unitCaster and UnitIsUnit(unitCaster, "player") then
+ if duration <= 0 then expTime = 0 end --just in case for non-cancel auras
sdTimer[i].id = sT
sdTimer[i].spellName = name
sdTimer[i].spellId = spellId
sdTimer[i].iconTex = icon
sdTimer[i].icon:SetTexture(icon)
- sdTimer[i].startTime = expiryTime - duration
+ sdTimer[i].startTime = (expTime - duration) or 0
sdTimer[i].durationTime = duration or 0
- sdTimer[i].expiryTime = expiryTime
- --sdTimer[i].timeleft = expiryTime and math_max(0, expiryTime - GetTime()) or 0
- --sdTimer[i].lastUpdate = GetTime()
+ sdTimer[i].endTime = expTime or 0
sdTimer[i].stacks = count or 0
-
- local tmpBL = ceil( string.len(BAR_TEXT) * ( (expiryTime - GetTime()) / duration ) )
-
- if duration == 0 then
- sdTimer[i].tmpBL = string.len(BAR_TEXT)
- else
- sdTimer[i].tmpBL = tmpBL
- end
-
+ --this has to check for duration=0 because we cannot divide by zero
+ local tmpBL
+ if duration > 0 then
+ tmpBL = ceil( string.len(BAR_TEXT) * ( (expTime - GetTime()) / duration ) )
+ elseif duration <= 0 then
+ tmpBL = string.len(BAR_TEXT)
+ end
+ if tmpBL > string.len(BAR_TEXT) then tmpBL = string.len(BAR_TEXT) end
+ sdTimer[i].tmpBL = tmpBL
sdTimer[i].active = true
if not sdTimer[i]:IsVisible() then sdTimer[i]:Show() end
countBuffs = countBuffs + 1
else
- sdTimer[i].timetext:SetText('')
- sdTimer[i].Bar:SetText('')
- sdTimer[i].icon:SetTexture(nil)
sdTimer[i].active = false
if sdTimer[i]:IsVisible() then sdTimer[i]:Hide() end
end
end
-
- f.selfProcessingBuffs = nil
-
if countBuffs > 0 then
f:ArrangeBuffs(false, sT)
end
-
end
function f:ClearBuffs(sdTimer)
+ local adj = 0
+
for i=1, MAX_TIMERS do
if sdTimer[i].active then
sdTimer[i].active = false
end
- sdTimer[i].timetext:SetText('')
- sdTimer[i].Bar:SetText('')
- sdTimer[i].icon:SetTexture(nil)
+ --reset the order
+ if XBT_DB.grow then
+ sdTimer[i]:ClearAllPoints()
+ sdTimer[i]:SetPoint("TOPLEFT", pointT[sdTimer[i].id], "BOTTOMRIGHT", 0, adj)
+ else
+ sdTimer[i]:ClearAllPoints()
+ sdTimer[i]:SetPoint("BOTTOMLEFT", pointT[sdTimer[i].id], "TOPRIGHT", 0, (adj * -1))
+ end
+ adj = adj - BAR_ADJUST
+
if sdTimer[i]:IsVisible() then sdTimer[i]:Hide() end
end
+
end
function f:ArrangeBuffs(throttle, id)
- if f.selfProcessingBuffs then return end
-
--to prevent spam and reduce CPU use
if throttle then
if not f.ADT then f.ADT = GetTime() end
@@ -422,48 +422,72 @@ function f:ArrangeBuffs(throttle, id)
end
local adj = 0
- local active = {}
- local pointT
local sdTimer
if id == "target" then
sdTimer = timers
- pointT = "XBT_Anchor"
elseif id == "focus" then
sdTimer = timersFocus
- pointT = "XBT_FocusAnchor"
- elseif id == "player" then
- sdTimer = timersPlayer
- pointT = "XBT_PlayerAnchor"
else
return
end
- for i=1, MAX_TIMERS do
- if sdTimer[i].active then
- table.insert(active, sdTimer[i])
+ if XBT_DB.grow then
+ --bars will grow down
+ if XBT_DB.sort then
+ --sort from shortest to longest
+ table.sort(sdTimer, function(a,b)
+ if a.active == true and b.active == false then
+ return true;
+ elseif a.active and b.active then
+ return (a.tmpBL < b.tmpBL);
+ end
+ return false;
+ end)
else
- break
- end
- end
-
- --sort by the size of the progressbar... duh
- table.sort(active, function(a,b)
- if a.tmpBL > b.tmpBL then
- return true;
- elseif a.tmpBL == b.tmpBL then
- return (a.durationTime < b.durationTime);
+ --sort from longest to shortest
+ table.sort(sdTimer, function(a,b)
+ if a.active == true and b.active == false then
+ return true;
+ elseif a.active and b.active then
+ return (a.tmpBL > b.tmpBL);
+ end
+ return false;
+ end)
end
- end)
+ else
+ --bars will grow up
+ if XBT_DB.sort then
+ --sort from shortest to longest
+ table.sort(sdTimer, function(a,b)
+ if a.active == true and b.active == false then
+ return true;
+ elseif a.active and b.active then
+ return (a.tmpBL > b.tmpBL);
+ end
+ return false;
+ end)
+ else
+ --sort from longest to shortest
+ table.sort(sdTimer, function(a,b)
+ if a.active == true and b.active == false then
+ return true;
+ elseif a.active and b.active then
+ return (a.tmpBL < b.tmpBL);
+ end
+ return false;
+ end)
+ end
+ end
--rearrange order
- for i=1, #active do
+ for i=1, #sdTimer do
if XBT_DB.grow then
- active[i]:ClearAllPoints()
- active[i]:SetPoint("TOPLEFT", pointT, "BOTTOMRIGHT", 0, adj)
+ sdTimer[i]:ClearAllPoints()
+ sdTimer[i]:SetPoint("TOPLEFT", pointT[sdTimer[i].id], "BOTTOMRIGHT", 0, adj)
else
- active[i]:ClearAllPoints()
- active[i]:SetPoint("BOTTOMLEFT", pointT, "TOPRIGHT", 0, (adj * -1))
+ sdTimer[i]:ClearAllPoints()
+ sdTimer[i]:SetPoint("BOTTOMLEFT", pointT[sdTimer[i].id], "TOPRIGHT", 0, (adj * -1))
end
adj = adj - BAR_ADJUST
end
@@ -484,8 +508,8 @@ function f:SaveLayout(frame)
XBT_DB[frame] = {
["point"] = "CENTER",
["relativePoint"] = "CENTER",
- ["xOfs"] = 0,
- ["yOfs"] = 0,
+ ["PosX"] = 0,
+ ["PosY"] = 0,
}
opt = XBT_DB[frame];
end
@@ -494,6 +518,7 @@ function f:SaveLayout(frame)
local scale = f:GetEffectiveScale();
opt.PosX = f:GetLeft() * scale;
opt.PosY = f:GetTop() * scale;
+
end
function f:RestoreLayout(frame)
@@ -507,54 +532,52 @@ function f:RestoreLayout(frame)
XBT_DB[frame] = {
["point"] = "CENTER",
["relativePoint"] = "CENTER",
- ["xOfs"] = 0,
- ["yOfs"] = 0,
+ ["PosX"] = 0,
+ ["PosY"] = 0,
+ ["firsttime"] = true,
}
- opt = XBT_DB[frame];
+ opt = XBT_DB[frame]
end
local x = opt.PosX;
local y = opt.PosY;
- local s = f:GetEffectiveScale();
+ local s = f:GetEffectiveScale()
- if not x or not y then
- f:ClearAllPoints();
- f:SetPoint("CENTER", UIParent, "CENTER", 0, 0);
+ if not x or not y or opt.firsttime then
+ f:ClearAllPoints()
+ f:SetPoint("CENTER", UIParent, "CENTER", 0, 0)
+ if opt.firsttime then opt.firsttime = nil end
return
- end
+ end
--calculate the scale
- x,y = x/s,y/s;
+ x,y = x/s, y/s
--set the location
- f:ClearAllPoints();
- f:SetPoint("TOPLEFT", UIParent, "BOTTOMLEFT", x, y);
+ f:ClearAllPoints()
+ f:SetPoint("TOPLEFT", UIParent, "BOTTOMLEFT", x, y)
end
-function f:getBarColor(dur, expR, reverse)
- --check for buffs that don't expire
- if dur == 0 then
- return 153/255, 217/255, 234/255
+function f:getBarColor(dur, expR)
+ if dur <= 0 then
+ --this will make the bar green
+ dur = 1
+ expR = 1
end
-
local r
local g = 1
local cur = 2 * expR/dur
if cur > 1 then
- r = 2 - cur
+ return 2 - cur, 1, 0
else
- r = 1
- g = cur
- end
- if reverse then
- return g, r, 0
- else
- return r, g, 0
+ return 1, cur, 0
end
end
function f:GetTimeText(timeLeft)
+ if timeLeft <= 0 then return nil end
+
local hours, minutes, seconds = 0, 0, 0
if( timeLeft >= 3600 ) then
hours = floor(timeLeft / 3600)
diff --git a/XanBuffTimers.toc b/XanBuffTimers.toc
index 04531ca..d3bcd56 100644
--- a/XanBuffTimers.toc
+++ b/XanBuffTimers.toc
@@ -1,8 +1,8 @@
-## Interface: 30300
-## Title: XanBuffTimers
-## Notes: A small text based progress bar system for tracking buffs (player/target/focus)
-## Author: Xanthos
-## Version: 1.1
+## Interface: 40000
+## Title: xanBuffTimers
+## Notes: A small text based progress bar system for target buffs.
+## Author: Xruptor
+## Version: 1.0
## SavedVariablesPerCharacter: XBT_DB
-XanBuffTimers.lua
+xanBuffTimers.lua