From 3e7c6f052c453da6a4bdf9093f39a23cfe8d494a Mon Sep 17 00:00:00 2001 From: Akechi-kun <167795370+Akechi-kun@users.noreply.github.com> Date: Mon, 3 Jun 2024 22:51:36 -0700 Subject: [PATCH 1/3] Added support for Lv40, Lv50, Lv60 rotations There were certain bugs within the code that were causing Autorotation to brick in plenty of instances regarding Lv40-Lv72. This is a fix for that. I added support for lower levels, preferably Lv40-70 - Lv40: Added logic to make sure ST and AOE combo works effectively the same as Lv50 combo. - Lv50: Added logic to ensure the appropriate skills are being used for the correct rotation. No Mercy was not being procced on ST or AOE & when you used it manually, it would get stuck. Added a couple !state checks to ensure no funny business with locked skills due to level sync. (fuck off Gnashing Fang) - Lv60: Fixed AOE combo issue; Kept getting stuck on Fated Circle, so added a !state check for appropriate skills to ensure Burst Strike (or Gnashing Fang) is used, regardless of ST or AOE. - Lv70: basically same shit as Lv60. --- BossMod/Autorotation/GNB/GNBRotation.cs | 206 ++++++++++++++++++++++-- 1 file changed, 189 insertions(+), 17 deletions(-) diff --git a/BossMod/Autorotation/GNB/GNBRotation.cs b/BossMod/Autorotation/GNB/GNBRotation.cs index 8b9d3542cd..c84c9b7a2b 100644 --- a/BossMod/Autorotation/GNB/GNBRotation.cs +++ b/BossMod/Autorotation/GNB/GNBRotation.cs @@ -1,4 +1,4 @@ -// CONTRIB: made by LazyLemo, tweaked by Akechi (there's still plenty of issues that need to be addressed.. but with DT around the corner, not so much on my mind) +// made by LazyLemo, edited by Akechi (there's still plenty of issues, but with DT around the corner, I dont care to fix them. These QoL updates should suffice until then) namespace BossMod.GNB; public static class Rotation @@ -394,6 +394,54 @@ public static AID GetNextAmmoAction(State state, Strategy strategy, bool aoe) if (Service.Config.Get().EarlySonicBreak && state.CD(CDGroup.NoMercy) > 40 && state.CD(CDGroup.SonicBreak) < 0.6f) return AID.SonicBreak; + // Lv30-53 NM proc ST + if (state.Unlocked(AID.NoMercy)) + { + bool canUseBurstStrike = (state.NoMercyLeft > 0) && + !state.Unlocked(AID.FatedCircle) && + !state.Unlocked(AID.DoubleDown) && + !state.Unlocked(AID.Bloodfest) && + !state.Unlocked(AID.Continuation) && + !state.Unlocked(AID.GnashingFang) && + state.Ammo >= 1; + + // ST + if (!aoe) + { + if (!state.Unlocked(AID.FatedCircle) && + !state.Unlocked(AID.DoubleDown) && + !state.Unlocked(AID.Bloodfest) && + !state.Unlocked(AID.Continuation) && + !state.Unlocked(AID.GnashingFang) && + state.Ammo >= 2) + { + return AID.NoMercy; + } + else if (canUseBurstStrike && state.Ammo >= 2) // Ensure at least 2 ammo for BurstStrike + { + return AID.BurstStrike; + } + } + + // AOE + if (aoe) + { + if (!state.Unlocked(AID.FatedCircle) && + !state.Unlocked(AID.DoubleDown) && + !state.Unlocked(AID.Bloodfest) && + !state.Unlocked(AID.Continuation) && + !state.Unlocked(AID.GnashingFang) && + state.Ammo >= 2) + { + return AID.NoMercy; + } + else if (canUseBurstStrike && state.Ammo >= 2) // Ensure at least 2 ammo for BurstStrike + { + return AID.BurstStrike; + } + } + } + if (state.CD(CDGroup.NoMercy) > 17) { if (state.GunComboStep == 0 && state.Unlocked(AID.GnashingFang) && state.CD(CDGroup.GnashingFang) < 0.6f && state.Ammo >= 1 && ShouldUseGnash(state, strategy) && state.NumTargetsHitByAOE <= 3) @@ -416,21 +464,70 @@ public static AID GetNextAmmoAction(State state, Strategy strategy, bool aoe) return AID.BurstStrike; if (!aoe && state.Ammo >= 1 && state.CD(CDGroup.GnashingFang) > state.GCD && !state.Unlocked(AID.DoubleDown) && !state.Unlocked(AID.SonicBreak) && state.GunComboStep == 0) return AID.BurstStrike; - - // Lv70 only; when in NM and you can't use Fated Circle (Lv72) sadge - if (aoe && state.Ammo >= 1 && !state.Unlocked(AID.FatedCircle) && !state.Unlocked(AID.DoubleDown) && !state.Unlocked(AID.Bloodfest) && state.Unlocked(AID.Continuation) && state.GunComboStep == 0) + if (!state.Unlocked(AID.FatedCircle) && !state.Unlocked(AID.DoubleDown) && !state.Unlocked(AID.Bloodfest) && !state.Unlocked(AID.Continuation) && !state.Unlocked(AID.GnashingFang) && !state.Unlocked(AID.SonicBreak) && state.Ammo >= 2) return AID.BurstStrike; - if (!aoe && state.Ammo >= 1 && !state.Unlocked(AID.DoubleDown) && !state.Unlocked(AID.SonicBreak) && !state.Unlocked(AID.GnashingFang)) - return AID.BurstStrike; - if (aoe && state.Ammo >= 1 && state.CD(CDGroup.GnashingFang) > state.GCD && state.CD(CDGroup.DoubleDown) > state.GCD && state.CD(CDGroup.SonicBreak) > state.GCD && state.Unlocked(AID.DoubleDown) && state.GunComboStep == 0) - return AID.FatedCircle; - if (aoe && state.Ammo >= 1 && state.CD(CDGroup.GnashingFang) > state.GCD && state.CD(CDGroup.SonicBreak) > state.GCD && !state.Unlocked(AID.DoubleDown) && state.GunComboStep == 0) - return AID.FatedCircle; - if (aoe && state.Ammo >= 1 && state.CD(CDGroup.GnashingFang) > state.GCD && state.Unlocked(AID.FatedCircle) && !state.Unlocked(AID.DoubleDown) && !state.Unlocked(AID.SonicBreak) && state.GunComboStep == 0) - return AID.FatedCircle; - if (aoe && state.Ammo >= 1 && state.Unlocked(AID.FatedCircle) && !state.Unlocked(AID.DoubleDown) && !state.Unlocked(AID.SonicBreak) && !state.Unlocked(AID.GnashingFang)) - return AID.FatedCircle; + if (!aoe) + { + if (state.Ammo >= 1 && !state.Unlocked(AID.DoubleDown) && !state.Unlocked(AID.Bloodfest) && !state.Unlocked(AID.Continuation) && !state.Unlocked(AID.GnashingFang) && !state.Unlocked(AID.SonicBreak)) + return AID.BurstStrike; // Use Burst Strike + } + // AOE Logic + else if (aoe) + { + if (state.NoMercyLeft > 0) + { + if (state.Ammo >= 1) + { + if (state.Unlocked(AID.GnashingFang) && state.CD(CDGroup.GnashingFang) == 0) + { + return AID.GnashingFang; // Use Gnashing Fang if available and off cooldown + } + if (!state.Unlocked(AID.FatedCircle) && !state.Unlocked(AID.DoubleDown)) + { + return AID.BurstStrike; // Use Burst Strike if Fated Circle and Double Down are not unlocked + } + } + if (state.Ammo >= 2 && !state.Unlocked(AID.DoubleDown) && + !state.Unlocked(AID.Bloodfest) && !state.Unlocked(AID.Continuation) && !state.Unlocked(AID.GnashingFang)) + { + return AID.BurstStrike; // Use Burst Strike for Lv30-53 AOE spender + } + if (state.Ammo >= 2 && state.Unlocked(AID.SonicBreak) && state.Unlocked(AID.GnashingFang) && + !state.Unlocked(AID.FatedCircle) && !state.Unlocked(AID.DoubleDown)) + { + return AID.GnashingFang; // Use Gnashing Fang for Lv60 AOE fix + } + } + if (state.Ammo >= 1 && state.GunComboStep == 0) + { + if (state.NoMercyLeft > 0 && !state.Unlocked(AID.FatedCircle) && !state.Unlocked(AID.DoubleDown) && !state.Unlocked(AID.Bloodfest) && + state.Unlocked(AID.Continuation)) + { + return AID.BurstStrike; // Lv70 AOE combo, no Fated Circle + } + if (state.Ammo >= 1 && state.NoMercyLeft > 0 && state.Unlocked(AID.SonicBreak) && state.Unlocked(AID.GnashingFang) && + !state.Unlocked(AID.FatedCircle) && !state.Unlocked(AID.DoubleDown)) + { + return AID.BurstStrike; // Lv60 AOE BurstStrike fix + } + if (state.CD(CDGroup.GnashingFang) > state.GCD && state.CD(CDGroup.DoubleDown) > state.GCD && + state.CD(CDGroup.SonicBreak) > state.GCD && state.Unlocked(AID.DoubleDown)) + { + return AID.FatedCircle; // Lv80 AOE with DoubleDown + } + if (state.CD(CDGroup.GnashingFang) > state.GCD && state.Unlocked(AID.FatedCircle) && + !state.Unlocked(AID.DoubleDown) && !state.Unlocked(AID.SonicBreak)) + { + return AID.FatedCircle; // Lv80 AOE with Fated Circle and without DoubleDown and SonicBreak + } + if (state.Unlocked(AID.FatedCircle) && !state.Unlocked(AID.DoubleDown) && + !state.Unlocked(AID.SonicBreak) && !state.Unlocked(AID.GnashingFang)) + { + return AID.FatedCircle; // Lv80 AOE with only Fated Circle unlocked + } + } + } } if (state.GunComboStep > 0) @@ -782,9 +879,70 @@ public static AID GetNextBestGCD(State state, Strategy strategy, bool aoe) if (strategy.GaugeStrategy == Strategy.GaugeUse.LightningShotIfNotInMelee && state.RangeToTarget > 3) return AID.LightningShot; - // Lv70 only; can't use Fated Circle (Lv72) sadge - if (aoe && state.Ammo >= 1 && !state.Unlocked(AID.FatedCircle) && !state.Unlocked(AID.DoubleDown) && !state.Unlocked(AID.Bloodfest) && state.Unlocked(AID.BurstStrike) && state.Unlocked(AID.Continuation) && state.CD(CDGroup.GnashingFang) > 24 && state.GunComboStep == 0) - return AID.BurstStrike; + if (!aoe) + { + if (state.Ammo >= 2 && !state.Unlocked(AID.DoubleDown) && + !state.Unlocked(AID.Bloodfest) && !state.Unlocked(AID.Continuation) && !state.Unlocked(AID.GnashingFang) && + !state.Unlocked(AID.SonicBreak)) + { + return AID.BurstStrike; // Use Burst Strike + } + } + // AOE Logic + else if (aoe) + { + if (state.Ammo >= 2) + { + if (state.Ammo >= 2) + { + if (state.Unlocked(AID.GnashingFang) && state.CD(CDGroup.GnashingFang) == 0) + { + return AID.GnashingFang; // Use Gnashing Fang if available and off cooldown + } + if (!state.Unlocked(AID.FatedCircle) && !state.Unlocked(AID.DoubleDown)) + { + return AID.BurstStrike; // Use Burst Strike if Fated Circle and Double Down are not unlocked + } + } + if (state.Ammo >= 2 && !state.Unlocked(AID.DoubleDown) && + !state.Unlocked(AID.Bloodfest) && !state.Unlocked(AID.Continuation) && !state.Unlocked(AID.GnashingFang)) + { + return AID.BurstStrike; // Use Burst Strike for Lv30-53 AOE spender + } + if (state.Ammo >= 2 && state.Unlocked(AID.SonicBreak) && state.Unlocked(AID.GnashingFang) && + !state.Unlocked(AID.FatedCircle) && !state.Unlocked(AID.DoubleDown)) + { + return AID.GnashingFang; // Use Gnashing Fang for Lv60 AOE fix + } + else if (state.Ammo >= 2 && state.Unlocked(AID.SonicBreak) && state.Unlocked(AID.GnashingFang) && (state.CD(CDGroup.GnashingFang) > state.AnimationLock && !state.Unlocked(AID.FatedCircle) && !state.Unlocked(AID.DoubleDown))) + { + return AID.BurstStrike; // Use BurstStrike for Lv60 AOE fix + } + } + if (state.Ammo >= 2 && state.GunComboStep == 0) + { + if (!state.Unlocked(AID.FatedCircle) && !state.Unlocked(AID.DoubleDown) && !state.Unlocked(AID.Bloodfest) && + state.Unlocked(AID.Continuation)) + { + return AID.BurstStrike; // Lv70 AOE combo, no Fated Circle + } + if (state.CD(CDGroup.GnashingFang) > state.GCD && state.CD(CDGroup.DoubleDown) > state.GCD && + state.CD(CDGroup.SonicBreak) > state.GCD && state.Unlocked(AID.DoubleDown)) + { + return AID.FatedCircle; // Lv80 AOE with DoubleDown + } + if (state.CD(CDGroup.GnashingFang) > state.GCD && state.Unlocked(AID.FatedCircle) && + !state.Unlocked(AID.DoubleDown) && !state.Unlocked(AID.SonicBreak)) + { + return AID.FatedCircle; // Lv80 AOE with Fated Circle and without DoubleDown and SonicBreak + } + if (state.Unlocked(AID.FatedCircle) && !state.Unlocked(AID.DoubleDown) && + !state.Unlocked(AID.SonicBreak) && !state.Unlocked(AID.GnashingFang)) + { + return AID.FatedCircle; // Lv80 AOE with only Fated Circle unlocked + } + } + } if (state.ReadyToBlast) return state.BestContinuation; @@ -875,6 +1033,20 @@ public static ActionID GetNextBestOGCD(State state, Strategy strategy, float dea if (state.Unlocked(AID.Bloodfest) && state.CanWeave(CDGroup.Bloodfest, 0.6f, deadline) && ShouldUseFest(state, strategy)) return ActionID.MakeSpell(AID.Bloodfest); + // Lv30-53 NM proc ST + if (state.Unlocked(AID.NoMercy)) + { + if (!state.Unlocked(AID.FatedCircle) && !state.Unlocked(AID.DoubleDown) && !state.Unlocked(AID.Bloodfest) && !state.Unlocked(AID.Continuation) && !state.Unlocked(AID.GnashingFang) && state.Ammo == 2 && state.CanWeave(CDGroup.NoMercy, 0.6f, deadline)) + return ActionID.MakeSpell(AID.NoMercy); + } + + // Lv30-53 NM proc AOE + if (state.Unlocked(AID.NoMercy)) + { + if (aoe && !state.Unlocked(AID.FatedCircle) && !state.Unlocked(AID.DoubleDown) && !state.Unlocked(AID.Bloodfest) && !state.Unlocked(AID.Continuation) && !state.Unlocked(AID.GnashingFang) && state.Ammo == 2) + return ActionID.MakeSpell(AID.NoMercy); + } + if (wantRoughDivide && Service.Config.Get().NoMercyRoughDivide && state.CanWeave(state.CD(CDGroup.RoughDivide) - 28.5f, 0.6f, deadline) && state.NoMercyLeft > state.AnimationLock && state.CD(CDGroup.SonicBreak) > 5.5 && state.Unlocked(AID.BurstStrike)) return ActionID.MakeSpell(AID.RoughDivide); From c0bc5674e04acd055e907653bae8c82ec1de7553 Mon Sep 17 00:00:00 2001 From: Akechi-kun <167795370+Akechi-kun@users.noreply.github.com> Date: Mon, 3 Jun 2024 23:07:30 -0700 Subject: [PATCH 2/3] minor code cleanup yada yada --- BossMod/Autorotation/GNB/GNBRotation.cs | 76 +++++++++++-------------- 1 file changed, 34 insertions(+), 42 deletions(-) diff --git a/BossMod/Autorotation/GNB/GNBRotation.cs b/BossMod/Autorotation/GNB/GNBRotation.cs index c84c9b7a2b..d515fbba9d 100644 --- a/BossMod/Autorotation/GNB/GNBRotation.cs +++ b/BossMod/Autorotation/GNB/GNBRotation.cs @@ -34,7 +34,7 @@ public override string ToString() } // strategy configuration - // TODO: add in "Hold Double Down" & rotation to support it, I'm lazy + // TODO: add in "Hold Double Down" option? public class Strategy : CommonRotation.Strategy { public enum GaugeUse : uint @@ -66,7 +66,7 @@ public enum GaugeUse : uint MaxGaugeBeforeDowntime = 8, // useful on late phases before downtime [PropertyDisplay("Use combo until second-last step, then spend gauge", 0x80400080)] - PenultimateComboThenSpend = 9, // useful for ensuring ST extension is used right before long downtime + PenultimateComboThenSpend = 9, // TODO: remove } public enum PotionUse : uint @@ -117,20 +117,20 @@ public enum SpecialAction : uint LB3 = 1, // use LB3 if available [PropertyDisplay("Stance ON", 0x80ff00ff)] - StanceOn = 2, // use LB3 if available + StanceOn = 2, [PropertyDisplay("Stance OFF", 0x80c0c000)] - StanceOff = 3, // use LB3 if available + StanceOff = 3, } - public GaugeUse GaugeStrategy; // how are we supposed to handle gauge - public PotionUse PotionStrategy; // how are we supposed to use potions - public OffensiveAbilityUse NoMercyUse; // how are we supposed to use IR - public OffensiveAbilityUse BloodFestUse; - public OffensiveAbilityUse GnashUse; // how are we supposed to use upheaval - public OffensiveAbilityUse ZoneUse; // how are we supposed to use upheaval - public OffensiveAbilityUse BowUse; // how are we supposed to use PR - public RoughDivideUse RoughDivideStrategy; // how are we supposed to use onslaught + public GaugeUse GaugeStrategy; // how are we supposed to handle carts + public PotionUse PotionStrategy; // how are we supposed to use pots + public OffensiveAbilityUse NoMercyUse; // how are we supposed to use NM + public OffensiveAbilityUse BloodFestUse; // how are we supposed to use BF + public OffensiveAbilityUse GnashUse; // how are we supposed to use GF + public OffensiveAbilityUse ZoneUse; // how are we supposed to use BZ + public OffensiveAbilityUse BowUse; // how are we supposed to use BowS + public RoughDivideUse RoughDivideStrategy; // how are we supposed to use dash public SpecialAction SpecialActionUse; // any special actions we want to use public bool Aggressive; // if true, we use buffs and stuff at last possible moment; otherwise we make sure to keep at least 1 GCD safety net @@ -394,7 +394,7 @@ public static AID GetNextAmmoAction(State state, Strategy strategy, bool aoe) if (Service.Config.Get().EarlySonicBreak && state.CD(CDGroup.NoMercy) > 40 && state.CD(CDGroup.SonicBreak) < 0.6f) return AID.SonicBreak; - // Lv30-53 NM proc ST + // Lv30-53 No Mercy procs if (state.Unlocked(AID.NoMercy)) { bool canUseBurstStrike = (state.NoMercyLeft > 0) && @@ -470,9 +470,8 @@ public static AID GetNextAmmoAction(State state, Strategy strategy, bool aoe) if (!aoe) { if (state.Ammo >= 1 && !state.Unlocked(AID.DoubleDown) && !state.Unlocked(AID.Bloodfest) && !state.Unlocked(AID.Continuation) && !state.Unlocked(AID.GnashingFang) && !state.Unlocked(AID.SonicBreak)) - return AID.BurstStrike; // Use Burst Strike + return AID.BurstStrike; } - // AOE Logic else if (aoe) { if (state.NoMercyLeft > 0) @@ -481,22 +480,22 @@ public static AID GetNextAmmoAction(State state, Strategy strategy, bool aoe) { if (state.Unlocked(AID.GnashingFang) && state.CD(CDGroup.GnashingFang) == 0) { - return AID.GnashingFang; // Use Gnashing Fang if available and off cooldown + return AID.GnashingFang; // GF prio } if (!state.Unlocked(AID.FatedCircle) && !state.Unlocked(AID.DoubleDown)) { - return AID.BurstStrike; // Use Burst Strike if Fated Circle and Double Down are not unlocked + return AID.BurstStrike; // Use BS if no GF } } if (state.Ammo >= 2 && !state.Unlocked(AID.DoubleDown) && !state.Unlocked(AID.Bloodfest) && !state.Unlocked(AID.Continuation) && !state.Unlocked(AID.GnashingFang)) { - return AID.BurstStrike; // Use Burst Strike for Lv30-53 AOE spender + return AID.BurstStrike; // Lv30-53 AOE BS } if (state.Ammo >= 2 && state.Unlocked(AID.SonicBreak) && state.Unlocked(AID.GnashingFang) && !state.Unlocked(AID.FatedCircle) && !state.Unlocked(AID.DoubleDown)) { - return AID.GnashingFang; // Use Gnashing Fang for Lv60 AOE fix + return AID.GnashingFang; // Lv60 AOE GF } } if (state.Ammo >= 1 && state.GunComboStep == 0) @@ -504,27 +503,27 @@ public static AID GetNextAmmoAction(State state, Strategy strategy, bool aoe) if (state.NoMercyLeft > 0 && !state.Unlocked(AID.FatedCircle) && !state.Unlocked(AID.DoubleDown) && !state.Unlocked(AID.Bloodfest) && state.Unlocked(AID.Continuation)) { - return AID.BurstStrike; // Lv70 AOE combo, no Fated Circle + return AID.BurstStrike; // Lv70 AOE BS } if (state.Ammo >= 1 && state.NoMercyLeft > 0 && state.Unlocked(AID.SonicBreak) && state.Unlocked(AID.GnashingFang) && !state.Unlocked(AID.FatedCircle) && !state.Unlocked(AID.DoubleDown)) { - return AID.BurstStrike; // Lv60 AOE BurstStrike fix + return AID.BurstStrike; // Lv60 AOE BS } if (state.CD(CDGroup.GnashingFang) > state.GCD && state.CD(CDGroup.DoubleDown) > state.GCD && state.CD(CDGroup.SonicBreak) > state.GCD && state.Unlocked(AID.DoubleDown)) { - return AID.FatedCircle; // Lv80 AOE with DoubleDown + return AID.FatedCircle; } if (state.CD(CDGroup.GnashingFang) > state.GCD && state.Unlocked(AID.FatedCircle) && !state.Unlocked(AID.DoubleDown) && !state.Unlocked(AID.SonicBreak)) { - return AID.FatedCircle; // Lv80 AOE with Fated Circle and without DoubleDown and SonicBreak + return AID.FatedCircle; } if (state.Unlocked(AID.FatedCircle) && !state.Unlocked(AID.DoubleDown) && !state.Unlocked(AID.SonicBreak) && !state.Unlocked(AID.GnashingFang)) { - return AID.FatedCircle; // Lv80 AOE with only Fated Circle unlocked + return AID.FatedCircle; } } } @@ -675,7 +674,6 @@ public static AID GetNextAmmoAction(State state, Strategy strategy, bool aoe) } } - // single-target gauge spender return GetNextUnlockedComboAction(state, strategy, aoe); } @@ -767,10 +765,6 @@ public static bool ShouldUseFest(State state, Strategy strategy) } else { - //var gnbConfig = Service.Config.Get(); - //bool isEarlyNoMercy = gnbConfig.EarlyNoMercy; - - //bool shouldUseEarlyNoMercy = state.TargetingEnemy && state.CD(CDGroup.NoMercy) < state.AnimationLock && ((!isEarlyNoMercy && state.ComboLastMove == AID.BrutalShell) || (isEarlyNoMercy && state.ComboLastMove == AID.KeenEdge)) && strategy.CombatTimer < 10 && state.Ammo == 0 && state.Unlocked(AID.Bloodfest); bool inNoMercy = state.NoMercyLeft > state.AnimationLock && state.Unlocked(AID.Bloodfest); return inNoMercy && state.Ammo == 0; } @@ -808,10 +802,10 @@ public static bool ShouldUseRoughDivide(State state, Strategy strategy) if (strategy.PositionLockIn <= state.AnimationLock) return false; // forbidden due to state flags if (OnCD && state.NoMercyLeft > state.AnimationLock) - return true; // delay until Gnashing Sonic and Doubledown on CD, even if overcapping charges + return true; // delay until GF, SB, and DD on CD, even if overcapping charges float chargeCapIn = state.CD(CDGroup.RoughDivide); if (chargeCapIn < state.GCD + 2.5) - return true; // if we won't onslaught now, we risk overcapping charges + return true; // if we won't dash now, we risk overcapping charges if (strategy.RoughDivideStrategy != Strategy.RoughDivideUse.NoReserve && state.CD(CDGroup.RoughDivide) > 30 + state.AnimationLock) return false; // strategy prevents us from using last charge if (state.RaidBuffsLeft > state.AnimationLock) @@ -863,7 +857,6 @@ public static AID ChooseRotationBasedOnGauge(State state, Strategy strategy, boo return GetNextAOEComboAction(state.ComboLastMove); } - // Default action return GetNextUnlockedComboAction(state, strategy, aoe); } @@ -888,7 +881,6 @@ public static AID GetNextBestGCD(State state, Strategy strategy, bool aoe) return AID.BurstStrike; // Use Burst Strike } } - // AOE Logic else if (aoe) { if (state.Ammo >= 2) @@ -897,26 +889,26 @@ public static AID GetNextBestGCD(State state, Strategy strategy, bool aoe) { if (state.Unlocked(AID.GnashingFang) && state.CD(CDGroup.GnashingFang) == 0) { - return AID.GnashingFang; // Use Gnashing Fang if available and off cooldown + return AID.GnashingFang; // GF prio } if (!state.Unlocked(AID.FatedCircle) && !state.Unlocked(AID.DoubleDown)) { - return AID.BurstStrike; // Use Burst Strike if Fated Circle and Double Down are not unlocked + return AID.BurstStrike; // BS if no GF } } if (state.Ammo >= 2 && !state.Unlocked(AID.DoubleDown) && !state.Unlocked(AID.Bloodfest) && !state.Unlocked(AID.Continuation) && !state.Unlocked(AID.GnashingFang)) { - return AID.BurstStrike; // Use Burst Strike for Lv30-53 AOE spender + return AID.BurstStrike; // Lv30-Lv53 AOE BS } if (state.Ammo >= 2 && state.Unlocked(AID.SonicBreak) && state.Unlocked(AID.GnashingFang) && !state.Unlocked(AID.FatedCircle) && !state.Unlocked(AID.DoubleDown)) { - return AID.GnashingFang; // Use Gnashing Fang for Lv60 AOE fix + return AID.GnashingFang; // Lv60 AOE GF } else if (state.Ammo >= 2 && state.Unlocked(AID.SonicBreak) && state.Unlocked(AID.GnashingFang) && (state.CD(CDGroup.GnashingFang) > state.AnimationLock && !state.Unlocked(AID.FatedCircle) && !state.Unlocked(AID.DoubleDown))) { - return AID.BurstStrike; // Use BurstStrike for Lv60 AOE fix + return AID.BurstStrike; // // Lv60 AOE BS } } if (state.Ammo >= 2 && state.GunComboStep == 0) @@ -924,22 +916,22 @@ public static AID GetNextBestGCD(State state, Strategy strategy, bool aoe) if (!state.Unlocked(AID.FatedCircle) && !state.Unlocked(AID.DoubleDown) && !state.Unlocked(AID.Bloodfest) && state.Unlocked(AID.Continuation)) { - return AID.BurstStrike; // Lv70 AOE combo, no Fated Circle + return AID.BurstStrike; // Lv70 AOE BS } if (state.CD(CDGroup.GnashingFang) > state.GCD && state.CD(CDGroup.DoubleDown) > state.GCD && state.CD(CDGroup.SonicBreak) > state.GCD && state.Unlocked(AID.DoubleDown)) { - return AID.FatedCircle; // Lv80 AOE with DoubleDown + return AID.FatedCircle; } if (state.CD(CDGroup.GnashingFang) > state.GCD && state.Unlocked(AID.FatedCircle) && !state.Unlocked(AID.DoubleDown) && !state.Unlocked(AID.SonicBreak)) { - return AID.FatedCircle; // Lv80 AOE with Fated Circle and without DoubleDown and SonicBreak + return AID.FatedCircle; } if (state.Unlocked(AID.FatedCircle) && !state.Unlocked(AID.DoubleDown) && !state.Unlocked(AID.SonicBreak) && !state.Unlocked(AID.GnashingFang)) { - return AID.FatedCircle; // Lv80 AOE with only Fated Circle unlocked + return AID.FatedCircle; } } } From e95d7fe75da609b6f6f5a8cbe0ab372152bbffac Mon Sep 17 00:00:00 2001 From: ace Date: Mon, 3 Jun 2024 23:18:31 -0700 Subject: [PATCH 3/3] Revert "minor code cleanup" This reverts commit c0bc5674e04acd055e907653bae8c82ec1de7553. --- BossMod/Autorotation/GNB/GNBRotation.cs | 76 ++++++++++++++----------- 1 file changed, 42 insertions(+), 34 deletions(-) diff --git a/BossMod/Autorotation/GNB/GNBRotation.cs b/BossMod/Autorotation/GNB/GNBRotation.cs index d515fbba9d..c84c9b7a2b 100644 --- a/BossMod/Autorotation/GNB/GNBRotation.cs +++ b/BossMod/Autorotation/GNB/GNBRotation.cs @@ -34,7 +34,7 @@ public override string ToString() } // strategy configuration - // TODO: add in "Hold Double Down" option? + // TODO: add in "Hold Double Down" & rotation to support it, I'm lazy public class Strategy : CommonRotation.Strategy { public enum GaugeUse : uint @@ -66,7 +66,7 @@ public enum GaugeUse : uint MaxGaugeBeforeDowntime = 8, // useful on late phases before downtime [PropertyDisplay("Use combo until second-last step, then spend gauge", 0x80400080)] - PenultimateComboThenSpend = 9, // TODO: remove + PenultimateComboThenSpend = 9, // useful for ensuring ST extension is used right before long downtime } public enum PotionUse : uint @@ -117,20 +117,20 @@ public enum SpecialAction : uint LB3 = 1, // use LB3 if available [PropertyDisplay("Stance ON", 0x80ff00ff)] - StanceOn = 2, + StanceOn = 2, // use LB3 if available [PropertyDisplay("Stance OFF", 0x80c0c000)] - StanceOff = 3, + StanceOff = 3, // use LB3 if available } - public GaugeUse GaugeStrategy; // how are we supposed to handle carts - public PotionUse PotionStrategy; // how are we supposed to use pots - public OffensiveAbilityUse NoMercyUse; // how are we supposed to use NM - public OffensiveAbilityUse BloodFestUse; // how are we supposed to use BF - public OffensiveAbilityUse GnashUse; // how are we supposed to use GF - public OffensiveAbilityUse ZoneUse; // how are we supposed to use BZ - public OffensiveAbilityUse BowUse; // how are we supposed to use BowS - public RoughDivideUse RoughDivideStrategy; // how are we supposed to use dash + public GaugeUse GaugeStrategy; // how are we supposed to handle gauge + public PotionUse PotionStrategy; // how are we supposed to use potions + public OffensiveAbilityUse NoMercyUse; // how are we supposed to use IR + public OffensiveAbilityUse BloodFestUse; + public OffensiveAbilityUse GnashUse; // how are we supposed to use upheaval + public OffensiveAbilityUse ZoneUse; // how are we supposed to use upheaval + public OffensiveAbilityUse BowUse; // how are we supposed to use PR + public RoughDivideUse RoughDivideStrategy; // how are we supposed to use onslaught public SpecialAction SpecialActionUse; // any special actions we want to use public bool Aggressive; // if true, we use buffs and stuff at last possible moment; otherwise we make sure to keep at least 1 GCD safety net @@ -394,7 +394,7 @@ public static AID GetNextAmmoAction(State state, Strategy strategy, bool aoe) if (Service.Config.Get().EarlySonicBreak && state.CD(CDGroup.NoMercy) > 40 && state.CD(CDGroup.SonicBreak) < 0.6f) return AID.SonicBreak; - // Lv30-53 No Mercy procs + // Lv30-53 NM proc ST if (state.Unlocked(AID.NoMercy)) { bool canUseBurstStrike = (state.NoMercyLeft > 0) && @@ -470,8 +470,9 @@ public static AID GetNextAmmoAction(State state, Strategy strategy, bool aoe) if (!aoe) { if (state.Ammo >= 1 && !state.Unlocked(AID.DoubleDown) && !state.Unlocked(AID.Bloodfest) && !state.Unlocked(AID.Continuation) && !state.Unlocked(AID.GnashingFang) && !state.Unlocked(AID.SonicBreak)) - return AID.BurstStrike; + return AID.BurstStrike; // Use Burst Strike } + // AOE Logic else if (aoe) { if (state.NoMercyLeft > 0) @@ -480,22 +481,22 @@ public static AID GetNextAmmoAction(State state, Strategy strategy, bool aoe) { if (state.Unlocked(AID.GnashingFang) && state.CD(CDGroup.GnashingFang) == 0) { - return AID.GnashingFang; // GF prio + return AID.GnashingFang; // Use Gnashing Fang if available and off cooldown } if (!state.Unlocked(AID.FatedCircle) && !state.Unlocked(AID.DoubleDown)) { - return AID.BurstStrike; // Use BS if no GF + return AID.BurstStrike; // Use Burst Strike if Fated Circle and Double Down are not unlocked } } if (state.Ammo >= 2 && !state.Unlocked(AID.DoubleDown) && !state.Unlocked(AID.Bloodfest) && !state.Unlocked(AID.Continuation) && !state.Unlocked(AID.GnashingFang)) { - return AID.BurstStrike; // Lv30-53 AOE BS + return AID.BurstStrike; // Use Burst Strike for Lv30-53 AOE spender } if (state.Ammo >= 2 && state.Unlocked(AID.SonicBreak) && state.Unlocked(AID.GnashingFang) && !state.Unlocked(AID.FatedCircle) && !state.Unlocked(AID.DoubleDown)) { - return AID.GnashingFang; // Lv60 AOE GF + return AID.GnashingFang; // Use Gnashing Fang for Lv60 AOE fix } } if (state.Ammo >= 1 && state.GunComboStep == 0) @@ -503,27 +504,27 @@ public static AID GetNextAmmoAction(State state, Strategy strategy, bool aoe) if (state.NoMercyLeft > 0 && !state.Unlocked(AID.FatedCircle) && !state.Unlocked(AID.DoubleDown) && !state.Unlocked(AID.Bloodfest) && state.Unlocked(AID.Continuation)) { - return AID.BurstStrike; // Lv70 AOE BS + return AID.BurstStrike; // Lv70 AOE combo, no Fated Circle } if (state.Ammo >= 1 && state.NoMercyLeft > 0 && state.Unlocked(AID.SonicBreak) && state.Unlocked(AID.GnashingFang) && !state.Unlocked(AID.FatedCircle) && !state.Unlocked(AID.DoubleDown)) { - return AID.BurstStrike; // Lv60 AOE BS + return AID.BurstStrike; // Lv60 AOE BurstStrike fix } if (state.CD(CDGroup.GnashingFang) > state.GCD && state.CD(CDGroup.DoubleDown) > state.GCD && state.CD(CDGroup.SonicBreak) > state.GCD && state.Unlocked(AID.DoubleDown)) { - return AID.FatedCircle; + return AID.FatedCircle; // Lv80 AOE with DoubleDown } if (state.CD(CDGroup.GnashingFang) > state.GCD && state.Unlocked(AID.FatedCircle) && !state.Unlocked(AID.DoubleDown) && !state.Unlocked(AID.SonicBreak)) { - return AID.FatedCircle; + return AID.FatedCircle; // Lv80 AOE with Fated Circle and without DoubleDown and SonicBreak } if (state.Unlocked(AID.FatedCircle) && !state.Unlocked(AID.DoubleDown) && !state.Unlocked(AID.SonicBreak) && !state.Unlocked(AID.GnashingFang)) { - return AID.FatedCircle; + return AID.FatedCircle; // Lv80 AOE with only Fated Circle unlocked } } } @@ -674,6 +675,7 @@ public static AID GetNextAmmoAction(State state, Strategy strategy, bool aoe) } } + // single-target gauge spender return GetNextUnlockedComboAction(state, strategy, aoe); } @@ -765,6 +767,10 @@ public static bool ShouldUseFest(State state, Strategy strategy) } else { + //var gnbConfig = Service.Config.Get(); + //bool isEarlyNoMercy = gnbConfig.EarlyNoMercy; + + //bool shouldUseEarlyNoMercy = state.TargetingEnemy && state.CD(CDGroup.NoMercy) < state.AnimationLock && ((!isEarlyNoMercy && state.ComboLastMove == AID.BrutalShell) || (isEarlyNoMercy && state.ComboLastMove == AID.KeenEdge)) && strategy.CombatTimer < 10 && state.Ammo == 0 && state.Unlocked(AID.Bloodfest); bool inNoMercy = state.NoMercyLeft > state.AnimationLock && state.Unlocked(AID.Bloodfest); return inNoMercy && state.Ammo == 0; } @@ -802,10 +808,10 @@ public static bool ShouldUseRoughDivide(State state, Strategy strategy) if (strategy.PositionLockIn <= state.AnimationLock) return false; // forbidden due to state flags if (OnCD && state.NoMercyLeft > state.AnimationLock) - return true; // delay until GF, SB, and DD on CD, even if overcapping charges + return true; // delay until Gnashing Sonic and Doubledown on CD, even if overcapping charges float chargeCapIn = state.CD(CDGroup.RoughDivide); if (chargeCapIn < state.GCD + 2.5) - return true; // if we won't dash now, we risk overcapping charges + return true; // if we won't onslaught now, we risk overcapping charges if (strategy.RoughDivideStrategy != Strategy.RoughDivideUse.NoReserve && state.CD(CDGroup.RoughDivide) > 30 + state.AnimationLock) return false; // strategy prevents us from using last charge if (state.RaidBuffsLeft > state.AnimationLock) @@ -857,6 +863,7 @@ public static AID ChooseRotationBasedOnGauge(State state, Strategy strategy, boo return GetNextAOEComboAction(state.ComboLastMove); } + // Default action return GetNextUnlockedComboAction(state, strategy, aoe); } @@ -881,6 +888,7 @@ public static AID GetNextBestGCD(State state, Strategy strategy, bool aoe) return AID.BurstStrike; // Use Burst Strike } } + // AOE Logic else if (aoe) { if (state.Ammo >= 2) @@ -889,26 +897,26 @@ public static AID GetNextBestGCD(State state, Strategy strategy, bool aoe) { if (state.Unlocked(AID.GnashingFang) && state.CD(CDGroup.GnashingFang) == 0) { - return AID.GnashingFang; // GF prio + return AID.GnashingFang; // Use Gnashing Fang if available and off cooldown } if (!state.Unlocked(AID.FatedCircle) && !state.Unlocked(AID.DoubleDown)) { - return AID.BurstStrike; // BS if no GF + return AID.BurstStrike; // Use Burst Strike if Fated Circle and Double Down are not unlocked } } if (state.Ammo >= 2 && !state.Unlocked(AID.DoubleDown) && !state.Unlocked(AID.Bloodfest) && !state.Unlocked(AID.Continuation) && !state.Unlocked(AID.GnashingFang)) { - return AID.BurstStrike; // Lv30-Lv53 AOE BS + return AID.BurstStrike; // Use Burst Strike for Lv30-53 AOE spender } if (state.Ammo >= 2 && state.Unlocked(AID.SonicBreak) && state.Unlocked(AID.GnashingFang) && !state.Unlocked(AID.FatedCircle) && !state.Unlocked(AID.DoubleDown)) { - return AID.GnashingFang; // Lv60 AOE GF + return AID.GnashingFang; // Use Gnashing Fang for Lv60 AOE fix } else if (state.Ammo >= 2 && state.Unlocked(AID.SonicBreak) && state.Unlocked(AID.GnashingFang) && (state.CD(CDGroup.GnashingFang) > state.AnimationLock && !state.Unlocked(AID.FatedCircle) && !state.Unlocked(AID.DoubleDown))) { - return AID.BurstStrike; // // Lv60 AOE BS + return AID.BurstStrike; // Use BurstStrike for Lv60 AOE fix } } if (state.Ammo >= 2 && state.GunComboStep == 0) @@ -916,22 +924,22 @@ public static AID GetNextBestGCD(State state, Strategy strategy, bool aoe) if (!state.Unlocked(AID.FatedCircle) && !state.Unlocked(AID.DoubleDown) && !state.Unlocked(AID.Bloodfest) && state.Unlocked(AID.Continuation)) { - return AID.BurstStrike; // Lv70 AOE BS + return AID.BurstStrike; // Lv70 AOE combo, no Fated Circle } if (state.CD(CDGroup.GnashingFang) > state.GCD && state.CD(CDGroup.DoubleDown) > state.GCD && state.CD(CDGroup.SonicBreak) > state.GCD && state.Unlocked(AID.DoubleDown)) { - return AID.FatedCircle; + return AID.FatedCircle; // Lv80 AOE with DoubleDown } if (state.CD(CDGroup.GnashingFang) > state.GCD && state.Unlocked(AID.FatedCircle) && !state.Unlocked(AID.DoubleDown) && !state.Unlocked(AID.SonicBreak)) { - return AID.FatedCircle; + return AID.FatedCircle; // Lv80 AOE with Fated Circle and without DoubleDown and SonicBreak } if (state.Unlocked(AID.FatedCircle) && !state.Unlocked(AID.DoubleDown) && !state.Unlocked(AID.SonicBreak) && !state.Unlocked(AID.GnashingFang)) { - return AID.FatedCircle; + return AID.FatedCircle; // Lv80 AOE with only Fated Circle unlocked } } }