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