Modules/Nameplates: Fix class power module

This commit is contained in:
andrew6180
2023-06-01 14:40:10 -07:00
parent 50e16a313b
commit 6d54612877
6 changed files with 331 additions and 15 deletions
+313
View File
@@ -0,0 +1,313 @@
--[[
# Element: ClassPower
Handles the visibility and updating of the player's class resources (like Chi Orbs or Holy Power) and combo points.
## Widget
ClassPower - An `table` consisting of as many StatusBars as the theoretical maximum return of [UnitPowerMax](http://wowprogramming.com/docs/api/UnitPowerMax.html).
## Sub-Widgets
.bg - A `Texture` used as a background. It will inherit the color of the main StatusBar.
## Sub-Widget Options
.multiplier - Used to tint the background based on the widget's R, G and B values. Defaults to 1 (number)[0-1]
## Notes
A default texture will be applied if the sub-widgets are StatusBars and don't have a texture set.
If the sub-widgets are StatusBars, their minimum and maximum values will be set to 0 and 1 respectively.
Supported class powers:
- All - Combo Points
- Mage - Arcane Charges
- Monk - Chi Orbs
- Paladin - Holy Power
- Warlock - Soul Shards
## Examples
local ClassPower = {}
for index = 1, 10 do
local Bar = CreateFrame('StatusBar', nil, self)
-- Position and size.
Bar:SetSize(16, 16)
Bar:SetPoint('TOPLEFT', self, 'BOTTOMLEFT', (index - 1) * Bar:GetWidth(), 0)
ClassPower[index] = Bar
end
-- Register with oUF
self.ClassPower = ClassPower
--]]
local _, ns = ...
local oUF = ns.oUF
local _, PlayerClass = UnitClass('player')
-- sourced from FrameXML/Constants.lua
local SPELL_POWER_ENERGY = 3
local COMBO_POINTS_ID = 4
-- Holds the class specific stuff.
local ClassPowerID, ClassPowerType
local ClassPowerEnable, ClassPowerDisable
local RequireSpec, RequirePower, RequireSpell
local function UpdateColor(element, powerType)
local color = element.__owner.colors.power[powerType]
local r, g, b = color.r, color.g, color.b
for i = 1, #element do
local bar = element[i]
bar:SetStatusBarColor(r, g, b)
local bg = bar.bg
if(bg) then
local mu = bg.multiplier or 1
bg:SetVertexColor(r * mu, g * mu, b * mu)
end
end
--[[ Callback: ClassPower:PostUpdateColor(r, g, b)
Called after the element color has been updated.
* self - the ClassPower element
* r - the red component of the used color (number)[0-1]
* g - the green component of the used color (number)[0-1]
* b - the blue component of the used color (number)[0-1]
--]]
if(element.PostUpdateColor) then
element:PostUpdateColor(r, g, b)
end
end
local function Update(self, event, unit, powerType)
if(not (unit and (UnitIsUnit(unit, 'player') and (not powerType or powerType == ClassPowerType)
or unit == 'vehicle' and powerType == 'COMBO_POINTS'))) then
return
end
local element = self.ClassPower
--[[ Callback: ClassPower:PreUpdate(event)
Called before the element has been updated.
* self - the ClassPower element
]]
if(element.PreUpdate) then
element:PreUpdate()
end
local cur, max, oldMax
if(event ~= 'ClassPowerDisable') then
local powerID = unit == 'vehicle' and COMBO_POINTS_ID or ClassPowerID
powerType = powerType or ClassPowerType
max = powerType == 'COMBO_POINTS' and GetComboPoints(unit, 'target') or UnitPower(unit, powerID)
cur = powerType == 'COMBO_POINTS' and GetComboPoints(unit, 'target') or UnitPower(unit, powerID)
local numActive = cur + 0.9
for i = 1, max do
if(i > numActive) then
element[i]:Hide()
element[i]:SetValue(0)
else
element[i]:Show()
element[i]:SetValue(cur - i + 1)
end
end
oldMax = element.__max
if(max ~= oldMax) then
if(max < oldMax) then
for i = max + 1, oldMax do
element[i]:Hide()
element[i]:SetValue(0)
end
end
element.__max = max
end
end
--[[ Callback: ClassPower:PostUpdate(cur, max, hasMaxChanged, powerType)
Called after the element has been updated.
* self - the ClassPower element
* cur - the current amount of power (number)
* max - the maximum amount of power (number)
* hasMaxChanged - indicates whether the maximum amount has changed since the last update (boolean)
* powerType - the active power type (string)
--]]
if(element.PostUpdate) then
return element:PostUpdate(cur, max, oldMax ~= max, powerType)
end
end
local function Path(self, ...)
--[[ Override: ClassPower.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)
* ... - the arguments accompanying the event
--]]
return (self.ClassPower.Override or Update) (self, ...)
end
local function Visibility(self, event, unit)
local element = self.ClassPower
local shouldEnable
if UnitHasVehicleUI('player') then
shouldEnable = true
unit = 'vehicle'
elseif(not RequirePower or RequirePower == UnitPowerType('player')) then
if(not RequireSpell or IsSpellKnown(RequireSpell)) then
self:UnregisterEvent('SPELLS_CHANGED', Visibility)
shouldEnable = true
unit = 'player'
else
self:RegisterEvent('SPELLS_CHANGED', Visibility, true)
end
end
local isEnabled = element.__isEnabled
local powerType = unit == 'vehicle' and 'COMBO_POINTS' or ClassPowerType
if(shouldEnable) then
--[[ Override: ClassPower:UpdateColor(powerType)
Used to completely override the internal function for updating the widgets' colors.
* self - the ClassPower element
* powerType - the active power type (string)
--]]
(element.UpdateColor or UpdateColor) (element, powerType)
end
if(shouldEnable and not isEnabled) then
ClassPowerEnable(self)
--[[ Callback: ClassPower:PostVisibility(isVisible)
Called after the element's visibility has been changed.
* self - the ClassPower element
* isVisible - the current visibility state of the element (boolean)
--]]
if(element.PostVisibility) then
element:PostVisibility(true)
end
elseif(not shouldEnable and (isEnabled or isEnabled == nil)) then
ClassPowerDisable(self)
if(element.PostVisibility) then
element:PostVisibility(false)
end
elseif(shouldEnable and isEnabled) then
Path(self, event, unit, powerType)
end
end
local function VisibilityPath(self, ...)
--[[ Override: ClassPower.OverrideVisibility(self, event, unit)
Used to completely override the internal visibility function.
* self - the parent object
* event - the event triggering the update (string)
* unit - the unit accompanying the event (string)
--]]
return (self.ClassPower.OverrideVisibility or Visibility) (self, ...)
end
local function ForceUpdate(element)
return VisibilityPath(element.__owner, 'ForceUpdate', element.__owner.unit)
end
do
function ClassPowerEnable(self)
self:RegisterEvent('UNIT_MAXPOWER', Path)
self:RegisterEvent('UNIT_POWER_UPDATE', Path)
self:RegisterEvent('PLAYER_TARGET_CHANGED', VisibilityPath, true)
self.ClassPower.__isEnabled = true
if UnitHasVehicleUI('player') then
Path(self, 'ClassPowerEnable', 'vehicle', 'COMBO_POINTS')
end
end
function ClassPowerDisable(self)
self:UnregisterEvent('UNIT_POWER_UPDATE', Path)
self:UnregisterEvent('UNIT_MAXPOWER', Path)
self:UnregisterEvent('PLAYER_TARGET_CHANGED', VisibilityPath)
local element = self.ClassPower
for i = 1, #element do
element[i]:Hide()
end
element.__isEnabled = false
Path(self, 'ClassPowerDisable', 'player', ClassPowerType)
end
if(PlayerClass == 'ROGUE' or PlayerClass == 'DRUID' or PlayerClass == 'HERO') then
ClassPowerType = 'COMBO_POINTS'
if(PlayerClass == 'DRUID') then
RequirePower = SPELL_POWER_ENERGY
RequireSpell = 768 -- cat form
end
end
end
local function Enable(self, unit)
local element = self.ClassPower
if(element and UnitIsUnit(unit, 'player')) then
element.__owner = self
element.__max = #element
element.ForceUpdate = ForceUpdate
if (RequireSpell and not IsSpellKnown(RequireSpell)) then
self:RegisterEvent('SPELLS_CHANGED', VisibilityPath, true)
end
if(RequirePower) then
self:RegisterEvent('UNIT_DISPLAYPOWER', VisibilityPath)
end
self:RegisterEvent('UNIT_COMBO_POINTS', VisibilityPath)
element.ClassPowerEnable = ClassPowerEnable
element.ClassPowerDisable = ClassPowerDisable
for i = 1, #element do
local bar = element[i]
if bar:IsObjectType('StatusBar') then
if not bar:GetStatusBarTexture() then
bar:SetStatusBarTexture([[Interface\TargetingFrame\UI-StatusBar]])
end
bar:SetMinMaxValues(0, 1)
end
end
return true
end
end
local function Disable(self)
if(self.ClassPower) then
ClassPowerDisable(self)
self:UnregisterEvent('UNIT_DISPLAYPOWER', VisibilityPath)
self:UnregisterEvent('SPELLS_CHANGED', Visibility)
self:RegisterEvent('UNIT_COMBO_POINTS', VisibilityPath)
end
end
oUF:AddElement('ClassPower', VisibilityPath, Enable, Disable)
+1
View File
@@ -33,6 +33,7 @@
<Script file="elements\combopoints.lua"/>
<Script file="elements\raidroleindicator.lua"/>
<Script file="elements\happinessindicator.lua"/>
<Script file="elements\classpower.lua"/>
<!-- Clique support -->
<Button name="oUF_ClickCastUnitTemplate" virtual="true" inherits="SecureUnitButtonTemplate, SecureHandlerEnterLeaveTemplate">
@@ -12,7 +12,7 @@ local MAX_COMBO_POINTS = MAX_COMBO_POINTS
local MAX_POINTS = { -- match to UF.classMaxResourceBar
DEATHKNIGHT = max(6, MAX_COMBO_POINTS),
ROGUE = max(7, MAX_COMBO_POINTS),
ROGUE = max(5, MAX_COMBO_POINTS),
HERO = max(5, MAX_COMBO_POINTS),
DRUID = max(5, MAX_COMBO_POINTS)
}
@@ -38,7 +38,7 @@ function NP:ClassPower_UpdateColor(powerType, rune)
local color = colors.DEATHKNIGHT[rune.runeType or 0]
NP:ClassPower_SetBarColor(rune, color.r, color.g, color.b)
else
local classColor = not classPower and ((isRunes and colors.DEATHKNIGHT) or (powerType == 'COMBO_POINTS' and colors.comboPoints) or (powerType == 'ESSENCE' and colors.EVOKER) or (powerType == 'CHI' and colors.MONK))
local classColor = not classPower and ((isRunes and colors.DEATHKNIGHT) or (powerType == 'COMBO_POINTS' and colors.comboPoints))
for i, bar in ipairs(self) do
local color = classPower or (isRunes and classColor[bar.runeType or 0]) or (classColor and classColor[i]) or colors[E.myclass] or fallback
NP:ClassPower_SetBarColor(bar, color.r, color.g, color.b)
@@ -57,7 +57,7 @@ function NP:ClassPower_PostUpdate(Cur, _, needUpdate, powerType, chargedPoints)
NP:Update_ClassPower(self.__owner)
end
if powerType == 'COMBO_POINTS' and E.myclass == 'ROGUE' then
if powerType == 'COMBO_POINTS' and (E.myclass == 'ROGUE' or E.myclass == 'DRUID' or E.myclass == 'HERO') then
NP.ClassPower_UpdateColor(self, powerType)
if chargedPoints then
+9 -9
View File
@@ -703,7 +703,7 @@ for unit, data in next, P.nameplates.units do
end
P.nameplates.units.PLAYER.buffs.maxDuration = 300
P.nameplates.units.PLAYER.buffs.priority = 'Blacklist,blockNoDuration,Personal,TurtleBuffs,PlayerBuffs'
P.nameplates.units.PLAYER.buffs.priority = 'Blacklist,Dispellable,blockNoDuration,Personal,TurtleBuffs,PlayerBuffs'
P.nameplates.units.PLAYER.debuffs.anchorPoint = 'TOPRIGHT'
P.nameplates.units.PLAYER.debuffs.growthDirection = 'LEFT_UP'
P.nameplates.units.PLAYER.debuffs.yOffset = 35
@@ -714,33 +714,33 @@ P.nameplates.units.PLAYER.level.enable = false
P.nameplates.units.PLAYER.power.enable = true
P.nameplates.units.PLAYER.castbar.yOffset = -20
P.nameplates.units.FRIENDLY_PLAYER.buffs.priority = 'Blacklist,blockNoDuration,Personal,TurtleBuffs'
P.nameplates.units.FRIENDLY_PLAYER.buffs.priority = 'Blacklist,Dispellable,blockNoDuration,Personal,TurtleBuffs,PlayerBuffs'
P.nameplates.units.FRIENDLY_PLAYER.debuffs.anchorPoint = 'TOPRIGHT'
P.nameplates.units.FRIENDLY_PLAYER.debuffs.growthDirection = 'LEFT_UP'
P.nameplates.units.FRIENDLY_PLAYER.debuffs.yOffset = 35
P.nameplates.units.FRIENDLY_PLAYER.debuffs.priority = 'Blacklist,Personal,RaidDebuffs,CCDebuffs,Whitelist'
P.nameplates.units.FRIENDLY_PLAYER.debuffs.priority = 'Blacklist,Personal,blockNonPersonal,RaidDebuffs,CCDebuffs,Whitelist'
P.nameplates.units.ENEMY_PLAYER.buffs.priority = 'Blacklist,Dispellable,PlayerBuffs,TurtleBuffs'
P.nameplates.units.ENEMY_PLAYER.buffs.priority = 'Blacklist,Dispellable,blockNoDuration,Personal,TurtleBuffs,PlayerBuffs'
P.nameplates.units.ENEMY_PLAYER.buffs.maxDuration = 300
P.nameplates.units.ENEMY_PLAYER.debuffs.anchorPoint = 'TOPRIGHT'
P.nameplates.units.ENEMY_PLAYER.debuffs.growthDirection = 'LEFT_UP'
P.nameplates.units.ENEMY_PLAYER.debuffs.yOffset = 35
P.nameplates.units.ENEMY_PLAYER.debuffs.priority = 'Blacklist,Personal,RaidDebuffs,CCDebuffs,Whitelist'
P.nameplates.units.ENEMY_PLAYER.debuffs.priority = 'Blacklist,Personal,blockNonPersonal,RaidDebuffs,CCDebuffs,Whitelist'
P.nameplates.units.ENEMY_PLAYER.name.format = '[classcolor][name:abbrev:long]'
P.nameplates.units.FRIENDLY_NPC.buffs.priority = 'Blacklist,blockNoDuration,Personal,TurtleBuffs'
P.nameplates.units.FRIENDLY_NPC.buffs.priority = 'Blacklist,Dispellable,blockNoDuration,Personal,TurtleBuffs,PlayerBuffs'
P.nameplates.units.FRIENDLY_NPC.debuffs.anchorPoint = 'TOPRIGHT'
P.nameplates.units.FRIENDLY_NPC.debuffs.growthDirection = 'LEFT_UP'
P.nameplates.units.FRIENDLY_NPC.debuffs.yOffset = 35
P.nameplates.units.FRIENDLY_NPC.debuffs.priority = 'Blacklist,Personal,RaidDebuffs,CCDebuffs,Whitelist'
P.nameplates.units.FRIENDLY_NPC.debuffs.priority = 'Blacklist,Personal,blockNonPersonal,RaidDebuffs,CCDebuffs,Whitelist'
P.nameplates.units.FRIENDLY_NPC.level.format = '[difficultycolor][level][shortclassification]'
P.nameplates.units.FRIENDLY_NPC.title.format = '[npctitle]'
P.nameplates.units.ENEMY_NPC.buffs.priority = 'Blacklist,blockNoDuration,Personal,TurtleBuffs'
P.nameplates.units.ENEMY_NPC.buffs.priority = 'Blacklist,Dispellable,blockNoDuration,Personal,TurtleBuffs,PlayerBuffs'
P.nameplates.units.ENEMY_NPC.debuffs.anchorPoint = 'TOPRIGHT'
P.nameplates.units.ENEMY_NPC.debuffs.growthDirection = 'LEFT_UP'
P.nameplates.units.ENEMY_NPC.debuffs.yOffset = 35
P.nameplates.units.ENEMY_NPC.debuffs.priority = 'Blacklist,Personal,RaidDebuffs,CCDebuffs,Whitelist'
P.nameplates.units.ENEMY_NPC.debuffs.priority = 'Blacklist,Personal,blockNonPersonal,RaidDebuffs,CCDebuffs,Whitelist'
P.nameplates.units.ENEMY_NPC.level.format = '[difficultycolor][level][shortclassification]'
P.nameplates.units.ENEMY_NPC.title.format = '[npctitle]'
P.nameplates.units.ENEMY_NPC.name.format = '[name]'
+3 -1
View File
@@ -6,7 +6,9 @@ Engine[1] = {Blank = function() return '' end }
Engine[2] = E.Libs.ACL:GetLocale("ElvUI", E.global.general.locale or "enUS")
local C, L = Engine[1], Engine[2]
local format = string.format
local format, strmatch, strsplit = string.format, string.match, string.split
local tconcat, tinsert, tremove = table.concat, table.insert, table.remove
local ipairs, gsub = ipairs, gsub
C.Values = {
FontFlags = {
+2 -2
View File
@@ -329,7 +329,7 @@ local function GetUnitSettings(unit, name)
group.args.raidTargetIndicator.args.yOffset = ACH:Range(L["Y-Offset"], nil, 6, { min = -100, max = 100, step = 1 })
if unit == 'PLAYER' then
group.args.classBarGroup = ACH:Group(L["Class Bar"], nil, 13, nil, function(info) return E.db.nameplates.units[unit].classpower[info[#info]] end, function(info, value) E.db.nameplates.units[unit].classpower[info[#info]] = value NP:ConfigureAll() end)
group.args.classBarGroup = ACH:Group(L["Combo Points / Runes"], nil, 13, nil, function(info) return E.db.nameplates.units[unit].classpower[info[#info]] end, function(info, value) E.db.nameplates.units[unit].classpower[info[#info]] = value NP:ConfigureAll() end)
group.args.classBarGroup.args.enable = ACH:Toggle(L["Enable"], nil, 1)
group.args.classBarGroup.args.classColor = ACH:Toggle(L["Use Class Color"], nil, 2, nil, nil, nil, nil, nil, nil, not E.Retail and E.myclass == 'DEATHKNIGHT')
group.args.classBarGroup.args.width = ACH:Range(L["Width"], nil, 3, { min = minWidth, max = MaxWidth(unit), step = 1 })
@@ -576,7 +576,7 @@ for key, arrow in pairs(arrows) do
NamePlates.targetGroup.args.arrows.values[key] = E:TextureString(arrow, ':32:32')
end
NamePlates.targetGroup.args.classBarGroup = ACH:Group(L["Class Bar"], nil, 13, nil, function(info) return E.db.nameplates.units.TARGET.classpower[info[#info]] end, function(info, value) E.db.nameplates.units.TARGET.classpower[info[#info]] = value NP:ConfigureAll() end)
NamePlates.targetGroup.args.classBarGroup = ACH:Group(L["Combo Points / Runes"], nil, 13, nil, function(info) return E.db.nameplates.units.TARGET.classpower[info[#info]] end, function(info, value) E.db.nameplates.units.TARGET.classpower[info[#info]] = value NP:ConfigureAll() end)
NamePlates.targetGroup.args.classBarGroup.inline = true
NamePlates.targetGroup.args.classBarGroup.args.enable = ACH:Toggle(L["Enable"], nil, 1)
NamePlates.targetGroup.args.classBarGroup.args.classColor = ACH:Toggle(L["Use Class Color"], nil, 2, nil, nil, nil, nil, nil, nil, not E.Retail and E.myclass == 'DEATHKNIGHT')