From 30e29a9b67e0ab4619eda787239fb5d41264d7fc Mon Sep 17 00:00:00 2001 From: LTS-FFXIV <127939494+LTS-FFXIV@users.noreply.github.com> Date: Tue, 7 Jan 2025 17:41:17 -0600 Subject: [PATCH] Refactor and enhance rotation logic across classes Refactored rotation logic in multiple classes to improve readability, consistency, and performance. Key changes include: - `AST_Default.cs`: Added healer count condition to healing methods. - `SMN_Default.cs`: Added `AddSwiftcastOnRuby` config and logic for Swiftcast. - `NIN_Default.cs`: Added `Dalamud.Interface.Colors` usage, new methods, and improved action handling. - `GNB_Default.PVP.cs`: Added `HypervelocityPvP` check and removed `usedUp` parameter. - `DRK_Default.cs`: Updated `GeneralGCD` to allow `DisesteemPvE` usage. - Introduced `NoMercyLogic` and `InBurstStatus` in `GNB_Default`. - Added new action checks and debug displays in various rotation classes. - Refactored `GunbreakerRotation`, `MachinistRotation`, and `MonkRotation` classes with new properties and methods for PvE action readiness. - Updated `NinjaRotation` with new readiness properties and debug information. - Introduced new `GNB_Beta` class with specialized logic and attributes. --- BasicRotations/Healer/AST_Default.cs | 2 - BasicRotations/Magical/SMN_Default.cs | 8 + BasicRotations/Melee/NIN_Default.cs | 76 +++-- .../PVPRotations/Tank/GNB_Default.PVP.cs | 11 +- BasicRotations/Tank/DRK_Default.cs | 2 +- BasicRotations/Tank/GNB_Beta.cs | 266 ++++++++++++++++ BasicRotations/Tank/GNB_Default.cs | 91 +++--- RotationSolver.Basic/Configuration/Configs.cs | 2 +- .../Rotations/Basic/BardRotation.cs | 17 +- .../Rotations/Basic/BlackMageRotation.cs | 14 +- .../Rotations/Basic/DancerRotation.cs | 57 +++- .../Rotations/Basic/DarkKnightRotation.cs | 50 +-- .../Rotations/Basic/DragoonRotation.cs | 45 ++- .../Rotations/Basic/GunbreakerRotation.cs | 141 ++++++--- .../Rotations/Basic/MachinistRotation.cs | 27 +- .../Rotations/Basic/MonkRotation.cs | 66 +++- .../Rotations/Basic/NinjaRotation.cs | 118 ++++++- .../Rotations/Basic/ReaperRotation.cs | 287 +++++++++++++----- 18 files changed, 1048 insertions(+), 232 deletions(-) create mode 100644 BasicRotations/Tank/GNB_Beta.cs diff --git a/BasicRotations/Healer/AST_Default.cs b/BasicRotations/Healer/AST_Default.cs index 7c6c980e3..d856a9d1f 100644 --- a/BasicRotations/Healer/AST_Default.cs +++ b/BasicRotations/Healer/AST_Default.cs @@ -283,8 +283,6 @@ protected override bool GeneralGCD(out IAction? act) } #endregion - - #region Extra Methods public override bool CanHealSingleSpell => base.CanHealSingleSpell && (GCDHeal || PartyMembers.GetJobCategory(JobRole.Healer).Count() < 2); public override bool CanHealAreaSpell => base.CanHealAreaSpell && (GCDHeal || PartyMembers.GetJobCategory(JobRole.Healer).Count() < 2); diff --git a/BasicRotations/Magical/SMN_Default.cs b/BasicRotations/Magical/SMN_Default.cs index a8abac873..4be3409f2 100644 --- a/BasicRotations/Magical/SMN_Default.cs +++ b/BasicRotations/Magical/SMN_Default.cs @@ -30,6 +30,9 @@ public enum SummonOrderType : byte [RotationConfig(CombatType.PvE, Name = "Use Swiftcast on Garuda")] public bool AddSwiftcastOnGaruda { get; set; } = false; + [RotationConfig(CombatType.PvE, Name = "Use Swiftcast on Ruby Rite if you are not high enough level for Garuda")] + public bool AddSwiftcastOnRuby { get; set; } = false; + [RotationConfig(CombatType.PvE, Name = "Order")] public SummonOrderType SummonOrder { get; set; } = SummonOrderType.TopazEmeraldRuby; @@ -148,6 +151,11 @@ protected override bool EmergencyAbility(IAction nextGCD, out IAction? act) if (SwiftcastPvE.CanUse(out act)) return true; } + if (AddSwiftcastOnRuby && nextGCD == RubyRitePvE && Player.Level < 86) + { + if (SwiftcastPvE.CanUse(out act)) return true; + } + if ((RadiantOnCooldown && RadiantAegisPvE.Cooldown.CurrentCharges == 2 || RadiantAegisPvE.Cooldown.CurrentCharges == 1 && RadiantAegisPvE.Cooldown.WillHaveOneCharge(5)) && (anyBigInvocationIsCoolingDown && Player.Level <= 100) && RadiantAegisPvE.CanUse(out act)) return true; if (RadiantOnCooldown && Player.Level < 88 && anyBigInvocationIsCoolingDown && RadiantAegisPvE.CanUse(out act)) return true; diff --git a/BasicRotations/Melee/NIN_Default.cs b/BasicRotations/Melee/NIN_Default.cs index 6214c6f5a..16eaea9fe 100644 --- a/BasicRotations/Melee/NIN_Default.cs +++ b/BasicRotations/Melee/NIN_Default.cs @@ -1,3 +1,5 @@ +using Dalamud.Interface.Colors; + namespace DefaultRotations.Melee; [Rotation("Default", CombatType.PvE, GameVersion = "7.15")] @@ -82,9 +84,18 @@ private bool ChoiceNinjutsu(out IAction? act) { act = null; - if (!JinPvE.CanUse(out _) || !ChiPvE.CanUse(out _) || !TenPvE.CanUse(out _)) return false; + // If the last action performed matches any of a list of specific actions, it clears the Ninjutsu aim. + // This serves as a reset/cleanup mechanism to ensure the decision logic starts fresh for the next cycle. + if (IsLastAction(true, DotonPvE, SuitonPvE, + RabbitMediumPvE, FumaShurikenPvE, KatonPvE, RaitonPvE, + HyotonPvE, HutonPvE, DotonPvE, SuitonPvE, GokaMekkyakuPvE, HyoshoRanryuPvE)) + { + ClearNinjutsu(); + } + + if ((!JinPvE.CanUse(out _) && JinPvE.EnoughLevel) || (!ChiPvE.CanUse(out _) && ChiPvE.EnoughLevel) || (!TenPvE.CanUse(out _) && 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 (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. if (TimeSinceLastAction.TotalSeconds > 4.5) ClearNinjutsu(); @@ -93,30 +104,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.CanUse(out _) && ChiPvE.CanUse(out _) && TenPvE.CanUse(out _)) + if (GokaMekkyakuPvE.EnoughLevel && ChiPvE.CanUse(out _) && TenPvE.CanUse(out _)) { SetNinjutsu(GokaMekkyakuPvE); return false; } - if (HyoshoRanryuPvE.CanUse(out _) && TenPvE.CanUse(out _) && JinPvE.CanUse(out _)) + if (HyoshoRanryuPvE.EnoughLevel && TenPvE.CanUse(out _) && JinPvE.CanUse(out _)) { SetNinjutsu(HyoshoRanryuPvE); return false; } - if (HutonPvE.CanUse(out _) && TenPvE.CanUse(out _) && ChiPvE.CanUse(out _) && JinPvE.CanUse(out _)) + if (HutonPvE.EnoughLevel && TenPvE.CanUse(out _) && ChiPvE.CanUse(out _) && JinPvE.CanUse(out _)) { SetNinjutsu(HutonPvE); return false; } - if (KatonPvE.CanUse(out _) && ChiPvE.CanUse(out _) && TenPvE.CanUse(out _)) + if (KatonPvE.EnoughLevel && ChiPvE.CanUse(out _) && TenPvE.CanUse(out _)) { SetNinjutsu(KatonPvE); return false; } - if (RaitonPvE.CanUse(out _) && TenPvE.CanUse(out _) && ChiPvE.CanUse(out _)) + if (RaitonPvE.EnoughLevel && TenPvE.CanUse(out _) && ChiPvE.CanUse(out _)) { SetNinjutsu(RaitonPvE); return false; @@ -137,24 +148,23 @@ private bool ChoiceNinjutsu(out IAction? act) // Also considers using Suiton for vulnerability debuff on the enemy if conditions are optimal. //Aoe - if (KatonPvE.CanUse(out _) && ChiPvE.CanUse(out _) && TenPvE.CanUse(out _)) + 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 _)) SetNinjutsu(DotonPvE); else SetNinjutsu(KatonPvE); - return false; } //Single if (!ShadowWalkerNeeded && TenPvE.CanUse(out _, usedUp: InTrickAttack && !Player.HasStatus(false, StatusID.RaijuReady))) { - if (RaitonPvE.CanUse(out _) && TenPvE.CanUse(out _) && ChiPvE.CanUse(out _)) + if (RaitonPvE.EnoughLevel && TenPvE.CanUse(out _) && ChiPvE.CanUse(out _)) { SetNinjutsu(RaitonPvE); return false; } - if (!ChiPvE.EnoughLevel && FumaShurikenPvE.CanUse(out _)) + if (!ChiPvE.EnoughLevel && FumaShurikenPvE.EnoughLevel) { SetNinjutsu(FumaShurikenPvE); return false; @@ -162,21 +172,12 @@ private bool ChoiceNinjutsu(out IAction? act) } //Vulnerable - if (ShadowWalkerNeeded && !Player.HasStatus(true, StatusID.TenChiJin) && SuitonPvE.CanUse(out _, skipStatusProvideCheck: false) && TenPvE.CanUse(out _) && ChiPvE.CanUse(out _) && JinPvE.CanUse(out _)) + if (ShadowWalkerNeeded && (!MeisuiPvE.Cooldown.IsCoolingDown || !TrickAttackPvE.Cooldown.IsCoolingDown || KunaisBanePvE.Cooldown.IsCoolingDown) && !Player.HasStatus(true, StatusID.ShadowWalker) && !Player.HasStatus(true, StatusID.TenChiJin) && SuitonPvE.EnoughLevel && TenPvE.CanUse(out _) && ChiPvE.CanUse(out _) && JinPvE.CanUse(out _)) { SetNinjutsu(SuitonPvE); return false; } } - - // If the last action performed matches any of a list of specific actions, it clears the Ninjutsu aim. - // This serves as a reset/cleanup mechanism to ensure the decision logic starts fresh for the next cycle. - if (IsLastAction(false, DotonPvE, SuitonPvE, - RabbitMediumPvE, FumaShurikenPvE, KatonPvE, RaitonPvE, - HyotonPvE, HutonPvE, DotonPvE, SuitonPvE, GokaMekkyakuPvE, HyoshoRanryuPvE)) - { - ClearNinjutsu(); - } return false; // Indicates that no specific Ninjutsu action was chosen in this cycle. } #endregion @@ -199,7 +200,7 @@ private bool DoNinjutsu(out IAction? act) && !IsLastAction(false, FumaShurikenPvE_18875, FumaShurikenPvE_18873)) { //AOE - if (KatonPvE.CanUse(out _)) + if (KatonPvE.EnoughLevel) { if (FumaShurikenPvE_18875.CanUse(out act)) return true; } @@ -322,6 +323,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 (TenriJindoPvE.CanUse(out act)) return true; @@ -352,7 +354,7 @@ protected override bool AttackAbility(IAction nextGCD, out IAction? act) // If the player is within Trick Attack's effective window, and Ten Chi Jin hasn't recently been used, // then Ten Chi Jin is set as the next action to perform. - if (InTrickAttack && !TenPvE.Cooldown.ElapsedAfter(30) && TenChiJinPvE.CanUse(out act)) return true; + if (InTrickAttack && !Player.HasStatus(true, StatusID.ShadowWalker) && !TenPvE.Cooldown.ElapsedAfter(30) && TenChiJinPvE.CanUse(out act)) return true; // If more than 5 seconds have passed in combat, checks if Bunshin is available to use. if (!CombatElapsedLess(5) && BunshinPvE.CanUse(out act)) return true; @@ -402,6 +404,8 @@ protected override bool GeneralGCD(out IAction? act) var hasRaijuReady = Player.HasStatus(true, StatusID.RaijuReady); + if (RabbitMediumPvE.CanUse(out act)) return true; + if ((InTrickAttack || InMug) && NoNinjutsu && !hasRaijuReady && !Player.HasStatus(true, StatusID.TenChiJin) && PhantomKamaitachiPvE.CanUse(out act)) return true; @@ -451,5 +455,31 @@ protected override bool GeneralGCD(out IAction? act) #region Extra Methods // Holds the next ninjutsu action to perform. private IBaseAction? _ninActionAim = null; + + public override void DisplayStatus() + { + ImGui.Text($"Ninjutsu Action: {_ninActionAim}"); + ImGui.Text($"Ninki: {Ninki}"); + ImGui.Text($"Kazematoi: {Kazematoi}"); + ImGui.Text($"HasJin: {HasJin}"); + ImGui.Text($"InTrickAttack: {InTrickAttack}"); + ImGui.Text($"InMug: {InMug}"); + ImGui.Text($"NoNinjutsu: {NoNinjutsu}"); + ImGui.Text($"RaijuStacks: {RaijuStacks}"); + ImGui.Text($"ShadowWalkerNeeded: {ShadowWalkerNeeded}"); + ImGui.TextColored(ImGuiColors.DalamudViolet, "PvE Actions"); + ImGui.Text("FumaShurikenPvEReady: " + FumaShurikenPvEReady.ToString()); + ImGui.Text("KatonPvEReady: " + KatonPvEReady.ToString()); + ImGui.Text("RaitonPvEReady: " + RaitonPvEReady.ToString()); + ImGui.Text("HyotonPvEReady: " + HyotonPvEReady.ToString()); + ImGui.Text("HutonPvEReady: " + HutonPvEReady.ToString()); + ImGui.Text("DotonPvEReady: " + DotonPvEReady.ToString()); + ImGui.Text("SuitonPvEReady: " + SuitonPvEReady.ToString()); + ImGui.Text("GokaMekkyakuPvEReady: " + GokaMekkyakuPvEReady.ToString()); + ImGui.Text("HyoshoRanryuPvEReady: " + HyoshoRanryuPvEReady.ToString()); + ImGui.Text("DeathfrogMediumPvEReady: " + DeathfrogMediumPvEReady.ToString()); + ImGui.Text("ZeshoMeppoPvEReady: " + ZeshoMeppoPvEReady.ToString()); + ImGui.Text("TenriJindoPvEReady: " + TenriJindoPvEReady.ToString()); + } #endregion } diff --git a/BasicRotations/PVPRotations/Tank/GNB_Default.PVP.cs b/BasicRotations/PVPRotations/Tank/GNB_Default.PVP.cs index 1a7d52cc6..e930f8b10 100644 --- a/BasicRotations/PVPRotations/Tank/GNB_Default.PVP.cs +++ b/BasicRotations/PVPRotations/Tank/GNB_Default.PVP.cs @@ -94,10 +94,11 @@ protected override bool AttackAbility(IAction nextGCD, out IAction? act) act = null; if (GuardCancel && Player.HasStatus(true, StatusID.Guard)) return false; + if (HypervelocityPvP.CanUse(out act)) return true; if (JugularRipPvP.CanUse(out act)) return true; - if (AbdomenTearPvE.CanUse(out act, usedUp: true)) return true; + if (AbdomenTearPvP.CanUse(out act)) return true; if (EyeGougePvP.CanUse(out act)) return true; - if (FatedBrandPvP.CanUse(out act, usedUp: true)) return true; + if (FatedBrandPvP.CanUse(out act)) return true; if (BlastingZonePvP.CanUse(out act)) return true; if (RoughDividePvP.CanUse(out act, usedUp: true)) return true; @@ -120,11 +121,11 @@ protected override bool GeneralGCD(out IAction? act) if (GuardCancel && Player.HasStatus(true, StatusID.Guard)) return false; if (!Player.HasStatus(true, StatusID.Guard) && UseSprintPvP && !Player.HasStatus(true, StatusID.Sprint) && !InCombat && SprintPvP.CanUse(out act)) return true; - if (!JugularRipPvPReady && !AbdomenTearPvPReady && !EyeGougePvPReady && !FatedBrandPvPReady + if (!JugularRipPvPReady && !AbdomenTearPvPReady && !EyeGougePvPReady && !FatedBrandPvPReady && !HypervelocityPvPReady && FatedCirclePvP.CanUse(out act)) return true; - if (WickedTalonPvE.CanUse(out act, usedUp: true)) return true; - if (SavageClawPvP.CanUse(out act, usedUp: true)) return true; + if (WickedTalonPvP.CanUse(out act)) return true; + if (SavageClawPvP.CanUse(out act)) return true; if (GnashingFangPvP.CanUse(out act, usedUp: true)) return true; if (!SavageClawPvPReady && !WickedTalonPvPReady) diff --git a/BasicRotations/Tank/DRK_Default.cs b/BasicRotations/Tank/DRK_Default.cs index 1358e9a88..0ca8fd434 100644 --- a/BasicRotations/Tank/DRK_Default.cs +++ b/BasicRotations/Tank/DRK_Default.cs @@ -136,7 +136,7 @@ protected override bool AttackAbility(IAction nextGCD, out IAction? act) #region GCD Logic protected override bool GeneralGCD(out IAction? act) { - if (DisesteemPvE.CanUse(out act)) return true; + if (DisesteemPvE.CanUse(out act, skipComboCheck: true, skipAoeCheck: true)) return true; //AOE Delirium if (ImpalementPvE.CanUse(out act)) return true; diff --git a/BasicRotations/Tank/GNB_Beta.cs b/BasicRotations/Tank/GNB_Beta.cs new file mode 100644 index 000000000..18da7a1d2 --- /dev/null +++ b/BasicRotations/Tank/GNB_Beta.cs @@ -0,0 +1,266 @@ +namespace DefaultRotations.Tank; + +[Rotation("Beta", CombatType.PvE, GameVersion = "7.15")] +[SourceCode(Path = "main/BasicRotations/Tank/GNB_Beta.cs")] +[Api(4)] +public sealed class GNB_Beta : GunbreakerRotation +{ + #region Countdown Logic + + protected override IAction? CountDownAction(float remainTime) + { + if (remainTime <= 0.7 && LightningShotPvE.CanUse(out var act)) return act; + if (remainTime <= 1.2 && UseBurstMedicine(out act)) return act; + return base.CountDownAction(remainTime); + } + #endregion + + #region Additional oGCD Logic + + [RotationDesc] + protected override bool EmergencyAbility(IAction nextGCD, out IAction? act) + { + // 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 (Player.HasStatus(true, StatusID.NoMercy) && BloodfestPvE.CanUse(out act, skipAoeCheck: true)) 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 sealed 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; + return base.DefenseAreaAbility(nextGCD, out act); + } + + [RotationDesc(ActionID.HeartOfStonePvE, ActionID.NebulaPvE, ActionID.RampartPvE, ActionID.CamouflagePvE, ActionID.ReprisalPvE)] + protected override bool DefenseSingleAbility(IAction nextGCD, out IAction? act) + { + //10 + if (CamouflagePvE.CanUse(out act)) return true; + //15 + if (HeartOfStonePvE.CanUse(out act)) return true; + + //30 + if ((!RampartPvE.Cooldown.IsCoolingDown || RampartPvE.Cooldown.ElapsedAfter(60)) && NebulaPvE.CanUse(out act)) return true; + //20 + if (NebulaPvE.Cooldown.IsCoolingDown && NebulaPvE.Cooldown.ElapsedAfter(60) && RampartPvE.CanUse(out act)) return true; + + if (ReprisalPvE.CanUse(out act)) return true; + + return base.DefenseSingleAbility(nextGCD, out act); + } + + [RotationDesc(ActionID.AuroraPvE)] + 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 (!CombatElapsedLessGCD(5) && NoMercyPvE.CanUse(out act, skipAoeCheck: true)) return true; + + if (JugularRipPvE.CanUse(out act)) return true; + + if (DangerZonePvE.CanUse(out act) && !DoubleDownPvE.EnoughLevel) + { + + if (!IsFullParty && !(DangerZonePvE.Target.Target?.IsBossFromTTK() ?? false)) return true; + + if (!GnashingFangPvE.EnoughLevel && (Player.HasStatus(true, StatusID.NoMercy) || !NoMercyPvE.Cooldown.WillHaveOneCharge(15))) return true; + + if (Player.HasStatus(true, StatusID.NoMercy) && GnashingFangPvE.Cooldown.IsCoolingDown) return true; + + if (!Player.HasStatus(true, StatusID.NoMercy) && !GnashingFangPvE.Cooldown.WillHaveOneCharge(20)) 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; + + 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 (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 (ReignOfBeastsPvE.CanUse(out act, skipAoeCheck: true)) return true; + + if (Player.HasStatus(true, StatusID.NoMercy) && 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 (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; + if (WickedTalonPvE.CanUse(out act, skipComboCheck: true)) return true; + + if (CanUseBurstStrike(out act)) return true; + + if (FatedCirclePvE.CanUse(out act)) return true; + if (DemonSlaughterPvE.CanUse(out act)) return true; + if (DemonSlicePvE.CanUse(out act)) return true; + + 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 (LightningShotPvE.CanUse(out act)) return true; + + return base.GeneralGCD(out act); + } + + #endregion + + #region Extra Methods + public override bool CanHealSingleSpell => false; + + public override bool CanHealAreaSpell => false; + + //private bool CanUseNoMercy(out IAction act) + //{ + // if (!NoMercy.CanUse(out act, CanUseOption.OnLastAbility)) return false; + + // if (!IsFullParty && !IsTargetBoss && !IsMoving && DemonSlice.CanUse(out _)) return true; + + // if (!BurstStrike.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; + // } + + // act = null; + // return false; + //} + + private bool CanUseGnashingFang(out IAction? act) + { + if (GnashingFangPvE.CanUse(out act)) + { + //AOE Check: Mobs = NO, Boss = YES + if (DemonSlicePvE.CanUse(out _)) return false; + + if (Player.HasStatus(true, StatusID.NoMercy) || !NoMercyPvE.Cooldown.WillHaveOneCharge(55)) return true; + + if (Ammo > 0 && !NoMercyPvE.Cooldown.WillHaveOneCharge(17) && NoMercyPvE.Cooldown.WillHaveOneCharge(35)) return true; + + if (Ammo <= 3 && IsLastGCD((ActionID)BrutalShellPvE.ID) && NoMercyPvE.Cooldown.WillHaveOneCharge(3)) return true; + + if (Ammo == 1 && !NoMercyPvE.Cooldown.WillHaveOneCharge(55) && BloodfestPvE.Cooldown.WillHaveOneCharge(5)) return true; + + if (Ammo == 1 && !NoMercyPvE.Cooldown.WillHaveOneCharge(55) && (!BloodfestPvE.Cooldown.IsCoolingDown && BloodfestPvE.EnoughLevel || !BloodfestPvE.EnoughLevel)) return true; + } + return false; + } + + /*private bool CanUseSonicBreak(out IAction act) + { + if (SonicBreakPvE.CanUse(out act)) + { + + if (!GnashingFangPvE.EnoughLevel && Player.HasStatus(true, StatusID.NoMercy)) return true; + + if (!DoubleDownPvE.EnoughLevel && Player.HasStatus(true, StatusID.ReadyToRip) + && GnashingFangPvE.Cooldown.IsCoolingDown) return true; + + } + return false; + }*/ + + private bool CanUseDoubleDown(out IAction? act) + { + if (DoubleDownPvE.CanUse(out act, skipAoeCheck: true)) + { + if (SonicBreakPvE.Cooldown.IsCoolingDown && Player.HasStatus(true, StatusID.NoMercy)) return true; + if (Player.HasStatus(true, StatusID.NoMercy) && !NoMercyPvE.Cooldown.WillHaveOneCharge(55) && BloodfestPvE.Cooldown.WillHaveOneCharge(5)) return true; + + } + return false; + } + + private bool CanUseBurstStrike(out IAction act) + { + if (BurstStrikePvE.CanUse(out act)) + { + if (DemonSlicePvE.CanUse(out _)) return false; + + if (SonicBreakPvE.Cooldown.IsCoolingDown && SonicBreakPvE.Cooldown.WillHaveOneCharge(0.5f) && GnashingFangPvE.EnoughLevel) return false; + + if (Player.HasStatus(true, StatusID.NoMercy) && + AmmoComboStep == 0 && + !GnashingFangPvE.Cooldown.WillHaveOneCharge(1)) return true; + + if (!CartridgeChargeIiTrait.EnoughLevel && Ammo == 2) return true; + + if (IsLastGCD((ActionID)BrutalShellPvE.ID) && + (Ammo == MaxAmmo || + BloodfestPvE.Cooldown.WillHaveOneCharge(6) && Ammo <= 2 && !NoMercyPvE.Cooldown.WillHaveOneCharge(10) && BloodfestPvE.EnoughLevel)) return true; + + } + return false; + } + + private bool CanUseBowShock(out IAction act) + { + if (BowShockPvE.CanUse(out act, skipAoeCheck: true)) + { + //AOE CHECK + if (DemonSlicePvE.CanUse(out _) && !IsFullParty) return true; + + if (!SonicBreakPvE.EnoughLevel && Player.HasStatus(true, StatusID.NoMercy)) return true; + + if (Player.HasStatus(true, StatusID.NoMercy) && SonicBreakPvE.Cooldown.IsCoolingDown) return true; + } + return false; + } + #endregion +} diff --git a/BasicRotations/Tank/GNB_Default.cs b/BasicRotations/Tank/GNB_Default.cs index ff131f879..10808a516 100644 --- a/BasicRotations/Tank/GNB_Default.cs +++ b/BasicRotations/Tank/GNB_Default.cs @@ -5,6 +5,13 @@ namespace DefaultRotations.Tank; [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) { @@ -22,17 +29,22 @@ protected override bool EmergencyAbility(IAction nextGCD, out IAction? act) 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; } + 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.HeartOfLightPvE, ActionID.ReprisalPvE)] 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); } @@ -62,9 +74,9 @@ protected override bool HealSingleAbility(IAction nextGCD, out IAction? 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; @@ -73,23 +85,25 @@ 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; - if (MergedStatus.HasFlag(AutoStatus.MoveForward) && MoveForwardAbility(nextGCD, 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 @@ -99,22 +113,19 @@ 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; @@ -128,9 +139,12 @@ 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; @@ -143,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) { diff --git a/RotationSolver.Basic/Configuration/Configs.cs b/RotationSolver.Basic/Configuration/Configs.cs index f7eb14c18..5b4a2b6a7 100644 --- a/RotationSolver.Basic/Configuration/Configs.cs +++ b/RotationSolver.Basic/Configuration/Configs.cs @@ -482,7 +482,7 @@ public const string Filter = HealingActionCondition, Section = 3)] private static readonly bool _friendlyBattleNPCHeal = false; - [ConditionBool, UI("Heal and raise Party NPCs. (Breaks some fights due to status weirdness)", Description = "Experimental, only enable as needed.", + [ConditionBool, UI("Heal and raise Party NPCs.", Description = "Experimental, only enable as needed.", Filter = HealingActionCondition, Section = 3)] private static readonly bool _friendlyPartyNPCHealRaise2 = false; diff --git a/RotationSolver.Basic/Rotations/Basic/BardRotation.cs b/RotationSolver.Basic/Rotations/Basic/BardRotation.cs index 09fe0dfcd..8b33c710c 100644 --- a/RotationSolver.Basic/Rotations/Basic/BardRotation.cs +++ b/RotationSolver.Basic/Rotations/Basic/BardRotation.cs @@ -1,3 +1,5 @@ +using Dalamud.Interface.Colors; + namespace RotationSolver.Basic.Rotations.Basic; partial class BardRotation @@ -52,6 +54,17 @@ partial class BardRotation /// protected static bool SongEndAfterGCD(uint gctCount = 0, float offset = 0) => SongEndAfter(GCDTime(gctCount, offset)); + #endregion + + #region PvE Actions Unassignable + + /// + /// + /// + public static bool BlastArrowPvEReady => Service.GetAdjustedActionId(ActionID.ApexArrowPvE) == ActionID.BlastArrowPvE; + #endregion + + #region Draw Debug /// public override void DisplayStatus() @@ -64,6 +77,8 @@ public override void DisplayStatus() ImGui.Text("SongTime: " + SongTime.ToString()); ImGui.Text("BloodletterMax: " + BloodletterMax.ToString()); ImGui.Text("Bloodlettercharges: " + BloodletterPvE.Cooldown.CurrentCharges.ToString()); + ImGui.TextColored(ImGuiColors.DalamudViolet, "PvE Actions"); + ImGui.Text("BlastArrowPvEReady: " + BlastArrowPvEReady.ToString()); } #endregion @@ -310,7 +325,7 @@ static partial void ModifyLadonsbitePvE(ref ActionSetting setting) static partial void ModifyBlastArrowPvE(ref ActionSetting setting) { - setting.StatusNeed = [StatusID.BlastArrowReady]; + setting.ActionCheck = () => BlastArrowPvEReady; setting.CreateConfig = () => new ActionConfig() { AoeCount = 1, diff --git a/RotationSolver.Basic/Rotations/Basic/BlackMageRotation.cs b/RotationSolver.Basic/Rotations/Basic/BlackMageRotation.cs index 5d717b9d5..4bc3f66dd 100644 --- a/RotationSolver.Basic/Rotations/Basic/BlackMageRotation.cs +++ b/RotationSolver.Basic/Rotations/Basic/BlackMageRotation.cs @@ -1,4 +1,6 @@ -namespace RotationSolver.Basic.Rotations.Basic; +using Dalamud.Interface.Colors; + +namespace RotationSolver.Basic.Rotations.Basic; partial class BlackMageRotation { @@ -164,6 +166,13 @@ public static bool IsPolyglotStacksMaxed protected static bool HasThunder => Player.HasStatus(true, StatusID.Thunderhead); #endregion + #region PvE Actions Unassignable + /// + /// + /// + public static bool ParadoxPvEReady => Service.GetAdjustedActionId(ActionID.FirePvE) == ActionID.ParadoxPvE; + #endregion + #region Debug /// public override void DisplayStatus() @@ -183,6 +192,9 @@ public override void DisplayStatus() ImGui.Text("IsEnochianActive: " + IsEnochianActive.ToString()); ImGui.Text("EnochianTimeRaw: " + EnochianTimeRaw.ToString()); ImGui.Text("EnochianTime: " + EnochianTime.ToString()); + ImGui.TextColored(ImGuiColors.DalamudViolet, "PvE Actions"); + ImGui.Text("ParadoxPvEReady: " + ParadoxPvEReady.ToString()); + ImGui.TextColored(ImGuiColors.DalamudOrange, "PvP Actions"); ImGui.Text("HasPvPAstralFire: " + HasPvPAstralFire.ToString()); ImGui.Text("HasPvPUmbralIce: " + HasPvPUmbralIce.ToString()); } diff --git a/RotationSolver.Basic/Rotations/Basic/DancerRotation.cs b/RotationSolver.Basic/Rotations/Basic/DancerRotation.cs index c005040c2..be71a7437 100644 --- a/RotationSolver.Basic/Rotations/Basic/DancerRotation.cs +++ b/RotationSolver.Basic/Rotations/Basic/DancerRotation.cs @@ -1,4 +1,6 @@ -namespace RotationSolver.Basic.Rotations.Basic; +using Dalamud.Interface.Colors; + +namespace RotationSolver.Basic.Rotations.Basic; partial class DancerRotation { @@ -7,6 +9,7 @@ partial class DancerRotation /// public override MedicineType MedicineType => MedicineType.Dexterity; + #region Job Gauge /// /// /// @@ -26,6 +29,42 @@ partial class DancerRotation /// /// public static byte CompletedSteps => JobGauge.CompletedSteps; + #endregion + + #region PvE Actions Unassignable + + /// + /// + /// + public static bool StandardFinishPvEReady => Service.GetAdjustedActionId(ActionID.StandardStepPvE) == ActionID.StandardFinishPvE; + + /// + /// + /// + public static bool TechnicalFinishPvEReady => Service.GetAdjustedActionId(ActionID.TechnicalStepPvE) == ActionID.TechnicalFinishPvE; + + /// + /// + /// + public static bool ImprovisedFinishPvEReady => Service.GetAdjustedActionId(ActionID.ImprovisationPvE) == ActionID.ImprovisedFinishPvE; + + /// + /// + /// + public static bool TillanaPvEReady => Service.GetAdjustedActionId(ActionID.TechnicalStepPvE) == ActionID.TillanaPvE; + + /// + /// + /// + public static bool FinishingMovePvEReady => Service.GetAdjustedActionId(ActionID.StandardStepPvE) == ActionID.FinishingMovePvE; + + /// + /// + /// + public static bool DanceOfTheDawnPvEReady => Service.GetAdjustedActionId(ActionID.SaberDancePvE) == ActionID.DanceOfTheDawnPvE; + #endregion + + #region Debug Status /// public override void DisplayStatus() @@ -34,7 +73,15 @@ public override void DisplayStatus() ImGui.Text("Esprit: " + Esprit.ToString()); ImGui.Text("Feathers: " + Feathers.ToString()); ImGui.Text("CompletedSteps: " + CompletedSteps.ToString()); + ImGui.TextColored(ImGuiColors.DalamudViolet, "PvE Actions"); + ImGui.Text("StandardFinishPvEReady: " + StandardFinishPvEReady.ToString()); + ImGui.Text("TechnicalFinishPvE: " + TechnicalFinishPvE.ToString()); + ImGui.Text("ImprovisedFinishPvEReady: " + ImprovisedFinishPvEReady.ToString()); + ImGui.Text("TillanaPvEReady: " + TillanaPvEReady.ToString()); + ImGui.Text("FinishingMovePvEReady: " + FinishingMovePvEReady.ToString()); + ImGui.Text("DanceOfTheDawnPvEReady: " + DanceOfTheDawnPvEReady.ToString()); } + #endregion static partial void ModifyCascadePvE(ref ActionSetting setting) { @@ -182,8 +229,7 @@ static partial void ModifyStarfallDancePvE(ref ActionSetting setting) static partial void ModifyTillanaPvE(ref ActionSetting setting) { - setting.ActionCheck = () => Esprit <= 50; - setting.StatusNeed = [StatusID.FlourishingFinish]; + setting.ActionCheck = () => Esprit <= 50 && TillanaPvEReady; setting.CreateConfig = () => new ActionConfig() { AoeCount = 1, @@ -292,7 +338,7 @@ static partial void ModifyLastDancePvE(ref ActionSetting setting) static partial void ModifyFinishingMovePvE(ref ActionSetting setting) { - setting.StatusNeed = [StatusID.FinishingMoveReady]; + setting.ActionCheck = () => FinishingMovePvEReady; setting.StatusProvide = [StatusID.LastDanceReady]; setting.CreateConfig = () => new ActionConfig() { @@ -303,8 +349,7 @@ static partial void ModifyFinishingMovePvE(ref ActionSetting setting) static partial void ModifyDanceOfTheDawnPvE(ref ActionSetting setting) { - setting.ActionCheck = () => Esprit >= 50; - setting.StatusNeed = [StatusID.DanceOfTheDawnReady]; + setting.ActionCheck = () => Esprit >= 50 && DanceOfTheDawnPvEReady; setting.CreateConfig = () => new ActionConfig() { AoeCount = 1, diff --git a/RotationSolver.Basic/Rotations/Basic/DarkKnightRotation.cs b/RotationSolver.Basic/Rotations/Basic/DarkKnightRotation.cs index 29b4b788a..481c3bdf3 100644 --- a/RotationSolver.Basic/Rotations/Basic/DarkKnightRotation.cs +++ b/RotationSolver.Basic/Rotations/Basic/DarkKnightRotation.cs @@ -23,26 +23,6 @@ partial class DarkKnightRotation /// public static bool HasDelirium => !Player.WillStatusEnd(0, true, StatusID.Delirium_3836); - /// - /// - /// - public static bool ScarletDeliriumReady => Service.GetAdjustedActionId(ActionID.BloodspillerPvE) == ActionID.ScarletDeliriumPvE; - - /// - /// - /// - public static bool ComeuppanceReady => Service.GetAdjustedActionId(ActionID.BloodspillerPvE) == ActionID.ComeuppancePvE; - - /// - /// - /// - public static bool TorcleaverReady => Service.GetAdjustedActionId(ActionID.BloodspillerPvE) == ActionID.TorcleaverPvE; - - /// - /// - /// - public static bool ImpalementReady => Service.GetAdjustedActionId(ActionID.QuietusPvE) == ActionID.ImpalementPvE; - static float DarkSideTimeRemainingRaw => JobGauge.DarksideTimeRemaining / 1000f; /// @@ -88,7 +68,9 @@ protected static bool DarkSideEndAfterGCD(uint gctCount = 0, float offset = 0) /// protected static bool ShadowTimeEndAfterGCD(uint gctCount = 0, float offset = 0) => ShadowTimeEndAfter(GCDTime(gctCount, offset)); + #endregion + #region Status Tracking /// /// Holds the remaining amount of BloodWeapon stacks /// @@ -124,6 +106,32 @@ public static byte LowDeliriumStacks return stacks == byte.MaxValue ? (byte)3 : stacks; } } + #endregion + + #region PvE Actions Unassignable + + /// + /// + /// + public static bool ScarletDeliriumReady => Service.GetAdjustedActionId(ActionID.BloodspillerPvE) == ActionID.ScarletDeliriumPvE; + + /// + /// + /// + public static bool ComeuppanceReady => Service.GetAdjustedActionId(ActionID.BloodspillerPvE) == ActionID.ComeuppancePvE; + + /// + /// + /// + public static bool TorcleaverReady => Service.GetAdjustedActionId(ActionID.BloodspillerPvE) == ActionID.TorcleaverPvE; + + /// + /// + /// + public static bool ImpalementReady => Service.GetAdjustedActionId(ActionID.QuietusPvE) == ActionID.ImpalementPvE; + #endregion + + #region Draw Debug /// public override void DisplayStatus() @@ -143,6 +151,7 @@ public override void DisplayStatus() } #endregion + #region PvE Actions static partial void ModifyHardSlashPvE(ref ActionSetting setting) { @@ -399,6 +408,7 @@ static partial void ModifyDisesteemPvE(ref ActionSetting setting) AoeCount = 1, }; } + #endregion /// protected override bool EmergencyAbility(IAction nextGCD, out IAction? act) diff --git a/RotationSolver.Basic/Rotations/Basic/DragoonRotation.cs b/RotationSolver.Basic/Rotations/Basic/DragoonRotation.cs index 684a5351b..797164747 100644 --- a/RotationSolver.Basic/Rotations/Basic/DragoonRotation.cs +++ b/RotationSolver.Basic/Rotations/Basic/DragoonRotation.cs @@ -1,10 +1,13 @@ -namespace RotationSolver.Basic.Rotations.Basic; +using Dalamud.Interface.Colors; + +namespace RotationSolver.Basic.Rotations.Basic; partial class DragoonRotation { /// public override MedicineType MedicineType => MedicineType.Strength; + #region Job Gauge /// /// /// @@ -40,6 +43,32 @@ partial class DragoonRotation /// protected static bool LOTDEndAfterGCD(uint gctCount = 0, float offset = 0) => LOTDEndAfter(GCDTime(gctCount, offset)); + #endregion + + #region PvE Actions Unassignable + + /// + /// + /// + public static bool DrakesbanePvEFangReady => Service.GetAdjustedActionId(ActionID.FangAndClawPvE) == ActionID.DrakesbanePvE; + + /// + /// + /// + public static bool DrakesbanePvEWheelingReady => Service.GetAdjustedActionId(ActionID.WheelingThrustPvE) == ActionID.DrakesbanePvE; + + /// + /// + /// + public static bool RaidenThrustPvEReady => Service.GetAdjustedActionId(ActionID.TrueThrustPvE) == ActionID.RaidenThrustPvE; + + /// + /// + /// + public static bool DraconianFuryPvEReady => Service.GetAdjustedActionId(ActionID.DoomSpikePvE) == ActionID.DraconianFuryPvE; + #endregion + + #region Draw Debug /// public override void DisplayStatus() @@ -48,9 +77,15 @@ public override void DisplayStatus() ImGui.Text("FocusCount: " + FocusCount.ToString()); ImGui.Text("LOTDTimeRaw: " + LOTDTimeRaw.ToString()); ImGui.Text("LOTDTime: " + LOTDTime.ToString()); + ImGui.TextColored(ImGuiColors.DalamudViolet, "PvE Actions"); + ImGui.Text("DrakesbanePvEFangReady: " + DrakesbanePvEFangReady.ToString()); + ImGui.Text("DrakesbanePvEWheelingReady: " + DrakesbanePvEWheelingReady.ToString()); + ImGui.Text("RaidenThrustPvEReady: " + RaidenThrustPvEReady.ToString()); + ImGui.Text("DraconianFuryPvEReady: " + DraconianFuryPvEReady.ToString()); } + #endregion - //Job + #region PvE Actions static partial void ModifyTrueThrustPvE(ref ActionSetting setting) { @@ -194,6 +229,7 @@ static partial void ModifySonicThrustPvE(ref ActionSetting setting) static partial void ModifyDrakesbanePvE(ref ActionSetting setting) //aka Kendrick Lamar { + setting.ActionCheck = () => DrakesbanePvEFangReady || DrakesbanePvEWheelingReady; setting.ComboIds = [ActionID.WheelingThrustPvE, ActionID.FangAndClawPvE]; setting.StatusProvide = [StatusID.DraconianFire]; setting.CreateConfig = () => new ActionConfig() @@ -234,7 +270,7 @@ static partial void ModifyHighJumpPvE(ref ActionSetting setting) static partial void ModifyRaidenThrustPvE(ref ActionSetting setting) { - setting.StatusNeed = [StatusID.DraconianFire]; + setting.ActionCheck = () => RaidenThrustPvEReady; } static partial void ModifyStardiverPvE(ref ActionSetting setting) @@ -249,7 +285,7 @@ static partial void ModifyStardiverPvE(ref ActionSetting setting) static partial void ModifyDraconianFuryPvE(ref ActionSetting setting) { - setting.StatusNeed = [StatusID.DraconianFire]; + setting.ActionCheck = () => DraconianFuryPvEReady; setting.CreateConfig = () => new ActionConfig() { AoeCount = 3, @@ -313,6 +349,7 @@ static partial void ModifyStarcrossPvE(ref ActionSetting setting) AoeCount = 1, }; } + #endregion // PvP static partial void ModifyHighJumpPvP(ref ActionSetting setting) diff --git a/RotationSolver.Basic/Rotations/Basic/GunbreakerRotation.cs b/RotationSolver.Basic/Rotations/Basic/GunbreakerRotation.cs index 5e4dbefad..c3adfb55e 100644 --- a/RotationSolver.Basic/Rotations/Basic/GunbreakerRotation.cs +++ b/RotationSolver.Basic/Rotations/Basic/GunbreakerRotation.cs @@ -6,8 +6,6 @@ partial class GunbreakerRotation { /// public override MedicineType MedicineType => MedicineType.Strength; - - /// /// /// @@ -30,14 +28,84 @@ partial class GunbreakerRotation public static byte AmmoComboStep => JobGauge.AmmoComboStep; /// - /// + /// Gets the maximum amount of ammo available. /// - public static byte MaxAmmo => CartridgeChargeIiTrait.EnoughLevel ? (byte)3 : (byte)2; + public static byte MaxAmmo + { + get + { + if (CartridgeChargeIiTrait.EnoughLevel) + { + return 3; + } + else if (CartridgeChargeTrait.EnoughLevel) + { + return 2; + } + else + { + return 0; + } + } + } /// /// Gets the max combo time of the Gnashing Fang combo. /// public static short MaxTimerDuration => JobGauge.MaxTimerDuration; + + /// + /// + /// + public static bool InGnashingFang => AmmoComboStep > 0; + #endregion + + #region PvE Actions Unassignable + + /// + /// + /// + public static bool SavageClawPvEReady => Service.GetAdjustedActionId(ActionID.GnashingFangPvE) == ActionID.SavageClawPvE; + + /// + /// + /// + public static bool WickedTalonPvEReady => Service.GetAdjustedActionId(ActionID.GnashingFangPvE) == ActionID.WickedTalonPvE; + + /// + /// + /// + public static bool JugularRipPvEReady => Service.GetAdjustedActionId(ActionID.ContinuationPvE) == ActionID.JugularRipPvE; + + /// + /// + /// + public static bool AbdomenTearPvEReady => Service.GetAdjustedActionId(ActionID.ContinuationPvE) == ActionID.AbdomenTearPvE; + + /// + /// + /// + public static bool EyeGougePvEReady => Service.GetAdjustedActionId(ActionID.ContinuationPvE) == ActionID.EyeGougePvE; + + /// + /// + /// + public static bool HypervelocityPvEReady => Service.GetAdjustedActionId(ActionID.ContinuationPvE) == ActionID.HypervelocityPvE; + + /// + /// + /// + public static bool FatedBrandPvEReady => Service.GetAdjustedActionId(ActionID.ContinuationPvE) == ActionID.FatedBrandPvE; + + /// + /// + /// + public static bool NobleBloodPvEReady => Service.GetAdjustedActionId(ActionID.ReignOfBeastsPvE) == ActionID.NobleBloodPvE; + + /// + /// + /// + public static bool LionHeartPvEReady => Service.GetAdjustedActionId(ActionID.ReignOfBeastsPvE) == ActionID.LionHeartPvE; #endregion #region Debug Status @@ -49,6 +117,19 @@ public override void DisplayStatus() ImGui.Text("AmmoComboStep: " + AmmoComboStep.ToString()); ImGui.Text("MaxAmmo: " + MaxAmmo.ToString()); ImGui.Text("MaxTimerDuration: " + MaxTimerDuration.ToString()); + ImGui.TextColored(ImGuiColors.DalamudViolet, "PvE Actions"); + ImGui.Text("SavageClawPvEReady: " + SavageClawPvEReady.ToString()); + ImGui.Text("WickedTalonPvEReady: " + WickedTalonPvEReady.ToString()); + ImGui.Spacing(); + ImGui.Text("JugularRipPvEReady: " + JugularRipPvEReady.ToString()); + ImGui.Text("AbdomenTearPvEReady: " + AbdomenTearPvEReady.ToString()); + ImGui.Text("EyeGougePvEReady: " + EyeGougePvEReady.ToString()); + ImGui.Text("HypervelocityPvEReady: " + HypervelocityPvEReady.ToString()); + ImGui.Spacing(); + ImGui.Text("FatedBrandPvEReady: " + FatedBrandPvEReady.ToString()); + ImGui.Spacing(); + ImGui.Text("NobleBloodPvEReady: " + NobleBloodPvEReady.ToString()); + ImGui.Text("LionHeartPvEReady: " + LionHeartPvEReady.ToString()); ImGui.TextColored(ImGuiColors.DalamudYellow, "PvP Actions"); ImGui.Text("SavageClawPvPReady: " + SavageClawPvPReady.ToString()); ImGui.Text("WickedTalonPvPReady: " + WickedTalonPvPReady.ToString()); @@ -75,18 +156,19 @@ static partial void ModifyNoMercyPvE(ref ActionSetting setting) setting.StatusProvide = [StatusID.ReadyToBreak]; setting.CreateConfig = () => new ActionConfig() { - TimeToKill = 10, + TimeToKill = 5, }; } static partial void ModifyBrutalShellPvE(ref ActionSetting setting) { - setting.ComboIds = [ActionID.KeenEdgePvE]; + } static partial void ModifyCamouflagePvE(ref ActionSetting setting) { setting.TargetType = TargetType.Self; + setting.IsFriendly = true; } static partial void ModifyDemonSlicePvE(ref ActionSetting setting) @@ -111,7 +193,7 @@ static partial void ModifyDangerZonePvE(ref ActionSetting setting) static partial void ModifySolidBarrelPvE(ref ActionSetting setting) { - setting.ComboIds = [ActionID.BrutalShellPvE]; + } static partial void ModifyBurstStrikePvE(ref ActionSetting setting) @@ -123,12 +205,12 @@ static partial void ModifyBurstStrikePvE(ref ActionSetting setting) static partial void ModifyNebulaPvE(ref ActionSetting setting) { setting.StatusProvide = StatusHelper.RampartStatus; - setting.ActionCheck = () => Player.IsTargetOnSelf(); + setting.TargetType = TargetType.Self; + setting.IsFriendly = true; } static partial void ModifyDemonSlaughterPvE(ref ActionSetting setting) { - setting.ComboIds = [ActionID.DemonSlicePvE]; setting.CreateConfig = () => new ActionConfig() { AoeCount = 2, @@ -166,15 +248,13 @@ static partial void ModifyGnashingFangPvE(ref ActionSetting setting) static partial void ModifySavageClawPvE(ref ActionSetting setting) { - setting.ActionCheck = () => Service.GetAdjustedActionId(ActionID.GnashingFangPvE) == ActionID.SavageClawPvE; - setting.ComboIds = [ActionID.GnashingFangPvE]; + setting.ActionCheck = () => SavageClawPvEReady; setting.StatusProvide = [StatusID.ReadyToTear]; } static partial void ModifyWickedTalonPvE(ref ActionSetting setting) { - setting.ActionCheck = () => Service.GetAdjustedActionId(ActionID.GnashingFangPvE) == ActionID.WickedTalonPvE; - setting.ComboIds = [ActionID.SavageClawPvE]; + setting.ActionCheck = () => WickedTalonPvEReady; setting.StatusProvide = [StatusID.ReadyToGouge]; } @@ -195,7 +275,7 @@ static partial void ModifyHeartOfLightPvE(ref ActionSetting setting) static partial void ModifyHeartOfStonePvE(ref ActionSetting setting) { setting.StatusProvide = [StatusID.HeartOfStone]; - setting.ActionCheck = () => Player.IsParty() || Player.IsTargetOnSelf(); + setting.IsFriendly = true; } static partial void ModifyContinuationPvE(ref ActionSetting setting) @@ -205,22 +285,19 @@ static partial void ModifyContinuationPvE(ref ActionSetting setting) static partial void ModifyJugularRipPvE(ref ActionSetting setting) { - setting.ActionCheck = () => Service.GetAdjustedActionId(ActionID.ContinuationPvE) == ActionID.JugularRipPvE; - setting.ComboIds = [ActionID.GnashingFangPvE]; + setting.ActionCheck = () => JugularRipPvEReady; setting.StatusNeed = [StatusID.ReadyToRip]; } static partial void ModifyAbdomenTearPvE(ref ActionSetting setting) { - setting.ActionCheck = () => Service.GetAdjustedActionId(ActionID.ContinuationPvE) == ActionID.AbdomenTearPvE; - setting.ComboIds = [ActionID.SavageClawPvE]; + setting.ActionCheck = () => AbdomenTearPvEReady; setting.StatusNeed = [StatusID.ReadyToTear]; } static partial void ModifyEyeGougePvE(ref ActionSetting setting) { - setting.ActionCheck = () => Service.GetAdjustedActionId(ActionID.ContinuationPvE) == ActionID.EyeGougePvE; - setting.ComboIds = [ActionID.WickedTalonPvE]; + setting.ActionCheck = () => EyeGougePvEReady; setting.StatusNeed = [StatusID.ReadyToGouge]; } @@ -253,8 +330,7 @@ static partial void ModifyHeartOfCorundumPvE(ref ActionSetting setting) static partial void ModifyHypervelocityPvE(ref ActionSetting setting) { - setting.ActionCheck = () => Service.GetAdjustedActionId(ActionID.ContinuationPvE) == ActionID.HypervelocityPvE; - setting.ComboIds = [ActionID.BurstStrikePvE]; + setting.ActionCheck = () => HypervelocityPvEReady; setting.StatusNeed = [StatusID.ReadyToBlast]; } @@ -270,13 +346,13 @@ static partial void ModifyDoubleDownPvE(ref ActionSetting setting) static partial void ModifyGreatNebulaPvE(ref ActionSetting setting) { setting.StatusProvide = StatusHelper.RampartStatus; - setting.ActionCheck = () => Player.IsTargetOnSelf(); + setting.TargetType = TargetType.Self; + setting.IsFriendly = true; } static partial void ModifyFatedBrandPvE(ref ActionSetting setting) { - setting.ComboIds = [ActionID.FatedCirclePvE]; - setting.StatusNeed = [StatusID.ReadyToRaze]; + setting.ActionCheck = () => FatedBrandPvEReady; setting.CreateConfig = () => new ActionConfig() { AoeCount = 2, @@ -294,6 +370,7 @@ static partial void ModifyReignOfBeastsPvE(ref ActionSetting setting) static partial void ModifyNobleBloodPvE(ref ActionSetting setting) { + setting.ActionCheck = () => NobleBloodPvEReady; setting.CreateConfig = () => new ActionConfig() { AoeCount = 1 @@ -304,6 +381,7 @@ static partial void ModifyNobleBloodPvE(ref ActionSetting setting) static partial void ModifyLionHeartPvE(ref ActionSetting setting) { + setting.ActionCheck = () => LionHeartPvEReady; setting.CreateConfig = () => new ActionConfig() { AoeCount = 1 @@ -432,6 +510,7 @@ static partial void ModifyEyeGougePvP(ref ActionSetting setting) { setting.ActionCheck = () => EyeGougePvPReady; } + #endregion /// protected override bool EmergencyAbility(IAction nextGCD, out IAction? act) @@ -440,14 +519,4 @@ protected override bool EmergencyAbility(IAction nextGCD, out IAction? act) && Player.GetHealthRatio() <= Service.Config.HealthForDyingTanks) return true; return base.EmergencyAbility(nextGCD, out act); } - - /// - [RotationDesc(ActionID.TrajectoryPvE)] - protected sealed override bool MoveForwardAbility(IAction nextGCD, out IAction? act) - { - if (TrajectoryPvE.CanUse(out act)) return true; - return false; - } - - #endregion -} +} \ No newline at end of file diff --git a/RotationSolver.Basic/Rotations/Basic/MachinistRotation.cs b/RotationSolver.Basic/Rotations/Basic/MachinistRotation.cs index b759a6760..f7a91dd85 100644 --- a/RotationSolver.Basic/Rotations/Basic/MachinistRotation.cs +++ b/RotationSolver.Basic/Rotations/Basic/MachinistRotation.cs @@ -1,3 +1,5 @@ +using Dalamud.Interface.Colors; + namespace RotationSolver.Basic.Rotations.Basic; partial class MachinistRotation @@ -72,7 +74,21 @@ public static byte OverheatedStacks /// protected static bool OverheatedEndAfterGCD(uint gctCount = 0, float offset = 0) => OverheatedEndAfter(GCDTime(gctCount, offset)); + #endregion + + #region PvE Actions Unassignable + + /// + /// + /// + public static bool DetonatorPvEReady => Service.GetAdjustedActionId(ActionID.WildfirePvE) == ActionID.DetonatorPvE; + /// + /// + /// + public static bool ExcavatorPvEReady => Service.GetAdjustedActionId(ActionID.ChainSawPvE) == ActionID.ExcavatorPvE; + #endregion + #region Debug Display /// public override void DisplayStatus() { @@ -86,6 +102,10 @@ public override void DisplayStatus() ImGui.Text("OverheatTimeRemainingRaw: " + OverheatTimeRemainingRaw.ToString()); ImGui.Text("OverheatTime: " + OverheatTime.ToString()); ImGui.Text("OverheatedStacks: " + OverheatedStacks.ToString()); + ImGui.TextColored(ImGuiColors.DalamudViolet, "PvE Actions"); + ImGui.Text("DetonatorPvEReady: " + DetonatorPvEReady.ToString()); + ImGui.Text("ExcavatorPvEReady: " + ExcavatorPvEReady.ToString()); + ImGui.Spacing(); } #endregion @@ -190,6 +210,11 @@ static partial void ModifyWildfirePvE(ref ActionSetting setting) }; } + static partial void ModifyDetonatorPvE(ref ActionSetting setting) + { + setting.ActionCheck = () => DetonatorPvEReady; + } + static partial void ModifyRicochetPvE(ref ActionSetting setting) { setting.UnlockedByQuestID = 67240; @@ -377,7 +402,7 @@ static partial void ModifyCheckmatePvE(ref ActionSetting setting) static partial void ModifyExcavatorPvE(ref ActionSetting setting) { - setting.ActionCheck = () => Player.HasStatus(true, StatusID.ExcavatorReady); + setting.ActionCheck = () => ExcavatorPvEReady; setting.CreateConfig = () => new ActionConfig() { AoeCount = 1, diff --git a/RotationSolver.Basic/Rotations/Basic/MonkRotation.cs b/RotationSolver.Basic/Rotations/Basic/MonkRotation.cs index 95608c92e..dacfaebc7 100644 --- a/RotationSolver.Basic/Rotations/Basic/MonkRotation.cs +++ b/RotationSolver.Basic/Rotations/Basic/MonkRotation.cs @@ -1,3 +1,5 @@ +using Dalamud.Interface.Colors; + namespace RotationSolver.Basic.Rotations.Basic; partial class MonkRotation { @@ -49,6 +51,47 @@ partial class MonkRotation /// Brotherhood /// public static bool InBrotherhood => !Player.WillStatusEnd(0, true, StatusID.Brotherhood); + #endregion + + #region PvE Actions Unassignable + + /// + /// + /// + public static bool CelestialRevolutionPvEReady => Service.GetAdjustedActionId(ActionID.MasterfulBlitzPvE) == ActionID.CelestialRevolutionPvE; + + /// + /// + /// + public static bool FlintStrikePvEReady => Service.GetAdjustedActionId(ActionID.MasterfulBlitzPvE) == ActionID.FlintStrikePvE; + + /// + /// + /// + public static bool RisingPhoenixPvEReady => Service.GetAdjustedActionId(ActionID.MasterfulBlitzPvE) == ActionID.RisingPhoenixPvE; + + /// + /// + /// + public static bool TornadoKickPvEReady => Service.GetAdjustedActionId(ActionID.MasterfulBlitzPvE) == ActionID.TornadoKickPvE; + + /// + /// + /// + public static bool PhantomRushPvEReady => Service.GetAdjustedActionId(ActionID.MasterfulBlitzPvE) == ActionID.PhantomRushPvE; + + /// + /// + /// + public static bool ElixirFieldPvEReady => Service.GetAdjustedActionId(ActionID.MasterfulBlitzPvE) == ActionID.ElixirFieldPvE; + + /// + /// + /// + public static bool ElixirBurstPvEReady => Service.GetAdjustedActionId(ActionID.MasterfulBlitzPvE) == ActionID.ElixirBurstPvE; + #endregion + + #region Draw Debug /// public override void DisplayStatus() @@ -61,9 +104,18 @@ public override void DisplayStatus() ImGui.Text($"HasSolar: {HasSolar}"); ImGui.Text($"Chakra: {Chakra}"); ImGui.Text($"BeastChakras: {string.Join(", ", BeastChakras)}"); + ImGui.TextColored(ImGuiColors.DalamudViolet, "PvE Actions"); + ImGui.Text("CelestialRevolutionPvEReady: " + CelestialRevolutionPvEReady.ToString()); + ImGui.Text("FlintStrikePvEReady: " + FlintStrikePvEReady.ToString()); + ImGui.Text("RisingPhoenixPvEReady: " + RisingPhoenixPvEReady.ToString()); + ImGui.Text("TornadoKickPvEReady: " + TornadoKickPvEReady.ToString()); + ImGui.Text("PhantomRushPvEReady: " + PhantomRushPvEReady.ToString()); + ImGui.Text("ElixirFieldPvEReady: " + ElixirFieldPvEReady.ToString()); + ImGui.Text("ElixirBurstPvEReady: " + ElixirBurstPvEReady.ToString()); } #endregion + #region PvE Actions static partial void ModifyBootshinePvE(ref ActionSetting setting) { setting.StatusProvide = [StatusID.RaptorForm]; @@ -215,7 +267,7 @@ static partial void ModifyTornadoKickPvE(ref ActionSetting setting) static partial void ModifyElixirFieldPvE(ref ActionSetting setting) { - setting.ActionCheck = () => BeastChakras.Distinct().Count() == 1 && BeastChakras.Any(chakra => chakra != BeastChakra.NONE); + setting.ActionCheck = () => ElixirFieldPvEReady; setting.StatusProvide = [StatusID.FormlessFist]; setting.CreateConfig = () => new ActionConfig() { @@ -225,7 +277,7 @@ static partial void ModifyElixirFieldPvE(ref ActionSetting setting) static partial void ModifyCelestialRevolutionPvE(ref ActionSetting setting) { - setting.ActionCheck = () => BeastChakras.Distinct().Count() == 2 && BeastChakras.Any(chakra => chakra != BeastChakra.NONE); + setting.ActionCheck = () => CelestialRevolutionPvEReady; setting.StatusProvide = [StatusID.FormlessFist]; setting.CreateConfig = () => new ActionConfig() { @@ -235,7 +287,7 @@ static partial void ModifyCelestialRevolutionPvE(ref ActionSetting setting) static partial void ModifyFlintStrikePvE(ref ActionSetting setting) { - setting.ActionCheck = () => BeastChakras.Distinct().Count() == 3 && BeastChakras.Any(chakra => chakra != BeastChakra.NONE); + setting.ActionCheck = () => FlintStrikePvEReady; setting.StatusProvide = [StatusID.FormlessFist]; setting.CreateConfig = () => new ActionConfig() { @@ -319,7 +371,7 @@ static partial void ModifyShadowOfTheDestroyerPvE(ref ActionSetting setting) static partial void ModifyRisingPhoenixPvE(ref ActionSetting setting) { - setting.ActionCheck = () => BeastChakras.Distinct().Count() == 3 && BeastChakras.Any(chakra => chakra != BeastChakra.NONE); + setting.ActionCheck = () => RisingPhoenixPvEReady; setting.StatusProvide = [StatusID.FormlessFist]; setting.CreateConfig = () => new ActionConfig() { @@ -329,7 +381,7 @@ static partial void ModifyRisingPhoenixPvE(ref ActionSetting setting) static partial void ModifyPhantomRushPvE(ref ActionSetting setting) { - setting.ActionCheck = () => HasSolar && HasLunar && BeastChakras.Any(chakra => chakra != BeastChakra.NONE); + setting.ActionCheck = () => PhantomRushPvEReady; setting.StatusProvide = [StatusID.FormlessFist]; setting.CreateConfig = () => new ActionConfig() { @@ -359,7 +411,7 @@ static partial void ModifyPouncingCoeurlPvE(ref ActionSetting setting) static partial void ModifyElixirBurstPvE(ref ActionSetting setting) { - setting.ActionCheck = () => BeastChakras.Distinct().Count() == 1 && BeastChakras.Any(chakra => chakra != BeastChakra.NONE); + setting.ActionCheck = () => ElixirBurstPvEReady; setting.StatusProvide = [StatusID.FormlessFist]; setting.CreateConfig = () => new ActionConfig() { @@ -385,7 +437,7 @@ static partial void ModifyFiresReplyPvE(ref ActionSetting setting) AoeCount = 1, }; } - + #endregion // PvP static partial void ModifyThunderclapPvP(ref ActionSetting setting) diff --git a/RotationSolver.Basic/Rotations/Basic/NinjaRotation.cs b/RotationSolver.Basic/Rotations/Basic/NinjaRotation.cs index 86ce1c1e8..6cad3b2a2 100644 --- a/RotationSolver.Basic/Rotations/Basic/NinjaRotation.cs +++ b/RotationSolver.Basic/Rotations/Basic/NinjaRotation.cs @@ -1,4 +1,6 @@ -namespace RotationSolver.Basic.Rotations.Basic; +using Dalamud.Interface.Colors; + +namespace RotationSolver.Basic.Rotations.Basic; partial class NinjaRotation { @@ -24,7 +26,7 @@ partial class NinjaRotation /// /// Do you need to prep or currently use shadowwalker /// - public bool ShadowWalkerNeeded => TrickAttackPvE.Cooldown.WillHaveOneCharge(18) || KunaisBanePvE.Cooldown.WillHaveOneCharge(18) || MeisuiPvE.Cooldown.WillHaveOneCharge(18); + public bool ShadowWalkerNeeded => (TrickAttackPvE.EnoughLevel && TrickAttackPvE.Cooldown.WillHaveOneCharge(18)) || (KunaisBanePvE.EnoughLevel && KunaisBanePvE.Cooldown.WillHaveOneCharge(18)) || (MeisuiPvE.EnoughLevel && MeisuiPvE.Cooldown.WillHaveOneCharge(18)); /// /// Determines if Trick Attack is in its effective period. @@ -52,7 +54,77 @@ public static byte RaijuStacks return stacks == byte.MaxValue ? (byte)3 : stacks; } } + #endregion + + #region PvE Actions Unassignable + + /// + /// + /// + public static bool RabbitMediumPvEActive => Service.GetAdjustedActionId(ActionID.NinjutsuPvE) == ActionID.RabbitMediumPvE; + + /// + /// + /// + public static bool FumaShurikenPvEReady => Service.GetAdjustedActionId(ActionID.NinjutsuPvE) == ActionID.FumaShurikenPvE; + + /// + /// + /// + public static bool KatonPvEReady => Service.GetAdjustedActionId(ActionID.NinjutsuPvE) == ActionID.KatonPvE; + + /// + /// + /// + public static bool RaitonPvEReady => Service.GetAdjustedActionId(ActionID.NinjutsuPvE) == ActionID.RaitonPvE; + + /// + /// + /// + public static bool HyotonPvEReady => Service.GetAdjustedActionId(ActionID.NinjutsuPvE) == ActionID.HyotonPvE; + + /// + /// + /// + public static bool HutonPvEReady => Service.GetAdjustedActionId(ActionID.NinjutsuPvE) == ActionID.HutonPvE; + + /// + /// + /// + public static bool DotonPvEReady => Service.GetAdjustedActionId(ActionID.NinjutsuPvE) == ActionID.DotonPvE; + /// + /// + /// + public static bool SuitonPvEReady => Service.GetAdjustedActionId(ActionID.NinjutsuPvE) == ActionID.SuitonPvE; + + /// + /// + /// + public static bool GokaMekkyakuPvEReady => Service.GetAdjustedActionId(ActionID.NinjutsuPvE) == ActionID.GokaMekkyakuPvE; + + /// + /// + /// + public static bool HyoshoRanryuPvEReady => Service.GetAdjustedActionId(ActionID.NinjutsuPvE) == ActionID.HyoshoRanryuPvE; + + /// + /// + /// + public static bool DeathfrogMediumPvEReady => Service.GetAdjustedActionId(ActionID.HellfrogMediumPvE) == ActionID.DeathfrogMediumPvE; + + /// + /// + /// + public static bool ZeshoMeppoPvEReady => Service.GetAdjustedActionId(ActionID.BhavacakraPvE) == ActionID.ZeshoMeppoPvE; + + /// + /// + /// + public static bool TenriJindoPvEReady => Service.GetAdjustedActionId(ActionID.TenChiJinPvE) == ActionID.TenriJindoPvE; + #endregion + + #region Draw Debug /// public override void DisplayStatus() { @@ -64,9 +136,29 @@ public override void DisplayStatus() ImGui.Text($"NoNinjutsu: {NoNinjutsu}"); ImGui.Text($"RaijuStacks: {RaijuStacks}"); ImGui.Text($"ShadowWalkerNeeded: {ShadowWalkerNeeded}"); + ImGui.TextColored(ImGuiColors.DalamudViolet, "PvE Actions"); + ImGui.Text("FumaShurikenPvEReady: " + FumaShurikenPvEReady.ToString()); + ImGui.Text("KatonPvEReady: " + KatonPvEReady.ToString()); + ImGui.Text("RaitonPvEReady: " + RaitonPvEReady.ToString()); + ImGui.Text("HyotonPvEReady: " + HyotonPvEReady.ToString()); + ImGui.Text("HutonPvEReady: " + HutonPvEReady.ToString()); + ImGui.Text("DotonPvEReady: " + DotonPvEReady.ToString()); + ImGui.Text("SuitonPvEReady: " + SuitonPvEReady.ToString()); + ImGui.Text("GokaMekkyakuPvEReady: " + GokaMekkyakuPvEReady.ToString()); + ImGui.Text("HyoshoRanryuPvEReady: " + HyoshoRanryuPvEReady.ToString()); + ImGui.Text("DeathfrogMediumPvEReady: " + DeathfrogMediumPvEReady.ToString()); + ImGui.Text("ZeshoMeppoPvEReady: " + ZeshoMeppoPvEReady.ToString()); + ImGui.Text("TenriJindoPvEReady: " + TenriJindoPvEReady.ToString()); } #endregion + #region PvE Actions + + static partial void ModifyRabbitMediumPvE(ref ActionSetting setting) + { + setting.ActionCheck = () => RabbitMediumPvEActive; + } + static partial void ModifySpinningEdgePvE(ref ActionSetting setting) { @@ -275,8 +367,7 @@ static partial void ModifyKunaisBanePvE(ref ActionSetting setting) static partial void ModifyDeathfrogMediumPvE(ref ActionSetting setting) { - setting.ActionCheck = () => Ninki <= 50; - setting.StatusNeed = [StatusID.Higi]; + setting.ActionCheck = () => Ninki <= 50 && DeathfrogMediumPvEReady; setting.CreateConfig = () => new ActionConfig() { AoeCount = 3, @@ -285,13 +376,12 @@ static partial void ModifyDeathfrogMediumPvE(ref ActionSetting setting) static partial void ModifyZeshoMeppoPvE(ref ActionSetting setting) { - setting.ActionCheck = () => Ninki <= 50; - setting.StatusNeed = [StatusID.Higi]; + setting.ActionCheck = () => Ninki <= 50 && ZeshoMeppoPvEReady; } static partial void ModifyTenriJindoPvE(ref ActionSetting setting) { - setting.StatusNeed = [StatusID.TenriJindoReady]; + setting.ActionCheck = () => TenriJindoPvEReady; setting.CreateConfig = () => new ActionConfig() { AoeCount = 1, @@ -316,11 +406,12 @@ public NinjaRotation() static partial void ModifyFumaShurikenPvE(ref ActionSetting setting) { - + setting.ActionCheck = () => FumaShurikenPvEReady; } static partial void ModifyKatonPvE(ref ActionSetting setting) { + setting.ActionCheck = () => KatonPvEReady; setting.CreateConfig = () => new ActionConfig() { AoeCount = 3, @@ -329,16 +420,18 @@ static partial void ModifyKatonPvE(ref ActionSetting setting) static partial void ModifyRaitonPvE(ref ActionSetting setting) { - //setting.StatusProvide = [StatusID.RaijuReady]; + setting.ActionCheck = () => RaitonPvEReady; } 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.CreateConfig = () => new ActionConfig() { @@ -348,6 +441,7 @@ static partial void ModifyHutonPvE(ref ActionSetting setting) static partial void ModifyDotonPvE(ref ActionSetting setting) { + setting.ActionCheck = () => DotonPvEReady; setting.StatusProvide = [StatusID.Doton]; setting.CreateConfig = () => new ActionConfig() { @@ -357,12 +451,13 @@ static partial void ModifyDotonPvE(ref ActionSetting setting) static partial void ModifySuitonPvE(ref ActionSetting setting) { + setting.ActionCheck = () => SuitonPvEReady; setting.StatusProvide = [StatusID.ShadowWalker]; } static partial void ModifyGokaMekkyakuPvE(ref ActionSetting setting) { - setting.StatusNeed = [StatusID.Kassatsu]; + setting.ActionCheck = () => GokaMekkyakuPvEReady; setting.CreateConfig = () => new ActionConfig() { AoeCount = 3, @@ -371,8 +466,9 @@ static partial void ModifyGokaMekkyakuPvE(ref ActionSetting setting) static partial void ModifyHyoshoRanryuPvE(ref ActionSetting setting) { - setting.StatusNeed = [StatusID.Kassatsu]; + setting.ActionCheck = () => HyoshoRanryuPvEReady; } + #endregion // PvP static partial void ModifyShukuchiPvP(ref ActionSetting setting) diff --git a/RotationSolver.Basic/Rotations/Basic/ReaperRotation.cs b/RotationSolver.Basic/Rotations/Basic/ReaperRotation.cs index 012842cbb..fb14e583c 100644 --- a/RotationSolver.Basic/Rotations/Basic/ReaperRotation.cs +++ b/RotationSolver.Basic/Rotations/Basic/ReaperRotation.cs @@ -1,64 +1,160 @@ -namespace RotationSolver.Basic.Rotations.Basic; +using Dalamud.Interface.Colors; + +namespace RotationSolver.Basic.Rotations.Basic; partial class ReaperRotation { /// public override MedicineType MedicineType => MedicineType.Strength; + #region JobGauge + /// + /// + /// + public static byte Soul => JobGauge.Soul; + + /// + /// + /// + public static byte Shroud => JobGauge.Shroud; + + /// + /// + /// + public static float EnshroudedTiemRemaining => JobGauge.EnshroudedTimeRemaining; + + /// + /// + /// + public static byte LemureShroud => JobGauge.LemureShroud; + + /// + /// + /// + public static byte VoidShroud => JobGauge.VoidShroud; + #endregion + + #region Status Tracking + /// + /// + /// + public static bool HasEnshrouded => !Player.WillStatusEnd(0, true, StatusID.Enshrouded); + /// /// /// - public static bool HasEnshrouded => Player.HasStatus(true, StatusID.Enshrouded); + public static bool HasSoulReaver => !Player.WillStatusEnd(0, true, StatusID.SoulReaver); /// /// /// - public static bool HasSoulReaver => Player.HasStatus(true, StatusID.SoulReaver); + public static bool HasSoulsow => !Player.WillStatusEnd(0, true, StatusID.Soulsow); /// /// /// - public static bool HasExecutioner => Player.HasStatus(true, StatusID.Executioner); + public static bool HasExecutioner => !Player.WillStatusEnd(0, true, StatusID.Executioner); /// /// /// - public static bool HasIdealHost => Player.HasStatus(true, StatusID.IdealHost); + public static bool HasIdealHost => !Player.WillStatusEnd(0, true, StatusID.IdealHost); /// /// /// - public static bool HasOblatio => Player.HasStatus(true, StatusID.Oblatio); + public static bool HasOblatio => !Player.WillStatusEnd(0, true, StatusID.Oblatio); /// /// /// public static bool HasPerfectioParata => Player.HasStatus(true, StatusID.PerfectioParata); + #endregion + + #region Actions Unassignable - #region JobGauge /// /// /// - public static byte Soul => JobGauge.Soul; + public static bool UnveiledGibbetPvEReady => Service.GetAdjustedActionId(ActionID.BloodStalkPvE) == ActionID.UnveiledGibbetPvE; /// /// /// - public static byte Shroud => JobGauge.Shroud; + public static bool UnveiledGallowsPvEReady => Service.GetAdjustedActionId(ActionID.BloodStalkPvE) == ActionID.UnveiledGallowsPvE; /// /// /// - public static byte LemureShroud => JobGauge.LemureShroud; + public static bool RegressPvEIngressReady => Service.GetAdjustedActionId(ActionID.HellsIngressPvE) == ActionID.RegressPvE; /// /// /// - public static byte VoidShroud => JobGauge.VoidShroud; + public static bool RegressPvEEgressReady => Service.GetAdjustedActionId(ActionID.HellsEgressPvE) == ActionID.RegressPvE; + + /// + /// + /// + public static bool VoidReapingPvEReady => Service.GetAdjustedActionId(ActionID.GibbetPvE) == ActionID.VoidReapingPvE; + + /// + /// + /// + public static bool CrossReapingPvEReady => Service.GetAdjustedActionId(ActionID.GallowsPvE) == ActionID.CrossReapingPvE; + + /// + /// + /// + public static bool GrimReapingPvEReady => Service.GetAdjustedActionId(ActionID.GuillotinePvE) == ActionID.GrimReapingPvE; + + /// + /// + /// + public static bool HarvestMoonPvEReady => Service.GetAdjustedActionId(ActionID.SoulsowPvE) == ActionID.HarvestMoonPvE; + + /// + /// + /// + public static bool LemuresSlicePvEReady => Service.GetAdjustedActionId(ActionID.BloodStalkPvE) == ActionID.LemuresSlicePvE; + + /// + /// + /// + public static bool LemuresScythePvEReady => Service.GetAdjustedActionId(ActionID.GrimSwathePvE) == ActionID.LemuresScythePvE; + + /// + /// + /// + public static bool SacrificiumPvEReady => Service.GetAdjustedActionId(ActionID.GluttonyPvE) == ActionID.SacrificiumPvE; + + /// + /// + /// + public static bool ExecutionersGibbetPvEReady => Service.GetAdjustedActionId(ActionID.GibbetPvE) == ActionID.ExecutionersGibbetPvE; + + /// + /// + /// + public static bool ExecutionersGallowsPvEReady => Service.GetAdjustedActionId(ActionID.GallowsPvE) == ActionID.ExecutionersGallowsPvE; + + /// + /// + /// + public static bool ExecutionersGuillotinePvEReady => Service.GetAdjustedActionId(ActionID.GuillotinePvE) == ActionID.ExecutionersGuillotinePvE; + + /// + /// + /// + public static bool PerfectioPvEReady => Service.GetAdjustedActionId(ActionID.CommunioPvE) == ActionID.PerfectioPvE; + #endregion + + #region Debug /// public override void DisplayStatus() { + ImGui.Text("EnshroudedTiemRemaining: " + EnshroudedTiemRemaining.ToString()); ImGui.Text("HasEnshrouded: " + HasEnshrouded.ToString()); ImGui.Text("HasSoulReaver: " + HasSoulReaver.ToString()); ImGui.Text("HasExecutioner: " + HasExecutioner.ToString()); @@ -69,9 +165,26 @@ public override void DisplayStatus() ImGui.Text("Shroud: " + Shroud.ToString()); ImGui.Text("LemureShroud: " + LemureShroud.ToString()); ImGui.Text("VoidShroud: " + VoidShroud.ToString()); + ImGui.TextColored(ImGuiColors.DalamudOrange, "PvE Actions"); + ImGui.Text("UnveiledGibbetPvEReady: " + UnveiledGibbetPvEReady.ToString()); + ImGui.Text("UnveiledGallowsPvEReady: " + UnveiledGallowsPvEReady.ToString()); + ImGui.Text("RegressPvEIngressReady: " + RegressPvEIngressReady.ToString()); + ImGui.Text("RegressPvEEgressReady: " + RegressPvEEgressReady.ToString()); + ImGui.Text("VoidReapingPvEReady: " + VoidReapingPvEReady.ToString()); + ImGui.Text("CrossReapingPvEReady: " + CrossReapingPvEReady.ToString()); + ImGui.Text("GrimReapingPvEReady: " + GrimReapingPvEReady.ToString()); + ImGui.Text("HarvestMoonPvEReady: " + HarvestMoonPvEReady.ToString()); + ImGui.Text("LemuresSlicePvEReady: " + LemuresSlicePvEReady.ToString()); + ImGui.Text("LemuresScythePvEReady: " + LemuresScythePvEReady.ToString()); + ImGui.Text("SacrificiumPvEReady: " + SacrificiumPvEReady.ToString()); + ImGui.Text("ExecutionersGibbetPvEReady: " + ExecutionersGibbetPvEReady.ToString()); + ImGui.Text("ExecutionersGallowsPvEReady: " + ExecutionersGallowsPvEReady.ToString()); + ImGui.Text("ExecutionersGuillotinePvEReady: " + ExecutionersGuillotinePvEReady.ToString()); + ImGui.Text("PerfectioPvEReady: " + PerfectioPvEReady.ToString()); } #endregion + #region PvE Actions static partial void ModifySlicePvE(ref ActionSetting setting) { setting.ActionCheck = () => !HasEnshrouded && !HasSoulReaver; @@ -82,20 +195,25 @@ static partial void ModifyWaxingSlicePvE(ref ActionSetting setting) setting.ActionCheck = () => !HasEnshrouded && !HasSoulReaver; } - static partial void ModifyInfernalSlicePvE(ref ActionSetting setting) - { - setting.ActionCheck = () => !HasEnshrouded && !HasSoulReaver; - } - static partial void ModifyShadowOfDeathPvE(ref ActionSetting setting) { setting.TargetStatusProvide = [StatusID.DeathsDesign]; setting.ActionCheck = () => !HasSoulReaver; } - static partial void ModifySoulSlicePvE(ref ActionSetting setting) + static partial void ModifyHarpePvE(ref ActionSetting setting) { - setting.ActionCheck = () => !HasEnshrouded && !HasSoulReaver && Soul <= 50; + setting.SpecialType = SpecialActionType.MeleeRange; + } + + static partial void ModifyHellsIngressPvE(ref ActionSetting setting) + { + setting.StatusProvide = [StatusID.EnhancedHarpe, StatusID.Bind]; + } + + static partial void ModifyHellsEgressPvE(ref ActionSetting setting) + { + setting.StatusProvide = [StatusID.EnhancedHarpe, StatusID.Bind]; } static partial void ModifySpinningScythePvE(ref ActionSetting setting) @@ -103,7 +221,7 @@ static partial void ModifySpinningScythePvE(ref ActionSetting setting) setting.ActionCheck = () => !HasEnshrouded && !HasSoulReaver; } - static partial void ModifyNightmareScythePvE(ref ActionSetting setting) + static partial void ModifyInfernalSlicePvE(ref ActionSetting setting) { setting.ActionCheck = () => !HasEnshrouded && !HasSoulReaver; } @@ -118,57 +236,52 @@ static partial void ModifyWhorlOfDeathPvE(ref ActionSetting setting) }; } - static partial void ModifySoulScythePvE(ref ActionSetting setting) - { - setting.ActionCheck = () => !HasEnshrouded && !HasSoulReaver && Soul <= 50; - } - - static partial void ModifyGibbetPvE(ref ActionSetting setting) + static partial void ModifyArcaneCrestPvE(ref ActionSetting setting) { - setting.StatusNeed = [StatusID.SoulReaver]; + setting.StatusProvide = [StatusID.CrestOfTimeBorrowed]; + setting.IsFriendly = true; } - static partial void ModifyExecutionersGibbetPvE(ref ActionSetting setting) + static partial void ModifyNightmareScythePvE(ref ActionSetting setting) { - setting.StatusNeed = [StatusID.Executioner]; + setting.ActionCheck = () => !HasEnshrouded && !HasSoulReaver; } - static partial void ModifyGallowsPvE(ref ActionSetting setting) + static partial void ModifyBloodStalkPvE(ref ActionSetting setting) { - setting.StatusNeed = [StatusID.SoulReaver]; + setting.StatusProvide = [StatusID.SoulReaver]; + setting.ActionCheck = () => !HasEnshrouded && !HasSoulReaver && Soul >= 50; } - static partial void ModifyExecutionersGallowsPvE(ref ActionSetting setting) + static partial void ModifyGrimSwathePvE(ref ActionSetting setting) { - setting.StatusNeed = [StatusID.Executioner]; + setting.StatusProvide = [StatusID.SoulReaver]; + setting.ActionCheck = () => !HasEnshrouded && !HasSoulReaver && Soul >= 50; } - static partial void ModifyGuillotinePvE(ref ActionSetting setting) + static partial void ModifySoulSlicePvE(ref ActionSetting setting) { - setting.StatusNeed = [StatusID.SoulReaver]; + setting.ActionCheck = () => !HasEnshrouded && !HasSoulReaver && Soul <= 50; } - static partial void ModifyExecutionersGuillotinePvE(ref ActionSetting setting) + static partial void ModifySoulScythePvE(ref ActionSetting setting) { - setting.StatusNeed = [StatusID.Executioner]; + setting.ActionCheck = () => !HasEnshrouded && !HasSoulReaver && Soul <= 50; } - static partial void ModifyBloodStalkPvE(ref ActionSetting setting) + static partial void ModifyGibbetPvE(ref ActionSetting setting) { - setting.StatusProvide = [StatusID.SoulReaver]; - setting.ActionCheck = () => !HasEnshrouded && !HasSoulReaver && Soul >= 50; + setting.ActionCheck = () => HasSoulReaver; } - static partial void ModifyGrimSwathePvE(ref ActionSetting setting) + static partial void ModifyGallowsPvE(ref ActionSetting setting) { - setting.StatusProvide = [StatusID.SoulReaver]; - setting.ActionCheck = () => !HasEnshrouded && !HasSoulReaver && Soul >= 50; + setting.ActionCheck = () => HasSoulReaver; } - static partial void ModifyGluttonyPvE(ref ActionSetting setting) + static partial void ModifyGuillotinePvE(ref ActionSetting setting) { - setting.StatusProvide = [StatusID.SoulReaver, StatusID.Executioner]; - setting.ActionCheck = () => !HasEnshrouded && !HasSoulReaver && Soul >= 50; + setting.ActionCheck = () => HasSoulReaver; } static partial void ModifyArcaneCirclePvE(ref ActionSetting setting) @@ -180,93 +293,117 @@ static partial void ModifyArcaneCirclePvE(ref ActionSetting setting) }; } - static partial void ModifyPlentifulHarvestPvE(ref ActionSetting setting) + static partial void ModifyGluttonyPvE(ref ActionSetting setting) { - setting.StatusNeed = [StatusID.ImmortalSacrifice]; - setting.ActionCheck = () => !Player.HasStatus(true, StatusID.BloodsownCircle_2972); + setting.StatusProvide = [StatusID.SoulReaver, StatusID.Executioner]; + setting.ActionCheck = () => !HasEnshrouded && !HasSoulReaver && Soul >= 50; } static partial void ModifyEnshroudPvE(ref ActionSetting setting) { - setting.StatusProvide = [StatusID.Enshrouded]; setting.ActionCheck = () => !HasEnshrouded && !HasSoulReaver && Soul >= 50; setting.UnlockedByQuestID = 69614; } - static partial void ModifySacrificiumPvE(ref ActionSetting setting) + static partial void ModifySoulsowPvE(ref ActionSetting setting) + { + setting.StatusProvide = [StatusID.Soulsow]; + setting.ActionCheck = () => !InCombat; + } + + static partial void ModifyPlentifulHarvestPvE(ref ActionSetting setting) { - setting.ActionCheck = () => HasEnshrouded && HasOblatio; + setting.StatusNeed = [StatusID.ImmortalSacrifice]; + setting.ActionCheck = () => !Player.HasStatus(true, StatusID.BloodsownCircle_2972); } static partial void ModifyCommunioPvE(ref ActionSetting setting) { setting.StatusProvide = [StatusID.PerfectioParata]; - setting.StatusNeed = [StatusID.Enshrouded]; - setting.ActionCheck = () => LemureShroud == 1; + setting.ActionCheck = () => LemureShroud == 1 && HasEnshrouded; } + #endregion - static partial void ModifyPerfectioPvE(ref ActionSetting setting) + #region PvE Actions Unassaignable + + static partial void ModifyUnveiledGibbetPvE(ref ActionSetting setting) { - setting.ActionCheck = () => HasPerfectioParata; + setting.ActionCheck = () => UnveiledGibbetPvEReady && Soul >= 50; } - static partial void ModifyLemuresSlicePvE(ref ActionSetting setting) + static partial void ModifyUnveiledGallowsPvE(ref ActionSetting setting) { - setting.StatusNeed = [StatusID.Enshrouded]; - setting.ActionCheck = () => VoidShroud >= 2; + setting.ActionCheck = () => UnveiledGallowsPvEReady && Soul >= 50; } - static partial void ModifyLemuresScythePvE(ref ActionSetting setting) + static partial void ModifyRegressPvE(ref ActionSetting setting) { - setting.StatusNeed = [StatusID.Enshrouded]; - setting.ActionCheck = () => VoidShroud >= 2; + setting.ActionCheck = () => RegressPvEIngressReady || RegressPvEEgressReady; } static partial void ModifyVoidReapingPvE(ref ActionSetting setting) { - setting.StatusNeed = [StatusID.Enshrouded]; + setting.ActionCheck = () => VoidReapingPvEReady && LemureShroud >= 1; } static partial void ModifyCrossReapingPvE(ref ActionSetting setting) { - setting.StatusNeed = [StatusID.Enshrouded]; + setting.ActionCheck = () => CrossReapingPvEReady && LemureShroud >= 1; } static partial void ModifyGrimReapingPvE(ref ActionSetting setting) { - setting.StatusNeed = [StatusID.Enshrouded]; + setting.ActionCheck = () => GrimReapingPvEReady && LemureShroud >= 1; } - static partial void ModifyHarpePvE(ref ActionSetting setting) + static partial void ModifyHarvestMoonPvE(ref ActionSetting setting) { - setting.SpecialType = SpecialActionType.MeleeRange; + setting.ActionCheck = () => HarvestMoonPvEReady && HasSoulsow; } - static partial void ModifyHellsIngressPvE(ref ActionSetting setting) + static partial void ModifyLemuresSlicePvE(ref ActionSetting setting) { - setting.StatusProvide = [StatusID.EnhancedHarpe, StatusID.Bind]; + setting.ActionCheck = () => LemuresSlicePvEReady && VoidShroud >= 2; } - static partial void ModifyHellsEgressPvE(ref ActionSetting setting) + static partial void ModifyLemuresScythePvE(ref ActionSetting setting) { - setting.StatusProvide = [StatusID.EnhancedHarpe, StatusID.Bind]; + setting.ActionCheck = () => LemuresScythePvEReady && VoidShroud >= 2; } - static partial void ModifySoulsowPvE(ref ActionSetting setting) + static partial void ModifySacrificiumPvE(ref ActionSetting setting) { - setting.StatusProvide = [StatusID.Soulsow]; - setting.ActionCheck = () => !InCombat; + setting.ActionCheck = () => SacrificiumPvEReady && HasEnshrouded && HasOblatio; } - static partial void ModifyHarvestMoonPvE(ref ActionSetting setting) + static partial void ModifyExecutionersGibbetPvE(ref ActionSetting setting) + { + setting.ActionCheck = () => ExecutionersGibbetPvEReady && HasExecutioner; + } + + static partial void ModifyExecutionersGallowsPvE(ref ActionSetting setting) { - setting.StatusNeed = [StatusID.Soulsow]; + setting.ActionCheck = () => ExecutionersGallowsPvEReady && HasExecutioner; } + static partial void ModifyExecutionersGuillotinePvE(ref ActionSetting setting) + { + setting.ActionCheck = () => ExecutionersGuillotinePvEReady && HasExecutioner; + } + + static partial void ModifyPerfectioPvE(ref ActionSetting setting) + { + setting.ActionCheck = () => PerfectioPvEReady && HasPerfectioParata; + } + + #endregion + + #region PvP Actions static partial void ModifyHellsIngressPvP(ref ActionSetting setting) { setting.SpecialType = SpecialActionType.MovingForward; } + #endregion /// [RotationDesc(ActionID.HellsIngressPvE)]