From de2e88029e9652f1caf94b6833c5b1c96d8f56d4 Mon Sep 17 00:00:00 2001 From: Emlembow <36314674+Emlembow@users.noreply.github.com> Date: Thu, 29 Aug 2024 10:39:32 -0700 Subject: [PATCH] Protection Paladin Rotation Enhancements Changes: - Added new spells: HandOfReckoning, EyeOfTyr, DivineSteed, and Rebuke. - Introduced helper functions: GetEnemiesInRange(range) and GetLowestThreatEnemy(). - Added new APLs for Interrupt and Threat Management. - Enhanced main rotation logic with dynamic target selection and threat management. - Defensive APL improvements, including the addition of EyeOfTyr for damage reduction. Improvements: - Incorporated range checks (IsWithinCombatDistance) for more accurate spell casting. - Improved HammerOfWrath conditions for better usage based on target health and active buffs. - Optimized Default APL for better resource management and cooldown handling. Bug Fixes: - Fixed target selection issues when current target is dead or out of range. - Improved performance by refining spell casting logic and target selection. Miscellaneous: - Added mount detection to pause rotation while mounted. - Enhanced code structure, readability, and added more comments for better understanding. --- .DS_Store | Bin 6148 -> 6148 bytes ProtPaladin.lua | 145 ++++++++++++++++++++++++++++++++++-------------- 2 files changed, 104 insertions(+), 41 deletions(-) diff --git a/.DS_Store b/.DS_Store index 5008ddfcf53c02e82d7eee2e57c38e5672ef89f6..26000199749cfd9bece574a6fcec1aaae0827b1d 100644 GIT binary patch delta 282 zcmZoMXfc=|#>B`mF;Q%yo}wrd0|Nsi1A_nqLjXe}Lk@>7APf<$u}G8wXgJP<1%XmKe}4@5nK7ZH~GK`kfX%#Df0Y?BQ{ST=KWaB~2C bzA^DT^JIPzMOKg(6($>s2ygZf*~1I~&`>zr delta 70 zcmZoMXfc=|#>AjHu~2NHo+1YW5HK<@2yA}HsK&PW17jECW_AvK4xj>{$am(+{342+ UKzW7)kiy9(Jj$D6L{=~Z075el%K!iX diff --git a/ProtPaladin.lua b/ProtPaladin.lua index 101d64f..609d039 100644 --- a/ProtPaladin.lua +++ b/ProtPaladin.lua @@ -10,120 +10,183 @@ local ShieldOfTheRighteous = SpellBook:GetSpell(53600) local Judgment = SpellBook:GetSpell(275779) local HammerOfWrath = SpellBook:GetSpell(24275) local AvengersShield = SpellBook:GetSpell(31935) -local HammerOfTheRighteous = SpellBook:GetSpell(53595) local BlessedHammer = SpellBook:GetSpell(204019) local WordOfGlory = SpellBook:GetSpell(85673) -local GuardianOfAncientKings = SpellBook:GetSpell(86659) -local ArdentDefender = SpellBook:GetSpell(31850) local AvengingWrath = SpellBook:GetSpell(31884) -local LayOnHands = SpellBook:GetSpell(633) local DivineShield = SpellBook:GetSpell(642) +local HandOfReckoning = SpellBook:GetSpell(62124) +local EyeOfTyr = SpellBook:GetSpell(387174) +local DivineSteed = SpellBook:GetSpell(190784) +local Rebuke = SpellBook:GetSpell(96231) -- Buffs local ConsecrationBuff = SpellBook:GetSpell(188370) local ShiningLightBuff = SpellBook:GetSpell(327510) +-- Helper Functions +local function GetEnemiesInRange(range) + local count = 0 + Bastion.UnitManager:EnumEnemies(function(unit) + if unit:GetDistance(Player) <= range and unit:IsAffectingCombat() then + count = count + 1 + end + end) + return count +end + +local function GetLowestThreatEnemy() + local lowestThreatUnit = nil + local lowestThreat = math.huge + + Bastion.UnitManager:EnumEnemies(function(unit) + if unit:IsAffectingCombat() and unit:GetDistance(Player) <= 30 then + local _, _, scaledPercent = UnitDetailedThreatSituation(Player:GetOMToken(), unit:GetOMToken()) + if scaledPercent and scaledPercent < lowestThreat then + lowestThreatUnit = unit + lowestThreat = scaledPercent + end + end + end) + + return lowestThreatUnit +end + -- Create APLs local DefaultAPL = Bastion.APL:New('default') local CooldownAPL = Bastion.APL:New('cooldown') local DefensiveAPL = Bastion.APL:New('defensive') +local InterruptAPL = Bastion.APL:New('interrupt') +local ThreatAPL = Bastion.APL:New('threat') --- Defensive APL -DefensiveAPL:AddSpell( - ShieldOfTheRighteous:CastableIf(function(self) - return self:IsKnownAndUsable() and Player:GetPower() >= 3 and Player:GetHP() < 80 - end):SetTarget(Player) +-- Interrupt APL +InterruptAPL:AddSpell( + Rebuke:CastableIf(function(self) + return self:IsKnownAndUsable() and Target:IsCasting() and Target:IsInterruptible() and Player:IsWithinCombatDistance(Target, 5) + end):SetTarget(Target) ) -DefensiveAPL:AddSpell( - WordOfGlory:CastableIf(function(self) - return self:IsKnownAndUsable() and (Player:GetPower() >= 3 or Player:GetAuras():FindMy(ShiningLightBuff):IsUp()) and Player:GetHP() < 50 - end):SetTarget(Player) +InterruptAPL:AddSpell( + AvengersShield:CastableIf(function(self) + return self:IsKnownAndUsable() and Target:IsCasting() and Target:IsInterruptible() and Rebuke:GetCooldownRemaining() > 0 and Player:IsWithinCombatDistance(Target, 30) + end):SetTarget(Target) +) + +-- Threat Management APL +ThreatAPL:AddSpell( + HandOfReckoning:CastableIf(function(self) + return self:IsKnownAndUsable() and Target:GetDistance(Player) > 10 and Target:GetDistance(Player) <= 30 + end):SetTarget(Target) ) +ThreatAPL:AddSpell( + AvengersShield:CastableIf(function(self) + return self:IsKnownAndUsable() and GetEnemiesInRange(30) > 1 and Player:IsWithinCombatDistance(Target, 30) + end):SetTarget(Target) +) + +-- Defensive APL DefensiveAPL:AddSpell( - GuardianOfAncientKings:CastableIf(function(self) - return self:IsKnownAndUsable() and Player:GetHP() < 40 + ShieldOfTheRighteous:CastableIf(function(self) + return self:IsKnownAndUsable() and Player:GetPower() >= 3 and Player:GetHP() < 80 and Player:IsWithinCombatDistance(Target, 5) end):SetTarget(Player) ) DefensiveAPL:AddSpell( - ArdentDefender:CastableIf(function(self) - return self:IsKnownAndUsable() and Player:GetHP() < 30 + WordOfGlory:CastableIf(function(self) + return self:IsKnownAndUsable() and (Player:GetPower() >= 3 or Player:GetAuras():FindMy(ShiningLightBuff):IsUp()) and Player:GetHP() < 50 end):SetTarget(Player) ) DefensiveAPL:AddSpell( - LayOnHands:CastableIf(function(self) - return self:IsKnownAndUsable() and Player:GetHP() < 20 + EyeOfTyr:CastableIf(function(self) + return self:IsKnownAndUsable() and Player:GetHP() < 60 and GetEnemiesInRange(8) >= 3 end):SetTarget(Player) ) -- Cooldown APL CooldownAPL:AddSpell( AvengingWrath:CastableIf(function(self) - return self:IsKnownAndUsable() and Player:GetEnemies(8) >= 3 + return self:IsKnownAndUsable() and GetEnemiesInRange(8) >= 3 end):SetTarget(Player) ) -- Default APL DefaultAPL:AddSpell( Consecration:CastableIf(function(self) - return self:IsKnownAndUsable() and not Player:GetAuras():FindMy(ConsecrationBuff):IsUp() + return self:IsKnownAndUsable() and not Player:GetAuras():FindMy(ConsecrationBuff):IsUp() and Player:IsWithinCombatDistance(Target, 8) end):SetTarget(Player) ) DefaultAPL:AddSpell( ShieldOfTheRighteous:CastableIf(function(self) - return self:IsKnownAndUsable() and Player:GetPower() >= 3 + return self:IsKnownAndUsable() and Player:GetPower() >= 3 and Player:IsWithinCombatDistance(Target, 5) end):SetTarget(Player) ) DefaultAPL:AddSpell( AvengersShield:CastableIf(function(self) - return self:IsKnownAndUsable() and Player:GetEnemies(8) >= 3 + return self:IsKnownAndUsable() and Player:IsWithinCombatDistance(Target, 30) end):SetTarget(Target) ) DefaultAPL:AddSpell( Judgment:CastableIf(function(self) - return self:IsKnownAndUsable() + return self:IsKnownAndUsable() and Player:IsWithinCombatDistance(Target, 30) end):SetTarget(Target) ) DefaultAPL:AddSpell( HammerOfWrath:CastableIf(function(self) - return self:IsKnownAndUsable() - end):SetTarget(Target) -) - -DefaultAPL:AddSpell( - AvengersShield:CastableIf(function(self) - return self:IsKnownAndUsable() + return self:IsKnownAndUsable() and (Target:GetHP() <= 20 or Player:GetAuras():FindMy(AvengingWrath):IsUp()) and Player:IsWithinCombatDistance(Target, 30) end):SetTarget(Target) ) DefaultAPL:AddSpell( BlessedHammer:CastableIf(function(self) - return self:IsKnownAndUsable() - end):SetTarget(Target) -) - -DefaultAPL:AddSpell( - HammerOfTheRighteous:CastableIf(function(self) - return self:IsKnownAndUsable() and not BlessedHammer:IsKnown() + return self:IsKnownAndUsable() and Player:IsWithinCombatDistance(Target, 5) end):SetTarget(Target) ) DefaultAPL:AddSpell( Consecration:CastableIf(function(self) - return self:IsKnownAndUsable() + return self:IsKnownAndUsable() and Player:IsWithinCombatDistance(Target, 8) end):SetTarget(Player) ) +-- Main rotation logic ProtPaladinModule:Sync(function() - if not Player:IsAffectingCombat() then return end - + -- Check if the player is mounted + if IsMounted() or Player:IsMounted() then + return -- Exit the function if mounted, pausing the rotation + end + + if not Player:IsAffectingCombat() then + if not Target:Exists() or Target:IsDead() then + Bastion.UnitManager:EnumEnemies(function(unit) + if unit:IsAlive() and unit:GetDistance(Player) <= 30 then + Target = unit + return true + end + end) + end + return + end + + -- Dynamic target selection and threat management + local lowestThreatEnemy = GetLowestThreatEnemy() + if lowestThreatEnemy then + Target = lowestThreatEnemy + elseif not Target:Exists() or Target:IsDead() or Target:GetDistance(Player) > 30 then + Bastion.UnitManager:EnumEnemies(function(unit) + if unit:IsAlive() and unit:GetDistance(Player) <= 30 and unit:IsAffectingCombat() then + Target = unit + return true + end + end) + end + + InterruptAPL:Execute() + ThreatAPL:Execute() DefensiveAPL:Execute() CooldownAPL:Execute() DefaultAPL:Execute()