From 5dbb5d84582caf464e8ade7b3fc27ff53f486478 Mon Sep 17 00:00:00 2001
From: LTS-FFXIV <127939494+LTS-FFXIV@users.noreply.github.com>
Date: Thu, 9 Jan 2025 12:51:26 -0600
Subject: [PATCH] Ninja fixes
---
BasicRotations/Melee/NIN_Default.cs | 41 +++-------
RotationSolver.Basic/Helpers/ObjectHelper.cs | 2 +-
.../Rotations/Basic/NinjaRotation.cs | 80 ++++++++++++++-----
3 files changed, 72 insertions(+), 51 deletions(-)
diff --git a/BasicRotations/Melee/NIN_Default.cs b/BasicRotations/Melee/NIN_Default.cs
index 16eaea9fe..32b4d118f 100644
--- a/BasicRotations/Melee/NIN_Default.cs
+++ b/BasicRotations/Melee/NIN_Default.cs
@@ -16,11 +16,6 @@ public sealed class NIN_Default : NinjaRotation
[RotationConfig(CombatType.PvE, Name = "Use Unhide")]
public bool AutoUnhide { get; set; } = true;
-
- [RotationConfig(CombatType.PvE, Name = "Attempt to lock out all GCDs except mudra during mudra to prevent ghosting")]
- public bool MudraProtection { get; set; } = false;
-
- public bool IsShadowWalking = Player.HasStatus(true, StatusID.ShadowWalker);
#endregion
#region CountDown Logic
@@ -104,34 +99,30 @@ private bool ChoiceNinjutsu(out IAction? act)
{
// Attempts to set high-damage AoE Ninjutsu if available under Kassatsu's effect.
// These are prioritized due to Kassatsu's enhancement of Ninjutsu abilities.
- if (GokaMekkyakuPvE.EnoughLevel && ChiPvE.CanUse(out _) && TenPvE.CanUse(out _))
+ if (NumberOfHostilesInRange > 2 && GokaMekkyakuPvE.EnoughLevel && ChiPvE.CanUse(out _) && TenPvE.CanUse(out _))
{
SetNinjutsu(GokaMekkyakuPvE);
- return false;
}
- if (HyoshoRanryuPvE.EnoughLevel && TenPvE.CanUse(out _) && JinPvE.CanUse(out _))
+ if (NumberOfHostilesInRange == 1 && HyoshoRanryuPvE.EnoughLevel && TenPvE.CanUse(out _) && JinPvE.CanUse(out _))
{
SetNinjutsu(HyoshoRanryuPvE);
- return false;
}
if (HutonPvE.EnoughLevel && TenPvE.CanUse(out _) && ChiPvE.CanUse(out _) && JinPvE.CanUse(out _))
{
SetNinjutsu(HutonPvE);
- return false;
}
if (KatonPvE.EnoughLevel && ChiPvE.CanUse(out _) && TenPvE.CanUse(out _))
{
SetNinjutsu(KatonPvE);
- return false;
}
if (RaitonPvE.EnoughLevel && TenPvE.CanUse(out _) && ChiPvE.CanUse(out _))
{
SetNinjutsu(RaitonPvE);
- return false;
}
+ else return false;
}
else
{
@@ -218,7 +209,7 @@ private bool DoNinjutsu(out IAction? act)
{
if (RaitonPvE_18877.CanUse(out act, skipAoeCheck: true)) return true;
}
- else if (chiId == DotonPvE_18880.ID && !IsLastAction(false, DotonPvE_18880) && !Player.HasStatus(true, StatusID.Doton))
+ else if (chiId == DotonPvE_18880.ID && !IsLastAction(false, DotonPvE_18880) && !HasDoton)
{
if (DotonPvE_18880.CanUse(out act, skipAoeCheck: true)) return true;
}
@@ -230,7 +221,7 @@ private bool DoNinjutsu(out IAction? act)
//Keep Kassatsu in Burst.
if (!Player.WillStatusEnd(3, false, StatusID.Kassatsu)
- && Player.HasStatus(false, StatusID.Kassatsu) && !InTrickAttack) return false;
+ && HasKassatsu && !InTrickAttack) return false;
if (_ninActionAim == null) return false;
var id = AdjustId(ActionID.NinjutsuPvE);
@@ -316,11 +307,6 @@ protected override bool EmergencyAbility(IAction nextGCD, out IAction? act)
// If Ninjutsu is available or not in combat, defers to the base class's emergency ability logic.
if (!NoNinjutsu || !InCombat) return base.EmergencyAbility(nextGCD, out act);
- if (NoNinjutsu)
- {
- if (!CombatElapsedLess(10) && FleetingRaijuPvE.CanUse(out act)) return true;
- }
-
// 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;
@@ -378,7 +364,7 @@ protected override bool AttackAbility(IAction nextGCD, out IAction? act)
// - Not in the Mug's effective window or within Trick Attack's window
// - Certain cooldown conditions are met, or specific statuses are active.
if ((!InMug || InTrickAttack)
- && (!BunshinPvE.Cooldown.WillHaveOneCharge(10) || Player.HasStatus(false, StatusID.PhantomKamaitachiReady) || MugPvE.Cooldown.WillHaveOneCharge(2)))
+ && (!BunshinPvE.Cooldown.WillHaveOneCharge(10) || HasPhantomKamaitachi || MugPvE.Cooldown.WillHaveOneCharge(2)))
{
if (HellfrogMediumPvE.CanUse(out act, skipAoeCheck: !BhavacakraPvE.EnoughLevel)) return true;
if (BhavacakraPvE.CanUse(out act)) return true;
@@ -402,14 +388,14 @@ protected override bool GeneralGCD(out IAction? act)
{
act = null;
- var hasRaijuReady = Player.HasStatus(true, StatusID.RaijuReady);
-
if (RabbitMediumPvE.CanUse(out act)) return true;
- if ((InTrickAttack || InMug) && NoNinjutsu && !hasRaijuReady
+ if ((InTrickAttack || InMug) && NoNinjutsu && !HasRaijuReady
&& !Player.HasStatus(true, StatusID.TenChiJin)
&& PhantomKamaitachiPvE.CanUse(out act)) return true;
+ if (FleetingRaijuPvE.CanUse(out act)) return true;
+
if (ChoiceNinjutsu(out act)) return true;
if ((!InCombat || !CombatElapsedLess(7)) && DoNinjutsu(out act)) return true;
@@ -417,12 +403,7 @@ protected override bool GeneralGCD(out IAction? act)
if (NoNinjutsu)
{
if (!CombatElapsedLess(10) && FleetingRaijuPvE.CanUse(out act)) return true;
- if (hasRaijuReady) return false;
- }
-
- if (IsLastAbility(true, TenPvE, ChiPvE, JinPvE) && MudraProtection)
- {
- return base.GeneralGCD(out act);
+ if (HasRaijuReady) return false;
}
//AOE
@@ -436,7 +417,7 @@ protected override bool GeneralGCD(out IAction? act)
if (SpinningEdgePvE.CanUse(out act)) return true;
//Range
- if (!Player.HasStatus(true, StatusID.Mudra))
+ if (!IsExecutingMudra)
{
if (ThrowingDaggerPvE.CanUse(out act)) return true;
}
diff --git a/RotationSolver.Basic/Helpers/ObjectHelper.cs b/RotationSolver.Basic/Helpers/ObjectHelper.cs
index 3c584776a..d63e5bb37 100644
--- a/RotationSolver.Basic/Helpers/ObjectHelper.cs
+++ b/RotationSolver.Basic/Helpers/ObjectHelper.cs
@@ -47,7 +47,7 @@ internal static bool CanProvoke(this IGameObject target)
{
foreach (var n in ns1)
{
- if (!string.IsNullOrEmpty(n) && new Regex(n).Match(target.Name?.ExtractText() ?? string.Empty).Success)
+ if (!string.IsNullOrEmpty(n) && new Regex(n).Match(target.Name?.GetText() ?? string.Empty).Success)
{
return false;
}
diff --git a/RotationSolver.Basic/Rotations/Basic/NinjaRotation.cs b/RotationSolver.Basic/Rotations/Basic/NinjaRotation.cs
index 6cad3b2a2..a33a3e81a 100644
--- a/RotationSolver.Basic/Rotations/Basic/NinjaRotation.cs
+++ b/RotationSolver.Basic/Rotations/Basic/NinjaRotation.cs
@@ -41,7 +41,7 @@ partial class NinjaRotation
///
/// Checks if no ninjutsu action is currently selected or if the Rabbit Medium has been invoked.
///
- public static bool NoNinjutsu => AdjustId(ActionID.NinjutsuPvE) is ActionID.NinjutsuPvE or ActionID.RabbitMediumPvE;
+ public static bool NoNinjutsu => !IsExecutingMudra || RabbitMediumPvEActive;
///
/// Holds the remaining amount of Delirium stacks
@@ -121,9 +121,49 @@ public static byte RaijuStacks
///
///
///
- public static bool TenriJindoPvEReady => Service.GetAdjustedActionId(ActionID.TenChiJinPvE) == ActionID.TenriJindoPvE;
+ public static bool TenriJindoPvEReady => Service.GetAdjustedActionId(ActionID.TenChiJinPvE) == ActionID.TenriJindoPvE && !HasTenChiJin;
#endregion
+ ///
+ ///
+ ///
+ public static bool HasKassatsu => !Player.WillStatusEnd(0, true, StatusID.Kassatsu);
+
+ ///
+ ///
+ ///
+ public static bool HasRaijuReady => !Player.WillStatusEnd(0, true, StatusID.RaijuReady);
+
+ ///
+ ///
+ ///
+ public static bool IsExecutingMudra => !Player.WillStatusEnd(0, true, StatusID.Mudra);
+
+ ///
+ ///
+ ///
+ public static bool HasDoton => !Player.WillStatusEnd(0, true, StatusID.Doton);
+
+ ///
+ ///
+ ///
+ public static bool IsShadowWalking => !Player.WillStatusEnd(0, true, StatusID.ShadowWalker);
+
+ ///
+ ///
+ ///
+ public static bool HasPhantomKamaitachi => !Player.WillStatusEnd(0, true, StatusID.PhantomKamaitachiReady);
+
+ ///
+ ///
+ ///
+ public static bool HasTenChiJin => !Player.WillStatusEnd(0, true, StatusID.TenChiJin);
+
+ ///
+ ///
+ ///
+ public static bool IsHidden => !Player.WillStatusEnd(0, true, StatusID.Hidden);
+
#region Draw Debug
///
public override void DisplayStatus()
@@ -277,11 +317,12 @@ static partial void ModifyArmorCrushPvE(ref ActionSetting setting)
static partial void ModifyDreamWithinADreamPvE(ref ActionSetting setting)
{
setting.UnlockedByQuestID = 67222;
+ setting.ActionCheck = () => !HasTenChiJin;
}
static partial void ModifyHellfrogMediumPvE(ref ActionSetting setting)
{
- setting.ActionCheck = () => Ninki >= 50;
+ setting.ActionCheck = () => Ninki >= 50 && !HasTenChiJin;
setting.CreateConfig = () => new ActionConfig()
{
AoeCount = 3,
@@ -292,7 +333,7 @@ static partial void ModifyDokumoriPvE(ref ActionSetting setting)
{
setting.StatusProvide = [StatusID.Higi];
setting.TargetStatusProvide = [StatusID.Dokumori];
- setting.ActionCheck = () => Ninki <= 60 && IsLongerThan(10);
+ setting.ActionCheck = () => Ninki <= 60 && IsLongerThan(10) && !HasTenChiJin;
setting.CreateConfig = () => new ActionConfig()
{
TimeToKill = 10,
@@ -305,31 +346,32 @@ static partial void ModifyDokumoriPvE(ref ActionSetting setting)
static partial void ModifyBhavacakraPvE(ref ActionSetting setting)
{
- setting.ActionCheck = () => Ninki >= 50;
+ setting.ActionCheck = () => Ninki >= 50 && !HasTenChiJin;
}
static partial void ModifyTenChiJinPvE(ref ActionSetting setting)
{
+ setting.ActionCheck = () => !HasKassatsu;
setting.StatusProvide = [StatusID.TenChiJin, StatusID.TenriJindoReady];
setting.UnlockedByQuestID = 68488;
}
-
+
static partial void ModifyMeisuiPvE(ref ActionSetting setting)
{
setting.StatusNeed = [StatusID.ShadowWalker];
setting.StatusProvide = [StatusID.Meisui];
- setting.ActionCheck = () => !Player.HasStatus(true, StatusID.Kassatsu) && InCombat;
+ setting.ActionCheck = () => !HasKassatsu && InCombat && !HasTenChiJin;
}
static partial void ModifyBunshinPvE(ref ActionSetting setting)
{
- setting.ActionCheck = () => Ninki >= 50;
+ setting.ActionCheck = () => Ninki >= 50 && !HasTenChiJin;
setting.StatusProvide = [StatusID.Bunshin, StatusID.PhantomKamaitachiReady];
}
static partial void ModifyPhantomKamaitachiPvE(ref ActionSetting setting)
{
- setting.StatusNeed = [StatusID.PhantomKamaitachiReady];
+ setting.ActionCheck = () => HasPhantomKamaitachi;
setting.CreateConfig = () => new ActionConfig()
{
AoeCount = 1,
@@ -338,7 +380,7 @@ static partial void ModifyPhantomKamaitachiPvE(ref ActionSetting setting)
static partial void ModifyHollowNozuchiPvE(ref ActionSetting setting)
{
- setting.StatusNeed = [StatusID.Doton];
+ setting.ActionCheck = () => HasDoton;
setting.CreateConfig = () => new ActionConfig()
{
AoeCount = 1,
@@ -347,17 +389,17 @@ static partial void ModifyHollowNozuchiPvE(ref ActionSetting setting)
static partial void ModifyForkedRaijuPvE(ref ActionSetting setting)
{
- setting.StatusNeed = [StatusID.RaijuReady];
+ setting.ActionCheck = () => HasRaijuReady;
}
static partial void ModifyFleetingRaijuPvE(ref ActionSetting setting)
{
- setting.StatusNeed = [StatusID.RaijuReady];
+ setting.ActionCheck = () => HasRaijuReady;
}
static partial void ModifyKunaisBanePvE(ref ActionSetting setting)
{
- setting.ActionCheck = () => Player.HasStatus(true, StatusID.Hidden) || Player.HasStatus(true, StatusID.ShadowWalker);
+ setting.ActionCheck = () => (IsHidden || IsShadowWalking) && !HasTenChiJin;
setting.TargetStatusProvide = [StatusID.KunaisBane];
setting.CreateConfig = () => new ActionConfig()
{
@@ -367,7 +409,7 @@ static partial void ModifyKunaisBanePvE(ref ActionSetting setting)
static partial void ModifyDeathfrogMediumPvE(ref ActionSetting setting)
{
- setting.ActionCheck = () => Ninki <= 50 && DeathfrogMediumPvEReady;
+ setting.ActionCheck = () => Ninki <= 50 && DeathfrogMediumPvEReady && !HasTenChiJin;
setting.CreateConfig = () => new ActionConfig()
{
AoeCount = 3,
@@ -376,7 +418,7 @@ static partial void ModifyDeathfrogMediumPvE(ref ActionSetting setting)
static partial void ModifyZeshoMeppoPvE(ref ActionSetting setting)
{
- setting.ActionCheck = () => Ninki <= 50 && ZeshoMeppoPvEReady;
+ setting.ActionCheck = () => Ninki <= 50 && ZeshoMeppoPvEReady && !HasTenChiJin;
}
static partial void ModifyTenriJindoPvE(ref ActionSetting setting)
@@ -426,13 +468,11 @@ static partial void ModifyRaitonPvE(ref ActionSetting setting)
static partial void ModifyHyotonPvE(ref ActionSetting setting)
{
setting.ActionCheck = () => HyotonPvEReady;
- setting.TargetStatusProvide = [StatusID.Blind];
}
static partial void ModifyHutonPvE(ref ActionSetting setting)
{
- setting.ActionCheck = () => HutonPvEReady;
- setting.StatusProvide = [StatusID.ShadowWalker];
+ setting.ActionCheck = () => HutonPvEReady && !IsShadowWalking;
setting.CreateConfig = () => new ActionConfig()
{
AoeCount = 3,
@@ -457,7 +497,7 @@ static partial void ModifySuitonPvE(ref ActionSetting setting)
static partial void ModifyGokaMekkyakuPvE(ref ActionSetting setting)
{
- setting.ActionCheck = () => GokaMekkyakuPvEReady;
+ setting.ActionCheck = () => HasKassatsu;
setting.CreateConfig = () => new ActionConfig()
{
AoeCount = 3,
@@ -466,7 +506,7 @@ static partial void ModifyGokaMekkyakuPvE(ref ActionSetting setting)
static partial void ModifyHyoshoRanryuPvE(ref ActionSetting setting)
{
- setting.ActionCheck = () => HyoshoRanryuPvEReady;
+ setting.ActionCheck = () => HasKassatsu;
}
#endregion