--[[---------------------------------------------------------- Srendarr - Aura & Buff Tracker ---------------------------------------------------------- * * * Version 1.60 * Kith, Garkin, silentgecko * * ]]-- local Srendarr = _G['Srendarr'] -- grab addon table from global local L Srendarr.name = 'Srendarr' Srendarr.slash = '/srendarr' Srendarr.version = '1.60' Srendarr.versionDB = 2 -- CONSTANTS Srendarr.ICON_SIZE = 40 Srendarr.BAR_HEIGHT = 16 Srendarr.SPAM_THRESHOLD = 0.25 -- button mash limiter Srendarr.UPDATE_THRESHOLD = 0.5 -- don't update aura display if start|finish values change by less than this Srendarr.UPDATE_RATE = 0.05 -- (ms) update rate Srendarr.AURA_FADE_TIME = 1 -- (ms) time to fade expired (timed) auras Srendarr.auraAnchors = {} -- display anchors for all 3 frames Srendarr.auraFrames = {} Srendarr.auraSceneFragments = {} Srendarr.ui_Locked = true local defaults = { -- general combineBuff = true, shortBuffThreshold = 90, -- buffs shorter then this value will be displayed on short buff frame onlyInCombat = false, showTargetAuras = false, showDebuff = true, hideMinorBuffs = false, hideMajorBuffs = false, -- filters showSoulSummons = true, showSoulSummonsTarget = true, showToggle = true, showToggleTarget = true, showPassive = true, -- master control for passives showPassiveTarget = true, -- master control for target passives showCyrodiil = true, showCyrodiilTarget = true, showDisguise = true, showDisguiseTarget = true, showAllEffects = false, showAllEffectsTarget = false, showMundus = true, showMundusTarget = true, showVampLycan = true, showVampLycanTarget = true, -- windows frames = { [1] = { -- short (and combined) buffs anchor = {point = BOTTOMRIGHT, x = 0, y = 0}, alpha = 1.0, scale = 1.0, tooltips = false, auraGrowth = 'UP', -- UP|DOWN|LEFT|LEFTCENTER|RIGHT|RIGHTCENTER auraPadding = 4, auraSort = 'TIME', -- TIME|NAME auraIconOnRight = true, -- only for vertical growth showNameBar = true, -- name nameFont = 'Univers 67', nameColour = {r = 0.9, g = 0.9, b = 0.9}, nameOutline = 'soft-shadow-thick', nameSize = 16, -- timer timerShowTP = false, -- show timer for (T)gogles or (P)assives timerShowHorz = 'BELOW', -- BELOW|ABOVE|OVER|HIDE timerShowVert = 'OVER', -- OVER|HIDE timerFont = 'Univers 67', timerColour = {r = 0.9, g = 0.9, b = 0.9}, timerOutline = 'soft-shadow-thick', timerSize = 14, barGloss = true, barWidth = 160, barColours = { timed = {r1 = 0, g1 = 0.1843137294054, b1 = 0.50980395078659, r2 = 0.32156863808632, g2 = 0.8431373285635, b2 = 1}, toggle = {r1 = 0.77647066116333, g1 = 0.60000002384186, b1 = 0.11372549831867, r2 = 0.97254908084869, g2 = 0.87450987100601, b2 = 0.29411765933037}, passive = {r1 = 0.41960787773132, g1 = 0.38039219379425, b1 = 0.23137256503105, r2 = 0.41960787773132, g2 = 0.38039219379425, b2 = 0.23137256503105}, }, }, [2] = { -- long buffs anchor = {point = BOTTOMRIGHT, x = -210, y = 0}, alpha = 1.0, scale = 1.0, tooltips = false, auraGrowth = 'UP', -- UP|DOWN|LEFT|LEFTCENTER|RIGHT|RIGHTCENTER auraPadding = 4, auraSort = 'TIME', -- TIME|NAME auraIconOnRight = true, -- only for vertical growth showNameBar = true, -- name nameFont = 'Univers 67', nameColour = {r = 0.9, g = 0.9, b = 0.9}, nameOutline = 'soft-shadow-thick', nameSize = 16, -- timer timerShowTP = false, -- show timer for (T)gogles or (P)assives timerShowHorz = 'BELOW', -- BELOW|ABOVE|OVER|HIDE timerShowVert = 'OVER', -- OVER|HIDE timerFont = 'Univers 67', timerColour = {r = 0.9, g = 0.9, b = 0.9}, timerOutline = 'soft-shadow-thick', timerSize = 14, barGloss = true, barWidth = 160, barColours = { timed = {r1 = 0, g1 = 0.1843137294054, b1 = 0.50980395078659, r2 = 0.32156863808632, g2 = 0.8431373285635, b2 = 1}, toggle = {r1 = 0.77647066116333, g1 = 0.60000002384186, b1 = 0.11372549831867, r2 = 0.97254908084869, g2 = 0.87450987100601, b2 = 0.29411765933037}, passive = {r1 = 0.41960787773132, g1 = 0.38039219379425, b1 = 0.23137256503105, r2 = 0.41960787773132, g2 = 0.38039219379425, b2 = 0.23137256503105}, }, }, [3] = { -- debuffs anchor = {point = TOPRIGHT, x = 0, y = 0}, alpha = 1.0, scale = 1.0, tooltips = false, auraGrowth = 'DOWN', -- UP|DOWN|LEFT|LEFTCENTER|RIGHT|RIGHTCENTER auraPadding = 4, auraSort = 'TIME', -- TIME|NAME auraIconOnRight = true, -- only for vertical growth showNameBar = true, -- name nameFont = 'Univers 67', nameColour = {r = 0.9, g = 0.9, b = 0.9}, nameOutline = 'soft-shadow-thick', nameSize = 16, -- timer timerShowTP = false, -- show timer for (T)gogles or (P)assives timerShowHorz = 'BELOW', -- BELOW|ABOVE|OVER|HIDE timerShowVert = 'OVER', -- OVER|HIDE timerFont = 'Univers 67', timerColour = {r = 0.9, g = 0.9, b = 0.9}, timerOutline = 'soft-shadow-thick', timerSize = 14, barGloss = true, barWidth = 160, barColours = { timed = {r1 = 0, g1 = 0.1843137294054, b1 = 0.50980395078659, r2 = 0.32156863808632, g2 = 0.8431373285635, b2 = 1}, toggle = {r1 = 0.77647066116333, g1 = 0.60000002384186, b1 = 0.11372549831867, r2 = 0.97254908084869, g2 = 0.87450987100601, b2 = 0.29411765933037}, passive = {r1 = 0.41960787773132, g1 = 0.38039219379425, b1 = 0.23137256503105, r2 = 0.41960787773132, g2 = 0.38039219379425, b2 = 0.23137256503105}, }, }, [4] = { -- target long buffs anchor = {point = TOP, x = 161, y = 88}, alpha = 1.0, scale = 0.8, tooltips = false, auraGrowth = 'RIGHT', -- UP|DOWN|LEFT|LEFTCENTER|RIGHT|RIGHTCENTER auraPadding = 2, auraSort = 'NAME', -- TIME|NAME auraIconOnRight = true, -- only for vertical growth showNameBar = true, -- name nameFont = 'Univers 67', nameColour = {r = 0.9, g = 0.9, b = 0.9}, nameOutline = 'soft-shadow-thick', nameSize = 16, -- timer timerShowTP = false, -- show timer for (T)gogles or (P)assives timerShowHorz = 'BELOW', -- BELOW|ABOVE|OVER|HIDE timerShowVert = 'OVER', -- OVER|HIDE timerFont = 'Univers 67', timerColour = {r = 0.9, g = 0.9, b = 0.9}, timerOutline = 'soft-shadow-thick', timerSize = 14, barGloss = true, barWidth = 160, barColours = { timed = {r1 = 0, g1 = 0.1843137294054, b1 = 0.50980395078659, r2 = 0.32156863808632, g2 = 0.8431373285635, b2 = 1}, toggle = {r1 = 0.77647066116333, g1 = 0.60000002384186, b1 = 0.11372549831867, r2 = 0.97254908084869, g2 = 0.87450987100601, b2 = 0.29411765933037}, passive = {r1 = 0.41960787773132, g1 = 0.38039219379425, b1 = 0.23137256503105, r2 = 0.41960787773132, g2 = 0.38039219379425, b2 = 0.23137256503105}, }, }, [5] = { -- debuffs anchor = {point = TOPRIGHT, x = 0, y = 0}, alpha = 1.0, scale = 1.0, tooltips = false, auraGrowth = 'DOWN', -- UP|DOWN|LEFT|LEFTCENTER|RIGHT|RIGHTCENTER auraPadding = 4, auraSort = 'TIME', -- TIME|NAME auraIconOnRight = true, -- only for vertical growth showNameBar = true, -- name nameFont = 'Univers 67', nameColour = {r = 0.9, g = 0.9, b = 0.9}, nameOutline = 'soft-shadow-thick', nameSize = 16, -- timer timerShowTP = false, -- show timer for (T)gogles or (P)assives timerShowHorz = 'BELOW', -- BELOW|ABOVE|OVER|HIDE timerShowVert = 'OVER', -- OVER|HIDE timerFont = 'Univers 67', timerColour = {r = 0.9, g = 0.9, b = 0.9}, timerOutline = 'soft-shadow-thick', timerSize = 14, barGloss = true, barWidth = 160, barColours = { timed = {r1 = 0, g1 = 0.1843137294054, b1 = 0.50980395078659, r2 = 0.32156863808632, g2 = 0.8431373285635, b2 = 1}, toggle = {r1 = 0.77647066116333, g1 = 0.60000002384186, b1 = 0.11372549831867, r2 = 0.97254908084869, g2 = 0.87450987100601, b2 = 0.29411765933037}, passive = {r1 = 0.41960787773132, g1 = 0.38039219379425, b1 = 0.23137256503105, r2 = 0.41960787773132, g2 = 0.38039219379425, b2 = 0.23137256503105}, }, }, }, } function Srendarr.OnInitialize(code, addon) if (addon ~= Srendarr.name) then return end local self = Srendarr EVENT_MANAGER:UnregisterForEvent(self.name, EVENT_ADD_ON_LOADED) SLASH_COMMANDS[self.slash] = self.SlashCommand self.db = ZO_SavedVars:New('SrendarrDB', self.versionDB, nil, defaults) L = self:GetLocale() for x = 1, 5 do local db = self.db.frames[x] self.auraAnchors[x] = self.AuraAnchor:New(x, db.anchor.point, db.anchor.x, db.anchor.y, db.scale) self.auraFrames[x] = self.AuraFrame:New(x, db.alpha) self.auraSceneFragments[x] = ZO_HUDFadeSceneFragment:New(self.auraAnchors[x]) HUD_SCENE:AddFragment(self.auraSceneFragments[x]) HUD_UI_SCENE:AddFragment(self.auraSceneFragments[x]) SIEGE_BAR_SCENE:AddFragment(self.auraSceneFragments[x]) end self:InitializeEvents() self:InitializeOnUpdate() self:InitializeAbilityCheck() self:InitializeSettings() end function Srendarr.SlashCommand(text) if (text == 'lock') then for _, frame in pairs(Srendarr.auraAnchors) do frame:DisableDrag() end Srendarr.ui_Locked = true elseif (text == 'unlock') then for _, frame in pairs(Srendarr.auraAnchors) do frame:EnableDrag() end Srendarr.ui_Locked = false else CHAT_SYSTEM:AddMessage(Srendarr:GetLocale().Usage) end end -- Remove all auras (called on player death and settings changes) function Srendarr:StripAuras() self:ClearTimers() -- end all update timers for _, frame in pairs(self.auraFrames) do frame:RemoveAllAuras() end end -- Check and add auras that are 'known' to the player, called on player alive, settings changes and 'proper' zone changes function Srendarr:UpdateAuras() self:StripAuras() local numAuras = GetNumBuffs('player') local auraFrameShort = self.auraFrames[1] local auraFrameDebuffs = self.auraFrames[3] local auraFrameLong = self.db.combineBuff and self.auraFrames[1] or self.auraFrames[2] local updateShort = false local updateLong = false if (self.db.showTargetAurasDebuff) then local numAurasTarget = GetNumBuffs('reticleover') if (numAurasTarget > 0) then for x = 1, numAurasTarget do local name, start, finish, buff, stack, icon, _, effectType, abilityType, _, abilityId = GetUnitBuffInfo('reticleover', x) local isShield = abilityType == ABILITY_TYPE_DAMAGESHIELD -- Skip Minor Buffs if (Srendarr.db.hideMinorBuffs and Srendarr.MinorBuffs[abilityId] ~= nil) then return end -- Skip Major Buffs if (Srendarr.db.hideMajorBuffs and Srendarr.MajorBuffs[abilityId] ~= nil) then return end if (finish > start) then if (Srendarr:IsWatchedTimedTarget(name)) then auraFrameShort:AddAura(1, 2, name, icon, start, finish, isShield, abilityType, buff, abilityId, effectType) end end end auraFrameShort:UpdateDisplay() end end if (numAuras > 0) then -- existing 'known' auras, re-add and UpdateDisplay for x = 1, numAuras do local name, start, finish, buff, stack, icon, _, effectType, abilityType, statusEffectType, abilityId = GetUnitBuffInfo('player', x) local isShield = abilityType == ABILITY_TYPE_DAMAGESHIELD -- Skip Minor Buffs if (Srendarr.db.hideMinorBuffs and Srendarr.MinorBuffs[abilityId] ~= nil) then return end -- Skip Major Buffs if (Srendarr.db.hideMajorBuffs and Srendarr.MajorBuffs[abilityId] ~= nil) then return end if (finish > start) then -- timed ability if(effectType == BUFF_EFFECT_TYPE_DEBUFF) then d('abilityId', abilityId) d('abilityName', name) d('buff', buff) d('effectType', effectType) d('statufEffectType', statusEffectType) if (Srendarr:IsWatchedTimed(name)) then auraFrameDebuffs:AddAura(1, 1, name, icon, start, finish, isShield, abilityType, buff, abilityId, effectType) end else if (finish - start < self.db.shortBuffThreshold) then if (Srendarr:IsWatchedTimed(name)) then auraFrameShort:AddAura(1, 1, name, icon, start, finish, isShield, abilityType, buff, abilityId, effectType) updateShort = true end else if (self:IsWatchedTimed(name)) then auraFrameLong:AddAura(2, 1, name, icon, start, finish, isShield, abilityType, buff, abilityId, effectType) updateLong = true end end end elseif (self:IsToggled(name)) then -- toggled ability if (self.db.showToggle) then -- showing toggled auraFrameLong:AddAura(3, 1, name, icon, 1, 1, isShield, abilityType, buff, abilityId, effectType) updateLong = true end else -- passive (assumption: passives have start = finish) if (abilityType == ABILITY_TYPE_REGISTERTRIGGER) then auraFrameShort:AddAura(4, 1, name, icon, 1, 1, isShield, abilityType, buff, abilityId, effectType) updateShort = true elseif (self:IsWatchedPassive(name, abilityType)) then -- validate against user settings auraFrameLong:AddAura(4, 1, name, icon, 1, 1, isShield, abilityType, buff, abilityId, effectType) updateLong = true end end if (abilityType == ABILITY_TYPE_REGISTERTRIGGER) then local slotNum = self:GetTriggeredSlotNum(name) if slotNum then local actionButton = ZO_ActionBar_GetButton(slotNum) self:PlayProcAnimations(actionButton) end end if (name == L.Passive_MedicinalUse) then self:SetMedicinalUseCoefficient(abilityId) end end end if (updateShort) then auraFrameShort:UpdateDisplay() end if (updateLong) then auraFrameLong:UpdateDisplay() end end do -- TIMER AND STATUSBAR UPDATE HANDLER local RATE = Srendarr.UPDATE_RATE local FADE_TIME = Srendarr.AURA_FADE_TIME * -1 local CAST_TIME = 1 -- fake 'max cast time' to make a facsimile casting bar when needed local strformat = string.format local math_floor = math.floor local math_max = math.max local seconds = '' local minutes = '' local hours = '' local cast = '' local auraTimers = { [1] = {}, -- buffs [2] = {}, -- debuffs [3] = {}, -- target buffs [4] = {}, -- target debuffs } local nextUpdate = 0 local percent, remaining local function FormatTime(remaining) if (remaining < 60) then -- seconds return strformat(seconds, remaining) elseif (remaining < 3600) then -- minutes return strformat(minutes, math_floor(remaining / 60)) else -- hours return strformat(hours, math_floor(remaining / 3600)) end end local function OnUpdate(self, updateTime) if (updateTime >= nextUpdate) then for _, timers in pairs(auraTimers) do for _, aura in pairs(timers) do remaining = aura.k_finish - updateTime if (remaining < FADE_TIME) then -- expired and finished fading, kill aura.k_frame:RemoveAura(aura.k_name) elseif (remaining <= 0) then -- expired but hasn't faded yet if (not aura.k_isGhost) then aura:Ghost() end aura:SetAlpha(math_max(0, 1 - (remaining / FADE_TIME))) elseif (aura.k_start > updateTime) then -- must have a cast time aura.bar:SetValue(math_max(0, (updateTime - aura.k_start) + CAST_TIME)) aura.timer:SetText(cast) else -- normal timer aura.bar:SetValue(1 - ((updateTime - aura.k_start) / (aura.k_finish - aura.k_start))) aura.timer:SetText(FormatTime(remaining)) end end end nextUpdate = updateTime + RATE end end function Srendarr:AddTimer(bdType, name, aura) if (not auraTimers[bdType][name]) then auraTimers[bdType][name] = aura end end function Srendarr:RemoveTimer(bdType, name) if (auraTimers[bdType][name]) then auraTimers[bdType][name] = nil end end function Srendarr:ClearTimers() for _, timers in pairs(auraTimers) do for name in pairs(timers) do timers[name] = nil end end end function Srendarr:ClearTimerType(bdType) for name in pairs(auraTimers[bdType]) do auraTimers[bdType][name] = nil end end function Srendarr:InitializeOnUpdate() local L = Srendarr:GetLocale() seconds = L.Time_Seconds minutes = L.Time_Minutes hours = L.Time_Hours cast = L.Time_Cast Srendarr:SetHandler('OnUpdate', OnUpdate) end end EVENT_MANAGER:RegisterForEvent(Srendarr.name, EVENT_ADD_ON_LOADED, Srendarr.OnInitialize)