--[[ # 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) The following options are listed by priority. The first check that returns true decides the color of the bar. .colorTapping - Use `self.colors.tapping` to color the bar if the unit isn't tapped by the player (boolean) .colorDisconnected - Use `self.colors.disconnected` to color the bar if the unit is offline (boolean) .colorHappiness - Use `self.colors.happiness` to color the bar if the unit is pet based on pet happiness (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) (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) (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 = oUF local oUF = ns.oUF local unpack = unpack local GetPetHappiness = GetPetHappiness local UnitClass = UnitClass local UnitHealth = UnitHealth local UnitHealthMax = UnitHealthMax local UnitIsConnected = UnitIsConnected local UnitIsPlayer = UnitIsPlayer local UnitIsTapped = UnitIsTapped local UnitIsTappedByPlayer = UnitIsTappedByPlayer local UnitIsUnit = UnitIsUnit local UnitPlayerControlled = UnitPlayerControlled local UnitReaction = UnitReaction local updateFrequentUpdates local function UpdateColor(element, unit, cur, max) local parent = element.__owner if element.frequentUpdates ~= element.__frequentUpdates then element.__frequentUpdates = element.frequentUpdates updateFrequentUpdates(parent, unit) end local r, g, b, t if(element.colorTapping and not UnitPlayerControlled(unit) and (UnitIsTapped(unit) and not UnitIsTappedByPlayer(unit))) then t = parent.colors.tapped elseif(element.colorDisconnected and element.disconnected) then t = parent.colors.disconnected elseif(element.colorHappiness and UnitIsUnit(unit, 'pet') and GetPetHappiness()) then t = parent.colors.happiness[GetPetHappiness()] elseif(element.colorClass and UnitIsPlayer(unit)) or (element.colorClassNPC and not UnitIsPlayer(unit)) or (element.colorClassPet and UnitPlayerControlled(unit) and not UnitIsPlayer(unit)) then local _, class = UnitClass(unit) t = parent.colors.class[class] elseif(element.colorReaction and UnitReaction(unit, 'player')) then t = parent.colors.reaction[UnitReaction(unit, 'player')] elseif(element.colorSmooth) then r, g, b = parent.ColorGradient(cur, max, unpack(element.smoothGradient or parent.colors.smooth)) elseif(element.colorHealth) then t = parent.colors.health end if(t) then r, g, b = t[1], t[2], t[3] end if(r or g or 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 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 element:SetValue(cur) end element.disconnected = disconnected --[[ Override: Health:UpdateColor(unit, cur, max) Used to completely override the internal function for updating the widgets' colors. * 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) --]] element:UpdateColor(unit, cur, max) --[[ 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 return 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) --]] return (self.Health.Override or Update) (self, unpack(arg)) end local function ForceUpdate(element) return Path(element.__owner, 'ForceUpdate', element.__owner.unit) end local function onHealthUpdate() if(this.disconnected) then return end local unit = this.__owner.unit local health = UnitHealth(unit) if(health ~= this.min) then this.min = health return Path(this.__owner, 'OnHealthUpdate', unit) end end function updateFrequentUpdates(self, unit) if(not unit or string.match(unit, '%w+target$')) then return end local element = self.Health if(element.frequentUpdates and not element:GetScript('OnUpdate')) then element:SetScript('OnUpdate', onHealthUpdate) if((unit == 'party' or string.match(unit, 'party%d?$'))) then self:RegisterEvent('UNIT_HEALTH', Path) elseif(self:IsEventRegistered("UNIT_HEALTH")) then self:UnregisterEvent('UNIT_HEALTH', Path) end elseif(not element.frequentUpdates and element:GetScript('OnUpdate')) then element:SetScript('OnUpdate', nil) self:RegisterEvent('UNIT_HEALTH', Path) end end local function Enable(self, unit) local element = self.Health if(element) then element.__owner = self element.ForceUpdate = ForceUpdate element.__frequentUpdates = element.frequentUpdates updateFrequentUpdates(self, unit) if(element.frequentUpdates and (unit and not string.match(unit, '%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) self:RegisterEvent('UNIT_CONNECTION', Path) self:RegisterEvent('UNIT_FACTION', Path) -- For tapping self:RegisterEvent('UNIT_HAPPINESS', Path) if(element:IsObjectType('StatusBar') and not element:GetStatusBarTexture()) then element:SetStatusBarTexture([[Interface\TargetingFrame\UI-StatusBar]]) end if(not element.UpdateColor) then element.UpdateColor = UpdateColor end element:Show() return true end end local function Disable(self) local element = self.Health if(element) then if(element:GetScript('OnUpdate')) then element:SetScript('OnUpdate', nil) end element:Hide() self:UnregisterEvent('UNIT_HEALTH', Path) self:UnregisterEvent('UNIT_MAXHEALTH', Path) self:UnregisterEvent('UNIT_CONNECTION', Path) self:UnregisterEvent('UNIT_FACTION', Path) self:UnregisterEvent('UNIT_HAPPINESS', Path) end end oUF:AddElement('Health', Path, Enable, Disable)