PetHealth.supportedClasses = { [1] = true, -- Dragonknight [2] = true, -- Sorcerer [3] = true, -- Nightblade [4] = true, -- Warden [5] = true, -- Necromancer [6] = true, -- Templar [117] = true, -- Arcanist }
Further digging shows that there are only a petOne and a petTwo defined in the code. This causes the error that you are seeing. This code starts around line 385, find and substitute the below code and see if it works with 3 pets. Remember that I am not a proficient coder. This could be wrong.
else
local name = currentPets.unitName
local petOne = currentPets[1].unitName
local petTwo = currentPets[2].unitName
local petThree = currentPets[3].unitName
if lowHealthAlertPercentage > 1 and powerValue ~= 0 and powerValue < (powerMax*.01*lowHealthAlertPercentage) then
if name == petOne and onScreenHealthAlertPetOne == 0 then
OnScreenMessage(zo_strformat("|cff0000<<1>> <<2>>|r", petOne, GetString(SI_PET_HEALTH_LOW_HEALTH_WARNING_MSG)))
onScreenHealthAlertPetOne = 1
elseif name == petTwo and onScreenHealthAlertPetTwo == 0 then
OnScreenMessage(zo_strformat("|cff0000<<1>> <<2>>|r", petTwo, GetString(SI_PET_HEALTH_LOW_HEALTH_WARNING_MSG)))
onScreenHealthAlertPetTwo = 1
elseif name == petThree and onScreenHealthAlertPetThree == 0 then
OnScreenMessage(zo_strformat("|cff0000<<1>> <<2>>|r", petThree, GetString(SI_PET_HEALTH_LOW_HEALTH_WARNING_MSG)))
onScreenHealthAlertPetThree = 1
end
else
if name == petOne then
onScreenHealthAlertPetOne = 0
elseif name == petTwo then
onScreenHealthAlertPetTwo = 0
elseif name == petThree then
onScreenHealthAlertPetThree = 0
end
end
end
--this might work: Use CTRL-A to copy everything. Open Notepad and use CTRL-V to past the entire text. Save as
--PetHealth.lua, in the pet health addon folder. Maybe rename the original first.
PetHealth = PetHealth or {}
--The supported classes for this addon (ClassId from function GetUnitClassId("player"))
PetHealth.supportedClasses = {
[1] = true, -- Dragonknight
[2] = true, -- Sorcerer
[3] = true, -- Nightblade
[4] = true, -- Warden
[5] = true, -- Necromancer
[6] = true, -- Templar
[117] = true, -- Archanist
}
local addon = {
name = "PetHealth",
displayName = "PetHealth",
version = "1.12",
savedVarName = "PetHealth_Save",
savedVarVersion = 2,
lamDisplayName = "PetHealth",
lamAuthor = "Scootworks, Goobsnake",
lamUrl = "https://www.esoui.com/downloads/info1884-PetHealth.html",
}
PetHealth.addonData = addon
local default = {
saveMode = 1, -- Default for each character setting
point = TOPLEFT,
relPoint = CENTER,
x = 0,
y = 0,
onlyInCombat = false,
showValues = true,
showLabels = true,
hideInDungeon = false,
lockWindow = false,
lowHealthAlertSlider = 0,
lowShieldAlertSlider = 0,
petUnsummonedAlerts = false,
onlyInCombatHealthSlider = 0,
showBackground = true,
useZosStyle = false,
debug = false,
}
local UNIT_PLAYER_PET = "playerpet"
local UNIT_PLAYER_TAG = "player"
local base, background, savedVars
local currentPets = {}
local PetHealthWarner
local window = {}
local inCombatAddon = false
local AddOnManager = GetAddOnManager()
local hideInDungeon = false
local LAM
local LSC
local lockWindow = false
local lowHealthAlertPercentage = 0
local lowShieldAlertPercentage = 0
local onlyInCombatHealthMax = 0
local onlyInCombatHealthCurrent = 0
local onlyInCombatHealthPercentage = 0
local onScreenHealthAlerts = {} -- Dynamic table for health alerts
local onScreenShieldAlerts = {} -- Dynamic table for shield alerts
local unsummonedAlerts = false
local WINDOW_MANAGER = GetWindowManager()
local WINDOW_WIDTH = 250
local WINDOW_HEIGHT_PER_PET = 40 -- Height per pet bar
local WINDOW_HEIGHT_BASE = 36 -- Base height for no pets
local PET_BAR_FRAGMENT
-- UTIL --
local function OnScreenMessage(message)
local messageParams = CENTER_SCREEN_ANNOUNCE:CreateMessageParams(CSA_CATEGORY_LARGE_TEXT)
messageParams:SetCSAType(CENTER_SCREEN_ANNOUNCE_TYPE_COUNTDOWN)
messageParams:SetText(message)
CENTER_SCREEN_ANNOUNCE:AddMessageWithParams(messageParams)
end
local function ChatOutput(message)
CHAT_SYSTEM:AddMessage(message)
end
local function CheckAddon(addonName)
for i = 1, AddOnManager:GetNumAddOns() do
local name, title, author, description, enabled, state, isOutOfDate = AddOnManager:GetAddOnInfo(i)
if title == addonName and enabled == true and state == 2 then
return true
end
end
end
local function GetPetNameLower(abilityId)
local abilityName = GetAbilityName(abilityId)
local petName
if abilityName:match('Summon ') then
if abilityName:match('Summon Unstable ') then
petName = abilityName:gsub("Summon Unstable ","")
else
petName = abilityName:gsub("Summon ","")
end
else
petName = abilityName
end
return zo_strformat("<<z:1>>", petName)
end
local validPets = {
-- Familiar
[GetPetNameLower(23304)] = true,
["begleiter"] = true, -- de
["familier"] = true, -- fr
["призванный слуга"] = true, -- ru
-- Clannfear
[GetPetNameLower(23319)] = true,
["clannbann"] = true, -- de
["faucheclan"] = true, -- fr
["кланфир"] = true, -- ru
-- Volatile Familiar
[GetPetNameLower(23316)] = true,
["explosiver begleiter"] = true, -- de
["familier explosif"] = true, -- fr
["взрывной призванный слуга"] = true, -- ru
-- Winged Twilight
[GetPetNameLower(24613)] = true,
["zwielichtschwinge"] = true, -- de
["crépuscule ailé"] = true, -- fr
["крылатый сумрак"] = true, -- ru
-- Twilight Tormentor
[GetPetNameLower(24636)] = true,
["zwielichtpeinigerin"] = true, -- de
["tourmenteur crépusculaire"] = true, -- fr
["сумрак-мучитель"] = true, -- ru
-- Twilight Matriarch
[GetPetNameLower(24639)] = true,
["zwielichtmatriarchin"] = true, -- de
["matriarche crépusculaire"] = true, -- fr
["сумрак-матриарх"] = true, -- ru
-- Warden Pets
[GetPetNameLower(85982)] = true,
["хищный страж"] = true, -- ru
[GetPetNameLower(85986)] = true,
["вечный страж"] = true, -- ru
[GetPetNameLower(85990)] = true,
["дикий защитник"] = true, -- ru
}
local function IsUnitValidPet(unitTag)
local unitName = zo_strformat("<<z:1>>", GetUnitName(unitTag))
return DoesUnitExist(unitTag) and validPets[unitName]
end
local function GetKeyWithData(unitTag)
for k, v in pairs(currentPets) do
if v.unitTag == unitTag then return k end
end
return nil
end
local function GetAlphaFromControl(savedVariable)
return (not savedVariable and 0) or 1
end
local function GetCombatState()
return not inCombatAddon and savedVars.onlyInCombat
end
local function SetPetWindowHidden(hidden, combatState)
local setToHidden = hidden
if combatState then
setToHidden = true
end
PET_BAR_FRAGMENT:SetHiddenForReason("NoPetOrOnlyInCombat", setToHidden)
end
local function PetUnSummonedAlerts(unitTag)
if unsummonedAlerts then
local i = GetKeyWithData(unitTag)
if i == nil then
return
end
local petName = currentPets.unitName
local swimming = IsUnitSwimming("player")
local inCombat = IsUnitInCombat("player")
if swimming then
OnScreenMessage(string.format(GetString(SI_PET_HEALTH_UNSUMMONED_SWIMMING_MSG)))
elseif inCombat then
OnScreenMessage(zo_strformat("<<1>> <<2>>", petName, GetString(SI_PET_HEALTH_UNSUMMONED_MSG)))
end
end
end
local function RefreshPetWindow()
local countPets = #currentPets
local combatState = GetCombatState()
if PET_BAR_FRAGMENT:IsHidden() and countPets == 0 and combatState then
return
end
local height = WINDOW_HEIGHT_BASE + (countPets * WINDOW_HEIGHT_PER_PET)
local setToHidden = true
if countPets > 0 then
for i = 1, countPets do
window:SetHidden(false)
end
for i = countPets + 1, #window do
window:SetHidden(true)
end
setToHidden = false
end
if not combatState and savedVars.onlyInCombat == true then
if onlyInCombatHealthPercentage == 0 then
setToHidden = false
elseif onlyInCombatHealthCurrent > (onlyInCombatHealthMax*.01*onlyInCombatHealthPercentage) then
setToHidden = true
end
end
if savedVars.hideInDungeon == true then
local inDungeon = IsUnitInDungeon("player")
local zoneDifficulty = GetCurrentZoneDungeonDifficulty()
if inDungeon == true and zoneDifficulty > 0 then
local currentZone = GetUnitZone("player")
if currentZone ~= 'Maelstrom Arena' then
setToHidden = true
end
end
end
base:SetHeight(height)
background:SetHeight(height)
SetPetWindowHidden(setToHidden, combatState)
end
-- SHIELD --
local function OnShieldUpdate(handler, unitTag, value, maxValue, initial)
local i = GetKeyWithData(unitTag)
if i == nil then
return
end
local petName = currentPets.unitName
if lowShieldAlertPercentage > 1 and value ~= 0 and value < (maxValue*.01*lowShieldAlertPercentage) then
if not onScreenShieldAlerts then
OnScreenMessage(zo_strformat("|c000099<<1>>\'s <<2>>|r", petName, GetString(SI_PET_HEALTH_LOW_SHIELD_WARNING_MSG)))
onScreenShieldAlerts = true
end
else
onScreenShieldAlerts = false
end
local ctrl, ctrlr
if not savedVars.useZosStyle then
ctrl = window.shield
else
ctrl = window.shieldleft
ctrlr = window.shieldright
end
if handler ~= nil then
if not ctrl:IsHidden() or value == 0 then
ctrl:SetHidden(true)
if savedVars.useZosStyle then
ctrlr:SetHidden(true)
end
end
else
if ctrl:IsHidden() then
ctrl:SetHidden(false)
if savedVars.useZosStyle then
ctrlr:SetHidden(false)
end
end
end
if maxValue > 0 then
if savedVars.useZosStyle then
value = value / 2
maxValue = maxValue / 2
ZO_StatusBar_SmoothTransition(window.shieldleft, value, maxValue, (initial == "true" and true or false))
ZO_StatusBar_SmoothTransition(window.shieldright, value, maxValue, (initial == "true" and true or false))
else
ZO_StatusBar_SmoothTransition(window.shield, value, maxValue, (initial == "true" and true or false))
end
end
end
local function GetShield(unitTag)
local value, maxValue = GetUnitAttributeVisualizerEffectInfo(unitTag, ATTRIBUTE_VISUAL_POWER_SHIELDING, STAT_MITIGATION, ATTRIBUTE_HEALTH, POWERTYPE_HEALTH)
if value == nil then
value = 0
maxValue = 0
end
OnShieldUpdate(_, unitTag, value, maxValue, "true")
end
-- HEALTH --
local function OnHealthUpdate(_, unitTag, _, _, powerValue, powerMax, initial)
if onlyInCombatHealthPercentage > 1 and savedVars.onlyInCombat == true then
onlyInCombatHealthMax = powerMax
onlyInCombatHealthCurrent = powerValue
RefreshPetWindow()
end
local i = GetKeyWithData(unitTag)
if i == nil then
return
end
local petName = currentPets.unitName
if lowHealthAlertPercentage > 1 and powerValue ~= 0 and powerValue < (powerMax*.01*lowHealthAlertPercentage) then
if not onScreenHealthAlerts then
OnScreenMessage(zo_strformat("|cff0000<<1>> <<2>>|r", petName, GetString(SI_PET_HEALTH_LOW_HEALTH_WARNING_MSG)))
onScreenHealthAlerts = true
end
else
onScreenHealthAlerts = false
end
window.values:SetText(ZO_FormatResourceBarCurrentAndMax(powerValue, powerMax))
if savedVars.useZosStyle then
local halfValue = powerValue / 2
local halfMax = powerMax / 2
ZO_StatusBar_SmoothTransition(window.barleft, halfValue, halfMax, (initial == "true" and true or false))
ZO_StatusBar_SmoothTransition(window.barright, halfValue, halfMax, (initial == "true" and true or false))
window.warner:OnHealthUpdate(powerValue, powerMax)
else
ZO_StatusBar_SmoothTransition(window.healthbar, powerValue, powerMax, (initial == "true" and true or false))
end
end
local function GetHealth(unitTag)
local powerValue, powerMax = GetUnitPower(unitTag, POWERTYPE_HEALTH)
OnHealthUpdate(_, unitTag, _, _, powerValue, powerMax, "true")
end
-- STATS --
local function GetControlText(control)
local controlText = control:GetText()
if controlText ~= nil then return controlText end
return ""
end
local function UpdatePetStats(unitTag)
local i = GetKeyWithData(unitTag)
if i == nil then
return
end
local name = currentPets.unitName
local control = window.label
if GetControlText(control) ~= name then
window.label:SetText(name)
end
GetHealth(unitTag)
GetShield(unitTag)
end
local function GetActivePets()
currentPets = {}
for i=1,7 do
local unitTag = UNIT_PLAYER_PET..i
if IsUnitValidPet(unitTag) then
table.insert(currentPets, { unitTag = unitTag, unitName = GetUnitName(unitTag) })
UpdatePetStats(unitTag)
end
end
zo_callLater(function() RefreshPetWindow() end, 300)
end
-- COMBAT --
local function OnPlayerCombatState(_, inCombat)
inCombatAddon = inCombat
RefreshPetWindow()
end
local function CreateWarner()
if savedVars.useZosStyle then
local HEALTH_ALPHA_PULSE_THRESHOLD = 0.25
local RESOURCE_WARNER_FLASH_TIME = 300
PetHealthWarner = ZO_Object:Subclass()
function PetHealthWarner:New(...)
local warner = ZO_Object.New(self)
warner:Initialize(...)
return warner
end
function PetHealthWarner:Initialize(parent)
self.warning = GetControl(parent, "Warner")
self.OnPowerUpdate = function(_, unitTag, powerIndex, powerType, health, maxHealth)
self:OnHealthUpdate(health, maxHealth)
end
local function OnPlayerActivated()
local current, max = GetUnitPower(self.unitTag, POWERTYPE_HEALTH)
self:OnHealthUpdate(current, max)
end
self.warning:RegisterForEvent(EVENT_PLAYER_ACTIVATED, OnPlayerActivated)
self.warnAnimation = ZO_AlphaAnimation:New(self.warning)
self.statusBar = parent
self.paused = false
end
function PetHealthWarner:SetPaused(paused)
if self.paused ~= paused then
self.paused = paused
if paused then
if self.warnAnimation:IsPlaying() then
self.warnAnimation:Stop()
end
else
local current, max = GetUnitPower("player", POWERTYPE_HEALTH)
self.warning:SetAlpha(0)
self:UpdateAlphaPulse(current / max)
end
end
end
function PetHealthWarner:UpdateAlphaPulse(healthPerc)
if healthPerc <= HEALTH_ALPHA_PULSE_THRESHOLD then
if not self.warnAnimation:IsPlaying() then
self.warnAnimation:PingPong(0, 1, RESOURCE_WARNER_FLASH_TIME)
end
else
if self.warnAnimation:IsPlaying() then
self.warnAnimation:Stop()
self.warning:SetAlpha(0)
end
end
end
function PetHealthWarner:OnHealthUpdate(health, maxHealth)
if not self.paused then
local healthPerc = health / maxHealth
self:UpdateAlphaPulse(healthPerc)
end
end
end
end
-- CONTROLS --
local function CreateControls()
local function AddControl(parent, cType, level)
local c = WINDOW_MANAGER:CreateControl(nil, parent, cType)
c:SetDrawLayer(DL_OVERLAY)
c:SetDrawLevel(level)
return c, c
end
base = WINDOW_MANAGER:CreateTopLevelWindow(addon.name.."_TopLevel")
base:SetDimensions(WINDOW_WIDTH, WINDOW_HEIGHT_BASE)
base:SetAnchor(savedVars.point, GuiRoot, savedVars.relPoint, savedVars.x, savedVars.y)
base:SetMouseEnabled(true)
if savedVars.lockWindow == true then
base:SetMovable(false)
else
base:SetMovable(true)
end
base:SetDrawLayer(DL_OVERLAY)
base:SetDrawLevel(0)
base:SetHandler("OnMouseUp", function()
local a, b
a, savedVars.point, b, savedVars.relPoint, savedVars.x, savedVars.y = base:GetAnchor(0)
end)
base:SetHidden(true)
local INSET_BACKGROUND = 32
local baseWidth = base:GetWidth()
local baseHeight = base:GetHeight()
local ctrl
background, ctrl = AddControl(base, CT_BACKDROP, 1)
ctrl:SetEdgeTexture("esoui/art/chatwindow/chat_bg_edge.dds", 256, 128, INSET_BACKGROUND)
ctrl:SetCenterTexture("esoui/art/chatwindow/chat_bg_center.dds")
ctrl:SetInsets(INSET_BACKGROUND, INSET_BACKGROUND, -INSET_BACKGROUND, -INSET_BACKGROUND)
ctrl:SetCenterColor(1,1,1,0.8)
ctrl:SetEdgeColor(1,1,1,0.8)
ctrl:SetDimensions(baseWidth, baseHeight)
ctrl:SetAnchor(TOPLEFT)
ctrl:SetAlpha(GetAlphaFromControl(savedVars.showBackground))
if not savedVars.useZosStyle then
for i=1,7 do
window, ctrl = AddControl(base, CT_BACKDROP, 5)
ctrl:SetDimensions(baseWidth*0.8, 36)
ctrl:SetCenterColor(1,0,1,0)
ctrl:SetEdgeColor(1,0,1,0)
ctrl:SetAnchor(CENTER, base)
local windowHeight = window:GetHeight()
window.label, ctrl = AddControl(window, CT_LABEL, 10)
ctrl:SetFont("$(BOLD_FONT)|$(KB_16)|soft-shadow-thin")
ctrl:SetColor(GetInterfaceColor(INTERFACE_COLOR_TYPE_TEXT_COLORS, INTERFACE_TEXT_COLOR_NORMAL))
ctrl:SetDimensions(baseWidth, windowHeight*0.4)
ctrl:SetAnchor(TOPLEFT, window)
ctrl:SetAlpha(GetAlphaFromControl(savedVars.showLabels))
window.border, ctrl = AddControl(window, CT_BACKDROP, 20)
ctrl:SetDimensions(window:GetWidth(), windowHeight*0.45)
ctrl:SetCenterColor(0,0,0,.6)
ctrl:SetEdgeColor(1,1,1,0.4)
ctrl:SetEdgeTexture("", 1, 1, 1)
ctrl:SetAnchor(BOTTOM, window)
local borderWidth = window.border:GetWidth()
local borderHeight = window.border:GetHeight()
window.healthbar, ctrl = AddControl(window.border, CT_STATUSBAR, 30)
ctrl:SetColor(1,1,1,0.5)
ctrl:SetGradientColors(.45, .13, .13, 1, .85, .19, .19, 1)
ctrl:SetDimensions(borderWidth-2, borderHeight-2)
ctrl:SetAnchor(CENTER, window.border)
window.shield, ctrl = AddControl(window.healthbar, CT_STATUSBAR, 40)
ctrl:SetColor(1,1,1,0.5)
ctrl:SetGradientColors(.5, .5, 1, .3, .25, .25, .5, .5)
ctrl:SetDimensions(borderWidth-2, borderHeight-2)
ctrl:SetAnchor(CENTER, window.healthbar)
ctrl:SetValue(0)
ctrl:SetMinMax(0,1)
window.values, ctrl = AddControl(window.healthbar, CT_LABEL, 50)
ctrl:SetFont("$(BOLD_FONT)|$(KB_14)|soft-shadow-thin")
ctrl:SetColor(GetInterfaceColor(INTERFACE_COLOR_TYPE_TEXT_COLORS, INTERFACE_TEXT_COLOR_SELECTED))
ctrl:SetAnchor(CENTER, window.healthbar)
ctrl:SetAlpha(GetAlphaFromControl(savedVars.showValues))
window:ClearAnchors()
if i == 1 then
window:SetAnchor(TOP, base, TOP, 0, 18)
else
window:SetAnchor(TOP, window[i-1], BOTTOM, 0, 2)
end
end
else
local CHILD_DIRECTIONS = { "Left", "Right", "Center" }
local function SetColors(self)
local powerType = self.powerType
local gradient = ZO_POWER_BAR_GRADIENT_COLORS[powerType]
for i, control in ipairs(self.barControls) do
ZO_StatusBar_SetGradientColor(control, gradient)
control:SetFadeOutLossColor(GetInterfaceColor(INTERFACE_COLOR_TYPE_POWER_FADE_OUT, powerType))
control:SetFadeOutGainColor(GetInterfaceColor(INTERFACE_COLOR_TYPE_POWER_FADE_IN, powerType))
end
end
local PAB_TEMPLATES = {
[POWERTYPE_HEALTH] = {
background = {
Left = "ZO_PlayerAttributeBgLeftArrow",
Right = "ZO_PlayerAttributeBgRightArrow",
Center = "ZO_PlayerAttributeBgCenter",
},
frame = {
Left = "ZO_PlayerAttributeFrameLeftArrow",
Right = "ZO_PlayerAttributeFrameRightArrow",
Center = "ZO_PlayerAttributeFrameCenter",
},
warner = {
texture = "ZO_PlayerAttributeHealthWarnerTexture",
Left = "ZO_PlayerAttributeWarnerLeftArrow",
Right = "ZO_PlayerAttributeWarnerRightArrow",
Center = "ZO_PlayerAttributeWarnerCenter",
},
anchors = {
"ZO_PlayerAttributeHealthBarAnchorLeft",
"ZO_PlayerAttributeHealthBarAnchorRight",
},
},
statusBar = "ZO_PlayerAttributeStatusBar",
statusBarGloss = "ZO_PlayerAttributeStatusBarGloss",
resourceNumbersLabel = "ZO_PlayerAttributeResourceNumbers",
}
local function ApplyStyle(bar)
local powerTypeTemplates = PAB_TEMPLATES[bar.powerType]
local backgroundTemplates = powerTypeTemplates.background
local frameTemplates = powerTypeTemplates.frame
local warnerControl = bar:GetNamedChild("Warner")
local bgControl = bar:GetNamedChild("BgContainer")
local warnerTemplates = powerTypeTemplates.warner
for _, direction in pairs(CHILD_DIRECTIONS) do
local bgChild = bgControl:GetNamedChild("Bg" .. direction)
ApplyTemplateToControl(bgChild, ZO_GetPlatformTemplate(backgroundTemplates[direction]))
local frameControl = bar:GetNamedChild("Frame" .. direction)
ApplyTemplateToControl(frameControl, ZO_GetPlatformTemplate(frameTemplates[direction]))
local warnerChild = warnerControl:GetNamedChild(direction)
ApplyTemplateToControl(warnerChild, ZO_GetPlatformTemplate(warnerTemplates.texture))
ApplyTemplateToControl(warnerChild, ZO_GetPlatformTemplate(warnerTemplates[direction]))
end
for i, subBar in pairs(bar.barControls) do
ApplyTemplateToControl(subBar, ZO_GetPlatformTemplate(PAB_TEMPLATES.statusBar))
local gloss = subBar:GetNamedChild("Gloss")
ApplyTemplateToControl(gloss, ZO_GetPlatformTemplate(PAB_TEMPLATES.statusBarGloss))
local anchorTemplates = powerTypeTemplates.anchors
if anchorTemplates then
subBar:ClearAnchors()
ApplyTemplateToControl(subBar, ZO_GetPlatformTemplate(anchorTemplates))
else
ApplyTemplateToControl(subBar, ZO_GetPlatformTemplate(PAB_TEMPLATES.anchor))
end
end
local resourceNumbersLabel = bar:GetNamedChild("ResourceNumbers")
if resourceNumbersLabel then
ApplyTemplateToControl(resourceNumbersLabel, ZO_GetPlatformTemplate(PAB_TEMPLATES.resourceNumbersLabel))
end
end
for i=1,7 do
window = WINDOW_MANAGER:CreateControlFromVirtual("PetHealth"..i, base, "PetHealth_ZOSStyleBar")
local windowHeight = window:GetHeight()
window.label, ctrl = AddControl(window, CT_LABEL, 10)
ctrl:SetFont("$(BOLD_FONT)|$(KB_16)|soft-shadow-thin")
ctrl:SetColor(GetInterfaceColor(INTERFACE_COLOR_TYPE_TEXT_COLORS, INTERFACE_TEXT_COLOR_NORMAL))
ctrl:SetDimensions(baseWidth, windowHeight*0.4)
ctrl:SetAnchor(BOTTOMLEFT, window, TOPLEFT, 0, -10.5)
ctrl:SetAlpha(GetAlphaFromControl(savedVars.showLabels))
window.barleft = window:GetNamedChild("BarLeft")
window.barright = window:GetNamedChild("BarRight")
window.barControls = { window.barleft, window.barright }
window.powerType = POWERTYPE_HEALTH
SetColors(window)
ApplyStyle(window)
window.shieldleft = window:GetNamedChild("ShieldLeft")
window.shieldright = window:GetNamedChild("ShieldRight")
window.values = window:GetNamedChild("ResourceNumbers")
window.values:SetAlpha(GetAlphaFromControl(savedVars.showValues))
window.warner = PetHealthWarner:New(window)
if i == 1 then
window:SetAnchor(TOP, base, TOP, 0, 18)
else
window:SetAnchor(TOP, window[i-1], BOTTOM, 0, 20)
end
end
end
PET_BAR_FRAGMENT = ZO_HUDFadeSceneFragment:New(base)
HUD_SCENE:AddFragment(PET_BAR_FRAGMENT)
HUD_UI_SCENE:AddFragment(PET_BAR_FRAGMENT)
PET_BAR_FRAGMENT:SetHiddenForReason("NoPetOrOnlyInCombat", true)
end
-- INIT --
local function LoadEvents()
EVENT_MANAGER:RegisterForEvent(addon.name, EVENT_POWER_UPDATE, OnHealthUpdate)
EVENT_MANAGER:RegisterForEvent(addon.name, EVENT_UNIT_CREATED, function(_, unitTag)
if IsUnitValidPet(unitTag) then
GetActivePets()
end
end)
EVENT_MANAGER:RegisterForEvent(addon.name, EVENT_UNIT_DESTROYED, function(_, unitTag)
PetUnSummonedAlerts(unitTag)
local key = GetKeyWithData(unitTag)
if key ~= nil then
table.remove(currentPets, key)
local countPets = #currentPets
if countPets > 0 then
for i = 1, countPets do
local name = currentPets.unitName
local control = window.label
unitTag = currentPets.unitTag
if GetControlText(control) ~= name then
window.label:SetText(name)
end
GetHealth(unitTag)
GetShield(unitTag)
end
end
RefreshPetWindow()
end
end)
EVENT_MANAGER:RegisterForEvent(addon.name, EVENT_PLAYER_DEAD, GetActivePets)
EVENT_MANAGER:RegisterForEvent(addon.name, EVENT_UNIT_DEATH_STATE_CHANGE, GetActivePets)
EVENT_MANAGER:RegisterForEvent(addon.name, EVENT_ACTION_SLOT_ABILITY_SLOTTED, GetActivePets)
EVENT_MANAGER:AddFilterForEvent(addon.name, EVENT_POWER_UPDATE, REGISTER_FILTER_UNIT_TAG_PREFIX, UNIT_PLAYER_PET)
EVENT_MANAGER:AddFilterForEvent(addon.name, EVENT_UNIT_CREATED, REGISTER_FILTER_UNIT_TAG_PREFIX, UNIT_PLAYER_PET)
EVENT_MANAGER:AddFilterForEvent(addon.name, EVENT_UNIT_DESTROYED, REGISTER_FILTER_UNIT_TAG_PREFIX, UNIT_PLAYER_PET)
EVENT_MANAGER:AddFilterForEvent(addon.name, EVENT_PLAYER_DEAD, REGISTER_FILTER_UNIT_TAG, UNIT_PLAYER_TAG)
EVENT_MANAGER:AddFilterForEvent(addon.name, EVENT_UNIT_DEATH_STATE_CHANGE, REGISTER_FILTER_UNIT_TAG, UNIT_PLAYER_TAG)
EVENT_MANAGER:RegisterForEvent(addon.name, EVENT_UNIT_ATTRIBUTE_VISUAL_ADDED, function(_, unitTag, unitAttributeVisual, _, _, _, value, maxValue)
if unitAttributeVisual == ATTRIBUTE_VISUAL_POWER_SHIELDING then
OnShieldUpdate(nil, unitTag, value, maxValue, "true")
end
end)
EVENT_MANAGER:RegisterForEvent(addon.name, EVENT_UNIT_ATTRIBUTE_VISUAL_REMOVED, function(_, unitTag, unitAttributeVisual, _, _, _, value, maxValue)
if unitAttributeVisual == ATTRIBUTE_VISUAL_POWER_SHIELDING then
OnShieldUpdate("removed", unitTag, value, maxValue, "false")
end
end)
EVENT_MANAGER:RegisterForEvent(addon.name, EVENT_UNIT_ATTRIBUTE_VISUAL_UPDATED, function(_, unitTag, unitAttributeVisual, _, _, _, _, newValue, _, newMaxValue)
if unitAttributeVisual == ATTRIBUTE_VISUAL_POWER_SHIELDING then
OnShieldUpdate(nil, unitTag, newValue, newMaxValue, "false")
end
end)
EVENT_MANAGER:AddFilterForEvent(addon.name, EVENT_UNIT_ATTRIBUTE_VISUAL_ADDED, REGISTER_FILTER_UNIT_TAG_PREFIX, UNIT_PLAYER_PET)
EVENT_MANAGER:AddFilterForEvent(addon.name, EVENT_UNIT_ATTRIBUTE_VISUAL_REMOVED, REGISTER_FILTER_UNIT_TAG_PREFIX, UNIT_PLAYER_PET)
EVENT_MANAGER:AddFilterForEvent(addon.name, EVENT_UNIT_ATTRIBUTE_VISUAL_UPDATED, REGISTER_FILTER_UNIT_TAG_PREFIX, UNIT_PLAYER_PET)
EVENT_MANAGER:RegisterForEvent(addon.name, EVENT_INTERFACE_SETTING_CHANGED, GetActivePets)
EVENT_MANAGER:AddFilterForEvent(addon.name, EVENT_INTERFACE_SETTING_CHANGED, REGISTER_FILTER_SETTING_SYSTEM_TYPE, SETTING_TYPE_UI)
EVENT_MANAGER:RegisterForEvent(addon.name, EVENT_PLAYER_COMBAT_STATE, OnPlayerCombatState)
OnPlayerCombatState(_, IsUnitInCombat(UNIT_PLAYER_TAG))
EVENT_MANAGER:RegisterForEvent(addon.name, EVENT_PLAYER_ACTIVATED, function() zo_callLater(function() GetActivePets() end, 75) end)
end
function PetHealth.changeCombatState()
OnPlayerCombatState(_, IsUnitInCombat(UNIT_PLAYER_TAG))
end
function PetHealth.hideInDungeon(toValue)
hideInDungeon = toValue
RefreshPetWindow()
end
function PetHealth.changeBackground(toValue)
background:SetAlpha(GetAlphaFromControl(toValue))
end
function PetHealth.changeValues(toValue)
for i=1,7 do
if window then
window.values:SetAlpha(GetAlphaFromControl(toValue))
end
end
end
function PetHealth.changeLabels(toValue)
for i=1,7 do
if window then
window.label:SetAlpha(GetAlphaFromControl(toValue))
end
end
end
function PetHealth.lockPetWindow(toValue)
lockWindow = toValue
end
function PetHealth.lowHealthAlertPercentage(toValue)
lowHealthAlertPercentage = toValue
end
function PetHealth.lowShieldAlertPercentage(toValue)
lowShieldAlertPercentage = toValue
end
function PetHealth.unsummonedAlerts(toValue)
unsummonedAlerts = toValue
end
function PetHealth.onlyInCombatHealthPercentage(toValue)
onlyInCombatHealthPercentage = toValue
end
local function SlashCommands()
LSC:Register("/pethealthcombat", function()
savedVars.onlyInCombat = not savedVars.onlyInCombat
if savedVars.onlyInCombat then
ChatOutput(GetString(SI_PET_HEALTH_COMBAT_ACTIVATED))
else
ChatOutput(GetString(SI_PET_HEALTH_COMBAT_DEACTIVATED))
end
PetHealth.changeCombatState()
end, GetString(SI_PET_HEALTH_LSC_COMBAT))
LSC:Register("/pethealthhideindungeon", function()
savedVars.hideInDungeon = not savedVars.hideInDungeon
if savedVars.hideInDungeon then
ChatOutput(GetString(SI_PET_HEALTH_HIDE_IN_DUNGEON_ACTIVATED))
else
ChatOutput(GetString(SI_PET_HEALTH_HIDE_IN_DUNGEON_DEACTIVATED))
end
PetHealth.hideInDungeon()
end, GetString(SI_PET_HEALTH_LSC_DUNGEON))
LSC:Register("/pethealthvalues", function()
savedVars.showValues = not savedVars.showValues
if savedVars.showValues then
ChatOutput(GetString(SI_PET_HEALTH_VALUES_ACTIVATED))
else
ChatOutput(GetString(SI_PET_HEALTH_VALUES_DEACTIVATED))
end
PetHealth.changeValues(savedVars.showValues)
end, GetString(SI_PET_HEALTH_LSC_VALUES))
LSC:Register("/pethealthlabels", function()
savedVars.showLabels = not savedVars.showLabels
if savedVars.showLabels then
ChatOutput(GetString(SI_PET_HEALTH_LABELS_ACTIVATED))
else
ChatOutput(GetString(SI_PET_HEALTH_LABELS_DEACTIVATED))
end
PetHealth.changeLabels(savedVars.showLabels)
end, GetString(SI_PET_HEALTH_LSC_LABELS))
if not savedVars.useZosStyle then
LSC:Register("/pethealthbackground", function()
savedVars.showBackground = not savedVars.showBackground
if savedVars.showBackground then
ChatOutput(GetString(SI_PET_HEALTH_BACKGROUND_ACTIVATED))
else
ChatOutput(GetString(SI_PET_HEALTH_BACKGROUND_DEACTIVATED))
end
PetHealth.changeBackground(savedVars.showBackground)
end, GetString(SI_PET_HEALTH_LSC_BACKGROUND))
else
showBackground = false
savedVars.showBackground = false
end
LSC:Register("/pethealthunsummonedalerts", function()
savedVars.petUnsummonedAlerts = not savedVars.petUnsummonedAlerts
if savedVars.petUnsummonedAlerts then
ChatOutput(GetString(SI_PET_HEALTH_UNSUMMONEDALERTS_ACTIVATED))
else
ChatOutput(GetString(SI_PET_HEALTH_UNSUMMONEDALERTS_DEACTIVATED))
end
PetHealth.unsummonedAlerts(savedVars.petUnsummonedAlerts)
end, GetString(SI_PET_HEALTH_LSC_UNSUMMONEDALERTS))
LSC:Register("/pethealthwarnhealth", function(healthValuePercent)
if healthValuePercent == nil or healthValuePercent == "" then
ChatOutput(GetString(SI_PET_HEALTH_LAM_LOW_HEALTH_WARN) .. ": " .. tostring(savedVars.lowHealthAlertSlider))
else
local healthValuePercentNumber = tonumber(healthValuePercent)
if type(healthValuePercentNumber) == "number" then
if healthValuePercentNumber <= 0 then healthValuePercentNumber = 0 end
if healthValuePercentNumber >= 100 then healthValuePercentNumber = 99 end
savedVars.lowHealthAlertSlider = healthValuePercentNumber
PetHealth.lowHealthAlertPercentage(healthValuePercentNumber)
ChatOutput(GetString(SI_PET_HEALTH_LAM_LOW_HEALTH_WARN) .. ": " .. tostring(healthValuePercentNumber))
end
end
end, GetString(SI_PET_HEALTH_LSC_WARN_HEALTH))
LSC:Register("/pethealthwarnshield", function(shieldValuePercent)
if shieldValuePercent == nil or shieldValuePercent == "" then
ChatOutput(GetString(SI_PET_HEALTH_LAM_LOW_SHIELD_WARN) .. ": " .. tostring(savedVars.lowShieldAlertSlider))
else
local shieldValuePercentNumber = tonumber(shieldValuePercent)
if type(shieldValuePercentNumber) == "number" then
if shieldValuePercentNumber <= 0 then shieldValuePercentNumber = 0 end
if shieldValuePercentNumber >= 100 then shieldValuePercentNumber = 99 end
savedVars.lowShieldAlertSlider = shieldValuePercentNumber
PetHealth.lowShieldAlertPercentage(shieldValuePercentNumber)
ChatOutput(GetString(SI_PET_HEALTH_LAM_LOW_SHIELD_WARN) .. ": " .. tostring(shieldValuePercentNumber))
end
end
end, GetString(SI_PET_HEALTH_LSC_WARN_SHIELD))
LSC:Register("/pethealthcombathealth", function(combatHealthValuePercent)
if combatHealthValuePercent == nil or combatHealthValuePercent == "" then
ChatOutput(GetString(SI_PET_HEALTH_LAM_ONLY_IN_COMBAT_HEALTH) .. ": " .. tostring(savedVars.onlyInCombatHealthSlider))
else
local combatHealthPercentNumber = tonumber(combatHealthValuePercent)
if type(combatHealthPercentNumber) == "number" then
if combatHealthPercentNumber <= 0 then combatHealthPercentNumber = 0 end
if combatHealthPercentNumber >= 100 then combatHealthPercentNumber = 99 end
savedVars.onlyInCombatHealthSlider = combatHealthPercentNumber
PetHealth.onlyInCombatHealthPercentage(combatHealthPercentNumber)
ChatOutput(GetString(SI_PET_HEALTH_LAM_ONLY_IN_COMBAT_HEALTH) .. ": " .. tostring(combatHealthPercentNumber))
end
end
end, GetString(SI_PET_HEALTH_LSC_COMBAT_HEALTH))
end
local function OnAddOnLoaded(_, addonName)
if addonName ~= addon.name then return end
EVENT_MANAGER:UnregisterForEvent(addon.name, EVENT_ADD_ON_LOADED)
savedVars = ZO_SavedVars:NewAccountWide(addon.savedVarName, addon.savedVarVersion, nil, default, GetWorldName())
if savedVars.saveMode == 1 then
savedVars = ZO_SavedVars:NewCharacterIdSettings(addon.savedVarName, addon.savedVarVersion, nil, default, GetWorldName())
end
PetHealth.savedVars = savedVars
PetHealth.savedVarsDefault = default
lowHealthAlertPercentage = savedVars.lowHealthAlertSlider
lowShieldAlertPercentage = savedVars.lowShieldAlertSlider
unsummonedAlerts = savedVars.petUnsummonedAlerts
onlyInCombatHealthPercentage = savedVars.onlyInCombatHealthSlider
local getUnitClassId = GetUnitClassId(UNIT_PLAYER_TAG)
local supportedClasses = PetHealth.supportedClasses
local supportedClass = supportedClasses[getUnitClassId] or false
if not supportedClass then
ChatOutput("[PetHealth] " .. GetString(SI_PET_HEALTH_CLASS))
return
end
local isLAMActive = CheckAddon('LibAddonMenu-2.0')
local isLSCActive = CheckAddon('LibSlashCommander')
if isLAMActive then
LAM = LibAddonMenu2
PetHealth.LAM = LAM
PetHealth.buildLAMAddonMenu()
end
if isLSCActive then
LSC = LibSlashCommander
SlashCommands()
end
CreateWarner()
CreateControls()
LoadEvents()
end
EVENT_MANAGER:RegisterForEvent(addon.name, EVENT_ADD_ON_LOADED, OnAddOnLoaded)
I built a sorcerer/warden and have 3 pets up and have 3 health bars. I did not experience those errors. Will see if I can fix.
As an aside, I am not the author, nor the maintainer of this addon. I take no credit for its creation or function. I am simply a selfish hacker that wanted this fixed for me, so I am trying. I suggest that if the original ever gets fixed, use it.