From b21945a65fb5bad8d47e67f97e105c547c69319d Mon Sep 17 00:00:00 2001 From: LTS-FFXIV <127939494+LTS-FFXIV@users.noreply.github.com> Date: Mon, 27 Jan 2025 17:45:00 -0600 Subject: [PATCH] Enhance ability logic and update dependencies Updated `AST_Default` with `StellarNow` property and new condition in `EmergencyAbility` method. Modified `SGE_Default` to change conditions for Prognosis and Diagnosis abilities. Enhanced `NIN_Default` with improved decision-making logic for Ninjutsu and other abilities, including new methods and regions for movement and oGCD logic. Added `DumbQueen` config to `MCH_Default` and updated logic for Automation Queen usage. Added `InterventionTank` config to `PLD_Default` and updated logic for Intervention on CoTank. Changed visibility of status arrays in `StatusHelper` and added XML documentation. Updated `System.Drawing.Common` to `9.0.1` and `Microsoft.CodeAnalysis.CSharp` to `4.12.0`. --- BasicRotations/Healer/AST_Default.cs | 5 + BasicRotations/Healer/SGE_Default.cs | 8 +- BasicRotations/Melee/NIN_Default.cs | 868 ++++++++++++++---- BasicRotations/Ranged/MCH_Default.cs | 4 + BasicRotations/Tank/PLD_Default.cs | 5 + RotationSolver.Basic/Helpers/StatusHelper.cs | 30 +- .../RotationSolver.Basic.csproj | 2 +- .../RotationSolver.SourceGenerators.csproj | 2 +- 8 files changed, 744 insertions(+), 180 deletions(-) diff --git a/BasicRotations/Healer/AST_Default.cs b/BasicRotations/Healer/AST_Default.cs index ea94af961..86bec5d6b 100644 --- a/BasicRotations/Healer/AST_Default.cs +++ b/BasicRotations/Healer/AST_Default.cs @@ -24,6 +24,9 @@ public sealed class AST_Default : AstrologianRotation [RotationConfig(CombatType.PvE, Name = "Simple Lord of Crowns logic (use under divinaiton)")] public bool SimpleLord { get; set; } = false; + [RotationConfig(CombatType.PvE, Name = "Detonate Earlthy Star when you have Giant Dominance")] + public bool StellarNow { get; set; } = false; + [Range(4, 20, ConfigUnitType.Seconds)] [RotationConfig(CombatType.PvE, Name = "Use Earthly Star during countdown timer.")] public float UseEarthlyStarTime { get; set; } = 15; @@ -85,6 +88,8 @@ protected override bool EmergencyAbility(IAction nextGCD, out IAction? act) if (DivinationPvE.CanUse(out _) && UseBurstMedicine(out act)) return true; + if (StellarNow && Player.HasStatus(true, StatusID.GiantDominance) && StellarDetonationPvE.CanUse(out act)) return true; + return base.EmergencyAbility(nextGCD, out act); } diff --git a/BasicRotations/Healer/SGE_Default.cs b/BasicRotations/Healer/SGE_Default.cs index f9f122e5c..919130bec 100644 --- a/BasicRotations/Healer/SGE_Default.cs +++ b/BasicRotations/Healer/SGE_Default.cs @@ -406,7 +406,7 @@ protected override bool HealAreaGCD(out IAction? act) if (PneumaPvE.CanUse(out act)) return true; } - if (_EukrasiaActionAim != null && PrognosisPvE.CanUse(out act)) + if (_EukrasiaActionAim == null && PrognosisPvE.CanUse(out act)) { return true; } @@ -419,7 +419,7 @@ protected override bool HealSingleGCD(out IAction? act) { act = null; if (IsLastAction(ActionID.SwiftcastPvE) && SwiftLogic && MergedStatus.HasFlag(AutoStatus.Raise)) return false; - if (_EukrasiaActionAim != null && DiagnosisPvE.CanUse(out act)) + if (_EukrasiaActionAim == null && DiagnosisPvE.CanUse(out act)) { return true; } @@ -453,13 +453,13 @@ protected override bool GeneralGCD(out IAction? act) if (DoEukrasianDyskrasia(out act)) return true; - if ((_EukrasiaActionAim != EukrasianDiagnosisPvE || _EukrasiaActionAim != EukrasianPrognosisPvE || _EukrasiaActionAim != EukrasianPrognosisIiPvE || _EukrasiaActionAim != EukrasianDyskrasiaPvE) + if ((_EukrasiaActionAim == null) && DyskrasiaPvE.CanUse(out act)) return true; if (DoEukrasianPrognosis(out act)) return true; if (DoEukrasianDiagnosis(out act)) return true; - if ( DoEukrasianDosis(out act)) return true; + if (DoEukrasianDosis(out act)) return true; if (DosisPvE.CanUse(out act)) return true; if (OOCEukrasia && !InCombat && !Player.HasStatus(true, StatusID.Eukrasia) && EukrasiaPvE.CanUse(out act)) return true; diff --git a/BasicRotations/Melee/NIN_Default.cs b/BasicRotations/Melee/NIN_Default.cs index 3cac7a1e1..0f6b3d8c6 100644 --- a/BasicRotations/Melee/NIN_Default.cs +++ b/BasicRotations/Melee/NIN_Default.cs @@ -39,7 +39,7 @@ public sealed class NIN_Default : NinjaRotation if (remainTime > 6) ClearNinjutsu(); // Decision-making for ninjutsu actions based on remaining time until combat starts. - if (DoNinjutsu(out var act)) + if (DoSuiton(out var act)) { if (act == SuitonPvE && remainTime > CountDownAhead) return null; return act; @@ -59,21 +59,129 @@ public sealed class NIN_Default : NinjaRotation } #endregion + #region Move Logic + // Defines logic for actions to take when moving forward during combat. + // This attribute associates the method with the Forked Raiju PvE action, + // indicating it's a relevant ability when considering movement-based actions. + [RotationDesc(ActionID.ForkedRaijuPvE)] + protected override bool MoveForwardGCD(out IAction? act) + { + // Checks if Forked Raiju, a movement-friendly ability, can be used. + // If so, sets it as the action to perform, returning true to indicate an action has been selected. + if (ForkedRaijuPvE.CanUse(out act)) return true; + + // If Forked Raiju is not available or not the best option, + // falls back to the base class's logic for choosing a move-forward action. + return base.MoveForwardGCD(out act); + } + #endregion + + #region oGCD Logic + // Determines the emergency abilities to use, overriding the base class implementation. + protected override bool EmergencyAbility(IAction nextGCD, out IAction? act) + { + // Initializes the action to null, indicating no action has been chosen yet. + act = null; + + // 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, RabbitMediumPvE, FumaShurikenPvE, KatonPvE, RaitonPvE, + HyotonPvE, HutonPvE, DotonPvE, SuitonPvE, GokaMekkyakuPvE, HyoshoRanryuPvE) || (Player.HasStatus(true, StatusID.ShadowWalker) + && (_ninActionAim == SuitonPvE || _ninActionAim == HutonPvE))) + { + ClearNinjutsu(); + } + + if ((InCombat || (CommbatMudra && HasHostilesInMaxRange)) && ChoiceNinjutsu(out act)) return true; + + // 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); + + // 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 (TenriJindoPvE.CanUse(out act)) return true; + + // If in a burst phase and not just starting combat, checks if Mug is available to generate additional Ninki. + if (IsBurst && !CombatElapsedLess(5) && MugPvE.CanUse(out act)) return true; + + // Prioritizes using Suiton and Trick Attack for maximizing damage, especially outside the initial combat phase. + if (!CombatElapsedLess(6)) + { + // Attempts to use Trick Attack if it's available. + if (KunaisBanePvE.CanUse(out act, skipAoeCheck: true, skipStatusProvideCheck: IsShadowWalking)) return true; + if (!KunaisBanePvE.EnoughLevel && TrickAttackPvE.CanUse(out act, skipStatusProvideCheck: IsShadowWalking)) return true; + + // If Trick Attack is on cooldown but will not be ready soon, considers using Meisui to recover Ninki. + if (TrickAttackPvE.Cooldown.IsCoolingDown && !TrickAttackPvE.Cooldown.WillHaveOneCharge(19) && TenChiJinPvE.Cooldown.IsCoolingDown && MeisuiPvE.CanUse(out act)) return true; + } + + if ((TenChiJinPvE.Cooldown.IsCoolingDown || Player.WillStatusEndGCD(2, 0, true, StatusID.ShadowWalker)) && MeisuiPvE.CanUse(out act)) return true; + + // If none of the specific conditions are met, falls back to the base class's emergency ability logic. + return base.EmergencyAbility(nextGCD, out act); + } + + // Defines attack abilities to use during combat, overriding the base class implementation. + protected override bool AttackAbility(IAction nextGCD, out IAction? act) + { + act = null; + // If Ninjutsu is available or not in combat, it exits early, indicating no attack action to perform. + if (!NoNinjutsu || !InCombat) return false; + + // 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 && !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; + + // Special handling if within Trick Attack's effective window: + if (InTrickAttack) + { + // If Dream Within A Dream is not yet available, checks if Assassinate can be used. + if (!DreamWithinADreamPvE.EnoughLevel) + { + if (AssassinatePvE.CanUse(out act)) return true; + } + else + { + // If Dream Within A Dream is available, it's set as the next action. + if (DreamWithinADreamPvE.CanUse(out act)) return true; + } + } + + // Checks for the use of Hellfrog Medium or Bhavacakra under certain conditions: + // - 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) || HasPhantomKamaitachi || MugPvE.Cooldown.WillHaveOneCharge(2))) + { + if (HellfrogMediumPvE.CanUse(out act, skipAoeCheck: !BhavacakraPvE.EnoughLevel)) return true; + if (BhavacakraPvE.CanUse(out act)) return true; + if (TenriJindoPvE.CanUse(out act)) return true; + } + + if (Ninki == 100) + { + if (HellfrogMediumPvE.CanUse(out act, skipAoeCheck: !BhavacakraPvE.EnoughLevel)) return true; + if (BhavacakraPvE.CanUse(out act)) return true; + } + + if (MergedStatus.HasFlag(AutoStatus.MoveForward) && MoveForwardAbility(nextGCD, out act)) return true; + // If none of the conditions are met, it falls back to the base class's implementation for attack ability. + return base.AttackAbility(nextGCD, out act); + } + #endregion + #region Ninjutsu Logic - // Sets the target ninjutsu action to be performed next. - // If the action is null, or currently set to Rabbit Medium (indicating a failed Ninjutsu attempt), it exits early. - // If the current action aim is not null and the last action matches certain conditions, it exits early. - // Finally, updates the current ninjutsu action aim if it's different from the incoming action. private void SetNinjutsu(IBaseAction act) { - if (act == null || AdjustId(ActionID.NinjutsuPvE) == ActionID.RabbitMediumPvE) return; + if (act == null || AdjustId(ActionID.NinjutsuPvE) == ActionID.RabbitMediumPvE || (_ninActionAim != null && IsLastAction(true, _ninActionAim))) return; if (_ninActionAim != null && IsLastAction(false, TenPvE, JinPvE, ChiPvE, FumaShurikenPvE_18873, FumaShurikenPvE_18874, FumaShurikenPvE_18875)) return; - if (_ninActionAim != act) - { - _ninActionAim = act; - } + _ninActionAim = act; } // Clears the ninjutsu action aim, effectively resetting any planned ninjutsu action. @@ -91,16 +199,8 @@ private bool ChoiceNinjutsu(out IAction? act) { act = null; - // 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 (!TenPvE.CanUse(out _) && !HasKassatsu) return false; - if (!TenPvE.Cooldown.HasOneCharge && TenPvE.EnoughLevel) return false; // Ensures that the action ID currently considered for Ninjutsu is actually valid for Ninjutsu execution. //if (AdjustId(ActionID.NinjutsuPvE) != ActionID.NinjutsuPvE) return false; // If more than 4.5 seconds have passed since the last action, it clears any pending Ninjutsu to avoid stale actions. @@ -111,26 +211,26 @@ 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 && JinPvE.Cooldown.HasOneCharge) + if (DeathBlossomPvE.CanUse(out _) && GokaMekkyakuPvE.EnoughLevel) { SetNinjutsu(GokaMekkyakuPvE); } - if (HyoshoRanryuPvE.EnoughLevel && JinPvE.Cooldown.HasOneCharge) + if (!DeathBlossomPvE.CanUse(out _) && HyoshoRanryuPvE.EnoughLevel) { SetNinjutsu(HyoshoRanryuPvE); } - if (!HyoshoRanryuPvE.EnoughLevel && HutonPvE.EnoughLevel && TenPvE.CanUse(out _) && JinPvE.Cooldown.HasOneCharge) + if (!IsShadowWalking && ShadowWalkerNeeded && !HyoshoRanryuPvE.EnoughLevel) { SetNinjutsu(HutonPvE); } - if (!HyoshoRanryuPvE.EnoughLevel && KatonPvE.EnoughLevel && TenPvE.Cooldown.HasOneCharge) + if (DeathBlossomPvE.CanUse(out _) && !HyoshoRanryuPvE.EnoughLevel) { SetNinjutsu(KatonPvE); } - if (!HyoshoRanryuPvE.EnoughLevel && RaitonPvE.EnoughLevel && TenPvE.Cooldown.HasOneCharge) + if (!DeathBlossomPvE.CanUse(out _) && !HyoshoRanryuPvE.EnoughLevel) { SetNinjutsu(RaitonPvE); } @@ -138,28 +238,30 @@ private bool ChoiceNinjutsu(out IAction? act) } else { - // If Suiton is active but no specific Ninjutsu is currently aimed, it clears the Ninjutsu aim. - // This check is relevant for managing Suiton's effect, particularly for enabling Trick Attack. - if (Player.HasStatus(true, StatusID.ShadowWalker) - && _ninActionAim == SuitonPvE) - { - ClearNinjutsu(); - } - // Chooses buffs or AoE actions based on combat conditions and cooldowns. // For instance, setting Huton for speed buff or choosing AoE Ninjutsu like Katon or Doton based on enemy positioning. // Also considers using Suiton for vulnerability debuff on the enemy if conditions are optimal. + //Vulnerable + if (ShadowWalkerNeeded && (!MeisuiPvE.Cooldown.IsCoolingDown || !TrickAttackPvE.Cooldown.IsCoolingDown || KunaisBanePvE.Cooldown.IsCoolingDown) && !IsShadowWalking && !HasTenChiJin && SuitonPvE.EnoughLevel && TenPvE.Cooldown.HasOneCharge) + { + if (DeathBlossomPvE.CanUse(out _)) + SetNinjutsu(HutonPvE); + else + SetNinjutsu(SuitonPvE); + return false; + } + //Aoe - if (NumberOfHostilesInRange > 1 && KatonPvE.EnoughLevel && ChiPvE.CanUse(out _) && TenPvE.CanUse(out _)) + if (DeathBlossomPvE.CanUse(out _) && KatonPvE.EnoughLevel && TenPvE.CanUse(out _)) { - if (!HasDoton && !IsMoving && !IsLastGCD(false, DotonPvE) && (!TenChiJinPvE.Cooldown.WillHaveOneCharge(6)) || !HasDoton && !TenChiJinPvE.Cooldown.IsCoolingDown && TenPvE.CanUse(out _) && ChiPvE.CanUse(out _) && JinPvE.CanUse(out _)) + if (!HasDoton && !IsMoving && !IsLastGCD(true, DotonPvE) && (!TenChiJinPvE.Cooldown.WillHaveOneCharge(6)) || !HasDoton && !TenChiJinPvE.Cooldown.IsCoolingDown) SetNinjutsu(DotonPvE); else SetNinjutsu(KatonPvE); } //Single - if (!ShadowWalkerNeeded && TenPvE.CanUse(out _, usedUp: InTrickAttack && !HasRaijuReady)) + if (!DeathBlossomPvE.CanUse(out _) && !ShadowWalkerNeeded && TenPvE.CanUse(out _, usedUp: InTrickAttack && !HasRaijuReady)) { if (RaitonPvE.EnoughLevel && TenPvE.Cooldown.HasOneCharge) { @@ -173,25 +275,29 @@ private bool ChoiceNinjutsu(out IAction? act) return false; } } - - //Vulnerable - if (ShadowWalkerNeeded && (!MeisuiPvE.Cooldown.IsCoolingDown || !TrickAttackPvE.Cooldown.IsCoolingDown || KunaisBanePvE.Cooldown.IsCoolingDown) && !IsShadowWalking && !HasTenChiJin && SuitonPvE.EnoughLevel && JinPvE.Cooldown.HasOneCharge) - { - SetNinjutsu(SuitonPvE); - return false; - } } return false; // Indicates that no specific Ninjutsu action was chosen in this cycle. } #endregion #region Ninjutsu Execution - // Attempts to perform a ninjutsu action, based on the current game state and conditions. - private bool DoNinjutsu(out IAction? act) + private bool DoRabbitMedium(out IAction? act) + { + act = null; + uint ninjutsunId = AdjustId(NinjutsuPvE.ID); + if (ninjutsunId == RabbitMediumPvE.ID) + { + _rabbitMediumFailures++; + if (RabbitMediumPvE.CanUse(out act)) return true; + ClearNinjutsu(); + } + return false; + } + + private bool DoTenChiJin(out IAction? act) { act = null; - //TenChiJin if (HasTenChiJin) { uint tenId = AdjustId(TenPvE.ID); @@ -203,7 +309,7 @@ private bool DoNinjutsu(out IAction? act) && !IsLastAction(false, FumaShurikenPvE_18875, FumaShurikenPvE_18873)) { //AOE - if (KatonPvE.CanUse(out _)) + if (DeathBlossomPvE.CanUse(out _)) { if (FumaShurikenPvE_18875.CanUse(out act)) return true; } @@ -230,171 +336,580 @@ private bool DoNinjutsu(out IAction? act) if (DotonPvE_18880.CanUse(out act, skipAoeCheck: true)) return true; } } + return false; + } - //Keep Kassatsu in Burst. - if (!Player.WillStatusEnd(3, false, StatusID.Kassatsu) - && HasKassatsu && !InTrickAttack) return false; - if (_ninActionAim == null) return false; - - var id = AdjustId(ActionID.NinjutsuPvE); + private bool DoSuiton(out IAction? act) + { + act = null; - //Failed - if ((uint)id == RabbitMediumPvE.ID) + if (_ninActionAim != null && (_ninActionAim == SuitonPvE)) { - _rabbitMediumFailures++; - ClearNinjutsu(); - act = null; - return false; - } - //First - else if (id == ActionID.NinjutsuPvE) - { - //Can't use. - if (!Player.HasStatus(true, StatusID.Kassatsu, StatusID.TenChiJin) - && !TenPvE.CanUse(out _, usedUp: true) - && !IsLastAction(false, _ninActionAim.Setting.Ninjutsu![0])) + var id = AdjustId(ActionID.NinjutsuPvE); + + //Failed + if ((uint)id == RabbitMediumPvE.ID) { + _rabbitMediumFailures++; + ClearNinjutsu(); + act = null; return false; } - act = _ninActionAim.Setting.Ninjutsu![0]; + //First + else if (id == ActionID.NinjutsuPvE) + { + //Can't use. + if (!Player.HasStatus(true, StatusID.Kassatsu, StatusID.TenChiJin) + && !TenPvE.CanUse(out _, usedUp: true) + && !IsLastAction(false, _ninActionAim.Setting.Ninjutsu![0])) + { + return false; + } + act = _ninActionAim.Setting.Ninjutsu![0]; + return true; + } + //Second + else if ((uint)id == _ninActionAim.ID) + { + if (_ninActionAim.CanUse(out act, skipAoeCheck: true)) return true; + if (_ninActionAim.ID == DotonPvE.ID && !InCombat) + { + act = _ninActionAim; + return true; + } + } + //Third + else if ((uint)id == FumaShurikenPvE.ID) + { + if (_ninActionAim.Setting.Ninjutsu!.Length > 1 + && !IsLastAction(false, _ninActionAim.Setting.Ninjutsu![1])) + { + act = _ninActionAim.Setting.Ninjutsu![1]; + return true; + } + } + //Finished + else if ((uint)id == KatonPvE.ID || (uint)id == RaitonPvE.ID || (uint)id == HyotonPvE.ID) + { + if (_ninActionAim.Setting.Ninjutsu!.Length > 2 + && !IsLastAction(false, _ninActionAim.Setting.Ninjutsu![2])) + { + act = _ninActionAim.Setting.Ninjutsu![2]; + return true; + } + } + + act = _ninActionAim; return true; } - //Second - else if ((uint)id == _ninActionAim.ID) + return false; + } + + private bool DoHyoshoRanryu(out IAction? act) + { + act = null; + + if (_ninActionAim != null && (_ninActionAim == HyoshoRanryuPvE) && HasKassatsu) { - if (_ninActionAim.CanUse(out act, skipAoeCheck: true)) return true; - if (_ninActionAim.ID == DotonPvE.ID && !InCombat) + var id = AdjustId(ActionID.NinjutsuPvE); + + //Failed + if ((uint)id == RabbitMediumPvE.ID) { - act = _ninActionAim; + _rabbitMediumFailures++; + ClearNinjutsu(); + act = null; + return false; + } + //First + else if (id == ActionID.NinjutsuPvE) + { + //Can't use. + if (!Player.HasStatus(true, StatusID.Kassatsu, StatusID.TenChiJin) + && !TenPvE.CanUse(out _, usedUp: true) + && !IsLastAction(false, _ninActionAim.Setting.Ninjutsu![0])) + { + return false; + } + act = _ninActionAim.Setting.Ninjutsu![0]; return true; } + //Second + else if ((uint)id == _ninActionAim.ID) + { + if (_ninActionAim.CanUse(out act, skipAoeCheck: true)) return true; + if (_ninActionAim.ID == DotonPvE.ID && !InCombat) + { + act = _ninActionAim; + return true; + } + } + //Third + else if ((uint)id == FumaShurikenPvE.ID) + { + if (_ninActionAim.Setting.Ninjutsu!.Length > 1 + && !IsLastAction(false, _ninActionAim.Setting.Ninjutsu![1])) + { + act = _ninActionAim.Setting.Ninjutsu![1]; + return true; + } + } + //Finished + else if ((uint)id == KatonPvE.ID || (uint)id == RaitonPvE.ID || (uint)id == HyotonPvE.ID) + { + if (_ninActionAim.Setting.Ninjutsu!.Length > 2 + && !IsLastAction(false, _ninActionAim.Setting.Ninjutsu![2])) + { + act = _ninActionAim.Setting.Ninjutsu![2]; + return true; + } + } + + act = _ninActionAim; + return true; } - //Third - else if ((uint)id == FumaShurikenPvE.ID) + return false; + } + + private bool DoGokaMekkyaku(out IAction? act) + { + act = null; + + if (_ninActionAim != null && (_ninActionAim == GokaMekkyakuPvE) && HasKassatsu) { - if (_ninActionAim.Setting.Ninjutsu!.Length > 1 - && !IsLastAction(false, _ninActionAim.Setting.Ninjutsu![1])) + var id = AdjustId(ActionID.NinjutsuPvE); + + //Failed + if ((uint)id == RabbitMediumPvE.ID) + { + _rabbitMediumFailures++; + ClearNinjutsu(); + act = null; + return false; + } + //First + else if (id == ActionID.NinjutsuPvE) { - act = _ninActionAim.Setting.Ninjutsu![1]; + //Can't use. + if (!Player.HasStatus(true, StatusID.Kassatsu, StatusID.TenChiJin) + && !TenPvE.CanUse(out _, usedUp: true) + && !IsLastAction(false, _ninActionAim.Setting.Ninjutsu![0])) + { + return false; + } + act = _ninActionAim.Setting.Ninjutsu![0]; return true; } + //Second + else if ((uint)id == _ninActionAim.ID) + { + if (_ninActionAim.CanUse(out act, skipAoeCheck: true)) return true; + if (_ninActionAim.ID == DotonPvE.ID && !InCombat) + { + act = _ninActionAim; + return true; + } + } + //Third + else if ((uint)id == FumaShurikenPvE.ID) + { + if (_ninActionAim.Setting.Ninjutsu!.Length > 1 + && !IsLastAction(false, _ninActionAim.Setting.Ninjutsu![1])) + { + act = _ninActionAim.Setting.Ninjutsu![1]; + return true; + } + } + //Finished + else if ((uint)id == KatonPvE.ID || (uint)id == RaitonPvE.ID || (uint)id == HyotonPvE.ID) + { + if (_ninActionAim.Setting.Ninjutsu!.Length > 2 + && !IsLastAction(false, _ninActionAim.Setting.Ninjutsu![2])) + { + act = _ninActionAim.Setting.Ninjutsu![2]; + return true; + } + } + + act = _ninActionAim; + return true; } - //Finished - else if ((uint)id == KatonPvE.ID || (uint)id == RaitonPvE.ID || (uint)id == HyotonPvE.ID) + return false; + } + + private bool DoDoton(out IAction? act) + { + act = null; + + if (_ninActionAim != null && (_ninActionAim == DotonPvE)) { - if (_ninActionAim.Setting.Ninjutsu!.Length > 2 - && !IsLastAction(false, _ninActionAim.Setting.Ninjutsu![2])) + var id = AdjustId(ActionID.NinjutsuPvE); + + //Failed + if ((uint)id == RabbitMediumPvE.ID) { - act = _ninActionAim.Setting.Ninjutsu![2]; + _rabbitMediumFailures++; + ClearNinjutsu(); + act = null; + return false; + } + //First + else if (id == ActionID.NinjutsuPvE) + { + //Can't use. + if (!Player.HasStatus(true, StatusID.Kassatsu, StatusID.TenChiJin) + && !TenPvE.CanUse(out _, usedUp: true) + && !IsLastAction(false, _ninActionAim.Setting.Ninjutsu![0])) + { + return false; + } + act = _ninActionAim.Setting.Ninjutsu![0]; return true; } + //Second + else if ((uint)id == _ninActionAim.ID) + { + if (_ninActionAim.CanUse(out act, skipAoeCheck: true)) return true; + if (_ninActionAim.ID == DotonPvE.ID && !InCombat) + { + act = _ninActionAim; + return true; + } + } + //Third + else if ((uint)id == FumaShurikenPvE.ID) + { + if (_ninActionAim.Setting.Ninjutsu!.Length > 1 + && !IsLastAction(false, _ninActionAim.Setting.Ninjutsu![1])) + { + act = _ninActionAim.Setting.Ninjutsu![1]; + return true; + } + } + //Finished + else if ((uint)id == KatonPvE.ID || (uint)id == RaitonPvE.ID || (uint)id == HyotonPvE.ID) + { + if (_ninActionAim.Setting.Ninjutsu!.Length > 2 + && !IsLastAction(false, _ninActionAim.Setting.Ninjutsu![2])) + { + act = _ninActionAim.Setting.Ninjutsu![2]; + return true; + } + } + + act = _ninActionAim; + return true; } return false; } - #endregion - #region Move Logic - // Defines logic for actions to take when moving forward during combat. - // This attribute associates the method with the Forked Raiju PvE action, - // indicating it's a relevant ability when considering movement-based actions. - [RotationDesc(ActionID.ForkedRaijuPvE)] - protected override bool MoveForwardGCD(out IAction? act) + private bool DoHuton(out IAction? act) { - // Checks if Forked Raiju, a movement-friendly ability, can be used. - // If so, sets it as the action to perform, returning true to indicate an action has been selected. - if (ForkedRaijuPvE.CanUse(out act)) return true; + act = null; - // If Forked Raiju is not available or not the best option, - // falls back to the base class's logic for choosing a move-forward action. - return base.MoveForwardGCD(out act); + if (_ninActionAim != null && (_ninActionAim == HutonPvE)) + { + var id = AdjustId(ActionID.NinjutsuPvE); + + //Failed + if ((uint)id == RabbitMediumPvE.ID) + { + _rabbitMediumFailures++; + ClearNinjutsu(); + act = null; + return false; + } + //First + else if (id == ActionID.NinjutsuPvE) + { + //Can't use. + if (!Player.HasStatus(true, StatusID.Kassatsu, StatusID.TenChiJin) + && !TenPvE.CanUse(out _, usedUp: true) + && !IsLastAction(false, _ninActionAim.Setting.Ninjutsu![0])) + { + return false; + } + act = _ninActionAim.Setting.Ninjutsu![0]; + return true; + } + //Second + else if ((uint)id == _ninActionAim.ID) + { + if (_ninActionAim.CanUse(out act, skipAoeCheck: true)) return true; + if (_ninActionAim.ID == DotonPvE.ID && !InCombat) + { + act = _ninActionAim; + return true; + } + } + //Third + else if ((uint)id == FumaShurikenPvE.ID) + { + if (_ninActionAim.Setting.Ninjutsu!.Length > 1 + && !IsLastAction(false, _ninActionAim.Setting.Ninjutsu![1])) + { + act = _ninActionAim.Setting.Ninjutsu![1]; + return true; + } + } + //Finished + else if ((uint)id == KatonPvE.ID || (uint)id == RaitonPvE.ID || (uint)id == HyotonPvE.ID) + { + if (_ninActionAim.Setting.Ninjutsu!.Length > 2 + && !IsLastAction(false, _ninActionAim.Setting.Ninjutsu![2])) + { + act = _ninActionAim.Setting.Ninjutsu![2]; + return true; + } + } + + act = _ninActionAim; + return true; + } + return false; } - #endregion - #region oGCD Logic - // Determines the emergency abilities to use, overriding the base class implementation. - protected override bool EmergencyAbility(IAction nextGCD, out IAction? act) + private bool DoHyoton(out IAction? act) { - // Initializes the action to null, indicating no action has been chosen yet. act = null; - if ((InCombat || (CommbatMudra && HasHostilesInMaxRange)) && ChoiceNinjutsu(out act)) return true; - - // 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 (_ninActionAim != null && (_ninActionAim == HyotonPvE)) + { + var id = AdjustId(ActionID.NinjutsuPvE); - // 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 || Player.WillStatusEndGCD(2, 0, true, StatusID.ShadowWalker)) && MeisuiPvE.CanUse(out act)) return true; + //Failed + if ((uint)id == RabbitMediumPvE.ID) + { + _rabbitMediumFailures++; + ClearNinjutsu(); + act = null; + return false; + } + //First + else if (id == ActionID.NinjutsuPvE) + { + //Can't use. + if (!Player.HasStatus(true, StatusID.Kassatsu, StatusID.TenChiJin) + && !TenPvE.CanUse(out _, usedUp: true) + && !IsLastAction(false, _ninActionAim.Setting.Ninjutsu![0])) + { + return false; + } + act = _ninActionAim.Setting.Ninjutsu![0]; + return true; + } + //Second + else if ((uint)id == _ninActionAim.ID) + { + if (_ninActionAim.CanUse(out act, skipAoeCheck: true)) return true; + if (_ninActionAim.ID == DotonPvE.ID && !InCombat) + { + act = _ninActionAim; + return true; + } + } + //Third + else if ((uint)id == FumaShurikenPvE.ID) + { + if (_ninActionAim.Setting.Ninjutsu!.Length > 1 + && !IsLastAction(false, _ninActionAim.Setting.Ninjutsu![1])) + { + act = _ninActionAim.Setting.Ninjutsu![1]; + return true; + } + } + //Finished + else if ((uint)id == KatonPvE.ID || (uint)id == RaitonPvE.ID || (uint)id == HyotonPvE.ID) + { + if (_ninActionAim.Setting.Ninjutsu!.Length > 2 + && !IsLastAction(false, _ninActionAim.Setting.Ninjutsu![2])) + { + act = _ninActionAim.Setting.Ninjutsu![2]; + return true; + } + } - if (TenriJindoPvE.CanUse(out act)) return true; + act = _ninActionAim; + return true; + } + return false; + } - // If in a burst phase and not just starting combat, checks if Mug is available to generate additional Ninki. - if (IsBurst && !CombatElapsedLess(5) && MugPvE.CanUse(out act)) return true; + private bool DoRaiton(out IAction? act) + { + act = null; - // Prioritizes using Suiton and Trick Attack for maximizing damage, especially outside the initial combat phase. - if (!CombatElapsedLess(6)) + if (_ninActionAim != null && (_ninActionAim == RaitonPvE)) { - // Attempts to use Trick Attack if it's available. - if (KunaisBanePvE.CanUse(out act, skipAoeCheck: true, skipStatusProvideCheck: IsShadowWalking)) return true; - if (!KunaisBanePvE.EnoughLevel && TrickAttackPvE.CanUse(out act, skipStatusProvideCheck: IsShadowWalking)) return true; + var id = AdjustId(ActionID.NinjutsuPvE); - // If Trick Attack is on cooldown but will not be ready soon, considers using Meisui to recover Ninki. - if (TrickAttackPvE.Cooldown.IsCoolingDown && !TrickAttackPvE.Cooldown.WillHaveOneCharge(19) && TenChiJinPvE.Cooldown.IsCoolingDown && MeisuiPvE.CanUse(out act)) return true; - } + //Failed + if ((uint)id == RabbitMediumPvE.ID) + { + _rabbitMediumFailures++; + ClearNinjutsu(); + act = null; + return false; + } + //First + else if (id == ActionID.NinjutsuPvE) + { + //Can't use. + if (!Player.HasStatus(true, StatusID.Kassatsu, StatusID.TenChiJin) + && !TenPvE.CanUse(out _, usedUp: true) + && !IsLastAction(false, _ninActionAim.Setting.Ninjutsu![0])) + { + return false; + } + act = _ninActionAim.Setting.Ninjutsu![0]; + return true; + } + //Second + else if ((uint)id == _ninActionAim.ID) + { + if (_ninActionAim.CanUse(out act, skipAoeCheck: true)) return true; + if (_ninActionAim.ID == DotonPvE.ID && !InCombat) + { + act = _ninActionAim; + return true; + } + } + //Third + else if ((uint)id == FumaShurikenPvE.ID) + { + if (_ninActionAim.Setting.Ninjutsu!.Length > 1 + && !IsLastAction(false, _ninActionAim.Setting.Ninjutsu![1])) + { + act = _ninActionAim.Setting.Ninjutsu![1]; + return true; + } + } + //Finished + else if ((uint)id == KatonPvE.ID || (uint)id == RaitonPvE.ID || (uint)id == HyotonPvE.ID) + { + if (_ninActionAim.Setting.Ninjutsu!.Length > 2 + && !IsLastAction(false, _ninActionAim.Setting.Ninjutsu![2])) + { + act = _ninActionAim.Setting.Ninjutsu![2]; + return true; + } + } - // If none of the specific conditions are met, falls back to the base class's emergency ability logic. - return base.EmergencyAbility(nextGCD, out act); + act = _ninActionAim; + return true; + } + return false; } - // Defines attack abilities to use during combat, overriding the base class implementation. - protected override bool AttackAbility(IAction nextGCD, out IAction? act) + private bool DoKaton(out IAction? act) { act = null; - // If Ninjutsu is available or not in combat, it exits early, indicating no attack action to perform. - if (!NoNinjutsu || !InCombat) return false; - // 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 && !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; - - // Special handling if within Trick Attack's effective window: - if (InTrickAttack) + if (_ninActionAim != null && (_ninActionAim == KatonPvE)) { - // If Dream Within A Dream is not yet available, checks if Assassinate can be used. - if (!DreamWithinADreamPvE.EnoughLevel) + var id = AdjustId(ActionID.NinjutsuPvE); + + //Failed + if ((uint)id == RabbitMediumPvE.ID) { - if (AssassinatePvE.CanUse(out act)) return true; + _rabbitMediumFailures++; + ClearNinjutsu(); + act = null; + return false; } - else + //First + else if (id == ActionID.NinjutsuPvE) { - // If Dream Within A Dream is available, it's set as the next action. - if (DreamWithinADreamPvE.CanUse(out act)) return true; + //Can't use. + if (!Player.HasStatus(true, StatusID.Kassatsu, StatusID.TenChiJin) + && !TenPvE.CanUse(out _, usedUp: true) + && !IsLastAction(false, _ninActionAim.Setting.Ninjutsu![0])) + { + return false; + } + act = _ninActionAim.Setting.Ninjutsu![0]; + return true; + } + //Second + else if ((uint)id == _ninActionAim.ID) + { + if (_ninActionAim.CanUse(out act, skipAoeCheck: true)) return true; + if (_ninActionAim.ID == DotonPvE.ID && !InCombat) + { + act = _ninActionAim; + return true; + } + } + //Third + else if ((uint)id == FumaShurikenPvE.ID) + { + if (_ninActionAim.Setting.Ninjutsu!.Length > 1 + && !IsLastAction(false, _ninActionAim.Setting.Ninjutsu![1])) + { + act = _ninActionAim.Setting.Ninjutsu![1]; + return true; + } + } + //Finished + else if ((uint)id == KatonPvE.ID || (uint)id == RaitonPvE.ID || (uint)id == HyotonPvE.ID) + { + if (_ninActionAim.Setting.Ninjutsu!.Length > 2 + && !IsLastAction(false, _ninActionAim.Setting.Ninjutsu![2])) + { + act = _ninActionAim.Setting.Ninjutsu![2]; + return true; + } } - } - // Checks for the use of Hellfrog Medium or Bhavacakra under certain conditions: - // - 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) || HasPhantomKamaitachi || MugPvE.Cooldown.WillHaveOneCharge(2))) - { - if (HellfrogMediumPvE.CanUse(out act, skipAoeCheck: !BhavacakraPvE.EnoughLevel)) return true; - if (BhavacakraPvE.CanUse(out act)) return true; - if (TenriJindoPvE.CanUse(out act)) return true; + act = _ninActionAim; + return true; } + return false; + } - if (Ninki == 100) + private bool DoFumaShuriken(out IAction? act) + { + act = null; + + if (_ninActionAim != null && (_ninActionAim == FumaShurikenPvE)) { - if (HellfrogMediumPvE.CanUse(out act, skipAoeCheck: !BhavacakraPvE.EnoughLevel)) return true; - if (BhavacakraPvE.CanUse(out act)) return true; - } + //Keep Kassatsu in Burst. + if (!Player.WillStatusEnd(4, true, StatusID.Kassatsu) && !InTrickAttack) return false; - if (MergedStatus.HasFlag(AutoStatus.MoveForward) && MoveForwardAbility(nextGCD, out act)) return true; - // If none of the conditions are met, it falls back to the base class's implementation for attack ability. - return base.AttackAbility(nextGCD, out act); + var id = AdjustId(ActionID.NinjutsuPvE); + + //Failed + if ((uint)id == RabbitMediumPvE.ID) + { + _rabbitMediumFailures++; + ClearNinjutsu(); + act = null; + return false; + } + //First + else if (id == ActionID.NinjutsuPvE) + { + //Can't use. + if (!Player.HasStatus(true, StatusID.Kassatsu, StatusID.TenChiJin) + && !TenPvE.CanUse(out _, usedUp: true) + && !IsLastAction(false, _ninActionAim.Setting.Ninjutsu![0])) + { + return false; + } + act = _ninActionAim.Setting.Ninjutsu![0]; + return true; + } + else if ((uint)id == FumaShurikenPvE.ID) + { + if (_ninActionAim.Setting.Ninjutsu!.Length > 1 + && !IsLastAction(false, _ninActionAim.Setting.Ninjutsu![1])) + { + act = _ninActionAim.Setting.Ninjutsu![1]; + return true; + } + } + } + return false; } #endregion @@ -403,8 +918,6 @@ protected override bool GeneralGCD(out IAction? act) { act = null; - if (_ninActionAim == null && RabbitMediumPvE.CanUse(out act)) return true; - if (!IsExecutingMudra && (InTrickAttack || InMug) && NoNinjutsu && !HasRaijuReady && !Player.HasStatus(true, StatusID.TenChiJin) && PhantomKamaitachiPvE.CanUse(out act)) return true; @@ -415,22 +928,41 @@ protected override bool GeneralGCD(out IAction? act) if (ForkedUse && ForkedRaijuPvE.CanUse(out act)) return true; } - if (((!InCombat && CommbatMudra && HasHostilesInMaxRange) || !CombatElapsedLess(7)) && DoNinjutsu(out act)) return true; - - //No Ninjutsu - if (NoNinjutsu) - { - if (!CombatElapsedLess(10) && FleetingRaijuPvE.CanUse(out act)) return true; - if (HasRaijuReady) return false; - } + if (DoTenChiJin(out act)) return true; + if (DoRabbitMedium(out act)) return true; //AOE + if (DoGokaMekkyaku(out act)) return true; + if (DoHuton(out act)) return true; + if (DoDoton(out act)) return true; + if (DoKaton(out act)) return true; + if (HakkeMujinsatsuPvE.CanUse(out act)) return true; if (DeathBlossomPvE.CanUse(out act)) return true; + if (DoHyoshoRanryu(out act)) return true; + if (DoSuiton(out act)) return true; + if (DoHuton(out act)) return true; + if (DoHyoton(out act)) return true; + if (DoRaiton(out act)) return true; + if (DoFumaShuriken(out act)) return true; + //Single - if (!InTrickAttack && Kazematoi < 4 && ArmorCrushPvE.CanUse(out act)) return true; - if (AeolianEdgePvE.CanUse(out act)) return true; + if (AeolianEdgePvE.EnoughLevel) + { + // If ArmorCrushPvE is not yet available, checks if AeolianEdgePvE can be used. + if (!ArmorCrushPvE.EnoughLevel) + { + if (AeolianEdgePvE.CanUse(out act)) return true; + } + else + { + if (Kazematoi == 0 && ArmorCrushPvE.CanUse(out act)) return true; + else if (Kazematoi > 0 && AeolianEdgePvE.CanUse(out act) && AeolianEdgePvE.Target.Target != null && CanHitPositional(EnemyPositional.Rear, AeolianEdgePvE.Target.Target)) return true; + else if (Kazematoi < 4 && ArmorCrushPvE.CanUse(out act) && ArmorCrushPvE.Target.Target != null && CanHitPositional(EnemyPositional.Flank, ArmorCrushPvE.Target.Target)) return true; + else if (Kazematoi > 0 && AeolianEdgePvE.CanUse(out act)) return true; + } + } if (GustSlashPvE.CanUse(out act)) return true; if (SpinningEdgePvE.CanUse(out act)) return true; diff --git a/BasicRotations/Ranged/MCH_Default.cs b/BasicRotations/Ranged/MCH_Default.cs index 87dbd8d0d..343d8391e 100644 --- a/BasicRotations/Ranged/MCH_Default.cs +++ b/BasicRotations/Ranged/MCH_Default.cs @@ -9,6 +9,9 @@ public sealed class MCH_Default : MachinistRotation [RotationConfig(CombatType.PvE, Name = "Prioritize Barrel Stabilizer use")] private bool BSPrio { get; set; } = true; + [RotationConfig(CombatType.PvE, Name = "Use Automation Queen as soon as its available")] + private bool DumbQueen { get; set; } = false; + [RotationConfig(CombatType.PvE, Name = "Delay Drill for combo GCD if have one charge and about to break combo")] private bool HoldDrillForCombo { get; set; } = true; @@ -106,6 +109,7 @@ protected override bool AttackAbility(IAction nextGCD, out IAction? act) } // Rook Autoturret/Queen Logic + if (DumbQueen && InCombat && RookAutoturretPvE.CanUse(out act)) return true; if (CanUseQueenMeow(out act, nextGCD)) return true; // Use Ricochet and Gauss diff --git a/BasicRotations/Tank/PLD_Default.cs b/BasicRotations/Tank/PLD_Default.cs index a9724d8c1..c0fcb453a 100644 --- a/BasicRotations/Tank/PLD_Default.cs +++ b/BasicRotations/Tank/PLD_Default.cs @@ -25,6 +25,9 @@ public sealed class PLD_Default : PaladinRotation [RotationConfig(CombatType.PvE, Name = "Health threshold for Intervention (Set to 0 to disable)")] private float InterventionRatio { get; set; } = 0.6f; + [RotationConfig(CombatType.PvE, Name = "Attempt to use intevention on CoTank during tankbusters")] + private bool InterventionTank { get; set; } = false; + [Range(0, 1, ConfigUnitType.Percent)] [RotationConfig(CombatType.PvE, Name = "Health threshold for Cover (Set to 0 to disable)")] private float CoverRatio { get; set; } = 0.3f; @@ -132,6 +135,8 @@ protected override bool DefenseSingleAbility(IAction nextGCD, out IAction? act) act = null; if (PassageProtec && Player.HasStatus(true, StatusID.PassageOfArms)) return false; + if (InterventionTank && InterventionPvE.Target.Target?.HasStatus(false, StatusID.Grit, StatusID.RoyalGuard_1833, StatusID.IronWill, StatusID.Defiance) == true && InterventionPvE.CanUse(out act)) return true; + // If the player has the Hallowed Ground status, don't use any abilities. if (!Player.HasStatus(true, StatusID.HallowedGround)) { diff --git a/RotationSolver.Basic/Helpers/StatusHelper.cs b/RotationSolver.Basic/Helpers/StatusHelper.cs index 063af48de..fd90d1045 100644 --- a/RotationSolver.Basic/Helpers/StatusHelper.cs +++ b/RotationSolver.Basic/Helpers/StatusHelper.cs @@ -81,7 +81,10 @@ public static class StatusHelper StatusID.TheEwer_3891, }; - internal static StatusID[] TankStanceStatus { get; } = + /// + /// + /// + public static StatusID[] TankStanceStatus { get; } = { StatusID.Grit, StatusID.RoyalGuard_1833, @@ -89,7 +92,10 @@ public static class StatusHelper StatusID.Defiance, }; - internal static StatusID[] NoNeedHealingStatus { get; } = + /// + /// + /// + public static StatusID[] NoNeedHealingStatus { get; } = { StatusID.Holmgang_409, StatusID.LivingDead, @@ -97,14 +103,20 @@ public static class StatusHelper StatusID.Superbolide, }; - internal static StatusID[] SwiftcastStatus { get; } = + /// + /// + /// + public static StatusID[] SwiftcastStatus { get; } = { StatusID.Swiftcast, StatusID.Triplecast, StatusID.Dualcast, }; - internal static StatusID[] AstCardStatus { get; } = + /// + /// + /// + public static StatusID[] AstCardStatus { get; } = { StatusID.TheBalance_3887, StatusID.TheSpear_3889, @@ -112,7 +124,10 @@ public static class StatusHelper StatusID.BrinkOfDeath, }; - internal static StatusID[] RampartStatus { get; } = + /// + /// + /// + public static StatusID[] RampartStatus { get; } = { StatusID.Superbolide, StatusID.HallowedGround, @@ -129,7 +144,10 @@ public static class StatusHelper StatusID.Superbolide, }; - internal static StatusID[] NoPositionalStatus { get; } = + /// + /// + /// + public static StatusID[] NoPositionalStatus { get; } = { StatusID.TrueNorth, StatusID.RightEye, diff --git a/RotationSolver.Basic/RotationSolver.Basic.csproj b/RotationSolver.Basic/RotationSolver.Basic.csproj index 6f15d7ddd..0d555fa3f 100644 --- a/RotationSolver.Basic/RotationSolver.Basic.csproj +++ b/RotationSolver.Basic/RotationSolver.Basic.csproj @@ -73,7 +73,7 @@ all - + diff --git a/RotationSolver.SourceGenerators/RotationSolver.SourceGenerators.csproj b/RotationSolver.SourceGenerators/RotationSolver.SourceGenerators.csproj index ed135280b..ff8b30519 100644 --- a/RotationSolver.SourceGenerators/RotationSolver.SourceGenerators.csproj +++ b/RotationSolver.SourceGenerators/RotationSolver.SourceGenerators.csproj @@ -7,7 +7,7 @@ - +