diff --git a/BasicRotations/Magical/ICWA_PCT_BETA.cs b/BasicRotations/Magical/ICWA_PCT_BETA
similarity index 100%
rename from BasicRotations/Magical/ICWA_PCT_BETA.cs
rename to BasicRotations/Magical/ICWA_PCT_BETA
diff --git a/BasicRotations/Magical/PCT_Default.cs b/BasicRotations/Magical/PCT_Default.cs
index d6bdc2908..974e67e23 100644
--- a/BasicRotations/Magical/PCT_Default.cs
+++ b/BasicRotations/Magical/PCT_Default.cs
@@ -105,7 +105,7 @@ protected override bool AttackAbility(IAction nextGCD, out IAction? act)
// Bursts
int adjustCombatTimeForOpener = Player.Level < 92 ? 2 : 5;
if (StarryMusePvE.CanUse(out act) && CombatTime > adjustCombatTimeForOpener && IsBurst) return true;
- if (CombatTime > adjustCombatTimeForOpener && StrikingMusePvE.CanUse(out act) && burstTimingCheckerStriking) return true;
+ if (CombatTime > adjustCombatTimeForOpener && StrikingMusePvE.CanUse(out act, usedUp: true) && burstTimingCheckerStriking) return true;
if (SubtractivePalettePvE.CanUse(out act)) return true;
if (HasStarryMuse)
@@ -115,7 +115,7 @@ protected override bool AttackAbility(IAction nextGCD, out IAction? act)
}
if (RetributionOfTheMadeenPvE.CanUse(out act)) return true;
if (MogOfTheAgesPvE.CanUse(out act)) return true;
- if (StrikingMusePvE.CanUse(out act) && burstTimingCheckerStriking) return true;
+ if (StrikingMusePvE.CanUse(out act, usedUp: true) && burstTimingCheckerStriking) return true;
if (PomMusePvE.CanUse(out act, usedUp: true)) return true;
if (WingedMusePvE.CanUse(out act, usedUp: true)) return true;
if (ClawedMusePvE.CanUse(out act, usedUp: true)) return true;
diff --git a/BasicRotations/Magical/SMN_Default.cs b/BasicRotations/Magical/SMN_Default.cs
index 366e832f1..955e557a1 100644
--- a/BasicRotations/Magical/SMN_Default.cs
+++ b/BasicRotations/Magical/SMN_Default.cs
@@ -96,7 +96,7 @@ protected override bool AttackAbility(IAction nextGCD, out IAction? act)
if (inBigInvocation && (elapsed1ChargeAfterInvocation || targetIsBossAndDying) && SunflarePvE.CanUse(out act, skipAoeCheck: true)) return true;
if (RekindlePvE.CanUse(out act, skipAoeCheck: true)) return true;
- if (MountainBusterPvE.CanUse(out act, skipAoeCheck: true)) return true;
+ if (MountainBusterPvE.CanUse(out act)) return true;
if ((inSolarUnique && Player.HasStatus(false, StatusID.SearingLight) || !SearingLightPvE.EnoughLevel || isTargetBoss && isTargetDying) && EnergyDrainPvE.IsInCooldown && PainflarePvE.CanUse(out act)) return true;
if ((inSolarUnique && Player.HasStatus(false, StatusID.SearingLight) || !SearingLightPvE.EnoughLevel || isTargetBoss && isTargetDying) && EnergyDrainPvE.IsInCooldown && FesterPvE.CanUse(out act)) return true;
@@ -128,7 +128,7 @@ protected override bool AttackAbility(IAction nextGCD, out IAction? act)
if (inBigInvocation && (elapsed4ChargeAfterInvocation || targetIsBossAndDying) && SunflarePvE.CanUse(out act, skipAoeCheck: true)) return true;
if (RekindlePvE.CanUse(out act, skipAoeCheck: true)) return true;
- if (MountainBusterPvE.CanUse(out act, skipAoeCheck: true)) return true;
+ if (MountainBusterPvE.CanUse(out act)) return true;
if ((inSolarUnique && Player.HasStatus(false, StatusID.SearingLight) && elapsed2ChargeAfterInvocation && EnergyDrainPvE.Cooldown.WillHaveOneCharge(2) || !SearingLightPvE.EnoughLevel || isTargetBoss && isTargetDying) && EnergyDrainPvE.IsInCooldown && PainflarePvE.CanUse(out act)) return true;
if ((inSolarUnique && Player.HasStatus(false, StatusID.SearingLight) && elapsed2ChargeAfterInvocation && EnergyDrainPvE.Cooldown.WillHaveOneCharge(2) || !SearingLightPvE.EnoughLevel || isTargetBoss && isTargetDying) && EnergyDrainPvE.IsInCooldown && FesterPvE.CanUse(out act)) return true;
diff --git a/BasicRotations/Melee/NIN_Default.cs b/BasicRotations/Melee/NIN_Default.cs
index cc0c45e9a..85a163591 100644
--- a/BasicRotations/Melee/NIN_Default.cs
+++ b/BasicRotations/Melee/NIN_Default.cs
@@ -16,6 +16,16 @@ public sealed class NIN_Default : NinjaRotation
[RotationConfig(CombatType.PvE, Name = "Use Unhide")]
public bool AutoUnhide { get; set; } = true;
+
+ [RotationConfig(CombatType.PvE, Name = "Use Mudras Outside of Combat when enemies are near")]
+ public bool CommbatMudra { get; set; } = true;
+ #endregion
+
+ #region Tracking Properties
+ // Properties to track RabbitMediumPvE failures and related information.
+ private int _rabbitMediumFailures = 0;
+ private IBaseAction? _lastNinActionAim = null;
+ private IAction? _followUpGCDAction = null;
#endregion
#region CountDown Logic
@@ -54,7 +64,6 @@ public sealed class NIN_Default : NinjaRotation
// Finally, updates the current ninjutsu action aim if it's different from the incoming action.
private void SetNinjutsu(IBaseAction act)
{
-
if (act == null || AdjustId(ActionID.NinjutsuPvE) == ActionID.RabbitMediumPvE) return;
if (_ninActionAim != null && IsLastAction(false, TenPvE, JinPvE, ChiPvE, FumaShurikenPvE_18873, FumaShurikenPvE_18874, FumaShurikenPvE_18875)) return;
@@ -70,6 +79,7 @@ private void ClearNinjutsu()
{
if (_ninActionAim != null)
{
+ _lastNinActionAim = _ninActionAim;
_ninActionAim = null;
}
}
@@ -88,7 +98,7 @@ private bool ChoiceNinjutsu(out IAction? act)
ClearNinjutsu();
}
- if ((!JinPvE.Cooldown.HasOneCharge && JinPvE.EnoughLevel) || (!JinPvE.Cooldown.HasOneCharge && TenPvE.EnoughLevel)) return false;
+ if (!TenPvE.Cooldown.HasOneCharge && TenPvE.EnoughLevel) return false;
// Ensures that the action ID currently considered for Ninjutsu is actually valid for Ninjutsu execution.
//if (AdjustId(ActionID.NinjutsuPvE) != ActionID.NinjutsuPvE) return false;
// If more than 4.5 seconds have passed since the last action, it clears any pending Ninjutsu to avoid stale actions.
@@ -129,7 +139,7 @@ private bool ChoiceNinjutsu(out IAction? act)
// If Suiton is active but no specific Ninjutsu is currently aimed, it clears the Ninjutsu aim.
// This check is relevant for managing Suiton's effect, particularly for enabling Trick Attack.
if (Player.HasStatus(true, StatusID.ShadowWalker)
- && _ninActionAim == SuitonPvE && NoNinjutsu)
+ && _ninActionAim == SuitonPvE)
{
ClearNinjutsu();
}
@@ -141,7 +151,7 @@ private bool ChoiceNinjutsu(out IAction? act)
//Aoe
if (NumberOfHostilesInRange > 1 && KatonPvE.EnoughLevel && ChiPvE.CanUse(out _) && TenPvE.CanUse(out _))
{
- if (!Player.HasStatus(true, StatusID.Doton) && !IsMoving && !IsLastGCD(false, DotonPvE) && (!TenChiJinPvE.Cooldown.WillHaveOneCharge(6)) || !Player.HasStatus(true, StatusID.Doton) && !TenChiJinPvE.Cooldown.IsCoolingDown && TenPvE.CanUse(out _) && ChiPvE.CanUse(out _) && JinPvE.CanUse(out _))
+ if (!HasDoton && !IsMoving && !IsLastGCD(false, DotonPvE) && (!TenChiJinPvE.Cooldown.WillHaveOneCharge(6)) || !HasDoton && !TenChiJinPvE.Cooldown.IsCoolingDown && TenPvE.CanUse(out _) && ChiPvE.CanUse(out _) && JinPvE.CanUse(out _))
SetNinjutsu(DotonPvE);
else SetNinjutsu(KatonPvE);
}
@@ -191,7 +201,7 @@ private bool DoNinjutsu(out IAction? act)
&& !IsLastAction(false, FumaShurikenPvE_18875, FumaShurikenPvE_18873))
{
//AOE
- if (KatonPvE.EnoughLevel)
+ if (KatonPvE.CanUse(out _))
{
if (FumaShurikenPvE_18875.CanUse(out act)) return true;
}
@@ -204,19 +214,19 @@ private bool DoNinjutsu(out IAction? act)
{
if (KatonPvE_18876.CanUse(out act, skipAoeCheck: true)) return true;
}
- //Others
else if (chiId == RaitonPvE_18877.ID && !IsLastAction(false, RaitonPvE_18877))
{
if (RaitonPvE_18877.CanUse(out act, skipAoeCheck: true)) return true;
}
- else if (chiId == DotonPvE_18880.ID && !IsLastAction(false, DotonPvE_18880) && !HasDoton)
- {
- if (DotonPvE_18880.CanUse(out act, skipAoeCheck: true)) return true;
- }
+ //Others
else if (jinId == SuitonPvE_18881.ID && !IsLastAction(false, SuitonPvE_18881))
{
if (SuitonPvE_18881.CanUse(out act, skipAoeCheck: true, skipStatusProvideCheck: true)) return true;
}
+ else if (chiId == DotonPvE_18880.ID && !IsLastAction(false, DotonPvE_18880) && !HasDoton)
+ {
+ if (DotonPvE_18880.CanUse(out act, skipAoeCheck: true)) return true;
+ }
}
//Keep Kassatsu in Burst.
@@ -229,6 +239,7 @@ private bool DoNinjutsu(out IAction? act)
//Failed
if ((uint)id == RabbitMediumPvE.ID)
{
+ _rabbitMediumFailures++;
ClearNinjutsu();
act = null;
return false;
@@ -309,7 +320,7 @@ protected override bool EmergencyAbility(IAction nextGCD, out IAction? act)
// First priority is given to Kassatsu if it's available, allowing for an immediate powerful Ninjutsu.
if (NoNinjutsu && KassatsuPvE.CanUse(out act)) return true;
- if (!TenChiJinPvE.Cooldown.IsCoolingDown && MeisuiPvE.CanUse(out act)) return true;
+ if ((!TenChiJinPvE.Cooldown.IsCoolingDown || Player.WillStatusEndGCD(2, 0, true, StatusID.ShadowWalker)) && MeisuiPvE.CanUse(out act)) return true;
if (TenriJindoPvE.CanUse(out act)) return true;
@@ -390,14 +401,14 @@ protected override bool GeneralGCD(out IAction? act)
if (RabbitMediumPvE.CanUse(out act)) return true;
- if ((InTrickAttack || InMug) && NoNinjutsu && !HasRaijuReady
+ if (!IsExecutingMudra && (InTrickAttack || InMug) && NoNinjutsu && !HasRaijuReady
&& !Player.HasStatus(true, StatusID.TenChiJin)
&& PhantomKamaitachiPvE.CanUse(out act)) return true;
- if (FleetingRaijuPvE.CanUse(out act)) return true;
+ if (!IsExecutingMudra && FleetingRaijuPvE.CanUse(out act)) return true;
- if (ChoiceNinjutsu(out act)) return true;
- if ((!InCombat || !CombatElapsedLess(7)) && DoNinjutsu(out act)) return true;
+ if ((InCombat || (CommbatMudra && HasHostilesInMaxRange)) && ChoiceNinjutsu(out act)) return true;
+ if (((!InCombat && CommbatMudra && HasHostilesInMaxRange) || !CombatElapsedLess(7)) && DoNinjutsu(out act)) return true;
//No Ninjutsu
if (NoNinjutsu)
@@ -428,7 +439,6 @@ protected override bool GeneralGCD(out IAction? act)
}
if (!InCombat && _ninActionAim == null && UseHide
&& TenPvE.Cooldown.IsCoolingDown && HidePvE.CanUse(out act)) return true;
-
return base.GeneralGCD(out act);
}
#endregion
@@ -440,6 +450,8 @@ protected override bool GeneralGCD(out IAction? act)
public override void DisplayStatus()
{
ImGui.Text($"Ninjutsu Action: {_ninActionAim}");
+ ImGui.Text($"Mudra Failure Count: {_rabbitMediumFailures}");
+ ImGui.Text($"Last Ninjutsu Action Cleared From Queue: {_lastNinActionAim}");
ImGui.Text($"Ninki: {Ninki}");
ImGui.Text($"Kazematoi: {Kazematoi}");
ImGui.Text($"HasJin: {HasJin}");
diff --git a/BasicRotations/RebornRotations.csproj b/BasicRotations/RebornRotations.csproj
index bf63a3b1e..a4ddcdbec 100644
--- a/BasicRotations/RebornRotations.csproj
+++ b/BasicRotations/RebornRotations.csproj
@@ -25,6 +25,9 @@
+
+
+
diff --git a/BasicRotations/Tank/GNB_Default.cs b/BasicRotations/Tank/GNB_Default.cs
index 10808a516..7d9f20050 100644
--- a/BasicRotations/Tank/GNB_Default.cs
+++ b/BasicRotations/Tank/GNB_Default.cs
@@ -1,18 +1,12 @@
-namespace DefaultRotations.Tank;
+namespace DefaultRotations.Tank;
-[Rotation("Default", CombatType.PvE, GameVersion = "7.15")]
+[Rotation("Beta", CombatType.PvE, GameVersion = "7.15")]
[SourceCode(Path = "main/BasicRotations/Tank/GNB_Default.cs")]
[Api(4)]
public sealed class GNB_Default : GunbreakerRotation
{
- #region Config Options
- [RotationConfig(CombatType.PvE, Name = "Use experimental No Mercy logic for burst")]
- public bool NoMercyLogic { get; set; } = false;
- #endregion
-
- private static bool InBurstStatus => !Player.WillStatusEnd(0, true, StatusID.NoMercy);
-
#region Countdown Logic
+
protected override IAction? CountDownAction(float remainTime)
{
if (remainTime <= 0.7 && LightningShotPvE.CanUse(out var act)) return act;
@@ -21,30 +15,33 @@ public sealed class GNB_Default : GunbreakerRotation
}
#endregion
- #region oGCD Logic
+ #region Additional oGCD Logic
+
+ [RotationDesc]
protected override bool EmergencyAbility(IAction nextGCD, out IAction? act)
{
- if (base.EmergencyAbility(nextGCD, out act)) return true;
-
+ // Attempt to align Bloodfest with No Mercy during opener
if (InCombat && CombatElapsedLess(30))
{
if (!CombatElapsedLessGCD(2) && NoMercyPvE.CanUse(out act, skipAoeCheck: true)) return true;
- if (InBurstStatus && BloodfestPvE.CanUse(out act, skipAoeCheck: true)) return true;
+ if (Player.HasStatus(true, StatusID.NoMercy) && BloodfestPvE.CanUse(out act, skipAoeCheck: true)) return true;
}
- if (AbdomenTearPvE.CanUse(out act)) return true;
- if (EyeGougePvE.CanUse(out act)) return true;
- if (FatedBrandPvE.CanUse(out act)) return true;
- if (HypervelocityPvE.CanUse(out act)) return true;
-
return base.EmergencyAbility(nextGCD, out act);
}
+ [RotationDesc(ActionID.TrajectoryPvE)]
+ protected override bool MoveForwardAbility(IAction nextGCD, out IAction? act)
+ {
+ if (TrajectoryPvE.CanUse(out act)) return true;
+ return base.MoveForwardAbility(nextGCD, out act);
+ }
+
[RotationDesc(ActionID.HeartOfLightPvE, ActionID.ReprisalPvE)]
- protected override bool DefenseAreaAbility(IAction nextGCD, out IAction? act)
+ protected sealed override bool DefenseAreaAbility(IAction nextGCD, out IAction? act)
{
- if (!InBurstStatus && HeartOfLightPvE.CanUse(out act, skipAoeCheck: true)) return true;
- if (!InBurstStatus && ReprisalPvE.CanUse(out act, skipAoeCheck: true)) return true;
+ if (!Player.HasStatus(true, StatusID.NoMercy) && HeartOfLightPvE.CanUse(out act, skipAoeCheck: true)) return true;
+ if (!Player.HasStatus(true, StatusID.NoMercy) && ReprisalPvE.CanUse(out act, skipAoeCheck: true)) return true;
return base.DefenseAreaAbility(nextGCD, out act);
}
@@ -72,11 +69,21 @@ protected override bool HealSingleAbility(IAction nextGCD, out IAction? act)
if (AuroraPvE.CanUse(out act, usedUp: true)) return true;
return base.HealSingleAbility(nextGCD, out act);
}
+ #endregion
+
+ #region oGCD Logic
+
+ protected override bool GeneralAbility(IAction nextGCD, out IAction? act)
+ {
+ if (!CombatElapsedLessGCD(5) && NoMercyPvE.CanUse(out act, skipAoeCheck: true)) return true;
+ return base.GeneralAbility(nextGCD, out act);
+ }
+
protected override bool AttackAbility(IAction nextGCD, out IAction? act)
{
- if (NoMercyLogic && IsBurst && CanUseNoMercy(out act)) return true;
+ //if (IsBurst && CanUseNoMercy(out act)) return true;
- if (!NoMercyLogic && !CombatElapsedLessGCD(5) && NoMercyPvE.CanUse(out act, skipAoeCheck: true)) return true;
+ if (!CombatElapsedLessGCD(5) && NoMercyPvE.CanUse(out act, skipAoeCheck: true)) return true;
if (JugularRipPvE.CanUse(out act)) return true;
@@ -85,47 +92,48 @@ protected override bool AttackAbility(IAction nextGCD, out IAction? act)
if (!IsFullParty && !(DangerZonePvE.Target.Target?.IsBossFromTTK() ?? false)) return true;
- if (!GnashingFangPvE.EnoughLevel && (InBurstStatus || !NoMercyPvE.Cooldown.WillHaveOneCharge(15))) return true;
+ if (!GnashingFangPvE.EnoughLevel && (Player.HasStatus(true, StatusID.NoMercy) || !NoMercyPvE.Cooldown.WillHaveOneCharge(15))) return true;
- if (InBurstStatus && GnashingFangPvE.Cooldown.IsCoolingDown) return true;
+ if (Player.HasStatus(true, StatusID.NoMercy) && GnashingFangPvE.Cooldown.IsCoolingDown) return true;
- if (!InBurstStatus && !GnashingFangPvE.Cooldown.WillHaveOneCharge(20)) return true;
+ if (!Player.HasStatus(true, StatusID.NoMercy) && !GnashingFangPvE.Cooldown.WillHaveOneCharge(20)) return true;
}
- if (InBurstStatus && CanUseBowShock(out act)) return true;
+ if (Player.HasStatus(true, StatusID.NoMercy) && CanUseBowShock(out act)) return true;
//if (TrajectoryPvE.CanUse(out act) && !IsMoving) return true;
if (GnashingFangPvE.Cooldown.IsCoolingDown && DoubleDownPvE.Cooldown.IsCoolingDown && Ammo == 0 && BloodfestPvE.CanUse(out act)) return true;
- bool areDDTargetsInRange = AllHostileTargets.Any(hostile => hostile.DistanceToPlayer() < 4.5f);
-
- if (areDDTargetsInRange)
- {
- if (InBurstStatus && IsLastGCD(ActionID.DoubleDownPvE) && BlastingZonePvE.CanUse(out act)) return true;
- }
- if (NoMercyPvE.Cooldown.IsCoolingDown && BloodfestPvE.Cooldown.IsCoolingDown && BlastingZonePvE.CanUse(out act)) return true;
+ if (AbdomenTearPvE.CanUse(out act)) return true;
+ if (EyeGougePvE.CanUse(out act)) return true;
+ if (FatedBrandPvE.CanUse(out act)) return true;
+ if (HypervelocityPvE.CanUse(out act)) return true;
return base.AttackAbility(nextGCD, out act);
}
#endregion
#region GCD Logic
+
protected override bool GeneralGCD(out IAction? act)
{
bool areDDTargetsInRange = AllHostileTargets.Any(hostile => hostile.DistanceToPlayer() < 4.5f);
- if (InBurstStatus && BloodfestPvE.CanUse(out act)) return true;
+ if (Player.HasStatus(true, StatusID.NoMercy) && BloodfestPvE.CanUse(out act)) return true;
if (IsLastGCD(false, NobleBloodPvE) && LionHeartPvE.CanUse(out act, skipComboCheck: true)) return true;
if (IsLastGCD(false, ReignOfBeastsPvE) && NobleBloodPvE.CanUse(out act, skipComboCheck: true)) return true;
- if (!InGnashingFang && ReignOfBeastsPvE.CanUse(out act, skipAoeCheck: true)) return true;
+ if (ReignOfBeastsPvE.CanUse(out act, skipAoeCheck: true)) return true;
- if (InBurstStatus && SonicBreakPvE.CanUse(out act)) return true;
+ if (Player.HasStatus(true, StatusID.NoMercy) && SonicBreakPvE.CanUse(out act)) return true;
if (areDDTargetsInRange)
{
- if (InBurstStatus && CanUseDoubleDown(out act)) return true;
+ if (Player.HasStatus(true, StatusID.NoMercy) && CanUseDoubleDown(out act)) return true;
+ if (Player.HasStatus(true, StatusID.NoMercy) && IsLastGCD(ActionID.DoubleDownPvE) && BlastingZonePvE.CanUse(out act)) return true;
}
+ if (NoMercyPvE.Cooldown.IsCoolingDown && BloodfestPvE.Cooldown.IsCoolingDown && BlastingZonePvE.CanUse(out act)) return true;
+
if (CanUseGnashingFang(out act)) return true;
if (SavageClawPvE.CanUse(out act, skipComboCheck: true)) return true;
@@ -139,17 +147,15 @@ protected override bool GeneralGCD(out IAction? act)
if (Ammo == MaxAmmo && IsLastGCD(ActionID.BrutalShellPvE) && BurstStrikePvE.CanUse(out act)) return true;
- if (!InGnashingFang)
- {
- if (SolidBarrelPvE.CanUse(out act)) return true;
- if (BrutalShellPvE.CanUse(out act)) return true;
- if (KeenEdgePvE.CanUse(out act)) return true;
- }
+ if (SolidBarrelPvE.CanUse(out act)) return true;
+ if (BrutalShellPvE.CanUse(out act)) return true;
+ if (KeenEdgePvE.CanUse(out act)) return true;
if (LightningShotPvE.CanUse(out act)) return true;
return base.GeneralGCD(out act);
}
+
#endregion
#region Extra Methods
@@ -157,25 +163,24 @@ protected override bool GeneralGCD(out IAction? act)
public override bool CanHealAreaSpell => false;
- private bool CanUseNoMercy(out IAction act)
- {
- var IsTargetBoss = HostileTarget?.IsBossFromIcon() ?? false;
+ //private bool CanUseNoMercy(out IAction act)
+ //{
+ // if (!NoMercy.CanUse(out act, CanUseOption.OnLastAbility)) return false;
- if (!NoMercyPvE.CanUse(out act)) return false;
+ // if (!IsFullParty && !IsTargetBoss && !IsMoving && DemonSlice.CanUse(out _)) return true;
- if (!IsFullParty && !IsTargetBoss && !IsMoving && DemonSlicePvE.CanUse(out _)) return true;
+ // if (!BurstStrike.EnoughLevel) return true;
- if (!BurstStrikePvE.EnoughLevel) return true;
+ // if (BurstStrike.EnoughLevel)
+ // {
+ // if (IsLastGCD((ActionID)KeenEdge.ID) && Ammo == 1 && !GnashingFang.IsCoolingDown && !BloodFest.IsCoolingDown) return true;
+ // else if (Ammo == (Level >= 88 ? 3 : 2)) return true;
+ // else if (Ammo == 2 && GnashingFang.IsCoolingDown) return true;
+ // }
- if (BurstStrikePvE.EnoughLevel)
- {
- if (IsLastGCD(ActionID.KeenEdgePvE) && Ammo == 1 && !GnashingFangPvE.Cooldown.IsCoolingDown && !BloodfestPvE.Cooldown.IsCoolingDown) return true;
- else if (Ammo == MaxAmmo) return true;
- else if (Ammo == 2 && GnashingFangPvE.Cooldown.IsCoolingDown) return true;
- }
-
- return false;
- }
+ // act = null;
+ // return false;
+ //}
private bool CanUseGnashingFang(out IAction? act)
{
@@ -258,4 +263,4 @@ private bool CanUseBowShock(out IAction act)
return false;
}
#endregion
-}
\ No newline at end of file
+}
diff --git a/BasicRotations/Tank/GNB_Beta.cs b/BasicRotations/Tank/GNB_Default_Old
similarity index 69%
rename from BasicRotations/Tank/GNB_Beta.cs
rename to BasicRotations/Tank/GNB_Default_Old
index 18da7a1d2..a9657707c 100644
--- a/BasicRotations/Tank/GNB_Beta.cs
+++ b/BasicRotations/Tank/GNB_Default_Old
@@ -1,12 +1,18 @@
-namespace DefaultRotations.Tank;
+namespace DefaultRotations.Tank;
-[Rotation("Beta", CombatType.PvE, GameVersion = "7.15")]
-[SourceCode(Path = "main/BasicRotations/Tank/GNB_Beta.cs")]
+[Rotation("Default", CombatType.PvE, GameVersion = "7.15")]
+[SourceCode(Path = "main/BasicRotations/Tank/GNB_Default.cs")]
[Api(4)]
-public sealed class GNB_Beta : GunbreakerRotation
+public sealed class GNB_Default_Old : GunbreakerRotation
{
- #region Countdown Logic
+ #region Config Options
+ [RotationConfig(CombatType.PvE, Name = "Use experimental No Mercy logic for burst")]
+ public bool NoMercyLogic { get; set; } = false;
+ #endregion
+
+ private static bool InBurstStatus => !Player.WillStatusEnd(0, true, StatusID.NoMercy);
+ #region Countdown Logic
protected override IAction? CountDownAction(float remainTime)
{
if (remainTime <= 0.7 && LightningShotPvE.CanUse(out var act)) return act;
@@ -15,33 +21,30 @@ public sealed class GNB_Beta : GunbreakerRotation
}
#endregion
- #region Additional oGCD Logic
-
- [RotationDesc]
+ #region oGCD Logic
protected override bool EmergencyAbility(IAction nextGCD, out IAction? act)
{
- // Attempt to align Bloodfest with No Mercy during opener
+ if (base.EmergencyAbility(nextGCD, out act)) return true;
+
if (InCombat && CombatElapsedLess(30))
{
if (!CombatElapsedLessGCD(2) && NoMercyPvE.CanUse(out act, skipAoeCheck: true)) return true;
- if (Player.HasStatus(true, StatusID.NoMercy) && BloodfestPvE.CanUse(out act, skipAoeCheck: true)) return true;
+ if (InBurstStatus && BloodfestPvE.CanUse(out act, skipAoeCheck: true)) return true;
}
- return base.EmergencyAbility(nextGCD, out act);
- }
+ if (AbdomenTearPvE.CanUse(out act)) return true;
+ if (EyeGougePvE.CanUse(out act)) return true;
+ if (FatedBrandPvE.CanUse(out act)) return true;
+ if (HypervelocityPvE.CanUse(out act)) return true;
- [RotationDesc(ActionID.TrajectoryPvE)]
- protected override bool MoveForwardAbility(IAction nextGCD, out IAction? act)
- {
- if (TrajectoryPvE.CanUse(out act)) return true;
- return base.MoveForwardAbility(nextGCD, out act);
+ return base.EmergencyAbility(nextGCD, out act);
}
[RotationDesc(ActionID.HeartOfLightPvE, ActionID.ReprisalPvE)]
- protected sealed override bool DefenseAreaAbility(IAction nextGCD, out IAction? act)
+ protected override bool DefenseAreaAbility(IAction nextGCD, out IAction? act)
{
- if (!Player.HasStatus(true, StatusID.NoMercy) && HeartOfLightPvE.CanUse(out act, skipAoeCheck: true)) return true;
- if (!Player.HasStatus(true, StatusID.NoMercy) && ReprisalPvE.CanUse(out act, skipAoeCheck: true)) return true;
+ if (!InBurstStatus && HeartOfLightPvE.CanUse(out act, skipAoeCheck: true)) return true;
+ if (!InBurstStatus && ReprisalPvE.CanUse(out act, skipAoeCheck: true)) return true;
return base.DefenseAreaAbility(nextGCD, out act);
}
@@ -69,21 +72,11 @@ protected override bool HealSingleAbility(IAction nextGCD, out IAction? act)
if (AuroraPvE.CanUse(out act, usedUp: true)) return true;
return base.HealSingleAbility(nextGCD, out act);
}
- #endregion
-
- #region oGCD Logic
-
- protected override bool GeneralAbility(IAction nextGCD, out IAction? act)
- {
- if (!CombatElapsedLessGCD(5) && NoMercyPvE.CanUse(out act, skipAoeCheck: true)) return true;
- return base.GeneralAbility(nextGCD, out act);
- }
-
protected override bool AttackAbility(IAction nextGCD, out IAction? act)
{
- //if (IsBurst && CanUseNoMercy(out act)) return true;
+ if (NoMercyLogic && IsBurst && CanUseNoMercy(out act)) return true;
- if (!CombatElapsedLessGCD(5) && NoMercyPvE.CanUse(out act, skipAoeCheck: true)) return true;
+ if (!NoMercyLogic && !CombatElapsedLessGCD(5) && NoMercyPvE.CanUse(out act, skipAoeCheck: true)) return true;
if (JugularRipPvE.CanUse(out act)) return true;
@@ -92,48 +85,47 @@ protected override bool AttackAbility(IAction nextGCD, out IAction? act)
if (!IsFullParty && !(DangerZonePvE.Target.Target?.IsBossFromTTK() ?? false)) return true;
- if (!GnashingFangPvE.EnoughLevel && (Player.HasStatus(true, StatusID.NoMercy) || !NoMercyPvE.Cooldown.WillHaveOneCharge(15))) return true;
+ if (!GnashingFangPvE.EnoughLevel && (InBurstStatus || !NoMercyPvE.Cooldown.WillHaveOneCharge(15))) return true;
- if (Player.HasStatus(true, StatusID.NoMercy) && GnashingFangPvE.Cooldown.IsCoolingDown) return true;
+ if (InBurstStatus && GnashingFangPvE.Cooldown.IsCoolingDown) return true;
- if (!Player.HasStatus(true, StatusID.NoMercy) && !GnashingFangPvE.Cooldown.WillHaveOneCharge(20)) return true;
+ if (!InBurstStatus && !GnashingFangPvE.Cooldown.WillHaveOneCharge(20)) return true;
}
- if (Player.HasStatus(true, StatusID.NoMercy) && CanUseBowShock(out act)) return true;
+ if (InBurstStatus && CanUseBowShock(out act)) return true;
//if (TrajectoryPvE.CanUse(out act) && !IsMoving) return true;
if (GnashingFangPvE.Cooldown.IsCoolingDown && DoubleDownPvE.Cooldown.IsCoolingDown && Ammo == 0 && BloodfestPvE.CanUse(out act)) return true;
- if (AbdomenTearPvE.CanUse(out act)) return true;
- if (EyeGougePvE.CanUse(out act)) return true;
- if (FatedBrandPvE.CanUse(out act)) return true;
- if (HypervelocityPvE.CanUse(out act)) return true;
+ bool areDDTargetsInRange = AllHostileTargets.Any(hostile => hostile.DistanceToPlayer() < 4.5f);
+
+ if (areDDTargetsInRange)
+ {
+ if (InBurstStatus && IsLastGCD(ActionID.DoubleDownPvE) && BlastingZonePvE.CanUse(out act)) return true;
+ }
+ if (NoMercyPvE.Cooldown.IsCoolingDown && BloodfestPvE.Cooldown.IsCoolingDown && BlastingZonePvE.CanUse(out act)) return true;
return base.AttackAbility(nextGCD, out act);
}
#endregion
#region GCD Logic
-
protected override bool GeneralGCD(out IAction? act)
{
bool areDDTargetsInRange = AllHostileTargets.Any(hostile => hostile.DistanceToPlayer() < 4.5f);
- if (Player.HasStatus(true, StatusID.NoMercy) && BloodfestPvE.CanUse(out act)) return true;
+ if (InBurstStatus && BloodfestPvE.CanUse(out act)) return true;
if (IsLastGCD(false, NobleBloodPvE) && LionHeartPvE.CanUse(out act, skipComboCheck: true)) return true;
if (IsLastGCD(false, ReignOfBeastsPvE) && NobleBloodPvE.CanUse(out act, skipComboCheck: true)) return true;
- if (ReignOfBeastsPvE.CanUse(out act, skipAoeCheck: true)) return true;
+ if (!InGnashingFang && ReignOfBeastsPvE.CanUse(out act, skipAoeCheck: true)) return true;
- if (Player.HasStatus(true, StatusID.NoMercy) && SonicBreakPvE.CanUse(out act)) return true;
+ if (InBurstStatus && SonicBreakPvE.CanUse(out act)) return true;
if (areDDTargetsInRange)
{
- if (Player.HasStatus(true, StatusID.NoMercy) && CanUseDoubleDown(out act)) return true;
- if (Player.HasStatus(true, StatusID.NoMercy) && IsLastGCD(ActionID.DoubleDownPvE) && BlastingZonePvE.CanUse(out act)) return true;
+ if (InBurstStatus && CanUseDoubleDown(out act)) return true;
}
- if (NoMercyPvE.Cooldown.IsCoolingDown && BloodfestPvE.Cooldown.IsCoolingDown && BlastingZonePvE.CanUse(out act)) return true;
-
if (CanUseGnashingFang(out act)) return true;
if (SavageClawPvE.CanUse(out act, skipComboCheck: true)) return true;
@@ -147,15 +139,17 @@ protected override bool GeneralGCD(out IAction? act)
if (Ammo == MaxAmmo && IsLastGCD(ActionID.BrutalShellPvE) && BurstStrikePvE.CanUse(out act)) return true;
- if (SolidBarrelPvE.CanUse(out act)) return true;
- if (BrutalShellPvE.CanUse(out act)) return true;
- if (KeenEdgePvE.CanUse(out act)) return true;
+ if (!InGnashingFang)
+ {
+ if (SolidBarrelPvE.CanUse(out act)) return true;
+ if (BrutalShellPvE.CanUse(out act)) return true;
+ if (KeenEdgePvE.CanUse(out act)) return true;
+ }
if (LightningShotPvE.CanUse(out act)) return true;
return base.GeneralGCD(out act);
}
-
#endregion
#region Extra Methods
@@ -163,24 +157,25 @@ protected override bool GeneralGCD(out IAction? act)
public override bool CanHealAreaSpell => false;
- //private bool CanUseNoMercy(out IAction act)
- //{
- // if (!NoMercy.CanUse(out act, CanUseOption.OnLastAbility)) return false;
+ private bool CanUseNoMercy(out IAction act)
+ {
+ var IsTargetBoss = HostileTarget?.IsBossFromIcon() ?? false;
- // if (!IsFullParty && !IsTargetBoss && !IsMoving && DemonSlice.CanUse(out _)) return true;
+ if (!NoMercyPvE.CanUse(out act)) return false;
- // if (!BurstStrike.EnoughLevel) return true;
+ if (!IsFullParty && !IsTargetBoss && !IsMoving && DemonSlicePvE.CanUse(out _)) return true;
- // if (BurstStrike.EnoughLevel)
- // {
- // if (IsLastGCD((ActionID)KeenEdge.ID) && Ammo == 1 && !GnashingFang.IsCoolingDown && !BloodFest.IsCoolingDown) return true;
- // else if (Ammo == (Level >= 88 ? 3 : 2)) return true;
- // else if (Ammo == 2 && GnashingFang.IsCoolingDown) return true;
- // }
+ if (!BurstStrikePvE.EnoughLevel) return true;
- // act = null;
- // return false;
- //}
+ if (BurstStrikePvE.EnoughLevel)
+ {
+ if (IsLastGCD(ActionID.KeenEdgePvE) && Ammo == 1 && !GnashingFangPvE.Cooldown.IsCoolingDown && !BloodfestPvE.Cooldown.IsCoolingDown) return true;
+ else if (Ammo == MaxAmmo) return true;
+ else if (Ammo == 2 && GnashingFangPvE.Cooldown.IsCoolingDown) return true;
+ }
+
+ return false;
+ }
private bool CanUseGnashingFang(out IAction? act)
{
@@ -263,4 +258,4 @@ private bool CanUseBowShock(out IAction act)
return false;
}
#endregion
-}
+}
\ No newline at end of file
diff --git a/BasicRotations/Tank/PLD_Beta.cs b/BasicRotations/Tank/PLD_Beta.cs
deleted file mode 100644
index 10947491f..000000000
--- a/BasicRotations/Tank/PLD_Beta.cs
+++ /dev/null
@@ -1,251 +0,0 @@
-namespace DefaultRotations.Tank;
-
-[Rotation("Beta", CombatType.PvE, GameVersion = "7.15")]
-[SourceCode(Path = "main/BasicRotations/Tank/PLD_Beta.cs")]
-[Api(4)]
-
-public sealed class PLD_Beta : PaladinRotation
-{
- #region Config Options
-
- [RotationConfig(CombatType.PvE, Name = "Prevent actions while you have Passage of Arms up")]
- public bool PassageProtec { get; set; } = false;
-
- [RotationConfig(CombatType.PvE, Name = "Use Hallowed Ground with Cover")]
- private bool HallowedWithCover { get; set; } = true;
-
- [RotationConfig(CombatType.PvE, Name = "Use up both stacks of Intervene during burst window")]
- private bool UseInterveneFight { get; set; } = true;
-
- [Range(0, 100, ConfigUnitType.Pixels)]
- [RotationConfig(CombatType.PvE, Name = "Use Sheltron at minimum X Oath to prevent over cap (Set to 0 to disable)")]
- private int WhenToSheltron { get; set; } = 100;
-
- [Range(0, 1, ConfigUnitType.Percent)]
- [RotationConfig(CombatType.PvE, Name = "Health threshold for Intervention (Set to 0 to disable)")]
- private float InterventionRatio { get; set; } = 0.6f;
-
- [Range(0, 1, ConfigUnitType.Percent)]
- [RotationConfig(CombatType.PvE, Name = "Health threshold for Cover (Set to 0 to disable)")]
- private float CoverRatio { get; set; } = 0.3f;
-
- [RotationConfig(CombatType.PvE, Name = "Use Holy Spirit when out of melee range")]
- private bool UseHolyWhenAway { get; set; } = false;
-
- [Range(0, 1, ConfigUnitType.Percent)]
- [RotationConfig(CombatType.PvE, Name = "Minimum HP threshold party member needs to be to use Clemency with Requiescat")]
- public float ClemencyRequi { get; set; } = 0.2f;
-
- [RotationConfig(CombatType.PvE, Name = "Use Clemency without Requiescat")]
- private bool HealBot { get; set; } = true;
-
- [Range(0, 1, ConfigUnitType.Percent)]
- [RotationConfig(CombatType.PvE, Name = "Minimum HP threshold party member needs to be to use Clemency without Requiescat")]
- public float ClemencyNoRequi { get; set; } = 0.4f;
- #endregion
-
- #region Countdown Logic
- protected override IAction? CountDownAction(float remainTime)
- {
- if (remainTime < HolySpiritPvE.Info.CastTime + CountDownAhead
- && HolySpiritPvE.CanUse(out var act)) return act;
-
- if (remainTime < 15 && DivineVeilPvE.CanUse(out act)) return act;
-
- return base.CountDownAction(remainTime);
- }
- #endregion
-
- #region Additional oGCD Logic
-
- [RotationDesc(ActionID.CoverPvE)]
- protected override bool EmergencyAbility(IAction nextGCD, out IAction? act)
- {
- act = null;
- if (PassageProtec && Player.HasStatus(true, StatusID.PassageOfArms)) return false;
-
- if (Player.HasStatus(true, StatusID.Cover) && HallowedWithCover && HallowedGroundPvE.CanUse(out act)) return true;
-
- if (HallowedGroundPvE.CanUse(out act)
- && Player.GetHealthRatio() <= HealthForDyingTanks) return true;
-
- if ((Player.HasStatus(true, StatusID.Rampart) || Player.HasStatus(true, StatusID.Sentinel)) &&
- InterventionPvE.CanUse(out act) &&
- InterventionPvE.Target.Target?.GetHealthRatio() < 0.6) return true;
-
- if (CoverPvE.CanUse(out act) && CoverPvE.Target.Target?.DistanceToPlayer() < 10 &&
- CoverPvE.Target.Target?.GetHealthRatio() < CoverRatio) return true;
-
- return base.EmergencyAbility(nextGCD, out act);
- }
-
- [RotationDesc]
- protected override bool MoveForwardAbility(IAction nextGCD, out IAction? act)
- {
- act = null;
- if (PassageProtec && Player.HasStatus(true, StatusID.PassageOfArms)) return false;
-
- if (IntervenePvE.CanUse(out act)) return true;
- return base.MoveForwardAbility(nextGCD, out act);
- }
-
- [RotationDesc(ActionID.DivineVeilPvE, ActionID.PassageOfArmsPvE)]
- protected override bool DefenseAreaAbility(IAction nextGCD, out IAction? act)
- {
- act = null;
- if (PassageProtec && Player.HasStatus(true, StatusID.PassageOfArms)) return false;
-
- if (DivineVeilPvE.CanUse(out act)) return true;
-
- if (PassageOfArmsPvE.CanUse(out act)) return true;
-
- return base.DefenseAreaAbility(nextGCD, out act);
- }
-
- [RotationDesc(ActionID.SentinelPvE, ActionID.RampartPvE, ActionID.BulwarkPvE, ActionID.SheltronPvE, ActionID.ReprisalPvE)]
- protected override bool DefenseSingleAbility(IAction nextGCD, out IAction? act)
- {
- act = null;
- if (PassageProtec && Player.HasStatus(true, StatusID.PassageOfArms)) return false;
-
- // If the player has the Hallowed Ground status, don't use any abilities.
- if (!Player.HasStatus(true, StatusID.HallowedGround))
- {
- // If Bulwark can be used, use it and return true.
- if (BulwarkPvE.CanUse(out act, skipAoeCheck: true)) return true;
-
- // If Oath can be used, use it and return true.
- if (UseOath(out act)) return true;
-
- // If Rampart is not cooling down or has been cooling down for more than 60 seconds, and Sentinel can be used, use Sentinel and return true.
- if ((!RampartPvE.Cooldown.IsCoolingDown || RampartPvE.Cooldown.ElapsedAfter(60)) && SentinelPvE.CanUse(out act)) return true;
-
- // If Sentinel is at an enough level and is cooling down for more than 60 seconds, or if Sentinel is not at an enough level, and Rampart can be used, use Rampart and return true.
- if ((SentinelPvE.EnoughLevel && SentinelPvE.Cooldown.IsCoolingDown && SentinelPvE.Cooldown.ElapsedAfter(60) || !SentinelPvE.EnoughLevel) && RampartPvE.CanUse(out act)) return true;
-
- // If Reprisal can be used, use it and return true.
- if (ReprisalPvE.CanUse(out act, skipAoeCheck: true)) return true;
-
- }
- return base.DefenseSingleAbility(nextGCD, out act);
- }
- #endregion
-
- #region oGCD Logic
-
- [RotationDesc(ActionID.SheltronPvE, ActionID.HolySheltronPvE)]
- protected override bool GeneralAbility(IAction nextGCD, out IAction? act)
- {
- act = null;
- if (PassageProtec && Player.HasStatus(true, StatusID.PassageOfArms)) return false;
-
- if (InCombat && OathGauge >= WhenToSheltron && WhenToSheltron > 0 && UseOath(out act)) return true;
- return base.GeneralAbility(nextGCD, out act);
- }
-
- [RotationDesc(ActionID.IntervenePvE, ActionID.SpiritsWithinPvE, ActionID.ExpiacionPvE, ActionID.CircleOfScornPvE, ActionID.RequiescatPvE, ActionID.ImperatorPvE, ActionID.FightOrFlightPvE)]
- protected override bool AttackAbility(IAction nextGCD, out IAction? act)
- {
- act = null;
- if (PassageProtec && Player.HasStatus(true, StatusID.PassageOfArms)) return false;
-
- if (BladeOfHonorPvE.CanUse(out act, skipAoeCheck: true)) return true;
-
- if (!RiotBladePvE.EnoughLevel && nextGCD.IsTheSameTo(true, FastBladePvE) && FightOrFlightPvE.CanUse(out act)) return true;
- if (!RageOfHalonePvE.EnoughLevel && nextGCD.IsTheSameTo(true, RiotBladePvE, TotalEclipsePvE) && FightOrFlightPvE.CanUse(out act)) return true;
- if (!ProminencePvE.EnoughLevel && nextGCD.IsTheSameTo(true, RageOfHalonePvE, TotalEclipsePvE) && FightOrFlightPvE.CanUse(out act)) return true;
- if (!AtonementPvE.EnoughLevel && nextGCD.IsTheSameTo(true, RoyalAuthorityPvE, ProminencePvE) && FightOrFlightPvE.CanUse(out act)) return true;
- if (AtonementPvE.EnoughLevel && (Player.HasStatus(true, StatusID.AtonementReady) || nextGCD.IsTheSameTo(true, ProminencePvE)) && FightOrFlightPvE.CanUse(out act)) return true;
-
- // if requiscat is able to proc confiteor, use it immediately after Fight or Flight
- if (RequiescatMasteryTrait.EnoughLevel)
- {
- if (IsLastAbility(true, FightOrFlightPvE) && ImperatorPvE.CanUse(out act, skipAoeCheck: true, usedUp: true)) return true;
- if (IsLastAbility(true, FightOrFlightPvE) && RequiescatPvE.CanUse(out act, skipAoeCheck: true, usedUp: true)) return true;
- }
-
- // if requiscat is not able to proc confiteor, use it as AOE tool if able, otherwise as Single Target
- if (!RequiescatMasteryTrait.EnoughLevel)
- {
- if (HolyCirclePvE.EnoughLevel && NumberOfHostilesInRange >= 1 && IsLastAbility(true, FightOrFlightPvE) && RequiescatPvE.CanUse(out act, skipAoeCheck: true, usedUp: true)) return true;
- if (!HolyCirclePvE.EnoughLevel && (NumberOfHostilesInRange == 1 || (RequiescatPvE.Target.Target?.IsBossFromIcon() ?? false)) && RequiescatPvE.CanUse(out act, skipAoeCheck: true, usedUp: true)) return true;
- }
-
- if (FightOrFlightPvE.Cooldown.IsCoolingDown && CircleOfScornPvE.CanUse(out act, skipAoeCheck: true)) return true;
- if (FightOrFlightPvE.Cooldown.IsCoolingDown && ExpiacionPvE.CanUse(out act, skipAoeCheck: true)) return true;
- if (FightOrFlightPvE.Cooldown.IsCoolingDown && SpiritsWithinPvE.CanUse(out act)) return true;
- if (!IsMoving && IntervenePvE.CanUse(out act, usedUp: UseInterveneFight && HasFightOrFlight)) return true;
- return base.AttackAbility(nextGCD, out act);
- }
- #endregion
-
- #region GCD Logic
-
- [RotationDesc(ActionID.ClemencyPvE)]
- protected override bool HealSingleGCD(out IAction? act)
- {
- act = null;
- if (PassageProtec && Player.HasStatus(true, StatusID.PassageOfArms)) return false;
- if (ClemencyPvE.Target.Target?.GetHealthRatio() < ClemencyRequi && RequiescatStacks > 0 && ClemencyPvE.CanUse(out act, skipCastingCheck: true)) return true;
- if (HealBot && ClemencyPvE.Target.Target?.GetHealthRatio() < ClemencyNoRequi && ClemencyPvE.CanUse(out act)) return true;
- return base.HealSingleGCD(out act);
- }
-
- [RotationDesc(ActionID.ShieldBashPvE)]
- protected override bool MyInterruptGCD(out IAction? act)
- {
- act = null;
- if (PassageProtec && Player.HasStatus(true, StatusID.PassageOfArms)) return false;
-
- if (LowBlowPvE.Cooldown.IsCoolingDown && ShieldBashPvE.CanUse(out act)) return true;
- return base.MyInterruptGCD(out act);
- }
-
- protected override bool GeneralGCD(out IAction? act)
- {
- act = null;
- if (PassageProtec && Player.HasStatus(true, StatusID.PassageOfArms)) return false;
-
- // Confiteor Combo
- if (ConfiteorPvE.CanUse(out act, usedUp: true, skipAoeCheck: true)) return true;
-
- if (GoringBladePvE.CanUse(out act)) return true;
-
- // Atonement Combo
- if (SepulchrePvE.CanUse(out act)) return true;
- if (SupplicationPvE.CanUse(out act)) return true;
- if (AtonementPvE.CanUse(out act)) return true;
-
- //AoE
- if ((Player.HasStatus(true, StatusID.DivineMight) || RequiescatStacks > 0) && HolyCirclePvE.CanUse(out act, skipCastingCheck: true)) return true;
- if (ProminencePvE.CanUse(out act)) return true;
- if (TotalEclipsePvE.CanUse(out act)) return true;
-
- //Single Target
- if ((Player.HasStatus(true, StatusID.DivineMight) || RequiescatStacks > 0) && HolySpiritPvE.CanUse(out act, skipCastingCheck: true)) return true;
-
- if (RoyalAuthorityPvE.CanUse(out act)) return true;
- if (RageOfHalonePvE.CanUse(out act)) return true;
- if (RiotBladePvE.CanUse(out act)) return true;
- if (FastBladePvE.CanUse(out act)) return true;
-
- //Ranged
- if (UseHolyWhenAway && StopMovingTime > 1 && HolySpiritPvE.CanUse(out act)) return true;
- if (ShieldLobPvE.CanUse(out act)) return true;
- return base.GeneralGCD(out act);
- }
-
- #endregion
-
- #region Extra Methods
-
- private bool UseOath(out IAction? act)
- {
- act = null;
- if ((InterventionPvE.Target.Target?.GetHealthRatio() <= InterventionRatio) && InterventionPvE.CanUse(out act)) return true;
- if (HolySheltronPvE.CanUse(out act)) return true;
- if (SheltronPvE.CanUse(out act)) return true;
- return false;
- }
- #endregion
-}
diff --git a/BasicRotations/Tank/PLD_Default.cs b/BasicRotations/Tank/PLD_Default.cs
index fc4df56ee..220968c6a 100644
--- a/BasicRotations/Tank/PLD_Default.cs
+++ b/BasicRotations/Tank/PLD_Default.cs
@@ -1,9 +1,10 @@
namespace DefaultRotations.Tank;
-[Rotation("Default", CombatType.PvE, GameVersion = "7.15")]
+[Rotation("Beta", CombatType.PvE, GameVersion = "7.15")]
[SourceCode(Path = "main/BasicRotations/Tank/PLD_Default.cs")]
[Api(4)]
-public class PLD_Default : PaladinRotation
+
+public sealed class PLD_Default : PaladinRotation
{
#region Config Options
@@ -13,30 +14,8 @@ public class PLD_Default : PaladinRotation
[RotationConfig(CombatType.PvE, Name = "Use Hallowed Ground with Cover")]
private bool HallowedWithCover { get; set; } = true;
- [Range(1, 8, ConfigUnitType.Pixels)]
- [RotationConfig(CombatType.PvE, Name = "How many GCDs to delay burst by (Assumes you open with Holy Spirit, 2 is best for melee opening) ")]
- private int AdjustedBurst { get; set; } = 3;
-
- [RotationConfig(CombatType.PvE, Name = "Prioritize Atonement Combo During Fight or Flight outside of Opener (Might not good for Dungeons Packs)")]
- private bool PrioritizeAtonementCombo { get; set; } = false;
-
- [RotationConfig(CombatType.PvE, Name = "Use Holy Spirit First (For if you want to MinMax it)")]
- private bool MinMaxHolySpirit { get; set; } = false;
-
- [RotationConfig(CombatType.PvE, Name = "Use Divine Veil at 15 seconds remaining on Countdown")]
- private bool UseDivineVeilPre { get; set; } = false;
-
- [RotationConfig(CombatType.PvE, Name = "Use Holy Circle or Holy Spirit when out of melee range")]
- private bool UseHolyWhenAway { get; set; } = false;
-
- [RotationConfig(CombatType.PvE, Name = "Use Shield Bash when Low Blow is cooling down")]
- private bool UseShieldBash { get; set; } = true;
-
- [RotationConfig(CombatType.PvE, Name = "Allow the Use of Shield Lob")]
- private bool UseShieldLob { get; set; } = true;
-
- [RotationConfig(CombatType.PvE, Name = "Maximize Damage if Target if considered dying")]
- private bool BurstTargetIfConsideredDying { get; set; } = false;
+ [RotationConfig(CombatType.PvE, Name = "Use up both stacks of Intervene during burst window")]
+ private bool UseInterveneFight { get; set; } = true;
[Range(0, 100, ConfigUnitType.Pixels)]
[RotationConfig(CombatType.PvE, Name = "Use Sheltron at minimum X Oath to prevent over cap (Set to 0 to disable)")]
@@ -50,20 +29,19 @@ public class PLD_Default : PaladinRotation
[RotationConfig(CombatType.PvE, Name = "Health threshold for Cover (Set to 0 to disable)")]
private float CoverRatio { get; set; } = 0.3f;
- private bool HasSupplicationReady => Player.HasStatus(true, StatusID.SupplicationReady);
- private bool HasSepulchreReady => Player.HasStatus(true, StatusID.SepulchreReady);
- private bool HasHonorReady => Player.HasStatus(true, StatusID.BladeOfHonorReady);
- private bool TargetIsDying => (HostileTarget?.IsDying() ?? false) && BurstTargetIfConsideredDying;
+ [RotationConfig(CombatType.PvE, Name = "Use Holy Spirit when out of melee range")]
+ private bool UseHolyWhenAway { get; set; } = false;
- private bool HolySpiritFirst(out IAction? act)
- {
- act = null;
- if (MinMaxHolySpirit && HasDivineMight && HolySpiritPvE.CanUse(out act)) return true;
- return false;
- }
+ [Range(0, 1, ConfigUnitType.Percent)]
+ [RotationConfig(CombatType.PvE, Name = "Minimum HP threshold party member needs to be to use Clemency with Requiescat")]
+ public float ClemencyRequi { get; set; } = 0.2f;
- private const ActionID ConfiteorPvEActionId = (ActionID)16459;
- private new readonly IBaseAction ConfiteorPvE = new BaseAction(ConfiteorPvEActionId);
+ [RotationConfig(CombatType.PvE, Name = "Use Clemency without Requiescat")]
+ private bool HealBot { get; set; } = true;
+
+ [Range(0, 1, ConfigUnitType.Percent)]
+ [RotationConfig(CombatType.PvE, Name = "Minimum HP threshold party member needs to be to use Clemency without Requiescat")]
+ public float ClemencyNoRequi { get; set; } = 0.4f;
#endregion
#region Countdown Logic
@@ -72,14 +50,15 @@ private bool HolySpiritFirst(out IAction? act)
if (remainTime < HolySpiritPvE.Info.CastTime + CountDownAhead
&& HolySpiritPvE.CanUse(out var act)) return act;
- if (remainTime < 15 && UseDivineVeilPre
- && DivineVeilPvE.CanUse(out act)) return act;
+ if (remainTime < 15 && DivineVeilPvE.CanUse(out act)) return act;
return base.CountDownAction(remainTime);
}
#endregion
- #region oGCD Logic
+ #region Additional oGCD Logic
+
+ [RotationDesc(ActionID.CoverPvE)]
protected override bool EmergencyAbility(IAction nextGCD, out IAction? act)
{
act = null;
@@ -97,18 +76,52 @@ protected override bool EmergencyAbility(IAction nextGCD, out IAction? act)
if (CoverPvE.CanUse(out act) && CoverPvE.Target.Target?.DistanceToPlayer() < 10 &&
CoverPvE.Target.Target?.GetHealthRatio() < CoverRatio) return true;
+ if (!RiotBladePvE.EnoughLevel && nextGCD.IsTheSameTo(true, FastBladePvE) && FightOrFlightPvE.CanUse(out act)) return true;
+ if (!RageOfHalonePvE.EnoughLevel && nextGCD.IsTheSameTo(true, RiotBladePvE, TotalEclipsePvE) && FightOrFlightPvE.CanUse(out act)) return true;
+ if (!ProminencePvE.EnoughLevel && nextGCD.IsTheSameTo(true, RageOfHalonePvE, TotalEclipsePvE) && FightOrFlightPvE.CanUse(out act)) return true;
+ if (!AtonementPvE.EnoughLevel && nextGCD.IsTheSameTo(true, RoyalAuthorityPvE, ProminencePvE) && FightOrFlightPvE.CanUse(out act)) return true;
+ if (AtonementPvE.EnoughLevel && (Player.HasStatus(true, StatusID.AtonementReady) || IsLastAction(true, RoyalAuthorityPvE)) && FightOrFlightPvE.CanUse(out act)) return true;
+
+ // if requiscat is able to proc confiteor, use it immediately after Fight or Flight
+ if (RequiescatMasteryTrait.EnoughLevel)
+ {
+ if ((IsLastAbility(true, FightOrFlightPvE) || HasFightOrFlight) && ImperatorPvE.CanUse(out act, skipAoeCheck: true, usedUp: true)) return true;
+ if ((IsLastAbility(true, FightOrFlightPvE) || HasFightOrFlight) && RequiescatPvE.CanUse(out act, skipAoeCheck: true, usedUp: true)) return true;
+ }
+
+ // if requiscat is not able to proc confiteor, use it as AOE tool if able, otherwise as Single Target
+ if (!RequiescatMasteryTrait.EnoughLevel)
+ {
+ if (HolyCirclePvE.EnoughLevel && NumberOfHostilesInRange >= 1 && (IsLastAbility(true, FightOrFlightPvE) || HasFightOrFlight) && RequiescatPvE.CanUse(out act, skipAoeCheck: true, usedUp: true)) return true;
+ if (!HolyCirclePvE.EnoughLevel && (NumberOfHostilesInRange == 1 || (RequiescatPvE.Target.Target?.IsBossFromIcon() ?? false)) && RequiescatPvE.CanUse(out act, skipAoeCheck: true, usedUp: true)) return true;
+ }
+
return base.EmergencyAbility(nextGCD, out act);
}
- [RotationDesc(ActionID.IntervenePvE)]
+ [RotationDesc]
protected override bool MoveForwardAbility(IAction nextGCD, out IAction? act)
{
act = null;
if (PassageProtec && Player.HasStatus(true, StatusID.PassageOfArms)) return false;
+
if (IntervenePvE.CanUse(out act)) return true;
return base.MoveForwardAbility(nextGCD, out act);
}
+ [RotationDesc(ActionID.DivineVeilPvE, ActionID.PassageOfArmsPvE)]
+ protected override bool DefenseAreaAbility(IAction nextGCD, out IAction? act)
+ {
+ act = null;
+ if (PassageProtec && Player.HasStatus(true, StatusID.PassageOfArms)) return false;
+
+ if (DivineVeilPvE.CanUse(out act)) return true;
+
+ if (PassageOfArmsPvE.CanUse(out act)) return true;
+
+ return base.DefenseAreaAbility(nextGCD, out act);
+ }
+
[RotationDesc(ActionID.SentinelPvE, ActionID.RampartPvE, ActionID.BulwarkPvE, ActionID.SheltronPvE, ActionID.ReprisalPvE)]
protected override bool DefenseSingleAbility(IAction nextGCD, out IAction? act)
{
@@ -136,134 +149,101 @@ protected override bool DefenseSingleAbility(IAction nextGCD, out IAction? act)
}
return base.DefenseSingleAbility(nextGCD, out act);
}
+ #endregion
- [RotationDesc(ActionID.DivineVeilPvE, ActionID.PassageOfArmsPvE)]
- protected override bool DefenseAreaAbility(IAction nextGCD, out IAction? act)
+ #region oGCD Logic
+
+ [RotationDesc(ActionID.SheltronPvE, ActionID.HolySheltronPvE)]
+ protected override bool GeneralAbility(IAction nextGCD, out IAction? act)
{
act = null;
if (PassageProtec && Player.HasStatus(true, StatusID.PassageOfArms)) return false;
- if (DivineVeilPvE.CanUse(out act)) return true;
-
- if (PassageOfArmsPvE.CanUse(out act)) return true;
-
- return base.DefenseAreaAbility(nextGCD, out act);
+ if (InCombat && OathGauge >= WhenToSheltron && WhenToSheltron > 0 && UseOath(out act)) return true;
+ return base.GeneralAbility(nextGCD, out act);
}
+ [RotationDesc(ActionID.IntervenePvE, ActionID.SpiritsWithinPvE, ActionID.ExpiacionPvE, ActionID.CircleOfScornPvE, ActionID.RequiescatPvE, ActionID.ImperatorPvE, ActionID.FightOrFlightPvE)]
protected override bool AttackAbility(IAction nextGCD, out IAction? act)
{
act = null;
if (PassageProtec && Player.HasStatus(true, StatusID.PassageOfArms)) return false;
- if (WeaponRemain > 0.42f)
- {
- act = null;
-
- if (HasHonorReady && BladeOfHonorPvE.CanUse(out act, skipAoeCheck: true)) return true;
-
- if ((InCombat && !CombatElapsedLessGCD(AdjustedBurst)))
- {
- if (FightOrFlightPvE.CanUse(out act)) return true;
- if (RequiescatPvE.CanUse(out act, skipAoeCheck: true, usedUp: HasFightOrFlight)) return true;
- if (OathGauge >= WhenToSheltron && WhenToSheltron > 0 && UseOath(out act)) return true;
- }
-
- if (CombatElapsedLessGCD(AdjustedBurst + 1)) return false;
-
- if (FightOrFlightPvE.CanUse(out act)) return true;
- if (RequiescatPvE.CanUse(out act, skipAoeCheck: true, usedUp: HasFightOrFlight)) return true;
- if (OathGauge >= WhenToSheltron && WhenToSheltron > 0 && UseOath(out act)) return true;
-
- if (CircleOfScornPvE.CanUse(out act, skipAoeCheck: true)) return true;
- if (SpiritsWithinPvE.CanUse(out act, skipAoeCheck: true)) return true;
-
- if (!IsMoving && IntervenePvE.CanUse(out act, skipAoeCheck: true, usedUp: HasFightOrFlight)) return true;
- }
+ if (BladeOfHonorPvE.CanUse(out act, skipAoeCheck: true)) return true;
+ if (FightOrFlightPvE.Cooldown.IsCoolingDown && CircleOfScornPvE.CanUse(out act, skipAoeCheck: true)) return true;
+ if (FightOrFlightPvE.Cooldown.IsCoolingDown && ExpiacionPvE.CanUse(out act, skipAoeCheck: true)) return true;
+ if (FightOrFlightPvE.Cooldown.IsCoolingDown && SpiritsWithinPvE.CanUse(out act)) return true;
+ if (!IsMoving && IntervenePvE.CanUse(out act, usedUp: UseInterveneFight && HasFightOrFlight)) return true;
return base.AttackAbility(nextGCD, out act);
}
#endregion
#region GCD Logic
- protected override bool GeneralGCD(out IAction? act)
+
+ [RotationDesc(ActionID.ClemencyPvE)]
+ protected override bool HealSingleGCD(out IAction? act)
{
act = null;
if (PassageProtec && Player.HasStatus(true, StatusID.PassageOfArms)) return false;
+ if (ClemencyPvE.Target.Target?.GetHealthRatio() < ClemencyRequi && RequiescatStacks > 0 && ClemencyPvE.CanUse(out act, skipCastingCheck: true)) return true;
+ if (HealBot && ClemencyPvE.Target.Target?.GetHealthRatio() < ClemencyNoRequi && ClemencyPvE.CanUse(out act)) return true;
+ return base.HealSingleGCD(out act);
+ }
- //Minimizes Accidents in EX and Savage Hopefully
- if (IsInHighEndDuty && !InCombat) { act = null; return false; }
-
- if (Player.HasStatus(true, StatusID.Requiescat))
- {
- if ((Player.Level >= 90) && (Player.StatusStack(true, StatusID.Requiescat) < 4))
- {
- if (!TargetIsDying && PrioritizeAtonementCombo && !CombatElapsedLess(30) && (Player.StatusTime(true, StatusID.FightOrFlight) > 12) && AtonementCombo(out act)) return true;
- if (ConfiteorPvE.CanUse(out act, skipAoeCheck: true)) return true;
- }
- if ((Player.Level >= 80) && (Player.StatusStack(true, StatusID.Requiescat) > 3))
- {
- if (!TargetIsDying && PrioritizeAtonementCombo && !CombatElapsedLess(30) && (Player.StatusTime(true, StatusID.FightOrFlight) > 12) && AtonementCombo(out act)) return true;
- if (ConfiteorPvE.CanUse(out act, skipAoeCheck: true)) return true;
- }
- if (HolyCirclePvE.CanUse(out act)) return true;
- if (HolySpiritPvE.CanUse(out act)) return true;
- }
-
- //AOE
- if (HasDivineMight && HolyCirclePvE.CanUse(out act)) return true;
- if (ProminencePvE.CanUse(out act)) return true;
- if (TotalEclipsePvE.CanUse(out act)) return true;
+ [RotationDesc(ActionID.ShieldBashPvE)]
+ protected override bool MyInterruptGCD(out IAction? act)
+ {
+ act = null;
+ if (PassageProtec && Player.HasStatus(true, StatusID.PassageOfArms)) return false;
- //Single
- if (UseShieldBash && ShieldBashPvE.CanUse(out act)) return true;
+ if (LowBlowPvE.Cooldown.IsCoolingDown && ShieldBashPvE.CanUse(out act)) return true;
+ return base.MyInterruptGCD(out act);
+ }
- if (Player.HasStatus(true, StatusID.FightOrFlight) && AtonementCombo(out act)) return true;
- if (TargetIsDying && AtonementCombo(out act)) return true;
+ protected override bool GeneralGCD(out IAction? act)
+ {
+ act = null;
+ if (PassageProtec && Player.HasStatus(true, StatusID.PassageOfArms)) return false;
- //Helps ensure Atonement combo is ready for FoF in cases of unfortunate downtime
- if (((!HasAtonementReady && (HasSepulchreReady || HasSupplicationReady || HasDivineMight)) ||
- (HasAtonementReady && !HasDivineMight)) &&
- !Player.HasStatus(true, StatusID.Medicated) && !RageOfHalonePvE.CanUse(out act, skipComboCheck: false))
- {
- if (RiotBladePvE.CanUse(out act) || FastBladePvE.CanUse(out act)) return true;
- }
+ // Confiteor Combo
+ if (ConfiteorPvE.CanUse(out act, usedUp: true, skipAoeCheck: true)) return true;
- if (!(HasSupplicationReady || HasSepulchreReady || HasDivineMight || HasAtonementReady) && RageOfHalonePvE.CanUse(out act)) return true;
+ if (GoringBladePvE.CanUse(out act)) return true;
- if (AtonementCombo(out act)) return true;
+ // Atonement Combo
+ if (SepulchrePvE.CanUse(out act)) return true;
+ if (SupplicationPvE.CanUse(out act)) return true;
+ if (AtonementPvE.CanUse(out act)) return true;
- if (RiotBladePvE.CanUse(out act) || FastBladePvE.CanUse(out act)) return true;
+ //AoE
+ if ((HasDivineMight || RequiescatStacks > 0) && HolyCirclePvE.CanUse(out act, skipCastingCheck: true)) return true;
+ if (ProminencePvE.CanUse(out act)) return true;
+ if (TotalEclipsePvE.CanUse(out act)) return true;
- //Range
- if (UseHolyWhenAway && Player.CurrentMp > 3000)
- {
- if (HolyCirclePvE.CanUse(out act) || HolySpiritPvE.CanUse(out act))
- return true;
- }
+ //Single Target
+ if ((HasDivineMight || RequiescatStacks > 0) && HolySpiritPvE.CanUse(out act, skipCastingCheck: true)) return true;
- if (UseShieldLob && ShieldLobPvE.CanUse(out act)) return true;
+ if (RoyalAuthorityPvE.CanUse(out act)) return true;
+ if (RageOfHalonePvE.CanUse(out act)) return true;
+ if (RiotBladePvE.CanUse(out act)) return true;
+ if (FastBladePvE.CanUse(out act)) return true;
+ //Ranged
+ if (UseHolyWhenAway && StopMovingTime > 1 && HolySpiritPvE.CanUse(out act)) return true;
+ if (ShieldLobPvE.CanUse(out act)) return true;
return base.GeneralGCD(out act);
}
- [RotationDesc(ActionID.ClemencyPvE)]
- protected override bool HealSingleGCD(out IAction? act)
- {
- act = null;
- if (PassageProtec && Player.HasStatus(true, StatusID.PassageOfArms)) return false;
- if (ClemencyPvE.CanUse(out act)) return true;
- return base.HealSingleGCD(out act);
- }
#endregion
#region Extra Methods
- private bool AtonementCombo(out IAction? act) => HolySpiritFirst(out act) || GoringBladePvE.CanUse(out act) || AtonementPvE.CanUse(out act) || SupplicationPvE.CanUse(out act) || SepulchrePvE.CanUse(out act) || HasDivineMight && HolyCirclePvE.CanUse(out act) || HasDivineMight && HolySpiritPvE.CanUse(out act);
-
private bool UseOath(out IAction? act)
{
act = null;
if ((InterventionPvE.Target.Target?.GetHealthRatio() <= InterventionRatio) && InterventionPvE.CanUse(out act)) return true;
+ if (HolySheltronPvE.CanUse(out act)) return true;
if (SheltronPvE.CanUse(out act)) return true;
return false;
}
diff --git a/BasicRotations/Tank/PLD_Default_Old b/BasicRotations/Tank/PLD_Default_Old
new file mode 100644
index 000000000..022277d70
--- /dev/null
+++ b/BasicRotations/Tank/PLD_Default_Old
@@ -0,0 +1,271 @@
+namespace DefaultRotations.Tank;
+
+[Rotation("Default", CombatType.PvE, GameVersion = "7.15")]
+[SourceCode(Path = "main/BasicRotations/Tank/PLD_Default.cs")]
+[Api(4)]
+public class PLD_Default_Old : PaladinRotation
+{
+ #region Config Options
+
+ [RotationConfig(CombatType.PvE, Name = "Prevent actions while you have Passage of Arms up")]
+ public bool PassageProtec { get; set; } = false;
+
+ [RotationConfig(CombatType.PvE, Name = "Use Hallowed Ground with Cover")]
+ private bool HallowedWithCover { get; set; } = true;
+
+ [Range(1, 8, ConfigUnitType.Pixels)]
+ [RotationConfig(CombatType.PvE, Name = "How many GCDs to delay burst by (Assumes you open with Holy Spirit, 2 is best for melee opening) ")]
+ private int AdjustedBurst { get; set; } = 3;
+
+ [RotationConfig(CombatType.PvE, Name = "Prioritize Atonement Combo During Fight or Flight outside of Opener (Might not good for Dungeons Packs)")]
+ private bool PrioritizeAtonementCombo { get; set; } = false;
+
+ [RotationConfig(CombatType.PvE, Name = "Use Holy Spirit First (For if you want to MinMax it)")]
+ private bool MinMaxHolySpirit { get; set; } = false;
+
+ [RotationConfig(CombatType.PvE, Name = "Use Divine Veil at 15 seconds remaining on Countdown")]
+ private bool UseDivineVeilPre { get; set; } = false;
+
+ [RotationConfig(CombatType.PvE, Name = "Use Holy Circle or Holy Spirit when out of melee range")]
+ private bool UseHolyWhenAway { get; set; } = false;
+
+ [RotationConfig(CombatType.PvE, Name = "Use Shield Bash when Low Blow is cooling down")]
+ private bool UseShieldBash { get; set; } = true;
+
+ [RotationConfig(CombatType.PvE, Name = "Allow the Use of Shield Lob")]
+ private bool UseShieldLob { get; set; } = true;
+
+ [RotationConfig(CombatType.PvE, Name = "Maximize Damage if Target if considered dying")]
+ private bool BurstTargetIfConsideredDying { get; set; } = false;
+
+ [Range(0, 100, ConfigUnitType.Pixels)]
+ [RotationConfig(CombatType.PvE, Name = "Use Sheltron at minimum X Oath to prevent over cap (Set to 0 to disable)")]
+ private int WhenToSheltron { get; set; } = 100;
+
+ [Range(0, 1, ConfigUnitType.Percent)]
+ [RotationConfig(CombatType.PvE, Name = "Health threshold for Intervention (Set to 0 to disable)")]
+ private float InterventionRatio { get; set; } = 0.6f;
+
+ [Range(0, 1, ConfigUnitType.Percent)]
+ [RotationConfig(CombatType.PvE, Name = "Health threshold for Cover (Set to 0 to disable)")]
+ private float CoverRatio { get; set; } = 0.3f;
+
+ private bool HasSupplicationReady => Player.HasStatus(true, StatusID.SupplicationReady);
+ private bool HasSepulchreReady => Player.HasStatus(true, StatusID.SepulchreReady);
+ private bool HasHonorReady => Player.HasStatus(true, StatusID.BladeOfHonorReady);
+ private bool TargetIsDying => (HostileTarget?.IsDying() ?? false) && BurstTargetIfConsideredDying;
+
+ private bool HolySpiritFirst(out IAction? act)
+ {
+ act = null;
+ if (MinMaxHolySpirit && HasDivineMight && HolySpiritPvE.CanUse(out act)) return true;
+ return false;
+ }
+
+ private const ActionID ConfiteorPvEActionId = (ActionID)16459;
+ private new readonly IBaseAction ConfiteorPvE = new BaseAction(ConfiteorPvEActionId);
+ #endregion
+
+ #region Countdown Logic
+ protected override IAction? CountDownAction(float remainTime)
+ {
+ if (remainTime < HolySpiritPvE.Info.CastTime + CountDownAhead
+ && HolySpiritPvE.CanUse(out var act)) return act;
+
+ if (remainTime < 15 && UseDivineVeilPre
+ && DivineVeilPvE.CanUse(out act)) return act;
+
+ return base.CountDownAction(remainTime);
+ }
+ #endregion
+
+ #region oGCD Logic
+ protected override bool EmergencyAbility(IAction nextGCD, out IAction? act)
+ {
+ act = null;
+ if (PassageProtec && Player.HasStatus(true, StatusID.PassageOfArms)) return false;
+
+ if (Player.HasStatus(true, StatusID.Cover) && HallowedWithCover && HallowedGroundPvE.CanUse(out act)) return true;
+
+ if (HallowedGroundPvE.CanUse(out act)
+ && Player.GetHealthRatio() <= HealthForDyingTanks) return true;
+
+ if ((Player.HasStatus(true, StatusID.Rampart) || Player.HasStatus(true, StatusID.Sentinel)) &&
+ InterventionPvE.CanUse(out act) &&
+ InterventionPvE.Target.Target?.GetHealthRatio() < 0.6) return true;
+
+ if (CoverPvE.CanUse(out act) && CoverPvE.Target.Target?.DistanceToPlayer() < 10 &&
+ CoverPvE.Target.Target?.GetHealthRatio() < CoverRatio) return true;
+
+ return base.EmergencyAbility(nextGCD, out act);
+ }
+
+ [RotationDesc(ActionID.IntervenePvE)]
+ protected override bool MoveForwardAbility(IAction nextGCD, out IAction? act)
+ {
+ act = null;
+ if (PassageProtec && Player.HasStatus(true, StatusID.PassageOfArms)) return false;
+ if (IntervenePvE.CanUse(out act)) return true;
+ return base.MoveForwardAbility(nextGCD, out act);
+ }
+
+ [RotationDesc(ActionID.SentinelPvE, ActionID.RampartPvE, ActionID.BulwarkPvE, ActionID.SheltronPvE, ActionID.ReprisalPvE)]
+ protected override bool DefenseSingleAbility(IAction nextGCD, out IAction? act)
+ {
+ act = null;
+ if (PassageProtec && Player.HasStatus(true, StatusID.PassageOfArms)) return false;
+
+ // If the player has the Hallowed Ground status, don't use any abilities.
+ if (!Player.HasStatus(true, StatusID.HallowedGround))
+ {
+ // If Bulwark can be used, use it and return true.
+ if (BulwarkPvE.CanUse(out act, skipAoeCheck: true)) return true;
+
+ // If Oath can be used, use it and return true.
+ if (UseOath(out act)) return true;
+
+ // If Rampart is not cooling down or has been cooling down for more than 60 seconds, and Sentinel can be used, use Sentinel and return true.
+ if ((!RampartPvE.Cooldown.IsCoolingDown || RampartPvE.Cooldown.ElapsedAfter(60)) && SentinelPvE.CanUse(out act)) return true;
+
+ // If Sentinel is at an enough level and is cooling down for more than 60 seconds, or if Sentinel is not at an enough level, and Rampart can be used, use Rampart and return true.
+ if ((SentinelPvE.EnoughLevel && SentinelPvE.Cooldown.IsCoolingDown && SentinelPvE.Cooldown.ElapsedAfter(60) || !SentinelPvE.EnoughLevel) && RampartPvE.CanUse(out act)) return true;
+
+ // If Reprisal can be used, use it and return true.
+ if (ReprisalPvE.CanUse(out act, skipAoeCheck: true)) return true;
+
+ }
+ return base.DefenseSingleAbility(nextGCD, out act);
+ }
+
+ [RotationDesc(ActionID.DivineVeilPvE, ActionID.PassageOfArmsPvE)]
+ protected override bool DefenseAreaAbility(IAction nextGCD, out IAction? act)
+ {
+ act = null;
+ if (PassageProtec && Player.HasStatus(true, StatusID.PassageOfArms)) return false;
+
+ if (DivineVeilPvE.CanUse(out act)) return true;
+
+ if (PassageOfArmsPvE.CanUse(out act)) return true;
+
+ return base.DefenseAreaAbility(nextGCD, out act);
+ }
+
+ protected override bool AttackAbility(IAction nextGCD, out IAction? act)
+ {
+ act = null;
+ if (PassageProtec && Player.HasStatus(true, StatusID.PassageOfArms)) return false;
+
+ if (WeaponRemain > 0.42f)
+ {
+ act = null;
+
+ if (HasHonorReady && BladeOfHonorPvE.CanUse(out act, skipAoeCheck: true)) return true;
+
+ if ((InCombat && !CombatElapsedLessGCD(AdjustedBurst)))
+ {
+ if (FightOrFlightPvE.CanUse(out act)) return true;
+ if (RequiescatPvE.CanUse(out act, skipAoeCheck: true, usedUp: HasFightOrFlight)) return true;
+ if (OathGauge >= WhenToSheltron && WhenToSheltron > 0 && UseOath(out act)) return true;
+ }
+
+ if (CombatElapsedLessGCD(AdjustedBurst + 1)) return false;
+
+ if (FightOrFlightPvE.CanUse(out act)) return true;
+ if (RequiescatPvE.CanUse(out act, skipAoeCheck: true, usedUp: HasFightOrFlight)) return true;
+ if (OathGauge >= WhenToSheltron && WhenToSheltron > 0 && UseOath(out act)) return true;
+
+ if (CircleOfScornPvE.CanUse(out act, skipAoeCheck: true)) return true;
+ if (SpiritsWithinPvE.CanUse(out act, skipAoeCheck: true)) return true;
+
+ if (!IsMoving && IntervenePvE.CanUse(out act, skipAoeCheck: true, usedUp: HasFightOrFlight)) return true;
+ }
+
+ return base.AttackAbility(nextGCD, out act);
+ }
+ #endregion
+
+ #region GCD Logic
+ protected override bool GeneralGCD(out IAction? act)
+ {
+ act = null;
+ if (PassageProtec && Player.HasStatus(true, StatusID.PassageOfArms)) return false;
+
+ //Minimizes Accidents in EX and Savage Hopefully
+ if (IsInHighEndDuty && !InCombat) { act = null; return false; }
+
+ if (Player.HasStatus(true, StatusID.Requiescat))
+ {
+ if ((Player.Level >= 90) && (Player.StatusStack(true, StatusID.Requiescat) < 4))
+ {
+ if (!TargetIsDying && PrioritizeAtonementCombo && !CombatElapsedLess(30) && (Player.StatusTime(true, StatusID.FightOrFlight) > 12) && AtonementCombo(out act)) return true;
+ if (ConfiteorPvE.CanUse(out act, skipAoeCheck: true)) return true;
+ }
+ if ((Player.Level >= 80) && (Player.StatusStack(true, StatusID.Requiescat) > 3))
+ {
+ if (!TargetIsDying && PrioritizeAtonementCombo && !CombatElapsedLess(30) && (Player.StatusTime(true, StatusID.FightOrFlight) > 12) && AtonementCombo(out act)) return true;
+ if (ConfiteorPvE.CanUse(out act, skipAoeCheck: true)) return true;
+ }
+ if (HolyCirclePvE.CanUse(out act)) return true;
+ if (HolySpiritPvE.CanUse(out act)) return true;
+ }
+
+ //AOE
+ if (HasDivineMight && HolyCirclePvE.CanUse(out act)) return true;
+ if (ProminencePvE.CanUse(out act)) return true;
+ if (TotalEclipsePvE.CanUse(out act)) return true;
+
+ //Single
+ if (UseShieldBash && ShieldBashPvE.CanUse(out act)) return true;
+
+ if (Player.HasStatus(true, StatusID.FightOrFlight) && AtonementCombo(out act)) return true;
+ if (TargetIsDying && AtonementCombo(out act)) return true;
+
+ //Helps ensure Atonement combo is ready for FoF in cases of unfortunate downtime
+ if (((!HasAtonementReady && (HasSepulchreReady || HasSupplicationReady || HasDivineMight)) ||
+ (HasAtonementReady && !HasDivineMight)) &&
+ !Player.HasStatus(true, StatusID.Medicated) && !RageOfHalonePvE.CanUse(out act, skipComboCheck: false))
+ {
+ if (RiotBladePvE.CanUse(out act) || FastBladePvE.CanUse(out act)) return true;
+ }
+
+ if (!(HasSupplicationReady || HasSepulchreReady || HasDivineMight || HasAtonementReady) && RageOfHalonePvE.CanUse(out act)) return true;
+
+ if (AtonementCombo(out act)) return true;
+
+ if (RiotBladePvE.CanUse(out act) || FastBladePvE.CanUse(out act)) return true;
+
+ //Range
+ if (UseHolyWhenAway && Player.CurrentMp > 3000)
+ {
+ if (HolyCirclePvE.CanUse(out act) || HolySpiritPvE.CanUse(out act))
+ return true;
+ }
+
+ if (UseShieldLob && ShieldLobPvE.CanUse(out act)) return true;
+
+ return base.GeneralGCD(out act);
+ }
+
+ [RotationDesc(ActionID.ClemencyPvE)]
+ protected override bool HealSingleGCD(out IAction? act)
+ {
+ act = null;
+ if (PassageProtec && Player.HasStatus(true, StatusID.PassageOfArms)) return false;
+ if (ClemencyPvE.CanUse(out act)) return true;
+ return base.HealSingleGCD(out act);
+ }
+ #endregion
+
+ #region Extra Methods
+
+ private bool AtonementCombo(out IAction? act) => HolySpiritFirst(out act) || GoringBladePvE.CanUse(out act) || AtonementPvE.CanUse(out act) || SupplicationPvE.CanUse(out act) || SepulchrePvE.CanUse(out act) || HasDivineMight && HolyCirclePvE.CanUse(out act) || HasDivineMight && HolySpiritPvE.CanUse(out act);
+
+ private bool UseOath(out IAction? act)
+ {
+ act = null;
+ if ((InterventionPvE.Target.Target?.GetHealthRatio() <= InterventionRatio) && InterventionPvE.CanUse(out act)) return true;
+ if (SheltronPvE.CanUse(out act)) return true;
+ return false;
+ }
+ #endregion
+}
diff --git a/RotationSolver.Basic/Rotations/Basic/NinjaRotation.cs b/RotationSolver.Basic/Rotations/Basic/NinjaRotation.cs
index a33a3e81a..47b8d4574 100644
--- a/RotationSolver.Basic/Rotations/Basic/NinjaRotation.cs
+++ b/RotationSolver.Basic/Rotations/Basic/NinjaRotation.cs
@@ -137,7 +137,7 @@ public static byte RaijuStacks
///
///
///
- public static bool IsExecutingMudra => !Player.WillStatusEnd(0, true, StatusID.Mudra);
+ public static bool IsExecutingMudra => !Player.WillStatusEnd(0, true, StatusID.Mudra) || !Player.WillStatusEnd(0, true, StatusID.TenChiJin);
///
///
diff --git a/RotationSolver.Basic/Rotations/Basic/SummonerRotation.cs b/RotationSolver.Basic/Rotations/Basic/SummonerRotation.cs
index 3cf3cb070..3ec1d8127 100644
--- a/RotationSolver.Basic/Rotations/Basic/SummonerRotation.cs
+++ b/RotationSolver.Basic/Rotations/Basic/SummonerRotation.cs
@@ -197,7 +197,7 @@ protected static bool AttunmentTimeEndAfterGCD(uint gcdCount = 0, float offset =
///
///
///
- public static bool MountainBusterPvEReady => Service.GetAdjustedActionId(ActionID.AstralFlowPvE) == ActionID.MountainBusterPvE;
+ public static bool MountainBusterPvEReady => Service.GetAdjustedActionId(ActionID.AstralFlowPvE) == ActionID.MountainBusterPvE_25836;
///
///
///
@@ -245,29 +245,29 @@ public override void DisplayStatus()
ImGui.Text("AttunmentTime: " + AttunmentTime.ToString());
ImGui.Text("HasSummon: " + HasSummon.ToString());
ImGui.TextColored(ImGuiColors.DalamudViolet, "PvE Actions");
- ImGui.Text("AstralImpulsePvEReady: " + AstralImpulsePvEReady.ToString());
- ImGui.Text("AstralFlarePvEReady: " + AstralFlarePvEReady.ToString());
- ImGui.Text("InBahamut: " + InBahamut.ToString());
- ImGui.Text("RubyRitePvEReady: " + RubyRitePvEReady.ToString());
- ImGui.Text("TopazRitePvEReady: " + TopazRitePvEReady.ToString());
- ImGui.Text("EmeraldRitePvEReady: " + EmeraldRitePvEReady.ToString());
- ImGui.Text("SummonPhoenixPvEReady: " + SummonPhoenixPvEReady.ToString());
- ImGui.Text("FountainOfFirePvEReady: " + FountainOfFirePvEReady.ToString());
- ImGui.Text("BrandOfPurgatoryPvEReady: " + BrandOfPurgatoryPvEReady.ToString());
- ImGui.Text("InPhoenix: " + InPhoenix.ToString());
- ImGui.Text("EnkindlePhoenixPvEReady: " + EnkindlePhoenixPvEReady.ToString());
- ImGui.Text("RubyCatastrophePvEReady: " + RubyCatastrophePvEReady.ToString());
- ImGui.Text("TopazCatastrophePvEReady: " + TopazCatastrophePvEReady.ToString());
- ImGui.Text("EmeraldCatastrophePvEReady: " + EmeraldCatastrophePvEReady.ToString());
- ImGui.Text("CrimsonCyclonePvEReady: " + CrimsonCyclonePvEReady.ToString());
- ImGui.Text("CrimsonStrikePvEReady: " + CrimsonStrikePvEReady.ToString());
- ImGui.Text("MountainBusterPvEReady: " + MountainBusterPvEReady.ToString());
- ImGui.Text("SlipstreamPvEReady: " + SlipstreamPvEReady.ToString());
- ImGui.Text("SummonSolarBahamutPvEReady: " + SummonSolarBahamutPvEReady.ToString());
- ImGui.Text("UmbralImpulsePvEReady: " + UmbralImpulsePvEReady.ToString());
- ImGui.Text("UmbralFlarePvEReady: " + UmbralFlarePvEReady.ToString());
- ImGui.Text("InSolarBahamut: " + InSolarBahamut.ToString());
- ImGui.Text("EnkindleSolarBahamutPvEReady: " + EnkindleSolarBahamutPvEReady.ToString());
+ ImGui.TextColored(AstralImpulsePvEReady ? ImGuiColors.HealerGreen : ImGuiColors.DalamudWhite, "AstralImpulsePvEReady: " + AstralImpulsePvEReady.ToString());
+ ImGui.TextColored(AstralFlarePvEReady ? ImGuiColors.HealerGreen : ImGuiColors.DalamudWhite, "AstralFlarePvEReady: " + AstralFlarePvEReady.ToString());
+ ImGui.TextColored(InBahamut ? ImGuiColors.HealerGreen : ImGuiColors.DalamudWhite, "InBahamut: " + InBahamut.ToString());
+ ImGui.TextColored(RubyRitePvEReady ? ImGuiColors.HealerGreen : ImGuiColors.DalamudWhite, "RubyRitePvEReady: " + RubyRitePvEReady.ToString());
+ ImGui.TextColored(TopazRitePvEReady ? ImGuiColors.HealerGreen : ImGuiColors.DalamudWhite, "TopazRitePvEReady: " + TopazRitePvEReady.ToString());
+ ImGui.TextColored(EmeraldRitePvEReady ? ImGuiColors.HealerGreen : ImGuiColors.DalamudWhite, "EmeraldRitePvEReady: " + EmeraldRitePvEReady.ToString());
+ ImGui.TextColored(SummonPhoenixPvEReady ? ImGuiColors.HealerGreen : ImGuiColors.DalamudWhite, "SummonPhoenixPvEReady: " + SummonPhoenixPvEReady.ToString());
+ ImGui.TextColored(FountainOfFirePvEReady ? ImGuiColors.HealerGreen : ImGuiColors.DalamudWhite, "FountainOfFirePvEReady: " + FountainOfFirePvEReady.ToString());
+ ImGui.TextColored(BrandOfPurgatoryPvEReady ? ImGuiColors.HealerGreen : ImGuiColors.DalamudWhite, "BrandOfPurgatoryPvEReady: " + BrandOfPurgatoryPvEReady.ToString());
+ ImGui.TextColored(InPhoenix ? ImGuiColors.HealerGreen : ImGuiColors.DalamudWhite, "InPhoenix: " + InPhoenix.ToString());
+ ImGui.TextColored(EnkindlePhoenixPvEReady ? ImGuiColors.HealerGreen : ImGuiColors.DalamudWhite, "EnkindlePhoenixPvEReady: " + EnkindlePhoenixPvEReady.ToString());
+ ImGui.TextColored(RubyCatastrophePvEReady ? ImGuiColors.HealerGreen : ImGuiColors.DalamudWhite, "RubyCatastrophePvEReady: " + RubyCatastrophePvEReady.ToString());
+ ImGui.TextColored(TopazCatastrophePvEReady ? ImGuiColors.HealerGreen : ImGuiColors.DalamudWhite, "TopazCatastrophePvEReady: " + TopazCatastrophePvEReady.ToString());
+ ImGui.TextColored(EmeraldCatastrophePvEReady ? ImGuiColors.HealerGreen : ImGuiColors.DalamudWhite, "EmeraldCatastrophePvEReady: " + EmeraldCatastrophePvEReady.ToString());
+ ImGui.TextColored(CrimsonCyclonePvEReady ? ImGuiColors.HealerGreen : ImGuiColors.DalamudWhite, "CrimsonCyclonePvEReady: " + CrimsonCyclonePvEReady.ToString());
+ ImGui.TextColored(CrimsonStrikePvEReady ? ImGuiColors.HealerGreen : ImGuiColors.DalamudWhite, "CrimsonStrikePvEReady: " + CrimsonStrikePvEReady.ToString());
+ ImGui.TextColored(SlipstreamPvEReady ? ImGuiColors.HealerGreen : ImGuiColors.DalamudWhite, "SlipstreamPvEReady: " + SlipstreamPvEReady.ToString());
+ ImGui.TextColored(SummonSolarBahamutPvEReady ? ImGuiColors.HealerGreen : ImGuiColors.DalamudWhite, "SummonSolarBahamutPvEReady: " + SummonSolarBahamutPvEReady.ToString());
+ ImGui.TextColored(UmbralImpulsePvEReady ? ImGuiColors.HealerGreen : ImGuiColors.DalamudWhite, "UmbralImpulsePvEReady: " + UmbralImpulsePvEReady.ToString());
+ ImGui.TextColored(UmbralFlarePvEReady ? ImGuiColors.HealerGreen : ImGuiColors.DalamudWhite, "UmbralFlarePvEReady: " + UmbralFlarePvEReady.ToString());
+ ImGui.TextColored(InSolarBahamut ? ImGuiColors.HealerGreen : ImGuiColors.DalamudWhite, "InSolarBahamut: " + InSolarBahamut.ToString());
+ ImGui.TextColored(EnkindleSolarBahamutPvEReady ? ImGuiColors.HealerGreen : ImGuiColors.DalamudWhite, "EnkindleSolarBahamutPvEReady: " + EnkindleSolarBahamutPvEReady.ToString());
+ ImGui.TextColored(MountainBusterPvEReady ? ImGuiColors.HealerGreen : ImGuiColors.DalamudWhite, "MountainBusterPvEReady: " + MountainBusterPvEReady.ToString());
}
#endregion