diff --git a/oUF/elements/happinessindicator.lua b/oUF/elements/happinessindicator.lua new file mode 100644 index 0000000..b6f56c2 --- /dev/null +++ b/oUF/elements/happinessindicator.lua @@ -0,0 +1,116 @@ +--[[ +# Element: HappinessIndicator + +Handles the visibility and updating of player pet happiness. + +## Widget + +HappinessIndicator - A `Texture` used to display the current happiness level. +The element works by changing the texture's vertex color. + +## Notes + +A default texture will be applied if the widget is a Texture and doesn't have a texture or a color set. + +## Examples + + -- Position and size + local HappinessIndicator = self:CreateTexture(nil, 'OVERLAY') + HappinessIndicator:SetSize(16, 16) + HappinessIndicator:SetPoint('TOPRIGHT', self) + + -- Register it with oUF + self.HappinessIndicator = HappinessIndicator +--]] + +local _, ns = ... +local oUF = ns.oUF + +local GetPetHappiness = GetPetHappiness +local HasPetUI = HasPetUI + +local function Update(self, event, unit) + if(not unit or self.unit ~= unit) then return end + + local element = self.HappinessIndicator + + --[[ Callback: HappinessIndicator:PreUpdate() + Called before the element has been updated. + + * self - the ComboPoints element + --]] + if(element.PreUpdate) then + element:PreUpdate() + end + + local _, hunterPet = HasPetUI() + local happiness, damagePercentage = GetPetHappiness() + + if(hunterPet and happiness) then + if(happiness == 1) then + element:SetTexCoord(0.375, 0.5625, 0, 0.359375) + elseif(happiness == 2) then + element:SetTexCoord(0.1875, 0.375, 0, 0.359375) + elseif(happiness == 3) then + element:SetTexCoord(0, 0.1875, 0, 0.359375) + end + + element:Show() + else + return element:Hide() + end + + --[[ Callback: HappinessIndicator:PostUpdate(role) + Called after the element has been updated. + + * self - the ComboPoints element + * unit - the unit for which the update has been triggered (string) + * happiness - the numerical happiness value of the pet (1 = unhappy, 2 = content, 3 = happy) (number) + * damagePercentage - damage modifier, happiness affects this (unhappy = 75%, content = 100%, happy = 125%) (number) + --]] + if(element.PostUpdate) then + return element:PostUpdate(unit, happiness, damagePercentage) + end +end + +local function Path(self, ...) + --[[ Override: HappinessIndicator.Override(self, event, ...) + Used to completely override the internal update function. + + * self - the parent object + * event - the event triggering the update (string) + * ... - the arguments accompanying the event + --]] + return (self.HappinessIndicator.Override or Update) (self, ...) +end + +local function ForceUpdate(element) + return Path(element.__owner, 'ForceUpdate', element.__owner.unit) +end + +local function Enable(self) + local element = self.HappinessIndicator + if(element) then + element.__owner = self + element.ForceUpdate = ForceUpdate + + self:RegisterEvent('UNIT_HAPPINESS', Path) + + if(element:IsObjectType('Texture') and not element:GetTexture()) then + element:SetTexture([[Interface\PetPaperDollFrame\UI-PetHappiness]]) + end + + return true + end +end + +local function Disable(self) + local element = self.HappinessIndicator + if(element) then + element:Hide() + + self:UnregisterEvent('UNIT_HAPPINESS', Path) + end +end + +oUF:AddElement('HappinessIndicator', Path, Enable, Disable) diff --git a/oUF/elements/masterlooterindicator.lua b/oUF/elements/masterlooterindicator.lua new file mode 100644 index 0000000..ad49362 --- /dev/null +++ b/oUF/elements/masterlooterindicator.lua @@ -0,0 +1,124 @@ +--[[ +# Element: Master Looter Indicator + +Toggles the visibility of an indicator based on the unit's master looter status. + +## Widget + +MasterLooterIndicator - Any UI widget. + +## Notes + +A default texture will be applied if the widget is a Texture and doesn't have a texture or a color set. + +## Examples + + -- Position and size + local MasterLooterIndicator = self:CreateTexture(nil, 'OVERLAY') + MasterLooterIndicator:SetSize(16, 16) + MasterLooterIndicator:SetPoint('TOPRIGHT', self) + + -- Register it with oUF + self.MasterLooterIndicator = MasterLooterIndicator +--]] + +local _, ns = ... +local oUF = ns.oUF + +local GetLootMethod = GetLootMethod +local UnitInParty = UnitInParty +local UnitInRaid = UnitInRaid +local UnitIsUnit = UnitIsUnit + +local function Update(self, event) + local unit = self.unit + local element = self.MasterLooterIndicator + + --[[ Callback: MasterLooterIndicator:PreUpdate() + Called before the element has been updated. + + * self - the MasterLooterIndicator element + --]] + if(element.PreUpdate) then + element:PreUpdate() + end + + local isShown = false + if(UnitInParty(unit) or UnitInRaid(unit)) then + local method, partyIndex, raidIndex = GetLootMethod() + if(method == 'master') then + local mlUnit + if(partyIndex) then + if(partyIndex == 0) then + mlUnit = 'player' + else + mlUnit = 'party' .. partyIndex + end + elseif(raidIndex) then + mlUnit = 'raid' .. raidIndex + end + + isShown = mlUnit and UnitIsUnit(unit, mlUnit) + end + end + + if isShown then + element:Show() + else + element:Hide() + end + + --[[ Callback: MasterLooterIndicator:PostUpdate(isShown) + Called after the element has been updated. + + * self - the MasterLooterIndicator element + * isShown - indicates whether the element is shown (boolean) + --]] + if(element.PostUpdate) then + return element:PostUpdate(isShown) + end +end + +local function Path(self, ...) + --[[ Override: MasterLooterIndicator.Override(self, event, ...) + Used to completely override the internal update function. + + * self - the parent object + * event - the event triggering the update (string) + * ... - the arguments accompanying the event + --]] + return (self.MasterLooterIndicator.Override or Update) (self, ...) +end + +local function ForceUpdate(element) + return Path(element.__owner, 'ForceUpdate') +end + +local function Enable(self, unit) + local element = self.MasterLooterIndicator + if(element) then + element.__owner = self + element.ForceUpdate = ForceUpdate + + self:RegisterEvent('PARTY_LOOT_METHOD_CHANGED', Path, true) + self:RegisterEvent('GROUP_ROSTER_UPDATE', Path, true) + + if(element:IsObjectType('Texture') and not element:GetTexture()) then + element:SetTexture([[Interface\GroupFrame\UI-Group-MasterLooter]]) + end + + return true + end +end + +local function Disable(self) + local element = self.MasterLooterIndicator + if(element) then + element:Hide() + + self:UnregisterEvent('PARTY_LOOT_METHOD_CHANGED', Path) + self:UnregisterEvent('GROUP_ROSTER_UPDATE', Path) + end +end + +oUF:AddElement('MasterLooterIndicator', Path, Enable, Disable) diff --git a/oUF_Simple/core/functions.lua b/oUF_Simple/core/functions.lua index 82a1f8f..7fd4540 100644 --- a/oUF_Simple/core/functions.lua +++ b/oUF_Simple/core/functions.lua @@ -680,4 +680,17 @@ local function CreateTrinket(self) return s end -L.F.CreateTrinket = CreateTrinket \ No newline at end of file +L.F.CreateTrinket = CreateTrinket + +--CreateEneryTicker +local function CreateEneryTicker(self) + if not self.cfg.emr then return end + + local s = CreateFrame("StatusBar", nil, self.Power) + s:SetFrameLevel(self.Power:GetFrameLevel() + 3) + s:SetAllPoints() + s.Spark = s:CreateTexture(nil, "OVERLAY") + + return s +end +L.F.CreateEneryTicker = CreateEneryTicker \ No newline at end of file diff --git a/oUF_Simple/core/style.lua b/oUF_Simple/core/style.lua index a1e6d80..7483279 100644 --- a/oUF_Simple/core/style.lua +++ b/oUF_Simple/core/style.lua @@ -50,5 +50,6 @@ local function CreateStyle(self) self.RaidRoleIndicator = L.F.CreateRaidRoleIndicator(self) self.Range = L.F.CreateRange(self) self.Trinket = L.F.CreateTrinket(self) + self.EnergyManaRegen = L.F.CreateEneryTicker(self) end L.F.CreateStyle = CreateStyle \ No newline at end of file diff --git a/oUF_Simple/modules/oUF_EnergyManaRegen.lua b/oUF_Simple/modules/oUF_EnergyManaRegen.lua new file mode 100644 index 0000000..bc7d60f --- /dev/null +++ b/oUF_Simple/modules/oUF_EnergyManaRegen.lua @@ -0,0 +1,174 @@ +local A, L = ... +local oUF = L.oUF or oUF +if not oUF then return end + +local _G = _G +local GetTime = GetTime +local UnitPower = UnitPower +local UnitClass = UnitClass +local tonumber = tonumber +local UnitPowerType = UnitPowerType +local UnitPowerMax = UnitPowerMax +local GetSpellPowerCost = GetSpellPowerCost + +local LastTickTime = GetTime() +local TickDelay = 2.025 -- Average tick time is slightly over 2 seconds +local CurrentValue = UnitPower('player') +local LastValue = CurrentValue +local myClass = select(2, UnitClass('player')) +local Mp5Delay = 5 +local Mp5DelayWillEnd = nil +local Mp5IgnoredSpells = { + [18182] = true, -- Improved Life Tap 1 + [18183] = true, -- Improved Life Tap 2 + [1454] = true, -- Life Tap 1 + [1455] = true, -- Life Tap 2 + [1456] = true, -- Life Tap 3 + [11687] = true, -- Life Tap 4 + [11688] = true, -- Life Tap 5 + [11689] = true, -- Life Tap 6 +} + +-- Sets tick time to the last possible time based on the last tick +local UpdateTickTime = function(now) + LastTickTime = now - ((now - LastTickTime) % TickDelay) +end + +local Update = function(self, elapsed) + local element = self.EnergyManaRegen + element.sinceLastUpdate = (element.sinceLastUpdate or 0) + (tonumber(elapsed) or 0) + + if element.sinceLastUpdate > 0.01 then + local powerType = UnitPowerType('player') + if powerType ~= Enum.PowerType.Energy and powerType ~= Enum.PowerType.Mana then + element.Spark:Hide() + return + end + + CurrentValue = UnitPower('player', powerType) + local MaxPower = UnitPowerMax('player', powerType) + local Now = GetTime() + + if powerType == Enum.PowerType.Mana then + if CurrentValue >= MaxPower then + element:SetValue(0) + element.Spark:Hide() + return + end + + -- Sync last tick time after 5 seconds are over + if Mp5DelayWillEnd and Mp5DelayWillEnd < Now then + Mp5DelayWillEnd = nil + UpdateTickTime(Now) + end + elseif powerType == Enum.PowerType.Energy then + -- If energy is not full we just wait for the next tick + if Now >= LastTickTime + TickDelay and CurrentValue >= MaxPower then + UpdateTickTime(Now) + end + end + + if Mp5DelayWillEnd and powerType == Enum.PowerType.Mana then + -- Show 5 second indicator + element.Spark:Show() + element:SetMinMaxValues(0, Mp5Delay) + element.Spark:SetVertexColor(1, 1, 0, 1) + element:SetValue(Mp5DelayWillEnd - Now) + else + -- Show tick indicator + element.Spark:Show() + element:SetMinMaxValues(0, TickDelay) + element.Spark:SetVertexColor(1, 1, 1, 1) + element:SetValue(Now - LastTickTime) + end + + element.sinceLastUpdate = 0 + end +end + +local OnUnitPowerUpdate = function() + local powerType = UnitPowerType('player') + if powerType ~= Enum.PowerType.Mana and powerType ~= Enum.PowerType.Energy then + return + end + + -- We also register ticks from mp5 gear within the 5-second-rule to get a more accurate sync later. + -- Unfortunately this registers a tick when a mana pot or life tab is used. + local CurrentValue = UnitPower('player', powerType) + if CurrentValue > LastValue then + LastTickTime = GetTime() + end + LastValue = CurrentValue +end + +local OnUnitSpellcastSucceeded = function(_, _, _, _, spellID) + local powerType = UnitPowerType('player') + if powerType ~= Enum.PowerType.Mana then + return + end + + local spellCost = false + local costTable = GetSpellPowerCost(spellID) + for _, costInfo in next, costTable do + if costInfo.cost then + spellCost = true + end + end + + if not spellCost or Mp5IgnoredSpells[spellID] then + return + end + + Mp5DelayWillEnd = GetTime() + 5 +end + +local Path = function(self, ...) + return (self.EnergyManaRegen.Override or Update) (self, ...) +end + +local Enable = function(self, unit) + local element = self.EnergyManaRegen + local Power = self.Power + + if (unit == 'player') and element and Power and myClass ~= 'WARRIOR' then + element.__owner = self + + if(element:IsObjectType('StatusBar')) then + element:SetStatusBarTexture([[Interface\Buttons\WHITE8X8]]) + element:GetStatusBarTexture():SetAlpha(0) + element:SetMinMaxValues(0, 2) + end + + local spark = element.Spark + if(spark and spark:IsObjectType('Texture')) then + spark:SetTexture([[Interface\CastingBar\UI-CastingBar-Spark]]) + spark:SetSize(5, 5) + spark:SetBlendMode('ADD') + spark:SetPoint('CENTER', element:GetStatusBarTexture(), 'RIGHT') + end + + self:RegisterEvent('UNIT_SPELLCAST_SUCCEEDED', OnUnitSpellcastSucceeded) + self:RegisterEvent('UNIT_POWER_UPDATE', OnUnitPowerUpdate) + + element:SetScript('OnUpdate', function(_, elapsed) Path(self, elapsed) end) + + return true + end +end + +local Disable = function(self) + local element = self.EnergyManaRegen + local Power = self.Power + + if (Power) and (element) then + self:UnregisterEvent('UNIT_SPELLCAST_SUCCEEDED', OnUnitSpellcastSucceeded) + self:UnregisterEvent('UNIT_POWER_UPDATE', OnUnitPowerUpdate) + + element.Spark:Hide() + element:SetScript('OnUpdate', nil) + + return false + end +end + +oUF:AddElement('EnergyManaRegen', Path, Enable, Disable) \ No newline at end of file diff --git a/oUF_Simple/oUF_Simple.toc b/oUF_Simple/oUF_Simple.toc index e2f4812..8f2cc4c 100644 --- a/oUF_Simple/oUF_Simple.toc +++ b/oUF_Simple/oUF_Simple.toc @@ -10,6 +10,7 @@ modules\oUF_DebuffHighlight.lua modules\oUF_Swing.lua modules\oUF_RaidDebuffs.lua modules\oUF_Trinkets.lua +modules\oUF_EnergyManaRegen.lua core\init.lua core\functions.lua diff --git a/oUF_SimpleConfig/player.lua b/oUF_SimpleConfig/player.lua index e5fb980..cb09511 100644 --- a/oUF_SimpleConfig/player.lua +++ b/oUF_SimpleConfig/player.lua @@ -134,4 +134,6 @@ L.C.player = { orientation = "VERTICAL", colorPower = true, }, + --energymanaregen + emr = true, }