From 8ddecf8169471779682dd8e841a464b995db5a14 Mon Sep 17 00:00:00 2001 From: Xruptor Date: Mon, 17 Jan 2011 11:59:55 -0500 Subject: [PATCH] -Major update\n -Revamped the entire code -Added checks for division by zero -Added a slash command to enable non-canceling auras -Added checks for non-canceling auras --- XanBuffTimers.lua | 355 ++++++++++++++++++++++++++++------------------------- XanBuffTimers.toc | 12 +- 2 files changed, 195 insertions(+), 172 deletions(-) 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 -- 1.7.9.5