Quantcast

-Added player buff display

Xruptor [04-18-12 - 14:44]
-Added player buff display
-Added "/xbt target" to toggle display of target buffs
-Added "/xbt focus" to toggle display of focus buffs
-Added "/xbt player" to toggle display of player buffs
-Added "/xbt infinite" to toggle display of buffs with no duration/timers. (Infinite buffs)
-Added "/xbt icon" to toggle display of buff icons
-Added "/xbt spellname" to toggle display of spell names
-Created a new player anchor for the new player buff display
-Added a new function to clean and refresh the buffs
-Updated the slash command listing
-Changed the way that infinite auras are processed and displayed.  Now infinite auras will be slightly transparent compared to those with actual timers.
-Changed the layout of the bar creation scheme to support new spellnames.
-Updated the way buffs are processed to reflect the icon, spellname, and infinite auras changes.
-Changed the way that stacks are displayed based on if icon is visible
-Completely redid the sorting algorithum to support the new infinite auras.  They will always be displayed first or last depending on the user grow bars option.
-Updated the RestoreLayout and SaveLayout routines.  I will be doing this for all my addons.
-Inifnite auras will always be a light shade of blue.  This is to distinguish it from other buffs with timers.
Filename
XanBuffTimers.lua
XanBuffTimers.toc
diff --git a/XanBuffTimers.lua b/XanBuffTimers.lua
index ab2fd16..bcfd5dc 100644
--- a/XanBuffTimers.lua
+++ b/XanBuffTimers.lua
@@ -1,22 +1,24 @@

-local timers = {}
+local timersTarget = {}
 local timersFocus = {}
+local timersPlayer = {}
 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 UnitGUID = UnitGUID
 local UnitName = UnitName

 local pointT = {
-	["target"] = "XBT_Anchor",
+	["target"] = "XBT_TargetAnchor",
 	["focus"] = "XBT_FocusAnchor",
+	["player"] = "XBT_PlayerAnchor",
 }

 local f = CreateFrame("frame","xanBuffTimers",UIParent)
@@ -32,15 +34,20 @@ function f:PLAYER_LOGIN()
 	if XBT_DB.scale == nil then XBT_DB.scale = 1 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
-	if XBT_DB.onlyFocus == nil then XBT_DB.onlyFocus = false end
+	if XBT_DB.showTarget == nil then XBT_DB.showTarget = true end
+	if XBT_DB.showFocus == nil then XBT_DB.showFocus = true end
+	if XBT_DB.showPlayer == nil then XBT_DB.showPlayer = true end
+	if XBT_DB.showInfinite == nil then XBT_DB.showInfinite = false end
+	if XBT_DB.showIcon == nil then XBT_DB.showIcon = true end
+	if XBT_DB.showSpellName == nil then XBT_DB.showSpellName = false end

 	--create our anchors
-	f:CreateAnchor("XBT_Anchor", UIParent, "xanBuffTimers: Target Anchor")
+	f:CreateAnchor("XBT_TargetAnchor", UIParent, "xanBuffTimers: Target Anchor")
 	f:CreateAnchor("XBT_FocusAnchor", UIParent, "xanBuffTimers: Focus Anchor")
+	f:CreateAnchor("XBT_PlayerAnchor", UIParent, "xanBuffTimers: Player Anchor")

-	f:UnregisterEvent("PLAYER_LOGIN")
-	f.PLAYER_LOGIN = nil
+	playerGUID = UnitGUID("player")
+	f:ProcessBuffs("player", timersPlayer)

 	f:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED")
 	f:RegisterEvent("PLAYER_TARGET_CHANGED")
@@ -54,12 +61,14 @@ function f:PLAYER_LOGIN()

 		if a then
 			if c and c:lower() == "anchor" then
-				if XBT_Anchor:IsVisible() then
-					XBT_Anchor:Hide()
+				if XBT_TargetAnchor:IsVisible() then
+					XBT_TargetAnchor:Hide()
 					XBT_FocusAnchor:Hide()
+					XBT_PlayerAnchor:Hide()
 				else
-					XBT_Anchor:Show()
+					XBT_TargetAnchor:Show()
 					XBT_FocusAnchor:Show()
+					XBT_PlayerAnchor:Show()
 				end
 				return true
 			elseif c and c:lower() == "scale" then
@@ -67,13 +76,14 @@ function f:PLAYER_LOGIN()
 					local scalenum = strsub(msg, b+2)
 					if scalenum and scalenum ~= "" and tonumber(scalenum) then
 						XBT_DB.scale = tonumber(scalenum)
-						for i=1, MAX_TIMERS do
-							if timers[i] then
-								timers[i]:SetScale(tonumber(scalenum))
-							end
-							if timersFocus[i] then
-								timersFocus[i]:SetScale(tonumber(scalenum))
-							end
+						for i=1, #timersTarget do
+							timersTarget[i]:SetScale(tonumber(scalenum))
+						end
+						for i=1, #timersFocus do
+							timersFocus[i]:SetScale(tonumber(scalenum))
+						end
+						for i=1, #timersPlayer do
+							timersPlayer[i]:SetScale(tonumber(scalenum))
 						end
 						DEFAULT_CHAT_FRAME:AddMessage("xanBuffTimers: Scale has been set to ["..tonumber(scalenum).."]")
 						return true
@@ -97,32 +107,68 @@ function f:PLAYER_LOGIN()
 					DEFAULT_CHAT_FRAME:AddMessage("xanBuffTimers: Bars sort [|cFF99CC33ASCENDING|r]")
 				end
 				return true
+			elseif c and c:lower() == "target" then
+				if XBT_DB.showTarget then
+					XBT_DB.showTarget = false
+					f:ClearBuffs(timersTarget)
+					DEFAULT_CHAT_FRAME:AddMessage("xanBuffTimers: Show target tracking [|cFF99CC33OFF|r]")
+				else
+					XBT_DB.showTarget = true
+					f:ProcessBuffs("target", timersTarget)
+					DEFAULT_CHAT_FRAME:AddMessage("xanBuffTimers: Show target tracking [|cFF99CC33ON|r]")
+				end
+				return true
 			elseif c and c:lower() == "focus" then
-				if XBT_DB.onlyFocus then
-					XBT_DB.onlyFocus = false
-					DEFAULT_CHAT_FRAME:AddMessage("xanBuffTimers: Show only focus target buffs [|cFF99CC33OFF|r]")
+				if XBT_DB.showFocus then
+					XBT_DB.showFocus = false
+					f:ClearBuffs(timersFocus)
+					DEFAULT_CHAT_FRAME:AddMessage("xanBuffTimers: Show focus tracking [|cFF99CC33OFF|r]")
 				else
-					XBT_DB.onlyFocus = true
-					DEFAULT_CHAT_FRAME:AddMessage("xanBuffTimers: Show only focus target buffs [|cFF99CC33ON|r]")
+					XBT_DB.showFocus = true
+					f:ProcessBuffs("focus", timersFocus)
+					DEFAULT_CHAT_FRAME:AddMessage("xanBuffTimers: Show focus tracking [|cFF99CC33ON|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]")
+			elseif c and c:lower() == "player" then
+				if XBT_DB.showPlayer then
+					XBT_DB.showPlayer = false
+					f:ClearBuffs(timersPlayer)
+					DEFAULT_CHAT_FRAME:AddMessage("xanBuffTimers: Show player tracking [|cFF99CC33OFF|r]")
 				else
-					XBT_DB.auras = true
-					DEFAULT_CHAT_FRAME:AddMessage("xanBuffTimers: Buff Auras [|cFF99CC33ON|r]")
+					XBT_DB.showPlayer = true
+					f:ProcessBuffs("player", timersPlayer)
+					DEFAULT_CHAT_FRAME:AddMessage("xanBuffTimers: Show player tracking [|cFF99CC33ON|r]")
 				end
-				--update the buff display
-				if UnitName("target") and UnitGUID("target") then
-					targetGUID = UnitGUID("target")
-					f:ProcessBuffs("target", timers)
+				return true
+			elseif c and c:lower() == "infinite" then
+				if XBT_DB.showInfinite then
+					XBT_DB.showInfinite = false
+					DEFAULT_CHAT_FRAME:AddMessage("xanBuffTimers: Show buffs whom have no durations/timers (Infinite) [|cFF99CC33OFF|r]")
+				else
+					XBT_DB.showInfinite = true
+					DEFAULT_CHAT_FRAME:AddMessage("xanBuffTimers: Show buffs whom have no durations/timers (Infinite) [|cFF99CC33ON|r]")
 				end
-				if UnitName("focus") and UnitGUID("focus") then
-					focusGUID = UnitGUID("focus")
-					f:ProcessBuffs("focus", timersFocus)
+				f:ReloadBuffs()
+				return true
+			elseif c and c:lower() == "icon" then
+				if XBT_DB.showIcon then
+					XBT_DB.showIcon = false
+					DEFAULT_CHAT_FRAME:AddMessage("xanBuffTimers: Show buff icons [|cFF99CC33OFF|r]")
+				else
+					XBT_DB.showIcon = true
+					DEFAULT_CHAT_FRAME:AddMessage("xanBuffTimers: Show buff icons [|cFF99CC33ON|r]")
+				end
+				f:ReloadBuffs()
+				return true
+			elseif c and c:lower() == "spellname" then
+				if XBT_DB.showSpellName then
+					XBT_DB.showSpellName = false
+					DEFAULT_CHAT_FRAME:AddMessage("xanBuffTimers: Show buff spell names [|cFF99CC33OFF|r]")
+				else
+					XBT_DB.showSpellName = true
+					DEFAULT_CHAT_FRAME:AddMessage("xanBuffTimers: Show buff spell names [|cFF99CC33ON|r]")
 				end
+				f:ReloadBuffs()
 				return true
 			end
 		end
@@ -132,26 +178,34 @@ function f:PLAYER_LOGIN()
 		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)")
-		DEFAULT_CHAT_FRAME:AddMessage("/xbt focus - toggles buffs only to be displayed for focus target (ON/OFF)")
+		DEFAULT_CHAT_FRAME:AddMessage("/xbt target - toggles target tracking (ON/OFF)")
+		DEFAULT_CHAT_FRAME:AddMessage("/xbt focus - toggles focus tracking (ON/OFF)")
+		DEFAULT_CHAT_FRAME:AddMessage("/xbt player - toggles player tracking (ON/OFF)")
+		DEFAULT_CHAT_FRAME:AddMessage("/xbt infinite - toggles displaying buffs whom have no duration/timers (ON/OFF)")
+		DEFAULT_CHAT_FRAME:AddMessage("/xbt icon - toggles displaying of buff icons (ON/OFF)")
+		DEFAULT_CHAT_FRAME:AddMessage("/xbt spellname - toggles displaying of buff spell names (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:PLAYER_TARGET_CHANGED()
-	if XBT_DB.onlyFocus then return end
+	if not XBT_DB.showTarget then return end
 	if UnitName("target") and UnitGUID("target") then
 		targetGUID = UnitGUID("target")
-		f:ProcessBuffs("target", timers)
+		f:ProcessBuffs("target", timersTarget)
 	else
-		f:ClearBuffs(timers)
+		f:ClearBuffs(timersTarget)
 		targetGUID = 0
 	end
 end

 function f:PLAYER_FOCUS_CHANGED()
+	if not XBT_DB.showFocus then return end
 	if UnitName("focus") and UnitGUID("focus") then
 		focusGUID = UnitGUID("focus")
 		f:ProcessBuffs("focus", timersFocus)
@@ -187,23 +241,29 @@ function f:COMBAT_LOG_EVENT_UNFILTERED(event, timestamp, eventType, hideCaster,
 		--clear the buffs if the unit died
 		--NOTE the reason an elseif isn't used is because some dorks may have
 		--their current target as their focus as well
-		if dstGUID == targetGUID and not XBT_DB.onlyFocus then
-			f:ClearBuffs(timers)
+		if dstGUID == targetGUID and XBT_DB.showTarget then
+			f:ClearBuffs(timersTarget)
 			targetGUID = 0
 		end
-		if dstGUID == focusGUID then
+		if dstGUID == focusGUID and XBT_DB.showFocus then
 			f:ClearBuffs(timersFocus)
 			focusGUID = 0
 		end
+		if dstGUID == playerGUID and XBT_DB.showPlayer then
+			f:ClearBuffs(timersPlayer)
+		end

 	elseif eventSwitch[eventType] and band(srcFlags, COMBATLOG_OBJECT_AFFILIATION_MINE) ~= 0 then
 		--process the spells based on GUID
-		if dstGUID == targetGUID and not XBT_DB.onlyFocus then
-			f:ProcessBuffs("target", timers)
+		if dstGUID == targetGUID and XBT_DB.showTarget then
+			f:ProcessBuffs("target", timersTarget)
 		end
-		if dstGUID == focusGUID then
+		if dstGUID == focusGUID and XBT_DB.showFocus then
 			f:ProcessBuffs("focus", timersFocus)
 		end
+		if dstGUID == playerGUID and XBT_DB.showPlayer then
+			f:ProcessBuffs("player", timersPlayer)
+		end
     end
 end

@@ -293,12 +353,15 @@ local TimerOnUpdate = function(self, time)
 		local beforeEnd
 		local barLength

-		if XBT_DB.auras and self.durationTime <= 0 then
+		--this is in case of auras with everlasting buffs (Infinite)
+		if XBT_DB and XBT_DB.showInfinite and self.durationTime <= 0 then
 			beforeEnd = 0
 			barLength = string.len(BAR_TEXT)
+			self:SetAlpha(0.5)
 		else
 			beforeEnd = self.endTime - GetTime()
 			barLength = ceil( string.len(BAR_TEXT) * (beforeEnd / self.durationTime) )
+			self:SetAlpha(1)
 		end

 		--check the string length JUST in case for errors
@@ -353,12 +416,24 @@ function f:CreateBuffTimers()
     Frm.timetext = Frm:CreateFontString(nil, "OVERLAY");
     Frm.timetext:SetFont("Fonts\\FRIZQT__.TTF",10,"OUTLINE")
     Frm.timetext:SetJustifyH("RIGHT")
-    Frm.timetext:SetPoint("RIGHT", Frm.icon, "LEFT" , -5, 0)
-
+    Frm.timetext:SetPoint("LEFT", Frm.icon, "RIGHT", 5, 0)
+
+    Frm.spellText = Frm:CreateFontString(nil, "OVERLAY");
+    Frm.spellText:SetFont("Fonts\\FRIZQT__.TTF",10,"OUTLINE")
+	Frm.spellText:SetTextColor(0,183/255,239/255)
+    Frm.spellText:SetJustifyH("RIGHT")
+    Frm.spellText:SetPoint("RIGHT", Frm.icon, "LEFT" , -5, 0)
+
+    Frm.spellText2 = Frm:CreateFontString(nil, "OVERLAY");
+    Frm.spellText2:SetFont("Fonts\\FRIZQT__.TTF",10,"OUTLINE")
+	Frm.spellText2:SetTextColor(0,183/255,239/255)
+    Frm.spellText2:SetJustifyH("RIGHT")
+    Frm.spellText2:SetPoint("RIGHT", Frm.icon, "LEFT" , 20, 0)
+
 	Frm.Bar = Frm:CreateFontString(nil, "GameFontNormal")
 	Frm.Bar:SetFont(STANDARD_TEXT_FONT, 14, "OUTLINE, MONOCHROME")
 	Frm.Bar:SetText(BAR_TEXT)
-	Frm.Bar:SetPoint("LEFT", Frm.icon, "RIGHT", 1, 0)
+	Frm.Bar:SetPoint("LEFT", Frm.icon, "RIGHT", 30, 0)

     Frm:SetScript("OnUpdate", TimerOnUpdate)

@@ -381,30 +456,55 @@ function f:ProcessBuffs(sT, sdTimer)
 		if not name then break end

 		local passChk = false
+
 		--only allow non-cancel auras if the user allowed it
-		if XBT_DB.auras then
+		if XBT_DB.showInfinite then
 			--auras are on so basically were allowing everything
 			passChk = true
-		elseif not XBT_DB.auras and duration and duration > 0 then
+		elseif not XBT_DB.showInfinite and duration 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 passChk and name and unitCaster and unitCaster == "player" then
 			--get the next timer slot we can use
 			slotNum = slotNum + 1
 			if not sdTimer[slotNum] then sdTimer[slotNum] = f:CreateBuffTimers() end --create the timer if it doesn't exist
-			if not duration or duration <= 0 then expTime = 0 end --just in case for non-cancel auras
+			if not duration or duration <= 0 then
+				sdTimer[slotNum].isInfinite = true
+				expTime = 0
+			else
+				sdTimer[slotNum].isInfinite = false
+			end
 			sdTimer[slotNum].id = sT
 			sdTimer[slotNum].spellName = name
 			sdTimer[slotNum].spellId = spellId
-			sdTimer[slotNum].iconTex = icon
-			sdTimer[slotNum].icon:SetTexture(icon)
+
+			--change the timer text according if we have icon or not and wether we are displaying spell name or not
+			if XBT_DB.showIcon then
+				sdTimer[slotNum].iconTex = icon
+				sdTimer[slotNum].icon:SetTexture(icon)
+				sdTimer[slotNum].showIcon = true
+				sdTimer[slotNum].spellText2:SetText("")
+				sdTimer[slotNum].stacks = count or 0
+				if XBT_DB.showSpellName then
+					sdTimer[slotNum].spellText:SetText(name)
+				else
+					sdTimer[slotNum].spellText:SetText("")
+					sdTimer[slotNum].spellText2:SetText("")
+				end
+			else
+				sdTimer[slotNum].iconTex = icon
+				sdTimer[slotNum].icon:SetTexture(nil)
+				sdTimer[slotNum].showIcon = false
+				sdTimer[slotNum].spellText:SetText("")
+				sdTimer[slotNum].stacks = 0
+				sdTimer[slotNum].spellText2:SetText(name)
+			end
+
 			sdTimer[slotNum].startTime = (expTime - duration) or 0
 			sdTimer[slotNum].durationTime = duration or 0
 			sdTimer[slotNum].endTime = expTime or 0
-			sdTimer[slotNum].stacks = count or 0
 				--this has to check for duration=0 because we cannot divide by zero
 				local tmpBL
 				if duration > 0 then
@@ -452,6 +552,15 @@ function f:ClearBuffs(sdTimer)

 end

+function f:ReloadBuffs()
+	f:ClearBuffs(timersTarget)
+	f:ClearBuffs(timersFocus)
+	f:ClearBuffs(timersPlayer)
+	f:ProcessBuffs("target", timersTarget)
+	f:ProcessBuffs("focus", timersFocus)
+	f:ProcessBuffs("player", timersPlayer)
+end
+
 function f:ArrangeBuffs(throttle, id)
 	--to prevent spam and reduce CPU use
 	if throttle then
@@ -466,9 +575,11 @@ function f:ArrangeBuffs(throttle, id)
 	local sdTimer

 	if id == "target" then
-		sdTimer = timers
+		sdTimer = timersTarget
 	elseif id == "focus" then
 		sdTimer = timersFocus
+	elseif id == "player" then
+		sdTimer = timersPlayer
 	else
 		return
 	end
@@ -480,7 +591,9 @@ function f:ArrangeBuffs(throttle, id)
 			table.sort(sdTimer, function(a,b)
 				if a.active == true and b.active == false then
 					return true;
-				elseif a.active and b.active then
+				elseif a.active and b.active and b.isInfinite then
+					return false;
+				elseif a.active and b.active and not b.isInfinite then
 					return (a.tmpBL < b.tmpBL);
 				end
 				return false;
@@ -490,7 +603,9 @@ function f:ArrangeBuffs(throttle, id)
 			table.sort(sdTimer, function(a,b)
 				if a.active == true and b.active == false then
 					return true;
-				elseif a.active and b.active then
+				elseif a.active and b.active and a.isInfinite then
+					return true;
+				elseif a.active and b.active and not a.isInfinite then
 					return (a.tmpBL > b.tmpBL);
 				end
 				return false;
@@ -503,7 +618,9 @@ function f:ArrangeBuffs(throttle, id)
 			table.sort(sdTimer, function(a,b)
 				if a.active == true and b.active == false then
 					return true;
-				elseif a.active and b.active then
+				elseif a.active and b.active and a.isInfinite then
+					return true;
+				elseif a.active and b.active and not a.isInfinite then
 					return (a.tmpBL > b.tmpBL);
 				end
 				return false;
@@ -513,7 +630,9 @@ function f:ArrangeBuffs(throttle, id)
 			table.sort(sdTimer, function(a,b)
 				if a.active == true and b.active == false then
 					return true;
-				elseif a.active and b.active then
+				elseif a.active and b.active and b.isInfinite then
+					return false;
+				elseif a.active and b.active and not b.isInfinite then
 					return (a.tmpBL < b.tmpBL);
 				end
 				return false;
@@ -540,71 +659,54 @@ end
 ----------------------

 function f:SaveLayout(frame)
-
+	if type(frame) ~= "string" then return end
+	if not _G[frame] then return end
 	if not XBT_DB then XBT_DB = {} end
+
+	local opt = XBT_DB[frame] or nil

-	local opt = XBT_DB[frame] or nil;
-
-	if opt == nil then
+	if not opt then
 		XBT_DB[frame] = {
 			["point"] = "CENTER",
 			["relativePoint"] = "CENTER",
-			["PosX"] = 0,
-			["PosY"] = 0,
+			["xOfs"] = 0,
+			["yOfs"] = 0,
 		}
-		opt = XBT_DB[frame];
+		opt = XBT_DB[frame]
+		return
 	end

-	local f = getglobal(frame);
-	local scale = f:GetEffectiveScale();
-	opt.PosX = f:GetLeft() * scale;
-	opt.PosY = f:GetTop() * scale;
-
+	local point, relativeTo, relativePoint, xOfs, yOfs = _G[frame]:GetPoint()
+	opt.point = point
+	opt.relativePoint = relativePoint
+	opt.xOfs = xOfs
+	opt.yOfs = yOfs
 end

 function f:RestoreLayout(frame)
-
+	if type(frame) ~= "string" then return end
+	if not _G[frame] then return end
 	if not XBT_DB then XBT_DB = {} end
-
-	local f = getglobal(frame);
-	local opt = XBT_DB[frame] or nil;

-	if opt == nil then
+	local opt = XBT_DB[frame] or nil
+
+	if not opt then
 		XBT_DB[frame] = {
 			["point"] = "CENTER",
 			["relativePoint"] = "CENTER",
-			["PosX"] = 0,
-			["PosY"] = 0,
-			["firsttime"] = true,
+			["xOfs"] = 0,
+			["yOfs"] = 0,
 		}
 		opt = XBT_DB[frame]
 	end

-	local x = opt.PosX;
-	local y = opt.PosY;
-	local s = f:GetEffectiveScale()
-
-	if opt.firsttime then
-		f:ClearAllPoints()
-		f:SetPoint("CENTER", UIParent, "CENTER", 0, 0)
-		if opt.firsttime then opt.firsttime = nil end
-		return
-	end
-
-	--calculate the scale
-	x,y = x/s, y/s
-
-	--set the location
-	f:ClearAllPoints()
-	f:SetPoint("TOPLEFT", UIParent, "BOTTOMLEFT", x, y)
-
+	_G[frame]:ClearAllPoints()
+	_G[frame]:SetPoint(opt.point, UIParent, opt.relativePoint, opt.xOfs, opt.yOfs)
 end

 function f:getBarColor(dur, expR)
 	if dur <= 0 then
-		--this will make the bar green
-		dur = 1
-		expR = 1
+		return 0, 183/255, 239/255
 	end
 	local r
 	local g = 1
diff --git a/XanBuffTimers.toc b/XanBuffTimers.toc
index 677706f..c91d4ae 100644
--- a/XanBuffTimers.toc
+++ b/XanBuffTimers.toc
@@ -1,8 +1,8 @@
 ## Interface: 40300
 ## Title: xanBuffTimers
-## Notes: A small text based progress bar system for target buffs.
+## Notes: A small text based progress bar system for target/focus/player buffs.
 ## Author: Xruptor
-## Version: 2.2
+## Version: 3.0
 ## SavedVariablesPerCharacter: XBT_DB

 xanBuffTimers.lua