WoWInterface SVN StellarUF

[/] [trunk/] [Stuf/] [aura.lua] - Rev 135

Compare with Previous | Blame | View Log

if not Stuf then return end

local Stuf = Stuf
local su = Stuf.units
local dbg, dbgaura, notmage, iswarlock
Stuf:AddOnInit(function(_, idbg, CLS) 
        dbg = idbg
        dbgaura = dbg.auracolor
        notmage, iswarlock = CLS ~= "MAGE", CLS == "WARLOCK"
end)

local floor, ceil = floor, ceil
local pairs, ipairs = pairs, ipairs
local sort, tremove, tinsert = sort, tremove, tinsert
local strmatch = strmatch
local GetTime = GetTime
local CreateFrame = CreateFrame
local GameTooltip = GameTooltip
local stamin, stahr = 1/60, 1/3600

local backdrop = { bgFile="Interface\\AddOns\\Stuf\\media\\aura1.tga", }

local key = { L = "LEFT", R = "RIGHT", T = "TOP", B = "BOTTOM", }
local function GrowthBreakdown(var)
        local d1, d2, d3, d4 = strmatch(var or "LRTB", "(%u?)(%u?)(%u?)(%u?)")
        d1, d2, d3, d4 = key[d1 or "L"], key[d2 or "R"], key[d3 or "T"], key[d4 or "B"]
        
        local hdir, vdir
        if d1 == "LEFT" or d1 == "RIGHT" then
                hdir, vdir = (d1 == "RIGHT" and -1) or 1, (d3 == "BOTTOM" and 1) or -1
        else
                hdir, vdir = (d3 == "RIGHT" and -1) or 1, (d1 == "BOTTOM" and 1) or -1
        end
        return d1, d2, d3, d4, hdir, vdir
end
Stuf.GrowthBreakdown = GrowthBreakdown


local StartTimer, StopTimer, SortTimerBars
do  -- Timer Bars handlers --------------------------------------------------------------------------------------------
        local bars = { }
        local function lsort(a, b)
                return a.endtime < b.endtime
        end
        local function ClearAndSetPoint(f, lrp, lrt, lp, lx, ly, rrp, rrt, rp, rx, ry)
                f:ClearAllPoints()
                f:SetPoint(lrp, lrt, lp, lx, ly)
                if rrp then f:SetPoint(rrp, rrt, rp, rx, ry) end
        end
        function SortTimerBars(p, ptimers)
                local db = p.db
                local count, cols, rows = db.count, db.cols, db.rows
                local d1, d2, d3, d4 = p.d1, p.d2, p.d3, p.d4
                local hdir, vdir = p.hdir, p.vdir
                local spacing, vspacing = db.spacing or 0, db.vspacing or 0

                sort(ptimers, lsort)
                if d1 == "LEFT" or d1 == "RIGHT" then  -- LRTB, LRBT, RLTB, RLBT
                        for i, icon in ipairs(ptimers) do
                                local crow = ceil(i / cols)
                                if crow > rows then
                                        icon:Hide()
                                else
                                        local ccol = i % cols
                                        ccol = (ccol == 0 and cols) or ccol
                                        icon:ClearAllPoints()
                                        if i == 1 then
                                                icon:SetPoint(d3..d1, p, d3..d1)
                                        elseif ccol == 1 then
                                                icon:SetPoint(d3, ptimers[i - cols], d4, 0, (1 + vspacing) * vdir)
                                        else
                                                icon:SetPoint(d1, ptimers[i - 1], d2, (2 + spacing) * hdir, 0)
                                        end
                                        icon:Show()
                                end
                        end
                else  -- TBLR, TBRL, BTLR, BTRL
                        for i, icon in ipairs(ptimers) do
                                local ccol = ceil(i / rows)
                                if ccol > cols then
                                        icon:Hide()
                                else
                                        icon:ClearAllPoints()
                                        local crow = i % rows
                                        crow = (crow == 0 and rows) or crow
                                        if i == 1 then
                                                icon:SetPoint(d1..d3, p, d1..d3)
                                        elseif crow == 1 then
                                                icon:SetPoint(d3, ptimers[i - rows], d4, (2 + spacing) * hdir, 0)
                                        else
                                                icon:SetPoint(d1, ptimers[i - 1], d2, 0, (1 + vspacing) * vdir)
                                        end
                                        icon:Show()
                                end
                        end
                end
        end
        local function TimerOnUpdate(this, a1)
                this.nextupdate = this.nextupdate - a1
                if this.nextupdate > 0 then return end
                this.nextupdate = this.throt
                
                local remain = this.endtime - GetTime()
                this.bar:SetValue(remain * this.duration, this.bvalue)
                if remain < 60 then
                        if remain > 10 then
                                this.time:SetFormattedText("%d", remain)
                        elseif remain > 0.8 then
                                this.nextupdate = 0.03
                                this.time:SetFormattedText("%0.1f", remain)
                        elseif remain > -0.2 then
                                this.nextupdate = 0.03
                                this:SetAlpha(remain + 0.2)
                                this.time:SetFormattedText("%0.1f", remain < 0 and 0 or remain)
                        else
                                local p = this:GetParent()
                                StopTimer(this.name, p)
                                SortTimerBars(p, p.timers)
                                return
                        end
                elseif remain < 600 then
                        this.time:SetFormattedText("%d:%02d", remain * stamin, remain % 60)
                elseif remain < 3600 then
                        this.time:SetFormattedText("%dm", 1 + remain * stamin)
                else
                        this.time:SetFormattedText("%0.1fh", remain * stahr)
                end
        end
        local function GetTimer(name, p, db)
                local timer
                for k, v in ipairs(p.timers) do
                        if v.name == name then
                                timer = v
                        end
                end
                if not timer then
                        timer = tremove(bars)  -- attempt to get unused timer
                        if not timer then  -- create new timer
                                timer = CreateFrame("Frame", nil, p)
                                timer:SetScript("OnUpdate", TimerOnUpdate)
                                timer:SetScript("OnHide", TimerOnHide)
                                timer:Hide()
                        
                                timer.icon = timer:CreateTexture(nil, "BORDER")
                                timer.icon:SetTexCoord(0.07, 0.93, 0.07, 0.93)
                                
                                local bb = timer:CreateTexture(nil, "BACKGROUND")
                                bb:SetVertexColor(0, 0, 0, 0.4)
                                timer.backbar = bb
                                
                                timer.bar = timer:CreateTexture(nil, "BORDER")
                                
                                local spark = timer:CreateTexture(nil, "ARTWORK")
                                spark:SetTexture("Interface\\CastingBar\\UI-CastingBar-Spark")
                                spark:SetBlendMode("ADD")
                                spark:SetAlpha(0.8)
                                spark:SetWidth(10)
                                timer.spark = spark
                                
                                timer.ctext = timer:CreateFontString(nil, "OVERLAY")
                                timer.ctext:SetPoint("TOPLEFT", bb, "TOPLEFT", 1, 0)
                                timer.ctext:SetPoint("BOTTOMRIGHT", bb, "BOTTOMRIGHT", -1, 0)
                                
                                timer.time = timer:CreateFontString(nil, "OVERLAY")
                                timer.time:SetPoint("TOPLEFT", bb, "TOPLEFT", 1, 0)
                                timer.time:SetPoint("BOTTOMRIGHT", bb, "BOTTOMRIGHT", -1, 0)
                        end
                        tinsert(p.timers, timer)
                end

                if timer.p ~= p or timer.pdb ~= p.dbupdate then  -- only update layout when necessary
                        timer.p, timer.pdb = p, p.dbupdate
                        
                        local icon, bar, backbar, spark, ctext, ttext = timer.icon, timer.bar, timer.backbar, timer.spark, timer.ctext, timer.time
                        local w, h = db.w, db.h
                        local sparkc = db.sparkcolor or Stuf.whitecolor
                        local fontc = db.fontcolor or Stuf.whitecolor
                        local font = Stuf:GetMedia("font", db.font)
                        local fontsize = db.fontsize or (h - 2)
                        fontsize = fontsize < 2 and 2 or fontsize
                        
                        timer:SetWidth(w)
                        timer:SetHeight(h)
                        if db.framelevel then
                                timer:SetFrameLevel(db.framelevel)
                        end
                
                        timer.bvalue = w - h
                        icon:SetWidth(h)
                        icon:SetHeight(h)
                        bar:SetHeight(h)
                        spark:SetHeight(h * 2.3)
                        spark:SetVertexColor(sparkc.r, sparkc.g, sparkc.b, sparkc.a)
                        bar:SetTexture(Stuf.statusbar)
                        backbar:SetTexture(Stuf.statusbar)
                        ctext:SetFont(font, fontsize - 1)
                        ctext:SetTextColor(fontc.r, fontc.g, fontc.b, fontc.a)
                        ttext:SetFont(font, fontsize)
                        ttext:SetTextColor(fontc.r, fontc.g, fontc.b, fontc.a)
                        
                        if db.reverse then
                                if timer.reversed ~= 1 then
                                        ClearAndSetPoint(backbar, "TOPLEFT", timer, "TOPLEFT", 0, 0, "BOTTOMRIGHT", icon, "BOTTOMLEFT", 0, 0)
                                        ClearAndSetPoint(icon, "RIGHT", timer, "RIGHT")
                                        ClearAndSetPoint(bar, "RIGHT", backbar, "RIGHT")
                                        spark:SetPoint("CENTER", bar, "LEFT")
                                        ctext:SetJustifyH("RIGHT")
                                        ttext:SetJustifyH("LEFT")
                                        Stuf:GetTexCoordOptions(false, "hflip", true, nil, bar)
                                        timer.reversed = 1
                                end
                        elseif timer.reversed ~= 0 then
                                ClearAndSetPoint(backbar, "TOPLEFT", icon, "TOPRIGHT", 0, 0, "BOTTOMRIGHT", timer, "BOTTOMRIGHT", 0, 0)
                                ClearAndSetPoint(icon, "LEFT", timer, "LEFT")
                                ClearAndSetPoint(bar, "LEFT", backbar, "LEFT")
                                spark:SetPoint("CENTER", bar, "RIGHT")
                                ctext:SetJustifyH("LEFT")
                                ttext:SetJustifyH("RIGHT")
                                Stuf:GetTexCoordOptions(false, "normal", false, nil, bar)
                                timer.reversed = 0
                        end
                end
                return timer
        end
        function StartTimer(name, duration, endtime, icon, color, count, p, spellname)
                local f = GetTimer(name, p, p.db)
                f.name = name
                f:SetParent(p)
                f.endtime = endtime
                f.duration = 1 / duration
                f.throt = (duration < 300 and 0.1) or (duration < 600 and 0.25) or 0.5
                f.nextupdate = 0
                f.ctext:SetFormattedText("%s%s", (count and count > 0 and (count.." ")) or "", p.db.showspellname and spellname or "")
                f.icon:SetTexture(icon)
                f.bar:SetVertexColor(color.r, color.g, color.b, color.a or 0.9)
                f:SetAlpha(1)
                f:Show()
        end
        function StopTimer(name, parent)
                for k, v in ipairs(parent.timers) do
                        if v.name == name then
                                v.name = ""
                                v:Hide()
                                tinsert(bars, tremove(parent.timers, k))
                                break
                        end
                end
        end
end

local function AuraTimeTextOnUpdate(this, a1)
        this.nextupdate = (this.nextupdate or 0) - a1
        if this.nextupdate > 0 then return end
        
        local remain = this.endtime - GetTime()
        if remain < 60 then
                if remain > 10 then
                        this.ttext:SetFormattedText("%d", remain)
                        this.nextupdate = remain - floor(remain)
                elseif remain > 0 then
                        this.ttext:SetFormattedText("%0.1f", remain)
                        this.nextupdate = 0.08
                else
                        this.ttext:SetText("")
                        this:SetScript("OnUpdate", nil)
                end
                if this.id and GameTooltip:IsOwned(this) then
                        this:GetScript("OnEnter")(this)
                end
        elseif remain < 3600 then
                this.ttext:SetFormattedText("%dm", 1 + remain * stamin)
                this.nextupdate = remain % 60
        else
                this.ttext:SetFormattedText("%0.1fh", remain * stahr)
                this.nextupdate = remain % 3600
        end
end
local function StartIconTimer(this, duration, endtime, mine)
        if this.ttext then
                if (mine or not this.ttextonlymine) and endtime and endtime > 0 then
                        this.endtime = endtime
                        this.nextupdate = 0
                        this:SetScript("OnUpdate", AuraTimeTextOnUpdate)
                else
                        this.ttext:SetText("")
                        this:SetScript("OnUpdate", nil)
                end
        end
        if this.showpie then
                if (mine or this.showpie ~= 1) and endtime and endtime > 0 then
                        this.pie:SetCooldown(endtime - duration, duration)
                        this.pie:Show()
                else
                        this.pie:Hide()
                end
        end
end

local UpdateAura
do      -- Aura handlers --------------------------------------------------------------------------------------------------
        local function getoffset(t, xy, dir)  -- gets precalculated offset if certain aura icons are shown
                local offset = 0
                for index, frame in ipairs(t) do
                        if frame:IsShown() then
                                offset = (frame[xy] or 0) + (1 * dir)
                        else
                                break
                        end
                end
                return offset
        end
        local function ApplyPush(buffgroup, debuffgroup, auratimers)
                local x, y = 0, 0

                local bdb = buffgroup and buffgroup.db
                local ddb = debuffgroup and debuffgroup.db
                local adb = auratimers and auratimers.db

                if buffgroup and not buffgroup.disablepush then
                        if (bdb.push == "v" or bdb.push == "h") then
                                local castbar = buffgroup:GetParent().castbar
                                if castbar and castbar:IsShown() then
                                        if bdb.push == "v" then
                                                y = (castbar.db.h + 2) * buffgroup.vdir
                                        else
                                                x = (castbar.db.w + 2) * buffgroup.hdir
                                        end
                                end
                        end
                        buffgroup:SetPoint("TOPLEFT", bdb.x + x, bdb.y + y)
                end
                if debuffgroup then
                        if buffgroup and (ddb.push == "h" or ddb.push == "v") then
                                if ddb.push == "h" then
                                        x = x + getoffset(buffgroup.firstrow, "xoff", buffgroup.hdir)
                                else
                                        y = y + getoffset(buffgroup.firstcol, "yoff", buffgroup.vdir)
                                end
                                debuffgroup:SetPoint("TOPLEFT", ddb.x + x, ddb.y + y)
                        else
                                debuffgroup:SetPoint("TOPLEFT", ddb.x, ddb.y)
                        end
                end
                if auratimers then
                        if debuffgroup and (adb.push == "h" or adb.push == "v") then
                                if adb.push == "h" then
                                        x = x + getoffset(debuffgroup.firstrow, "xoff", debuffgroup.hdir)
                                else
                                        y = y + getoffset(debuffgroup.firstcol, "yoff", debuffgroup.vdir)
                                end
                                auratimers:SetPoint("TOPLEFT", adb.x + x, adb.y + y)
                        else
                                auratimers:SetPoint("TOPLEFT", adb.x, adb.y)
                        end
                end
        end
        Stuf.ApplyPush = ApplyPush
        local ShowSetupMode
        local temp, debuffconfig, rtime, showpet = { }, nil, nil, nil
        local UnitBuff, UnitDebuff, UnitIsUnit = UnitBuff, UnitDebuff, UnitIsUnit
        function UpdateAura(unit, uf, _, _, _, config)  -- updates all elements dealing with buffs/debuffs
                uf = uf or su[unit]
                if not uf or uf.hidden then return end
                
                local allow, clr, bfilter, dfilter, onlymineb, onlymined = true, nil, nil, nil, nil, nil
                local name, icon, count, atype, duration, endtime, ismine, isstealable
                local cache = uf.cache
                
                local dispellicon, buffgroup, debuffgroup, auratimers = uf.dispellicon, uf.buffgroup, uf.debuffgroup, uf.auratimers
                if not dispellicon or dispellicon.hidden then
                        dispellicon = nil
                end
                if not buffgroup or buffgroup.hidden then
                        buffgroup = nil
                elseif cache.assist then
                        bfilter = buffgroup.filter
                        onlymineb = buffgroup.db.onlymine
                end
                if not debuffgroup or debuffgroup.hidden then
                        debuffgroup = nil
                elseif cache.assist then
                        dfilter = debuffgroup.filter
                else
                        onlymined = debuffgroup.db.onlymine
                end
                if not auratimers or auratimers.hidden then
                        auratimers = nil
                else
                        for k, v in ipairs(auratimers.timers) do
                                temp[v.name] = true
                        end
                        showpet = auratimers.db.showpet or Stuf.vunit == "pet"
                end
                if config then
                        ShowSetupMode = ShowSetupMode or function(dispellicon, buffgroup, debuffgroup, auratimers)  -- shows buffs/debuffs in config mode
                                local currenttime = GetTime()
                                if dispellicon then
                                        local dc = dbgaura.Curse
                                        dispellicon.texture:SetTexture("Interface\\Icons\\Spell_ChargeNegative")
                                        dispellicon.ctext:SetText(2)
                                        dispellicon:SetBackdropColor(dc.r, dc.g, dc.b)
                                        dispellicon:Show()
                                end
                                rtime = rtime or { 0, 65, 610, 3000, }
                                for i = 1, 32, 1 do
                                        local icon = buffgroup and buffgroup[i]
                                        if icon then
                                                icon.texture:SetTexture("Interface\\Icons\\Spell_ChargePositive")
                                                icon.ctext:SetText(i)
                                                local clr = i > 3 and dbgaura.Buff or dbgaura.MyBuff
                                                icon:SetBackdropColor(clr.r, clr.g, clr.b)
                                                icon:Show()
                                                local duration = rtime[math.random(1,4)] or 0
                                                StartIconTimer(icon, duration, currenttime + duration, true)
                                        end
                                        if auratimers and i <= auratimers.db.count/2 then
                                                local duration = 30 * i
                                                StartTimer("b"..i, duration, currenttime + duration, "Interface\\Icons\\Spell_ChargePositive", dbgaura.MyBuff, i*2 - 2, auratimers, "Spell Name Spell Name Spell Name")
                                                temp["b"..i] = nil
                                        end
                                end
                                debuffconfig = debuffconfig or { "none", "Magic", "Curse", "Poison", "Disease", }
                                for i = 1, 40, 1 do
                                        local icon = debuffgroup and debuffgroup[i]
                                        local clr = dbgaura[debuffconfig[(i % 5) + 1] or "none"]
                                        if icon then
                                                icon.texture:SetTexture("Interface\\Icons\\Spell_ChargeNegative")
                                                icon.ctext:SetText(i)
                                                icon:SetBackdropColor(clr.r, clr.g, clr.b)
                                                icon:Show()
                                                local duration = rtime[math.random(1,4)] or 0
                                                StartIconTimer(icon, duration, currenttime + duration, true)
                                        end
                                        if auratimers and i <= auratimers.db.count/2 then
                                                local duration = 30.5 * i
                                                StartTimer("d"..i, duration, currenttime + duration, "Interface\\Icons\\Spell_ChargeNegative", clr, i*2-1, auratimers, "Spell Name Spell Name Spell Name")
                                                temp["d"..i] = nil
                                        end
                                end
                                if auratimers then  -- stop timers that shouldn't exist anymore
                                        for k, v in pairs(temp) do
                                                StopTimer(k, auratimers)
                                        end
                                        SortTimerBars(auratimers, auratimers.timers)
                                end
                                ApplyPush(buffgroup, debuffgroup, auratimers)
                        end
                        return ShowSetupMode(dispellicon, buffgroup, debuffgroup, auratimers)
                end
                if dispellicon then
                        if cache.assist then
                                if iswarlock then
                                        if UnitCreatureFamily("pet") == "Felhunter" then
                                                for i = 1, 40, 1 do
                                                        name, icon, count, atype = UnitDebuff(unit, i)
                                                        if not name or atype == "Magic" then
                                                                break
                                                        else
                                                                name = nil
                                                        end
                                                end
                                        end
                                else
                                        name, icon, count, atype = UnitDebuff(unit, 1, "RAID")
                                end
                                if name then
                                        local dc = dbgaura[atype or "none"] or dbgaura.none
                                        dispellicon.texture:SetTexture(icon)
                                        dispellicon.ctext:SetText((count > 1 and count) or "")
                                        dispellicon:SetBackdropColor(dc.r, dc.g, dc.b)
                                        dispellicon:Show()
                                else
                                        dispellicon:Hide()
                                end
                        else
                                dispellicon:Hide()
                        end
                end
                
                for i = 1, 32, 1 do  -- update buffgroup
                        if allow then  -- prevents calling UnitBuff when it's useless
                                name, icon, count, atype, duration, endtime, ismine, isstealable = UnitBuff(unit, i, bfilter)
                                ismine = ismine == "player" or ismine == "vehicle" or (showpet and ismine == "pet")
                                allow = name and (not onlymineb or ismine)
                        end
                        
                        local b = buffgroup and buffgroup[i]
                        if b then
                                if allow then
                                        b.texture:SetTexture(icon)
                                        b.ctext:SetText((count and count > 1 and count) or "")
                                        if cache.attackable and (isstealable or (atype == "Magic" and notmage)) then
                                                clr = dbgaura.Magic
                                        elseif ismine then
                                                clr = dbgaura.MyBuff
                                        else
                                                clr = dbgaura.Buff
                                        end
                                        b:SetBackdropColor(clr.r, clr.g, clr.b)
                                        b:Show()
                                        StartIconTimer(b, duration, endtime, ismine)
                                else
                                        b:Hide()
                                end
                        elseif not allow then
                                break
                        end
                        if auratimers and ismine and endtime and endtime > 0 then
                                StartTimer("b"..i, duration, endtime, icon, dbgaura.MyBuff, count, auratimers, name)
                                temp["b"..i] = nil
                        end
                end
                
                allow = true
                for i = 1, 40, 1 do  -- update debuffgroup
                        if allow then  -- prevents calling UnitDebuff when it's useless
                                name, icon, count, atype, duration, endtime, ismine, isstealable = UnitDebuff(unit, i, dfilter)
                                ismine = ismine == "player" or ismine == "vehicle" or (showpet and ismine == "pet")
                                clr = dbgaura[atype or "none"] or dbgaura.none
                                allow = name and (not onlymined or ismine)
                        end
                        
                        local b = debuffgroup and debuffgroup[i]
                        if b then
                                if allow then
                                        b:SetBackdropColor(clr.r, clr.g, clr.b)
                                        b.texture:SetTexture(icon)
                                        b.ctext:SetText((count and count > 1 and count) or "")
                                        b:Show()
                                        StartIconTimer(b, duration, endtime, ismine)
                                else
                                        b:Hide()
                                end
                        elseif not allow then
                                break
                        end
                        if auratimers and ismine and endtime and endtime > 0 then
                                StartTimer("d"..i, duration, endtime, icon, clr, count, auratimers, name)
                                temp["d"..i] = nil
                        end
                end
                if auratimers then  -- stop timers that shouldn't exist anymore
                        for k, v in pairs(temp) do
                                StopTimer(k, auratimers)
                                temp[k] = nil
                        end
                        SortTimerBars(auratimers, auratimers.timers)
                end
                ApplyPush(buffgroup, debuffgroup, auratimers)
        end
end


do  -- Aura Icons -----------------------------------------------------------------------------------------------------
        local lbf = nil
        local GetWeaponEnchantInfo = GetWeaponEnchantInfo
        local function BuffOnEnter(this) -- buff tooltip
                GameTooltip:SetOwner(this, "ANCHOR_BOTTOMRIGHT", 8, -16)
                GameTooltip:SetUnitBuff(this:GetParent().unit, this.id, this:GetParent().filter)
        end
        local function DebuffOnEnter(this) -- debuff tooltip
                GameTooltip:SetOwner(this, "ANCHOR_BOTTOMRIGHT", 8, -16)
                GameTooltip:SetUnitDebuff(this:GetParent().unit, this.id, this:GetParent().filter)
        end
        local function TempOnEnter(this)
                GameTooltip:SetOwner(this, "ANCHOR_BOTTOMRIGHT", 8, -16)
                GameTooltip:SetInventoryItem("player", (this.id == 1 and 16) or 17)
        end
        local function TempEnchantOnUpdate(unit, uf, _, _, _, config)
                uf = uf or su[unit]
                local f = uf and not uf.hidden and uf.tempenchant
                if not f then return end
                
                f.tog = (f.tog or 0) + 1
                if f.tog < 4 then return end
                f.tog = 0
                
                local ctime = GetTime()
                local i1, i2 = f[1], f[2]
                
                local e1, e1duration, e1count, e1id, e2, e2duration, e2count, e2id
                if config then
                        e1, e1duration, e1count, e2, e2duration, e2count = true, 60000, 0, true, 600000, 23
                else
                        e1, e1duration, e1count, e1id, e2, e2duration, e2count, e2id = GetWeaponEnchantInfo()
                end
                if e1 then
                        i1.texture:SetTexture(GetInventoryItemTexture("player", 16))
                        i1.ctext:SetText(e1count > 1 and e1count or "")
                        i1:Show()
                        local duration = e1duration * 0.001
                        StartIconTimer(i1, duration, ctime + duration, true)
                else
                        i1:Hide()
                end
                if e2 then
                        i2.texture:SetTexture(GetInventoryItemTexture("player", 17))
                        i2.endtime = ctime + e2duration * 0.001
                        i2.ctext:SetText(e2count > 1 and e2count or "")
                        i2:Show()
                        local duration = e2duration * 0.001
                        StartIconTimer(i2, duration, ctime + duration, true)
                else
                        i2:Hide()
                end
        end
        local function CreateAuraGroup(unit, uf, name, db, _, config)
                local f = uf[name]
                local isplayer, isbuff, isdebuff, istemp = (unit == "player"), (name == "buffgroup"), (name == "debuffgroup"), (name == "tempenchant")
                if db.hide then
                        if f then
                                f.hidden = true
                                f:Hide()
                                if isplayer then
                                        if istemp then
                                                TemporaryEnchantFrame:Show()
                                        elseif isbuff then
                                                BuffFrame:Show()
                                                BuffFrame:RegisterEvent("UNIT_AURA")
                                        end
                                end
                                UpdateAura(unit, uf, nil, nil, nil, config)
                        end
                        return
                end
                if not f then
                        f = CreateFrame("Frame", nil, uf)
                        f:SetSize(2, 2)
                        f.unit = unit
                        f.db = db
                        f.firstcol, f.firstrow = { }, { }
                        
                        uf[name] = f
                        uf.refreshfuncs["auras"] = UpdateAura
                        if istemp then
                                uf.refreshfuncs.tempenchant = TempEnchantOnUpdate
                                uf.metroelements.tempenchant = TempEnchantOnUpdate
                        elseif isplayer and isbuff then
                                f.secure = CreateFrame("Frame", nil, f, "SecureAuraHeaderTemplate")
                                f.secure:SetSize(2, 2)
                                f.secure:SetAttribute("unit", "player")
                                f.secure:SetAttribute("filter", "HELPFUL")
                                f.secure:SetAttribute("separateOwn", "1")
                                f.secure:SetAttribute("template", "StufBuffTemplate")
                                f.secure:SetAttribute("minWidth", 1)
                                f.secure:SetAttribute("minHeight", 1)
                                f.secure:SetAttribute("sortMethod", "INDEX")
                                f.secure:SetAttribute("sortDir", "+")
                                f.disablepush = true
                        end
                else
                        f.hidden = nil
                        f:Show()
                end
                
                local x, y, w, h = db.x, db.y, db.w, db.h
                local cfontsize = db.counttfontsize or db.fontsize or (w < 2 and 1) or floor(w * 0.6 + 0.5)
                local cfont = Stuf:GetMedia("font", db.counttfont)
                local cfontflags = db.counttfontflags ~= "None" and db.counttfontflags
                local cc = db.counttfontcolor or Stuf.whitecolor
                local sc = dbg.shadowcolor
                local d1, d2, d3, d4, hdir, vdir = GrowthBreakdown(db.growth)
                local hfirst = (d1 == "LEFT" or d1 == "RIGHT")
                local spacing, vspacing = db.spacing or 0, db.vspacing or 0
                local cols, rows = db.cols or (hfirst and 2) or 1, db.rows or (hfirst and 1) or 2
                f.hdir, f.vdir = hdir, vdir
                
                f.filter = db.curable and "RAID"
                f:SetPoint("TOPLEFT", uf, "TOPLEFT", x, y)
                if db.framelevel then
                        f:SetFrameLevel(db.framelevel)
                end
                if istemp then
                        TemporaryEnchantFrame:Hide()
                elseif isplayer and isbuff then
                        BuffFrame:Hide()
                        BuffFrame:UnregisterEvent("UNIT_AURA")
                        f.secure:ClearAllPoints()
                        if hfirst then
                                f.secure:SetAttribute("point", d3..d1)
                                f.secure:SetAttribute("xOffset", (spacing + w) * hdir)
                                f.secure:SetAttribute("yOffset", 0)
                                f.secure:SetAttribute("wrapAfter", cols)
                                f.secure:SetAttribute("wrapXOffset", 0)
                                f.secure:SetAttribute("wrapYOffset", (vspacing + h) * vdir)
                                f.secure:SetAttribute("maxWraps", rows)
                                f.secure:SetPoint(d3..d1, f, "TOPLEFT")
                        else
                                f.secure:SetAttribute("point", d1..d3)
                                f.secure:SetAttribute("xOffset", 0)
                                f.secure:SetAttribute("yOffset", (vspacing + h) * vdir)
                                f.secure:SetAttribute("wrapAfter", rows)
                                f.secure:SetAttribute("wrapXOffset", (spacing + w) * hdir)
                                f.secure:SetAttribute("wrapYOffset", 0)
                                f.secure:SetAttribute("maxWraps", cols)
                                f.secure:SetPoint(d1..d3, f, "TOPLEFT")
                        end
                        f.secure:SetFrameLevel(f:GetFrameLevel() + 20)
                        f.secure:Show()
                end
                f:Show()

                local offset1, offset2, uselbf
                if dbg.aurastyle == 2 then
                        offset1 = w * 0.05 + 0.5
                        offset1 = (offset1 > 3 and 3) or (offset1 < 1 and 1) or floor(offset1)
                        offset2 = offset1
                        backdrop.bgFile = "Interface\\AddOns\\Stuf\\media\\aura2.tga"
                elseif dbg.aurastyle == 3 and lbf then
                        uselbf = true
                        offset1, offset2 = 0, 0
                        backdrop.bgFile = ""
                        if not Stuf.lbfgroup then
                                Stuf.lbfgroup = lbf:Group("Stuf")
                                lbf:RegisterSkinCallback("Stuf", function(_, SkinID, Gloss, Backdrop, Group, Button, Colors)
                                        dbg.lbfskin, dbg.lbfgloss, dbg.lbfbackdrop = SkinID, Gloss, Backdrop
                                end)
                        end
                        Stuf.lbfgroup:Skin(dbg.lbfskin, dbg.lbfgloss or true, dbg.lbfbackdrop or true)
                else
                        offset1 = (w < 6 and 1) or floor(w * 0.1 + 0.5)
                        offset2 = floor(w * 0.05)
                        backdrop.bgFile = "Interface\\AddOns\\Stuf\\media\\aura1.tga"
                end

                wipe(f.firstcol)
                wipe(f.firstrow)
                
                local tfc, tfont, tfontsize, tfontflags
                if not uf.ismetro and db.timefontcolor and db.timefontcolor.a > 0.1 then
                        tfc = db.timefontcolor
                        tfont = Stuf:GetMedia("font", db.timefont)
                        tfontsize = db.timefontsize or cfontsize
                        tfontflags = db.timefontflags ~= "None" and db.timefontflags
                end
                for i = 1, db.count or 2, 1 do
                        local icon = f[i]
                        if not icon then
                                icon = CreateFrame("Button", lbf and format("Stuf.units.%s.%s.a%d", unit, name, i) or nil, f)
                                icon:Hide()
                                icon.overlay = CreateFrame("Frame", nil, icon)
                                icon.overlay:SetFrameLevel(4)
                                icon.texture = icon.overlay:CreateTexture(nil, "BORDER")
                                icon.texture:SetTexCoord(0.07, 0.93, 0.07, 0.93)
                                icon.ctext = icon.overlay:CreateFontString(nil, "ARTWORK")
                        
                                icon.id = i
                                icon:SetScript("OnEnter", (isdebuff and DebuffOnEnter) or (istemp and TempOnEnter) or BuffOnEnter)
                                icon:SetScript("OnLeave", Stuf.GameTooltipOnLeave)

                                f[i] = icon
                        end
                        if db.showpie then
                                icon.pie = icon.pie or CreateFrame("Cooldown", nil, icon, "StufAuraCooldown")
                                icon.pie:SetReverse(true)
                                icon.pie.noCooldownCount = db.hidecc
                                icon.showpie = (db.pieonlymine and 1) or true
                        elseif icon.pie then
                                icon.pie:Hide()
                                icon.showpie = nil
                        end
                        icon:SetWidth(w)
                        icon:SetHeight(h)
                        icon:EnableMouse(not db.nomouse)
                        icon.SetAlpha = Stuf.SetAlpha
                        icon:SetAlpha(1)
                        icon:SetBackdrop(backdrop)
                        if uselbf then
                                icon.Icon = icon.texture
                                icon.Cooldown = icon.pie
                                icon.Border = icon.Border or icon:CreateTexture(icon:GetName().."Border", "OVERLAY")
                                Stuf.lbfgroup:AddButton(icon, icon)
                                Stuf.lbfsetcolor = Stuf.lbfsetcolor or function(icon, r, g, b, a)
                                        icon.Border:SetVertexColor(r, g, b, a)
                                end
                                icon.SetBackdropColor = Stuf.lbfsetcolor
                        else
                                if icon.Icon then
                                        icon.SetBackdropColor = Stuf.SetBackdropColor
                                end
                                icon.texture:SetPoint("TOPRIGHT", icon, "TOPRIGHT", -offset1, -offset1)
                                icon.texture:SetPoint("BOTTOMLEFT", icon, "BOTTOMLEFT", offset2, offset2)
                        end
                        if istemp then
                                icon:SetBackdropColor(0.5, 0, 1)
                        end
                        
                        icon.ctext:SetPoint("BOTTOMRIGHT", icon, "BOTTOMRIGHT", db.counttx or (-offset2 + 1), db.countty or offset2)
                        Stuf:UpdateTextLook( icon.ctext, nil, cfont, cfontsize, cfontflags,
                                             db.counttjustifyH or "RIGHT", db.counttjustifyV or "BOTTOM", cc, db.counttshadowx or -1, db.counttshadowy or 1 )
                        if tfc then
                                local ttext = icon.ttext
                                if not ttext then
                                        ttext = icon.overlay:CreateFontString(nil, "ARTWORK")
                                        icon.ttext = ttext
                                end
                                icon.ttextonlymine = db.timeonlymine
                                icon.talpha = db.alpha or 1
                                ttext:SetWidth(db.timew or (w + 4))
                                ttext:SetHeight(db.timeh or cfontsize)
                                ttext:SetPoint("TOPLEFT", icon, "TOPLEFT", db.timex or -2, db.timey or -(h - cfontsize))
                                Stuf:UpdateTextLook( ttext, nil, tfont, tfontsize, tfontflags,
                                                     db.timejustifyH, db.timejustifyV, tfc, db.timeshadowx, db.timeshadowy )
                                ttext:Show()
                        elseif icon.ttext then
                                icon.ttextonlymine = nil
                                icon.ttext:Hide()
                        end
                        
                        icon:ClearAllPoints()
                        icon.xoff, icon.yoff = nil, nil
                        if hfirst then  -- LRTB, LRBT, RLTB, RLBT
                                local crow = ceil(i / cols)
                                if crow > rows then break end
                                local ccol = i % cols
                                ccol = (ccol == 0 and cols) or ccol
                                if i == 1 then  -- first row, first col
                                        icon:SetPoint(d3..d1, f, d3..d1)
                                        icon.xoff = (w + 4 + spacing) * hdir
                                        icon.yoff = (h + 2 + vspacing) * vdir
                                        tinsert(f.firstrow, icon)
                                        tinsert(f.firstcol, icon)
                                elseif ccol == 1 then  -- start of a new row (first column)
                                        icon:SetPoint(d3, f[i - cols], d4, 0, vspacing * vdir)
                                        icon.yoff = ((h * crow) + (vspacing * crow) + 2) * vdir
                                        tinsert(f.firstcol, icon)
                                else
                                        icon:SetPoint(d1, f[i - 1], d2, spacing * hdir, 0)
                                        if crow == 1 then
                                                icon.xoff = ((w * ccol) + (spacing * ccol) + 4) * hdir
                                                tinsert(f.firstrow, icon)
                                        end
                                end
                        else  -- TBLR, TBRL, BTLR, BTRL
                                local ccol = ceil(i / rows)
                                if ccol > cols then break end
                                local crow = i % rows
                                crow = (crow == 0 and rows) or crow
                                if i == 1 then  -- first row, first col
                                        icon:SetPoint(d1..d3, f, d1..d3)
                                        icon.xoff = (w + 4 + spacing) * hdir 
                                        icon.yoff = (h + 2 + vspacing) * vdir
                                        tinsert(f.firstrow, icon)
                                        tinsert(f.firstcol, icon)
                                elseif crow == 1 then  -- start of a new column (first row)
                                        icon:SetPoint(d3, f[i - rows], d4, spacing * hdir, 0)
                                        icon.xoff = ((w * ccol) + (spacing * ccol) + 4) * hdir
                                        tinsert(f.firstrow, icon)
                                else
                                        icon:SetPoint(d1, f[i - 1], d2, 0, vspacing * vdir)
                                        if ccol == 1 then
                                                icon.yoff = ((h * crow) + (vspacing * crow) + 2) * vdir
                                                tinsert(f.firstcol, icon)
                                        end
                                end
                        end
                end  -- for
                for i = db.count + 1, 80, 1 do  -- hide icons in case db.count is less than before
                        if not f[i] then break end
                        f[i]:EnableMouse(false)
                        f[i]:SetAlpha(0)
                        f[i].SetAlpha = Stuf.nofunc
                end
                if Stuf.inworld then
                        UpdateAura(unit, uf, nil, nil, nil, config)
                end
        end
        Stuf:AddBuilder("buffgroup", CreateAuraGroup)
        Stuf:AddBuilder("debuffgroup", CreateAuraGroup)
        Stuf:AddBuilder("tempenchant", CreateAuraGroup)
        Stuf:AddEvent("UNIT_AURA", UpdateAura)
        
        Stuf:AddBuilder("auratimers", function(unit, uf, name, db, _, config)
                local f = uf[name]
                if db.hide then
                        if f then
                                f.hidden = true
                                f:Hide()
                        end
                        return
                end
                if not f then
                        f = CreateFrame("Frame", nil, uf)
                        f:SetWidth(2)
                        f:SetHeight(2)
                        f.unit = unit
                        f.db = db
                        f.timers = { }
                        uf[name] = f
                        uf.refreshfuncs["auras"] = UpdateAura
                else
                        f.hidden = nil
                        f:Show()
                end

                f.d1, f.d2, f.d3, f.d4, f.hdir, f.vdir = GrowthBreakdown(db.growth)
                f:SetPoint("TOPLEFT", uf, "TOPLEFT", db.x, db.y)
                
                f.dbupdate = (f.dbupdate or 0) + 1
                if Stuf.inworld then
                        UpdateAura(unit, uf, nil, nil, nil, config)
                end
        end)
end


do  -- Dispell Icon ---------------------------------------------------------------------------------------------------
        local function DispellOnUpdate(this, a1)  -- flash effect
                local dir = this.dir or 0.5
                local alp = (this.alp or 0.5) + a1 * dir
                if (dir == 0.5 and alp > 0.7) or (dir == -0.5 and alp < 0.3) then
                        this.dir = dir * -1
                end
                this.alp = alp
                this:SetAlpha(alp)  -- flash between 0.3 and 0.7 alpha
        end
        Stuf:AddBuilder("dispellicon", function(unit, uf, name, db, _, config)
                if not Stuf.supportspell and not iswarlock then return end
                local f = uf[name]
                if db.hide then
                        if f then
                                f.hidden = true
                                f:Hide()
                        end
                        return
                end
                if not f then
                        f = CreateFrame("Frame", nil, uf)
                        f.texture = f:CreateTexture(nil, "BORDER")
                        f.texture:SetTexCoord(0.07, 0.93, 0.07, 0.93)
                        f.ctext = f:CreateFontString(nil, "ARTWORK")
                        f:SetScript("OnUpdate", DispellOnUpdate)
                        
                        f.db = db
                        f:Hide()
                        uf.refreshfuncs["auras"] = UpdateAura
                        uf[name] = f
                else
                        f.hidden = nil
                end
                f:SetFrameLevel(db.framelevel or 3)
                f:SetWidth(db.w)
                f:SetHeight(db.h)
                f:SetPoint("TOPLEFT", uf, "TOPLEFT", db.x, db.y)
                f:SetAlpha(db.alpha or 1)
                f:SetBackdrop(backdrop)
                
                local offset1, offset2 = 0, floor(db.h * 0.05 + 0.5)
                if dbg.aurastyle == 2 then
                        backdrop.bgFile = "Interface\\AddOns\\Stuf\\media\\aura2.tga"
                        offset1 = offset2
                else
                        backdrop.bgFile = "Interface\\AddOns\\Stuf\\media\\aura1.tga"
                        offset1 = floor(db.h * 0.1 + 0.5)
                end
                f:SetBackdrop(backdrop)
                f.texture:SetPoint("TOPRIGHT", f, "TOPRIGHT", -offset1, -offset1)
                f.texture:SetPoint("BOTTOMLEFT", f, "BOTTOMLEFT", offset2, offset2)
                f.ctext:SetPoint("TOPLEFT", f, "TOPLEFT", db.counttx or 0, db.countty or 0)
                f.ctext:SetWidth(db.counttw or db.w)
                f.ctext:SetHeight(db.countth or db.h)

                Stuf:UpdateTextLook( f.ctext, db.counttfont, nil, db.counttfontsize or (db.h * 0.5), db.counttfontflags,
                                     db.counttjustifyH or "RIGHT", db.counttjustifyV or "BOTTOM", 
                                                         db.counttfontcolor or Stuf.whitecolor, db.counttshadowx or -1, db.counttshadowy or 1 )
                if Stuf.inworld then
                        UpdateAura(unit, uf, nil, nil, nil, config)
                end
        end)
end

Compare with Previous | Blame