diff --git a/RotationSolver.Basic/Data/ActionID.cs b/RotationSolver.Basic/Data/ActionID.cs index 98ce1dd86..c81a7c7e2 100644 --- a/RotationSolver.Basic/Data/ActionID.cs +++ b/RotationSolver.Basic/Data/ActionID.cs @@ -544,7 +544,7 @@ public enum ActionID : uint AbyssalDrain = 3641, - CarveandSpit = 3643, + CarveAndSpit = 3643, BloodSpiller = 7392, diff --git a/RotationSolver.Basic/Rotations/Basic/AST_Base.cs b/RotationSolver.Basic/Rotations/Basic/AST_Base.cs index 185fc7d36..6c8c71c40 100644 --- a/RotationSolver.Basic/Rotations/Basic/AST_Base.cs +++ b/RotationSolver.Basic/Rotations/Basic/AST_Base.cs @@ -2,22 +2,19 @@ namespace RotationSolver.Basic.Rotations.Basic; public abstract class AST_Base : CustomRotation { - private static ASTGauge JobGauge => Service.JobGauges.Get(); - public override MedicineType MedicineType => MedicineType.Mind; - private static CardType DrawnCard => JobGauge.DrawnCard; - - protected static CardType DrawnCrownCard => JobGauge.DrawnCrownCard; + public sealed override ClassJobID[] JobIDs => new ClassJobID[] { ClassJobID.Astrologian }; - protected static SealType[] Seals => JobGauge.Seals; + static ASTGauge JobGauge => Service.JobGauges.Get(); - public sealed override ClassJobID[] JobIDs => new ClassJobID[] { ClassJobID.Astrologian }; + protected static CardType DrawnCard => JobGauge.DrawnCard; - private sealed protected override IBaseAction Raise => Ascend; + protected static CardType DrawnCrownCard => JobGauge.DrawnCrownCard; - public static IBaseAction Ascend { get; } = new BaseAction(ActionID.Ascend, ActionOption.Friendly); + protected static SealType[] Seals => JobGauge.Seals; + #region Attack public static IBaseAction Malefic { get; } = new BaseAction(ActionID.Malefic); public static IBaseAction Combust { get; } = new BaseAction(ActionID.Combust, ActionOption.Dot) @@ -32,6 +29,12 @@ public abstract class AST_Base : CustomRotation }; public static IBaseAction Gravity { get; } = new BaseAction(ActionID.Gravity); + #endregion + + #region Heal Single + private sealed protected override IBaseAction Raise => Ascend; + + public static IBaseAction Ascend { get; } = new BaseAction(ActionID.Ascend, ActionOption.Friendly); public static IBaseAction Benefic { get; } = new BaseAction(ActionID.Benefic, ActionOption.Heal); @@ -45,19 +48,9 @@ public abstract class AST_Base : CustomRotation public static IBaseAction EssentialDignity { get; } = new BaseAction(ActionID.EssentialDignity, ActionOption.Heal); public static IBaseAction Synastry { get; } = new BaseAction(ActionID.Synastry, ActionOption.Heal); + #endregion - public static IBaseAction CelestialIntersection { get; } = new BaseAction(ActionID.CelestialIntersection, ActionOption.Heal) - { - ChoiceTarget = TargetFilter.FindAttackedTarget, - - TargetStatus = new StatusID[] { StatusID.Intersection }, - }; - - public static IBaseAction Exaltation { get; } = new BaseAction(ActionID.Exaltation, ActionOption.Heal) - { - ChoiceTarget = TargetFilter.FindAttackedTarget, - }; - + #region Heal Area public static IBaseAction Helios { get; } = new BaseAction(ActionID.Helios, ActionOption.Heal); public static IBaseAction AspectedHelios { get; } = new BaseAction(ActionID.AspectedHelios, ActionOption.Hot) @@ -70,16 +63,38 @@ public abstract class AST_Base : CustomRotation public static IBaseAction EarthlyStar { get; } = new BaseAction(ActionID.EarthlyStar, ActionOption.Heal); - public static IBaseAction CollectiveUnconscious { get; } = new BaseAction(ActionID.CollectiveUnconscious, ActionOption.Heal); - public static IBaseAction Horoscope { get; } = new BaseAction(ActionID.Horoscope, ActionOption.Heal); + public static IBaseAction Macrocosmos { get; } = new BaseAction(ActionID.Macrocosmos, ActionOption.Heal); + + #endregion + + #region Defense Single + + public static IBaseAction CelestialIntersection { get; } = new BaseAction(ActionID.CelestialIntersection, ActionOption.Defense) + { + ChoiceTarget = TargetFilter.FindAttackedTarget, + TargetStatus = new StatusID[] { StatusID.Intersection }, + }; + + public static IBaseAction Exaltation { get; } = new BaseAction(ActionID.Exaltation, ActionOption.Heal) + { + ChoiceTarget = TargetFilter.FindAttackedTarget, + }; + #endregion + + #region Defense Area + + public static IBaseAction CollectiveUnconscious { get; } = new BaseAction(ActionID.CollectiveUnconscious, ActionOption.Defense); + + #endregion + + + #region Support public static IBaseAction Lightspeed { get; } = new BaseAction(ActionID.Lightspeed); public static IBaseAction NeutralSect { get; } = new BaseAction(ActionID.NeutralSect, ActionOption.Heal); - public static IBaseAction Macrocosmos { get; } = new BaseAction(ActionID.Macrocosmos, ActionOption.Heal); - public static IBaseAction Astrodyne { get; } = new BaseAction(ActionID.Astrodyne) { ActionCheck = b => @@ -103,52 +118,49 @@ public abstract class AST_Base : CustomRotation ActionCheck = b => DrawnCard != CardType.NONE && Seals.Contains(GetCardSeal(DrawnCard)), }; + public static IBaseAction MinorArcana { get; } = new BaseAction(ActionID.MinorArcana) { ActionCheck = b => InCombat && DrawnCrownCard == CardType.NONE, }; - //public static IBaseAction CrownPlay { get; } = new BaseAction(ActionID.CrownPlay) - //{ - // ActionCheck = b => DrawnCrownCard is CardType.LADY or CardType.LORD, - //}; - - private static IBaseAction Balance { get; } = new BaseAction(ActionID.Balance) + static IBaseAction Balance { get; } = new BaseAction(ActionID.Balance) { ChoiceTarget = TargetFilter.ASTMeleeTarget, ActionCheck = b => DrawnCard == CardType.BALANCE, }; - private static IBaseAction Arrow { get; } = new BaseAction(ActionID.Arrow) + static IBaseAction Arrow { get; } = new BaseAction(ActionID.Arrow) { ChoiceTarget = TargetFilter.ASTMeleeTarget, ActionCheck = b => DrawnCard == CardType.ARROW, }; - private static IBaseAction Spear { get; } = new BaseAction(ActionID.Spear) + static IBaseAction Spear { get; } = new BaseAction(ActionID.Spear) { ChoiceTarget = TargetFilter.ASTMeleeTarget, ActionCheck = b => DrawnCard == CardType.SPEAR, }; - private static IBaseAction Bole { get; } = new BaseAction(ActionID.Bole) + static IBaseAction Bole { get; } = new BaseAction(ActionID.Bole) { ChoiceTarget = TargetFilter.ASTRangeTarget, ActionCheck = b => DrawnCard == CardType.BOLE, }; - private static IBaseAction Ewer { get; } = new BaseAction(ActionID.Ewer) + static IBaseAction Ewer { get; } = new BaseAction(ActionID.Ewer) { ChoiceTarget = TargetFilter.ASTRangeTarget, ActionCheck = b => DrawnCard == CardType.EWER, }; - private static IBaseAction Spire { get; } = new BaseAction(ActionID.Spire) + static IBaseAction Spire { get; } = new BaseAction(ActionID.Spire) { ChoiceTarget = TargetFilter.ASTRangeTarget, ActionCheck = b => DrawnCard == CardType.SPIRE, }; + #endregion protected static bool PlayCard(out IAction act) { @@ -165,7 +177,7 @@ protected static bool PlayCard(out IAction act) return false; } - private static SealType GetCardSeal(CardType card) + static SealType GetCardSeal(CardType card) { switch (card) { diff --git a/RotationSolver.Basic/Rotations/Basic/BLM_Base.cs b/RotationSolver.Basic/Rotations/Basic/BLM_Base.cs index dbaa8d5c5..b8a59c440 100644 --- a/RotationSolver.Basic/Rotations/Basic/BLM_Base.cs +++ b/RotationSolver.Basic/Rotations/Basic/BLM_Base.cs @@ -2,10 +2,13 @@ public abstract partial class BLM_Base : CustomRotation { - private static BLMGauge JobGauge => Service.JobGauges.Get(); - public override MedicineType MedicineType => MedicineType.Intelligence; + public sealed override ClassJobID[] JobIDs => new ClassJobID[] { ClassJobID.BlackMage, ClassJobID.Thaumaturge }; + + #region Job Gauge + static BLMGauge JobGauge => Service.JobGauges.Get(); + protected static byte UmbralIceStacks => JobGauge.UmbralIceStacks; protected static byte AstralFireStacks => JobGauge.AstralFireStacks; @@ -22,34 +25,35 @@ public abstract partial class BLM_Base : CustomRotation protected static bool IsEnochianActive => JobGauge.IsEnochianActive; + protected static bool IsPolyglotStacksMaxed => Xenoglossy.EnoughLevel ? PolyglotStacks == 2 : PolyglotStacks == 1; + + static float ElementTime => JobGauge.EnochianTimer / 1000f; + protected static bool EnchinaEndAfter(float time) { return EndAfter(JobGauge.EnochianTimer / 1000f, time); } - protected static bool EnchinaEndAfterGCD(uint gctCount = 0, int abilityCount = 0) + protected static bool EnchinaEndAfterGCD(uint gctCount = 0, float offset = 0) { - return EndAfterGCD(JobGauge.EnochianTimer / 1000f, gctCount, abilityCount); + return EndAfterGCD(JobGauge.EnochianTimer / 1000f, gctCount, offset); } protected static bool ElementTimeEndAfter(float time) { - return EndAfter(JobGauge.ElementTimeRemaining / 1000f, time); + return EndAfter(ElementTime, time); } - protected static bool ElementTimeEndAfterGCD(uint gctCount = 0, int abilityCount = 0) + protected static bool ElementTimeEndAfterGCD(uint gctCount = 0, float offset = 0) { - return EndAfterGCD(JobGauge.ElementTimeRemaining / 1000f, gctCount, abilityCount); + return EndAfterGCD(ElementTime, gctCount, offset); } - public sealed override ClassJobID[] JobIDs => new ClassJobID[] { ClassJobID.BlackMage, ClassJobID.Thaumaturge }; - + #endregion protected static bool HasFire => Player.HasStatus(true, StatusID.Firestarter); protected static bool HasThunder => Player.HasStatus(true, StatusID.Thundercloud); - protected static bool IsPolyglotStacksMaxed => Xenoglossy.EnoughLevel ? JobGauge.PolyglotStacks == 2 : JobGauge.PolyglotStacks == 1; - public class ThunderAction : BaseAction { public override uint MPNeed => HasThunder ? 0 : base.MPNeed; @@ -87,92 +91,120 @@ public override bool CanUse(out IAction act, CanUseOption option = CanUseOption. } } - public static IBaseAction Thunder { get; } = new ThunderAction(ActionID.Thunder); - - public static IBaseAction Thunder2 { get; } = new ThunderAction(ActionID.Thunder2); - - public static IBaseAction Transpose { get; } = new BaseAction(ActionID.Transpose) { ActionCheck = b => DataCenter.ActionRemain.IsLessThan(JobGauge.ElementTimeRemaining / 1000f) }; - - public static IBaseAction UmbralSoul { get; } = new BaseAction(ActionID.UmbralSoul) { ActionCheck = b => JobGauge.InUmbralIce && Transpose.ActionCheck(b) }; - - public static IBaseAction Manaward { get; } = new BaseAction(ActionID.Manaward, ActionOption.Defense); + #region Attack Single + public static IBaseAction Fire { get; } = new BaseAction(ActionID.Fire); - public static IBaseAction Manafont { get; } = new BaseAction(ActionID.Manafont) + public static IBaseAction Fire3 { get; } = new Fire3Action(ActionID.Fire3) { - ActionCheck = b => Player.CurrentMp <= 7000, + ActionCheck = b => !IsLastGCD(ActionID.Fire3), }; - - public static IBaseAction SharpCast { get; } = new BaseAction(ActionID.SharpCast) + public static IBaseAction Fire4 { get; } = new ElementAction(ActionID.Fire4) { - StatusProvide = new[] { StatusID.SharpCast }, - ActionCheck = b => HasHostilesInRange, + ActionCheck = b => InAstralFire && !ElementTimeEndAfter(Fire4.CastTime), }; - public static IBaseAction TripleCast { get; } = new BaseAction(ActionID.TripleCast) + public static IBaseAction Despair { get; } = new ElementAction(ActionID.Despair) { - StatusProvide = Swiftcast.StatusProvide, + ActionCheck = b => InAstralFire && !ElementTimeEndAfter(Despair.CastTime), }; - public static IBaseAction LeyLines { get; } = new BaseAction(ActionID.LeyLines, ActionOption.Buff | ActionOption.EndSpecial) + public static IBaseAction Blizzard { get; } = new BaseAction(ActionID.Blizzard); + + public static IBaseAction Blizzard3 { get; } = new BaseAction(ActionID.Blizzard3) { - StatusProvide = new[] { StatusID.LeyLines, }, + ActionCheck = b => !IsLastGCD(ActionID.Blizzard3), }; - - public static IBaseAction BetweenTheLines { get; } = new BaseAction(ActionID.BetweenTheLines, ActionOption.Buff | ActionOption.EndSpecial) + public static IBaseAction Blizzard4 { get; } = new ElementAction(ActionID.Blizzard4) { - StatusNeed = LeyLines.StatusProvide, + ActionCheck = b => InUmbralIce && !ElementTimeEndAfter(Blizzard4.CastTime), }; - public static IBaseAction AetherialManipulation { get; } = new BaseAction(ActionID.AetherialManipulation, ActionOption.Friendly) + public static IBaseAction Thunder { get; } = new ThunderAction(ActionID.Thunder); + + public static IBaseAction Xenoglossy { get; } = new BaseAction(ActionID.Xenoglossy) + { + ActionCheck = b => PolyglotStacks > 0 + }; + + public static IBaseAction Paradox { get; } = new BaseAction(ActionID.Paradox) { - ChoiceTarget = TargetFilter.FindTargetForMoving, + ActionCheck = b => IsParadoxActive, }; + public static IBaseAction Scathe { get; } = new BaseAction(ActionID.Scathe); + #endregion - public static IBaseAction Amplifier { get; } = new BaseAction(ActionID.Amplifier) { ActionCheck = b => JobGauge.EnochianTimer > 10000 && JobGauge.PolyglotStacks < 2 }; + #region Attack Area + public static IBaseAction Fire2 { get; } = new BaseAction(ActionID.Fire2); - public static IBaseAction Flare { get; } = new ElementAction(ActionID.Flare) { ActionCheck = b => JobGauge.InAstralFire }; + public static IBaseAction Flare { get; } = new ElementAction(ActionID.Flare) + { + ActionCheck = b => InAstralFire && !ElementTimeEndAfter(Flare.CastTime), + }; - public static IBaseAction Despair { get; } = new ElementAction(ActionID.Despair) { ActionCheck = b => JobGauge.InAstralFire }; + public static IBaseAction Blizzard2 { get; } = new BaseAction(ActionID.Blizzard2); - public static IBaseAction Foul { get; } = new BaseAction(ActionID.Foul) { ActionCheck = b => JobGauge.PolyglotStacks != 0 }; + public static IBaseAction Freeze { get; } = new ElementAction(ActionID.Freeze); - public static IBaseAction Xenoglossy { get; } = new BaseAction(ActionID.Xenoglossy) { ActionCheck = b => JobGauge.PolyglotStacks != 0 }; + public static IBaseAction Thunder2 { get; } = new ThunderAction(ActionID.Thunder2); - public static IBaseAction Scathe { get; } = new BaseAction(ActionID.Scathe); + public static IBaseAction Foul { get; } = new BaseAction(ActionID.Foul) + { + ActionCheck = Xenoglossy.ActionCheck, + }; + #endregion - public static IBaseAction Paradox { get; } = new BaseAction(ActionID.Paradox) + #region Support + public static IBaseAction AetherialManipulation { get; } = new BaseAction(ActionID.AetherialManipulation, ActionOption.Friendly) { - ActionCheck = b => JobGauge.IsParadoxActive, + ChoiceTarget = TargetFilter.FindTargetForMoving, }; - public static IBaseAction Fire { get; } = new BaseAction(ActionID.Fire); + public static IBaseAction Amplifier { get; } = new BaseAction(ActionID.Amplifier) + { + ActionCheck = b => !EnchinaEndAfter(10) && PolyglotStacks < 2 + }; - public static IBaseAction Fire2 { get; } = new BaseAction(ActionID.Fire2); + public static IBaseAction Manaward { get; } = new BaseAction(ActionID.Manaward, ActionOption.Defense); - public static IBaseAction Fire3 { get; } = new Fire3Action(ActionID.Fire3) + public static IBaseAction Manafont { get; } = new BaseAction(ActionID.Manafont) { - ActionCheck = b => !IsLastGCD(ActionID.Fire3), + ActionCheck = b => Player.CurrentMp <= 7000, }; - public static IBaseAction Fire4 { get; } = new ElementAction(ActionID.Fire4) + public static IBaseAction LeyLines { get; } = new BaseAction(ActionID.LeyLines, ActionOption.Buff | ActionOption.EndSpecial) { - ActionCheck = b => JobGauge.InAstralFire, + StatusProvide = new[] { StatusID.LeyLines, }, }; - public static IBaseAction Blizzard { get; } = new BaseAction(ActionID.Blizzard); + public static IBaseAction BetweenTheLines { get; } = new BaseAction(ActionID.BetweenTheLines, ActionOption.Buff | ActionOption.EndSpecial) + { + StatusNeed = LeyLines.StatusProvide, + }; - public static IBaseAction Blizzard2 { get; } = new BaseAction(ActionID.Blizzard2); + public static IBaseAction SharpCast { get; } = new BaseAction(ActionID.SharpCast) + { + StatusProvide = new[] { StatusID.SharpCast }, + ActionCheck = b => HasHostilesInRange, + }; - public static IBaseAction Blizzard3 { get; } = new BaseAction(ActionID.Blizzard3) + public static IBaseAction TripleCast { get; } = new BaseAction(ActionID.TripleCast) { - ActionCheck = b => !IsLastGCD(ActionID.Blizzard3), + StatusProvide = Swiftcast.StatusProvide, }; - public static IBaseAction Blizzard4 { get; } = new ElementAction(ActionID.Blizzard4); + public static IBaseAction Transpose { get; } = new BaseAction(ActionID.Transpose) + { + ActionCheck = b => DataCenter.ActionRemain.IsLessThan(ElementTime) + }; + + public static IBaseAction UmbralSoul { get; } = new BaseAction(ActionID.UmbralSoul) + { + ActionCheck = b => JobGauge.InUmbralIce && Transpose.ActionCheck(b) + }; + #endregion - public static IBaseAction Freeze { get; } = new ElementAction(ActionID.Freeze); - public static float Fire4Time { get; private set; } + protected static float Fire4Time { get; private set; } protected override void UpdateInfo() { if (Player.CastActionId == (uint)ActionID.Fire4 && Player.CurrentCastTime < 0.2) diff --git a/RotationSolver.Basic/Rotations/Basic/BRD_Base.cs b/RotationSolver.Basic/Rotations/Basic/BRD_Base.cs index 18a2f8363..3afd534ae 100644 --- a/RotationSolver.Basic/Rotations/Basic/BRD_Base.cs +++ b/RotationSolver.Basic/Rotations/Basic/BRD_Base.cs @@ -2,10 +2,13 @@ namespace RotationSolver.Basic.Rotations.Basic; public abstract class BRD_Base : CustomRotation { - private static BRDGauge JobGauge => Service.JobGauges.Get(); - public override MedicineType MedicineType => MedicineType.Dexterity; + public sealed override ClassJobID[] JobIDs => new[] { ClassJobID.Bard, ClassJobID.Archer }; + + #region Job Gauge + static BRDGauge JobGauge => Service.JobGauges.Get(); + protected static byte Repertoire => JobGauge.Repertoire; protected static Song Song => JobGauge.Song; @@ -13,24 +16,23 @@ public abstract class BRD_Base : CustomRotation protected static Song LastSong => JobGauge.LastSong; protected static byte SoulVoice => JobGauge.SoulVoice; + static float SongTime => JobGauge.SongTimer / 1000f; protected static bool SongEndAfter(float time) => EndAfter(SongTime, time); - protected static bool SongEndAfterGCD(uint gctCount = 0, int abilityCount = 0) - => EndAfterGCD(SongTime, gctCount, abilityCount); + protected static bool SongEndAfterGCD(uint gctCount = 0, float offset = 0) + => EndAfterGCD(SongTime, gctCount, offset); + #endregion - private static float SongTime => JobGauge.SongTimer / 1000f; - - public sealed override ClassJobID[] JobIDs => new[] { ClassJobID.Bard, ClassJobID.Archer }; - - public static IBaseAction HeavyShoot { get; } = new BaseAction(ActionID.HeavyShoot) - { - StatusProvide = new[] { StatusID.StraightShotReady } + #region Attack Single + public static IBaseAction HeavyShoot { get; } = new BaseAction(ActionID.HeavyShoot) + { + StatusProvide = new[] { StatusID.StraightShotReady } }; - public static IBaseAction StraitShoot { get; } = new BaseAction(ActionID.StraitShoot) - { - StatusNeed = new[] { StatusID.StraightShotReady } + public static IBaseAction StraitShoot { get; } = new BaseAction(ActionID.StraitShoot) + { + StatusNeed = new[] { StatusID.StraightShotReady } }; public static IBaseAction VenomousBite { get; } = new BaseAction(ActionID.VenomousBite, ActionOption.Dot) @@ -49,37 +51,19 @@ protected static bool SongEndAfterGCD(uint gctCount = 0, int abilityCount = 0) ActionCheck = b => b.HasStatus(true, VenomousBite.TargetStatus) & b.HasStatus(true, WindBite.TargetStatus), }; - public static IBaseAction WanderersMinuet { get; } = new BaseAction(ActionID.WanderersMinuet); - - public static IBaseAction MagesBallad { get; } = new BaseAction(ActionID.MagesBallad); - - public static IBaseAction ArmysPaeon { get; } = new BaseAction(ActionID.ArmysPaeon); - - public static IBaseAction BattleVoice { get; } = new BaseAction(ActionID.BattleVoice, ActionOption.Buff); - - public static IBaseAction RagingStrikes { get; } = new BaseAction(ActionID.RagingStrikes, ActionOption.Buff); - - public static IBaseAction RadiantFinale { get; } = new BaseAction(ActionID.RadiantFinale, ActionOption.Buff) - { - ActionCheck = b => JobGauge.Coda.Any(s => s != Song.NONE), - }; - - public static IBaseAction Barrage { get; } = new BaseAction(ActionID.Barrage); - public static IBaseAction EmpyrealArrow { get; } = new BaseAction(ActionID.EmpyrealArrow); public static IBaseAction PitchPerfect { get; } = new BaseAction(ActionID.PitchPerfect) { - ActionCheck = b => JobGauge.Song == Song.WANDERER, + ActionCheck = b => Song == Song.WANDERER && Repertoire > 0, }; public static IBaseAction Bloodletter { get; } = new BaseAction(ActionID.Bloodletter); - public static IBaseAction RainOfDeath { get; } = new BaseAction(ActionID.RainOfDeath) - { - AOECount = 2, - }; + public static IBaseAction Sidewinder { get; } = new BaseAction(ActionID.Sidewinder); + #endregion + #region Attack Area public static IBaseAction QuickNock { get; } = new BaseAction(ActionID.QuickNock) { StatusProvide = new[] { StatusID.ShadowBiteReady } @@ -90,15 +74,9 @@ protected static bool SongEndAfterGCD(uint gctCount = 0, int abilityCount = 0) StatusNeed = new[] { StatusID.ShadowBiteReady } }; - public static IBaseAction WardensPaean { get; } = new BaseAction(ActionID.WardensPaean, ActionOption.Heal); - - public static IBaseAction NaturesMinne { get; } = new BaseAction(ActionID.NaturesMinne, ActionOption.Heal); - - public static IBaseAction Sidewinder { get; } = new BaseAction(ActionID.Sidewinder); - public static IBaseAction ApexArrow { get; } = new BaseAction(ActionID.ApexArrow) { - ActionCheck = b => JobGauge.SoulVoice >= 20 && !Player.HasStatus(true, StatusID.BlastArrowReady), + ActionCheck = b => SoulVoice >= 20 && !Player.HasStatus(true, StatusID.BlastArrowReady), }; public static IBaseAction BlastArrow { get; } = new BaseAction(ActionID.BlastArrow) @@ -106,6 +84,36 @@ protected static bool SongEndAfterGCD(uint gctCount = 0, int abilityCount = 0) ActionCheck = b => Player.HasStatus(true, StatusID.BlastArrowReady), }; + public static IBaseAction RainOfDeath { get; } = new BaseAction(ActionID.RainOfDeath) + { + AOECount = 2, + }; + #endregion + + #region Support + public static IBaseAction BattleVoice { get; } = new BaseAction(ActionID.BattleVoice, ActionOption.Buff); + + public static IBaseAction RadiantFinale { get; } = new BaseAction(ActionID.RadiantFinale, ActionOption.Buff) + { + ActionCheck = b => JobGauge.Coda.Any(s => s != Song.NONE), + }; + + public static IBaseAction Barrage { get; } = new BaseAction(ActionID.Barrage); + + public static IBaseAction RagingStrikes { get; } = new BaseAction(ActionID.RagingStrikes); + + public static IBaseAction WanderersMinuet { get; } = new BaseAction(ActionID.WanderersMinuet); + + public static IBaseAction MagesBallad { get; } = new BaseAction(ActionID.MagesBallad); + + public static IBaseAction ArmysPaeon { get; } = new BaseAction(ActionID.ArmysPaeon); + #endregion + + #region Heal Defense + public static IBaseAction WardensPaean { get; } = new BaseAction(ActionID.WardensPaean, ActionOption.Heal); + + public static IBaseAction NaturesMinne { get; } = new BaseAction(ActionID.NaturesMinne, ActionOption.Heal); + public static IBaseAction Troubadour { get; } = new BaseAction(ActionID.Troubadour, ActionOption.Defense) { ActionCheck = b => !Player.HasStatus(false, StatusID.Troubadour, @@ -113,6 +121,7 @@ protected static bool SongEndAfterGCD(uint gctCount = 0, int abilityCount = 0) StatusID.Tactician2, StatusID.ShieldSamba), }; + #endregion protected override bool EmergencyAbility(IAction nextGCD, out IAction act) { diff --git a/RotationSolver.Basic/Rotations/Basic/DNC_Base.cs b/RotationSolver.Basic/Rotations/Basic/DNC_Base.cs index 2780850d0..ed24101b8 100644 --- a/RotationSolver.Basic/Rotations/Basic/DNC_Base.cs +++ b/RotationSolver.Basic/Rotations/Basic/DNC_Base.cs @@ -1,9 +1,11 @@ namespace RotationSolver.Basic.Rotations.Basic; public abstract class DNC_Base : CustomRotation { - private static DNCGauge JobGauge => Service.JobGauges.Get(); - public override MedicineType MedicineType => MedicineType.Dexterity; + public sealed override ClassJobID[] JobIDs => new ClassJobID[] { ClassJobID.Dancer }; + + #region Job Gauge + static DNCGauge JobGauge => Service.JobGauges.Get(); protected static bool IsDancing => JobGauge.IsDancing; @@ -12,24 +14,36 @@ public abstract class DNC_Base : CustomRotation protected static byte Feathers => JobGauge.Feathers; protected static byte CompletedSteps => JobGauge.CompletedSteps; + #endregion - public sealed override ClassJobID[] JobIDs => new ClassJobID[] { ClassJobID.Dancer }; - + #region Attack Single + /// + /// 1 + /// public static IBaseAction Cascade { get; } = new BaseAction(ActionID.Cascade) { StatusProvide = new[] { StatusID.SilkenSymmetry } }; + /// + /// 2 + /// public static IBaseAction Fountain { get; } = new BaseAction(ActionID.Fountain) { StatusProvide = new[] { StatusID.SilkenFlow } }; + /// + /// 3 + /// public static IBaseAction ReverseCascade { get; } = new BaseAction(ActionID.ReverseCascade) { StatusNeed = new[] { StatusID.SilkenSymmetry, StatusID.SilkenSymmetry2 }, }; + /// + /// 4 + /// public static IBaseAction FountainFall { get; } = new BaseAction(ActionID.FountainFall) { StatusNeed = new[] { StatusID.SilkenFlow, StatusID.SilkenFlow2 } @@ -37,25 +51,39 @@ public abstract class DNC_Base : CustomRotation public static IBaseAction FanDance { get; } = new BaseAction(ActionID.FanDance) { - ActionCheck = b => JobGauge.Feathers > 0, + ActionCheck = b => Feathers > 0, StatusProvide = new[] { StatusID.ThreefoldFanDance }, }; + #endregion + #region Attack Area + /// + /// 1 + /// public static IBaseAction Windmill { get; } = new BaseAction(ActionID.Windmill) { StatusProvide = Cascade.StatusProvide, }; + /// + /// 2 + /// public static IBaseAction BladeShower { get; } = new BaseAction(ActionID.BladeShower) { StatusProvide = Fountain.StatusProvide, }; + /// + /// 3 + /// public static IBaseAction RisingWindmill { get; } = new BaseAction(ActionID.RisingWindmill) { StatusNeed = ReverseCascade.StatusNeed, }; + /// + /// 4 + /// public static IBaseAction BloodShower { get; } = new BaseAction(ActionID.BloodShower) { AOECount = 2, @@ -89,28 +117,59 @@ public abstract class DNC_Base : CustomRotation StatusNeed = new[] { StatusID.FlourishingStarfall }, }; - public static IBaseAction EnAvant { get; } = new BaseAction(ActionID.EnAvant, ActionOption.Heal | ActionOption.EndSpecial); - - private static IBaseAction Emboite { get; } = new BaseAction(ActionID.Emboite) + public static IBaseAction Tillana { get; } = new BaseAction(ActionID.Tillana) { - ActionCheck = b => (ActionID)JobGauge.NextStep == ActionID.Emboite, + StatusNeed = new[] { StatusID.FlourishingFinish }, }; + #endregion - private static IBaseAction Entrechat { get; } = new BaseAction(ActionID.Entrechat) + #region Support + /// + /// Moving + /// + public static IBaseAction EnAvant { get; } = new BaseAction(ActionID.EnAvant, ActionOption.Heal | ActionOption.EndSpecial); + + public static IBaseAction ShieldSamba { get; } = new BaseAction(ActionID.ShieldSamba, ActionOption.Defense) { - ActionCheck = b => (ActionID)JobGauge.NextStep == ActionID.Entrechat, + ActionCheck = b => !Player.HasStatus(false, StatusID.Troubadour, + StatusID.Tactician1, + StatusID.Tactician2, + StatusID.ShieldSamba), }; - private static IBaseAction Jete { get; } = new BaseAction(ActionID.Jete) + public static IBaseAction CuringWaltz { get; } = new BaseAction(ActionID.CuringWaltz, ActionOption.Heal); + + public static IBaseAction Improvisation { get; } = new BaseAction(ActionID.Improvisation, ActionOption.Heal); + + public static IBaseAction ClosedPosition { get; } = new BaseAction(ActionID.ClosedPosition, ActionOption.Buff) { - ActionCheck = b => (ActionID)JobGauge.NextStep == ActionID.Jete, + ChoiceTarget = (Targets, mustUse) => + { + Targets = Targets.Where(b => b.ObjectId != Player.ObjectId && b.CurrentHp != 0 && + //Remove Weak + !b.HasStatus(false, StatusID.Weakness, StatusID.BrinkOfDeath) + //Remove other partner. + && (!b.HasStatus(false, StatusID.ClosedPosition2) || b.HasStatus(true, StatusID.ClosedPosition2))); + + return Targets.GetJobCategory(JobRole.Melee, JobRole.RangedMagical, JobRole.RangedPhysical).FirstOrDefault(); + }, }; - private static IBaseAction Pirouette { get; } = new BaseAction(ActionID.Pirouette) + public static IBaseAction Devilment { get; } = new BaseAction(ActionID.Devilment); + + public static IBaseAction Flourish { get; } = new BaseAction(ActionID.Flourish) { - ActionCheck = b => (ActionID)JobGauge.NextStep == ActionID.Pirouette, + StatusNeed = new[] { StatusID.StandardFinish }, + StatusProvide = new[] + { + StatusID.ThreefoldFanDance, + StatusID.FourfoldFanDance, + }, + ActionCheck = b => InCombat, }; + #endregion + #region Step public static IBaseAction StandardStep { get; } = new BaseAction(ActionID.StandardStep) { StatusProvide = new[] @@ -132,58 +191,33 @@ public abstract class DNC_Base : CustomRotation protected static IBaseAction StandardFinish { get; } = new BaseAction(ActionID.StandardFinish) { StatusNeed = new[] { StatusID.StandardStep }, - ActionCheck = b => IsDancing && JobGauge.CompletedSteps == 2, + ActionCheck = b => IsDancing && CompletedSteps == 2, }; protected static IBaseAction TechnicalFinish { get; } = new BaseAction(ActionID.TechnicalFinish) { StatusNeed = new[] { StatusID.TechnicalStep }, - ActionCheck = b => IsDancing && JobGauge.CompletedSteps == 4, + ActionCheck = b => IsDancing && CompletedSteps == 4, }; - public static IBaseAction ShieldSamba { get; } = new BaseAction(ActionID.ShieldSamba, ActionOption.Defense) + private static IBaseAction Emboite { get; } = new BaseAction(ActionID.Emboite) { - ActionCheck = b => !Player.HasStatus(false, StatusID.Troubadour, - StatusID.Tactician1, - StatusID.Tactician2, - StatusID.ShieldSamba), + ActionCheck = b => (ActionID)JobGauge.NextStep == ActionID.Emboite, }; - public static IBaseAction CuringWaltz { get; } = new BaseAction(ActionID.CuringWaltz, ActionOption.Heal); - - public static IBaseAction ClosedPosition { get; } = new BaseAction(ActionID.ClosedPosition, ActionOption.Buff) + private static IBaseAction Entrechat { get; } = new BaseAction(ActionID.Entrechat) { - ChoiceTarget = (Targets, mustUse) => - { - Targets = Targets.Where(b => b.ObjectId != Player.ObjectId && b.CurrentHp != 0 && - //Remove Weak - !b.HasStatus(false, StatusID.Weakness, StatusID.BrinkOfDeath) - //Remove other partner. - && !b.HasStatus(false, StatusID.ClosedPosition2) | b.HasStatus(true, StatusID.ClosedPosition2) - ); - - return Targets.GetJobCategory(JobRole.Melee, JobRole.RangedMagical, JobRole.RangedPhysical).FirstOrDefault(); - }, + ActionCheck = b => (ActionID)JobGauge.NextStep == ActionID.Entrechat, }; - public static IBaseAction Devilment { get; } = new BaseAction(ActionID.Devilment, ActionOption.Buff); - - public static IBaseAction Flourish { get; } = new BaseAction(ActionID.Flourish, ActionOption.Buff) + private static IBaseAction Jete { get; } = new BaseAction(ActionID.Jete) { - StatusNeed = new[] { StatusID.StandardFinish }, - StatusProvide = new[] - { - StatusID.ThreefoldFanDance, - StatusID.FourfoldFanDance, - }, - ActionCheck = b => InCombat, + ActionCheck = b => (ActionID)JobGauge.NextStep == ActionID.Jete, }; - public static IBaseAction Improvisation { get; } = new BaseAction(ActionID.Improvisation, ActionOption.Heal); - - public static IBaseAction Tillana { get; } = new BaseAction(ActionID.Tillana) + private static IBaseAction Pirouette { get; } = new BaseAction(ActionID.Pirouette) { - StatusNeed = new[] { StatusID.FlourishingFinish }, + ActionCheck = b => (ActionID)JobGauge.NextStep == ActionID.Pirouette, }; protected static bool ExecuteStepGCD(out IAction act) @@ -199,6 +233,7 @@ protected static bool ExecuteStepGCD(out IAction act) if (Pirouette.CanUse(out act)) return true; return false; } + #endregion [RotationDesc(ActionID.EnAvant)] protected sealed override bool MoveForwardAbility(out IAction act, CanUseOption option = CanUseOption.None) diff --git a/RotationSolver.Basic/Rotations/Basic/DRG_Base.cs b/RotationSolver.Basic/Rotations/Basic/DRG_Base.cs index 7155af7a7..b9f6fb98c 100644 --- a/RotationSolver.Basic/Rotations/Basic/DRG_Base.cs +++ b/RotationSolver.Basic/Rotations/Basic/DRG_Base.cs @@ -2,38 +2,54 @@ namespace RotationSolver.Basic.Rotations.Basic; public abstract class DRG_Base : CustomRotation { - private static DRGGauge JobGauge => Service.JobGauges.Get(); - - private static float LOTDTime => JobGauge.LOTDTimer / 1000f; + public override MedicineType MedicineType => MedicineType.Strength; + public sealed override ClassJobID[] JobIDs => new ClassJobID[] { ClassJobID.Dragoon, ClassJobID.Lancer }; - protected static bool SongEndAfter(float time) => EndAfter(LOTDTime, time); - protected static bool SongEndAfterGCD(uint gctCount = 0, float offset = 0) - => EndAfterGCD(LOTDTime, gctCount, offset); + #region Job Gauge + static DRGGauge JobGauge => Service.JobGauges.Get(); protected static byte EyeCount => JobGauge.EyeCount; /// - /// FocusCount + /// Firstminds Count /// protected static byte FocusCount => JobGauge.FirstmindsFocusCount; - public override MedicineType MedicineType => MedicineType.Strength; + static float LOTDTime => JobGauge.LOTDTimer / 1000f; - public sealed override ClassJobID[] JobIDs => new ClassJobID[] { ClassJobID.Dragoon, ClassJobID.Lancer }; + protected static bool SongEndAfter(float time) => EndAfter(LOTDTime, time); + + protected static bool SongEndAfterGCD(uint gctCount = 0, float offset = 0) + => EndAfterGCD(LOTDTime, gctCount, offset); + #endregion + #region Attack Single + /// + /// 1 + /// public static IBaseAction TrueThrust { get; } = new BaseAction(ActionID.TrueThrust); + /// + /// 2 + /// public static IBaseAction VorpalThrust { get; } = new BaseAction(ActionID.VorpalThrust) { ComboIds = new[] { ActionID.RaidenThrust } }; - public static IBaseAction HeavensThrust { get; } = new BaseAction(ActionID.HeavensThrust); - + /// + /// 3 + /// public static IBaseAction FullThrust { get; } = new BaseAction(ActionID.FullThrust); + /// + /// 3 + /// + [Obsolete("Please use Full Thrust instead.")] + public static IBaseAction HeavensThrust { get; } = new BaseAction(ActionID.HeavensThrust); + public static IBaseAction Disembowel { get; } = new BaseAction(ActionID.Disembowel) { ComboIds = new[] { ActionID.RaidenThrust } @@ -57,21 +73,8 @@ protected static bool SongEndAfterGCD(uint gctCount = 0, float offset = 0) ActionCheck = b => !IsLastAction(IActionHelper.MovingActions), }; - public static IBaseAction DoomSpike { get; } = new BaseAction(ActionID.DoomSpike); - - public static IBaseAction SonicThrust { get; } = new BaseAction(ActionID.SonicThrust) - { - ComboIds = new[] { ActionID.DraconianFury } - }; - - public static IBaseAction CoerthanTorment { get; } = new BaseAction(ActionID.CoerthanTorment); - public static IBaseAction SpineShatterDive { get; } = new BaseAction(ActionID.SpineShatterDive); - public static IBaseAction DragonFireDive { get; } = new BaseAction(ActionID.DragonFireDive); - - public static IBaseAction ElusiveJump { get; } = new BaseAction(ActionID.ElusiveJump); - public static IBaseAction Jump { get; } = new BaseAction(ActionID.Jump) { StatusProvide = new StatusID[] { StatusID.DiveReady }, @@ -86,6 +89,28 @@ protected static bool SongEndAfterGCD(uint gctCount = 0, float offset = 0) { StatusNeed = Jump.StatusProvide, }; + #endregion + + #region Attack Area + /// + /// 1 + /// + public static IBaseAction DoomSpike { get; } = new BaseAction(ActionID.DoomSpike); + + /// + /// 2 + /// + public static IBaseAction SonicThrust { get; } = new BaseAction(ActionID.SonicThrust) + { + ComboIds = new[] { ActionID.DraconianFury } + }; + + /// + /// 3 + /// + public static IBaseAction CoerthanTorment { get; } = new BaseAction(ActionID.CoerthanTorment); + + public static IBaseAction DragonFireDive { get; } = new BaseAction(ActionID.DragonFireDive); public static IBaseAction Geirskogul { get; } = new BaseAction(ActionID.Geirskogul); @@ -101,17 +126,18 @@ protected static bool SongEndAfterGCD(uint gctCount = 0, float offset = 0) public static IBaseAction WyrmwindThrust { get; } = new BaseAction(ActionID.WyrmwindThrust) { - ActionCheck = b => JobGauge.FirstmindsFocusCount == 2, + ActionCheck = b => FocusCount == 2, }; + #endregion - public static IBaseAction LifeSurge { get; } = new BaseAction(ActionID.LifeSurge, ActionOption.Buff) + #region Support + public static IBaseAction LifeSurge { get; } = new BaseAction(ActionID.LifeSurge) { StatusProvide = new[] { StatusID.LifeSurge }, - ActionCheck = b => !IsLastAbility(true, LifeSurge), }; - public static IBaseAction LanceCharge { get; } = new BaseAction(ActionID.LanceCharge, ActionOption.Buff); + public static IBaseAction LanceCharge { get; } = new BaseAction(ActionID.LanceCharge); public static IBaseAction DragonSight { get; } = new BaseAction(ActionID.DragonSight, ActionOption.Buff) { @@ -127,6 +153,9 @@ protected static bool SongEndAfterGCD(uint gctCount = 0, float offset = 0) }; public static IBaseAction BattleLitany { get; } = new BaseAction(ActionID.BattleLitany, ActionOption.Buff); + #endregion + + public static IBaseAction ElusiveJump { get; } = new BaseAction(ActionID.ElusiveJump); [RotationDesc(ActionID.Feint)] protected sealed override bool DefenseAreaAbility(out IAction act) @@ -134,4 +163,11 @@ protected sealed override bool DefenseAreaAbility(out IAction act) if (Feint.CanUse(out act)) return true; return false; } + + [RotationDesc(ActionID.ElusiveJump)] + protected override bool MoveBackAbility(out IAction act) + { + if(ElusiveJump.CanUse(out act, CanUseOption.IgnoreClippingCheck)) return true; + return base.MoveBackAbility(out act); + } } diff --git a/RotationSolver.Basic/Rotations/Basic/DRK_Base.cs b/RotationSolver.Basic/Rotations/Basic/DRK_Base.cs index 82c74e70c..0417a3a0d 100644 --- a/RotationSolver.Basic/Rotations/Basic/DRK_Base.cs +++ b/RotationSolver.Basic/Rotations/Basic/DRK_Base.cs @@ -1,118 +1,151 @@ namespace RotationSolver.Basic.Rotations.Basic; public abstract class DRK_Base : CustomRotation { - private static DRKGauge JobGauge => Service.JobGauges.Get(); public override MedicineType MedicineType => MedicineType.Strength; - private static float DarkSideTimeRemaining => JobGauge.DarksideTimeRemaining / 1000f; + public sealed override ClassJobID[] JobIDs => new ClassJobID[] { ClassJobID.DarkKnight }; + + #region Job Gauge + private static DRKGauge JobGauge => Service.JobGauges.Get(); protected static byte Blood => JobGauge.Blood; protected static bool HasDarkArts => JobGauge.HasDarkArts; + private static float DarkSideTimeRemaining => JobGauge.DarksideTimeRemaining / 1000f; + protected static bool DarkSideEndAfter(float time) { return EndAfter(DarkSideTimeRemaining, time); } - protected static bool DarkSideEndAfterGCD(uint gctCount = 0, int abilityCount = 0) + protected static bool DarkSideEndAfterGCD(uint gctCount = 0, float offset = 0) { - return EndAfterGCD(DarkSideTimeRemaining, gctCount, abilityCount); + return EndAfterGCD(DarkSideTimeRemaining, gctCount, offset); } + #endregion - public sealed override ClassJobID[] JobIDs => new ClassJobID[] { ClassJobID.DarkKnight }; - - private sealed protected override IBaseAction TankStance => Grit; - + #region Attack Single + /// + /// 1 + /// public static IBaseAction HardSlash { get; } = new BaseAction(ActionID.HardSlash); + /// + /// 2 + /// public static IBaseAction SyphonStrike { get; } = new BaseAction(ActionID.SyphonStrike); - public static IBaseAction Unleash { get; } = new BaseAction(ActionID.Unleash); - - public static IBaseAction Grit { get; } = new BaseAction(ActionID.Grit, ActionOption.EndSpecial); - - public static IBaseAction Unmend { get; } = new BaseAction(ActionID.Unmend) - { - FilterForHostiles = TargetFilter.TankRangeTarget, - ActionCheck = b => !IsLastAction(IActionHelper.MovingActions), - }; - + /// + /// 3 + /// public static IBaseAction Souleater { get; } = new BaseAction(ActionID.Souleater); - public static IBaseAction FloodOfDarkness { get; } = new BaseAction(ActionID.FloodOfDarkness); - public static IBaseAction EdgeOfDarkness { get; } = new BaseAction(ActionID.EdgeOfDarkness); - public static IBaseAction BloodWeapon { get; } = new BaseAction(ActionID.BloodWeapon); + public static IBaseAction CarveAndSpit { get; } = new BaseAction(ActionID.CarveAndSpit); - public static IBaseAction ShadowWall { get; } = new BaseAction(ActionID.ShadowWall, ActionOption.Defense) + public static IBaseAction BloodSpiller { get; } = new BaseAction(ActionID.BloodSpiller) { - StatusProvide = Rampart.StatusProvide, - ActionCheck = BaseAction.TankDefenseSelf, + ActionCheck = b => JobGauge.Blood >= 50 || Player.HasStatus(true, StatusID.Delirium), }; - public static IBaseAction DarkMind { get; } = new BaseAction(ActionID.DarkMind, ActionOption.Defense) + public static IBaseAction Unmend { get; } = new BaseAction(ActionID.Unmend) { - ActionCheck = BaseAction.TankDefenseSelf, + FilterForHostiles = TargetFilter.TankRangeTarget, + ActionCheck = b => !IsLastAction(IActionHelper.MovingActions), }; - public static IBaseAction LivingDead { get; } = new BaseAction(ActionID.LivingDead, ActionOption.Defense); - - public static IBaseAction SaltedEarth { get; } = new BaseAction(ActionID.SaltedEarth); - public static IBaseAction Plunge { get; } = new BaseAction(ActionID.Plunge, ActionOption.EndSpecial) { ChoiceTarget = TargetFilter.FindTargetForMoving }; - public static IBaseAction AbyssalDrain { get; } = new BaseAction(ActionID.AbyssalDrain); - - public static IBaseAction CarveandSpit { get; } = new BaseAction(ActionID.CarveandSpit); - - public static IBaseAction BloodSpiller { get; } = new BaseAction(ActionID.BloodSpiller) + public static IBaseAction LivingShadow { get; } = new BaseAction(ActionID.LivingShadow) { - ActionCheck = b => JobGauge.Blood >= 50 || Player.HasStatus(true, StatusID.Delirium), + ActionCheck = b => JobGauge.Blood >= 50, }; + #endregion + + #region Attack Area + /// + /// 1 + /// + public static IBaseAction Unleash { get; } = new BaseAction(ActionID.Unleash); + + /// + /// 2 + /// + public static IBaseAction StalwartSoul { get; } = new BaseAction(ActionID.StalwartSoul); public static IBaseAction Quietus { get; } = new BaseAction(ActionID.Quietus) { ActionCheck = BloodSpiller.ActionCheck, }; - public static IBaseAction Delirium { get; } = new BaseAction(ActionID.Delirium); + public static IBaseAction FloodOfDarkness { get; } = new BaseAction(ActionID.FloodOfDarkness); - public static IBaseAction TheBlackestNight { get; } = new BaseAction(ActionID.TheBlackestNight, ActionOption.Defense) + public static IBaseAction SaltedEarth { get; } = new BaseAction(ActionID.SaltedEarth); + + public static IBaseAction AbyssalDrain { get; } = new BaseAction(ActionID.AbyssalDrain); + + public static IBaseAction SaltandDarkness { get; } = new BaseAction(ActionID.SaltandDarkness) { - ChoiceTarget = TargetFilter.FindAttackedTarget, + StatusNeed = new[] { StatusID.SaltedEarth }, }; - public static IBaseAction StalwartSoul { get; } = new BaseAction(ActionID.StalwartSoul); + public static IBaseAction ShadowBringer { get; } = new BaseAction(ActionID.ShadowBringer) + { + ActionCheck = b => DarkSideTimeRemaining > 0, + }; + #endregion - public static IBaseAction DarkMissionary { get; } = new BaseAction(ActionID.DarkMissionary, ActionOption.Defense); + #region Heal Single + private sealed protected override IBaseAction TankStance => Grit; + public static IBaseAction Grit { get; } = new BaseAction(ActionID.Grit, ActionOption.EndSpecial); + #endregion - public static IBaseAction LivingShadow { get; } = new BaseAction(ActionID.LivingShadow) + #region Support + public static IBaseAction BloodWeapon { get; } = new BaseAction(ActionID.BloodWeapon); + + #endregion + + #region Defense Single + public static IBaseAction ShadowWall { get; } = new BaseAction(ActionID.ShadowWall, ActionOption.Defense) { - ActionCheck = b => JobGauge.Blood >= 50, + StatusProvide = Rampart.StatusProvide, + ActionCheck = BaseAction.TankDefenseSelf, }; - public static IBaseAction Oblation { get; } = new BaseAction(ActionID.Oblation, ActionOption.Defense) + public static IBaseAction DarkMind { get; } = new BaseAction(ActionID.DarkMind, ActionOption.Defense) { - ActionCheck = b => !b.HasStatus(true, StatusID.Oblation), - ChoiceTarget = TargetFilter.FindAttackedTarget, + ActionCheck = BaseAction.TankDefenseSelf, }; - public static IBaseAction ShadowBringer { get; } = new BaseAction(ActionID.ShadowBringer) + public static IBaseAction TheBlackestNight { get; } = new BaseAction(ActionID.TheBlackestNight, ActionOption.Defense) { - ActionCheck = b => JobGauge.DarksideTimeRemaining > 0, + ChoiceTarget = TargetFilter.FindAttackedTarget, }; - public static IBaseAction SaltandDarkness { get; } = new BaseAction(ActionID.SaltandDarkness) + public static IBaseAction Oblation { get; } = new BaseAction(ActionID.Oblation, ActionOption.Defense) { - StatusNeed = new[] { StatusID.SaltedEarth }, + TargetStatus = new StatusID[] { StatusID.Oblation }, + ChoiceTarget = TargetFilter.FindAttackedTarget, }; + public static IBaseAction LivingDead { get; } = new BaseAction(ActionID.LivingDead, ActionOption.Defense); + #endregion + + #region Defense Area + public static IBaseAction DarkMissionary { get; } = new BaseAction(ActionID.DarkMissionary, ActionOption.Defense); + + #endregion + + #region Support + public static IBaseAction Delirium { get; } = new BaseAction(ActionID.Delirium); + #endregion + protected override bool EmergencyAbility(IAction nextGCD, out IAction act) { if (LivingDead.CanUse(out act) && BaseAction.TankBreakOtherCheck(JobIDs[0])) return true; diff --git a/RotationSolver.Basic/Rotations/Basic/GNB_Base.cs b/RotationSolver.Basic/Rotations/Basic/GNB_Base.cs index 6938ead94..36758a77f 100644 --- a/RotationSolver.Basic/Rotations/Basic/GNB_Base.cs +++ b/RotationSolver.Basic/Rotations/Basic/GNB_Base.cs @@ -2,140 +2,161 @@ namespace RotationSolver.Basic.Rotations.Basic; public abstract class GNB_Base : CustomRotation { - private static GNBGauge JobGauge => Service.JobGauges.Get(); - - public override MedicineType MedicineType => MedicineType.Strength; - - protected static byte Ammo => JobGauge.Ammo; - - protected static byte AmmoComboStep => JobGauge.AmmoComboStep; - public sealed override ClassJobID[] JobIDs => new ClassJobID[] { ClassJobID.Gunbreaker }; - private sealed protected override IBaseAction TankStance => RoyalGuard; - + public override MedicineType MedicineType => MedicineType.Strength; protected override bool CanHealSingleSpell => false; protected override bool CanHealAreaSpell => false; - protected static byte MaxAmmo => Level >= 88 ? (byte)3 : (byte)2; + #region Job Gauge + static GNBGauge JobGauge => Service.JobGauges.Get(); - public static IBaseAction RoyalGuard { get; } = new BaseAction(ActionID.RoyalGuard, ActionOption.EndSpecial); + protected static byte Ammo => JobGauge.Ammo; + protected static byte AmmoComboStep => JobGauge.AmmoComboStep; + protected static byte MaxAmmo => Level >= 88 ? (byte)3 : (byte)2; + #endregion + #region Attack Single + /// + /// 1 + /// public static IBaseAction KeenEdge { get; } = new BaseAction(ActionID.KeenEdge); - public static IBaseAction NoMercy { get; } = new BaseAction(ActionID.NoMercy); - + /// + /// 2 + /// public static IBaseAction BrutalShell { get; } = new BaseAction(ActionID.BrutalShell); - public static IBaseAction Camouflage { get; } = new BaseAction(ActionID.Camouflage, ActionOption.Defense) + /// + /// 3 + /// + public static IBaseAction SolidBarrel { get; } = new BaseAction(ActionID.SolidBarrel); + + public static IBaseAction DangerZone { get; } = new BaseAction(ActionID.DangerZone); + public static IBaseAction SonicBreak { get; } = new BaseAction(ActionID.SonicBreak); + + public static IBaseAction BurstStrike { get; } = new BaseAction(ActionID.BurstStrike) { - ActionCheck = BaseAction.TankDefenseSelf, + ActionCheck = b => Ammo > 0, }; - public static IBaseAction DemonSlice { get; } = new BaseAction(ActionID.DemonSlice) + public static IBaseAction GnashingFang { get; } = new BaseAction(ActionID.GnashingFang) { - AOECount = 2, + ActionCheck = b => AmmoComboStep == 0 && Ammo > 0, }; - public static IBaseAction LightningShot { get; } = new BaseAction(ActionID.LightningShot) + public static IBaseAction SavageClaw { get; } = new BaseAction(ActionID.SavageClaw) { - FilterForHostiles = TargetFilter.TankRangeTarget, - ActionCheck = b => !IsLastAction(IActionHelper.MovingActions), + ActionCheck = b => Service.GetAdjustedActionId(ActionID.GnashingFang) == ActionID.SavageClaw, }; - public static IBaseAction DangerZone { get; } = new BaseAction(ActionID.DangerZone); - - public static IBaseAction SolidBarrel { get; } = new BaseAction(ActionID.SolidBarrel); + public static IBaseAction WickedTalon { get; } = new BaseAction(ActionID.WickedTalon) + { + ActionCheck = b => Service.GetAdjustedActionId(ActionID.GnashingFang) == ActionID.WickedTalon, + }; - public static IBaseAction BurstStrike { get; } = new BaseAction(ActionID.BurstStrike) + public static IBaseAction JugularRip { get; } = new BaseAction(ActionID.JugularRip) { - ActionCheck = b => JobGauge.Ammo > 0, + ActionCheck = b => Service.GetAdjustedActionId(ActionID.Continuation) == ActionID.JugularRip, }; - public static IBaseAction Nebula { get; } = new BaseAction(ActionID.Nebula, ActionOption.Defense) + public static IBaseAction AbdomenTear { get; } = new BaseAction(ActionID.AbdomenTear) { - StatusProvide = Rampart.StatusProvide, - ActionCheck = BaseAction.TankDefenseSelf, + ActionCheck = b => Service.GetAdjustedActionId(ActionID.Continuation) == ActionID.AbdomenTear, }; - public static IBaseAction DemonSlaughter { get; } = new BaseAction(ActionID.DemonSlaughter) + public static IBaseAction EyeGouge { get; } = new BaseAction(ActionID.EyeGouge) { - AOECount = 2, + ActionCheck = b => Service.GetAdjustedActionId(ActionID.Continuation) == ActionID.EyeGouge, }; - public static IBaseAction Aurora { get; } = new BaseAction(ActionID.Aurora, ActionOption.Heal) + public static IBaseAction Hypervelocity { get; } = new BaseAction(ActionID.Hypervelocity) { - ActionCheck = b => !b.HasStatus(true, StatusID.Aurora), + ActionCheck = b => Service.GetAdjustedActionId(ActionID.Continuation) == ActionID.Hypervelocity, }; - public static IBaseAction SuperBolide { get; } = new BaseAction(ActionID.SuperBolide, ActionOption.Defense); - - public static IBaseAction SonicBreak { get; } = new BaseAction(ActionID.SonicBreak); + public static IBaseAction LightningShot { get; } = new BaseAction(ActionID.LightningShot) + { + FilterForHostiles = TargetFilter.TankRangeTarget, + ActionCheck = b => !IsLastAction(IActionHelper.MovingActions), + }; public static IBaseAction RoughDivide { get; } = new BaseAction(ActionID.RoughDivide, ActionOption.EndSpecial) { ChoiceTarget = TargetFilter.FindTargetForMoving, }; + #endregion - public static IBaseAction GnashingFang { get; } = new BaseAction(ActionID.GnashingFang) + #region Attack Area + /// + /// 1 + /// + public static IBaseAction DemonSlice { get; } = new BaseAction(ActionID.DemonSlice) { - ActionCheck = b => JobGauge.AmmoComboStep == 0 && JobGauge.Ammo > 0, + AOECount = 2, }; - public static IBaseAction BowShock { get; } = new BaseAction(ActionID.BowShock); - - public static IBaseAction HeartOfLight { get; } = new BaseAction(ActionID.HeartOfLight, ActionOption.Heal); - - public static IBaseAction HeartOfStone { get; } = new BaseAction(ActionID.HeartOfStone, ActionOption.Defense) + /// + /// 2 + /// + public static IBaseAction DemonSlaughter { get; } = new BaseAction(ActionID.DemonSlaughter) { - ChoiceTarget = TargetFilter.FindAttackedTarget, + AOECount = 2, }; public static IBaseAction FatedCircle { get; } = new BaseAction(ActionID.FatedCircle) { - ActionCheck = b => JobGauge.Ammo > 0, - }; - - public static IBaseAction BloodFest { get; } = new BaseAction(ActionID.BloodFest, ActionOption.Buff) - { - ActionCheck = b => MaxAmmo - JobGauge.Ammo > 1, + ActionCheck = b => Ammo > 0, }; - public static IBaseAction DoubleDown { get; } = new BaseAction(ActionID.DoubleDown) { - ActionCheck = b => JobGauge.Ammo > 1, + ActionCheck = b => Ammo > 1, }; + public static IBaseAction BowShock { get; } = new BaseAction(ActionID.BowShock); - public static IBaseAction SavageClaw { get; } = new BaseAction(ActionID.SavageClaw) - { - ActionCheck = b => Service.GetAdjustedActionId(ActionID.GnashingFang) == ActionID.SavageClaw, - }; + #endregion - public static IBaseAction WickedTalon { get; } = new BaseAction(ActionID.WickedTalon) + #region Heal + private sealed protected override IBaseAction TankStance => RoyalGuard; + public static IBaseAction RoyalGuard { get; } = new BaseAction(ActionID.RoyalGuard, ActionOption.EndSpecial); + + public static IBaseAction Aurora { get; } = new BaseAction(ActionID.Aurora, ActionOption.Heal) { - ActionCheck = b => Service.GetAdjustedActionId(ActionID.GnashingFang) == ActionID.WickedTalon, + TargetStatus = new StatusID[] { StatusID.Aurora }, }; - public static IBaseAction JugularRip { get; } = new BaseAction(ActionID.JugularRip) + public static IBaseAction HeartOfLight { get; } = new BaseAction(ActionID.HeartOfLight, ActionOption.Heal); + #endregion + + #region Defense Single + public static IBaseAction Nebula { get; } = new BaseAction(ActionID.Nebula, ActionOption.Defense) { - ActionCheck = b => Service.GetAdjustedActionId(ActionID.Continuation) == ActionID.JugularRip, + StatusProvide = Rampart.StatusProvide, + ActionCheck = BaseAction.TankDefenseSelf, }; - public static IBaseAction AbdomenTear { get; } = new BaseAction(ActionID.AbdomenTear) + public static IBaseAction Camouflage { get; } = new BaseAction(ActionID.Camouflage, ActionOption.Defense) { - ActionCheck = b => Service.GetAdjustedActionId(ActionID.Continuation) == ActionID.AbdomenTear, + ActionCheck = BaseAction.TankDefenseSelf, }; - public static IBaseAction EyeGouge { get; } = new BaseAction(ActionID.EyeGouge) + public static IBaseAction HeartOfStone { get; } = new BaseAction(ActionID.HeartOfStone, ActionOption.Defense) { - ActionCheck = b => Service.GetAdjustedActionId(ActionID.Continuation) == ActionID.EyeGouge, + ChoiceTarget = TargetFilter.FindAttackedTarget, }; - public static IBaseAction Hypervelocity { get; } = new BaseAction(ActionID.Hypervelocity) + public static IBaseAction SuperBolide { get; } = new BaseAction(ActionID.SuperBolide, ActionOption.Defense); + #endregion + + #region Support + public static IBaseAction NoMercy { get; } = new BaseAction(ActionID.NoMercy); + + public static IBaseAction BloodFest { get; } = new BaseAction(ActionID.BloodFest, ActionOption.Buff) { - ActionCheck = b => Service.GetAdjustedActionId(ActionID.Continuation) - == ActionID.Hypervelocity, + ActionCheck = b => MaxAmmo - Ammo > 1, }; + #endregion + protected override bool EmergencyAbility(IAction nextGCD, out IAction act) { if (SuperBolide.CanUse(out act) && BaseAction.TankBreakOtherCheck(JobIDs[0])) return true; diff --git a/RotationSolver.Basic/Service.cs b/RotationSolver.Basic/Service.cs index a145b1647..fa8eff50c 100644 --- a/RotationSolver.Basic/Service.cs +++ b/RotationSolver.Basic/Service.cs @@ -132,7 +132,7 @@ public unsafe static IEnumerable GetAddons() where T : struct public static Condition Conditions { get; private set; } [PluginService] - public static JobGauges JobGauges { get; private set; } + internal static JobGauges JobGauges { get; private set; } [PluginService] public static ObjectTable ObjectTable { get; private set; }