diff --git a/oUF/blizzard.lua b/oUF/blizzard.lua index e90aae8..3c29780 100644 --- a/oUF/blizzard.lua +++ b/oUF/blizzard.lua @@ -5,7 +5,7 @@ local oUF = ns.oUF local MAX_ARENA_ENEMIES = _G.MAX_ARENA_ENEMIES or 5 -- sourced from FrameXML/TargetFrame.lua -local MAX_BOSS_FRAMES = _G.MAX_BOSS_FRAMES or 5 +local MAX_BOSS_FRAMES = 8 -- sourced from FrameXML/PartyMemberFrame.lua local MAX_PARTY_MEMBERS = _G.MAX_PARTY_MEMBERS or 4 @@ -69,10 +69,10 @@ function oUF:DisableBlizzard(unit) -- For the damn vehicle support: PlayerFrame:RegisterEvent('PLAYER_ENTERING_WORLD') - --PlayerFrame:RegisterEvent('UNIT_ENTERING_VEHICLE') - --PlayerFrame:RegisterEvent('UNIT_ENTERED_VEHICLE') - --PlayerFrame:RegisterEvent('UNIT_EXITING_VEHICLE') - --PlayerFrame:RegisterEvent('UNIT_EXITED_VEHICLE') + PlayerFrame:RegisterEvent('UNIT_ENTERING_VEHICLE') + PlayerFrame:RegisterEvent('UNIT_ENTERED_VEHICLE') + PlayerFrame:RegisterEvent('UNIT_EXITING_VEHICLE') + PlayerFrame:RegisterEvent('UNIT_EXITED_VEHICLE') -- User placed frames don't animate PlayerFrame:SetUserPlaced(true) @@ -87,7 +87,7 @@ function oUF:DisableBlizzard(unit) handleFrame(TargetofFocusFrame) elseif(unit == 'targettarget') then handleFrame(TargetFrameToT) ---[[elseif(unit:match('boss%d?$')) then + elseif(unit:match('boss%d?$')) then local id = unit:match('boss(%d)') if(id) then handleFrame('Boss' .. id .. 'TargetFrame') @@ -95,7 +95,7 @@ function oUF:DisableBlizzard(unit) for i = 1, MAX_BOSS_FRAMES do handleFrame(string.format('Boss%dTargetFrame', i)) end - end]] + end elseif(unit:match('party%d?$')) then local id = unit:match('party(%d)') if(id) then @@ -117,7 +117,7 @@ function oUF:DisableBlizzard(unit) -- Blizzard_ArenaUI should not be loaded _G.Arena_LoadUI = function() end - SetCVar('showArenaEnemyFrames', '0', 'SHOW_ARENA_ENEMY_FRAMES_TEXT') + --SetCVar('showArenaEnemyFrames', '0', 'SHOW_ARENA_ENEMY_FRAMES_TEXT') elseif(unit:match('nameplate%d+$')) then local frame = C_NamePlate.GetNamePlateForUnit(unit) if(frame and frame.UnitFrame) then @@ -129,4 +129,4 @@ function oUF:DisableBlizzard(unit) handleFrame(frame.UnitFrame, true) end end -end \ No newline at end of file +end diff --git a/oUF/colors.lua b/oUF/colors.lua index 9bfe2b9..b36b62a 100644 --- a/oUF/colors.lua +++ b/oUF/colors.lua @@ -1,4 +1,4 @@ -local parent, ns = ... +local _, ns = ... local oUF = ns.oUF local Private = oUF.Private @@ -10,6 +10,11 @@ local colors = { 1, 1, 0, 0, 1, 0 }, + happiness = { + [1] = {.69, .31, .31}, + [2] = {.65, .63, .35}, + [3] = {.33, .59, .33}, + }, health = {49 / 255, 207 / 255, 37 / 255}, disconnected = {0.6, 0.6, 0.6}, tapped = {0.6, 0.6, 0.6}, @@ -17,6 +22,7 @@ local colors = { {247 / 255, 65 / 255, 57 / 255}, -- blood {148 / 255, 203 / 255, 247 / 255}, -- frost {173 / 255, 235 / 255, 66 / 255}, -- unholy + {247 / 255, 66 / 255, 247 / 255}, -- death }, selection = { [ 0] = {255 / 255, 0 / 255, 0 / 255}, -- HOSTILE @@ -38,19 +44,20 @@ local colors = { debuff = {}, reaction = {}, power = {}, - happiness = { - [1] = {1, 0, 0}, -- need.... | unhappy - [2] = {1, 1, 0}, -- new..... | content - [3] = {0, 1, 0}, -- colors.. | happy + threat = { + [0] = { .69, .69, .69}, + [1] = { 1, 1, .47 }, + [2] = { 1, .6, 0 }, + [3] = { 1, 0, 0 }, }, } -- We do this because people edit the vars directly, and changing the default -- globals makes SPICE FLOW! local function customClassColors() - if(CUSTOM_CLASS_COLORS) then + if(_G.CUSTOM_CLASS_COLORS) then local function updateColors() - for classToken, color in next, CUSTOM_CLASS_COLORS do + for classToken, color in next, _G.CUSTOM_CLASS_COLORS do colors.class[classToken] = {color.r, color.g, color.b} end @@ -60,14 +67,14 @@ local function customClassColors() end updateColors() - CUSTOM_CLASS_COLORS:RegisterCallback(updateColors) + _G.CUSTOM_CLASS_COLORS:RegisterCallback(updateColors) return true end end if(not customClassColors()) then - for classToken, color in next, RAID_CLASS_COLORS do + for classToken, color in next, _G.RAID_CLASS_COLORS do colors.class[classToken] = {color.r, color.g, color.b} end @@ -81,11 +88,11 @@ if(not customClassColors()) then end) end -for debuffType, color in next, DebuffTypeColor do +for debuffType, color in next, _G.DebuffTypeColor do colors.debuff[debuffType] = {color.r, color.g, color.b} end -for eclass, color in next, FACTION_BAR_COLORS do +for eclass, color in next, _G.FACTION_BAR_COLORS do colors.reaction[eclass] = {color.r, color.g, color.b} end @@ -94,8 +101,8 @@ for power, color in next, PowerBarColor do if(type(select(2, next(color))) == 'table') then colors.power[power] = {} - for index, color in next, color do - colors.power[power][index] = {color.r, color.g, color.b} + for index, color_ in next, color do + colors.power[power][index] = {color_.r, color_.g, color_.b} end else colors.power[power] = {color.r, color.g, color.b, atlas = color.atlas} @@ -121,6 +128,16 @@ colors.power[16] = colors.power.ARCANE_CHARGES colors.power[17] = colors.power.FURY colors.power[18] = colors.power.PAIN +-- alternate power, sourced from FrameXML/CompactUnitFrame.lua +colors.power.ALTERNATE = {0.7, 0.7, 0.6} +colors.power[10] = colors.power.ALTERNATE + +if GetThreatStatusColor then + for i = 0, 3 do + colors.threat[i] = {GetThreatStatusColor(i)} + end +end + local function colorsAndPercent(a, b, ...) if(a <= 0 or b == 0) then return nil, ... @@ -265,4 +282,4 @@ oUF.colors = colors oUF.useHCYColorGradient = false frame_metatable.__index.colors = colors -frame_metatable.__index.ColorGradient = oUF.ColorGradient \ No newline at end of file +frame_metatable.__index.ColorGradient = oUF.ColorGradient diff --git a/oUF/elements/additionalpower.lua b/oUF/elements/additionalpower.lua index 8fbaa52..04d3e5e 100644 --- a/oUF/elements/additionalpower.lua +++ b/oUF/elements/additionalpower.lua @@ -1,7 +1,8 @@ --[[ # Element: Additional Power Bar -Handles the visibility and updating of a status bar that displays the player's additional power, such as Mana for druids. +Handles the visibility and updating of a status bar that displays the player's additional power, such as Mana for +Balance druids. ## Widget @@ -17,18 +18,18 @@ A default texture will be applied if the widget is a StatusBar and doesn't have ## Options -.frequentUpdates - Indicates whether to use UNIT_POWER_FREQUENT instead UNIT_POWER_UPDATE to update the - bar (boolean) -.smoothGradient - 9 color values to be used with the .colorSmooth option (table) +.frequentUpdates - Indicates whether to use UNIT_POWER_FREQUENT instead UNIT_POWER_UPDATE to update the bar (boolean) +.displayPairs - Use to override display pairs. (table) +.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. -.colorPower - Use `self.colors.power[token]` to color the bar based on the player's additional power type - (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) -.colorSmooth - Use `self.colors.smooth` to color the bar with a smooth gradient based on the player's current - additional power percentage (boolean) +.colorPower - Use `self.colors.power[token]` to color the bar based on the player's additional power type + (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) +.colorSmooth - Use `self.colors.smooth` to color the bar with a smooth gradient based on the player's current + additional power percentage (boolean) ## Sub-Widget Options @@ -53,21 +54,35 @@ The following options are listed by priority. The first check that returns true self.AdditionalPower = AdditionalPower --]] -if(select(2, UnitClass('player')) ~= 'DRUID') then return end - local _, ns = ... local oUF = ns.oUF -local function UpdateColor(self, event, unit, powertype) - if(not (unit and unit == 'player') and powertype == 'MANA') then return end +local _, playerClass = UnitClass('player') + +-- ElvUI block +local unpack = unpack +local CopyTable = CopyTable +local UnitIsUnit = UnitIsUnit +local UnitPower = UnitPower +local UnitPowerMax = UnitPowerMax +local UnitHasVehicleUI = UnitHasVehicleUI +local UnitPowerType = UnitPowerType +-- end block + +-- sourced from FrameXML/AlternatePowerBar.lua +local POWER_NAME = _G.ADDITIONAL_POWER_BAR_NAME or 'MANA' +local POWER_INDEX = _G.ADDITIONAL_POWER_BAR_INDEX or 0 +local ALT_MANA_INFO = _G.ALT_MANA_BAR_PAIR_DISPLAY_INFO or {DRUID={[8]=true}, SHAMAN={[11]=true}, PRIEST={[13]=true}} + +local function UpdateColor(self, event, unit, powerType) + if(not (unit and UnitIsUnit(unit, 'player') and powerType == POWER_NAME)) then return end local element = self.AdditionalPower local r, g, b, t if(element.colorPower) then - t = self.colors.power[0] - elseif(element.colorClass and UnitIsPlayer(unit)) then - local _, class = UnitClass(unit) - t = self.colors.class[class] + t = self.colors.power[POWER_INDEX] + elseif(element.colorClass) then + t = self.colors.class[playerClass] elseif(element.colorSmooth) then r, g, b = self:ColorGradient(element.cur or 1, element.max or 1, unpack(element.smoothGradient or self.colors.smooth)) end @@ -86,27 +101,23 @@ local function UpdateColor(self, event, unit, powertype) end end - if(element.PostUpdateColor) then - element:PostUpdateColor(unit, r, g, b) - end -end - -local function ColorPath(self, ...) - --[[ Override: AdditionalPower.UpdateColor(self, event, unit, ...) - Used to completely override the internal function for updating the widgets' colors. + --[[ Callback: AdditionalPower:PostUpdateColor(r, g, b) + Called after the element color has been updated. - * self - the parent object - * event - the event triggering the update (string) - * unit - the unit accompanying the event (string) - * ... - the arguments accompanying the event + * self - the AdditionalPower 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] --]] - (self.AdditionalPower.UpdateColor or UpdateColor) (self, ...) + if(element.PostUpdateColor) then + element:PostUpdateColor(r, g, b) + end end -local function Update(self, event, unit, powertype) - if(not (unit and unit == 'player') and powertype == 'MANA') then return end - +local function Update(self, event, unit, powerType) + if(not (unit and UnitIsUnit(unit, 'player') and powerType == POWER_NAME)) then return end local element = self.AdditionalPower + --[[ Callback: AdditionalPower:PreUpdate(unit) Called before the element has been updated. @@ -117,25 +128,23 @@ local function Update(self, event, unit, powertype) element:PreUpdate(unit) end - local cur = UnitPower('player', 0) - local max = UnitPowerMax('player', 0) - + local cur, max = UnitPower('player', POWER_INDEX), UnitPowerMax('player', POWER_INDEX) element:SetMinMaxValues(0, max) + element:SetValue(cur) element.cur = cur element.max = max - --[[ Callback: AdditionalPower:PostUpdate(unit, cur, max) + --[[ Callback: AdditionalPower:PostUpdate(cur, max) Called after the element has been updated. * self - the AdditionalPower element - * unit - the unit for which the update has been triggered (string) * cur - the current value of the player's additional power (number) * max - the maximum value of the player's additional power (number) --]] if(element.PostUpdate) then - return element:PostUpdate(unit, cur, max) + return element:PostUpdate(cur, max, event) -- ElvUI adds event end end @@ -148,9 +157,17 @@ local function Path(self, ...) * unit - the unit accompanying the event (string) * ... - the arguments accompanying the event --]] - (self.AdditionalPower.Override or Update) (self, ...) + (self.AdditionalPower.Override or Update) (self, ...); - ColorPath(self, ...) + --[[ Override: AdditionalPower.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) + * ... - the arguments accompanying the event + --]] + (self.AdditionalPower.UpdateColor or UpdateColor) (self, ...) end local function ElementEnable(self) @@ -166,36 +183,57 @@ local function ElementEnable(self) element:Show() - Path(self, 'ElementEnable', 'player', 'MANA') + element.__isEnabled = true + + Path(self, 'ElementEnable', 'player', POWER_NAME) end local function ElementDisable(self) local element = self.AdditionalPower - if(element.frequentUpdates) then - self:RegisterEvent('UNIT_POWER_FREQUENT', Path) - else - self:RegisterEvent('UNIT_POWER_UPDATE', Path) - end - self:UnregisterEvent('UNIT_MAXPOWER', Path) + self:UnregisterEvent('UNIT_POWER_FREQUENT', Path) + self:UnregisterEvent('UNIT_POWER_UPDATE', Path) - self.AdditionalPower:Hide() + element:Hide() - Path(self, 'ElementDisable', 'player', 'MANA') + element.__isEnabled = false + Path(self, 'ElementDisable', 'player', POWER_NAME) end -local function Visibility(self) +local function Visibility(self, event, unit) + local element = self.AdditionalPower local shouldEnable - if((UnitPowerType('player') ~= 0) and (UnitPowerMax('player', 0) ~= 0)) then - shouldEnable = true + if (oUF.isClassic or oUF.isTBC) or not UnitHasVehicleUI('player') then + local allowed = element.displayPairs[playerClass] + if allowed and UnitPowerMax(unit, POWER_INDEX) ~= 0 then + shouldEnable = allowed[UnitPowerType(unit)] + end end - if(shouldEnable) then + local isEnabled = element.__isEnabled + + if(shouldEnable and not isEnabled) then ElementEnable(self) - else + + --[[ Callback: AdditionalPower:PostVisibility(isVisible) + Called after the element's visibility has been changed. + + * self - the AdditionalPower 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 ElementDisable(self) + + if(element.PostVisibility) then + element:PostVisibility(false) + end + elseif(shouldEnable and isEnabled) then + Path(self, event, unit, POWER_NAME) end end @@ -207,22 +245,47 @@ local function VisibilityPath(self, ...) * event - the event triggering the update (string) * unit - the unit accompanying the event (string) --]] - return (self.AdditionalPower.OverrideVisibility or Visibility) (self, ...) + (self.AdditionalPower.OverrideVisibility or Visibility) (self, ...) end local function ForceUpdate(element) - return VisibilityPath(element.__owner, 'ForceUpdate', element.__owner.unit) + VisibilityPath(element.__owner, 'ForceUpdate', element.__owner.unit) +end + +--[[ Power:SetFrequentUpdates(state, isForced) +Used to toggle frequent updates. + +* self - the Power element +* state - the desired state (boolean) +* isForced - forces the event update even if the state wasn't changed (boolean) +--]] +local function SetFrequentUpdates(element, state, isForced) + if(element.frequentUpdates ~= state or isForced) then + element.frequentUpdates = state + if(state) then + element.__owner:UnregisterEvent('UNIT_POWER_UPDATE', Path) + element.__owner:RegisterEvent('UNIT_POWER_FREQUENT', Path) + else + element.__owner:UnregisterEvent('UNIT_POWER_FREQUENT', Path) + element.__owner:RegisterEvent('UNIT_POWER_UPDATE', Path) + end + end end local function Enable(self, unit) local element = self.AdditionalPower - if(element and unit == 'player') then + if(element and UnitIsUnit(unit, 'player')) then element.__owner = self element.ForceUpdate = ForceUpdate + element.SetFrequentUpdates = SetFrequentUpdates self:RegisterEvent('UNIT_DISPLAYPOWER', VisibilityPath) - if(element:IsObjectType('StatusBar') and not element:GetStatusBarTexture()) then + if(not element.displayPairs) then + element.displayPairs = CopyTable(ALT_MANA_INFO) + end + + if(element:IsObjectType('StatusBar') and not (element:GetStatusBarTexture() or element:GetStatusBarAtlas())) then element:SetStatusBarTexture([[Interface\TargetingFrame\UI-StatusBar]]) end @@ -239,4 +302,4 @@ local function Disable(self) end end -oUF:AddElement('AdditionalPower', VisibilityPath, Enable, Disable) \ No newline at end of file +oUF:AddElement('AdditionalPower', VisibilityPath, Enable, Disable) diff --git a/oUF/elements/alternativepower.lua b/oUF/elements/alternativepower.lua index 6185b8d..56ce005 100644 --- a/oUF/elements/alternativepower.lua +++ b/oUF/elements/alternativepower.lua @@ -59,8 +59,11 @@ local unitSelectionType = Private.unitSelectionType -- sourced from FrameXML/UnitPowerBarAlt.lua local ALTERNATE_POWER_INDEX = Enum.PowerType.Alternate or 10 local ALTERNATE_POWER_NAME = 'ALTERNATE' +local GameTooltip = GameTooltip local function updateTooltip(self) + if GameTooltip:IsForbidden() then return end + local name, tooltip = GetUnitPowerBarStringsByID(self.__barID) GameTooltip:SetText(name or '', 1, 1, 1) GameTooltip:AddLine(tooltip or '', nil, nil, nil, true) @@ -68,13 +71,16 @@ local function updateTooltip(self) end local function onEnter(self) - if(not self:IsVisible()) then return end + if GameTooltip:IsForbidden() or not self:IsVisible() then return end + GameTooltip:ClearAllPoints() GameTooltip_SetDefaultAnchor(GameTooltip, self) self:UpdateTooltip() end local function onLeave() + if GameTooltip:IsForbidden() then return end + GameTooltip:Hide() end @@ -141,12 +147,16 @@ local function Update(self, event, unit, powerType) element:PreUpdate() end - local cur, max, min + local min, max, cur = 0 local barInfo = element.__barInfo if(barInfo) then cur = UnitPower(unit, ALTERNATE_POWER_INDEX) max = UnitPowerMax(unit, ALTERNATE_POWER_INDEX) - min = barInfo.minPower + + if barInfo.minPower then + min = barInfo.minPower + end + element:SetMinMaxValues(min, max) element:SetValue(cur) end diff --git a/oUF/elements/classpower.lua b/oUF/elements/classpower.lua index c2cc7aa..74ac39a 100644 --- a/oUF/elements/classpower.lua +++ b/oUF/elements/classpower.lua @@ -50,13 +50,20 @@ local oUF = ns.oUF local _, PlayerClass = UnitClass('player') -- sourced from FrameXML/Constants.lua +local SPEC_MAGE_ARCANE = _G.SPEC_MAGE_ARCANE or 1 +local SPEC_MONK_WINDWALKER = _G.SPEC_MONK_WINDWALKER or 3 +local SPEC_WARLOCK_DESTRUCTION = _G.SPEC_WARLOCK_DESTRUCTION or 3 local SPELL_POWER_ENERGY = Enum.PowerType.Energy or 3 local SPELL_POWER_COMBO_POINTS = Enum.PowerType.ComboPoints or 4 +local SPELL_POWER_SOUL_SHARDS = Enum.PowerType.SoulShards or 7 +local SPELL_POWER_HOLY_POWER = Enum.PowerType.HolyPower or 9 +local SPELL_POWER_CHI = Enum.PowerType.Chi or 12 +local SPELL_POWER_ARCANE_CHARGES = Enum.PowerType.ArcaneCharges or 16 -- Holds the class specific stuff. local ClassPowerID, ClassPowerType local ClassPowerEnable, ClassPowerDisable -local RequirePower, RequireSpell +local RequireSpec, RequirePower, RequireSpell local function UpdateColor(element, powerType) local color = element.__owner.colors.power[powerType] @@ -71,16 +78,23 @@ local function UpdateColor(element, powerType) bg:SetVertexColor(r * mu, g * mu, b * mu) end end -end -local function Update(self, event, unit, powerType) - if event == "PLAYER_TARGET_CHANGED" then - unit, powerType = "player", "COMBO_POINTS" - elseif powerType == "ENERGY" then - powerType = "COMBO_POINTS" -- sometimes powerType return ENERGY for the first combo point + --[[ 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 - if (not (unit and (UnitIsUnit(unit, 'player') and powerType == ClassPowerType))) then +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 @@ -95,17 +109,28 @@ local function Update(self, event, unit, powerType) element:PreUpdate() end - local cur, max, mod, oldMax + local cur, max, mod, oldMax, chargedPoints if(event ~= 'ClassPowerDisable') then - local powerID = ClassPowerID - --cur = UnitPower(unit, powerID, true) - cur = GetComboPoints(unit, "target") -- has to use GetComboPoints in classic + local powerID = unit == 'vehicle' and SPELL_POWER_COMBO_POINTS or ClassPowerID + cur = not oUF.isRetail and powerType == 'COMBO_POINTS' and GetComboPoints('player', 'target') or UnitPower(unit, powerID, true) max = UnitPowerMax(unit, powerID) mod = UnitPowerDisplayMod(powerID) -- mod should never be 0, but according to Blizz code it can actually happen cur = mod == 0 and 0 or cur / mod + -- BUG: Destruction is supposed to show partial soulshards, but Affliction and Demonology should only show full ones + if oUF.isRetail and (ClassPowerType == 'SOUL_SHARDS' and GetSpecialization() ~= SPEC_WARLOCK_DESTRUCTION) then + cur = cur - cur % 1 + end + + if oUF.isRetail and (PlayerClass == 'ROGUE') then + chargedPoints = GetUnitChargedPowerPoints(unit) + + -- UNIT_POWER_POINT_CHARGE doesn't provide a power type + powerType = powerType or ClassPowerType + end + local numActive = cur + 0.9 for i = 1, max do if(i > numActive) then @@ -137,9 +162,10 @@ local function Update(self, event, unit, powerType) * 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) + * chargedTable - current chargedPoints table --]] if(element.PostUpdate) then - return element:PostUpdate(cur, max, oldMax ~= max, powerType) + return element:PostUpdate(cur, max, oldMax ~= max, powerType, chargedPoints) -- ElvUI uses chargedPoints as table end end @@ -159,21 +185,26 @@ local function Visibility(self, event, unit) local element = self.ClassPower local shouldEnable - if(ClassPowerID) then - -- use 'player' instead of unit because 'SPELLS_CHANGED' is a unitless event - if(not RequirePower or RequirePower == UnitPowerType('player')) then - if(not RequireSpell or IsPlayerSpell(RequireSpell)) then - self:UnregisterEvent('SPELLS_CHANGED', Visibility) - shouldEnable = true - unit = 'player' - else - self:RegisterEvent('SPELLS_CHANGED', Visibility, true) + if oUF.isRetail and UnitHasVehicleUI('player') then + shouldEnable = PlayerVehicleHasComboPoints() + unit = 'vehicle' + elseif(ClassPowerID) then + if(not RequireSpec or oUF.isRetail and (RequireSpec == GetSpecialization())) then + -- use 'player' instead of unit because 'SPELLS_CHANGED' is a unitless event + if(not RequirePower or RequirePower == UnitPowerType('player')) then + if(not RequireSpell or IsPlayerSpell(RequireSpell)) then + self:UnregisterEvent('SPELLS_CHANGED', Visibility) + shouldEnable = true + unit = 'player' + else + self:RegisterEvent('SPELLS_CHANGED', Visibility, true) + end end end end - local isEnabled = element.isEnabled - local powerType = ClassPowerType + local isEnabled = element.__isEnabled + local powerType = unit == 'vehicle' and 'COMBO_POINTS' or ClassPowerType if(shouldEnable) then --[[ Override: ClassPower:UpdateColor(powerType) @@ -187,8 +218,22 @@ local function Visibility(self, event, unit) 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 @@ -212,36 +257,66 @@ end do function ClassPowerEnable(self) self:RegisterEvent('UNIT_POWER_FREQUENT', Path) - self:RegisterEvent('PLAYER_TARGET_CHANGED', Path, true) self:RegisterEvent('UNIT_MAXPOWER', Path) - self.ClassPower.isEnabled = true + if not oUF.isRetail then + self:RegisterEvent('PLAYER_TARGET_CHANGED', VisibilityPath, true) + end + + if oUF.isRetail and (PlayerClass == 'ROGUE') then + self:RegisterEvent('UNIT_POWER_POINT_CHARGE', Path) + end + + self.ClassPower.__isEnabled = true - Path(self, 'ClassPowerEnable', 'player', ClassPowerType) + if (oUF.isRetail or oUF.isWrath) and UnitHasVehicleUI('player') then + Path(self, 'ClassPowerEnable', 'vehicle', 'COMBO_POINTS') + else + Path(self, 'ClassPowerEnable', 'player', ClassPowerType) + end end function ClassPowerDisable(self) self:UnregisterEvent('UNIT_POWER_FREQUENT', Path) - self:UnregisterEvent('PLAYER_TARGET_CHANGED', Path) self:UnregisterEvent('UNIT_MAXPOWER', Path) + if oUF.isRetail then + self:UnregisterEvent('UNIT_POWER_POINT_CHARGE', Path) + else + self:UnregisterEvent('PLAYER_TARGET_CHANGED', VisibilityPath) + end + local element = self.ClassPower for i = 1, #element do element[i]:Hide() end - self.ClassPower.isEnabled = false + element.__isEnabled = false Path(self, 'ClassPowerDisable', 'player', ClassPowerType) end - if(PlayerClass == 'ROGUE' or PlayerClass == 'DRUID') then + if(PlayerClass == 'MONK') then + ClassPowerID = SPELL_POWER_CHI + ClassPowerType = 'CHI' + RequireSpec = SPEC_MONK_WINDWALKER + elseif(PlayerClass == 'PALADIN') then + ClassPowerID = SPELL_POWER_HOLY_POWER + ClassPowerType = 'HOLY_POWER' + elseif(PlayerClass == 'WARLOCK') then + ClassPowerID = SPELL_POWER_SOUL_SHARDS + ClassPowerType = 'SOUL_SHARDS' + elseif(PlayerClass == 'ROGUE' or PlayerClass == 'DRUID') then ClassPowerID = SPELL_POWER_COMBO_POINTS ClassPowerType = 'COMBO_POINTS' if(PlayerClass == 'DRUID') then RequirePower = SPELL_POWER_ENERGY - RequireSpell = 768 -- Cat Form + RequireSpell = oUF.isRetail and 5221 or 768 end + elseif(PlayerClass == 'MAGE') then + ClassPowerID = SPELL_POWER_ARCANE_CHARGES + ClassPowerType = 'ARCANE_CHARGES' + RequireSpec = SPEC_MAGE_ARCANE end end @@ -252,6 +327,10 @@ local function Enable(self, unit) element.__max = #element element.ForceUpdate = ForceUpdate + if(oUF.isRetail or oUF.isWrath) and (RequireSpec or RequireSpell) then + self:RegisterEvent('PLAYER_TALENT_UPDATE', VisibilityPath, true) + end + if(RequirePower) then self:RegisterEvent('UNIT_DISPLAYPOWER', VisibilityPath) end @@ -262,7 +341,7 @@ local function Enable(self, unit) for i = 1, #element do local bar = element[i] if(bar:IsObjectType('StatusBar')) then - if(not bar:GetStatusBarTexture()) then + if(not (bar:GetStatusBarTexture() or bar:GetStatusBarAtlas())) then bar:SetStatusBarTexture([[Interface\TargetingFrame\UI-StatusBar]]) end @@ -278,9 +357,13 @@ local function Disable(self) if(self.ClassPower) then ClassPowerDisable(self) + if oUF.isRetail or oUF.isWrath then + self:UnregisterEvent('PLAYER_TALENT_UPDATE', VisibilityPath) + end + self:UnregisterEvent('UNIT_DISPLAYPOWER', VisibilityPath) self:UnregisterEvent('SPELLS_CHANGED', Visibility) end end -oUF:AddElement('ClassPower', VisibilityPath, Enable, Disable) \ No newline at end of file +oUF:AddElement('ClassPower', VisibilityPath, Enable, Disable) diff --git a/oUF/elements/combatindicator.lua b/oUF/elements/combatindicator.lua index 4717be0..ac80c0f 100644 --- a/oUF/elements/combatindicator.lua +++ b/oUF/elements/combatindicator.lua @@ -25,7 +25,8 @@ A default texture will be applied if the widget is a Texture and doesn't have a local _, ns = ... local oUF = ns.oUF -local function Update(self, event) +local function Update(self, event, unit) + if not unit or self.unit ~= unit then return end local element = self.CombatIndicator --[[ Callback: CombatIndicator:PreUpdate() @@ -37,7 +38,7 @@ local function Update(self, event) element:PreUpdate() end - local inCombat = UnitAffectingCombat('player') + local inCombat = UnitAffectingCombat(unit) if(inCombat) then element:Show() else @@ -71,10 +72,12 @@ end local function Enable(self, unit) local element = self.CombatIndicator - if(element and UnitIsUnit(unit, 'player')) then + if element then element.__owner = self element.ForceUpdate = ForceUpdate + self:RegisterEvent('UNIT_COMBAT', Path) + self:RegisterEvent('UNIT_FLAGS', Path) self:RegisterEvent('PLAYER_REGEN_DISABLED', Path, true) self:RegisterEvent('PLAYER_REGEN_ENABLED', Path, true) @@ -92,6 +95,8 @@ local function Disable(self) if(element) then element:Hide() + self:UnregisterEvent('UNIT_COMBAT', Path) + self:UnregisterEvent('UNIT_FLAGS', Path) self:UnregisterEvent('PLAYER_REGEN_DISABLED', Path) self:UnregisterEvent('PLAYER_REGEN_ENABLED', Path) end diff --git a/oUF/elements/health.lua b/oUF/elements/health.lua index 8ef1500..c0337f5 100644 --- a/oUF/elements/health.lua +++ b/oUF/elements/health.lua @@ -23,8 +23,10 @@ A default texture will be applied if the widget is a StatusBar and doesn't have 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) +.colorTapping - Use `self.colors.tapping` to color the bar if the unit isn't tapped by the player (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) @@ -45,37 +47,33 @@ The following options are listed by priority. The first check that returns true .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.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 + -- 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.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 = ... @@ -83,21 +81,25 @@ local oUF = ns.oUF local Private = oUF.Private local unitSelectionType = Private.unitSelectionType +local _, PlayerClass = UnitClass('player') 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 + if(element.colorDisconnected and not UnitIsConnected(unit)) then t = self.colors.disconnected elseif(element.colorTapping and not UnitPlayerControlled(unit) and UnitIsTapDenied(unit)) then t = self.colors.tapped - elseif(element.colorHappiness and unit == "pet" and GetPetHappiness()) then + elseif(element.colorHappiness and not oUF.isRetail and PlayerClass == "HUNTER" and UnitIsUnit(unit, "pet") and GetPetHappiness()) then t = self.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 + 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 or element.colorPetByUnitClass) and UnitPlayerControlled(unit) and not UnitIsPlayer(unit)) then + if element.colorPetByUnitClass then unit = unit == 'pet' and 'player' or gsub(unit, 'pet', '') end local _, class = UnitClass(unit) t = self.colors.class[class] elseif(element.colorSelection and unitSelectionType(unit, element.considerSelectionInCombatHostile)) then @@ -124,6 +126,15 @@ local function UpdateColor(self, event, unit) end end + --[[ Callback: Health:PostUpdateColor(unit, r, g, b) + Called after the element color has been updated. + + * self - the Health element + * unit - the unit for which the update has been triggered (string) + * 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(unit, r, g, b) end @@ -155,18 +166,16 @@ local function Update(self, event, 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(UnitIsConnected(unit)) then element:SetValue(cur) + else + element:SetValue(max) end element.cur = cur element.max = max - element.disconnected = disconnected --[[ Callback: Health:PostUpdate(unit, cur, max) Called after the element has been updated. @@ -182,6 +191,8 @@ local function Update(self, event, unit) end local function Path(self, event, ...) + if (self.isForced and event ~= 'ElvUI_UpdateAllElements') then return end -- ElvUI changed + --[[ Override: Health.Override(self, event, unit) Used to completely override the internal update function. @@ -198,62 +209,132 @@ local function ForceUpdate(element) Path(element.__owner, 'ForceUpdate', element.__owner.unit) end -local onUpdateElapsed, onUpdateWait = 0, 0.25 -local function onUpdateHealth(self, elapsed) - if onUpdateElapsed > onUpdateWait then - Path(self.__owner, 'OnUpdate', self.__owner.unit) +--[[ Health:SetColorDisconnected(state, isForced) +Used to toggle coloring if the unit is offline. - onUpdateElapsed = 0 - else - onUpdateElapsed = onUpdateElapsed + elapsed +* self - the Health element +* state - the desired state (boolean) +* isForced - forces the event update even if the state wasn't changed (boolean) +--]] +local function SetColorDisconnected(element, state, isForced) + if(element.colorDisconnected ~= state or isForced) then + element.colorDisconnected = state + if(state) then + element.__owner:RegisterEvent('UNIT_CONNECTION', ColorPath) + element.__owner:RegisterEvent('PARTY_MEMBER_ENABLE', ColorPath) + element.__owner:RegisterEvent('PARTY_MEMBER_DISABLE', ColorPath) + else + element.__owner:UnregisterEvent('UNIT_CONNECTION', ColorPath) + element.__owner:UnregisterEvent('PARTY_MEMBER_ENABLE', ColorPath) + element.__owner:UnregisterEvent('PARTY_MEMBER_DISABLE', ColorPath) + end end end -local function SetHealthUpdateSpeed(self, state) - if state < .1 then state = .1 end - onUpdateWait = state +--[[ Health:SetColorSelection(state, isForced) +Used to toggle coloring by the unit's selection. + +* self - the Health element +* state - the desired state (boolean) +* isForced - forces the event update even if the state wasn't changed (boolean) +--]] +local function SetColorSelection(element, state, isForced) + if(element.colorSelection ~= state or isForced) then + element.colorSelection = state + if(state) then + element.__owner:RegisterEvent('UNIT_FLAGS', ColorPath) + else + element.__owner:UnregisterEvent('UNIT_FLAGS', ColorPath) + end + end end -local function SetHealthUpdateMethod(self, state, force) - if self.effectiveHealth ~= state or force then - self.effectiveHealth = state +--[[ Health:SetColorTapping(state, isForced) +Used to toggle coloring if the unit isn't tapped by the player. - if state then - self.Health:SetScript('OnUpdate', onUpdateHealth) - self:UnregisterEvent('UNIT_HEALTH_FREQUENT', Path) - self:UnregisterEvent('UNIT_HEALTH', Path) - self:UnregisterEvent('UNIT_MAXHEALTH', Path) +* self - the Health element +* state - the desired state (boolean) +* isForced - forces the event update even if the state wasn't changed (boolean) +--]] +local function SetColorTapping(element, state, isForced) + if(element.colorTapping ~= state or isForced) then + element.colorTapping = state + if(state) then + element.__owner:RegisterEvent('UNIT_FACTION', ColorPath) else - self.Health:SetScript('OnUpdate', nil) - self:RegisterEvent('UNIT_HEALTH', Path) -- Needed for Pet Battles - self:RegisterEvent('UNIT_HEALTH_FREQUENT', Path) - self:RegisterEvent('UNIT_MAXHEALTH', Path) + element.__owner:UnregisterEvent('UNIT_FACTION', ColorPath) end end end -local function Enable(self, unit) +--[[ Health:SetColorThreat(state, isForced) +Used to toggle coloring by the unit's threat status. + +* self - the Health element +* state - the desired state (boolean) +* isForced - forces the event update even if the state wasn't changed (boolean) +--]] +local function SetColorThreat(element, state, isForced) + if(element.colorThreat ~= state or isForced) then + element.colorThreat = state + if(state) then + element.__owner:RegisterEvent('UNIT_THREAT_LIST_UPDATE', ColorPath) + else + element.__owner:UnregisterEvent('UNIT_THREAT_LIST_UPDATE', ColorPath) + end + end +end + +local function SetColorHappiness(element, state, isForced) + if(element.colorHappiness ~= state or isForced) then + element.colorHappiness = state + + if(state) then + element.__owner:RegisterEvent('UNIT_HAPPINESS', ColorPath) + else + element.__owner:UnregisterEvent('UNIT_HAPPINESS', ColorPath) + end + end +end + +local function Enable(self) local element = self.Health if(element) then element.__owner = self element.ForceUpdate = ForceUpdate + element.SetColorHappiness = SetColorHappiness + element.SetColorDisconnected = SetColorDisconnected + element.SetColorSelection = SetColorSelection + element.SetColorTapping = SetColorTapping + element.SetColorThreat = SetColorThreat + + oUF:RegisterEvent(self, 'UNIT_MAXHEALTH', Path) - self.SetHealthUpdateSpeed = SetHealthUpdateSpeed - self.SetHealthUpdateMethod = SetHealthUpdateMethod - SetHealthUpdateMethod(self, self.effectiveHealth, true) + if oUF.isRetail then + oUF:RegisterEvent(self, 'UNIT_HEALTH', Path) + else + oUF:RegisterEvent(self, 'UNIT_HEALTH_FREQUENT', Path) + end if(element.colorDisconnected) then - self:RegisterEvent('UNIT_CONNECTION', ColorPath) - self:RegisterEvent('PARTY_MEMBER_ENABLE', ColorPath) - self:RegisterEvent('PARTY_MEMBER_DISABLE', ColorPath) + oUF:RegisterEvent(self, 'UNIT_CONNECTION', ColorPath) + oUF:RegisterEvent(self, 'PARTY_MEMBER_ENABLE', ColorPath) + oUF:RegisterEvent(self, 'PARTY_MEMBER_DISABLE', ColorPath) + end + + if(element.colorSelection) then + oUF:RegisterEvent(self, 'UNIT_FLAGS', ColorPath) end if(element.colorTapping) then - self:RegisterEvent('UNIT_FACTION', ColorPath) + oUF:RegisterEvent(self, 'UNIT_FACTION', ColorPath) + end + + if(element.colorThreat) then + oUF:RegisterEvent(self, 'UNIT_THREAT_LIST_UPDATE', ColorPath) end - self:RegisterEvent('UNIT_HAPPINESS', ColorPath) - if(element:IsObjectType('StatusBar') and not element:GetStatusBarTexture()) then + if(element:IsObjectType('StatusBar') and not (element:GetStatusBarTexture() or element:GetStatusBarAtlas())) then element:SetStatusBarTexture([[Interface\TargetingFrame\UI-StatusBar]]) end @@ -268,17 +349,20 @@ local function Disable(self) if(element) then element:Hide() - element:SetScript('OnUpdate', nil) - self:UnregisterEvent('UNIT_HEALTH_FREQUENT', Path) - self:UnregisterEvent('UNIT_HEALTH', Path) - self:UnregisterEvent('UNIT_MAXHEALTH', Path) + if oUF.isRetail then + oUF:UnregisterEvent(self, 'UNIT_HEALTH', Path) + else + oUF:UnregisterEvent(self, 'UNIT_HEALTH_FREQUENT', Path) + end - self:UnregisterEvent('UNIT_CONNECTION', ColorPath) - self:UnregisterEvent('UNIT_FACTION', ColorPath) - self:UnregisterEvent('PARTY_MEMBER_ENABLE', ColorPath) - self:UnregisterEvent('PARTY_MEMBER_DISABLE', ColorPath) - self:UnregisterEvent('UNIT_HAPPINESS', ColorPath) + oUF:UnregisterEvent(self, 'UNIT_MAXHEALTH', Path) + oUF:UnregisterEvent(self, 'UNIT_CONNECTION', ColorPath) + oUF:UnregisterEvent(self, 'UNIT_FACTION', ColorPath) + oUF:UnregisterEvent(self, 'UNIT_FLAGS', ColorPath) + oUF:UnregisterEvent(self, 'PARTY_MEMBER_ENABLE', ColorPath) + oUF:UnregisterEvent(self, 'PARTY_MEMBER_DISABLE', ColorPath) + oUF:UnregisterEvent(self, 'UNIT_THREAT_LIST_UPDATE', ColorPath) end end -oUF:AddElement('Health', Path, Enable, Disable) \ No newline at end of file +oUF:AddElement('Health', Path, Enable, Disable) diff --git a/oUF/elements/healthprediction.lua b/oUF/elements/healthprediction.lua index 56f7f08..80742db 100644 --- a/oUF/elements/healthprediction.lua +++ b/oUF/elements/healthprediction.lua @@ -80,25 +80,8 @@ A default texture will be applied to the Texture widgets if they don't have a te local _, ns = ... local oUF = ns.oUF -local myGUID = UnitGUID('player') -local HealComm, ALL_PENDING_HEALS, ALL_OVERTIME_HEALS, HEAL_TICK_INTERVAL -if not oUF.isRetail then - HealComm = LibStub("LibHealComm-4.0") - - ALL_PENDING_HEALS = bit.bor(HealComm.DIRECT_HEALS, HealComm.BOMB_HEALS) - ALL_OVERTIME_HEALS = bit.bor(HealComm.CHANNEL_HEALS, HealComm.HOT_HEALS) - HEAL_TICK_INTERVAL = 3 -end - -local function GetHealAmount(targetGUID, currentTime, casterGUID) - local nextTickTime = currentTime + HEAL_TICK_INTERVAL - - local pendingHeal = HealComm:GetHealAmount(targetGUID, ALL_PENDING_HEALS, nil, casterGUID) or 0 - local overtimeHeal = HealComm:GetHealAmount(targetGUID, ALL_OVERTIME_HEALS, nextTickTime, casterGUID) or 0 - - return (pendingHeal + overtimeHeal) * HealComm:GetHealModifier(casterGUID) -end +local HealComm = LibStub('LibHealComm-4.0', true) local function Update(self, event, unit) if(self.unit ~= unit) then return end @@ -115,13 +98,12 @@ local function Update(self, event, unit) element:PreUpdate(unit) end - local guid = UnitGUID(unit) - local currentTime = GetTime() - local isSmoothedEvent = event == "UNIT_MAXHEALTH" or event == "UNIT_HEALTH_FREQUENT" or event == "UNIT_HEALTH" - local myIncomingHeal = not oUF.isRetail and GetHealAmount(guid, currentTime, myGUID) or UnitGetIncomingHeals(unit, 'player') or 0 - local allIncomingHeal = not oUF.isRetail and GetHealAmount(guid, currentTime, nil) or UnitGetIncomingHeals(unit) or 0 - local absorb = oUF.Retail and UnitGetTotalAbsorbs(unit) or 0 - local healAbsorb = oUF.Retail and UnitGetTotalHealAbsorbs(unit) or 0 + local GUID = UnitGUID(unit) + local myIncomingHeal = UnitGetIncomingHeals(unit, 'player') or 0 + local allIncomingHeal = UnitGetIncomingHeals(unit) or 0 + local overTimeHeals = not oUF.isRetail and HealComm and ((HealComm:GetHealAmount(GUID, HealComm.OVERTIME_AND_BOMB_HEALS) or 0) * (HealComm:GetHealModifier(GUID) or 1)) or 0 + local absorb = oUF.isRetail and UnitGetTotalAbsorbs(unit) or 0 + local healAbsorb = oUF.isRetail and UnitGetTotalHealAbsorbs(unit) or 0 local health, maxHealth = UnitHealth(unit), UnitHealthMax(unit) local otherIncomingHeal = 0 local hasOverHealAbsorb = false @@ -133,7 +115,6 @@ local function Update(self, event, unit) if(health < healAbsorb) then hasOverHealAbsorb = true - healAbsorb = health end else allIncomingHeal = allIncomingHeal - healAbsorb @@ -146,45 +127,25 @@ local function Update(self, event, unit) if(allIncomingHeal < myIncomingHeal) then myIncomingHeal = allIncomingHeal else - otherIncomingHeal = allIncomingHeal - myIncomingHeal + otherIncomingHeal = allIncomingHeal - myIncomingHeal + overTimeHeals end end local hasOverAbsorb = false - if(health + allIncomingHeal + absorb >= maxHealth) then - if(absorb > 0) then - hasOverAbsorb = true - end - - absorb = math.max(0, maxHealth - health - allIncomingHeal) + if(health + allIncomingHeal + absorb >= maxHealth) and (absorb > 0) then + hasOverAbsorb = true end if(element.myBar) then - if element.smoothing then - element.myBar:SetMinMaxSmoothedValue(0, maxHealth) - element.myBar:SetSmoothedValue(myIncomingHeal) - end - - if not element.smoothing or not isSmoothedEvent then - element.myBar:SetMinMaxValues(0, maxHealth) - element.myBar:SetValue(myIncomingHeal) - end - - element.myBar:Show() + element.myBar:SetMinMaxValues(0, maxHealth) + element.myBar:SetValue(myIncomingHeal) + element.myBar:Show() end if(element.otherBar) then - if element.smoothing then - element.otherBar:SetMinMaxSmoothedValue(0, maxHealth) - element.otherBar:SetSmoothedValue(otherIncomingHeal) - end - - if not element.smoothing or not isSmoothedEvent then - element.otherBar:SetMinMaxValues(0, maxHealth) - element.otherBar:SetValue(otherIncomingHeal) - end - - element.otherBar:Show() + element.otherBar:SetMinMaxValues(0, maxHealth) + element.otherBar:SetValue(otherIncomingHeal) + element.otherBar:Show() end if(element.absorbBar) then @@ -228,11 +189,11 @@ local function Update(self, event, unit) * hasOverHealAbsorb - indicates if the amount of heal absorb is higher than the unit's current health (boolean) --]] if(element.PostUpdate) then - return element:PostUpdate(unit, myIncomingHeal, otherIncomingHeal, absorb, healAbsorb, hasOverAbsorb, hasOverHealAbsorb) + return element:PostUpdate(unit, myIncomingHeal, otherIncomingHeal, absorb, healAbsorb, hasOverAbsorb, hasOverHealAbsorb, health, maxHealth) end end -local function Path(self, event, ...) +local function Path(self, ...) --[[ Override: HealthPrediction.Override(self, event, unit) Used to completely override the internal update function. @@ -240,75 +201,68 @@ local function Path(self, event, ...) * event - the event triggering the update (string) * unit - the unit accompanying the event --]] - - if not oUF.Retail and self:IsVisible() then - for i = 1, select('#', ...) do - if self.unit and UnitGUID(self.unit) == (UnitGUID(select(i, ...)) or select(i, ...)) then - return (self.HealthPrediction.Override or Update) (self, event, self.unit) - end - end - else - return (self.HealthPrediction.Override or Update) (self, event, ...) - end + return (self.HealthPrediction.Override or Update) (self, ...) end local function ForceUpdate(element) return Path(element.__owner, 'ForceUpdate', element.__owner.unit) end +local function HealComm_Check(self, element, ...) + if element and self:IsVisible() then + for i = 1, select('#', ...) do + if self.unit and UnitGUID(self.unit) == select(i, ...) then + Path(self, nil, self.unit) + end + end + end +end + +local function HealComm_Create(self, element) + local update = function(event, casterGUID, spellID, healType, _, ...) HealComm_Check(self, element, ...) end + local modified = function(event, guid) HealComm_Check(self, element, guid) end + return update, modified +end + local function Enable(self) local element = self.HealthPrediction if(element) then element.__owner = self element.ForceUpdate = ForceUpdate + oUF:RegisterEvent(self, 'UNIT_MAXHEALTH', Path) + oUF:RegisterEvent(self, 'UNIT_HEAL_PREDICTION', Path) + if oUF.isRetail then - self:RegisterEvent('UNIT_HEALTH', Path) - self:RegisterEvent('UNIT_HEAL_PREDICTION', Path) - self:RegisterEvent('UNIT_ABSORB_AMOUNT_CHANGED', Path) - self:RegisterEvent('UNIT_HEAL_ABSORB_AMOUNT_CHANGED', Path) + oUF:RegisterEvent(self, 'UNIT_HEALTH', Path) + oUF:RegisterEvent(self, 'UNIT_ABSORB_AMOUNT_CHANGED', Path) + oUF:RegisterEvent(self, 'UNIT_HEAL_ABSORB_AMOUNT_CHANGED', Path) else - self:RegisterEvent('UNIT_HEALTH_FREQUENT', Path) - - local function UpdateHeal(event, casterGUID, spellID, healType, _, ...) - Path(self, event, ...) + if not self.HealComm_Update then + self.HealComm_Update, self.HealComm_Modified = HealComm_Create(self, element) end - local function UpdateModifier(event, guid) - Path(self, event, guid) - end + HealComm.RegisterCallback(element, 'HealComm_HealStarted', self.HealComm_Update) + HealComm.RegisterCallback(element, 'HealComm_HealUpdated', self.HealComm_Update) + HealComm.RegisterCallback(element, 'HealComm_HealDelayed', self.HealComm_Update) + HealComm.RegisterCallback(element, 'HealComm_HealStopped', self.HealComm_Update) + HealComm.RegisterCallback(element, 'HealComm_ModifierChanged', self.HealComm_Modified) + HealComm.RegisterCallback(element, 'HealComm_GUIDDisappeared', self.HealComm_Modified) - HealComm.RegisterCallback(self, "HealComm_HealStarted", UpdateHeal) - HealComm.RegisterCallback(self, "HealComm_HealUpdated", UpdateHeal) - HealComm.RegisterCallback(self, "HealComm_HealDelayed", UpdateHeal) - HealComm.RegisterCallback(self, "HealComm_HealStopped", UpdateHeal) - HealComm.RegisterCallback(self, "HealComm_ModifierChanged", UpdateModifier) - HealComm.RegisterCallback(self, "HealComm_GUIDDisappeared", UpdateModifier) + oUF:RegisterEvent(self, 'UNIT_HEALTH_FREQUENT', Path) end - self:RegisterEvent('UNIT_MAXHEALTH', Path) - - if(not element.maxOverflow) then + if (not element.maxOverflow) then element.maxOverflow = 1.05 end if(element.myBar) then - if(element.smoothing) then - element.myBar.SetSmoothedValue = SmoothStatusBarMixin.SetSmoothedValue - element.myBar.SetMinMaxSmoothedValue = SmoothStatusBarMixin.SetMinMaxSmoothedValue - end - if(element.myBar:IsObjectType('StatusBar') and not element.myBar:GetStatusBarTexture()) then element.myBar:SetStatusBarTexture([[Interface\TargetingFrame\UI-StatusBar]]) end end if(element.otherBar) then - if(element.smoothing) then - element.otherBar.SetSmoothedValue = SmoothStatusBarMixin.SetSmoothedValue - element.otherBar.SetMinMaxSmoothedValue = SmoothStatusBarMixin.SetMinMaxSmoothedValue - end - if(element.otherBar:IsObjectType('StatusBar') and not element.otherBar:GetStatusBarTexture()) then element.otherBar:SetStatusBarTexture([[Interface\TargetingFrame\UI-StatusBar]]) end @@ -371,11 +325,23 @@ local function Disable(self) element.overHealAbsorb:Hide() end - self:UnregisterEvent('UNIT_HEALTH', Path) - self:UnregisterEvent('UNIT_MAXHEALTH', Path) - self:UnregisterEvent('UNIT_HEAL_PREDICTION', Path) - self:UnregisterEvent('UNIT_ABSORB_AMOUNT_CHANGED', Path) - self:UnregisterEvent('UNIT_HEAL_ABSORB_AMOUNT_CHANGED', Path) + oUF:UnregisterEvent(self, 'UNIT_MAXHEALTH', Path) + oUF:UnregisterEvent(self, 'UNIT_HEAL_PREDICTION', Path) + + if oUF.isRetail then + oUF:UnregisterEvent(self, 'UNIT_HEALTH', Path) + oUF:UnregisterEvent(self, 'UNIT_ABSORB_AMOUNT_CHANGED', Path) + oUF:UnregisterEvent(self, 'UNIT_HEAL_ABSORB_AMOUNT_CHANGED', Path) + else + HealComm.UnregisterCallback(element, 'HealComm_HealStarted') + HealComm.UnregisterCallback(element, 'HealComm_HealUpdated') + HealComm.UnregisterCallback(element, 'HealComm_HealDelayed') + HealComm.UnregisterCallback(element, 'HealComm_HealStopped') + HealComm.UnregisterCallback(element, 'HealComm_ModifierChanged') + HealComm.UnregisterCallback(element, 'HealComm_GUIDDisappeared') + + oUF:UnregisterEvent(self, 'UNIT_HEALTH_FREQUENT', Path) + end end end diff --git a/oUF/elements/leaderindicator.lua b/oUF/elements/leaderindicator.lua index 70dd083..223ea0e 100644 --- a/oUF/elements/leaderindicator.lua +++ b/oUF/elements/leaderindicator.lua @@ -38,7 +38,15 @@ local function Update(self, event) element:PreUpdate() end - local isLeader = (UnitInParty(unit) or UnitInRaid(unit)) and UnitIsGroupLeader(unit) + -- ElvUI changed block + local isLeader + if IsInInstance() then + isLeader = UnitIsGroupLeader(unit) + else + isLeader = UnitLeadsAnyGroup(unit) + end + -- end block + if(isLeader) then element:Show() else diff --git a/oUF/elements/partyindicator.lua b/oUF/elements/partyindicator.lua new file mode 100644 index 0000000..3a2b153 --- /dev/null +++ b/oUF/elements/partyindicator.lua @@ -0,0 +1,90 @@ +--[[ +# Element: Party Indicator (by Caedis) + Toggles the visibility of an indicator based on if the player was in a group before joining the instance. + +## Widget + PartyIndicator - Player only widget. +]] + +local _, ns = ... +local oUF = ns.oUF + +local function Update(self, event) + local element = self.PartyIndicator + + if(element.PreUpdate) then + element:PreUpdate() + end + + local forced = not event or event == 'ElvUI_UpdateAllElements' + if forced or event == 'GROUP_ROSTER_UPDATE' then + if IsInGroup(LE_PARTY_CATEGORY_HOME) and IsInGroup(LE_PARTY_CATEGORY_INSTANCE) then + element:Show() + else + element:Hide() + end + end + + if forced or event == 'UPDATE_CHAT_COLOR' then + local private = ChatTypeInfo.PARTY + if private and element.HomeIcon then + element.HomeIcon:SetVertexColor(private.r, private.g, private.b, 1) + end + + local public = ChatTypeInfo.INSTANCE_CHAT + if public and element.InstanceIcon then + element.InstanceIcon:SetVertexColor(public.r, public.g, public.b, 1) + end + end + + if(element.PostUpdate) then + return element:PostUpdate() + end +end + +local function Path(self, ...) + --[[ Override: PartyIndicator.Override(self, event) + Used to completely override the internal update function. + + * self - the parent object + * event - the event triggering the update (string) + --]] + return (self.PartyIndicator.Override or Update) (self, ...) +end + +local function ForceUpdate(element) + return Path(element.__owner, 'ForceUpdate') +end + +local function Enable(self) + local element = self.PartyIndicator + if element then + element.__owner = self + element.ForceUpdate = ForceUpdate + + self:RegisterEvent('UPDATE_CHAT_COLOR', Path, true) + self:RegisterEvent('GROUP_ROSTER_UPDATE', Path, true) + + if(element.HomeIcon and element.HomeIcon:IsObjectType('Texture') and not element.HomeIcon:GetTexture()) then + element.HomeIcon:SetTexture([[Interface\FriendsFrame\UI-Toast-FriendOnlineIcon]]) + end + + if(element.InstanceIcon and element.InstanceIcon:IsObjectType('Texture') and not element.InstanceIcon:GetTexture()) then + element.InstanceIcon:SetTexture([[Interface\FriendsFrame\UI-Toast-FriendOnlineIcon]]) + end + + return true + end +end + +local function Disable(self) + local element = self.PartyIndicator + if(element) then + element:Hide() + + self:UnregisterEvent('UPDATE_CHAT_COLOR', Path) + self:UnregisterEvent('GROUP_ROSTER_UPDATE', Path) + end +end + +oUF:AddElement('PartyIndicator', Path, Enable, Disable) diff --git a/oUF/elements/phaseindicator.lua b/oUF/elements/phaseindicator.lua index 24ac51d..18a62d5 100644 --- a/oUF/elements/phaseindicator.lua +++ b/oUF/elements/phaseindicator.lua @@ -7,16 +7,27 @@ Toggles the visibility of an indicator based on the unit's phasing relative to t PhaseIndicator - Any UI widget. +## Sub-Widgets + +Icon - A `Texture` to represent the phased status. + ## Notes A default texture will be applied if the widget is a Texture and doesn't have a texture or a color set. +OnEnter and OnLeave script handlers will be set to display a Tooltip if the widget is mouse enabled and does not have +OnEnter and/or OnLeave handlers. ## Examples -- Position and size - local PhaseIndicator = self:CreateTexture(nil, 'OVERLAY') + local PhaseIndicator = CreateFrame('Frame', nil, self) PhaseIndicator:SetSize(16, 16) PhaseIndicator:SetPoint('TOPLEFT', self) + PhaseIndicator:EnableMouse(true) + + local Icon = PhaseIndicator:CreateTexture(nil, 'OVERLAY') + Icon:SetAllPoints() + PhaseIndicator.Icon = Icon -- Register it with oUF self.PhaseIndicator = PhaseIndicator @@ -25,6 +36,38 @@ A default texture will be applied if the widget is a Texture and doesn't have a local _, ns = ... local oUF = ns.oUF +local GameTooltip = GameTooltip + +--[[ Override: PhaseIndicator:UpdateTooltip() +Used to populate the tooltip when the widget is hovered. + +* self - the PhaseIndicator widget +--]] +local function UpdateTooltip(element) + if GameTooltip:IsForbidden() then return end + + local text = PartyUtil.GetPhasedReasonString(element.reason, element.__owner.unit) + if(text) then + GameTooltip:SetText(text, nil, nil, nil, nil, true) + GameTooltip:Show() + end +end + +local function onEnter(element) + if GameTooltip:IsForbidden() or not element:IsVisible() then return end + + if(element.reason) then + GameTooltip:SetOwner(element, 'ANCHOR_BOTTOMRIGHT') + element:UpdateTooltip() + end +end + +local function onLeave() + if GameTooltip:IsForbidden() then return end + + GameTooltip:Hide() +end + local function Update(self, event, unit) if(self.unit ~= unit) then return end @@ -39,21 +82,26 @@ local function Update(self, event, unit) element:PreUpdate() end - local isInSamePhase = UnitInPhase(unit) - if(not isInSamePhase and UnitIsPlayer(unit) and UnitIsConnected(unit)) then + -- BUG: UnitPhaseReason returns wrong data for friendly NPCs in phased scenarios like WM or Chromie Time + -- https://github.com/Stanzilla/WoWUIBugs/issues/49 + local phaseReason = UnitIsPlayer(unit) and UnitIsConnected(unit) and UnitPhaseReason(unit) or nil + if(phaseReason) then element:Show() else element:Hide() end - --[[ Callback: PhaseIndicator:PostUpdate(isInSamePhase) + element.reason = phaseReason + + --[[ Callback: PhaseIndicator:PostUpdate(isInSamePhase, phaseReason) Called after the element has been updated. * self - the PhaseIndicator element * isInSamePhase - indicates whether the unit is in the same phase as the player (boolean) + * phaseReason - the reason why the unit is in a different phase (number?) --]] if(element.PostUpdate) then - return element:PostUpdate(isInSamePhase) + return element:PostUpdate(not phaseReason, phaseReason) end end @@ -80,8 +128,21 @@ local function Enable(self) self:RegisterEvent('UNIT_PHASE', Path) - if(element:IsObjectType('Texture') and not element:GetTexture()) then - element:SetTexture([[Interface\TargetingFrame\UI-PhasingIcon]]) + local icon = (element.Icon or element) + if(icon:IsObjectType('Texture') and not icon:GetTexture()) then + icon:SetTexture([[Interface\TargetingFrame\UI-PhasingIcon]]) + end + + if(element.IsMouseEnabled and element:IsMouseEnabled()) then + if(not element:GetScript('OnEnter')) then + element:SetScript('OnEnter', onEnter) + end + + if(not element:GetScript('OnLeave')) then + element:SetScript('OnLeave', onLeave) + end + + element.UpdateTooltip = element.UpdateTooltip or UpdateTooltip end return true @@ -97,4 +158,4 @@ local function Disable(self) end end -oUF:AddElement('PhaseIndicator', Path, Enable, Disable) \ No newline at end of file +oUF:AddElement('PhaseIndicator', Path, Enable, Disable) diff --git a/oUF/elements/portrait.lua b/oUF/elements/portrait.lua index d68a637..81df9bf 100644 --- a/oUF/elements/portrait.lua +++ b/oUF/elements/portrait.lua @@ -12,6 +12,10 @@ Portrait - A `PlayerModel` or a `Texture` used to represent the unit's portrait. A question mark model will be used if the widget is a PlayerModel and the client doesn't have the model information for the unit. +## Options + +.showClass - Displays the unit's class in the portrait (boolean) + ## Examples -- 3D Portrait @@ -35,6 +39,15 @@ the unit. local _, ns = ... local oUF = ns.oUF +-- ElvUI block +local UnitIsUnit = UnitIsUnit +local UnitGUID = UnitGUID +local UnitIsConnected = UnitIsConnected +local UnitIsVisible = UnitIsVisible +local UnitClassBase = UnitClassBase +local SetPortraitTexture = SetPortraitTexture +-- end block + local function Update(self, event, unit) if(not unit or not UnitIsUnit(self.unit, unit)) then return end @@ -50,9 +63,14 @@ local function Update(self, event, unit) local guid = UnitGUID(unit) local isAvailable = UnitIsConnected(unit) and UnitIsVisible(unit) - if(event ~= 'OnUpdate' or element.guid ~= guid or element.state ~= isAvailable) then - if(element:IsObjectType('PlayerModel')) then - if(not isAvailable) then + local hasStateChanged = event ~= 'OnUpdate' or element.guid ~= guid or element.state ~= isAvailable + if hasStateChanged then + element.playerModel = element:IsObjectType('PlayerModel') + element.state = isAvailable + element.guid = guid + + if element.playerModel then + if not isAvailable then element:SetCamDistanceScale(0.25) element:SetPortraitZoom(0) element:SetPosition(0, 0, 0.25) @@ -65,22 +83,25 @@ local function Update(self, event, unit) element:ClearModel() element:SetUnit(unit) end - else - SetPortraitTexture(element, unit) + elseif not element.customTexture then -- ElvUI changed + local class = element.showClass and UnitClassBase(unit) + if class then + element:SetAtlas('classicon-' .. class) + else + SetPortraitTexture(element, unit) + end end - - element.guid = guid - element.state = isAvailable end --[[ Callback: Portrait:PostUpdate(unit) Called after the element has been updated. - * self - the Portrait element - * unit - the unit for which the update has been triggered (string) + * self - the Portrait element + * unit - the unit for which the update has been triggered (string) + * hasStateChanged - indicates whether the state has changed since the last update (boolean) --]] if(element.PostUpdate) then - return element:PostUpdate(unit) + return element:PostUpdate(unit, hasStateChanged) end end diff --git a/oUF/elements/power.lua b/oUF/elements/power.lua index 873618b..4f2fa81 100644 --- a/oUF/elements/power.lua +++ b/oUF/elements/power.lua @@ -22,6 +22,8 @@ A default texture will be applied if the widget is a StatusBar and doesn't have .displayAltPower - Use this to let the widget display alternative power, if the unit has one. By default, it does so only for raid and party units. If none, the display will fall back to the primary power (boolean) +.useAtlas - Use this to let the widget use an atlas for its texture if an atlas is present in + `self.colors.power` for the appropriate power type (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) @@ -108,9 +110,9 @@ type and zero for the minimum value. --]] local function GetDisplayPower(element) local unit = element.__owner.unit - local _, min, _, _, _, _, showOnRaid = UnitAlternatePowerInfo(unit) - if(showOnRaid) then - return ALTERNATE_POWER_INDEX, min + local barInfo = GetUnitPowerBarInfo(unit) + if(barInfo and barInfo.showOnRaid and (UnitInParty(unit) or UnitInRaid(unit))) then + return ALTERNATE_POWER_INDEX, barInfo.minPower end end @@ -120,14 +122,11 @@ local function UpdateColor(self, event, unit) local pType, pToken, altR, altG, altB = UnitPowerType(unit) - local r, g, b, t - local happiness = GetPetHappiness() + local r, g, b, t, atlas if(element.colorDisconnected and not UnitIsConnected(unit)) then t = self.colors.disconnected elseif(element.colorTapping and not UnitPlayerControlled(unit) and UnitIsTapDenied(unit)) then t = self.colors.tapped - elseif(element.colorHappiness and unit == "pet" and happiness) then - t = self.colors.happiness[happiness] elseif(element.colorThreat and not UnitPlayerControlled(unit) and UnitThreatSituation('player', unit)) then t = self.colors.threat[UnitThreatSituation('player', unit)] elseif(element.colorPower) then @@ -149,6 +148,10 @@ local function UpdateColor(self, event, unit) else t = self.colors.power[ALTERNATE_POWER_INDEX] end + + if(element.useAtlas and t and t.atlas) then + atlas = t.atlas + end elseif(element.colorClass and UnitIsPlayer(unit)) or (element.colorClassNPC and not UnitIsPlayer(unit)) or (element.colorClassPet and UnitPlayerControlled(unit) and not UnitIsPlayer(unit)) then @@ -167,7 +170,10 @@ local function UpdateColor(self, event, unit) r, g, b = t[1], t[2], t[3] end - if(b) then + if(atlas) then + element:SetStatusBarAtlas(atlas) + element:SetStatusBarColor(1, 1, 1) + elseif(b) then element:SetStatusBarColor(r, g, b) local bg = element.bg @@ -180,12 +186,13 @@ local function UpdateColor(self, event, unit) --[[ Callback: Power:PostUpdateColor(unit, r, g, b) Called after the element color has been updated. - * self - the Power element - * unit - the unit for which the update has been triggered (string) - * 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] + local bg = element.bg + if(bg and b) then + local mu = bg.multiplier or 1 + bg:SetVertexColor(r * mu, g * mu, b * mu) + end --]] + if(element.PostUpdateColor) then element:PostUpdateColor(unit, r, g, b) end @@ -217,12 +224,14 @@ local function Update(self, event, unit) end local displayType, min - if(element.displayAltPower) then + if(oUF.isRetail and element.displayAltPower) then displayType, min = element:GetDisplayPower() end local cur, max = UnitPower(unit, displayType), UnitPowerMax(unit, displayType) - element:SetMinMaxValues(min or 0, max) + if not min then min = 0 end + + element:SetMinMaxValues(min, max) if(UnitIsConnected(unit)) then element:SetValue(cur) @@ -249,7 +258,9 @@ local function Update(self, event, unit) end end -local function Path(self, ...) +local function Path(self, event, ...) + if (self.isForced and event ~= 'ElvUI_UpdateAllElements') then return end -- ElvUI changed + --[[ Override: Power.Override(self, event, unit, ...) Used to completely override the internal update function. @@ -258,9 +269,9 @@ local function Path(self, ...) * unit - the unit accompanying the event (string) * ... - the arguments accompanying the event --]] - (self.Power.Override or Update) (self, ...); + (self.Power.Override or Update) (self, event, ...); - ColorPath(self, ...) + ColorPath(self, event, ...) end local function ForceUpdate(element) @@ -370,39 +381,39 @@ local function Enable(self) element.SetColorThreat = SetColorThreat element.SetFrequentUpdates = SetFrequentUpdates + oUF:RegisterEvent(self, 'UNIT_MAXPOWER', Path) + + if(element.frequentUpdates) then + oUF:RegisterEvent(self, 'UNIT_POWER_FREQUENT', Path) + else + oUF:RegisterEvent(self, 'UNIT_POWER_UPDATE', Path) + end + if(element.colorDisconnected) then - self:RegisterEvent('UNIT_CONNECTION', ColorPath) + oUF:RegisterEvent(self, 'UNIT_CONNECTION', ColorPath) end if(element.colorSelection) then - self:RegisterEvent('UNIT_FLAGS', ColorPath) + oUF:RegisterEvent(self, 'UNIT_FLAGS', ColorPath) end if(element.colorTapping) then - self:RegisterEvent('UNIT_FACTION', ColorPath) + oUF:RegisterEvent(self, 'UNIT_FACTION', ColorPath) end if(element.colorThreat) then - self:RegisterEvent('UNIT_THREAT_LIST_UPDATE', ColorPath) - end - - if(element.frequentUpdates) then - self:RegisterEvent('UNIT_POWER_FREQUENT', Path) - else - self:RegisterEvent('UNIT_POWER_UPDATE', Path) + oUF:RegisterEvent(self, 'UNIT_THREAT_LIST_UPDATE', ColorPath) end - self:RegisterEvent('UNIT_DISPLAYPOWER', Path) - self:RegisterEvent('UNIT_MAXPOWER', Path) - self:RegisterEvent('UNIT_POWER_BAR_HIDE', Path) - self:RegisterEvent('UNIT_POWER_BAR_SHOW', Path) - self:RegisterEvent('UNIT_HAPPINESS', Path) + oUF:RegisterEvent(self, 'UNIT_DISPLAYPOWER', Path) + oUF:RegisterEvent(self, 'UNIT_POWER_BAR_HIDE', Path) + oUF:RegisterEvent(self, 'UNIT_POWER_BAR_SHOW', Path) if(element:IsObjectType('StatusBar') and not (element:GetStatusBarTexture() or element:GetStatusBarAtlas())) then element:SetStatusBarTexture([[Interface\TargetingFrame\UI-StatusBar]]) end - if(not element.GetDisplayPower) then + if(oUF.isRetail and not element.GetDisplayPower) then element.GetDisplayPower = GetDisplayPower end @@ -417,18 +428,17 @@ local function Disable(self) if(element) then element:Hide() - self:UnregisterEvent('UNIT_DISPLAYPOWER', Path) - self:UnregisterEvent('UNIT_MAXPOWER', Path) - self:UnregisterEvent('UNIT_POWER_BAR_HIDE', Path) - self:UnregisterEvent('UNIT_POWER_BAR_SHOW', Path) - self:UnregisterEvent('UNIT_POWER_FREQUENT', Path) - self:UnregisterEvent('UNIT_POWER_UPDATE', Path) - self:UnregisterEvent('UNIT_HAPPINESS', Path) - self:UnregisterEvent('UNIT_CONNECTION', ColorPath) - self:UnregisterEvent('UNIT_FACTION', ColorPath) - self:UnregisterEvent('UNIT_FLAGS', ColorPath) - self:UnregisterEvent('UNIT_THREAT_LIST_UPDATE', ColorPath) + oUF:UnregisterEvent(self, 'UNIT_DISPLAYPOWER', Path) + oUF:UnregisterEvent(self, 'UNIT_MAXPOWER', Path) + oUF:UnregisterEvent(self, 'UNIT_POWER_BAR_HIDE', Path) + oUF:UnregisterEvent(self, 'UNIT_POWER_BAR_SHOW', Path) + oUF:UnregisterEvent(self, 'UNIT_POWER_FREQUENT', Path) + oUF:UnregisterEvent(self, 'UNIT_POWER_UPDATE', Path) + oUF:UnregisterEvent(self, 'UNIT_CONNECTION', ColorPath) + oUF:UnregisterEvent(self, 'UNIT_FACTION', ColorPath) + oUF:UnregisterEvent(self, 'UNIT_FLAGS', ColorPath) + oUF:UnregisterEvent(self, 'UNIT_THREAT_LIST_UPDATE', ColorPath) end end -oUF:AddElement('Power', Path, Enable, Disable) \ No newline at end of file +oUF:AddElement('Power', Path, Enable, Disable) diff --git a/oUF/elements/powerprediction.lua b/oUF/elements/powerprediction.lua index be28e42..7dc3f27 100644 --- a/oUF/elements/powerprediction.lua +++ b/oUF/elements/powerprediction.lua @@ -44,8 +44,8 @@ local _, ns = ... local oUF = ns.oUF -- sourced from FrameXML/AlternatePowerBar.lua -local ADDITIONAL_POWER_BAR_INDEX = ADDITIONAL_POWER_BAR_INDEX or 0 -local ALT_MANA_BAR_PAIR_DISPLAY_INFO = ALT_MANA_BAR_PAIR_DISPLAY_INFO +local ADDITIONAL_POWER_BAR_INDEX = _G.ADDITIONAL_POWER_BAR_INDEX or 0 +local ALT_MANA_BAR_PAIR_DISPLAY_INFO = _G.ALT_MANA_BAR_PAIR_DISPLAY_INFO local _, playerClass = UnitClass('player') @@ -64,26 +64,31 @@ local function Update(self, event, unit) element:PreUpdate(unit) end - local _, _, _, startTime, endTime, _, _, notInterruptible, spellID = UnitCastingInfo(unit) - local mainPowerType = UnitPowerType(unit) - local hasAltManaBar = oUF.Retail and ALT_MANA_BAR_PAIR_DISPLAY_INFO[playerClass] and ALT_MANA_BAR_PAIR_DISPLAY_INFO[playerClass][mainPowerType] local mainCost, altCost = 0, 0 + local mainType = UnitPowerType(unit) + local mainMax = UnitPowerMax(unit, mainType) + local isPlayer = UnitIsUnit('player', unit) + local altManaInfo = isPlayer and oUF.isRetail and ALT_MANA_BAR_PAIR_DISPLAY_INFO[playerClass] + local hasAltManaBar = altManaInfo and altManaInfo[mainType] + local _, _, _, startTime, endTime, _, _, _, spellID = UnitCastingInfo(unit) if(event == 'UNIT_SPELLCAST_START' and startTime ~= endTime) then local costTable = GetSpellPowerCost(spellID) - - -- hasRequiredAura is always false if there's only 1 subtable - local checkRequiredAura = #costTable > 1 - - for _, costInfo in next, costTable do - if(not checkRequiredAura or costInfo.hasRequiredAura) then - if(costInfo.type == mainPowerType) then - mainCost = costInfo.cost + if not costTable then + element.mainCost = mainCost + element.altCost = altCost + else + local checkRequiredAura = isPlayer and #costTable > 1 + for _, costInfo in next, costTable do + local cost, ctype, cperc = costInfo.cost, costInfo.type, costInfo.costPercent + local checkSpec = not checkRequiredAura or costInfo.hasRequiredAura + if checkSpec and ctype == mainType then + mainCost = ((isPlayer or cost < mainMax) and cost) or (mainMax * cperc) / 100 element.mainCost = mainCost break - elseif(costInfo.type == ADDITIONAL_POWER_BAR_INDEX) then - altCost = costInfo.cost + elseif hasAltManaBar and checkSpec and ctype == ADDITIONAL_POWER_BAR_INDEX then + altCost = cost element.altCost = altCost break @@ -91,8 +96,7 @@ local function Update(self, event, unit) end end elseif(spellID) then - -- if we try to cast a spell while casting another one we need to avoid - -- resetting the element + -- if we try to cast a spell while casting another one we need to avoid resetting the element mainCost = element.mainCost or 0 altCost = element.altCost or 0 else @@ -101,7 +105,7 @@ local function Update(self, event, unit) end if(element.mainBar) then - element.mainBar:SetMinMaxValues(0, UnitPowerMax(unit, mainPowerType)) + element.mainBar:SetMinMaxValues(0, mainMax) element.mainBar:SetValue(mainCost) element.mainBar:Show() end @@ -142,17 +146,17 @@ local function ForceUpdate(element) return Path(element.__owner, 'ForceUpdate', element.__owner.unit) end -local function Enable(self, unit) +local function Enable(self) local element = self.PowerPrediction - if(element and UnitIsUnit(unit, 'player')) then + if(element) then element.__owner = self element.ForceUpdate = ForceUpdate - self:RegisterEvent('UNIT_SPELLCAST_START', Path) - self:RegisterEvent('UNIT_SPELLCAST_STOP', Path) - self:RegisterEvent('UNIT_SPELLCAST_FAILED', Path) - self:RegisterEvent('UNIT_SPELLCAST_SUCCEEDED', Path) - self:RegisterEvent('UNIT_DISPLAYPOWER', Path) + oUF:RegisterEvent(self, 'UNIT_SPELLCAST_START', Path) + oUF:RegisterEvent(self, 'UNIT_SPELLCAST_STOP', Path) + oUF:RegisterEvent(self, 'UNIT_SPELLCAST_FAILED', Path) + oUF:RegisterEvent(self, 'UNIT_SPELLCAST_SUCCEEDED', Path) + oUF:RegisterEvent(self, 'UNIT_DISPLAYPOWER', Path) if(element.mainBar) then if(element.mainBar:IsObjectType('StatusBar') @@ -183,11 +187,11 @@ local function Disable(self) element.altBar:Hide() end - self:UnregisterEvent('UNIT_SPELLCAST_START', Path) - self:UnregisterEvent('UNIT_SPELLCAST_STOP', Path) - self:UnregisterEvent('UNIT_SPELLCAST_FAILED', Path) - self:UnregisterEvent('UNIT_SPELLCAST_SUCCEEDED', Path) - self:UnregisterEvent('UNIT_DISPLAYPOWER', Path) + oUF:UnregisterEvent(self, 'UNIT_SPELLCAST_START', Path) + oUF:UnregisterEvent(self, 'UNIT_SPELLCAST_STOP', Path) + oUF:UnregisterEvent(self, 'UNIT_SPELLCAST_FAILED', Path) + oUF:UnregisterEvent(self, 'UNIT_SPELLCAST_SUCCEEDED', Path) + oUF:UnregisterEvent(self, 'UNIT_DISPLAYPOWER', Path) end end diff --git a/oUF/elements/pvpindicator.lua b/oUF/elements/pvpindicator.lua index 9cb2c66..5963371 100644 --- a/oUF/elements/pvpindicator.lua +++ b/oUF/elements/pvpindicator.lua @@ -53,12 +53,12 @@ local function Update(self, event, unit) local status local factionGroup = UnitFactionGroup(unit) or 'Neutral' - local honorRewardInfo = C_PvP.GetHonorRewardInfo(UnitHonorLevel(unit)) + local honorRewardInfo = oUF.isRetail and C_PvP.GetHonorRewardInfo(UnitHonorLevel(unit)) if(UnitIsPVPFreeForAll(unit)) then status = 'FFA' elseif(factionGroup ~= 'Neutral' and UnitIsPVP(unit)) then - if(unit == 'player' and UnitIsMercenary(unit)) then + if oUF.isRetail and (unit == 'player' and UnitIsMercenary(unit)) then if(factionGroup == 'Horde') then factionGroup = 'Alliance' elseif(factionGroup == 'Alliance') then @@ -128,7 +128,10 @@ local function Enable(self) element.ForceUpdate = ForceUpdate self:RegisterEvent('UNIT_FACTION', Path) - self:RegisterEvent('HONOR_LEVEL_UPDATE', Path, true) + + if oUF.isRetail then + self:RegisterEvent('HONOR_LEVEL_UPDATE', Path, true) + end return true end @@ -144,7 +147,10 @@ local function Disable(self) end self:UnregisterEvent('UNIT_FACTION', Path) - self:UnregisterEvent('HONOR_LEVEL_UPDATE', Path) + + if oUF.isRetail then + self:UnregisterEvent('HONOR_LEVEL_UPDATE', Path) + end end end diff --git a/oUF/elements/raidroleindicator.lua b/oUF/elements/raidroleindicator.lua index ed63d82..26941bc 100644 --- a/oUF/elements/raidroleindicator.lua +++ b/oUF/elements/raidroleindicator.lua @@ -42,7 +42,8 @@ local function Update(self, event) end local role, isShown - if(UnitInRaid(unit)) then + local inVehicle = (oUF.isRetail or oUF.isWrath) and UnitHasVehicleUI(unit) + if(UnitInRaid(unit) and not inVehicle) then if(GetPartyAssignment('MAINTANK', unit)) then isShown = true element:SetTexture(MAINTANK_ICON) diff --git a/oUF/elements/readycheckindicator.lua b/oUF/elements/readycheckindicator.lua index 1906301..1c710c3 100644 --- a/oUF/elements/readycheckindicator.lua +++ b/oUF/elements/readycheckindicator.lua @@ -122,14 +122,14 @@ end local function Enable(self, unit) local element = self.ReadyCheckIndicator - unit = unit and unit:match('(%a+)%d*') + unit = unit and unit:match('(%a+)%d*$') if(element and (unit == 'party' or unit == 'raid')) then element.__owner = self element.ForceUpdate = ForceUpdate - element.readyTexture = element.readyTexture or READY_CHECK_READY_TEXTURE - element.notReadyTexture = element.notReadyTexture or READY_CHECK_NOT_READY_TEXTURE - element.waitingTexture = element.waitingTexture or READY_CHECK_WAITING_TEXTURE + element.readyTexture = element.readyTexture or _G.READY_CHECK_READY_TEXTURE + element.notReadyTexture = element.notReadyTexture or _G.READY_CHECK_NOT_READY_TEXTURE + element.waitingTexture = element.waitingTexture or _G.READY_CHECK_WAITING_TEXTURE local AnimationGroup = element:CreateAnimationGroup() AnimationGroup:HookScript('OnFinished', OnFinished) diff --git a/oUF/elements/runes.lua b/oUF/elements/runes.lua index 2c75253..7d41ef0 100644 --- a/oUF/elements/runes.lua +++ b/oUF/elements/runes.lua @@ -47,7 +47,16 @@ if(select(2, UnitClass('player')) ~= 'DEATHKNIGHT') then return end local _, ns = ... local oUF = ns.oUF -local runemap = {1, 2, 3, 4, 5, 6} +local sort = sort +local ipairs = ipairs +local UnitHasVehicleUI = UnitHasVehicleUI +local GetSpecialization = GetSpecialization +local GetRuneCooldown = GetRuneCooldown +local GetRuneType = GetRuneType +local UnitIsUnit = UnitIsUnit +local GetTime = GetTime + +local runemap = oUF.isWrath and {1, 2, 5, 6, 3, 4} or {1, 2, 3, 4, 5, 6} local hasSortOrder = false local function onUpdate(self, elapsed) @@ -80,27 +89,56 @@ local function descSort(runeAID, runeBID) end end -local function UpdateColor(self, event) - local element = self.Runes +local function UpdateRuneType(rune, runeID, alt) + rune.runeType = GetRuneType(runeID) or alt - local spec = GetSpecialization() or 0 + return rune +end - local color - if(spec > 0 and spec < 4 and element.colorSpec) then - color = self.colors.runes[spec] - else - color = self.colors.power.RUNES +local function ColorRune(self, bar, runeType) + local color = runeType and self.colors.runes[runeType] or self.colors.power.RUNES + local r, g, b = color[1], color[2], color[3] + 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 - local r, g, b = color[1], color[2], color[3] + return color, r, g, b +end - for index = 1, #element do - element[index]:SetStatusBarColor(r, g, b) +local function UpdateColor(self, event, runeID, alt) + local element = self.Runes - local bg = element[index].bg - if(bg) then - local mu = bg.multiplier or 1 - bg:SetVertexColor(r * mu, g * mu, b * mu) + local rune, specType + if oUF.isWrath then -- runeID, alt + if runeID and event == 'RUNE_TYPE_UPDATE' then + rune = UpdateRuneType(element[runemap[runeID]], runeID, alt) + end + else + local spec = element.colorSpec and GetSpecialization() or 0 + if spec > 0 and spec < 4 then + specType = spec + end + end + + local color, r, g, b + if rune then + color, r, g, b = ColorRune(self, rune, specType or rune.runeType) + else + for i = 1, #element do + local bar = element[i] + if oUF.isWrath then + if not bar.runeType then + bar.runeType = GetRuneType(runemap[i]) + end + else + bar.runeType = specType + end + + color, r, g, b = ColorRune(self, bar, specType or bar.runeType) end end @@ -113,7 +151,7 @@ local function UpdateColor(self, event) * b - the blue component of the used color (number)[0-1] --]] if(element.PostUpdateColor) then - element:PostUpdateColor(r, g, b) + element:PostUpdateColor(r, g, b, color, rune) end end @@ -131,37 +169,47 @@ end local function Update(self, event) local element = self.Runes - if(element.sortOrder == 'asc') then - table.sort(runemap, ascSort) - hasSortOrder = true - elseif(element.sortOrder == 'desc') then - table.sort(runemap, descSort) - hasSortOrder = true - elseif(hasSortOrder) then - table.sort(runemap) - hasSortOrder = false + if not oUF.isWrath then + if element.sortOrder == 'asc' then + sort(runemap, ascSort) + hasSortOrder = true + elseif element.sortOrder == 'desc' then + sort(runemap, descSort) + hasSortOrder = true + elseif hasSortOrder then + sort(runemap) + hasSortOrder = false + end end - local rune, start, duration, runeReady - for index, runeID in next, runemap do - rune = element[index] - if(not rune) then break end + local allReady = true + local currentTime = GetTime() + local hasVehicle = UnitHasVehicleUI('player') + for index, runeID in ipairs(runemap) do + local rune = element[index] + if not rune then break end - if(UnitHasVehicleUI('player')) then + if hasVehicle then rune:Hide() + + allReady = false else - start, duration, runeReady = GetRuneCooldown(runeID) - if(runeReady) then + local start, duration, runeReady = GetRuneCooldown(runeID) + if runeReady then rune:SetMinMaxValues(0, 1) rune:SetValue(1) rune:SetScript('OnUpdate', nil) - elseif(start) then - rune.duration = GetTime() - start + elseif start then + rune.duration = currentTime - start rune:SetMinMaxValues(0, duration) rune:SetValue(0) rune:SetScript('OnUpdate', onUpdate) end + if not runeReady then + allReady = false + end + rune:Show() end end @@ -173,7 +221,7 @@ local function Update(self, event) * runemap - the ordered list of runes' indices (table) --]] if(element.PostUpdate) then - return element:PostUpdate(runemap) + return element:PostUpdate(runemap, hasVehicle, allReady) end end @@ -211,7 +259,18 @@ local function Enable(self, unit) end end - self:RegisterEvent('PLAYER_SPECIALIZATION_CHANGED', ColorPath) + -- ElvUI block + if element.IsObjectType and element:IsObjectType("Frame") then + element:Show() + end + -- end block + + if oUF.isRetail then + self:RegisterEvent('PLAYER_SPECIALIZATION_CHANGED', ColorPath) + else + self:RegisterEvent('RUNE_TYPE_UPDATE', ColorPath, true) + end + self:RegisterEvent('RUNE_POWER_UPDATE', Path, true) return true @@ -225,7 +284,18 @@ local function Disable(self) element[i]:Hide() end - self:UnregisterEvent('PLAYER_SPECIALIZATION_CHANGED', ColorPath) + -- ElvUI block + if element.IsObjectType and element:IsObjectType("Frame") then + element:Hide() + end + -- end block + + if oUF.isRetail then + self:UnregisterEvent('PLAYER_SPECIALIZATION_CHANGED', ColorPath) + else + self:UnregisterEvent('RUNE_TYPE_UPDATE', ColorPath) + end + self:UnregisterEvent('RUNE_POWER_UPDATE', Path) end end diff --git a/oUF/elements/stagger.lua b/oUF/elements/stagger.lua index 0ae3a61..5f2806e 100644 --- a/oUF/elements/stagger.lua +++ b/oUF/elements/stagger.lua @@ -34,20 +34,29 @@ if(select(2, UnitClass('player')) ~= 'MONK') then return end local _, ns = ... local oUF = ns.oUF +-- ElvUI block +local GetSpecialization = GetSpecialization +local UnitHasVehiclePlayerFrameUI = UnitHasVehiclePlayerFrameUI +local UnitHealthMax = UnitHealthMax +local UnitIsUnit = UnitIsUnit +local UnitStagger = UnitStagger +-- GLOBALS: MonkStaggerBar +-- end block + -- sourced from FrameXML/Constants.lua -local SPEC_MONK_BREWMASTER = SPEC_MONK_BREWMASTER or 1 +local SPEC_MONK_BREWMASTER = _G.SPEC_MONK_BREWMASTER or 1 -- sourced from FrameXML/MonkStaggerBar.lua -local BREWMASTER_POWER_BAR_NAME = BREWMASTER_POWER_BAR_NAME or 'STAGGER' +local BREWMASTER_POWER_BAR_NAME = _G.BREWMASTER_POWER_BAR_NAME or 'STAGGER' -- percentages at which bar should change color -local STAGGER_YELLOW_TRANSITION = STAGGER_YELLOW_TRANSITION or 0.3 -local STAGGER_RED_TRANSITION = STAGGER_RED_TRANSITION or 0.6 +local STAGGER_YELLOW_TRANSITION = _G.STAGGER_YELLOW_TRANSITION or 0.3 +local STAGGER_RED_TRANSITION = _G.STAGGER_RED_TRANSITION or 0.6 -- table indices of bar colors -local STAGGER_GREEN_INDEX = STAGGER_GREEN_INDEX or 1 -local STAGGER_YELLOW_INDEX = STAGGER_YELLOW_INDEX or 2 -local STAGGER_RED_INDEX = STAGGER_RED_INDEX or 3 +local STAGGER_GREEN_INDEX = _G.STAGGER_GREEN_INDEX or 1 +local STAGGER_YELLOW_INDEX = _G.STAGGER_YELLOW_INDEX or 2 +local STAGGER_RED_INDEX = _G.STAGGER_RED_INDEX or 3 local function UpdateColor(self, event, unit) if(unit and unit ~= self.unit) then return end @@ -92,8 +101,18 @@ local function UpdateColor(self, event, unit) end end -local function Update(self, event, unit) - if(unit and unit ~= self.unit) then return end +local staggerID = { + [124275] = true, -- [GREEN] Light Stagger + [124274] = true, -- [YELLOW] Moderate Stagger + [124273] = true, -- [RED] Heavy Stagger +} + +local function verifyStagger(frame, event, unit, auraInfo) + return staggerID[auraInfo.spellId] +end + +local function Update(self, event, unit, isFullUpdate, updatedAuras) + if oUF:ShouldSkipAuraUpdate(self, event, unit, isFullUpdate, updatedAuras, verifyStagger) then return end local element = self.Stagger @@ -148,21 +167,32 @@ local function Path(self, ...) (self.Stagger.UpdateColor or UpdateColor) (self, ...) end +-- ElvUI changed local function Visibility(self, event, unit) - if(SPEC_MONK_BREWMASTER ~= GetSpecialization() or UnitHasVehiclePlayerFrameUI('player')) then - if(self.Stagger:IsShown()) then - self.Stagger:Hide() - self:UnregisterEvent('UNIT_AURA', Path) - end - else - if(not self.Stagger:IsShown()) then - self.Stagger:Show() - self:RegisterEvent('UNIT_AURA', Path) - end + local element = self.Stagger + local isShown = element:IsShown() + local useClassbar = (SPEC_MONK_BREWMASTER ~= GetSpecialization()) or UnitHasVehiclePlayerFrameUI('player') + local stateChanged = false + + if useClassbar and isShown then + element:Hide() + self:UnregisterEvent('UNIT_AURA', Path) + stateChanged = true + elseif not useClassbar and not isShown then + element:Show() + self:RegisterEvent('UNIT_AURA', Path) + stateChanged = true + end + + if element.PostVisibility then + element.PostVisibility(self, event, unit, not useClassbar, stateChanged) + end + if not useClassbar then Path(self, event, unit) end end +-- end block local function VisibilityPath(self, ...) --[[ Override: Stagger.OverrideVisibility(self, event, unit) diff --git a/oUF/elements/tags.lua b/oUF/elements/tags.lua index 1d51f06..d15836e 100644 --- a/oUF/elements/tags.lua +++ b/oUF/elements/tags.lua @@ -12,15 +12,15 @@ A FontString to hold a tag string. Unlike other elements, this widget must not h ## Notes A `Tag` is a Lua string consisting of a function name surrounded by square brackets. The tag will be replaced by the -output of the function and displayed as text on the font string widget with that the tag has been registered. Literals -can be pre- or appended by separating them with a `>` before or `<` after the function name. The literals will be only +output of the function and displayed as text on the font string widget with that the tag has been registered. +Literals can be pre or appended by separating them with a `>` before or `<` after the function name. The literals will be only displayed when the function returns a non-nil value. I.e. `"[perhp<%]"` will display the current health as a percentage of the maximum health followed by the % sign. -A `Tag String` is a Lua string consisting of one or multiple tags with optional literals between them. Each tag will be -updated individually and the output will follow the tags order. Literals will be displayed in the output string -regardless of whether the surrounding tag functions return a value. I.e. `"[curhp]/[maxhp]"` will resolve to something -like `2453/5000`. +A `Tag String` is a Lua string consisting of one or multiple tags with optional literals between them. +Each tag will be updated individually and the output will follow the tags order. Literals will be displayed in the +output string regardless of whether the surrounding tag functions return a value. I.e. `"[curhp]/[maxhp]"` will resolve +to something like `2453/5000`. A `Tag Function` is used to replace a single tag in a tag string by its output. A tag function receives only two arguments - the unit and the realUnit of the unit frame used to register the tag (see Options for further details). The @@ -37,9 +37,9 @@ in the `oUF.Tags.SharedEvents` table as follows: `oUF.Tags.SharedEvents.EVENT_NA .overrideUnit - if specified on the font string widget, the frame's realUnit will be passed as the second argument to every tag function whose name is contained in the relevant tag string. Otherwise the second argument is always nil (boolean) -.frequentUpdates - defines how often the correspondig tag function(s) should be called. This will override the events for - the tag(s), if any. If the value is a number, it is taken as a time interval in seconds. If the value - is a boolean, the time interval is set to 0.5 seconds (number or boolean) +.frequentUpdates - defines how often the corresponding tag function(s) should be called. This will override the events + for the tag(s), if any. If the value is a number, it is taken as a time interval in seconds. If the + value is a boolean, the time interval is set to 0.5 seconds (number or boolean) ## Attributes @@ -69,10 +69,20 @@ local _, ns = ... local oUF = ns.oUF local Private = oUF.Private -local nierror = Private.nierror local unitExists = Private.unitExists local xpcall = Private.xpcall +-- ElvUI block +local _G = _G +local CreateFrame = CreateFrame +local hooksecurefunc = hooksecurefunc +local setfenv, getfenv, gsub = setfenv, getfenv, gsub +local rawget, rawset, select = rawget, rawset, select +local format, tinsert, tremove = format, tinsert, tremove +local next, type, pcall, unpack = next, type, pcall, unpack +local error, assert, loadstring = error, assert, loadstring +-- end block + local _PATTERN = '%[..-%]+' local _ENV = { @@ -84,7 +94,14 @@ local _ENV = { r, g, b = unpack(r) end end - return string.format('|cff%02x%02x%02x', r * 255, g * 255, b * 255) + + -- ElvUI block + if not r or type(r) == 'string' then --wtf? + return '|cffFFFFFF' + end + -- end block + + return format('|cff%02x%02x%02x', r * 255, g * 255, b * 255) end, } _ENV.ColorGradient = function(...) @@ -110,6 +127,17 @@ local tagStrings = { end end]], + ['arenaspec'] = [[function(u) + local id = u:match('arena(%d)$') + if(id) then + local specID = GetArenaOpponentSpec(tonumber(id)) + if(specID and specID > 0) then + local _, specName = GetSpecializationInfoByID(specID) + return specName + end + end + end]], + ['chi'] = [[function() if(GetSpecialization() == SPEC_MONK_WINDWALKER) then local num = UnitPower('player', Enum.PowerType.Chi) @@ -169,7 +197,7 @@ local tagStrings = { ['difficulty'] = [[function(u) if UnitCanAttack('player', u) then - local l = UnitEffectiveLevel(u) + local l = (UnitEffectiveLevel or UnitLevel)(u) return Hex(GetCreatureDifficultyColor((l > 0) and l or 999)) end end]], @@ -210,7 +238,10 @@ local tagStrings = { end]], ['level'] = [[function(u) - local l = UnitLevel(u) + local l = (UnitEffectiveLevel or UnitLevel)(u) + if C_PetBattles and (UnitIsWildBattlePet(u) or UnitIsBattlePetCompanion(u)) then + l = UnitBattlePetLevel(u) + end if(l > 0) then return l @@ -284,7 +315,7 @@ local tagStrings = { return Hex(altR, altG, altB) end else - return Hex(_COLORS.power[pType]) + return Hex(_COLORS.power[pType] or _COLORS.power.MANA) end end @@ -483,21 +514,20 @@ local vars = setmetatable({}, { _ENV._VARS = vars +-- ElvUI switches to UNIT_POWER_FREQUENT for regen powers local tagEvents = { ['affix'] = 'UNIT_CLASSIFICATION_CHANGED', - ['arcanecharges'] = 'UNIT_POWER_UPDATE PLAYER_TALENT_UPDATE', - ['chi'] = 'UNIT_POWER_UPDATE PLAYER_TALENT_UPDATE', + ['arenaspec'] = 'ARENA_PREP_OPPONENT_SPECIALIZATIONS', ['classification'] = 'UNIT_CLASSIFICATION_CHANGED', - ['cpoints'] = 'UNIT_POWER_FREQUENT PLAYER_TARGET_CHANGED', + ['cpoints'] = 'UNIT_POWER_UPDATE PLAYER_TARGET_CHANGED', ['curhp'] = 'UNIT_HEALTH UNIT_MAXHEALTH', - ['curmana'] = 'UNIT_POWER_UPDATE UNIT_MAXPOWER', - ['curpp'] = 'UNIT_POWER_UPDATE UNIT_MAXPOWER', + ['curmana'] = 'UNIT_POWER_FREQUENT UNIT_MAXPOWER', + ['curpp'] = 'UNIT_POWER_FREQUENT UNIT_MAXPOWER', ['dead'] = 'UNIT_HEALTH', ['deficit:name'] = 'UNIT_HEALTH UNIT_MAXHEALTH UNIT_NAME_UPDATE', ['difficulty'] = 'UNIT_FACTION', ['faction'] = 'NEUTRAL_FACTION_SELECT_RESULT', ['group'] = 'GROUP_ROSTER_UPDATE', - ['holypower'] = 'UNIT_POWER_UPDATE PLAYER_TALENT_UPDATE', ['leader'] = 'PARTY_LEADER_CHANGED', ['leaderlong'] = 'PARTY_LEADER_CHANGED', ['level'] = 'UNIT_LEVEL PLAYER_LEVEL_UP', @@ -505,11 +535,11 @@ local tagEvents = { ['maxmana'] = 'UNIT_POWER_UPDATE UNIT_MAXPOWER', ['maxpp'] = 'UNIT_MAXPOWER', ['missinghp'] = 'UNIT_HEALTH UNIT_MAXHEALTH', - ['missingpp'] = 'UNIT_MAXPOWER UNIT_POWER_UPDATE', + ['missingpp'] = 'UNIT_MAXPOWER UNIT_POWER_FREQUENT', ['name'] = 'UNIT_NAME_UPDATE', ['offline'] = 'UNIT_HEALTH UNIT_CONNECTION', ['perhp'] = 'UNIT_HEALTH UNIT_MAXHEALTH', - ['perpp'] = 'UNIT_MAXPOWER UNIT_POWER_UPDATE', + ['perpp'] = 'UNIT_MAXPOWER UNIT_POWER_FREQUENT', ['plus'] = 'UNIT_CLASSIFICATION_CHANGED', ['powercolor'] = 'UNIT_DISPLAYPOWER', ['pvp'] = 'UNIT_FACTION', @@ -520,18 +550,35 @@ local tagEvents = { ['smartlevel'] = 'UNIT_LEVEL PLAYER_LEVEL_UP UNIT_CLASSIFICATION_CHANGED', ['soulshards'] = 'UNIT_POWER_UPDATE', ['status'] = 'UNIT_HEALTH PLAYER_UPDATE_RESTING UNIT_CONNECTION', + ['threat'] = 'UNIT_THREAT_SITUATION_UPDATE', + ['threatcolor'] = 'UNIT_THREAT_SITUATION_UPDATE', } local unitlessEvents = { + ARENA_PREP_OPPONENT_SPECIALIZATIONS = true, GROUP_ROSTER_UPDATE = true, NEUTRAL_FACTION_SELECT_RESULT = true, PARTY_LEADER_CHANGED = true, PLAYER_LEVEL_UP = true, PLAYER_TARGET_CHANGED = true, PLAYER_UPDATE_RESTING = true, + RAID_TARGET_UPDATE = true, RUNE_POWER_UPDATE = true, } +if oUF.isRetail then + tagEvents['arcanecharges'] = 'UNIT_POWER_UPDATE PLAYER_TALENT_UPDATE' + tagEvents['chi'] = 'UNIT_POWER_UPDATE PLAYER_TALENT_UPDATE' + tagEvents['holypower'] = 'UNIT_POWER_UPDATE PLAYER_TALENT_UPDATE' + unitlessEvents.PLAYER_TALENT_UPDATE = true +elseif oUF.isWrath then + unitlessEvents.PLAYER_TALENT_UPDATE = true +end + +for tag, events in pairs(tagEvents) do -- ElvUI: UNIT_HEALTH is bugged on TBC, use same method to convert as E.AddTag + tagEvents[tag] = (oUF.isRetail and gsub(events, 'UNIT_HEALTH_FREQUENT', 'UNIT_HEALTH')) or gsub(events, 'UNIT_HEALTH([^%s_]?)', 'UNIT_HEALTH_FREQUENT%1') +end + local events = {} local eventFrame = CreateFrame('Frame') eventFrame:SetScript('OnEvent', function(self, event, unit) @@ -585,124 +632,78 @@ local function Update(self) end end +-- ElvUI block +local onUpdateDelay = {} +local function escapeSequence(a) return format('|%s', a) end +local function makeDeadTagFunc(bracket) + return function() + return format('|cFFffffff%s|r', bracket) + end +end + +local function makeTagFunc(tag, prefix, suffix) + return function(unit, realUnit, customArgs) + local str = tag(unit, realUnit, customArgs) + if str then + return format('%s%s%s', prefix or '', str, suffix or '') + end + end +end +-- end block + local tagPool = {} local funcPool = {} local tmp = {} +local function getTagName(tag) + local tagStart = tag:match('>+()') or 2 + local tagEnd = (tag:match('.-()<') or -1) - 1 --- full tag syntax: '[prefix$>tag-name<$suffix(a,r,g,s)]' --- for a small test case see https://github.com/oUF-wow/oUF/pull/602 -local function getBracketData(tag) - local prefixEnd, prefixOffset = tag:match('()$>'), 1 - if(not prefixEnd) then - prefixEnd = 1 - else - prefixEnd = prefixEnd - 1 - prefixOffset = 3 - end - - local suffixEnd = (tag:match('()%(', prefixOffset + 1) or -1) - 1 - local suffixStart, suffixOffset = tag:match('<$()', prefixEnd), 1 - if(not suffixStart) then - suffixStart = suffixEnd + 1 - else - suffixOffset = 3 - end - - return tag:sub(prefixEnd + prefixOffset, suffixStart - suffixOffset), - prefixEnd, - suffixStart, - suffixEnd, - tag:match('%((.-)%)', suffixOffset + 1) + return tag:sub(tagStart, tagEnd), tagStart, tagEnd end local function getTagFunc(tagstr) local func = tagPool[tagstr] - if(not func) then - local format, numTags = tagstr:gsub('%%', '%%%%'):gsub(_PATTERN, '%%s') + if not func then + local frmt, numTags = tagstr:gsub('%%', '%%%%'):gsub(_PATTERN, '%%s') local args = {} - local idx = 1 - - local format_ = {} - for i = 1, numTags do - format_[i] = '%s' - end + -- ElvUI changed for bracket in tagstr:gmatch(_PATTERN) do local tagFunc = funcPool[bracket] or tags[bracket:sub(2, -2)] - if(not tagFunc) then - local tagName, prefixEnd, suffixStart, suffixEnd, customArgs = getBracketData(bracket) - local tag = tags[tagName] - if(tag) then - if(prefixEnd ~= 1 or suffixStart - suffixEnd ~= 1) then - local prefix = prefixEnd ~= 1 and bracket:sub(2, prefixEnd) or '' - local suffix = suffixStart - suffixEnd ~= 1 and bracket:sub(suffixStart, suffixEnd) or '' - - tagFunc = function(unit, realUnit) - local str - if(customArgs) then - str = tag(unit, realUnit, string.split(',', customArgs)) - else - str = tag(unit, realUnit) - end - - if(str and str ~= '') then - return prefix .. str .. suffix - end - end - else - tagFunc = function(unit, realUnit) - local str - if(customArgs) then - str = tag(unit, realUnit, string.split(',', customArgs)) - else - str = tag(unit, realUnit) - end - - if(str and str ~= '') then - return str - end - end - end + if not tagFunc then + local tagName, tagStart, tagEnd = getTagName(bracket) + local tag = tags[tagName] + if tag then + tagStart, tagEnd = tagStart - 2, tagEnd + 2 + tagFunc = makeTagFunc(tag, tagStart ~= 0 and bracket:sub(2, tagStart), tagEnd ~= 0 and bracket:sub(tagEnd, -2)) funcPool[bracket] = tagFunc end end - if(tagFunc) then - table.insert(args, tagFunc) - - idx = idx + 1 - else - nierror(string.format('Attempted to use invalid tag %s.', bracket)) - - format_[idx] = bracket - format = format:format(unpack(format_, 1, numTags)) - format_[idx] = '%s' - - numTags = numTags - 1 - end + tinsert(args, tagFunc or makeDeadTagFunc(bracket)) end func = function(self) local parent = self.parent local unit = parent.unit - local realUnit - if(self.overrideUnit) then - realUnit = parent.realUnit - end + local realUnit = self.overrideUnit and parent.realUnit + local customArgs = parent.__customargs[self] - _ENV._COLORS = parent.colors _ENV._FRAME = parent - for i, f in next, args do - tmp[i] = f(unit, realUnit) or '' + _ENV._COLORS = parent.colors + + for i, fnc in next, args do + tmp[i] = fnc(unit, realUnit, customArgs) or '' end -- We do 1, numTags because tmp can hold several unneeded variables. - return self:SetFormattedText(format, unpack(tmp, 1, numTags)) + self:SetFormattedText(frmt, unpack(tmp, 1, numTags)) end tagPool[tagstr] = func + -- end block end return func @@ -713,13 +714,13 @@ local function registerEvent(fontstr, event) local isOK = xpcall(eventFrame.RegisterEvent, eventFrame, event) if(isOK) then - table.insert(events[event], fontstr) + tinsert(events[event], fontstr) end end local function registerEvents(fontstr, tagstr) for tag in tagstr:gmatch(_PATTERN) do - tag = getBracketData(tag) + tag = getTagName(tag) local tagevents = tagEvents[tag] if(tagevents) then for event in tagevents:gmatch('%S+') do @@ -739,7 +740,7 @@ local function unregisterEvents(fontstr) eventFrame:UnregisterEvent(event) end - table.remove(data, index) + tremove(data, index) else index = index + 1 end @@ -749,6 +750,30 @@ local function unregisterEvents(fontstr) end end +-- this bullshit is to fix texture strings not adjusting to its inherited alpha +-- it is a blizzard issue with how texture strings are rendered +local alphaFix = CreateFrame('Frame') +alphaFix.fontStrings = {} +alphaFix:SetScript('OnUpdate', function() + local strs = alphaFix.fontStrings + if next(strs) then + for fs in next, strs do + strs[fs] = nil + + local a = fs:GetAlpha() + fs:SetAlpha(0) + fs:SetAlpha(a) + end + else + alphaFix:Hide() + end +end) + +local function fixAlpha(self) + alphaFix.fontStrings[self] = true + alphaFix:Show() +end + local taggedFS = {} --[[ Tags: frame:Tag(fs, tagstr, ...) @@ -764,26 +789,75 @@ local function Tag(self, fs, tagstr, ...) if(not self.__tags) then self.__tags = {} - table.insert(self.__elements, Update) + self.__mousetags = {} -- ElvUI + self.__customargs = {} -- ElvUI + + tinsert(self.__elements, Update) elseif(self.__tags[fs]) then -- We don't need to remove it from the __tags table as Untag handles -- that for us. self:Untag(fs) end + -- ElvUI + if not fs.__HookedAlphaFix then + hooksecurefunc(fs, 'SetText', fixAlpha) + hooksecurefunc(fs, 'SetFormattedText', fixAlpha) + fs.__HookedAlphaFix = true + end + + tagstr = tagstr:gsub('||([TCRAtcra])', escapeSequence) + + local customArgs = tagstr:match('{(.-)}%]') + if customArgs then + self.__customargs[fs] = customArgs + tagstr = tagstr:gsub('{.-}%]', ']') + else + self.__customargs[fs] = nil + end + + if not self.isNamePlate then + if tagstr:find('%[mouseover%]') then + self.__mousetags[fs] = true + fs:SetAlpha(0) + + tagstr = tagstr:gsub('%[mouseover%]', '') + else + for fontString in next, self.__mousetags do + if fontString == fs then + self.__mousetags[fontString] = nil + fs:SetAlpha(1) + end + end + end + end + + local containsOnUpdate + for tag in tagstr:gmatch(_PATTERN) do + tag = getTagName(tag) + if not tagEvents[tag] then + containsOnUpdate = onUpdateDelay[tag] or 0.15; + end + end + -- end block + fs.parent = self fs.UpdateTag = getTagFunc(tagstr) - if(self.__eventless or fs.frequentUpdates) then + if(self.__eventless or fs.frequentUpdates) or containsOnUpdate then -- ElvUI changed local timer if(type(fs.frequentUpdates) == 'number') then timer = fs.frequentUpdates + -- ElvUI added check + elseif containsOnUpdate then + timer = containsOnUpdate + -- end block else timer = .5 end if(not eventlessUnits[timer]) then eventlessUnits[timer] = {} end - table.insert(eventlessUnits[timer], fs) + tinsert(eventlessUnits[timer], fs) createOnUpdate(timer) else @@ -819,7 +893,7 @@ local function Untag(self, fs) local fontstr = timers[index] while fontstr do if(fs == fontstr) then - table.remove(timers, index) + tremove(timers, index) else index = index + 1 end @@ -836,24 +910,24 @@ end local function strip(tag) -- remove prefix, custom args, and suffix - return tag:gsub('%[.-$>', '['):gsub('%(.-%)%]', ']'):gsub('<$.-%]', ']') + return tag:gsub("%[[^%[%]]*>", "["):gsub("<[^%[%]]*%]", "]") -- ElvUI uses old tag format end oUF.Tags = { Methods = tags, Events = tagEvents, SharedEvents = unitlessEvents, + OnUpdateThrottle = onUpdateDelay, -- ElvUI Vars = vars, RefreshMethods = function(self, tag) if(not tag) then return end - -- If a tag's name contains magic chars, there's a chance that - -- string.match will fail to find the match. + -- If a tag's name contains magic chars, there's a chance that string.match will fail to find the match. tag = '%[' .. tag:gsub('[%^%$%(%)%%%.%*%+%-%?]', '%%%1') .. '%]' - for func in next, funcPool do - if(strip(func):match(tag)) then - funcPool[func] = nil + for bracket in next, funcPool do + if(strip(bracket):match(tag)) then + funcPool[bracket] = nil end end @@ -876,9 +950,9 @@ oUF.Tags = { RefreshEvents = function(self, tag) if(not tag) then return end - -- If a tag's name contains magic chars, there's a chance that - -- string.match will fail to find the match. + -- If a tag's name contains magic chars, there's a chance that string.match will fail to find the match. tag = '%[' .. tag:gsub('[%^%$%(%)%%%.%*%+%-%?]', '%%%1') .. '%]' + for tagstr in next, tagPool do if(strip(tagstr):match(tag)) then for fs, ts in next, taggedFS do @@ -894,4 +968,4 @@ oUF.Tags = { oUF:RegisterMetaFunction('Tag', Tag) oUF:RegisterMetaFunction('Untag', Untag) -oUF:RegisterMetaFunction('UpdateTags', Update) \ No newline at end of file +oUF:RegisterMetaFunction('UpdateTags', Update) diff --git a/oUF/elements/threatindicator.lua b/oUF/elements/threatindicator.lua index 6eb6fd3..1cb1ece 100644 --- a/oUF/elements/threatindicator.lua +++ b/oUF/elements/threatindicator.lua @@ -15,7 +15,7 @@ A default texture will be applied if the widget is a Texture and doesn't have a ## Options .feedbackUnit - The unit whose threat situation is being requested. If defined, it'll be passed as the first argument to - [GetThreatStatusColor](http://wowprogramming.com/docs/api/UnitThreatSituation.html). + [UnitThreatSituation](https://wow.gamepedia.com/API_UnitThreatSituation). ## Examples @@ -34,20 +34,6 @@ local Private = oUF.Private local unitExists = Private.unitExists -if not GetThreatStatusColor then - function GetThreatStatusColor(status) - if status == 3 then - return 1, 0, 0 - elseif status == 2 then - return 1, .6, 0 - elseif status == 1 then - return 1, 1, .47 - else - return .69, .69, .69 - end - end -end - local function Update(self, event, unit) if(unit ~= self.unit) then return end @@ -75,7 +61,7 @@ local function Update(self, event, unit) local r, g, b if(status and status > 0) then - r, g, b = GetThreatStatusColor(status) + r, g, b = unpack(self.colors.threat[status]) if(element.SetVertexColor) then element:SetVertexColor(r, g, b) diff --git a/oUF/elements/totems.lua b/oUF/elements/totems.lua index 6694473..c48f585 100644 --- a/oUF/elements/totems.lua +++ b/oUF/elements/totems.lua @@ -48,21 +48,46 @@ OnEnter and OnLeave script handlers will be set to display a Tooltip if the `Tot local _, ns = ... local oUF = ns.oUF +local GameTooltip = GameTooltip +local GetTotemInfo = GetTotemInfo +local GetTime = GetTime + local function UpdateTooltip(self) + if GameTooltip:IsForbidden() then return end + GameTooltip:SetTotem(self:GetID()) end local function OnEnter(self) - if(not self:IsVisible()) then return end + if GameTooltip:IsForbidden() or not self:IsVisible() then return end GameTooltip:SetOwner(self, 'ANCHOR_BOTTOMRIGHT') self:UpdateTooltip() end local function OnLeave() + if GameTooltip:IsForbidden() then return end + GameTooltip:Hide() end +local function TotemOnUpdate(self, elapsed) + self.elapsed = (self.elapsed or 0) + elapsed + + if (self.elapsed >= .01) then + self.elapsed = 0 + + local _, _, startTime, expiration = GetTotemInfo(self:GetID()) + local currentTime = GetTime() - startTime + + if currentTime <= 0 or expiration <= 0 then + self:SetValue(0) + else + self:SetValue(1 - (currentTime / expiration)) + end + end +end + local function UpdateTotem(self, event, slot) local element = self.Totems if(slot > #element) then return end @@ -77,15 +102,20 @@ local function UpdateTotem(self, event, slot) local totem = element[slot] local haveTotem, name, start, duration, icon = GetTotemInfo(slot) - if(haveTotem and duration > 0) then - if(totem.Icon) then + + if haveTotem and duration > 0 then + if totem.Icon then totem.Icon:SetTexture(icon) end - if(totem.Cooldown) then + if totem.Cooldown then totem.Cooldown:SetCooldown(start, duration) end + if totem:IsObjectType('StatusBar') then + totem:SetValue(0) + end + totem:Show() else totem:Hide() @@ -119,13 +149,19 @@ local function Path(self, ...) end local function Update(self, event) - for i = 1, #self.Totems do + local element = self.Totems + + for i = 1, #element do Path(self, event, i) end + + if(element.PostUpdateColor) then + element:PostUpdateColor() + end end local function ForceUpdate(element) - return Update(element.__owner, 'ForceUpdate') + Update(element.__owner, 'ForceUpdate') end local function Enable(self) @@ -139,7 +175,11 @@ local function Enable(self) totem:SetID(i) - if(totem:IsMouseEnabled()) then + if totem:IsObjectType('StatusBar') then + totem:SetScript('OnUpdate', TotemOnUpdate) + end + + if totem:IsMouseEnabled() then totem:SetScript('OnEnter', OnEnter) totem:SetScript('OnLeave', OnLeave) @@ -154,6 +194,7 @@ local function Enable(self) end end + element:Show() self:RegisterEvent('PLAYER_TOTEM_UPDATE', Path, true) return true @@ -167,6 +208,7 @@ local function Disable(self) element[i]:Hide() end + element:Hide() self:UnregisterEvent('PLAYER_TOTEM_UPDATE', Path) end end diff --git a/oUF/events.lua b/oUF/events.lua index 98db72a..a5aece9 100644 --- a/oUF/events.lua +++ b/oUF/events.lua @@ -1,10 +1,11 @@ -local parent, ns = ... +local _, ns = ... local oUF = ns.oUF local Private = oUF.Private local argcheck = Private.argcheck -local error = Private.error +local validateEvent = Private.validateEvent local validateUnit = Private.validateUnit +local isUnitEvent = Private.isUnitEvent local frame_metatable = Private.frame_metatable -- Original event methods @@ -16,6 +17,12 @@ local isEventRegistered = frame_metatable.__index.IsEventRegistered -- to update unit frames correctly, some events need to be registered for -- a specific combination of primary and secondary units local secondaryUnits = { + UNIT_ENTERED_VEHICLE = { + pet = 'player', + }, + UNIT_EXITED_VEHICLE = { + pet = 'player', + }, UNIT_PET = { pet = 'player', }, @@ -98,8 +105,8 @@ function frame_metatable.__index:RegisterEvent(event, func, unitless) argcheck(func, 3, 'function') local curev = self[event] - local kind = type(curev) if(curev) then + local kind = type(curev) if(kind == 'function' and curev ~= func) then self[event] = setmetatable({curev, func}, event_metatable) elseif(kind == 'table') then @@ -113,11 +120,12 @@ function frame_metatable.__index:RegisterEvent(event, func, unitless) if(unitless or self.__eventless) then -- re-register the event in case we have mixed registration registerEvent(self, event) + if(self.unitEvents) then self.unitEvents[event] = nil end end - else + elseif(validateEvent(event)) then self[event] = func if(not self:GetScript('OnEvent')) then @@ -129,6 +137,7 @@ function frame_metatable.__index:RegisterEvent(event, func, unitless) else self.unitEvents = self.unitEvents or {} self.unitEvents[event] = true + -- UpdateUnits will take care of unit event registration for header -- units in case we don't have a valid unit yet local unit1, unit2 = self.unit @@ -137,6 +146,10 @@ function frame_metatable.__index:RegisterEvent(event, func, unitless) unit2 = secondaryUnits[event][unit1] end + -- be helpful and throw a custom error when attempting to register + -- an event that is unitless + assert(isUnitEvent(event, unit1), string.format('Event "%s" is not an unit event', event)) + registerUnitEvent(self, event, unit1, unit2 or '') end end @@ -178,4 +191,4 @@ function frame_metatable.__index:UnregisterEvent(event, func) unregisterEvent(self, event) end -end \ No newline at end of file +end diff --git a/oUF/factory.lua b/oUF/factory.lua index f862eba..2e2cf41 100644 --- a/oUF/factory.lua +++ b/oUF/factory.lua @@ -1,48 +1,71 @@ -local parent, ns = ... +local _, ns = ... local oUF = ns.oUF local Private = oUF.Private local argcheck = Private.argcheck -local _QUEUE = {} -local _FACTORY = CreateFrame'Frame' -_FACTORY:SetScript('OnEvent', function(self, event, ...) +local queue = {} +local factory = CreateFrame('Frame') +factory:SetScript('OnEvent', function(self, event, ...) return self[event](self, event, ...) end) -_FACTORY:RegisterEvent'PLAYER_LOGIN' -_FACTORY.active = true +factory:RegisterEvent('PLAYER_LOGIN') +factory.active = true -function _FACTORY:PLAYER_LOGIN() +function factory:PLAYER_LOGIN() if(not self.active) then return end - for _, func in next, _QUEUE do + for _, func in next, queue do func(oUF) end -- Avoid creating dupes. - wipe(_QUEUE) + table.wipe(queue) end +--[[ Factory: oUF:Factory(func) +Used to call a function directly if the current character is logged in and the factory is active. Else the function is +queued up to be executed at a later time (upon PLAYER_LOGIN by default). + +* self - the global oUF object +* func - function to be executed or delayed (function) +--]] function oUF:Factory(func) argcheck(func, 2, 'function') -- Call the function directly if we're active and logged in. - if(IsLoggedIn() and _FACTORY.active) then + if(IsLoggedIn() and factory.active) then return func(self) else - table.insert(_QUEUE, func) + table.insert(queue, func) end end +--[[ Factory: oUF:EnableFactory() +Used to enable the factory. + +* self - the global oUF object +--]] function oUF:EnableFactory() - _FACTORY.active = true + factory.active = true end +--[[ Factory: oUF:DisableFactory() +Used to disable the factory. + +* self - the global oUF object +--]] function oUF:DisableFactory() - _FACTORY.active = nil + factory.active = nil end +--[[ Factory: oUF:RunFactoryQueue() +Used to try to execute queued up functions. The current player must be logged in and the factory must be active for +this to succeed. + +* self - the global oUF object +--]] function oUF:RunFactoryQueue() - _FACTORY:PLAYER_LOGIN() -end \ No newline at end of file + factory:PLAYER_LOGIN() +end diff --git a/oUF/finalize.lua b/oUF/finalize.lua index dec0bc1..55119b8 100644 --- a/oUF/finalize.lua +++ b/oUF/finalize.lua @@ -1,4 +1,4 @@ -local parent, ns = ... +local _, ns = ... -- It's named Private for a reason! -ns.oUF.Private = nil \ No newline at end of file +ns.oUF.Private = nil diff --git a/oUF/init.lua b/oUF/init.lua index dabbd5d..1a8e978 100644 --- a/oUF/init.lua +++ b/oUF/init.lua @@ -1,3 +1,10 @@ -local parent, ns = ... +local _, ns = ... ns.oUF = {} -ns.oUF.Private = {} \ No newline at end of file +ns.oUF.Private = {} + +local _, _, _, toc = GetBuildInfo() + +ns.oUF.isRetail = WOW_PROJECT_ID == WOW_PROJECT_MAINLINE +ns.oUF.isClassic = WOW_PROJECT_ID == WOW_PROJECT_CLASSIC +ns.oUF.isTBC = toc >= 20500 and toc < 30000 -- TODO: Wrath +ns.oUF.isWrath = toc >= 30400 and toc < 40000 -- TODO: Wrath diff --git a/oUF/oUF.toc b/oUF/oUF.toc index 822f8b7..5e6d839 100644 --- a/oUF/oUF.toc +++ b/oUF/oUF.toc @@ -1,5 +1,5 @@ -## Interface: 20504 -## Title: oUF |cff1a9fc0BCC|r +## Interface: 30400 +## Title: oUF |cff1a9fc0WLK|r ## Author: Haste, lightspark, p3lim, Rainrider ## Version: @project-version@ ## Notes: Unit frame framework. Does nothing by itself. @@ -15,38 +15,4 @@ libs\CallbackHandler-1.0\CallbackHandler-1.0.lua libs\LibHealComm-4.0\ChatThrottleLib.lua libs\LibHealComm-4.0\LibHealComm-4.0.lua -init.lua -private.lua -ouf.lua -events.lua -combatevents.lua -factory.lua -blizzard.lua -units.lua -colors.lua -elements\assistantindicator.lua -elements\auras.lua -elements\castbar.lua -elements\classpower.lua -elements\combatindicator.lua -elements\grouproleindicator.lua -elements\health.lua -elements\healthprediction.lua -elements\leaderindicator.lua -elements\phaseindicator.lua -elements\portrait.lua -elements\power.lua -elements\powerprediction.lua -elements\pvpindicator.lua -elements\questindicator.lua -elements\raidroleindicator.lua -elements\raidtargetindicator.lua -elements\range.lua -elements\readycheckindicator.lua -elements\restingindicator.lua -elements\resurrectindicator.lua -elements\stagger.lua -elements\tags.lua -elements\threatindicator.lua -elements\totems.lua -finalize.lua \ No newline at end of file +oUF_Wrath.xml \ No newline at end of file diff --git a/oUF/oUF.xml b/oUF/oUF.xml index 043ccc6..4e37a8c 100644 --- a/oUF/oUF.xml +++ b/oUF/oUF.xml @@ -9,33 +9,81 @@ <Script file="units.lua"/> <Script file="colors.lua"/> - <Script file='Plugins\RaidDebuffs.lua' /> - <Script file="elements\additionalpower.lua"/> + <Script file="elements\alternativepower.lua"/> <Script file="elements\assistantindicator.lua"/> <Script file="elements\auras.lua"/> <Script file="elements\castbar.lua"/> <Script file="elements\classpower.lua"/> <Script file="elements\combatindicator.lua"/> - <Script file="elements\healprediction.lua"/> + <Script file="elements\grouproleindicator.lua"/> <Script file="elements\health.lua"/> + <Script file="elements\healthprediction.lua"/> <Script file="elements\leaderindicator.lua"/> <Script file="elements\masterlooterindicator.lua"/> + <Script file="elements\partyindicator.lua"/> <Script file="elements\phaseindicator.lua"/> <Script file="elements\portrait.lua"/> <Script file="elements\power.lua"/> + <Script file="elements\powerprediction.lua"/> + <Script file="elements\pvpclassificationindicator.lua"/> + <Script file="elements\pvpindicator.lua"/> + <Script file="elements\questindicator.lua"/> <Script file="elements\raidroleindicator.lua"/> <Script file="elements\raidtargetindicator.lua"/> <Script file="elements\range.lua"/> <Script file="elements\readycheckindicator.lua"/> <Script file="elements\restingindicator.lua"/> <Script file="elements\resurrectindicator.lua"/> + <Script file="elements\runes.lua"/> + <Script file="elements\stagger.lua"/> + <Script file="elements\summonindicator.lua"/> <Script file="elements\tags.lua"/> <Script file="elements\threatindicator.lua"/> - - <Script file='Plugins\FloatingCombatFeedback.lua' /> - <Script file='Plugins\Swing.lua' /> - <Script file='Plugins\EnergyManaRegen.lua' /> + <Script file="elements\totems.lua"/> <Script file="finalize.lua"/> -</Ui> \ No newline at end of file + + <!-- + Sub-object as a child of the parent unit frame: + <Button name="oUF_HeaderTargetTemplate" inherits="SecureUnitButtonTemplate" virtual="true"> + <Frames> + <Button name="$parentTarget" inherits="SecureUnitButtonTemplate"> + <Attributes> + <Attribute name="unitsuffix" type="string" value="target"/> + <Attribute name="useparent-unit" type="boolean" value="true"/> + </Attributes> + </Button> + </Frames> + </Button> + + Separate unit template example: + <Button name="oUF_HeaderSeparateSubOjectsTemplate" inherits="SecureUnitButtonTemplate" virtual="true"> + <Attributes> + <Attribute name="oUF-onlyProcessChildren" type="boolean" value="true"/> + </Attributes> + + <Frames> + <Button name="$parentUnit" inherits="SecureUnitButtonTemplate"> + <Attributes> + <Attribute name="useparent-unit" type="boolean" value="true"/> + </Attributes> + </Button> + + <Button name="$parentPet" inherits="SecureUnitButtonTemplate"> + <Attributes> + <Attribute name="unitsuffix" type="string" value="pet"/> + <Attribute name="useparent-unit" type="boolean" value="true"/> + </Attributes> + </Button> + + <Button name="$parentTarget" inherits="SecureUnitButtonTemplate"> + <Attributes> + <Attribute name="unitsuffix" type="string" value="target"/> + <Attribute name="useparent-unit" type="boolean" value="true"/> + </Attributes> + </Button> + </Frames> + </Button> + --> +</Ui> diff --git a/oUF/oUF_Classic.xml b/oUF/oUF_Classic.xml new file mode 100644 index 0000000..5ea9f98 --- /dev/null +++ b/oUF/oUF_Classic.xml @@ -0,0 +1,39 @@ +<Ui xmlns="http://www.blizzard.com/wow/ui/"> + <Script file="init.lua"/> + <Script file="private.lua"/> + <Script file="ouf.lua"/> + <Script file="events.lua"/> + <Script file="combatevents.lua"/> + <Script file="factory.lua"/> + <Script file="blizzard.lua"/> + <Script file="units.lua"/> + <Script file="colors.lua"/> + + <Script file="elements\additionalpower.lua"/> + <Script file="elements\assistantindicator.lua"/> + <Script file="elements\auras.lua"/> + <Script file="elements\castbar.lua"/> + <Script file="elements\classpower.lua"/> + <Script file="elements\combatindicator.lua"/> + <Script file="elements\grouproleindicator.lua"/> + <Script file="elements\health.lua"/> + <Script file="elements\healthprediction.lua"/> + <Script file="elements\leaderindicator.lua"/> + <Script file="elements\masterlooterindicator.lua"/> + <Script file="elements\portrait.lua"/> + <Script file="elements\power.lua"/> + <Script file="elements\powerprediction.lua"/> + <Script file="elements\pvpindicator.lua"/> + <Script file="elements\questindicator.lua"/> + <Script file="elements\raidroleindicator.lua"/> + <Script file="elements\raidtargetindicator.lua"/> + <Script file="elements\range.lua"/> + <Script file="elements\readycheckindicator.lua"/> + <Script file="elements\restingindicator.lua"/> + <Script file="elements\resurrectindicator.lua"/> + <Script file="elements\tags.lua"/> + <Script file="elements\threatindicator.lua"/> + <Script file="elements\totems.lua"/> + + <Script file="finalize.lua"/> +</Ui> diff --git a/oUF/oUF_TBC.xml b/oUF/oUF_TBC.xml new file mode 100644 index 0000000..5ea9f98 --- /dev/null +++ b/oUF/oUF_TBC.xml @@ -0,0 +1,39 @@ +<Ui xmlns="http://www.blizzard.com/wow/ui/"> + <Script file="init.lua"/> + <Script file="private.lua"/> + <Script file="ouf.lua"/> + <Script file="events.lua"/> + <Script file="combatevents.lua"/> + <Script file="factory.lua"/> + <Script file="blizzard.lua"/> + <Script file="units.lua"/> + <Script file="colors.lua"/> + + <Script file="elements\additionalpower.lua"/> + <Script file="elements\assistantindicator.lua"/> + <Script file="elements\auras.lua"/> + <Script file="elements\castbar.lua"/> + <Script file="elements\classpower.lua"/> + <Script file="elements\combatindicator.lua"/> + <Script file="elements\grouproleindicator.lua"/> + <Script file="elements\health.lua"/> + <Script file="elements\healthprediction.lua"/> + <Script file="elements\leaderindicator.lua"/> + <Script file="elements\masterlooterindicator.lua"/> + <Script file="elements\portrait.lua"/> + <Script file="elements\power.lua"/> + <Script file="elements\powerprediction.lua"/> + <Script file="elements\pvpindicator.lua"/> + <Script file="elements\questindicator.lua"/> + <Script file="elements\raidroleindicator.lua"/> + <Script file="elements\raidtargetindicator.lua"/> + <Script file="elements\range.lua"/> + <Script file="elements\readycheckindicator.lua"/> + <Script file="elements\restingindicator.lua"/> + <Script file="elements\resurrectindicator.lua"/> + <Script file="elements\tags.lua"/> + <Script file="elements\threatindicator.lua"/> + <Script file="elements\totems.lua"/> + + <Script file="finalize.lua"/> +</Ui> diff --git a/oUF/oUF_Wrath.xml b/oUF/oUF_Wrath.xml new file mode 100644 index 0000000..c547186 --- /dev/null +++ b/oUF/oUF_Wrath.xml @@ -0,0 +1,40 @@ +<Ui xmlns="http://www.blizzard.com/wow/ui/"> + <Script file="init.lua"/> + <Script file="private.lua"/> + <Script file="ouf.lua"/> + <Script file="events.lua"/> + <Script file="combatevents.lua"/> + <Script file="factory.lua"/> + <Script file="blizzard.lua"/> + <Script file="units.lua"/> + <Script file="colors.lua"/> + + <Script file="elements\additionalpower.lua"/> + <Script file="elements\assistantindicator.lua"/> + <Script file="elements\auras.lua"/> + <Script file="elements\castbar.lua"/> + <Script file="elements\classpower.lua"/> + <Script file="elements\combatindicator.lua"/> + <Script file="elements\grouproleindicator.lua"/> + <Script file="elements\health.lua"/> + <Script file="elements\healthprediction.lua"/> + <Script file="elements\leaderindicator.lua"/> + <Script file="elements\masterlooterindicator.lua"/> + <Script file="elements\portrait.lua"/> + <Script file="elements\power.lua"/> + <Script file="elements\powerprediction.lua"/> + <Script file="elements\pvpindicator.lua"/> + <Script file="elements\questindicator.lua"/> + <Script file="elements\raidroleindicator.lua"/> + <Script file="elements\raidtargetindicator.lua"/> + <Script file="elements\range.lua"/> + <Script file="elements\readycheckindicator.lua"/> + <Script file="elements\restingindicator.lua"/> + <Script file="elements\resurrectindicator.lua"/> + <Script file="elements\runes.lua"/> + <Script file="elements\tags.lua"/> + <Script file="elements\threatindicator.lua"/> + <Script file="elements\totems.lua"/> + + <Script file="finalize.lua"/> +</Ui> diff --git a/oUF/ouf.lua b/oUF/ouf.lua index 9342a92..aba9cba 100644 --- a/oUF/ouf.lua +++ b/oUF/ouf.lua @@ -10,7 +10,7 @@ local Private = oUF.Private local argcheck = Private.argcheck local error = Private.error -local print = Private.print +local print = Private.print --luacheck: no unused local unitExists = Private.unitExists local styles, style = {} @@ -19,31 +19,27 @@ local callback, objects, headers = {}, {}, {} local elements = {} local activeElements = {} +-- ElvUI +local _G = _G +local assert, setmetatable = assert, setmetatable +local unpack, tinsert, tremove = unpack, tinsert, tremove +local next, time, wipe, type = next, time, wipe, type +local select, pairs, ipairs = select, pairs, ipairs +local strupper, strsplit = strupper, strsplit + +local GetNamePlateForUnit = C_NamePlate.GetNamePlateForUnit +local CreateFrame = CreateFrame +local IsLoggedIn = IsLoggedIn +local UnitGUID = UnitGUID +local SetCVar = SetCVar +-- end + local PetBattleFrameHider = CreateFrame('Frame', (global or parent) .. '_PetBattleFrameHider', UIParent, 'SecureHandlerStateTemplate') PetBattleFrameHider:SetAllPoints() PetBattleFrameHider:SetFrameStrata('LOW') RegisterStateDriver(PetBattleFrameHider, 'visibility', '[petbattle] hide; show') --- updating of "invalid" units. -local function enableTargetUpdate(object) - object.onUpdateFrequency = object.onUpdateFrequency or .5 - object.__eventless = true - - local total = 0 - object:SetScript('OnUpdate', function(self, elapsed) - if(not self.unit) then - return - elseif(total > self.onUpdateFrequency) then - self:UpdateAllElements('OnUpdate') - total = 0 - end - - total = total + elapsed - end) -end -Private.enableTargetUpdate = enableTargetUpdate - -local function updateActiveUnit(self, event, unit) +local function updateActiveUnit(self, event) -- Calculate units to work with local realUnit, modUnit = SecureButton_GetUnit(self), SecureButton_GetModifiedUnit(self) @@ -54,16 +50,26 @@ local function updateActiveUnit(self, event, unit) realUnit = 'target' end + if(modUnit == 'pet' and realUnit ~= 'pet') then + modUnit = 'vehicle' + end + if(not unitExists(modUnit)) then return end -- Change the active unit and run a full update. if(Private.UpdateUnits(self, modUnit, realUnit)) then - self:UpdateAllElements('RefreshUnit') + self:UpdateAllElements(event or 'RefreshUnit') return true end end +local function evalUnitAndUpdate(self, event) + if(not updateActiveUnit(self, event)) then + return self:UpdateAllElements(event) + end +end + local function iterateChildren(...) for i = 1, select('#', ...) do local obj = select(i, ...) @@ -110,7 +116,7 @@ for k, v in next, { activeElements[self][name] = true if(element.update) then - table.insert(self.__elements, element.update) + tinsert(self.__elements, element.update) end end end, @@ -128,10 +134,12 @@ for k, v in next, { if(not enabled) then return end local update = elements[name].update - for k, func in next, self.__elements do - if(func == update) then - table.remove(self.__elements, k) - break + if(update) then + for k, func in next, self.__elements do + if(func == update) then + tremove(self.__elements, k) + break + end end end @@ -222,9 +230,7 @@ for k, v in next, { end local function onShow(self) - if(not updateActiveUnit(self, 'OnShow')) then - return self:UpdateAllElements('OnShow') - end + evalUnitAndUpdate(self, 'OnShow') end local function updatePet(self, event, unit) @@ -239,9 +245,8 @@ local function updatePet(self, event, unit) end if(self.unit ~= petUnit) then return end - if(not updateActiveUnit(self, event)) then - return self:UpdateAllElements(event) - end + + evalUnitAndUpdate(self, event) end local function updateRaid(self, event) @@ -253,6 +258,18 @@ local function updateRaid(self, event) end end +-- boss6-8 exsist in some encounters, but unit event registration seems to be +-- completely broken for them, so instead we use OnUpdate to update them. +local eventlessUnits = { + ['boss6'] = true, + ['boss7'] = true, + ['boss8'] = true, +} + +local function isEventlessUnit(unit) + return unit:match('%w+target') or eventlessUnits[unit] +end + local function initObject(unit, style, styleFunc, header, ...) local num = select('#', ...) for i = 1, num do @@ -260,25 +277,34 @@ local function initObject(unit, style, styleFunc, header, ...) local objectUnit = object:GetAttribute('oUF-guessUnit') or unit local suffix = object:GetAttribute('unitsuffix') + -- Handle the case where someone has modified the unitsuffix attribute in + -- oUF-initialConfigFunction. + if(suffix and not objectUnit:match(suffix)) then + objectUnit = objectUnit .. suffix + end + object.__elements = {} object.style = style object = setmetatable(object, frame_metatable) -- Expose the frame through oUF.objects. - table.insert(objects, object) + tinsert(objects, object) -- We have to force update the frames when PEW fires. - object:RegisterEvent('PLAYER_ENTERING_WORLD', object.UpdateAllElements, true) - - -- Handle the case where someone has modified the unitsuffix attribute in - -- oUF-initialConfigFunction. - if(suffix and not objectUnit:match(suffix)) then - objectUnit = objectUnit .. suffix - end + -- It's also important to evaluate units before running an update + -- because sometimes events that are required for unit updates end up + -- not firing because of loading screens. For instance, there's a slight + -- delay between UNIT_EXITING_VEHICLE and UNIT_EXITED_VEHICLE during + -- which a user can go through a loading screen after which the player + -- frame will be stuck with the 'vehicle' unit. + object:RegisterEvent('PLAYER_ENTERING_WORLD', evalUnitAndUpdate, true) + + if(not isEventlessUnit(objectUnit)) then + object:RegisterEvent('UNIT_ENTERED_VEHICLE', evalUnitAndUpdate) + object:RegisterEvent('UNIT_EXITED_VEHICLE', evalUnitAndUpdate) - if(not (suffix == 'target' or objectUnit and objectUnit:match('target'))) then -- We don't need to register UNIT_PET for the player unit. We register it - -- mainly because UNIT_EXITED_VEHICLE and UNIT_ENTERED_VEHICLE doesn't always + -- mainly because UNIT_EXITED_VEHICLE and UNIT_ENTERED_VEHICLE don't always -- have pet information when they fire for party and raid units. if(objectUnit ~= 'player') then object:RegisterEvent('UNIT_PET', updatePet) @@ -290,10 +316,11 @@ local function initObject(unit, style, styleFunc, header, ...) object:SetAttribute('*type1', 'target') object:SetAttribute('*type2', 'togglemenu') - -- Other boss and target units are handled by :HandleUnit(). - if(suffix == 'target') then - enableTargetUpdate(object) + if(isEventlessUnit(objectUnit)) then + oUF:HandleEventlessUnit(object) else + -- No need to enable this for eventless units. + object:SetAttribute('toggleForVehicle', true) oUF:HandleUnit(object) end else @@ -310,10 +337,12 @@ local function initObject(unit, style, styleFunc, header, ...) end if(suffix == 'target') then - enableTargetUpdate(object) + oUF:HandleEventlessUnit(object) end end + activeElements[object] = {} -- ElvUI: styleFunc on headers break before this is set when they try to enable elements before it's set. + Private.UpdateUnits(object, objectUnit) styleFunc(object, objectUnit, not header) @@ -326,7 +355,6 @@ local function initObject(unit, style, styleFunc, header, ...) object:SetScript('OnShow', onShow) end - activeElements[object] = {} for element in next, elements do object:EnableElement(element, objectUnit) end @@ -337,8 +365,8 @@ local function initObject(unit, style, styleFunc, header, ...) -- Make Clique kinda happy if(not object.isNamePlate) then - _G.ClickCastFrames = ClickCastFrames or {} - ClickCastFrames[object] = true + _G.ClickCastFrames = _G.ClickCastFrames or {} + _G.ClickCastFrames[object] = true end end end @@ -367,7 +395,7 @@ Used to add a function to a table to be executed upon unit frame/header initiali * func - function to be added --]] function oUF:RegisterInitCallback(func) - table.insert(callback, func) + tinsert(callback, func) end --[[ oUF:RegisterMetaFunction(name, func) @@ -510,7 +538,7 @@ local function generateName(unit, ...) elseif(party) then append = 'Party' elseif(unit) then - append = unit:gsub('^%l', string.upper) + append = unit:gsub('^%l', strupper) end if(append) then @@ -535,7 +563,7 @@ local function generateName(unit, ...) end do - local function styleProxy(self, frame, ...) + local function styleProxy(self, frame) return walkObject(_G[frame]) end @@ -628,7 +656,7 @@ do local name = overrideName or generateName(nil, ...) local header = CreateFrame('Frame', name, PetBattleFrameHider, template) - header:SetAttribute('template', 'SecureUnitButtonTemplate, SecureHandlerStateTemplate, SecureHandlerEnterLeaveTemplate, SecureHandlerShowHideTemplate, SecureHandlerMouseUpDownTemplate') + header:SetAttribute('template', 'SecureUnitButtonTemplate, SecureHandlerStateTemplate, SecureHandlerEnterLeaveTemplate') for i = 1, select('#', ...), 2 do local att, val = select(i, ...) if(not att) then break end @@ -640,14 +668,43 @@ do header.visibility = visibility -- Expose the header through oUF.headers. - table.insert(headers, header) + tinsert(headers, header) -- We set it here so layouts can't directly override it. header:SetAttribute('initialConfigFunction', initialConfigFunction) + header:SetAttribute('_initialAttributeNames', '_onenter,_onleave,refreshUnitChange,_onstate-vehicleui') + header:SetAttribute('_initialAttribute-_onenter', [[ + local snippet = self:GetAttribute('clickcast_onenter') + if(snippet) then + self:Run(snippet) + end + ]]) + header:SetAttribute('_initialAttribute-_onleave', [[ + local snippet = self:GetAttribute('clickcast_onleave') + if(snippet) then + self:Run(snippet) + end + ]]) + header:SetAttribute('_initialAttribute-refreshUnitChange', [[ + local unit = self:GetAttribute('unit') + if(unit) then + RegisterStateDriver(self, 'vehicleui', '[@' .. unit .. ',unithasvehicleui]vehicle; novehicle') + else + UnregisterStateDriver(self, 'vehicleui') + end + ]]) + header:SetAttribute('_initialAttribute-_onstate-vehicleui', [[ + local unit = self:GetAttribute('unit') + if(newstate == 'vehicle' and unit and UnitPlayerOrPetInRaid(unit) and not UnitTargetsVehicleInRaidUI(unit)) then + self:SetAttribute('toggleForVehicle', false) + else + self:SetAttribute('toggleForVehicle', true) + end + ]]) header:SetAttribute('oUF-headerType', isPetHeader and 'pet' or 'group') - if(Clique) then - SecureHandlerSetFrameRef(header, 'clickcast_header', Clique.header) + if(_G.Clique) then + SecureHandlerSetFrameRef(header, 'clickcast_header', _G.Clique.header) end if(header:GetAttribute('showParty')) then @@ -655,12 +712,12 @@ do end if(visibility) then - local type, list = string.split(' ', visibility, 2) + local type, list = strsplit(' ', visibility, 2) if(list and type == 'custom') then RegisterAttributeDriver(header, 'state-visibility', list) header.visibility = list else - local condition = getCondition(string.split(',', visibility)) + local condition = getCondition(strsplit(',', visibility)) RegisterAttributeDriver(header, 'state-visibility', condition) header.visibility = condition end @@ -682,17 +739,17 @@ oUF implements some of its own attributes. These can be supplied by the layout, * oUF-enableArenaPrep - can be used to toggle arena prep support. Defaults to true (boolean) --]] -function oUF:Spawn(unit, overrideName, noHandle) +function oUF:Spawn(unit, overrideName, overrideTemplate) -- ElvUI adds overrideTemplate argcheck(unit, 2, 'string') if(not style) then return error('Unable to create frame. No styles have been registered.') end unit = unit:lower() local name = overrideName or generateName(unit) - local object = CreateFrame('Button', name, PetBattleFrameHider, 'SecureUnitButtonTemplate') + local object = CreateFrame('Button', name, PetBattleFrameHider, overrideTemplate or 'SecureUnitButtonTemplate') Private.UpdateUnits(object, unit) - if not noHandle then self:DisableBlizzard(unit) end + self:DisableBlizzard(unit) walkObject(object, unit) object:SetAttribute('unit', unit) @@ -715,7 +772,7 @@ function oUF:SpawnNamePlates(namePrefix, nameplateCallback, nameplateCVars) argcheck(nameplateCallback, 3, 'function', 'nil') argcheck(nameplateCVars, 4, 'table', 'nil') if(not style) then return error('Unable to create frame. No styles have been registered.') end - if(oUF_NamePlateDriver) then return error('oUF nameplate driver has already been initialized.') end + if(_G.oUF_NamePlateDriver) then return error('oUF nameplate driver has already been initialized.') end local style = style local prefix = namePrefix or generateName() @@ -734,6 +791,7 @@ function oUF:SpawnNamePlates(namePrefix, nameplateCallback, nameplateCVars) eventHandler:RegisterEvent('NAME_PLATE_UNIT_ADDED') eventHandler:RegisterEvent('NAME_PLATE_UNIT_REMOVED') eventHandler:RegisterEvent('PLAYER_TARGET_CHANGED') + eventHandler:RegisterEvent('UNIT_FACTION') if(IsLoggedIn()) then if(nameplateCVars) then @@ -753,7 +811,7 @@ function oUF:SpawnNamePlates(namePrefix, nameplateCallback, nameplateCVars) end end elseif(event == 'PLAYER_TARGET_CHANGED') then - local nameplate = C_NamePlate.GetNamePlateForUnit('target') + local nameplate = GetNamePlateForUnit('target') if(nameplateCallback) then nameplateCallback(nameplate and nameplate.unitFrame, event, 'target') end @@ -763,8 +821,15 @@ function oUF:SpawnNamePlates(namePrefix, nameplateCallback, nameplateCVars) if(nameplate) then nameplate.unitFrame:UpdateAllElements(event) end + elseif(event == 'UNIT_FACTION' and unit) then + local nameplate = GetNamePlateForUnit(unit) + if(not nameplate) then return end + + if(nameplateCallback) then + nameplateCallback(nameplate.unitFrame, event, unit) + end elseif(event == 'NAME_PLATE_UNIT_ADDED' and unit) then - local nameplate = C_NamePlate.GetNamePlateForUnit(unit) + local nameplate = GetNamePlateForUnit(unit) if(not nameplate) then return end if(not nameplate.unitFrame) then @@ -791,7 +856,7 @@ function oUF:SpawnNamePlates(namePrefix, nameplateCallback, nameplateCVars) -- ForceUpdate calls layout devs have to do themselves nameplate.unitFrame:UpdateAllElements(event) elseif(event == 'NAME_PLATE_UNIT_REMOVED' and unit) then - local nameplate = C_NamePlate.GetNamePlateForUnit(unit) + local nameplate = GetNamePlateForUnit(unit) if(not nameplate) then return end nameplate.unitFrame:SetAttribute('unit', nil) @@ -808,15 +873,15 @@ Used to register an element with oUF. * self - the global oUF object * name - unique name of the element (string) -* update - used to update the element (function?) -* enable - used to enable the element for a given unit frame and unit (function?) -* disable - used to disable the element for a given unit frame (function?) +* update - used to update the element (function) +* enable - used to enable the element for a given unit frame and unit (function) +* disable - used to disable the element for a given unit frame (function) --]] function oUF:AddElement(name, update, enable, disable) argcheck(name, 2, 'string') argcheck(update, 3, 'function', 'nil') - argcheck(enable, 4, 'function', 'nil') - argcheck(disable, 5, 'function', 'nil') + argcheck(enable, 4, 'function') + argcheck(disable, 5, 'function') if(elements[name]) then return error('Element [%s] is already registered.', name) end elements[name] = { @@ -844,4 +909,250 @@ if(global) then else _G[global] = oUF end -end \ No newline at end of file +end + +do -- ShouldSkipAuraUpdate by Blizzard (implemented and heavily modified by Simpy) + local SpellGetVisibilityInfo = SpellGetVisibilityInfo + local SpellIsPriorityAura = SpellIsPriorityAura + local UnitAffectingCombat = UnitAffectingCombat + + local hasValidPlayer = false + local cachedVisibility = {} + local cachedPriority = {} + + local eventFrame = CreateFrame('Frame') + eventFrame:RegisterEvent('PLAYER_REGEN_ENABLED') + eventFrame:RegisterEvent('PLAYER_REGEN_DISABLED') + eventFrame:RegisterEvent('PLAYER_ENTERING_WORLD') + eventFrame:RegisterEvent('PLAYER_LEAVING_WORLD') + + if oUF.isRetail then + eventFrame:RegisterEvent('PLAYER_SPECIALIZATION_CHANGED') + end + + eventFrame:SetScript('OnEvent', function(_, event) + if event == 'PLAYER_ENTERING_WORLD' then + hasValidPlayer = true + elseif event == 'PLAYER_LEAVING_WORLD' then + hasValidPlayer = false + elseif event == 'PLAYER_SPECIALIZATION_CHANGED' then + wipe(cachedVisibility) + elseif event == 'PLAYER_REGEN_ENABLED' or event == 'PLAYER_REGEN_DISABLED' then + wipe(cachedVisibility) + wipe(cachedPriority) + end + end) + + local function VisibilityInfo(spellId) + return SpellGetVisibilityInfo(spellId, UnitAffectingCombat('player') and 'RAID_INCOMBAT' or 'RAID_OUTOFCOMBAT') + end + + local function CachedVisibility(spellId) + if cachedVisibility[spellId] == nil then + if not hasValidPlayer then -- Don't cache the info if the player is not valid since we didn't get a valid result + return VisibilityInfo(spellId) + else + cachedVisibility[spellId] = {VisibilityInfo(spellId)} + end + end + + return unpack(cachedVisibility[spellId]) + end + + local function AllowAura(spellId) + local hasCustom, alwaysShowMine, showForMySpec = CachedVisibility(spellId) + return (not hasCustom) or alwaysShowMine or showForMySpec + end + + local AlwaysAllow = { -- spells could get stuck but it's very rare, this table is for that + [335904] = true -- Doom Winds: Unable to gain effects of Doom Winds + } + + local function AuraIsPriority(spellId) + if AlwaysAllow[spellId] then + return true + end + + if cachedPriority[spellId] == nil then + cachedPriority[spellId] = SpellIsPriorityAura(spellId) + end + + return cachedPriority[spellId] + end + + local function CouldDisplayAura(frame, event, unit, auraInfo) + if auraInfo.isNameplateOnly then + return frame.isNamePlate + elseif auraInfo.isBossAura or AuraIsPriority(auraInfo.spellId) then + return true + elseif auraInfo.isHarmful or auraInfo.isHelpful then + return AllowAura(auraInfo.spellId) + end + + return false + end + + local function ShouldSkipAura(frame, event, unit, fullUpdate, updatedAuras, relevantFunc, ...) + if fullUpdate or fullUpdate == nil then + return false + elseif updatedAuras and relevantFunc then + for _, auraInfo in ipairs(updatedAuras) do + if relevantFunc(frame, event, unit, auraInfo, ...) then + return false + end + end + + return true + end + end + + function oUF:ShouldSkipAuraUpdate(frame, event, unit, fullUpdate, updatedAuras, relevantFunc) + return (not unit or frame.unit ~= unit) or ShouldSkipAura(frame, event, unit, fullUpdate, updatedAuras, relevantFunc or CouldDisplayAura) + end +end + +do -- Event Pooler by Simpy + local pooler = CreateFrame('Frame') + pooler.events = {} + pooler.times = {} + + pooler.delay = 0.1 -- update check rate + pooler.instant = 1 -- seconds since last event + + pooler.run = function(funcs, frame, event, ...) + for _, func in pairs(funcs) do + func(frame, event, ...) + end + end + + pooler.execute = function(event, pool, instant, arg1, ...) + for frame, info in pairs(pool) do + local funcs = info.functions + if instant and funcs then + if event == 'UNIT_AURA' and oUF.isRetail then + local fullUpdate, updatedAuras = ... + if not oUF:ShouldSkipAuraUpdate(frame, event, arg1, fullUpdate, updatedAuras) then + pooler.run(funcs, frame, event, arg1, fullUpdate, updatedAuras) + end + else + pooler.run(funcs, frame, event, arg1, ...) + end + else + local data = funcs and info.data[event] + if data then + if event == 'UNIT_AURA' and oUF.isRetail then + local allowUnit = false + for _, args in ipairs(data) do + local unit, fullUpdate, updatedAuras = unpack(args) + if not oUF:ShouldSkipAuraUpdate(frame, event, unit, fullUpdate, updatedAuras) then + allowUnit = unit + break + end + end + + if allowUnit then + pooler.run(funcs, frame, event, allowUnit) + end + else + local count = #data + local args = count and data[count] + if args then + -- if count > 1 then print(frame:GetDebugName(), event, count, unpack(args)) end + pooler.run(funcs, frame, event, unpack(args)) + end + + end + + wipe(data) + end + end + end + end + + pooler.update = function() + for event, pool in pairs(pooler.events) do + pooler.execute(event, pool) + end + end + + pooler.tracker = function(frame, event, arg1, ...) + -- print('tracker', frame, event, arg1, ...) + + local pool = pooler.events[event] + if pool then + local now = time() + local last = pooler.times[event] + if last and (last + pooler.instant) < now then + pooler.execute(event, pool, true, arg1, ...) + -- print('instant', frame:GetDebugName(), event, arg1) + elseif arg1 ~= nil then -- require arg1, no unitless + local pooled = pool[frame] + if pooled then + if not pooled.data[event] then + pooled.data[event] = {} + end + + tinsert(pooled.data[event], {arg1, ...}) + end + end + + pooler.times[event] = now + end + end + + pooler.onUpdate = function(self, elapsed) + if self.elapsed and self.elapsed > pooler.delay then + pooler.update() + + self.elapsed = 0 + else + self.elapsed = (self.elapsed or 0) + elapsed + end + end + + pooler:SetScript('OnUpdate', pooler.onUpdate) + + function oUF:RegisterEvent(frame, event, func) + -- print('RegisterEvent', frame, event, func) + + if not pooler.events[event] then + pooler.events[event] = {} + pooler.events[event][frame] = {functions={},data={}} + elseif not pooler.events[event][frame] then + pooler.events[event][frame] = {functions={},data={}} + end + + frame:RegisterEvent(event, pooler.tracker) + tinsert(pooler.events[event][frame].functions, func) + end + + function oUF:UnregisterEvent(frame, event, func) + -- print('UnregisterEvent', frame, event, func) + + local pool = pooler.events[event] + if pool then + local pooled = pool[frame] + if pooled then + for i, funct in ipairs(pooled.functions) do + if funct == func then + tremove(pooled.functions, i) + end + end + + if not next(pooled.functions) then + pooled.functions = nil + pooled.data = nil -- clear data + end + + if not next(pooled) then + pool[frame] = nil + end + end + + if not next(pool) then + pooler.events[event] = nil + frame:UnregisterEvent(event, pooler.tracker) + end + end + end +end diff --git a/oUF/private.lua b/oUF/private.lua index 9d31559..cc61027 100644 --- a/oUF/private.lua +++ b/oUF/private.lua @@ -1,4 +1,4 @@ -local parent, ns = ... +local _, ns = ... local Private = ns.oUF.Private function Private.argcheck(value, num, ...) @@ -8,7 +8,7 @@ function Private.argcheck(value, num, ...) if(type(value) == select(i, ...)) then return end end - local types = strjoin(', ', ...) + local types = string.join(', ', ...) local name = debugstack(2,2,0):match(": in function [`<](.-)['>]") error(string.format("Bad argument #%d to '%s' (%s expected, got %s)", num, name, types, type(value)), 3) end @@ -77,4 +77,13 @@ function Private.validateEvent(event) end return isOK -end \ No newline at end of file +end + +function Private.isUnitEvent(event, unit) + local isOK = pcall(validator.RegisterUnitEvent, validator, event, unit) + if(isOK) then + validator:UnregisterEvent(event) + end + + return isOK +end diff --git a/oUF/units.lua b/oUF/units.lua index 517090f..7ea00d7 100644 --- a/oUF/units.lua +++ b/oUF/units.lua @@ -1,21 +1,246 @@ -local parent, ns = ... +local _, ns = ... local oUF = ns.oUF local Private = oUF.Private -local enableTargetUpdate = Private.enableTargetUpdate +local unitExists = Private.unitExists + +local function updateArenaPreparationElements(self, event, elementName, specID) + local element = self[elementName] + if(element and self:IsElementEnabled(elementName)) then + if(element.OverrideArenaPreparation) then + --[[ Override: Health.OverrideArenaPreparation(self, event, specID) + Used to completely override the internal update function for arena preparation. + + * self - the parent object + * event - the event triggering the update (string) + * specID - the specialization ID for the opponent (number) + --]] + --[[ Override: Power.OverrideArenaPreparation(self, event, specID) + Used to completely override the internal update function for arena preparation. + + * self - the parent object + * event - the event triggering the update (string) + * specID - the specialization ID for the opponent (number) + --]] + element.OverrideArenaPreparation(self, event, specID) + return + end + + element:SetMinMaxValues(0, 1) + element:SetValue(1) + if(element.UpdateColorArenaPreparation) then + --[[ Override: Health:UpdateColor(specID) + Used to completely override the internal function for updating the widget's colors + during arena preparation. + + * self - the Health element + * specID - the specialization ID for the opponent (number) + --]] + --[[ Override: Power:UpdateColor(specID) + Used to completely override the internal function for updating the widget's colors + during arena preparation. + + * self - the Power element + * specID - the specialization ID for the opponent (number) + --]] + element:UpdateColorArenaPreparation(specID) + else + -- this section just replicates the color options available to the Health and Power elements + local r, g, b, t, _ + -- if(element.colorPower and elementName == 'Power') then + -- FIXME: no idea if we can get power type here without the unit + if(element.colorClass) then + local _, _, _, _, _, class = GetSpecializationInfoByID(specID) + t = self.colors.class[class] + elseif(element.colorReaction) then + t = self.colors.reaction[2] + elseif(element.colorSmooth) then + _, _, _, _, _, _, r, g, b = unpack(element.smoothGradient or self.colors.smooth) + elseif(element.colorHealth and elementName == 'Health') then + t = self.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 + + if(element.PostUpdateArenaPreparation) then + --[[ Callback: Health:PostUpdateArenaPreparation(event, specID) + Called after the element has been updated during arena preparation. + + * self - the Health element + * event - the event triggering the update (string) + * specID - the specialization ID for the opponent (number) + --]] + --[[ Callback: Power:PostUpdateArenaPreparation(event, specID) + Called after the element has been updated during arena preparation. + + * self - the Power element + * event - the event triggering the update (string) + * specID - the specialization ID for the opponent (number) + --]] + element:PostUpdateArenaPreparation(event, specID) + end + end +end + +local function updateArenaPreparation(self, event) + if(not self:GetAttribute('oUF-enableArenaPrep')) then + return + end + + if(event == 'ARENA_OPPONENT_UPDATE' and not self:IsEnabled()) then + self:Enable() + self:UpdateAllElements('ArenaPreparation') + self:UnregisterEvent(event, updateArenaPreparation) + + -- show elements that don't handle their own visibility + if(self:IsElementEnabled('Auras')) then + if(self.Auras) then self.Auras:Show() end + if(self.Buffs) then self.Buffs:Show() end + if(self.Debuffs) then self.Debuffs:Show() end + end + + if(self.Portrait and self:IsElementEnabled('Portrait')) then + self.Portrait:Show() + end + elseif(event == 'PLAYER_ENTERING_WORLD' and not UnitExists(self.unit)) then + -- semi-recursive call for when the player zones into an arena + if oUF.isRetail then + updateArenaPreparation(self, 'ARENA_PREP_OPPONENT_SPECIALIZATIONS') + end + elseif(event == 'ARENA_PREP_OPPONENT_SPECIALIZATIONS') then + if(InCombatLockdown()) then + -- prevent calling protected functions if entering arena while in combat + self:RegisterEvent('PLAYER_REGEN_ENABLED', updateArenaPreparation, true) + return + end + + if(self.PreUpdate) then + self:PreUpdate(event) + end + + local id = tonumber(self.id) + if(not self:IsEnabled() and GetNumArenaOpponentSpecs() < id) then + -- hide the object if the opponent leaves + self:Hide() + end + + local specID = GetArenaOpponentSpec(id) + if(specID) then + if(self:IsEnabled()) then + -- disable the unit watch so we can forcefully show the object ourselves + self:Disable() + self:RegisterEvent('ARENA_OPPONENT_UPDATE', updateArenaPreparation) + end + + -- update Health and Power (if available) with "fake" data + updateArenaPreparationElements(self, event, 'Health', specID) + updateArenaPreparationElements(self, event, 'Power', specID) + + -- hide all other (relevant) elements (they have no effect during arena prep) + if(self.Auras) then self.Auras:Hide() end + if(self.Buffs) then self.Buffs:Hide() end + if(self.Debuffs) then self.Debuffs:Hide() end + if(self.Castbar) then self.Castbar:Hide() end + if(self.CombatIndicator) then self.CombatIndicator:Hide() end + if(self.PartyIndicator) then self.PartyIndicator:Hide() end + if(self.GroupRoleIndicator) then self.GroupRoleIndicator:Hide() end + if(self.Portrait) then self.Portrait:Hide() end + if(self.PvPIndicator) then self.PvPIndicator:Hide() end + if(self.RaidTargetIndicator) then self.RaidTargetIndicator:Hide() end + + self:Show() + self:UpdateTags() + end + + if(self.PostUpdate) then + self:PostUpdate(event) + end + elseif(event == 'PLAYER_REGEN_ENABLED') then + self:UnregisterEvent(event, updateArenaPreparation) + updateArenaPreparation(self, 'ARENA_PREP_OPPONENT_SPECIALIZATIONS') + end +end -- Handles unit specific actions. function oUF:HandleUnit(object, unit) - local unit = object.unit or unit + unit = object.unit or unit if(unit == 'target') then object:RegisterEvent('PLAYER_TARGET_CHANGED', object.UpdateAllElements, true) elseif(unit == 'mouseover') then object:RegisterEvent('UPDATE_MOUSEOVER_UNIT', object.UpdateAllElements, true) elseif(unit == 'focus') then object:RegisterEvent('PLAYER_FOCUS_CHANGED', object.UpdateAllElements, true) + elseif(unit:match('boss%d?$')) then + object:RegisterEvent('INSTANCE_ENCOUNTER_ENGAGE_UNIT', object.UpdateAllElements, true) + object:RegisterEvent('UNIT_TARGETABLE_CHANGED', object.UpdateAllElements) elseif(unit:match('arena%d?$')) then object:RegisterEvent('ARENA_OPPONENT_UPDATE', object.UpdateAllElements, true) - elseif(unit and unit:match('%w+target')) then - enableTargetUpdate(object) + if oUF.isRetail then + object:RegisterEvent('ARENA_PREP_OPPONENT_SPECIALIZATIONS', updateArenaPreparation, true) + end + object:SetAttribute('oUF-enableArenaPrep', true) + -- the event handler only fires for visible frames, so we have to hook it for arena prep + object:HookScript('OnEvent', updateArenaPreparation) end -end \ No newline at end of file +end + +local eventlessObjects = {} +local onUpdates = {} + +local function createOnUpdate(timer) + if(not onUpdates[timer]) then + local frame = CreateFrame('Frame') + local objects = eventlessObjects[timer] + + frame:SetScript('OnUpdate', function(self, elapsed) + self.elapsed = (self.elapsed or 0) + elapsed + if(self.elapsed > timer) then + for _, object in next, objects do + if(object.unit and unitExists(object.unit)) then + object:UpdateAllElements('OnUpdate') + end + end + + self.elapsed = 0 + end + end) + + onUpdates[timer] = frame + end +end + +function oUF:HandleEventlessUnit(object) + object.__eventless = true + + local timer = object.onUpdateFrequency or 0.5 + + -- Remove it, in case it's registered with another timer previously + for t, objects in next, eventlessObjects do + if(t ~= timer) then + for i, obj in next, objects do + if(obj == object) then + table.remove(objects, i) + break + end + end + end + end + + if(not eventlessObjects[timer]) then eventlessObjects[timer] = {} end + table.insert(eventlessObjects[timer], object) + + createOnUpdate(timer) +end diff --git a/oUF_Simple/core/functions.lua b/oUF_Simple/core/functions.lua index 7fd4540..c6ffb56 100644 --- a/oUF_Simple/core/functions.lua +++ b/oUF_Simple/core/functions.lua @@ -693,4 +693,66 @@ local function CreateEneryTicker(self) return s end -L.F.CreateEneryTicker = CreateEneryTicker \ No newline at end of file +L.F.CreateEneryTicker = CreateEneryTicker + +local function RunesPostUpdate(self, runemap) + local bar = self + local runemap = runemap + + for i, runeId in next, runemap do + local isReady = select(3, GetRuneCooldown(runeId)) + + if isReady then + bar[i]:SetAlpha(1) + else + bar[i]:SetAlpha(0.5) + end + end +end + +--CreateRunesBar +local function CreateRunesBar(self) + if not self.cfg.runebar or not self.cfg.runebar.enabled then return end + if(select(2, UnitClass('player')) ~= 'DEATHKNIGHT') then return end + + local s = CreateFrame("Frame", self:GetName().."RuneBar", self) + local w, h = unpack(self.cfg.runebar.size) + -- Runes + -- s:SetFrameLevel(self.Health:GetFrameLevel() + 1) + s:SetSize(w, h) + SetPoint(s,self,self.cfg.runebar.point) + + -- s:SetHeight(6) + -- s:SetPoint("TOPLEFT", self.Health, 0, 10) + -- s:SetPoint("TOPRIGHT", self.Health, 0, 10) + + --backdrop + CreateBackdrop(s) + + for i = 1, 6 do + s[i] = CreateFrame("StatusBar", self:GetName().."Rune"..i, s) + s[i]:SetHeight(s:GetHeight()) + s[i]:SetStatusBarTexture(L.C.textures.statusbar) + s[i]:SetStatusBarColor(self.Power:GetStatusBarColor()) + + s[i].bg = s[i]:CreateTexture(nil, "BACKGROUND") + s[i].bg:SetAllPoints(s[i]) + s[i].bg:SetTexture(L.C.textures.statusbar) + s[i].bg:SetAlpha(0.4) + --attributes + s[i].bg.multiplier = L.C.colors.bgMultiplier + + if i == 1 then + s[i]:SetWidth(w/6) + s[i]:SetPoint("LEFT", s, "LEFT", 0, 0) + else + s[i]:SetWidth(w/6 - 2) + s[i]:SetPoint("LEFT", s[i-1], "RIGHT", 2, 0) + end + end + + s.PostUpdate = RunesPostUpdate + s.colorSpec = true + return s +end +L.F.CreateRunesBar = CreateRunesBar \ No newline at end of file diff --git a/oUF_Simple/core/style.lua b/oUF_Simple/core/style.lua index 7483279..4231dc8 100644 --- a/oUF_Simple/core/style.lua +++ b/oUF_Simple/core/style.lua @@ -37,6 +37,7 @@ local function CreateStyle(self) L.F.ToggleSmooth(self, L.C.smooth) self.Castbar = L.F.CreateCastBar(self) self.rClassBar = L.F.CreateClassBar(self) + self.Runes = L.F.CreateRunesBar(self) -- self.AlternativePower = L.F.CreateAltPowerBar(self) -- self.AdditionalPower = L.F.CreateAdditionalPowerBar(self) self.Swing = L.F.CreateSwing(self) diff --git a/oUF_Simple/oUF_Simple.toc b/oUF_Simple/oUF_Simple.toc index d9cfe55..e363171 100644 --- a/oUF_Simple/oUF_Simple.toc +++ b/oUF_Simple/oUF_Simple.toc @@ -1,5 +1,5 @@ -## Interface: 20504 -## Title: oUF_Simple |cff1a9fc0BCC|r +## Interface: 30400 +## Title: oUF_Simple |cff1a9fc0WLK|r ## Author: zork ## Notes: Simple oUF layout ## Dependencies: oUF, rLib, oUF_SimpleConfig diff --git a/oUF_SimpleConfig/oUF_SimpleConfig.toc b/oUF_SimpleConfig/oUF_SimpleConfig.toc index ae05426..a31a237 100644 --- a/oUF_SimpleConfig/oUF_SimpleConfig.toc +++ b/oUF_SimpleConfig/oUF_SimpleConfig.toc @@ -1,6 +1,6 @@ -## Interface: 20504 +## Interface: 30400 ## Author: zork -## Title: oUF_SimpleConfig |cff1a9fc0BCC|r +## Title: oUF_SimpleConfig |cff1a9fc0WLK|r ## Notes: oUF_Simple config ## RequiredDeps: rLib diff --git a/oUF_SimpleConfig/player.lua b/oUF_SimpleConfig/player.lua index 18b9412..ffe0f47 100644 --- a/oUF_SimpleConfig/player.lua +++ b/oUF_SimpleConfig/player.lua @@ -64,8 +64,7 @@ L.C.player = { enabled = true, point = {"RIGHT",-2,0}, size = 8, - --tag = "[perpp]", - tag = "[curmana]", + tag = "[curpp]", font = L.C.fonts.expressway, }, }, @@ -121,6 +120,11 @@ L.C.player = { color = {0,0,0,1} }, }, + runebar = { + enabled = true, + size = {265,5}, + point = {"BOTTOM","TOP",0,4}, --if no relativeTo is given the frame base will be the relativeTo reference + }, --altpowerbar altpowerbar = { enabled = false, diff --git a/rButtonAura/rButtonAura.toc b/rButtonAura/rButtonAura.toc index 797ef03..03bfb54 100644 --- a/rButtonAura/rButtonAura.toc +++ b/rButtonAura/rButtonAura.toc @@ -1,5 +1,5 @@ -## Interface: 20504 -## Title: rButtonAura |cff1a9fc0BCC|r +## Interface: 30400 +## Title: rButtonAura |cff1a9fc0WLK|r ## Author: zork ## Notes: Highlights action buttons when a matching unit aura is present ## RequiredDeps: rLib diff --git a/rButtonAura_Zork/rButtonAura_Zork.toc b/rButtonAura_Zork/rButtonAura_Zork.toc index 012c1d0..02042a9 100644 --- a/rButtonAura_Zork/rButtonAura_Zork.toc +++ b/rButtonAura_Zork/rButtonAura_Zork.toc @@ -1,5 +1,5 @@ -## Interface: 20504 -## Title: rButtonAura_Zork |cff1a9fc0BCC|r +## Interface: 30400 +## Title: rButtonAura_Zork |cff1a9fc0WLK|r ## Author: zork ## Notes: Zork's config for rButtonAura ## RequiredDeps: rButtonAura diff --git a/rChatPlus/rChatPlus.toc b/rChatPlus/rChatPlus.toc index 3565ce5..3781142 100644 --- a/rChatPlus/rChatPlus.toc +++ b/rChatPlus/rChatPlus.toc @@ -1,6 +1,6 @@ -## Interface: 20504 +## Interface: 30400 ## Author: rawoil -## Title: rChat|cffff7d0aPlus|r |cff1a9fc0BCC|r +## Title: rChat|cffff7d0aPlus|r |cff1a9fc0WLK|r ## Notes: Chat enhancements advanced ## RequiredDeps: rLib, oUF_SimpleConfig diff --git a/rFilter/rFilter.toc b/rFilter/rFilter.toc index 909dd1a..b1cef74 100644 --- a/rFilter/rFilter.toc +++ b/rFilter/rFilter.toc @@ -1,5 +1,5 @@ -## Interface: 20504 -## Title: rFilter |cff1a9fc0BCC|r +## Interface: 30400 +## Title: rFilter |cff1a9fc0WLK|r ## Author: zork ## Notes: Buff, debuff, raidbuff and cooldown filter. Eats puppies! ## Dependencies: rLib diff --git a/rFilter_Zork/rFilter_Zork.toc b/rFilter_Zork/rFilter_Zork.toc index 13aa5ff..2c92bb9 100644 --- a/rFilter_Zork/rFilter_Zork.toc +++ b/rFilter_Zork/rFilter_Zork.toc @@ -1,6 +1,6 @@ -## Interface: 20504 +## Interface: 30400 ## Author: zork -## Title: rFilter_Zork |cff1a9fc0BCC|r +## Title: rFilter_Zork |cff1a9fc0WLK|r ## Notes: Layout and optional theme for rFilter ## RequiredDeps: rLib, rFilter ## OptionalDeps: rButtonTemplate, rButtonTemplate_Zork diff --git a/rSkin/rSkin.toc b/rSkin/rSkin.toc index 35d2219..4c7c9f4 100644 --- a/rSkin/rSkin.toc +++ b/rSkin/rSkin.toc @@ -1,6 +1,6 @@ -## Interface: 20504 +## Interface: 30400 ## Author: rawoil -## Title: rSkin |cff1a9fc0BCC|r +## Title: rSkin |cff1a9fc0WLK|r ## Notes: Reskin other addons to fit zorkui's L&F ## RequiredDeps: rLib, rButtonTemplate_Zork, oUF_SimpleConfig ## OptionalDeps: DBM-Core, WeakAuras, ls_Toasts, Details, BigWigs_Plugins, ThreatClassic2, Dominos, MerInspect diff --git a/rStatusButton/core.lua b/rStatusButton/core.lua index af8065e..db95976 100644 --- a/rStatusButton/core.lua +++ b/rStatusButton/core.lua @@ -49,7 +49,7 @@ local function OnEnter(self) GameTooltip:SetOwner(self, "ANCHOR_TOP") GameTooltip:AddLine(self:GetName(), 1, 0.5, 0, 1, 1, 1) --experience - if UnitLevel("player") < MAX_PLAYER_LEVEL then -- classic-disable --and not IsXPUserDisabled() then + if UnitLevel("player") < 70 then -- MAX_PLAYER_LEVEL then -- classic-disable --and not IsXPUserDisabled() then local cur, max = UnitXP("player"), UnitXPMax("player") local lvl = UnitLevel("player") local rested = GetXPExhaustion() or 0