diff --git a/.DS_Store b/.DS_Store index 5008ddf..2600019 100644 Binary files a/.DS_Store and b/.DS_Store differ 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()