ESOUI SVN ZAMBuffDisplay

[/] [trunk/] [ZAM_BuffDisplay/] [ZAM_BuffDisplay.lua] - Rev 13

Compare with Previous | Blame | View Log

-- ZAM_BuffDisplay © ZAM Network LLC
-- All Rights Reserved

local zbdVersion = "1.2"
local wm = WINDOW_MANAGER
local em = EVENT_MANAGER
local playerPool, reticlePool, db, _
local pbc = wm:CreateTopLevelWindow("ZAM_BuffDisplayPlayerContainer")
local rbc = wm:CreateTopLevelWindow("ZAM_BuffDisplayReticleoverContainer")
local GetNumBuffs = GetNumBuffs
local GetUnitBuffInfo = GetUnitBuffInfo
local GetBuffColor = GetBuffColor
local GetControl = GetControl
local zo_ceil = zo_ceil
local LAM = LibStub("LibAddonMenu-2.0")
local LMP = LibStub("LibMediaProvider-1.0")

--add option later to change text color (maybe also separate bar colors if buff/debuff?)
local defaults = {
        isLocked = true,
        player = {
                anchor = {
                        a = TOPLEFT,
                        b = TOPLEFT,
                        x = 5,
                        y = 100,
                },
                growUp = false,
        },
        reticleover = {
                anchor = {
                        a = TOPLEFT,
                        b = TOP,
                        x = 150,
                        y = 85,
                },
                growUp = false,
        },
        displayBars = true,
        font = "Arial Narrow",
        barTex = "ESO Basic",
        barColor = {
                r = .35,
                g = .35,
                b = .35,
                a = 1,
        },
        defaultTextColor = true,
        customTextColors = {
                [BUFF_EFFECT_TYPE_NOT_AN_EFFECT] = { r = 1, g = 1, b = 1},      --[0]
                [BUFF_EFFECT_TYPE_BUFF] = { r = 0, g = 1, b = 0},                       --[1]
                [BUFF_EFFECT_TYPE_DEBUFF] = { r = 1, g = 0, b = 0},                     --[2]
        },
        cmbtShow = false,
        attackShow = false,
        menuHide = false,
}

local function HandleAnchors(buff, buffID, unit)
        buff:ClearAnchors()
        local bc = unit == "player" and pbc or rbc
        local pool = unit == "player" and playerPool or reticlePool
        local anchorBuff = buffID == 1 and bc or pool:AcquireObject(buffID-1)
        if db[unit].growUp then
                buff:SetAnchor(BOTTOMLEFT, anchorBuff, anchorBuff == bc and BOTTOMLEFT or TOPLEFT)
                buff:SetAnchor(BOTTOMRIGHT, anchorBuff, anchorBuff == bc and BOTTOMRIGHT or TOPRIGHT)
        else
                buff:SetAnchor(TOPLEFT, anchorBuff, anchorBuff == bc and TOPLEFT or BOTTOMLEFT)
                buff:SetAnchor(TOPRIGHT, anchorBuff, anchorBuff == bc and TOPRIGHT or BOTTOMRIGHT)
        end
end

local function SetFonts(buff)
        buff.name:SetFont(LMP:Fetch("font", db.font).."|18|soft-shadow-thin")
        buff.time:SetFont(LMP:Fetch("font", db.font).."|18|soft-shadow-thin")
end

local function SetTexture(buff)
        buff.bar:SetTexture(LMP:Fetch("statusbar", db.barTex))
end

local function SetTextColors(unit, pool)
        --local pool = unit == "player" and playerPool or reticlePool
        for i = 1, GetNumBuffs(unit) do
                local buffName, timeStarted, timeEnding, buffSlot, stackCount, iconFilename, buffType, effectType, abilityType, statusEffectType = GetUnitBuffInfo(unit, i)
                local myBuff = pool:AcquireObject(i)
                if db.defaultTextColor then
                        myBuff.name:SetColor(GetBuffColor(effectType):UnpackRGBA())
                else
                        local color = db.customTextColors[effectType]
                        myBuff.name:SetColor(color.r, color.g, color.b)
                end
        end
end

local function CreateBuff(pool)
        local forPlayer = pool == playerPool
        local buff = ZO_ObjectPool_CreateControl(forPlayer and "ZAM_BuffDisplay_Player" or "ZAM_BuffDisplay_Reticleover", pool, forPlayer and pbc or rbc)
        buff.icon = GetControl(buff, "Icon")
        buff.time = GetControl(buff, "Time")
        buff.name = GetControl(buff, "Name")
        --GetControl(myBuff, "Name"):SetWidth(170)
        buff.bar = GetControl(buff, "Statusbar")
        buff.bar:SetColor(db.barColor.r, db.barColor.g, db.barColor.b, db.barColor.a)
        buff.bar:SetHidden(not db.displayBars)
        local buffID = pool.m_NextControlId
        HandleAnchors(buff, buffID, forPlayer and "player" or "reticleover")
        SetFonts(buff)
        SetTexture(buff)
        buff.timeLastRun = 0
        buff:SetHandler("OnUpdate", function(self, updateTime)
                        if (updateTime - self.timeLastRun) >= .5 then
                                self.timeLastRun = updateTime
                                --if self.endTime == "\195\236" then
                                if self.endTime == "--" then
                                        return
                                else
                                        local timeLeft = (self.endTime-updateTime)
                                        if timeLeft < 60 then
                                                self.time:SetText(zo_ceil(timeLeft).."s")
                                        else
                                                self.time:SetText(zo_ceil(timeLeft/60).."m")
                                        end
                                end
                        end
                end)
        buff.bar.timeLastRun = 0
        buff.bar:SetHandler("OnUpdate", function(self,updateTime)
                        if (updateTime - self.timeLastRun) >= .01 then
                                self.timeLastRun = updateTime
                                if self.noDur then
                                        return
                                else
                                        self:SetValue((buff.endTime - updateTime) + self.min)
                                end
                        end
                end)
        
        return buff
end

local function RemoveBuff(buffFrame)
        buffFrame:SetHidden(true)
end

local function UpdateBuffs(unit)
        unit = unit or "player"
        if unit ~= "player" and db.attackShow then
                if IsUnitAttackable(unit) then
                        rbc:SetHidden(false)
                        return
                else
                        rbc:SetHidden(true)
                end
        end
        local pool = unit == "player" and playerPool or reticlePool
        local numBuffs = GetNumBuffs(unit)
        for i = 1, numBuffs do
                local buffName, timeStarted, timeEnding, buffSlot, stackCount, iconFilename, buffType, effectType, abilityType, statusEffectType = GetUnitBuffInfo(unit, i)
                local myBuff = pool:AcquireObject(i)    
                myBuff.name:SetText(buffName)
                myBuff.name:SetColor(GetBuffColor(effectType):UnpackRGBA())
                --myBuff.bar:SetColor(GetBuffColor(effectType):UnpackRGBA())
                myBuff.icon:SetTexture(iconFilename)
                myBuff:SetHidden(false)
                local noDur = timeStarted == timeEnding
                myBuff.bar.noDur = noDur
                myBuff.endTime = noDur and "--" or timeEnding
                if noDur then
                        myBuff.time:SetText(myBuff.endTime)
                end
                myBuff.bar.min = timeStarted
                myBuff.bar.max = timeEnding
                myBuff.bar:SetMinMax(myBuff.bar.min, myBuff.bar.max)
        end
        local activeBuffs = pool:GetActiveObjectCount()
        if activeBuffs > numBuffs then
                for i = numBuffs+1, activeBuffs do
                        pool:ReleaseObject(i)
                end
        end
end

local function SetUpContainer(unit)
        local bc = unit == "player" and pbc or rbc
        bc:SetDimensions(250,30)
        local anchors = db[unit].anchor
        bc:SetAnchor(anchors.a, GuiRoot, anchors.b, anchors.x, anchors.y)
        bc:SetDrawLayer(DL_BACKGROUND)
        bc:SetMouseEnabled(true)
        bc:SetMovable(not db.isLocked)
        bc:SetClampedToScreen(true)
        bc:SetHandler("OnReceiveDrag", function(self)
                        if not db.isLocked then
                                self:StartMoving()
                        end
                end)
        bc:SetHandler("OnMouseUp", function(self)
                        self:StopMovingOrResizing()
                        _, anchors.a, _, anchors.b, anchors.x, anchors.y = self:GetAnchor()
                end)
        
        bc.bg = wm:CreateControl("ZAM_BuffDisplay"..unit.."ContainerBG", bc, CT_TEXTURE)
        bc.bg:SetAnchor(TOPLEFT, bc, TOPLEFT, -3, -3)
        bc.bg:SetAnchor(BOTTOMRIGHT, bc, BOTTOMRIGHT, 3, 3)
        bc.bg:SetColor(1,1,1,.5)
        bc.bg:SetAlpha(db.isLocked and 0 or .5)
end

local function CombatVisibility(event, inCombat)
        rbc:SetHidden(not inCombat)
end

local changevisibility = EVENT_ACTION_LAYER_PUSHED
--popped & pushed can fire 2-3 times in a row...
local function MenuVisibility(event)
        if event == EVENT_ACTION_LAYER_PUSHED and changevisibility == event then
                pbc:SetHidden(true)
                changevisibility = EVENT_ACTION_LAYER_POPPED
        elseif event == EVENT_ACTION_LAYER_POPPED and changevisibility == event then
                pbc:SetHidden(false)
                changevisibility = EVENT_ACTION_LAYER_PUSHED
        end
end


local panelData = {
        type = "panel",
        name = "ZAM BuffDisplay",
        displayName = "|t72:36:ZAM_BuffDisplay\\ZAM_Logo.dds|t BuffDisplay",
        slashCommand = "/zambd",
        registerForRefresh = true,
        registerForDefaults = true,
        resetFunc = function()
                                        db.player.anchor = defaults.player.anchor
                                        pbc:ClearAnchors()
                                        local anchor = db.player.anchor
                                        pbc:SetAnchor(anchor.a, GuiRoot, anchor.b, anchor.x, anchor.y)
                                        db.reticleover.anchor = defaults.reticleover.anchor
                                        pbc:ClearAnchors()
                                        local anchor = db.reticleover.anchor
                                        pbc:SetAnchor(anchor.a, GuiRoot, anchor.b, anchor.x, anchor.y)
                                end,
        author = "Seerah",
        version = zbdVersion,
}
local optionsData = {
        [1] = {
                type = "checkbox",
                name = "Lock Buff Displays",
                tooltip = "Lock or unlock the buff anchors to move them.",
                getFunc = function() return db.isLocked end,
                setFunc = function(value)
                                        db.isLocked = value
                                        pbc:SetMovable(not db.isLocked)
                                        pbc.bg:SetAlpha(db.isLocked and 0 or 1)
                                        rbc:SetMovable(not db.isLocked)
                                        rbc.bg:SetAlpha(db.isLocked and 0 or 1)
                                end,
                default = defaults.isLocked,
        },
        [2] = {
                type = "header",
                name = "Skinning Options",
        },
        [3] = {
                type = "dropdown",
                name = "Font",
                tooltip = "The font to use for the text.",
                choices = LMP:List("font"),
                getFunc = function() return db.font end,
                setFunc = function(val)
                                                db.font = val
                                                for i = 1, playerPool:GetTotalObjectCount() do
                                                        SetFonts(playerPool:AcquireObject(i))
                                                end
                                                for i = 1, reticlePool:GetTotalObjectCount() do
                                                        SetFonts(reticlePool:AcquireObject(i))
                                                end
                                        end,
                default = defaults.font,
        },
        [4] = {
                type = "dropdown",
                name = "Bar Texture",
                tooltip = "The texture used for the bars.",
                choices = LMP:List("statusbar"),
                getFunc = function() return db.barTex end,
                setFunc = function(val)
                                                db.barTex = val
                                                for i = 1, playerPool:GetTotalObjectCount() do
                                                        SetTexture(playerPool:AcquireObject(i))
                                                end
                                                for i = 1, reticlePool:GetTotalObjectCount() do
                                                        SetTexture(reticlePool:AcquireObject(i))
                                                end
                                        end,
                default = defaults.barTex,
        },
        [5] = {
                type = "colorpicker",
                name = "Statusbar Color",
                tooltip = "The color of the statusbar.",
                getFunc = function() return db.barColor.r, db.barColor.g, db.barColor.b, db.barColor.a end,
                setFunc = function(r,g,b,a)
                                                        db.barColor.r = r
                                                        db.barColor.g = g
                                                        db.barColor.b = b
                                                        db.barColor.a = a
                                                        for i = 1, playerPool:GetTotalObjectCount() do
                                                                (playerPool:AcquireObject(i)).bar:SetColor(r, g, b, a)
                                                        end
                                                        for i = 1, reticlePool:GetTotalObjectCount() do
                                                                (reticlePool:AcquireObject(i)).bar:SetColor(r, g, b, a)
                                                        end                                                     
                                                end,
                default = defaults.barColor,
        },
        [6] = {
                type = "checkbox",
                name = "Grow Player Buffs Upward",
                tooltip = "When enabled, new buffs will be added above the anchor instead of below.",
                getFunc = function() return db.player.growUp end,
                setFunc = function(value)                                                       --setFunc
                                                db.player.growUp = value
                                                for i = 1, playerPool:GetTotalObjectCount() do
                                                        HandleAnchors(playerPool:AcquireObject(i), i, "player")
                                                end
                                        end,
                default = defaults.player.growUp,
        },
        [7] = {
                type = "checkbox",
                name = "Grow Reticleover Buffs Upward",
                tooltip = "When enabled, new buffs will be added above the anchor instead of below.",
                getFunc = function() return db.reticleover.growUp end,
                setFunc = function(value)                                                       --setFunc
                                                db.reticleover.growUp = value
                                                for i = 1, reticlePool:GetTotalObjectCount() do
                                                        HandleAnchors(reticlePool:AcquireObject(i), i, "reticleover")
                                                end
                                        end,
                default = defaults.reticleover.growUp,
        },
        [8] = {
                type = "checkbox",
                name = "Display Statusbar",
                tooltip = "Display the statusbar counting down the duration of the buff.",
                getFunc = function() return db.displayBars end,
                setFunc = function(value)                                                       --setFunc
                                                db.displayBars = value
                                                for i = 1, playerPool:GetTotalObjectCount() do
                                                        (playerPool:AcquireObject(i)).bar:SetHidden(not db.displayBars)
                                                end
                                                for i = 1, reticlePool:GetTotalObjectCount() do
                                                        (reticlePool:AcquireObject(i)).bar:SetHidden(not db.displayBars)
                                                end
                                        end,
                default = defaults.displayBars,
        },
        [9] = {
                type = "checkbox",
                name = "Use Default Colors for Buff/Debuff Text",
                tooltip = "Use the default UI values for buffs (bright green) and debuffs (bright red).",
                getFunc = function() return db.defaultTextColor end,
                setFunc = function(value)
                                                db.defaultTextColor = value
                                                SetTextColors("player", playerPool)
                                                SetTextColors("reticleover", reticlePool)
                                        end,
                default = defaults.defaultTextColor,
        },
        [10] = {
                type = "colorpicker",
                name = "Buff Text Color",
                tooltip = "The color of the text on a buff bar.",
                getFunc = function() return db.customTextColors[BUFF_EFFECT_TYPE_BUFF].r, db.customTextColors[BUFF_EFFECT_TYPE_BUFF].g, db.customTextColors[BUFF_EFFECT_TYPE_BUFF].b end,
                setFunc = function(r,g,b)
                                                db.customTextColors[BUFF_EFFECT_TYPE_BUFF].r = r
                                                db.customTextColors[BUFF_EFFECT_TYPE_BUFF].g = g
                                                db.customTextColors[BUFF_EFFECT_TYPE_BUFF].b = b
                                                SetTextColors("player", playerPool)
                                                SetTextColors("reticleover", reticlePool)
                                        end,
                width = "half",
                disabled = function() return db.defaultTextColor end,
                default = defaults.customTextColors[BUFF_EFFECT_TYPE_BUFF],
        },
        [11] = {
                type = "colorpicker",
                name = "Debuff Text Color",
                tooltip = "The color of the text on a debuff bar.",
                getFunc = function() return db.customTextColors[BUFF_EFFECT_TYPE_DEBUFF].r, db.customTextColors[BUFF_EFFECT_TYPE_DEBUFF].g, db.customTextColors[BUFF_EFFECT_TYPE_DEBUFF].b end,
                setFunc = function(r,g,b)
                                                db.customTextColors[BUFF_EFFECT_TYPE_DEBUFF].r = r
                                                db.customTextColors[BUFF_EFFECT_TYPE_DEBUFF].g = g
                                                db.customTextColors[BUFF_EFFECT_TYPE_DEBUFF].b = b
                                                SetTextColors("player", playerPool)
                                                SetTextColors("reticleover", reticlePool)
                                        end,
                width = "half",
                disabled = function() return db.defaultTextColor end,
                default = defaults.customTextColors[BUFF_EFFECT_TYPE_DEBUFF],
        },
        [12] = {
                type = "header",
                name = "Visibility Options",
        },
        [13] = {
                type = "checkbox",
                name = "Only Show If Attackable",
                tooltip = "Display the target's buffs only if you can attack the unit.",
                getFunc = function() return db.attackShow end,
                setFunc = function(value)                                                       --setFunc
                                                db.attackShow = value
                                                rbc:SetHidden(db.attackShow)
                                        end,
                default = defaults.attackShow,
        },
        [14] = {
                type = "checkbox",
                name = "Only Show In Combat",
                tooltip = "Display the target's buffs only when you are in combat.",
                getFunc = function() return db.cmbtShow end,
                setFunc = function(value)                                                       --setFunc
                                                db.cmbtShow = value
                                                if db.cmbtShow then
                                                        em:RegisterForEvent("ZAM_BuffDisplay", EVENT_PLAYER_COMBAT_STATE, CombatVisibility)
                                                else
                                                        em:UnregisterForEvent("ZAM_BuffDisplay", EVENT_PLAYER_COMBAT_STATE)
                                                end
                                                rbc:SetHidden(db.cmbtShow)
                                        end,
                default = defaults.cmbtShow,
        },
        [15] = {
                type = "checkbox",
                name = "Hide In Menus",
                tooltip = "Hide the player buffs when in game menus and UI screens.",
                getFunc = function() return db.menuHide end,
                setFunc = function(value)                                                       --setFunc
                                                db.menuHide = value
                                                if db.menuHide then
                                                        em:RegisterForEvent("ZAM_BuffDisplay", EVENT_ACTION_LAYER_POPPED, MenuVisibility)
                                                        em:RegisterForEvent("ZAM_BuffDisplay", EVENT_ACTION_LAYER_PUSHED, MenuVisibility)
                                                else
                                                        em:UnregisterForEvent("ZAM_BuffDisplay", EVENT_ACTION_LAYER_POPPED, MenuVisibility)
                                                        em:UnregisterForEvent("ZAM_BuffDisplay", EVENT_ACTION_LAYER_PUSHED, MenuVisibility)
                                                end
                                                pbc:SetHidden(db.menuHide)
                                                changevisibility = EVENT_ACTION_LAYER_POPPED
                                        end,
                default = defaults.menuHide,
        },
}

local function CreateOptions()
        LAM:RegisterAddonPanel("ZAMBuffDisplayOptions", panelData)
        LAM:RegisterOptionControls("ZAMBuffDisplayOptions", optionsData)
end

local function Initialize()
        ZAM_BuffDisplayDB = ZAM_BuffDisplayDB or {}
        for k,v in pairs(defaults) do
            if type(ZAM_BuffDisplayDB[k]) == "nil" then
                ZAM_BuffDisplayDB[k] = v
            end
        end
        db = ZAM_BuffDisplayDB
        
        SetUpContainer("player")
        SetUpContainer("reticleover")
        CreateOptions()

        playerPool = ZO_ObjectPool:New(CreateBuff, RemoveBuff)
        reticlePool = ZO_ObjectPool:New(CreateBuff, RemoveBuff)
        UpdateBuffs("player")
        
        if db.cmbtShow then
                em:RegisterForEvent("ZAM_BuffDisplay", EVENT_PLAYER_COMBAT_STATE, CombatVisibility)
                rbc:SetHidden(true)
        end
        if db.menuHide then
                em:RegisterForEvent("ZAM_BuffDisplay", EVENT_ACTION_LAYER_POPPED, MenuVisibility)
                em:RegisterForEvent("ZAM_BuffDisplay", EVENT_ACTION_LAYER_PUSHED, MenuVisibility)
        end
        
        em:RegisterForEvent("ZAM_BuffDisplay", EVENT_EFFECT_CHANGED, function(event, changeType, effectSlot, effectName, unitTag, beginTime, endTime, stackCount, iconName, buffType, effectType, abilityType, statusEffectType)
                        if unitTag =="player" or unitTag == "reticleover" then
                                UpdateBuffs(unitTag)
                        end
                        if effectType == 5 then print(effectName.." = passive?") return end
                end)
        em:UnregisterForEvent("ZAM_BuffDisplay", EVENT_PLAYER_ACTIVATED)        --the next event handler was adding to instead of replacing the old one ><
        em:RegisterForEvent("ZAM_BuffDisplay", EVENT_PLAYER_ACTIVATED, function()
                        UpdateBuffs("player")
                end)
end

em:RegisterForEvent("ZAM_BuffDisplay", EVENT_PLAYER_ACTIVATED, function()
--em:RegisterForEvent("ZAM_BuffDisplay", EVENT_ADD_ON_LOADED, function(event, addon)
--              if addon == "ZAM_BuffDisplay" then
                        Initialize()
--                      em:UnregisterForEvent("ZAM_BuffDisplay", EVENT_ADD_ON_LOADED)
--              end
        end)
em:RegisterForEvent("ZAM_BuffDisplay", EVENT_RETICLE_TARGET_CHANGED, function()
                        UpdateBuffs("reticleover")
        end)

--em:RegisterForEvent("ZAM_BuffDisplay", EVENT_EFFECTS_FULL_UPDATE, function() print("full update") endem

Compare with Previous | Blame