Files
coa-elvui/ElvUI/Libraries/oUF/elements/health.lua
T
Andrew6810 60ef8a38af init
2022-10-21 07:09:01 -07:00

381 lines
12 KiB
Lua

--[[
# Element: Health Bar
Handles the updating of a status bar that displays the unit's health.
## Widget
Health - A `StatusBar` used to represent the unit's health.
## Sub-Widgets
.bg - A `Texture` used as a background. It will inherit the color of the main StatusBar.
## Notes
A default texture will be applied if the widget is a StatusBar and doesn't have a texture set.
## Options
.frequentUpdates - Indicates whether to use OnUpdate script instead of UNIT_HEALTH to update the
bar (boolean)
.smoothGradient - 9 color values to be used with the .colorSmooth option (table)
.considerSelectionInCombatHostile - Indicates whether selection should be considered hostile while the unit is in
combat with the player (boolean)
The following options are listed by priority. The first check that returns true decides the color of the bar.
.colorDisconnected - Use `self.colors.disconnected` to color the bar if the unit is offline (boolean)
.colorTapping - Use `self.colors.tapping` to color the bar if the unit isn't tapped by the player (boolean)
.colorHappiness - Use `self.colors.happiness` to color the bar if the unit is pet based on pet happiness (boolean)
.colorThreat - Use `self.colors.threat[threat]` to color the bar based on the unit's threat status. `threat` is
defined by the first return of [UnitThreatSituation](https://wow.gamepedia.com/API_UnitThreatSituation) (boolean)
.colorClass - Use `self.colors.class[class]` to color the bar based on unit class. `class` is defined by the
second return of [UnitClass](http://wowprogramming.com/docs/api/UnitClass.html) (boolean)
.colorClassNPC - Use `self.colors.class[class]` to color the bar if the unit is a NPC (boolean)
.colorClassPet - Use `self.colors.class[class]` to color the bar if the unit is player controlled, but not a player
(boolean)
.colorReaction - Use `self.colors.reaction[reaction]` to color the bar based on the player's reaction towards the
unit. `reaction` is defined by the return value of
[UnitReaction](http://wowprogramming.com/docs/api/UnitReaction.html) (boolean)
.colorSmooth - Use `smoothGradient` if present or `self.colors.smooth` to color the bar with a smooth gradient
based on the player's current health percentage (boolean)
.colorHealth - Use `self.colors.health` to color the bar. This flag is used to reset the bar color back to default
if none of the above conditions are met (boolean)
## Sub-Widgets Options
.multiplier - Used to tint the background based on the main widgets R, G and B values. Defaults to 1 (number)[0-1]
## Attributes
.disconnected - Indicates whether the unit is disconnected (boolean)
## Examples
-- Position and size
local Health = CreateFrame('StatusBar', nil, self)
Health:SetHeight(20)
Health:SetPoint('TOP')
Health:SetPoint('LEFT')
Health:SetPoint('RIGHT')
-- Add a background
local Background = Health:CreateTexture(nil, 'BACKGROUND')
Background:SetAllPoints(Health)
Background:SetTexture(1, 1, 1, .5)
-- Options
Health.frequentUpdates = true
Health.colorTapping = true
Health.colorDisconnected = true
Health.colorClass = true
Health.colorReaction = true
Health.colorHealth = true
-- Make the background darker.
Background.multiplier = .5
-- Register it with oUF
Health.bg = Background
self.Health = Health
--]]
local _, ns = ...
local oUF = ns.oUF
local Private = oUF.Private
local function UpdateColor(self, event, unit)
if(not unit or self.unit ~= unit) then return end
local element = self.Health
local r, g, b, t
if(element.colorDisconnected and element.disconnected) then
t = self.colors.disconnected
elseif(element.colorTapping and not UnitPlayerControlled(unit) and (UnitIsTapped(unit) and not UnitIsTappedByPlayer(unit) and not UnitIsTappedByAllThreatList(unit))) then
t = self.colors.tapped
elseif(element.colorHappiness and UnitIsUnit(unit, 'pet') and GetPetHappiness()) then
t = self.colors.happiness[GetPetHappiness()]
elseif(element.colorThreat and not UnitPlayerControlled(unit) and UnitThreatSituation('player', unit)) then
t = self.colors.threat[UnitThreatSituation('player', unit)]
elseif(element.colorClass and UnitIsPlayer(unit)) or
(element.colorClassNPC and not UnitIsPlayer(unit)) or
(element.colorClassPet and UnitPlayerControlled(unit) and not UnitIsPlayer(unit)) then
t = oUF.herocolor
elseif(element.colorReaction and UnitReaction(unit, 'player')) then
t = self.colors.reaction[UnitReaction(unit, 'player')]
elseif(element.colorSmooth) then
r, g, b = self:ColorGradient(element.cur or 1, element.max or 1, unpack(element.smoothGradient or self.colors.smooth))
elseif(element.colorHealth) then
t = self.colors.health
end
if(t) then
r, g, b = t[1], t[2], t[3]
end
if(b) then
element:SetStatusBarColor(r, g, b)
local bg = element.bg
if(bg) then
local mu = bg.multiplier or 1
bg:SetVertexColor(r * mu, g * mu, b * mu)
end
end
if(element.PostUpdateColor) then
element:PostUpdateColor(unit, r, g, b)
end
end
local function ColorPath(self, ...)
--[[ Override: Health.UpdateColor(self, event, unit)
Used to completely override the internal function for updating the widgets' colors.
* self - the parent object
* event - the event triggering the update (string)
* unit - the unit accompanying the event (string)
--]]
(self.Health.UpdateColor or UpdateColor) (self, ...)
end
local function Update(self, event, unit)
if(not unit or self.unit ~= unit) then return end
local element = self.Health
--[[ Callback: Health:PreUpdate(unit)
Called before the element has been updated.
* self - the Health element
* unit - the unit for which the update has been triggered (string)
--]]
if(element.PreUpdate) then
element:PreUpdate(unit)
end
local cur, max = UnitHealth(unit), UnitHealthMax(unit)
local disconnected = not UnitIsConnected(unit)
element:SetMinMaxValues(0, max)
if(disconnected) then
element:SetValue(max)
else
if(cur == 0) then
cur = 0.0001
end
element:SetValue(cur)
end
element.cur = cur
element.max = max
element.disconnected = disconnected
--[[ Callback: Health:PostUpdate(unit, cur, max)
Called after the element has been updated.
* self - the Health element
* unit - the unit for which the update has been triggered (string)
* cur - the unit's current health value (number)
* max - the unit's maximum possible health value (number)
--]]
if(element.PostUpdate) then
element:PostUpdate(unit, cur, max)
end
end
local function Path(self, ...)
--[[ Override: Health.Override(self, event, unit)
Used to completely override the internal update function.
* self - the parent object
* event - the event triggering the update (string)
* unit - the unit accompanying the event (string)
--]]
(self.Health.Override or Update) (self, ...);
ColorPath(self, ...)
end
local function ForceUpdate(element)
Path(element.__owner, 'ForceUpdate', element.__owner.unit)
end
--[[ Health:SetColorDisconnected(state)
Used to toggle coloring if the unit is offline.
* self - the Health element
* state - the desired state (boolean)
--]]
local function SetColorDisconnected(element, state)
if(element.colorDisconnected ~= state) then
element.colorDisconnected = state
if(element.colorDisconnected) then
element.__owner:RegisterEvent('UNIT_CONNECTION', ColorPath)
else
element.__owner:UnregisterEvent('UNIT_CONNECTION', ColorPath)
end
end
end
--[[ Health:SetColorHappiness(state)
Used to toggle coloring by the unit's happiness.
* self - the Health element
* state - the desired state (boolean)
--]]
local function SetColorHappiness(element, state)
if(element.colorHappiness ~= state) then
element.colorHappiness = state
if(element.colorHappiness) then
element.__owner:RegisterEvent('UNIT_HAPPINESS', ColorPath)
else
element.__owner:UnregisterEvent('UNIT_HAPPINESS', ColorPath)
end
end
end
--[[ Health:SetColorTapping(state)
Used to toggle coloring if the unit isn't tapped by the player.
* self - the Health element
* state - the desired state (boolean)
--]]
local function SetColorTapping(element, state)
if(element.colorTapping ~= state) then
element.colorTapping = state
if(element.colorTapping) then
element.__owner:RegisterEvent('UNIT_FACTION', ColorPath)
else
element.__owner:UnregisterEvent('UNIT_FACTION', ColorPath)
end
end
end
--[[ Health:SetColorThreat(state)
Used to toggle coloring by the unit's threat status.
* self - the Health element
* state - the desired state (boolean)
--]]
local function SetColorThreat(element, state)
if(element.colorThreat ~= state) then
element.colorThreat = state
if(element.colorThreat) then
element.__owner:RegisterEvent('UNIT_THREAT_LIST_UPDATE', ColorPath)
else
element.__owner:UnregisterEvent('UNIT_THREAT_LIST_UPDATE', ColorPath)
end
end
end
local function onHealthUpdate(self)
if(self.disconnected) then return end
local unit = self.__owner.unit
local health = UnitHealth(unit)
if(health ~= self.health) then
self.health = health
return Path(self.__owner, 'OnHealthUpdate', unit)
end
end
--[[ Health:SetFrequentUpdates(state)
Used to toggle frequent updates.
* self - the Health element
* state - the desired state (boolean)
--]]
local function SetFrequentUpdates(element, state)
if(element.frequentUpdates ~= state) then
element.frequentUpdates = state
if(element.frequentUpdates) then
element:SetScript('OnUpdate', onHealthUpdate)
local unit = element.__owner.unit
if((unit == 'party' or unit:match('party%d?$')) and not element:IsEventRegistered("UNIT_HEALTH")) then
element:RegisterEvent('UNIT_HEALTH', Path)
elseif(element:IsEventRegistered('UNIT_HEALTH')) then
element:UnregisterEvent('UNIT_HEALTH', Path)
end
else
element:SetScript('OnUpdate', nil)
element.__owner:RegisterEvent('UNIT_HEALTH', Path)
end
end
end
local function Enable(self, unit)
local element = self.Health
if(element) then
element.__owner = self
element.ForceUpdate = ForceUpdate
element.SetColorDisconnected = SetColorDisconnected
element.SetColorHappiness = SetColorHappiness
element.SetColorTapping = SetColorTapping
element.SetColorThreat = SetColorThreat
element.SetFrequentUpdates = SetFrequentUpdates
if(element.colorDisconnected) then
self:RegisterEvent('UNIT_CONNECTION', ColorPath)
end
if(element.colorHappiness) then
self:RegisterEvent('UNIT_HAPPINESS', ColorPath)
end
if(element.colorTapping) then
self:RegisterEvent('UNIT_FACTION', ColorPath)
end
if(element.colorThreat) then
self:RegisterEvent('UNIT_THREAT_LIST_UPDATE', ColorPath)
end
if(element.frequentUpdates and (unit and not unit:match('%w+target$'))) then
element:SetScript('OnUpdate', onHealthUpdate)
-- The party frames need this to handle disconnect states correctly.
if(unit == 'party') then
self:RegisterEvent('UNIT_HEALTH', Path)
end
else
self:RegisterEvent('UNIT_HEALTH', Path)
end
self:RegisterEvent('UNIT_MAXHEALTH', Path)
if(element:IsObjectType('StatusBar') and not element:GetStatusBarTexture()) then
element:SetStatusBarTexture([[Interface\TargetingFrame\UI-StatusBar]])
end
element:Show()
return true
end
end
local function Disable(self)
local element = self.Health
if(element) then
element:Hide()
if(element:GetScript('OnUpdate')) then
element:SetScript('OnUpdate', nil)
end
self:UnregisterEvent('UNIT_HEALTH', Path)
self:UnregisterEvent('UNIT_MAXHEALTH', Path)
self:UnregisterEvent('UNIT_CONNECTION', ColorPath)
self:UnregisterEvent('UNIT_FACTION', ColorPath)
self:UnregisterEvent('UNIT_HAPPINESS', ColorPath)
self:UnregisterEvent('UNIT_THREAT_LIST_UPDATE', ColorPath)
end
end
oUF:AddElement('Health', Path, Enable, Disable)