From b7fcff9eb1b46704fe15672a4e3041cc2d4b787b Mon Sep 17 00:00:00 2001 From: AceAkechi123 Date: Sat, 4 Jan 2025 17:02:35 -0800 Subject: [PATCH 01/17] we workin we workin --- BossMod/Autorotation/akechi/AkechiPLD.cs | 1154 ++++++++++++---------- 1 file changed, 614 insertions(+), 540 deletions(-) diff --git a/BossMod/Autorotation/akechi/AkechiPLD.cs b/BossMod/Autorotation/akechi/AkechiPLD.cs index 0b8c6ecc66..8dfb6d0747 100644 --- a/BossMod/Autorotation/akechi/AkechiPLD.cs +++ b/BossMod/Autorotation/akechi/AkechiPLD.cs @@ -1,4 +1,8 @@ using FFXIVClientStructs.FFXIV.Client.Game.Gauge; +using System; +using System.Runtime.InteropServices; +using static BossMod.ActorCastEvent; +using static BossMod.Autorotation.akechi.AkechiGNB; using AID = BossMod.PLD.AID; using SID = BossMod.PLD.SID; @@ -8,145 +12,129 @@ namespace BossMod.Autorotation.akechi; public sealed class AkechiPLD(RotationModuleManager manager, Actor player) : RotationModule(manager, player) { - //Actions tracked for Cooldown Planner execution + #region Enums public enum Track { - AoE, //Tracks both AoE and single-target actions - Burst, //Tracks burst damage actions - Potion, //Tracks potion usage - Atonement, //Tracks Atonement actions - BladeCombo, //Tracks Blade Combo actions - Dash, //Tracks the use of Intervene - Ranged, //Tracks ranged attacks - FightOrFlight, //Tracks Fight or Flight actions - Requiescat, //Tracks Requiescat actions - SpiritsWithin, //Tracks Spirits Within actions - CircleOfScorn, //Tracks Circle of Scorn actions - GoringBlade, //Tracks Goring Blade actions - HolySpirit, //Tracks Holy Spirit actions - HolyCircle, //Tracks Holy Circle actions - BladeOfHonor, //Tracks Blade of Honor actions + AoE, //Tracks both AoE and single-target actions + Cooldowns, //Tracks Cooldowns damage actions + Potion, //Tracks potion usage + Atonement, //Tracks Atonement actions + BladeCombo, //Tracks Blade Combo actions + Holy, //Tracks Holy actions + Dash, //Tracks the use of Intervene + Ranged, //Tracks ranged attacks + FightOrFlight, //Tracks Fight or Flight actions + Requiescat, //Tracks Requiescat actions + SpiritsWithin, //Tracks Spirits Within actions + CircleOfScorn, //Tracks Circle of Scorn actions + GoringBlade, //Tracks Goring Blade actions + BladeOfHonor, //Tracks Blade of Honor actions } - - //Strategy definitions for AoE usage public enum AOEStrategy { - UseST, //Use single-target actions when appropriate - ForceST, //Force the use of single-target actions - UseAoE, //Use AoE actions when beneficial - ForceAoE, //Force the use of AoE actions - Auto, //Automatically decide based on target count; may break combos - AutoFinishCombo, //Automatically decide with a preference to finish combos + AutoFinishCombo, //Automatically decide based on targets; finish combo first + AutoBreakCombo, //Automatically decide based on targets; break combo if needed + ForceST, //Force single-target rotation + ForceAoE //Force AoE rotation } - - //Strategy definitions for burst damage - public enum BurstStrategy + public enum CooldownStrategy { - Automatic, //Automatically execute burst actions when conditions are met - Conserve, //Conserve MP and cooldowns for strategic usage - UnderRaidBuffs, //Execute burst actions when under raid buffs for maximum effect - UnderPotion, //Execute burst actions while under potion effects + Allow, //Allow cooldowns when conditions are met + Hold, //Hold MP and cooldowns for strategic usage } - - //Strategy definitions for potion usage public enum PotionStrategy { Manual, //Use potions manually based on player discretion AlignWithRaidBuffs, //Align potion usage with the timing of raid buffs Immediate //Use potions immediately when available } - - //Strategy definitions for Atonement usage public enum AtonementStrategy { - Automatic, //Automatically use Atonement when needed - ForceAtonement, //Force the use of Atonement regardless of other actions - ForceSupplication, //Force use of Supplication - ForceSepulchre, //Force use of Sepulchre actions - Delay //Delay the use of Atonement for optimal timing + Automatic, //Automatically use Atonement when needed + ForceAtonement, //Force the use of Atonement regardless of other actions + ForceSupplication, //Force use of Supplication + ForceSepulchre, //Force use of Sepulchre actions + Delay //Delay the use of Atonement for optimal timing } - - //Strategy definitions for Blade Combo actions public enum BladeComboStrategy { - Automatic, //Automatically execute Blade Combo when conditions are favorable - ForceConfiteor, //Force the use of Confiteor action - ForceFaith, //Force the use of Blade of Faith - ForceTruth, //Force the use of Blade of Truth - ForceValor, //Force the use of Blade of Valor - Delay //Delay the use of Confiteor and Blade Combo for timing + Automatic, //Automatically execute Blade Combo when conditions are favorable + ForceConfiteor, //Force the use of Confiteor action + ForceFaith, //Force the use of Blade of Faith + ForceTruth, //Force the use of Blade of Truth + ForceValor, //Force the use of Blade of Valor + Delay //Delay the use of Confiteor and Blade Combo for timing + } + public enum HolyStrategy + { + Automatic, //Automatically decide on Holy actions based on conditions + Spirit, //Force the use of Holy Spirit + Circle, //Force the use of Holy Circle + Delay //Delay Holy actions for strategic timing } - - //Strategy definitions for dash actions public enum DashStrategy { - Automatic, //Automatically use Intervene as needed - Force, //Force the use of Intervene regardless of other factors - Conserve1, //Conserve one use of Intervene for later - GapClose, //Use Intervene to close gaps between targets - Delay //Delay the use of Intervene for strategic reasons + Automatic, //Automatically use Intervene as needed + Force, //Force the use of Intervene regardless of other factors + Force1, //Force the use of Intervene; Holds one charge for manual usage + GapClose, //Use Intervene to close gaps between targets + GapClose1, //Use Intervene to close gaps between targets; Hold one charge of Intervene for manual usage + Delay //Delay the use of Intervene for strategic reasons } - - //Strategy definitions for ranged attacks public enum RangedStrategy { - OpenerRanged, //Use Shield Lob as part of the opening sequence - OpenerRangedCast, //Use Holy Spirit as part of the opening sequence - Opener, //Use Shield Lob at the start of combat - OpenerCast, //Use Holy Spirit at the start of combat - Force, //Force Shield Lob when possible - ForceCast, //Force Holy Spirit when possible - Ranged, //Use Shield Lob for ranged attacks - RangedCast, //Use Holy Spirit for ranged attacks - Forbid //Prohibit the use of ranged attacks entirely + OpenerRangedCast, //Use Holy Spirit at the start of combat only if outside melee range + OpenerCast, //Use Holy Spirit at the start of combat regardless of range + ForceCast, //Force Holy Spirit when possible + RangedCast, //Use Holy Spirit for ranged attacks + OpenerRanged, //Use Shield Lob at the start of combat only if outside melee range + Opener, //Use Shield Lob at the start of combat regardless of range + Force, //Force Shield Lob when possible + Ranged, //Use Shield Lob for ranged attacks + Forbid //Prohibit the use of all ranged attacks entirely (unless under Divine Might) } - - //Strategy definitions for offensive actions - public enum OffensiveStrategy + public enum GCDStrategy { - Automatic, //Automatically decide on offensive actions based on conditions - Force, //Force the use of offensive actions regardless of context - Delay //Delay offensive actions for strategic timing + Automatic, //Automatically decide on GCD actions based on conditions + Force, //Force GCD actions regardless of any conditions + Delay //Delay GCD actions for strategic reasons } + public enum OGCDStrategy + { + Automatic, //Automatically decide when to use off-global offensive abilities + Force, //Force the use of off-global offensive abilities, regardless of weaving conditions + AnyWeave, //Force the use of off-global offensive abilities in any next possible weave slot + EarlyWeave, //Force the use of off-global offensive abilities in very next FIRST weave slot only + LateWeave, //Force the use of off-global offensive abilities in very next LAST weave slot only + Delay //Delay the use of offensive abilities for strategic reasons + } + #endregion + #region Module & Strategy Definitions public static RotationModuleDefinition Definition() { - //Define the rotation module - var res = new RotationModuleDefinition("Akechi PLD", "Standard Rotation Module", "Standard rotation (Akechi)", "Akechi", RotationModuleQuality.Ok, BitMask.Build((int)Class.GLA, (int)Class.PLD), 100); + var res = new RotationModuleDefinition("Akechi PLD", "Standard Rotation Module", "Standard rotation (Akechi)", "Akechi", RotationModuleQuality.Good, BitMask.Build((int)Class.GLA, (int)Class.PLD), 100); - //AoE Strategy: Manage AoE versus single-target rotations res.Define(Track.AoE).As("AoE", uiPriority: 200) - .AddOption(AOEStrategy.UseST, "Use ST", "Use single-target rotation") + .AddOption(AOEStrategy.AutoFinishCombo, "Auto (Finish Combo)", "Auto-selects best rotation dependant on targets; Finishes combo first", supportedTargets: ActionTargets.Hostile) + .AddOption(AOEStrategy.AutoBreakCombo, "Auto (Break Combo)", "Auto-selects best rotation dependant on targets; Breaks combo if needed", supportedTargets: ActionTargets.Hostile) .AddOption(AOEStrategy.ForceST, "Use AoE", "Force single-target rotation") - .AddOption(AOEStrategy.UseAoE, "Force ST", "Use AoE rotation") - .AddOption(AOEStrategy.ForceAoE, "Force AoE", "Force AoE rotation") - .AddOption(AOEStrategy.Auto, "Auto", "Choose AoE if 3+ targets; otherwise, use single-target") - .AddOption(AOEStrategy.AutoFinishCombo, "Auto Finish Combo", "Choose AoE if 3+ targets; otherwise, finish combo if possible"); - - //Burst Strategy: Control burst actions based on situational needs - res.Define(Track.Burst).As("Burst", uiPriority: 190) - .AddOption(BurstStrategy.Automatic, "Automatic", "Spend cartridges optimally") - .AddOption(BurstStrategy.Conserve, "Conserve", "Conserve MP and cooldowns") - .AddOption(BurstStrategy.UnderRaidBuffs, "Under Raid Buffs", "Spend under raid buffs; conserve otherwise") - .AddOption(BurstStrategy.UnderPotion, "Under Potion", "Spend under potion; conserve otherwise"); - - //Potion Strategy: Manage potion usage + .AddOption(AOEStrategy.ForceAoE, "Force AoE", "Force AoE rotation"); + res.Define(Track.Cooldowns).As("Cooldowns", uiPriority: 190) + .AddOption(CooldownStrategy.Allow, "Allow", "Allow use of cooldowns") + .AddOption(CooldownStrategy.Hold, "Hold", "Hold all cooldowns"); res.Define(Track.Potion).As("Potion", uiPriority: 180) .AddOption(PotionStrategy.Manual, "Manual", "Do not use potions automatically") .AddOption(PotionStrategy.AlignWithRaidBuffs, "Align With Raid Buffs", "Align potion usage with raid buffs", 270, 30, ActionTargets.Self) .AddOption(PotionStrategy.Immediate, "Immediate", "Use potions immediately when available", 270, 30, ActionTargets.Self) .AddAssociatedAction(ActionDefinitions.IDPotionStr); - - //Atonement Strategy: Control the use of Atonement abilities res.Define(Track.Atonement).As("Atonement", "Atone", uiPriority: 160) .AddOption(AtonementStrategy.Automatic, "Automatic", "Normal use of Atonement & it's combo") - .AddOption(AtonementStrategy.ForceAtonement, "Force Atonement", "Force use of Atonement", 30, 0, ActionTargets.Hostile, 76) + .AddOption(AtonementStrategy.ForceAtonement, "Force Atonement", "Force use of Atonement", 0, 30, ActionTargets.Hostile, 76) .AddOption(AtonementStrategy.ForceSupplication, "Force Supplication", "Force use of Supplication", 0, 0, ActionTargets.Hostile, 76) .AddOption(AtonementStrategy.ForceSepulchre, "Force Sepulchre", "Force use of Sepulchre", 0, 0, ActionTargets.Hostile, 76) - .AddOption(AtonementStrategy.Delay, "Delay", "Delay use of Atonement", 0, 0, ActionTargets.None, 60) + .AddOption(AtonementStrategy.Delay, "Delay", "Delay use of Atonement & its combo chain", 0, 0, ActionTargets.None, 60) .AddAssociatedActions(AID.Atonement, AID.Supplication, AID.Sepulchre); - - //Blade Combo Strategy: Manage the Blade Combo actions res.Define(Track.BladeCombo).As("Blade Combo", "Blades", uiPriority: 160) .AddOption(BladeComboStrategy.Automatic, "Automatic", "Normal use of Confiteor & Blades Combo") .AddOption(BladeComboStrategy.ForceConfiteor, "Force", "Force use of Confiteor", 0, 0, ActionTargets.Hostile, 80) @@ -154,90 +142,84 @@ public static RotationModuleDefinition Definition() .AddOption(BladeComboStrategy.ForceTruth, "Force Truth", "Force use of Blade of Truth", 0, 0, ActionTargets.Hostile, 90) .AddOption(BladeComboStrategy.ForceValor, "Force Valor", "Force use of Blade of Valor", 0, 0, ActionTargets.Hostile, 90) .AddOption(BladeComboStrategy.Delay, "Delay", "Delay use of Confiteor & Blade Combo", 0, 0, ActionTargets.None, 80) - .AddAssociatedActions(AID.BladeOfFaith, AID.BladeOfTruth, AID.BladeOfValor); - - //Dash Strategy: Control the use of the Intervene ability + .AddAssociatedActions(AID.Confiteor, AID.BladeOfFaith, AID.BladeOfTruth, AID.BladeOfValor); + res.Define(Track.Holy).As("Holy Spirit / Circle", "Holy", uiPriority: 150) + .AddOption(HolyStrategy.Automatic, "Automatic", "Automatically choose which Holy action to use based on conditions") + .AddOption(HolyStrategy.Spirit, "Spirit", "Force use of Holy Spirit", 0, 0, ActionTargets.Hostile, 64) + .AddOption(HolyStrategy.Circle, "Circle", "Force use of Holy Circle", 0, 0, ActionTargets.Hostile, 72) + .AddOption(HolyStrategy.Delay, "Delay", "Delay use of Holy actions", 0, 0, ActionTargets.None, 64) + .AddAssociatedActions(AID.HolySpirit, AID.HolyCircle); res.Define(Track.Dash).As("Intervene", "Dash", uiPriority: 150) .AddOption(DashStrategy.Automatic, "Automatic", "Normal use of Intervene") - .AddOption(DashStrategy.Force, "Force", "Force use of Intervene", 30, 0, ActionTargets.Hostile, 74) - .AddOption(DashStrategy.Conserve1, "Conserve 1", "Conserve one use of Intervene for manual usage", 30, 0, ActionTargets.Hostile, 74) - .AddOption(DashStrategy.GapClose, "Gap Close", "Use as gap closer if outside melee range", 30, 0, ActionTargets.None, 74) - .AddOption(DashStrategy.Delay, "Delay", "Delay use of Intervene", 30, 0, ActionTargets.None, 74) + .AddOption(DashStrategy.Force, "Force", "Force use of Intervene", 30, 0, ActionTargets.Hostile, 66) + .AddOption(DashStrategy.Force1, "Force (Hold 1)", "Force use of Intervene; Hold one charge for manual usage", 30, 0, ActionTargets.Hostile, 66) + .AddOption(DashStrategy.GapClose, "Gap Close", "Use as gap closer if outside melee range", 30, 0, ActionTargets.None, 66) + .AddOption(DashStrategy.GapClose1, "Gap Close (Hold 1)", "Use as gap closer if outside melee range; Hold one charge for manual usage", 30, 0, ActionTargets.None, 66) + .AddOption(DashStrategy.Delay, "Delay", "Delay use of Intervene", 0, 0, ActionTargets.None, 66) .AddAssociatedActions(AID.Intervene); - - //Ranged Strategy: Manage ranged attacks when outside melee range - res.Define(Track.Ranged).As("Ranged", uiPriority: 20) - .AddOption(RangedStrategy.OpenerRanged, "Opener Ranged", "Use Shield Lob as the first GCD if outside melee range") - .AddOption(RangedStrategy.OpenerRangedCast, "Opener Ranged Cast", "Use Holy Spirit as the first GCD if outside melee range", 0, 0, ActionTargets.Hostile, 64) - .AddOption(RangedStrategy.Opener, "Opener", "Use Shield Lob as the first GCD regardless of range") - .AddOption(RangedStrategy.OpenerCast, "Opener Cast", "Use Holy Spirit as the first GCD regardless of range", 0, 0, ActionTargets.Hostile, 64) - .AddOption(RangedStrategy.Force, "Force", "Always use Shield Lob regardless of conditions") - .AddOption(RangedStrategy.ForceCast, "Force Cast", "Always use Holy Spirit regardless of conditions", 0, 0, ActionTargets.Hostile, 64) - .AddOption(RangedStrategy.Ranged, "Ranged", "Use Shield Lob when outside melee range") - .AddOption(RangedStrategy.RangedCast, "Ranged Cast", "Use Holy Spirit when outside melee range", 0, 0, ActionTargets.Hostile, 64) - .AddOption(RangedStrategy.Forbid, "Forbid", "Prohibit use of both ranged attacks") + res.Define(Track.Ranged).As("Ranged", "Ranged", uiPriority: 140) + .AddOption(RangedStrategy.OpenerRangedCast, "Opener (Cast)", "Use Holy Spirit at the start of combat if outside melee range", 0, 0, ActionTargets.Hostile, 64) + .AddOption(RangedStrategy.OpenerCast, "Opener", "Use Holy Spirit at the start of combat regardless of range", 0, 0, ActionTargets.Hostile, 64) + .AddOption(RangedStrategy.ForceCast, "Force Cast", "Force use of Holy Spirit", 0, 0, ActionTargets.Hostile, 64) + .AddOption(RangedStrategy.RangedCast, "Ranged Cast", "Use Holy Spirit for ranged attacks", 0, 0, ActionTargets.Hostile, 64) + .AddOption(RangedStrategy.OpenerRanged, "Opener (Lob)", "Use Shield Lob at the start of combat if outside melee range", 0, 0, ActionTargets.Hostile, 15) + .AddOption(RangedStrategy.Opener, "Opener", "Use Shield Lob at the start of combat regardless of range", 0, 0, ActionTargets.Hostile, 15) + .AddOption(RangedStrategy.Force, "Force", "Force use of Shield Lob", 0, 0, ActionTargets.Hostile, 15) + .AddOption(RangedStrategy.Ranged, "Ranged", "Use Shield Lob for ranged attacks", 0, 0, ActionTargets.Hostile, 15) + .AddOption(RangedStrategy.Forbid, "Forbid", "Prohibit the use of ranged attacks", 0, 0, ActionTargets.Hostile, 15) .AddAssociatedActions(AID.ShieldLob, AID.HolySpirit); - - //Fight or Flight Strategy: Manage offensive cooldowns - res.Define(Track.FightOrFlight).As("Fight or Flight", "FoF", uiPriority: 170) - .AddOption(OffensiveStrategy.Automatic, "Automatic", "Use Fight or Flight normally") - .AddOption(OffensiveStrategy.Force, "Force", "Force use of Fight or Flight", 60, 20, ActionTargets.Self, 2) - .AddOption(OffensiveStrategy.Delay, "Delay", "Delay use of Fight or Flight", 0, 0, ActionTargets.None, 2) + res.Define(Track.FightOrFlight).As("Fight or Flight", "F.Flight", uiPriority: 170) + .AddOption(OGCDStrategy.Automatic, "Automatic", "Use Fight or Flight normally") + .AddOption(OGCDStrategy.Force, "Force", "Force use of Fight or Flight", 60, 20, ActionTargets.Self, 2) + .AddOption(OGCDStrategy.AnyWeave, "Any Weave", "Force use of Fight or Flight in any weave slot", 60, 20, ActionTargets.Self, 2) + .AddOption(OGCDStrategy.EarlyWeave, "Early Weave", "Force use of Fight or Flight in the first weave slot", 60, 20, ActionTargets.Self, 2) + .AddOption(OGCDStrategy.LateWeave, "Late Weave", "Force use of Fight or Flight in the last weave slot", 60, 20, ActionTargets.Self, 2) + .AddOption(OGCDStrategy.Delay, "Delay", "Delay use of Fight or Flight", 0, 0, ActionTargets.None, 2) .AddAssociatedActions(AID.FightOrFlight); - - //Requiescat Strategy: Control the use of Requiescat ability - res.Define(Track.Requiescat).As("Requiescat", "Req", uiPriority: 170) - .AddOption(OffensiveStrategy.Automatic, "Automatic", "Use Requiescat normally") - .AddOption(OffensiveStrategy.Force, "Force", "Force use of Requiescat / Imperator", 60, 20, ActionTargets.Self, 68) - .AddOption(OffensiveStrategy.Delay, "Delay", "Delay use of Requiescat / Imperator", 0, 0, ActionTargets.None, 68) + res.Define(Track.Requiescat).As("Requiescat", "R.scat", uiPriority: 170) + .AddOption(OGCDStrategy.Automatic, "Automatic", "Use Requiescat normally") + .AddOption(OGCDStrategy.Force, "Force", "Force use of Requiescat / Imperator", 60, 20, ActionTargets.Self, 68) + .AddOption(OGCDStrategy.AnyWeave, "Any Weave", "Force use of Requiescat / Imperator in any weave slot", 60, 20, ActionTargets.Self, 68) + .AddOption(OGCDStrategy.EarlyWeave, "Early Weave", "Force use of Requiescat / Imperator in the first weave slot", 60, 20, ActionTargets.Self, 68) + .AddOption(OGCDStrategy.LateWeave, "Late Weave", "Force use of Requiescat / Imperator in the last weave slot", 60, 20, ActionTargets.Self, 68) + .AddOption(OGCDStrategy.Delay, "Delay", "Delay use of Requiescat / Imperator", 0, 0, ActionTargets.None, 68) .AddAssociatedActions(AID.Requiescat, AID.Imperator); - - //Spirits Within Strategy: Manage usage of Spirits Within ability - res.Define(Track.SpiritsWithin).As("Spirits Within", "S.Within", uiPriority: 150) - .AddOption(OffensiveStrategy.Automatic, "Automatic", "Use Spirits Within normally") - .AddOption(OffensiveStrategy.Force, "Force", "Force use of Spirits Within / Expiacion", 30, 0, ActionTargets.Hostile, 30) - .AddOption(OffensiveStrategy.Delay, "Delay", "Delay use of Spirits Within / Expiacion", 0, 0, ActionTargets.None, 30) + res.Define(Track.SpiritsWithin).As("Spirits Within", "S.Within", uiPriority: 150) + .AddOption(OGCDStrategy.Automatic, "Automatic", "Use Spirits Within normally") + .AddOption(OGCDStrategy.Force, "Force", "Force use of Spirits Within / Expiacion", 30, 0, ActionTargets.Hostile, 30) + .AddOption(OGCDStrategy.AnyWeave, "Any Weave", "Force use of Spirits Within / Expiacion in any weave slot", 30, 0, ActionTargets.Hostile, 30) + .AddOption(OGCDStrategy.EarlyWeave, "Early Weave", "Force use of Spirits Within / Expiacion in the first weave slot", 30, 0, ActionTargets.Hostile, 30) + .AddOption(OGCDStrategy.LateWeave, "Late Weave", "Force use of Spirits Within / Expiacion in the last weave slot", 30, 0, ActionTargets.Hostile, 30) + .AddOption(OGCDStrategy.Delay, "Delay", "Delay use of Spirits Within / Expiacion", 0, 0, ActionTargets.None, 30) .AddAssociatedActions(AID.SpiritsWithin, AID.Expiacion); - - //Circle of Scorn Strategy: Control the use of Circle of Scorn - res.Define(Track.CircleOfScorn).As("Circle of Scorn Strategy", "Circle of Scorn", uiPriority: 150) - .AddOption(OffensiveStrategy.Automatic, "Automatic", "Use Circle of Scorn normally") - .AddOption(OffensiveStrategy.Force, "Force", "Force use of Circle of Scorn ASAP", 60, 15, ActionTargets.Hostile, 50) - .AddOption(OffensiveStrategy.Delay, "Delay", "Delay use of Circle of Scorn", 0, 0, ActionTargets.None, 50) + res.Define(Track.CircleOfScorn).As("Circle of Scorn", "C.Scorn", uiPriority: 150) + .AddOption(OGCDStrategy.Automatic, "Automatic", "Use Circle of Scorn normally") + .AddOption(OGCDStrategy.Force, "Force", "Force use of Circle of Scorn ASAP", 60, 15, ActionTargets.Hostile, 50) + .AddOption(OGCDStrategy.AnyWeave, "Any Weave", "Force use of Circle of Scorn in any weave slot", 60, 15, ActionTargets.Hostile, 50) + .AddOption(OGCDStrategy.EarlyWeave, "Early Weave", "Force use of Circle of Scorn in the first weave slot", 60, 15, ActionTargets.Hostile, 50) + .AddOption(OGCDStrategy.LateWeave, "Late Weave", "Force use of Circle of Scorn in the last weave slot", 60, 15, ActionTargets.Hostile, 50) + .AddOption(OGCDStrategy.Delay, "Delay", "Delay use of Circle of Scorn", 0, 0, ActionTargets.None, 50) .AddAssociatedActions(AID.CircleOfScorn); - - //Goring Blade Strategy: Manage the Goring Blade action - res.Define(Track.GoringBlade).As("Goring Blade Strategy", "Sonic Break", uiPriority: 150) - .AddOption(OffensiveStrategy.Automatic, "Automatic", "Use Goring Blade normally") - .AddOption(OffensiveStrategy.Force, "Force", "Force use of Goring Blade ASAP", 0, 30, ActionTargets.Hostile, 54) - .AddOption(OffensiveStrategy.Delay, "Delay", "Delay use of Goring Blade", 0, 0, ActionTargets.None, 54) + res.Define(Track.GoringBlade).As("Goring Blade", "G.Blade", uiPriority: 150) + .AddOption(GCDStrategy.Automatic, "Automatic", "Use Goring Blade normally") + .AddOption(GCDStrategy.Force, "Force", "Force use of Goring Blade ASAP", 0, 30, ActionTargets.Hostile, 54) + .AddOption(GCDStrategy.Delay, "Delay", "Delay use of Goring Blade", 0, 0, ActionTargets.None, 54) .AddAssociatedActions(AID.GoringBlade); - - //Holy Spirit Strategy: Control usage of Holy Spirit ability - res.Define(Track.HolySpirit).As("Holy Spirit Strategy", "Holy Spirit", uiPriority: 140) - .AddOption(OffensiveStrategy.Automatic, "Automatic", "Use Holy Spirit normally") - .AddOption(OffensiveStrategy.Force, "Force", "Force use of Holy Spirit ASAP", 0, 0, ActionTargets.Hostile, 30) - .AddOption(OffensiveStrategy.Delay, "Delay", "Delay use of Holy Spirit", 0, 0, ActionTargets.None, 30) - .AddAssociatedActions(AID.HolySpirit); - - //Holy Circle Strategy: Manage usage of Holy Circle ability - res.Define(Track.HolyCircle).As("Holy Circle Strategy", "Holy Circle", uiPriority: 140) - .AddOption(OffensiveStrategy.Automatic, "Automatic", "Use Holy Circle normally") - .AddOption(OffensiveStrategy.Force, "Force", "Force use of Holy Circle ASAP", 0, 0, ActionTargets.Hostile, 72) - .AddOption(OffensiveStrategy.Delay, "Delay", "Delay use of Holy Circle", 0, 0, ActionTargets.None, 72) - .AddAssociatedActions(AID.HolyCircle); - - //Blade of Honor Strategy: Manage usage of Blade of Honor ability - res.Define(Track.BladeOfHonor).As("Blade of Honor Strategy", "Blade of Honor", uiPriority: 150) - .AddOption(OffensiveStrategy.Automatic, "Automatic", "Use Blade of Honor normally") - .AddOption(OffensiveStrategy.Force, "Force", "Force use of Blade of Honor ASAP", 0, 0, ActionTargets.Hostile, 100) - .AddOption(OffensiveStrategy.Delay, "Delay", "Delay use of Blade of Honor", 0, 0, ActionTargets.None, 100) + res.Define(Track.BladeOfHonor).As("Blade of Honor", "B.Honor", uiPriority: 150) + .AddOption(OGCDStrategy.Automatic, "Automatic", "Use Blade of Honor normally") + .AddOption(OGCDStrategy.Force, "Force", "Force use of Blade of Honor ASAP", 0, 0, ActionTargets.Hostile, 100) + .AddOption(OGCDStrategy.AnyWeave, "Any Weave", "Force use of Blade of Honor in any weave slot", 0, 0, ActionTargets.Hostile, 100) + .AddOption(OGCDStrategy.EarlyWeave, "Early Weave", "Force use of Blade of Honor in the first weave slot", 0, 0, ActionTargets.Hostile, 100) + .AddOption(OGCDStrategy.LateWeave, "Late Weave", "Force use of Blade of Honor in the last weave slot", 0, 0, ActionTargets.Hostile, 100) + .AddOption(OGCDStrategy.Delay, "Delay", "Delay use of Blade of Honor", 0, 0, ActionTargets.None, 100) .AddAssociatedActions(AID.BladeOfHonor); return res; } + #endregion + #region Priorities public enum GCDPriority //Priority for GCDs used { None = 0, @@ -245,9 +227,7 @@ public static RotationModuleDefinition Definition() NormalGCD = 450, HolyCircle = 490, HolySpirit = 500, - Atonement3 = 560, - Atonement2 = 570, - Atonement1 = 580, + Atonement = 580, GoringBlade = 590, Valor = 600, Truth = 610, @@ -255,7 +235,6 @@ public static RotationModuleDefinition Definition() Confiteor = 650, ForcedGCD = 900, } - public enum OGCDPriority //Priority for oGCDs used { None = 0, @@ -268,334 +247,412 @@ public static RotationModuleDefinition Definition() ForcedOGCD = 900, Potion = 910, } + #endregion + + #region Variables public int Oath; //Current value of the oath gauge public int BladeComboStep; //Current step in the Confiteor combo sequence - public float GCDLength; //Length of the global cooldown, adjusted by skill speed and haste (baseline: 2.5s) - public float PotionLeft; //Remaining duration of the potion buff (typically 30s) public float RaidBuffsLeft; //Remaining duration of active raid-wide buffs (typically 20s-22s) public float RaidBuffsIn; //Time until the next set of raid-wide buffs are applied (typically 20s-22s) - - public float BurstWindowLeft; //Time remaining in the current burst window (typically 20s-22s) - public float BurstWindowIn; //Time until the next burst window begins (typically 20s-22s) - - //Buff and cooldown management - public float fofCD; //Cooldown remaining on the Fight or Flight ability - public float fofLeft; //Time left before Fight or Flight is available again - public float reqCD; //Cooldown remaining on the Requiescat ability - public (float Left, int Stacks) req; //Remaining cooldown for Requiescat, along with its stack count - public uint playerMP; //Current MP (mana points) of the player - - //Buff status indicators - public bool hasFoF; //Indicates if the Fight or Flight buff is currently active - public bool hasReq; //Indicates if the Requiescat buff is currently active - public bool hasMight; //Indicates if the Divine Might buff is currently active - public bool hasMPforMight; //Checks if there is enough MP to use Holy Spirit with Divine Might - public bool hasMPforReq; //Checks if there is enough MP to use Holy Spirit under the Requiescat buff - - //Phase and condition monitoring - public bool isDivineMightExpiring; //Indicates if the Divine Might buff is nearing expiration - public bool isAtonementExpiring; //Indicates if any Atonement buffs are about to expire - + public float CooldownsWindowLeft; //Time remaining in the current Cooldowns window (typically 20s-22s) + public float CooldownsWindowIn; //Time until the next Cooldowns window begins (typically 20s-22s) + public (float Left, bool IsActive) DivineMight; //Conditions for the Divine Might buff + public (float CD, float Left, bool IsReady, bool IsActive) FightOrFlight; //Conditions for Fight or Flight ability + public (float CD, bool IsReady) SpiritsWithin; //Conditions for Spirits Within ability + public (float CD, bool IsReady) CircleOfScorn; //Conditions for Circle of Scorn ability + public (float CD, float Left, bool IsReady, bool IsActive) GoringBlade; //Conditions for Goring Blade ability + public (float TotalCD, bool HasCharges, bool IsReady) Intervene; //Conditions for Intervene ability + public (float CD, int Stacks, bool IsReady, bool IsActive) Requiescat; //Conditions for Requiescat ability + public (float Left, bool IsReady, bool IsActive) Atonement; //Conditions for Atonement ability + public (float Left, bool IsReady, bool IsActive) Supplication; //Conditions for Supplication ability + public (float Left, bool IsReady, bool IsActive) Sepulchre; //Conditions for Sepulchre ability + public (float Left, bool HasMP, bool IsReady, bool IsActive) Confiteor; //Conditions for Confiteor ability + public (float Left, bool IsReady, bool IsActive) BladeOfHonor; //Conditions for Blade of Honor ability + public (bool HasMP, bool IsReady) HolySpirit; //Conditions for Holy Spirit ability + public (bool HasMP, bool IsReady) HolyCircle; //Conditions for Holy Circle ability + public uint MP; //Current MP (mana points) of the player + public bool ShouldUseAOE; //Check if AOE rotation should be used + public bool ShouldNormalHolyCircle; //Check if Holy Circle should be used + public bool ShouldUseDMHolyCircle; //Check if Holy Circle should be used under Divine Might public AID NextGCD; //The next action to be executed during the global cooldown (for cartridge management) - private GCDPriority NextGCDPrio; //Priority of the next global cooldown action for decision-making on cooldowns - - //Check if the desired ability is unlocked - private bool Unlocked(AID aid) => ActionUnlocked(ActionID.MakeSpell(aid)); - - //Get remaining cooldown time for the specified action - private float CD(AID aid) => World.Client.Cooldowns[ActionDefinitions.Instance.Spell(aid)!.MainCooldownGroup].Remaining; - - //Check if we can fit an additional GCD within the provided deadline - private bool CanFitGCD(float deadline, int extraGCDs = 0) => GCD + GCDLength * extraGCDs < deadline; - - //Get the last action used in the combo sequence - private AID ComboLastMove => (AID)World.Client.ComboState.Action; - - //Check if the target is within melee range (3 yalms) - private bool In3y(Actor? target) => Player.DistanceToHitbox(target) <= 3; - - //Check if the target is within 5 yalms - private bool In5y(Actor? target) => Player.DistanceToHitbox(target) <= 4.75; - - //Check if the desired action is ready (cooldown less than 0.6 seconds) - private bool ActionReady(AID aid) => World.Client.Cooldowns[ActionDefinitions.Instance.Spell(aid)!.MainCooldownGroup].Remaining < 0.6f; - - //Check if this is the first GCD in combat - private bool IsFirstGCD() => !Player.InCombat || (World.CurrentTime - Manager.CombatStart).TotalSeconds < 0.1f; - - //Returns the number of targets hit by AoE within a 5-yalm radius around the player - private int NumTargetsHitByAoE() => Hints.NumPriorityTargetsInAOECircle(Player.Position, 5); - - //Checks if the potion should be used before raid buffs expire - private bool IsPotionBeforeRaidbuffs() => RaidBuffsLeft == 0 && PotionLeft > RaidBuffsIn + 17.5f; - - //Checks if Status effect is on self - public bool HasEffect(SID sid) where SID : Enum => Player.FindStatus((uint)(object)sid, Player.InstanceID) != null; - - //Calculates the elapsed time since combat started in seconds - public float CombatTimer => (float)(World.CurrentTime - Manager.CombatStart).TotalSeconds; - + public bool canWeaveIn; //Can weave in oGCDs + public bool canWeaveEarly; //Can early weave oGCDs + public bool canWeaveLate; //Can late weave oGCDs + private delegate bool PositionCheck(Actor playerTarget, Actor targetToTest); + #endregion + + #region Module Helpers + private bool Unlocked(AID aid) => ActionUnlocked(ActionID.MakeSpell(aid)); //Check if the desired ability is unlocked + private float CD(AID aid) => World.Client.Cooldowns[ActionDefinitions.Instance.Spell(aid)!.MainCooldownGroup].Remaining; //Get remaining cooldown time for the specified action + private bool IsOffCooldown(AID aid) => World.Client.Cooldowns[ActionDefinitions.Instance.Spell(aid)!.MainCooldownGroup].Remaining < 0.6f; //Check if the desired action is ready (cooldown less than 0.6 seconds) + private bool ActionReady(AID aid) => Unlocked(aid) && IsOffCooldown(aid); //Check if the desired action is unlocked and off cooldown + private AID ComboLastMove => (AID)World.Client.ComboState.Action; //Get the last action used in the combo sequence + private bool In3y(Actor? target) => Player.DistanceToHitbox(target) <= 2.99f; //Check if the target is within ST melee range (3 yalms) + private bool In5y(Actor? target) => Player.DistanceToHitbox(target) <= 4.99f; //Check if the target is within AOE melee range (5 yalms) + private bool In20y(Actor? target) => Player.DistanceToHitbox(target) <= 19.99f; //Check if the target is within 20 yalms + private bool In25y(Actor? target) => Player.DistanceToHitbox(target) <= 24.99f; //Check if the target is within 25 yalms + private bool IsFirstGCD() => !Player.InCombat || (World.CurrentTime - Manager.CombatStart).TotalSeconds < 0.1f; //Check if this is the first GCD in combat + private int TargetsHitByPlayerAOE() => Hints.NumPriorityTargetsInAOECircle(Player.Position, 5); //Returns the number of targets hit by AoE within a 5-yalm radius around the player + private int TargetsHitByTargetAOE(Actor? target) => Hints.NumPriorityTargetsInAOECircle(target!.Position, 5); //Returns the number of targets hit by AoE within a 5-yalm radius around the target + private PositionCheck IsSplashTarget => (Actor primary, Actor other) => Hints.TargetInAOECircle(other, primary.Position, 5); + public bool HasEffect(SID sid) => SelfStatusLeft(sid) > 0; //Checks if Status effect is on self + public float CombatTimer => (float)(World.CurrentTime - Manager.CombatStart).TotalSeconds; //Calculates the elapsed time since combat started in seconds + public Actor? TargetChoice(StrategyValues.OptionRef strategy) => ResolveTargetOverride(strategy.Value); + #endregion + + #region Upgrade Paths + public AID BestSpirits + => Unlocked(AID.Expiacion) //if Expiacion is unlocked + ? AID.Expiacion //then use Expiacion + : AID.SpiritsWithin; //otherwise use Spirits Within + public AID BestRequiescat + => Unlocked(AID.Imperator) //if Imperator is unlocked + ? AID.Imperator //then use Imperator + : AID.Requiescat; //otherwise use Requiescat + public AID BestHoly + => ShouldUseDMHolyCircle || ShouldNormalHolyCircle //if Holy Circle should be used + ? AID.HolyCircle //then use Holy Circle + : AID.HolySpirit; //otherwise use Holy Spirit + public AID BestHolyCircle //for AOE use from Lv64-Lv71 + => HolyCircle.IsReady //if Holy Circle is ready + ? AID.HolyCircle //then use Holy Circle + : AID.HolySpirit; //then use Holy Spirit + public AID BestAtonement + => Sepulchre.IsReady //if Sepulchre is ready + ? AID.Sepulchre //then use Sepulchre + : Supplication.IsReady //if Supplication is ready + ? AID.Supplication //then use Supplication + : AID.Atonement; //otherwise use Atonement + public AID BestBlade + => BladeComboStep is 3 + ? AID.BladeOfValor + : BladeComboStep is 2 + ? AID.BladeOfTruth + : BladeComboStep is 1 + ? AID.BladeOfFaith + : AID.Confiteor; + #endregion public override void Execute(StrategyValues strategy, Actor? primaryTarget, float estimatedAnimLockDelay, bool isMoving) //Executes our actions { - + #region Variables var gauge = World.Client.GetGauge(); //Retrieve current Paladin gauge Oath = gauge.OathGauge; //Get the current value of the Oath gauge BladeComboStep = gauge.ConfiteorComboStep; //Get the current step in the Confiteor/Blades combo - - //Buff and cooldown management - fofCD = CD(AID.FightOrFlight); //Remaining cooldown for the Fight or Flight ability - fofLeft = SelfStatusLeft(SID.FightOrFlight); //Remaining duration of the Fight or Flight buff - reqCD = CD(AID.Requiescat); //Remaining cooldown for the Requiescat ability - playerMP = Player.HPMP.CurMP; //Current mana points (MP) of the player - - //Buff status checks - hasFoF = fofCD is >= 40 and <= 60; //Check if the Fight or Flight buff is active (within cooldown range) - hasReq = HasEffect(AID.Requiescat); //Check if the Requiescat buff is active - hasMight = HasEffect(SID.DivineMight); //Check if the Divine Might buff is active - hasMPforMight = playerMP >= 1000; //Check if there is enough MP for Holy Spirit while using Divine Might - hasMPforReq = playerMP >= 1000 * 3.6; //Check if there is enough MP for Holy Spirit under the Requiescat buff - - //Phase and condition monitoring - isDivineMightExpiring = SelfStatusLeft(SID.DivineMight) < 6; //Check if the Divine Might buff is about to expire - isAtonementExpiring = - HasEffect(SID.AtonementReady) && SelfStatusLeft(SID.AtonementReady) < 6 || - HasEffect(SID.SupplicationReady) && SelfStatusLeft(SID.SupplicationReady) < 6 || - HasEffect(SID.SepulchreReady) && SelfStatusLeft(SID.SepulchreReady) < 6; //Check if any Atonement buffs are close to expiring - + MP = Player.HPMP.CurMP; //Current mana points (MP) of the player + DivineMight.Left = SelfStatusLeft(SID.DivineMight, 30); //Remaining duration of the Divine Might buff + DivineMight.IsActive = DivineMight.Left > 0; //Check if the Divine Might buff is active + FightOrFlight.CD = CD(AID.FightOrFlight); //Remaining cooldown for the Fight or Flight ability + FightOrFlight.Left = SelfStatusLeft(SID.FightOrFlight, 20); //Remaining duration of the Fight or Flight buff + FightOrFlight.IsActive = FightOrFlight.CD is >= 39.5f and <= 60; //Check if the Fight or Flight buff is active + FightOrFlight.IsReady = ActionReady(AID.FightOrFlight); //Fight or Flight ability + SpiritsWithin.CD = CD(AID.SpiritsWithin); //Remaining cooldown for the Spirits Within ability + SpiritsWithin.IsReady = Unlocked(AID.SpiritsWithin) && IsOffCooldown(BestSpirits); //Spirits Within ability + CircleOfScorn.CD = CD(AID.CircleOfScorn); //Remaining cooldown for the Circle of Scorn ability + CircleOfScorn.IsReady = Unlocked(AID.CircleOfScorn) && IsOffCooldown(AID.CircleOfScorn); //Circle of Scorn ability + GoringBlade.CD = CD(AID.GoringBlade); //Remaining cooldown for the Goring Blade ability + GoringBlade.Left = SelfStatusLeft(SID.GoringBladeReady, 30); //Remaining duration of the Goring Blade buff + GoringBlade.IsActive = GoringBlade.Left > 0; //Check if the Goring Blade buff is active + GoringBlade.IsReady = Unlocked(AID.GoringBlade) && GoringBlade.IsActive; //Goring Blade ability + Intervene.TotalCD = CD(AID.Intervene); //Total cooldown for the Intervene ability (60s) + Intervene.HasCharges = Intervene.TotalCD <= 30f; //Check if the player has charges of Intervene + Intervene.IsReady = Unlocked(AID.Intervene) && Intervene.HasCharges; //Intervene ability + Requiescat.CD = CD(BestRequiescat); //Remaining cooldown for the Requiescat ability + Requiescat.Stacks = SelfStatusDetails(SID.Requiescat).Stacks; //Get the current number of Requiescat stacks + Requiescat.IsActive = Requiescat.Stacks > 0; //Check if the Requiescat buff is active + Requiescat.IsReady = Unlocked(AID.Requiescat) && Requiescat.IsActive; //Requiescat ability + Atonement.Left = SelfStatusLeft(SID.AtonementReady, 30); //Remaining duration of the Atonement buff + Atonement.IsActive = Atonement.Left > 0; //Check if the Atonement buff is active + Atonement.IsReady = Unlocked(AID.Atonement) && Atonement.IsActive; //Atonement ability + Supplication.Left = SelfStatusLeft(SID.SupplicationReady, 30); //Remaining duration of the Supplication buff + Supplication.IsActive = Supplication.Left > 0; //Check if the Supplication buff is active + Supplication.IsReady = Unlocked(AID.Supplication) && Supplication.IsActive; //Supplication ability + Sepulchre.Left = SelfStatusLeft(SID.SepulchreReady, 30); //Remaining duration of the Sepulchre buff + Sepulchre.IsActive = Sepulchre.Left > 0; //Check if the Sepulchre buff is active + Sepulchre.IsReady = Unlocked(AID.Sepulchre) && Sepulchre.IsActive; //Sepulchre ability + Confiteor.Left = SelfStatusLeft(SID.ConfiteorReady, 30); //Remaining duration of the Confiteor buff + Confiteor.IsActive = Confiteor.Left > 0; //Check if the Confiteor buff is active + Confiteor.IsReady = Unlocked(AID.Confiteor) && Confiteor.IsActive && MP >= 1000; //Confiteor ability + var canBlade = Unlocked(AID.BladeOfValor) && BladeComboStep is not 0; //Blade abilities, only if combo step is not zero + BladeOfHonor.Left = SelfStatusLeft(SID.BladeOfHonorReady, 30); //Remaining duration of the Blade of Honor buff + BladeOfHonor.IsActive = BladeOfHonor.Left > 0; //Check if the Blade of Honor buff is active + BladeOfHonor.IsReady = Unlocked(AID.BladeOfHonor) && IsOffCooldown(AID.BladeOfHonor); //Blade of Honor ability + HolySpirit.HasMP = MP >= 1000; //Check if the player has enough mana points for Holy Spirit + HolySpirit.IsReady = Unlocked(AID.HolySpirit) && HolySpirit.HasMP; //Holy Spirit ability + HolyCircle.HasMP = MP >= 1000; //Check if the player has enough mana points for Holy Circle + HolyCircle.IsReady = Unlocked(AID.HolyCircle) && HolyCircle.HasMP; //Holy Circle ability GCDLength = ActionSpeed.GCDRounded(World.Client.PlayerStats.SkillSpeed, World.Client.PlayerStats.Haste, Player.Level); //Calculate GCD based on skill speed and haste - - //Buff durations PotionLeft = PotionStatusLeft(); //Remaining duration of the potion buff (typically 30s) - - //Raid buff timings (RaidBuffsLeft, RaidBuffsIn) = EstimateRaidBuffTimings(primaryTarget); //Estimate remaining and incoming raid buff durations - - //Next global cooldown action NextGCD = AID.None; //Initialize next action as none - NextGCDPrio = GCDPriority.None; //Set next GCD priority to none - - //Define the AoE strategy and determine the number of targets hit - var AOEStrategy = strategy.Option(Track.AoE).As(); - var AoETargets = AOEStrategy switch + canWeaveIn = GCD is <= 2.5f and >= 0.1f; //Can weave in oGCDs + canWeaveEarly = GCD is <= 2.5f and >= 1.25f; //Can weave in oGCDs early + canWeaveLate = GCD is <= 1.25f and >= 0.1f; //Can weave in oGCDs late + ShouldUseAOE = TargetsHitByPlayerAOE() > 2; //Check if AOE rotation should be used + ShouldNormalHolyCircle = !DivineMight.IsActive && TargetsHitByPlayerAOE() > 3; //Check if Holy Circle should be used + ShouldUseDMHolyCircle = DivineMight.IsActive && TargetsHitByPlayerAOE() > 2; + + #region Strategy Options + var AOE = strategy.Option(Track.AoE); //Retrieves AOE track + var AOEStrategy = AOE.As(); //Retrieves AOE strategy + var cd = strategy.Option(Track.Cooldowns); //Retrieves Cooldowns track + var cdStrat = cd.As(); //Retrieves Cooldowns strategy + var pot = strategy.Option(Track.Potion); //Retrieves Potion track + var potStrat = pot.As(); //Retrieves Potion strategy + var fof = strategy.Option(Track.FightOrFlight); + var fofStrat = fof.As(); + var req = strategy.Option(Track.Requiescat); + var reqStrat = req.As(); + var atone = strategy.Option(Track.Atonement); //Retrieves Atonement track + var atoneStrat = atone.As(); //Retrieves Atonement strategy + var blade = strategy.Option(Track.BladeCombo); //Retrieves Blade Combo track + var bladeStrat = blade.As(); + var cos = strategy.Option(Track.CircleOfScorn); + var cosStrat = cos.As(); + var sw = strategy.Option(Track.SpiritsWithin); + var swStrat = sw.As(); + var dash = strategy.Option(Track.Dash); + var dashStrat = dash.As(); + var gb = strategy.Option(Track.GoringBlade); + var gbStrat = gb.As(); + var boh = strategy.Option(Track.BladeOfHonor); + var bohStrat = boh.As(); + var holy = strategy.Option(Track.Holy); + var holyStrat = holy.As(); + var ranged = strategy.Option(Track.Ranged); + var rangedStrat = ranged.As(); + #endregion + + #endregion + + #region Standard Execution + if (AOEStrategy == AOEStrategy.AutoBreakCombo) //if Break Combo option is selected { - AOEStrategy.UseST => NumTargetsHitByAoE() > 0 ? 1 : 0, //Use single-target actions if any AoE targets exist - AOEStrategy.UseAoE => NumTargetsHitByAoE() > 0 ? 100 : 0, //Use AoE actions if any targets are hit - _ => NumTargetsHitByAoE() //Default to the number of targets hit by AoE - }; - - //Burst (raid buff) windows typically last 20 seconds every 120 seconds - var burst = strategy.Option(Track.Burst); - var burstStrategy = burst.As(); - var hold = burstStrategy == BurstStrategy.Conserve; //Determine if we are conserving cartridges - - //Calculate the burst window based on the current strategy - (BurstWindowIn, BurstWindowLeft) = burstStrategy switch + if (ShouldUseAOE) //if AOE rotation should be used + QueueGCD(RotationAOE(), //queue the next AOE combo action + Player, //on Self (no target needed) + GCDPriority.Combo123); //with priority for 123/12 combo actions + if (!ShouldUseAOE) + QueueGCD(RotationST(), //queue the next single-target combo action + TargetChoice(AOE) //Get target choice + ?? primaryTarget, //if none, choose primary target + GCDPriority.Combo123); //with priority for 123/12 combo actions + } + if (AOEStrategy == AOEStrategy.AutoFinishCombo) //if Finish Combo option is selected { - BurstStrategy.Automatic => (RaidBuffsIn, IsPotionBeforeRaidbuffs() ? 0 : Math.Max(PotionLeft, RaidBuffsLeft)), //Automatically calculate based on current buffs and potions - BurstStrategy.UnderRaidBuffs => (RaidBuffsIn, RaidBuffsLeft), //Under raid buffs, use remaining durations - BurstStrategy.UnderPotion => (PotionCD, PotionLeft), //Under potion effects, use potion cooldown and remaining duration - _ => (0, 0), //no burst window - }; - - //Check GCD (Global Cooldown) conditions for various abilities - var canFoF = Unlocked(AID.FightOrFlight) && ActionReady(AID.FightOrFlight); //Fight or Flight ability - var canReq = Unlocked(AID.Requiescat) && ActionReady(AID.Requiescat); //Requiescat ability - var canScorn = Unlocked(AID.CircleOfScorn) && ActionReady(AID.CircleOfScorn); //Circle of Scorn ability - var canSpirit = Unlocked(AID.SpiritsWithin) && ActionReady(AID.SpiritsWithin); //Spirits Within ability - var canGB = Unlocked(AID.GoringBlade) && HasEffect(SID.GoringBladeReady); //Goring Blade ability readiness - var canHS = Unlocked(AID.HolySpirit); //Holy Spirit ability - var canHC = Unlocked(AID.HolyCircle); //Holy Circle ability - var canAtone = Unlocked(AID.Atonement) && HasEffect(SID.AtonementReady); //Atonement ability readiness - var canDash = Unlocked(AID.Intervene) && CD(AID.Intervene) <= 30; //Intervene ability with cooldown check - var canConfiteor = Unlocked(AID.Confiteor) && HasEffect(SID.ConfiteorReady) && BladeComboStep is 0; //Confiteor ability readiness and combo step check - var canBlade = Unlocked(AID.BladeOfValor) && BladeComboStep is not 0; //Blade abilities, only if combo step is not zero - var canHonor = Unlocked(AID.BladeOfHonor) && HasEffect(SID.BladeOfHonorReady); //Blade of Honor ability readiness - - //Determine and queue the next combo action based on AoE strategy - var (comboAction, comboPrio) = ComboActionPriority(AOEStrategy, AoETargets, burstStrategy, burst.Value.ExpireIn); - QueueGCD(comboAction, comboAction is AID.TotalEclipse or AID.Prominence ? Player : primaryTarget, - AOEStrategy is AOEStrategy.ForceST or AOEStrategy.ForceAoE ? GCDPriority.ForcedGCD : comboPrio); - - //Execute Fight or Flight if conditions are met - var fofStrat = strategy.Option(Track.FightOrFlight).As(); - if (!hold && canFoF && ShouldUseFightOrFlight(fofStrat, primaryTarget)) - QueueOGCD(AID.FightOrFlight, Player, fofStrat is OffensiveStrategy.Force ? OGCDPriority.ForcedOGCD : OGCDPriority.FightOrFlight); - - //Execute Requiescat if conditions are met - var reqStrat = strategy.Option(Track.Requiescat).As(); - if (!hold && canReq && ShouldUseRequiescat(reqStrat, primaryTarget)) - QueueOGCD(Unlocked(AID.Imperator) ? AID.Imperator : AID.Requiescat, primaryTarget, reqStrat is OffensiveStrategy.Force ? OGCDPriority.ForcedOGCD : OGCDPriority.Requiescat); - - //Execute Confiteor if conditions are met - var bladeStrat = strategy.Option(Track.BladeCombo).As(); - if (canConfiteor && BladeComboStep is 0 && ShouldUseBladeCombo(bladeStrat, primaryTarget)) - QueueGCD(AID.Confiteor, primaryTarget, bladeStrat is BladeComboStrategy.ForceConfiteor ? GCDPriority.ForcedGCD : GCDPriority.Confiteor); - - //Execute Circle of Scorn if conditions are met - var scornStrat = strategy.Option(Track.CircleOfScorn).As(); - if (!hold && canScorn && ShouldUseCircleOfScorn(scornStrat, primaryTarget)) - QueueOGCD(AID.CircleOfScorn, primaryTarget, scornStrat is OffensiveStrategy.Force ? OGCDPriority.ForcedOGCD : OGCDPriority.CircleOfScorn); + QueueGCD(BestRotation(), //queue the next single-target combo action only if combo is finished + TargetChoice(AOE) //Get target choice + ?? primaryTarget, //if none, choose primary target + GCDPriority.Combo123); //with priority for 123/12 combo actions + } + #endregion - //Execute Spirits Within if conditions are met - var spiritsStrat = strategy.Option(Track.SpiritsWithin).As(); - if (!hold && canSpirit && ShouldUseSpiritsWithin(spiritsStrat, primaryTarget)) - QueueOGCD(Unlocked(AID.Expiacion) ? AID.Expiacion : AID.SpiritsWithin, primaryTarget, spiritsStrat is OffensiveStrategy.Force ? OGCDPriority.ForcedOGCD : OGCDPriority.SpiritsWithin); + #region Cooldowns Execution + var hold = cdStrat == CooldownStrategy.Hold; + if (!hold) + { + if (ShouldUseFightOrFlight(fofStrat, primaryTarget)) + QueueOGCD(AID.FightOrFlight, + Player, + fofStrat is OGCDStrategy.Force + or OGCDStrategy.AnyWeave + or OGCDStrategy.EarlyWeave + or OGCDStrategy.LateWeave + ? OGCDPriority.ForcedOGCD + : OGCDPriority.FightOrFlight); + if (ShouldUseRequiescat(reqStrat, primaryTarget)) + QueueOGCD(BestRequiescat, + TargetChoice(req) ?? primaryTarget, + reqStrat is OGCDStrategy.Force + or OGCDStrategy.AnyWeave + or OGCDStrategy.EarlyWeave + or OGCDStrategy.LateWeave + ? OGCDPriority.ForcedOGCD + : OGCDPriority.Requiescat); + if (bladeStrat == BladeComboStrategy.ForceConfiteor) + QueueGCD(AID.Confiteor, + TargetChoice(blade) ?? primaryTarget, + GCDPriority.ForcedGCD); + if (ShouldUseCircleOfScorn(cosStrat, primaryTarget)) + QueueOGCD(AID.CircleOfScorn, + Player, + cosStrat is OGCDStrategy.Force + or OGCDStrategy.AnyWeave + or OGCDStrategy.EarlyWeave + or OGCDStrategy.LateWeave + ? OGCDPriority.ForcedOGCD + : OGCDPriority.CircleOfScorn); + if (ShouldUseSpiritsWithin(swStrat, primaryTarget)) + QueueOGCD(BestSpirits, + TargetChoice(sw) ?? primaryTarget, + swStrat is OGCDStrategy.Force + or OGCDStrategy.AnyWeave + or OGCDStrategy.EarlyWeave + or OGCDStrategy.LateWeave + ? OGCDPriority.ForcedOGCD + : OGCDPriority.SpiritsWithin); + if (ShouldUseDash(dashStrat, primaryTarget)) + QueueOGCD(AID.Intervene, + TargetChoice(dash) ?? primaryTarget, + dashStrat is DashStrategy.Force + or DashStrategy.Force1 + or DashStrategy.GapClose + or DashStrategy.GapClose1 + ? OGCDPriority.ForcedOGCD + : OGCDPriority.Intervene); + if (HasEffect(SID.BladeOfHonorReady)) + QueueOGCD(AID.BladeOfHonor, + TargetChoice(boh) ?? primaryTarget, + bohStrat is OGCDStrategy.Force + or OGCDStrategy.AnyWeave + or OGCDStrategy.EarlyWeave + or OGCDStrategy.LateWeave + ? OGCDPriority.ForcedOGCD + : OGCDPriority.BladeOfHonor); + if (ShouldUseGoringBlade(gbStrat, primaryTarget)) + QueueGCD(AID.GoringBlade, + TargetChoice(gb) ?? primaryTarget, + gbStrat is GCDStrategy.Force + ? GCDPriority.ForcedGCD + : GCDPriority.GoringBlade); + } - //Execute Blade Combo actions based on the current combo step - if (canBlade) + if (canBlade && + ShouldUseBladeCombo(bladeStrat, primaryTarget)) { - if (BladeComboStep is 1) - QueueGCD(AID.BladeOfFaith, primaryTarget, bladeStrat is BladeComboStrategy.ForceFaith ? GCDPriority.ForcedGCD : GCDPriority.Faith); + if (bladeStrat is BladeComboStrategy.Automatic) + QueueGCD(BestBlade, + TargetChoice(blade) ?? primaryTarget, + GCDPriority.Confiteor); + if (bladeStrat is BladeComboStrategy.ForceFaith) + QueueGCD(AID.BladeOfFaith, + TargetChoice(blade) ?? primaryTarget, + GCDPriority.ForcedGCD); if (BladeComboStep is 2) - QueueGCD(AID.BladeOfTruth, primaryTarget, bladeStrat is BladeComboStrategy.ForceTruth ? GCDPriority.ForcedGCD : GCDPriority.Truth); + QueueGCD(AID.BladeOfTruth, + TargetChoice(blade) ?? primaryTarget, + bladeStrat is BladeComboStrategy.ForceTruth + ? GCDPriority.ForcedGCD + : GCDPriority.Truth); if (BladeComboStep is 3) - QueueGCD(AID.BladeOfValor, primaryTarget, bladeStrat is BladeComboStrategy.ForceValor ? GCDPriority.ForcedGCD : GCDPriority.Valor); + QueueGCD(AID.BladeOfValor, + TargetChoice(blade) ?? primaryTarget, + bladeStrat is BladeComboStrategy.ForceValor + ? GCDPriority.ForcedGCD + : GCDPriority.Valor); } + if (ShouldUseAtonement(atoneStrat, primaryTarget)) + { + if (atoneStrat == AtonementStrategy.Automatic) + QueueGCD(BestAtonement, + TargetChoice(atone) ?? primaryTarget, + GCDPriority.Atonement); + if (atoneStrat is AtonementStrategy.ForceAtonement) + QueueGCD(AID.Atonement, + TargetChoice(atone) ?? primaryTarget, + GCDPriority.ForcedGCD); + if (atoneStrat is AtonementStrategy.ForceSupplication) + QueueGCD(AID.Supplication, + TargetChoice(atone) ?? primaryTarget, + GCDPriority.ForcedGCD); + if (atoneStrat is AtonementStrategy.ForceSepulchre) + QueueGCD(AID.Sepulchre, + TargetChoice(atone) ?? primaryTarget, + GCDPriority.ForcedGCD); - //Execute Intervene if conditions are met - var dashStrat = strategy.Option(Track.Dash).As(); - if (canDash && ShouldUseDash(dashStrat, primaryTarget)) - QueueOGCD(AID.Intervene, primaryTarget, dashStrat is DashStrategy.Force or DashStrategy.GapClose ? OGCDPriority.ForcedOGCD : OGCDPriority.Intervene); - - //Execute Goring Blade if conditions are met - var gbStrat = strategy.Option(Track.GoringBlade).As(); - if (!hold && canGB && ShouldUseGoringBlade(gbStrat, primaryTarget)) - QueueGCD(AID.GoringBlade, primaryTarget, gbStrat is OffensiveStrategy.Force ? GCDPriority.ForcedGCD : GCDPriority.GoringBlade); - - //Execute Blade of Honor if conditions are met - var bohStrat = strategy.Option(Track.GoringBlade).As(); - if (!hold && canHonor && ShouldUseGoringBlade(bohStrat, primaryTarget)) - QueueOGCD(AID.BladeOfHonor, primaryTarget, bohStrat is OffensiveStrategy.Force ? OGCDPriority.ForcedOGCD : OGCDPriority.BladeOfHonor); - - //Execute Atonement if conditions are met - var atoneStrat = strategy.Option(Track.Atonement).As(); - if (!hold && canAtone && ShouldUseAtonement(atoneStrat, primaryTarget)) - QueueGCD(AID.Atonement, primaryTarget, atoneStrat is AtonementStrategy.ForceAtonement ? GCDPriority.ForcedGCD : GCDPriority.Atonement1); - - //Execute Atonement Combo actions based on readiness - if (HasEffect(SID.SupplicationReady)) - QueueGCD(AID.Supplication, primaryTarget, atoneStrat is AtonementStrategy.ForceSupplication ? GCDPriority.ForcedGCD : GCDPriority.Atonement2); - if (HasEffect(SID.SepulchreReady)) - QueueGCD(AID.Sepulchre, primaryTarget, atoneStrat is AtonementStrategy.ForceSepulchre ? GCDPriority.ForcedGCD : GCDPriority.Atonement3); - - //Execute Holy Spirit if conditions are met - var hsStrat = strategy.Option(Track.HolySpirit).As(); - var hcStrat = strategy.Option(Track.HolyCircle).As(); - if (canHS && ShouldUseHolySpirit(hsStrat, primaryTarget)) - QueueGCD(AID.HolySpirit, primaryTarget, hsStrat is OffensiveStrategy.Force ? GCDPriority.ForcedGCD : GCDPriority.HolySpirit); + } - //Execute Holy Circle if conditions are met - if (canHC && ShouldUseHolyCircle(hcStrat, primaryTarget)) - QueueGCD(AID.HolyCircle, primaryTarget, hcStrat is OffensiveStrategy.Force ? GCDPriority.ForcedGCD : GCDPriority.HolyCircle); - if (!canHC && canHS) - QueueGCD(AID.HolySpirit, primaryTarget, hsStrat is OffensiveStrategy.Force ? GCDPriority.ForcedGCD : GCDPriority.HolySpirit); + if (ShouldUseHoly(holyStrat, primaryTarget)) + { + if (holyStrat == HolyStrategy.Automatic) + QueueGCD(BestHoly, TargetChoice(holy) ?? primaryTarget, GCDPriority.HolySpirit); + if (holyStrat == HolyStrategy.Spirit) + QueueGCD(AID.HolySpirit, TargetChoice(holy) ?? primaryTarget, GCDPriority.ForcedGCD); + if (holyStrat == HolyStrategy.Circle) + QueueGCD(BestHolyCircle, Player, GCDPriority.ForcedGCD); + } - //Execute ranged skills based on strategy - var rangedStrat = strategy.Option(Track.Ranged).As(); if (ShouldUseRangedLob(primaryTarget, rangedStrat)) - QueueGCD(AID.ShieldLob, primaryTarget, rangedStrat is RangedStrategy.Force ? GCDPriority.ForcedGCD : GCDPriority.NormalGCD); + QueueGCD(AID.ShieldLob, TargetChoice(ranged) ?? primaryTarget, rangedStrat is RangedStrategy.Force ? GCDPriority.ForcedGCD : GCDPriority.Combo123); if (ShouldUseRangedCast(primaryTarget, rangedStrat)) - QueueGCD(AID.HolySpirit, primaryTarget, rangedStrat is RangedStrategy.ForceCast ? GCDPriority.ForcedGCD : GCDPriority.NormalGCD); - - //Execute potion if conditions are met + QueueGCD(AID.HolySpirit, TargetChoice(ranged) ?? primaryTarget, rangedStrat is RangedStrategy.ForceCast ? GCDPriority.ForcedGCD : GCDPriority.Combo123); if (ShouldUsePotion(strategy.Option(Track.Potion).As())) Hints.ActionsToExecute.Push(ActionDefinitions.IDPotionStr, Player, ActionQueue.Priority.VeryHigh + (int)OGCDPriority.Potion, 0, GCD - 0.9f); - + #endregion } - //Method to queue a GCD (Global Cooldown) action - private void QueueGCD(AID aid, Actor? target, GCDPriority prio) + #region Core Execution Helpers + public void QueueGCD

(AID aid, Actor? target, P priority, float delay = 0) where P : Enum => QueueGCD(aid, target, (int)(object)priority, delay); + public void QueueOGCD

(AID aid, Actor? target, P priority, float delay = 0) where P : Enum => QueueOGCD(aid, target, (int)(object)priority, delay); + public void QueueGCD(AID aid, Actor? target, int priority = 8, float delay = 0) { - //Check if the priority for this action is valid - if (prio != GCDPriority.None) + var NextGCDPrio = 0; + if (priority == 0) + return; + if (QueueAction(aid, target, ActionQueue.Priority.High + priority, delay) && priority > NextGCDPrio) { - //Push the action to the execution queue with the specified priority - Hints.ActionsToExecute.Push(ActionID.MakeSpell(aid), target, ActionQueue.Priority.High + (int)prio); - - //Update the next GCD action and its priority if this one has a higher priority - if (prio > NextGCDPrio) - { - NextGCD = aid; //Set the next GCD action - NextGCDPrio = prio; //Update the priority for the next GCD - } + NextGCD = aid; } } - - //Method to queue an OGCD (Off Global Cooldown) action - private void QueueOGCD(AID aid, Actor? target, OGCDPriority prio, float basePrio = ActionQueue.Priority.Medium) + public void QueueOGCD(AID aid, Actor? target, int priority = 4, float delay = 0) { - //Check if the priority for this action is valid - if (prio != OGCDPriority.None) + if (priority == 0) + return; + QueueAction(aid, target, ActionQueue.Priority.Medium + priority, delay); + } + public bool QueueAction(AID aid, Actor? target, float priority, float delay) + { + Vector3 targetPos = default; + var def = ActionDefinitions.Instance.Spell(aid); + if ((uint)(object)aid == 0) + return false; + if (def == null) + return false; + if (def.Range != 0 && target == null) + { + return false; + } + if (def.AllowedTargets.HasFlag(ActionTargets.Area)) { - //Push the OGCD action to the execution queue with the specified priority - Hints.ActionsToExecute.Push(ActionID.MakeSpell(aid), target, basePrio + (int)prio); + if (def.Range == 0) + targetPos = Player.PosRot.XYZ(); + else if (target != null) + targetPos = target.PosRot.XYZ(); } + Hints.ActionsToExecute.Push(ActionID.MakeSpell(aid), target, priority, delay: delay, targetPos: targetPos); + return true; } + #endregion - //Method to determine the next single-target action based on the last action used - private AID NextComboSingleTarget() => ComboLastMove switch + #region Rotation Helpers + private AID RotationST() => ComboLastMove switch { AID.RiotBlade => Unlocked(AID.RoyalAuthority) ? AID.RoyalAuthority : AID.RageOfHalone, //If Riot Blade was last used, choose Royal Authority if available, otherwise Rage of Halone AID.FastBlade => AID.RiotBlade, //If Fast Blade was last used, go back to Riot Blade _ => AID.FastBlade, //Default to Fast Blade if no recognized last action }; - - //Method to determine the next AoE action based on the last action used - private AID NextComboAoE() => ComboLastMove switch + private AID RotationAOE() => ComboLastMove switch { AID.TotalEclipse => AID.Prominence, //If Total Eclipse was last used, use Prominence next _ => AID.TotalEclipse, //Default to Total Eclipse if no recognized last action }; + private AID BestRotation() => ComboLastMove switch + { + //ST + AID.RoyalAuthority => ShouldUseAOE ? RotationAOE() : RotationST(), + AID.RageOfHalone => ShouldUseAOE ? RotationAOE() : RotationST(), + AID.RiotBlade => RotationST(), + AID.FastBlade => RotationST(), + //AOE + AID.TotalEclipse => ShouldUseAOE ? RotationAOE() : RotationST(), + AID.Prominence => RotationAOE(), + _ => ShouldUseAOE ? RotationAOE() : RotationST(), + }; + #endregion - //Method to determine the next combo action and its priority based on AoE strategy, target count, and burst strategy - private (AID, GCDPriority) ComboActionPriority(AOEStrategy aoeStrategy, int AoETargets, BurstStrategy burstStrategy, float burstStrategyExpire) - { - //Determine how many combo steps are remaining based on the last action - var comboStepsRemaining = ComboLastMove switch - { - AID.FastBlade => Unlocked(AID.RiotBlade) ? 2 : Unlocked(AID.RoyalAuthority) ? 1 : 0, //Fast Blade allows up to 2 or 1 additional combo actions based on availability - AID.TotalEclipse => Unlocked(AID.Prominence) ? 1 : 0, //Total Eclipse allows 1 more combo action if Prominence is unlocked - _ => 0 //Default to no combo steps if the last action doesn't match - }; - - //Check if we can fit a GCD based on remaining combo state time - if (comboStepsRemaining > 0 && !CanFitGCD(World.Client.ComboState.Remaining)) - comboStepsRemaining = 0; //Reset combo steps if not enough time to complete them - - var doingAOECombo = ComboLastMove == AID.TotalEclipse; //Track if currently performing an AoE combo - - //Determine if an AoE action is desirable based on target count and strategy - var wantAOEAction = Unlocked(AID.TotalEclipse) && aoeStrategy switch - { - AOEStrategy.UseST => false, //Explicitly using single-target strategy, so AoE action is not desired - AOEStrategy.ForceST => false, //Forcing single-target, so AoE action is not desired - AOEStrategy.UseAoE => true, //Explicitly using AoE strategy, so AoE action is desired - AOEStrategy.ForceAoE => false, //Forcing AoE action but this is mainly for planning, so AoE not action is desired - AOEStrategy.Auto => AoETargets >= 3, //Automatically choose AoE if there are 3 or more targets - AOEStrategy.AutoFinishCombo => comboStepsRemaining > 0 - ? doingAOECombo : AoETargets >= 3, //Continue combo if ongoing, otherwise switch to AoE if targets are sufficient - _ => false //Default to no AoE action if no matching strategy - }; - - //Reset combo steps if the desired action type doesn't match the current combo type - if (comboStepsRemaining > 0 && wantAOEAction != doingAOECombo) - comboStepsRemaining = 0; //Reset if we need to switch from AoE to single-target or vice versa - - //Determine the next action based on whether an AoE or single-target action is desired - var nextAction = wantAOEAction ? NextComboAoE() : NextComboSingleTarget(); - - //Return combo priority based on the ability to fit GCDs and remaining combo steps - if (comboStepsRemaining > 0 && !CanFitGCD(World.Client.ComboState.Remaining, 1)) - return (nextAction, GCDPriority.Combo123); //Return with priority if combo steps cannot fit - - //Return normal combo action priority based on action risks - return (nextAction, GCDPriority.Combo123); //Return the next action and its priority - } - - //Determines when to use Shield Lob for Ranged purposes + #region Cooldown Helpers private bool ShouldUseRangedLob(Actor? target, RangedStrategy strategy) => strategy switch { RangedStrategy.OpenerRanged => IsFirstGCD() && !In3y(target), //Use if it's the first GCD and target is not within 3y @@ -605,8 +662,6 @@ private void QueueOGCD(AID aid, Actor? target, OGCDPriority prio, float basePrio RangedStrategy.Forbid => false, //Delay usage _ => false }; - - //Determines when to use Holy Spirit for Ranged purposes private bool ShouldUseRangedCast(Actor? target, RangedStrategy strategy) => strategy switch { RangedStrategy.OpenerRangedCast => IsFirstGCD() && !In3y(target), //Use if it's the first GCD and target is not within 3y @@ -615,134 +670,153 @@ private void QueueOGCD(AID aid, Actor? target, OGCDPriority prio, float basePrio RangedStrategy.RangedCast => !In3y(target), //Use if target is not within 3y _ => false }; - - //Determines when to use Fight or Flight - private bool ShouldUseFightOrFlight(OffensiveStrategy strategy, Actor? target) => strategy switch - { - OffensiveStrategy.Automatic => - Player.InCombat && target != null && ActionReady(AID.FightOrFlight) && CombatTimer >= GCDLength * 2 + 0.5f, //Use if in combat, target is valid, action is ready - OffensiveStrategy.Force => true, //Force - OffensiveStrategy.Delay => false, //Delay usage + private bool ShouldUseFightOrFlight(OGCDStrategy strategy, Actor? target) => strategy switch + { + OGCDStrategy.Automatic => + Player.InCombat && + target != null && + FightOrFlight.IsReady && + CombatTimer >= GCDLength * 2 + 0.5f, + OGCDStrategy.Force => true, + OGCDStrategy.AnyWeave => canWeaveIn, + OGCDStrategy.EarlyWeave => canWeaveEarly, + OGCDStrategy.LateWeave => canWeaveLate, + OGCDStrategy.Delay => false, _ => false }; - - //Determines when to use Requiescat - private bool ShouldUseRequiescat(OffensiveStrategy strategy, Actor? target) => strategy switch - { - OffensiveStrategy.Automatic => - Player.InCombat && target != null && ActionReady(AID.Requiescat) && hasFoF, //Use if in combat, target is valid, action is ready, and has Fight or Flight - OffensiveStrategy.Force => true, //Force - OffensiveStrategy.Delay => false, //Delay usage + private bool ShouldUseRequiescat(OGCDStrategy strategy, Actor? target) => strategy switch + { + OGCDStrategy.Automatic => + Player.InCombat && + target != null && + Requiescat.IsReady && + FightOrFlight.IsActive, + OGCDStrategy.Force => true, + OGCDStrategy.AnyWeave => canWeaveIn, + OGCDStrategy.EarlyWeave => canWeaveEarly, + OGCDStrategy.LateWeave => canWeaveLate, + OGCDStrategy.Delay => false, _ => false }; - - //Determines when to use Spirits Within - private bool ShouldUseSpiritsWithin(OffensiveStrategy strategy, Actor? target) => strategy switch - { - OffensiveStrategy.Automatic => - Player.InCombat && In3y(target) && fofCD is < 57.55f and > 17 && //Use if in combat, target is in range, and cooldown is within limits - ActionReady(Unlocked(AID.Expiacion) ? AID.Expiacion : AID.SpiritsWithin), //Action is ready, prioritizing Expiacion if unlocked - OffensiveStrategy.Force => true, //Force - OffensiveStrategy.Delay => false, //Delay usage + private bool ShouldUseSpiritsWithin(OGCDStrategy strategy, Actor? target) => strategy switch + { + OGCDStrategy.Automatic => + Player.InCombat && + target != null && + In3y(target) && + FightOrFlight.CD is < 57.55f and > 17 && + SpiritsWithin.IsReady, + OGCDStrategy.Force => true, + OGCDStrategy.AnyWeave => canWeaveIn, + OGCDStrategy.EarlyWeave => canWeaveEarly, + OGCDStrategy.LateWeave => canWeaveLate, + OGCDStrategy.Delay => false, _ => false }; - - //Determines when to use Circle of Scorn - private bool ShouldUseCircleOfScorn(OffensiveStrategy strategy, Actor? target) => strategy switch - { - OffensiveStrategy.Automatic => - Player.InCombat && ActionReady(AID.CircleOfScorn) && In5y(target) && fofCD is < 57.55f and > 17, //Use if in combat, action is ready, target is within 5y, and cooldown is within limits - OffensiveStrategy.Force => true, //Force - OffensiveStrategy.Delay => false, //Delay usage + private bool ShouldUseCircleOfScorn(OGCDStrategy strategy, Actor? target) => strategy switch + { + OGCDStrategy.Automatic => + Player.InCombat && + target != null && + CircleOfScorn.IsReady && + In5y(target) && + FightOrFlight.CD is < 57.55f and > 17, + OGCDStrategy.Force => true, + OGCDStrategy.AnyWeave => canWeaveIn, + OGCDStrategy.EarlyWeave => canWeaveEarly, + OGCDStrategy.LateWeave => canWeaveLate, + OGCDStrategy.Delay => false, _ => false }; - - //Determines when to use Goring Blade - private bool ShouldUseGoringBlade(OffensiveStrategy strategy, Actor? target) => strategy switch - { - OffensiveStrategy.Automatic => - Player.InCombat && In3y(target) && hasFoF, //Use if in combat, target is in range, and has Fight or Flight active - OffensiveStrategy.Force => true, //Force - OffensiveStrategy.Delay => false, //Delay usage + private bool ShouldUseGoringBlade(GCDStrategy strategy, Actor? target) => strategy switch + { + GCDStrategy.Automatic => + Player.InCombat && + In3y(target) && + GoringBlade.IsReady && + FightOrFlight.IsActive, + GCDStrategy.Force => true, + GCDStrategy.Delay => false, _ => false }; - - //Determines when to use Blade Combo private bool ShouldUseBladeCombo(BladeComboStrategy strategy, Actor? target) => strategy switch { BladeComboStrategy.Automatic => - Player.InCombat && HasEffect(SID.ConfiteorReady) && hasFoF && BladeComboStep is 0, //Use if in combat, Confiteor is ready, has Fight or Flight, and it's the first step - BladeComboStrategy.ForceConfiteor => HasEffect(SID.ConfiteorReady) && BladeComboStep is 0, //Force use of Confiteor if ready and it's the first step - BladeComboStrategy.ForceFaith => BladeComboStep is 1, //Force use of Faith if it's the second step - BladeComboStrategy.ForceTruth => BladeComboStep is 2, //Force use of Truth if it's the third step - BladeComboStrategy.ForceValor => BladeComboStep is 3, //Force use of Valor if it's the fourth step - BladeComboStrategy.Delay => false, //Delay usage + Player.InCombat && + target != null && + In25y(target) && + Confiteor.IsReady && + FightOrFlight.IsActive && + BladeComboStep is 0, + BladeComboStrategy.ForceConfiteor => Confiteor.IsReady && BladeComboStep is 0, + BladeComboStrategy.ForceFaith => BladeComboStep is 1, + BladeComboStrategy.ForceTruth => BladeComboStep is 2, + BladeComboStrategy.ForceValor => BladeComboStep is 3, + BladeComboStrategy.Delay => false, _ => false }; - - //Determines when to use Atonement private bool ShouldUseAtonement(AtonementStrategy strategy, Actor? target) => strategy switch { AtonementStrategy.Automatic => - Player.InCombat && In3y(target) && HasEffect(SID.AtonementReady), //Use if in combat, target is in range, and Atonement is ready - AtonementStrategy.ForceAtonement => HasEffect(SID.AtonementReady), //Force use of Atonement if ready - AtonementStrategy.ForceSupplication => HasEffect(SID.SupplicationReady), //Force use of Supplication if ready - AtonementStrategy.ForceSepulchre => HasEffect(SID.SepulchreReady), //Force use of Sepulchre if ready - AtonementStrategy.Delay => false, //Delay usage + Player.InCombat && + target != null && + In3y(target) && + Atonement.IsReady || Supplication.IsReady || Sepulchre.IsReady, + AtonementStrategy.ForceAtonement => Atonement.IsReady, + AtonementStrategy.ForceSupplication => Supplication.IsReady, + AtonementStrategy.ForceSepulchre => Sepulchre.IsReady, + AtonementStrategy.Delay => false, _ => false }; - - //Determines when to use Holy Spirit - private bool ShouldUseHolySpirit(OffensiveStrategy strategy, Actor? target) => strategy switch - { - OffensiveStrategy.Automatic => - Player.InCombat && //Use if in combat - hasMight && hasMPforMight && !hasReq, //Check if we have Might, sufficient MP for Might, and not under Requiescat - OffensiveStrategy.Force => true, //Force - OffensiveStrategy.Delay => false, //Delay usage + private bool ShouldUseHoly(HolyStrategy strategy, Actor? target) => strategy switch + { + HolyStrategy.Automatic => + ShouldUseDMHolyCircle || ShouldNormalHolyCircle + ? ShouldUseHolyCircle(HolyStrategy.Automatic, target) + : ShouldUseHolySpirit(HolyStrategy.Automatic, target), + HolyStrategy.Spirit => HolySpirit.IsReady, + HolyStrategy.Circle => HolyCircle.IsReady, + HolyStrategy.Delay => false, _ => false }; - - //Determines when to use Holy Circle - private bool ShouldUseHolyCircle(OffensiveStrategy strategy, Actor? AoETargets) => strategy switch - { - OffensiveStrategy.Automatic => - Player.InCombat && //Use if in combat - hasMight && hasMPforMight && NumTargetsHitByAoE() >= 3 && !hasReq, //Check if we have Might, sufficient MP for Might, hit at least 3 targets, and not under Requiescat - OffensiveStrategy.Force => true, //Force - OffensiveStrategy.Delay => false, //Delay usage + private bool ShouldUseHolySpirit(HolyStrategy strategy, Actor? target) => strategy switch + { + HolyStrategy.Automatic => + Player.InCombat && //In combat + target != null && //Target exists + In25y(target) && //Target in range + HolyCircle.IsReady && //can execute Holy Circle + DivineMight.IsActive, //Divine Might is active + _ => false + }; + private bool ShouldUseHolyCircle(HolyStrategy strategy, Actor? target) => strategy switch + { + HolyStrategy.Automatic => + Player.InCombat && //In combat + target != null && //Target exists + In5y(target) && //Target in range + HolyCircle.IsReady && //can execute Holy Circle + DivineMight.IsActive, //Divine Might is active _ => false }; - - //Determines when to use Dash private bool ShouldUseDash(DashStrategy strategy, Actor? target) => strategy switch { DashStrategy.Automatic => - Player.InCombat && target != null && hasFoF, //Use in Fight or Flight - DashStrategy.Force => true, //Force - DashStrategy.Conserve1 => CD(AID.Intervene) > 30, //Use if cooldown is greater than 30 seconds - DashStrategy.GapClose => !In3y(target), //Use if target is out of range + Player.InCombat && + target != null && + FightOrFlight.IsActive, + DashStrategy.Force => true, + DashStrategy.Force1 => Intervene.TotalCD < 1f, + DashStrategy.GapClose => !In3y(target), + DashStrategy.GapClose1 => Intervene.TotalCD < 1f && !In3y(target), _ => false }; - - //Potion Helpers - //Determines if potions are aligned with buffs - private bool IsPotionAlignedWithNM() - { - //Use potion before FoF/Req in opener - //Use for 6m window - return ActionReady(AID.FightOrFlight) && - (ActionReady(AID.Requiescat) || //Opener - reqCD < 15); //Use if Requiescat is on cooldown for less than 15 seconds - } - - //Determines when to use a potion based on strategy private bool ShouldUsePotion(PotionStrategy strategy) => strategy switch { - PotionStrategy.AlignWithRaidBuffs => - IsPotionAlignedWithNM() || fofCD < 5 && reqCD < 15, //Align potions with major buffs + PotionStrategy.AlignWithRaidBuffs => FightOrFlight.CD < 5 && Requiescat.CD < 15, //Align potions with major buffs PotionStrategy.Immediate => true, //Force potion immediately _ => false, }; + #endregion } From 4f3289b8ecdd331d8227f8f2d606a4864a49b98b Mon Sep 17 00:00:00 2001 From: ace Date: Sat, 4 Jan 2025 18:40:46 -0800 Subject: [PATCH 02/17] PLD updated --- BossMod/Autorotation/akechi/AkechiPLD.cs | 192 ++++++++++++----------- 1 file changed, 102 insertions(+), 90 deletions(-) diff --git a/BossMod/Autorotation/akechi/AkechiPLD.cs b/BossMod/Autorotation/akechi/AkechiPLD.cs index 8dfb6d0747..205700d798 100644 --- a/BossMod/Autorotation/akechi/AkechiPLD.cs +++ b/BossMod/Autorotation/akechi/AkechiPLD.cs @@ -1,8 +1,4 @@ using FFXIVClientStructs.FFXIV.Client.Game.Gauge; -using System; -using System.Runtime.InteropServices; -using static BossMod.ActorCastEvent; -using static BossMod.Autorotation.akechi.AkechiGNB; using AID = BossMod.PLD.AID; using SID = BossMod.PLD.SID; @@ -15,27 +11,27 @@ public sealed class AkechiPLD(RotationModuleManager manager, Actor player) : Rot #region Enums public enum Track { - AoE, //Tracks both AoE and single-target actions + AOE, //Tracks both AOE and single-target rotations Cooldowns, //Tracks Cooldowns damage actions Potion, //Tracks potion usage - Atonement, //Tracks Atonement actions - BladeCombo, //Tracks Blade Combo actions + Atonement, //Tracks Atonement combo actions + BladeCombo, //Tracks Blade combo actions Holy, //Tracks Holy actions - Dash, //Tracks the use of Intervene + Dash, //Tracks Intervene Ranged, //Tracks ranged attacks - FightOrFlight, //Tracks Fight or Flight actions + FightOrFlight, //Tracks Fight or Flight Requiescat, //Tracks Requiescat actions SpiritsWithin, //Tracks Spirits Within actions - CircleOfScorn, //Tracks Circle of Scorn actions - GoringBlade, //Tracks Goring Blade actions - BladeOfHonor, //Tracks Blade of Honor actions + CircleOfScorn, //Tracks Circle of Scorn + GoringBlade, //Tracks Goring Blade + BladeOfHonor, //Tracks Blade of Honor } public enum AOEStrategy { AutoFinishCombo, //Automatically decide based on targets; finish combo first AutoBreakCombo, //Automatically decide based on targets; break combo if needed ForceST, //Force single-target rotation - ForceAoE //Force AoE rotation + ForceAOE //Force AOE rotation } public enum CooldownStrategy { @@ -113,28 +109,39 @@ public enum OGCDStrategy #region Module & Strategy Definitions public static RotationModuleDefinition Definition() { - var res = new RotationModuleDefinition("Akechi PLD", "Standard Rotation Module", "Standard rotation (Akechi)", "Akechi", RotationModuleQuality.Good, BitMask.Build((int)Class.GLA, (int)Class.PLD), 100); + var res = new RotationModuleDefinition("Akechi PLD", + "Standard Rotation Module", + "Standard rotation (Akechi)", + "Akechi", + RotationModuleQuality.Good, + BitMask.Build((int)Class.GLA, (int)Class.PLD), + 100); - res.Define(Track.AoE).As("AoE", uiPriority: 200) + //AOE definitions + res.Define(Track.AOE).As("AOE", uiPriority: 200) .AddOption(AOEStrategy.AutoFinishCombo, "Auto (Finish Combo)", "Auto-selects best rotation dependant on targets; Finishes combo first", supportedTargets: ActionTargets.Hostile) .AddOption(AOEStrategy.AutoBreakCombo, "Auto (Break Combo)", "Auto-selects best rotation dependant on targets; Breaks combo if needed", supportedTargets: ActionTargets.Hostile) - .AddOption(AOEStrategy.ForceST, "Use AoE", "Force single-target rotation") - .AddOption(AOEStrategy.ForceAoE, "Force AoE", "Force AoE rotation"); + .AddOption(AOEStrategy.ForceST, "Use AOE", "Force single-target rotation") + .AddOption(AOEStrategy.ForceAOE, "Force AOE", "Force AOE rotation"); + //Cooldown definitions res.Define(Track.Cooldowns).As("Cooldowns", uiPriority: 190) .AddOption(CooldownStrategy.Allow, "Allow", "Allow use of cooldowns") .AddOption(CooldownStrategy.Hold, "Hold", "Hold all cooldowns"); + //Potion definitions res.Define(Track.Potion).As("Potion", uiPriority: 180) .AddOption(PotionStrategy.Manual, "Manual", "Do not use potions automatically") .AddOption(PotionStrategy.AlignWithRaidBuffs, "Align With Raid Buffs", "Align potion usage with raid buffs", 270, 30, ActionTargets.Self) .AddOption(PotionStrategy.Immediate, "Immediate", "Use potions immediately when available", 270, 30, ActionTargets.Self) .AddAssociatedAction(ActionDefinitions.IDPotionStr); - res.Define(Track.Atonement).As("Atonement", "Atone", uiPriority: 160) + //Atonement Combo definitions + res.Define(Track.Atonement).As("Atonement", "Atones", uiPriority: 160) .AddOption(AtonementStrategy.Automatic, "Automatic", "Normal use of Atonement & it's combo") .AddOption(AtonementStrategy.ForceAtonement, "Force Atonement", "Force use of Atonement", 0, 30, ActionTargets.Hostile, 76) .AddOption(AtonementStrategy.ForceSupplication, "Force Supplication", "Force use of Supplication", 0, 0, ActionTargets.Hostile, 76) .AddOption(AtonementStrategy.ForceSepulchre, "Force Sepulchre", "Force use of Sepulchre", 0, 0, ActionTargets.Hostile, 76) .AddOption(AtonementStrategy.Delay, "Delay", "Delay use of Atonement & its combo chain", 0, 0, ActionTargets.None, 60) .AddAssociatedActions(AID.Atonement, AID.Supplication, AID.Sepulchre); + //Blade Combo definitions res.Define(Track.BladeCombo).As("Blade Combo", "Blades", uiPriority: 160) .AddOption(BladeComboStrategy.Automatic, "Automatic", "Normal use of Confiteor & Blades Combo") .AddOption(BladeComboStrategy.ForceConfiteor, "Force", "Force use of Confiteor", 0, 0, ActionTargets.Hostile, 80) @@ -143,12 +150,14 @@ public static RotationModuleDefinition Definition() .AddOption(BladeComboStrategy.ForceValor, "Force Valor", "Force use of Blade of Valor", 0, 0, ActionTargets.Hostile, 90) .AddOption(BladeComboStrategy.Delay, "Delay", "Delay use of Confiteor & Blade Combo", 0, 0, ActionTargets.None, 80) .AddAssociatedActions(AID.Confiteor, AID.BladeOfFaith, AID.BladeOfTruth, AID.BladeOfValor); - res.Define(Track.Holy).As("Holy Spirit / Circle", "Holy", uiPriority: 150) + //Holy action definitions + res.Define(Track.Holy).As("Holy Spirit / Circle", "Holy S/C", uiPriority: 150) .AddOption(HolyStrategy.Automatic, "Automatic", "Automatically choose which Holy action to use based on conditions") .AddOption(HolyStrategy.Spirit, "Spirit", "Force use of Holy Spirit", 0, 0, ActionTargets.Hostile, 64) .AddOption(HolyStrategy.Circle, "Circle", "Force use of Holy Circle", 0, 0, ActionTargets.Hostile, 72) .AddOption(HolyStrategy.Delay, "Delay", "Delay use of Holy actions", 0, 0, ActionTargets.None, 64) .AddAssociatedActions(AID.HolySpirit, AID.HolyCircle); + //Intervene definitions res.Define(Track.Dash).As("Intervene", "Dash", uiPriority: 150) .AddOption(DashStrategy.Automatic, "Automatic", "Normal use of Intervene") .AddOption(DashStrategy.Force, "Force", "Force use of Intervene", 30, 0, ActionTargets.Hostile, 66) @@ -157,6 +166,7 @@ public static RotationModuleDefinition Definition() .AddOption(DashStrategy.GapClose1, "Gap Close (Hold 1)", "Use as gap closer if outside melee range; Hold one charge for manual usage", 30, 0, ActionTargets.None, 66) .AddOption(DashStrategy.Delay, "Delay", "Delay use of Intervene", 0, 0, ActionTargets.None, 66) .AddAssociatedActions(AID.Intervene); + //Ranged attack definitions res.Define(Track.Ranged).As("Ranged", "Ranged", uiPriority: 140) .AddOption(RangedStrategy.OpenerRangedCast, "Opener (Cast)", "Use Holy Spirit at the start of combat if outside melee range", 0, 0, ActionTargets.Hostile, 64) .AddOption(RangedStrategy.OpenerCast, "Opener", "Use Holy Spirit at the start of combat regardless of range", 0, 0, ActionTargets.Hostile, 64) @@ -168,6 +178,7 @@ public static RotationModuleDefinition Definition() .AddOption(RangedStrategy.Ranged, "Ranged", "Use Shield Lob for ranged attacks", 0, 0, ActionTargets.Hostile, 15) .AddOption(RangedStrategy.Forbid, "Forbid", "Prohibit the use of ranged attacks", 0, 0, ActionTargets.Hostile, 15) .AddAssociatedActions(AID.ShieldLob, AID.HolySpirit); + //Fight or Flight definitions res.Define(Track.FightOrFlight).As("Fight or Flight", "F.Flight", uiPriority: 170) .AddOption(OGCDStrategy.Automatic, "Automatic", "Use Fight or Flight normally") .AddOption(OGCDStrategy.Force, "Force", "Force use of Fight or Flight", 60, 20, ActionTargets.Self, 2) @@ -176,14 +187,16 @@ public static RotationModuleDefinition Definition() .AddOption(OGCDStrategy.LateWeave, "Late Weave", "Force use of Fight or Flight in the last weave slot", 60, 20, ActionTargets.Self, 2) .AddOption(OGCDStrategy.Delay, "Delay", "Delay use of Fight or Flight", 0, 0, ActionTargets.None, 2) .AddAssociatedActions(AID.FightOrFlight); + //Requiescat definitions res.Define(Track.Requiescat).As("Requiescat", "R.scat", uiPriority: 170) .AddOption(OGCDStrategy.Automatic, "Automatic", "Use Requiescat normally") - .AddOption(OGCDStrategy.Force, "Force", "Force use of Requiescat / Imperator", 60, 20, ActionTargets.Self, 68) - .AddOption(OGCDStrategy.AnyWeave, "Any Weave", "Force use of Requiescat / Imperator in any weave slot", 60, 20, ActionTargets.Self, 68) - .AddOption(OGCDStrategy.EarlyWeave, "Early Weave", "Force use of Requiescat / Imperator in the first weave slot", 60, 20, ActionTargets.Self, 68) - .AddOption(OGCDStrategy.LateWeave, "Late Weave", "Force use of Requiescat / Imperator in the last weave slot", 60, 20, ActionTargets.Self, 68) + .AddOption(OGCDStrategy.Force, "Force", "Force use of Requiescat / Imperator", 60, 30, ActionTargets.Self, 68) + .AddOption(OGCDStrategy.AnyWeave, "Any Weave", "Force use of Requiescat / Imperator in any weave slot", 60, 30, ActionTargets.Self, 68) + .AddOption(OGCDStrategy.EarlyWeave, "Early Weave", "Force use of Requiescat / Imperator in the first weave slot", 60, 30, ActionTargets.Self, 68) + .AddOption(OGCDStrategy.LateWeave, "Late Weave", "Force use of Requiescat / Imperator in the last weave slot", 60, 30, ActionTargets.Self, 68) .AddOption(OGCDStrategy.Delay, "Delay", "Delay use of Requiescat / Imperator", 0, 0, ActionTargets.None, 68) .AddAssociatedActions(AID.Requiescat, AID.Imperator); + //Spirits Within definitions res.Define(Track.SpiritsWithin).As("Spirits Within", "S.Within", uiPriority: 150) .AddOption(OGCDStrategy.Automatic, "Automatic", "Use Spirits Within normally") .AddOption(OGCDStrategy.Force, "Force", "Force use of Spirits Within / Expiacion", 30, 0, ActionTargets.Hostile, 30) @@ -192,19 +205,22 @@ public static RotationModuleDefinition Definition() .AddOption(OGCDStrategy.LateWeave, "Late Weave", "Force use of Spirits Within / Expiacion in the last weave slot", 30, 0, ActionTargets.Hostile, 30) .AddOption(OGCDStrategy.Delay, "Delay", "Delay use of Spirits Within / Expiacion", 0, 0, ActionTargets.None, 30) .AddAssociatedActions(AID.SpiritsWithin, AID.Expiacion); + //Circle of Scorn definitions res.Define(Track.CircleOfScorn).As("Circle of Scorn", "C.Scorn", uiPriority: 150) .AddOption(OGCDStrategy.Automatic, "Automatic", "Use Circle of Scorn normally") - .AddOption(OGCDStrategy.Force, "Force", "Force use of Circle of Scorn ASAP", 60, 15, ActionTargets.Hostile, 50) - .AddOption(OGCDStrategy.AnyWeave, "Any Weave", "Force use of Circle of Scorn in any weave slot", 60, 15, ActionTargets.Hostile, 50) - .AddOption(OGCDStrategy.EarlyWeave, "Early Weave", "Force use of Circle of Scorn in the first weave slot", 60, 15, ActionTargets.Hostile, 50) - .AddOption(OGCDStrategy.LateWeave, "Late Weave", "Force use of Circle of Scorn in the last weave slot", 60, 15, ActionTargets.Hostile, 50) + .AddOption(OGCDStrategy.Force, "Force", "Force use of Circle of Scorn ASAP", 30, 15, ActionTargets.Hostile, 50) + .AddOption(OGCDStrategy.AnyWeave, "Any Weave", "Force use of Circle of Scorn in any weave slot", 30, 15, ActionTargets.Hostile, 50) + .AddOption(OGCDStrategy.EarlyWeave, "Early Weave", "Force use of Circle of Scorn in the first weave slot", 30, 15, ActionTargets.Hostile, 50) + .AddOption(OGCDStrategy.LateWeave, "Late Weave", "Force use of Circle of Scorn in the last weave slot", 30, 15, ActionTargets.Hostile, 50) .AddOption(OGCDStrategy.Delay, "Delay", "Delay use of Circle of Scorn", 0, 0, ActionTargets.None, 50) .AddAssociatedActions(AID.CircleOfScorn); + //Goring Blade definitions res.Define(Track.GoringBlade).As("Goring Blade", "G.Blade", uiPriority: 150) .AddOption(GCDStrategy.Automatic, "Automatic", "Use Goring Blade normally") - .AddOption(GCDStrategy.Force, "Force", "Force use of Goring Blade ASAP", 0, 30, ActionTargets.Hostile, 54) + .AddOption(GCDStrategy.Force, "Force", "Force use of Goring Blade ASAP", 0, 0, ActionTargets.Hostile, 54) .AddOption(GCDStrategy.Delay, "Delay", "Delay use of Goring Blade", 0, 0, ActionTargets.None, 54) .AddAssociatedActions(AID.GoringBlade); + //Blade of Honor definitions res.Define(Track.BladeOfHonor).As("Blade of Honor", "B.Honor", uiPriority: 150) .AddOption(OGCDStrategy.Automatic, "Automatic", "Use Blade of Honor normally") .AddOption(OGCDStrategy.Force, "Force", "Force use of Blade of Honor ASAP", 0, 0, ActionTargets.Hostile, 100) @@ -223,26 +239,21 @@ public static RotationModuleDefinition Definition() public enum GCDPriority //Priority for GCDs used { None = 0, - Combo123 = 350, - NormalGCD = 450, - HolyCircle = 490, - HolySpirit = 500, - Atonement = 580, - GoringBlade = 590, - Valor = 600, - Truth = 610, - Faith = 620, - Confiteor = 650, + Combo123 = 300, + HolySpirit = 400, + Atonement = 500, + GoringBlade = 600, + Blades = 700, ForcedGCD = 900, } public enum OGCDPriority //Priority for oGCDs used { None = 0, - BladeOfHonor = 520, - Intervene = 530, - SpiritsWithin = 540, + BladeOfHonor = 400, + Intervene = 450, + SpiritsWithin = 500, CircleOfScorn = 550, - Requiescat = 650, + Requiescat = 600, FightOrFlight = 700, ForcedOGCD = 900, Potion = 910, @@ -250,7 +261,6 @@ public static RotationModuleDefinition Definition() #endregion #region Variables - public int Oath; //Current value of the oath gauge public int BladeComboStep; //Current step in the Confiteor combo sequence public float GCDLength; //Length of the global cooldown, adjusted by skill speed and haste (baseline: 2.5s) @@ -265,7 +275,7 @@ public static RotationModuleDefinition Definition() public (float CD, bool IsReady) CircleOfScorn; //Conditions for Circle of Scorn ability public (float CD, float Left, bool IsReady, bool IsActive) GoringBlade; //Conditions for Goring Blade ability public (float TotalCD, bool HasCharges, bool IsReady) Intervene; //Conditions for Intervene ability - public (float CD, int Stacks, bool IsReady, bool IsActive) Requiescat; //Conditions for Requiescat ability + public (float CD, float Left, bool IsReady, bool IsActive) Requiescat; //Conditions for Requiescat ability public (float Left, bool IsReady, bool IsActive) Atonement; //Conditions for Atonement ability public (float Left, bool IsReady, bool IsActive) Supplication; //Conditions for Supplication ability public (float Left, bool IsReady, bool IsActive) Sepulchre; //Conditions for Sepulchre ability @@ -281,7 +291,6 @@ public static RotationModuleDefinition Definition() public bool canWeaveIn; //Can weave in oGCDs public bool canWeaveEarly; //Can early weave oGCDs public bool canWeaveLate; //Can late weave oGCDs - private delegate bool PositionCheck(Actor playerTarget, Actor targetToTest); #endregion #region Module Helpers @@ -292,15 +301,15 @@ public static RotationModuleDefinition Definition() private AID ComboLastMove => (AID)World.Client.ComboState.Action; //Get the last action used in the combo sequence private bool In3y(Actor? target) => Player.DistanceToHitbox(target) <= 2.99f; //Check if the target is within ST melee range (3 yalms) private bool In5y(Actor? target) => Player.DistanceToHitbox(target) <= 4.99f; //Check if the target is within AOE melee range (5 yalms) - private bool In20y(Actor? target) => Player.DistanceToHitbox(target) <= 19.99f; //Check if the target is within 20 yalms private bool In25y(Actor? target) => Player.DistanceToHitbox(target) <= 24.99f; //Check if the target is within 25 yalms private bool IsFirstGCD() => !Player.InCombat || (World.CurrentTime - Manager.CombatStart).TotalSeconds < 0.1f; //Check if this is the first GCD in combat - private int TargetsHitByPlayerAOE() => Hints.NumPriorityTargetsInAOECircle(Player.Position, 5); //Returns the number of targets hit by AoE within a 5-yalm radius around the player - private int TargetsHitByTargetAOE(Actor? target) => Hints.NumPriorityTargetsInAOECircle(target!.Position, 5); //Returns the number of targets hit by AoE within a 5-yalm radius around the target - private PositionCheck IsSplashTarget => (Actor primary, Actor other) => Hints.TargetInAOECircle(other, primary.Position, 5); + private int TargetsHitByPlayerAOE() => Hints.NumPriorityTargetsInAOECircle(Player.Position, 5); //Returns the number of targets hit by AOE within a 5-yalm radius around the player public bool HasEffect(SID sid) => SelfStatusLeft(sid) > 0; //Checks if Status effect is on self public float CombatTimer => (float)(World.CurrentTime - Manager.CombatStart).TotalSeconds; //Calculates the elapsed time since combat started in seconds public Actor? TargetChoice(StrategyValues.OptionRef strategy) => ResolveTargetOverride(strategy.Value); + + //TODO: add better targeting for Blades + //public Actor? BestSplashTarget() #endregion #region Upgrade Paths @@ -360,9 +369,9 @@ public override void Execute(StrategyValues strategy, Actor? primaryTarget, floa Intervene.HasCharges = Intervene.TotalCD <= 30f; //Check if the player has charges of Intervene Intervene.IsReady = Unlocked(AID.Intervene) && Intervene.HasCharges; //Intervene ability Requiescat.CD = CD(BestRequiescat); //Remaining cooldown for the Requiescat ability - Requiescat.Stacks = SelfStatusDetails(SID.Requiescat).Stacks; //Get the current number of Requiescat stacks - Requiescat.IsActive = Requiescat.Stacks > 0; //Check if the Requiescat buff is active - Requiescat.IsReady = Unlocked(AID.Requiescat) && Requiescat.IsActive; //Requiescat ability + Requiescat.Left = SelfStatusLeft(SID.Requiescat, 30); //Get the current number of Requiescat stacks + Requiescat.IsActive = Requiescat.Left > 0; //Check if the Requiescat buff is active + Requiescat.IsReady = Unlocked(AID.Requiescat) && Requiescat.CD < 0.6f; //Requiescat ability Atonement.Left = SelfStatusLeft(SID.AtonementReady, 30); //Remaining duration of the Atonement buff Atonement.IsActive = Atonement.Left > 0; //Check if the Atonement buff is active Atonement.IsReady = Unlocked(AID.Atonement) && Atonement.IsActive; //Atonement ability @@ -375,7 +384,6 @@ public override void Execute(StrategyValues strategy, Actor? primaryTarget, floa Confiteor.Left = SelfStatusLeft(SID.ConfiteorReady, 30); //Remaining duration of the Confiteor buff Confiteor.IsActive = Confiteor.Left > 0; //Check if the Confiteor buff is active Confiteor.IsReady = Unlocked(AID.Confiteor) && Confiteor.IsActive && MP >= 1000; //Confiteor ability - var canBlade = Unlocked(AID.BladeOfValor) && BladeComboStep is not 0; //Blade abilities, only if combo step is not zero BladeOfHonor.Left = SelfStatusLeft(SID.BladeOfHonorReady, 30); //Remaining duration of the Blade of Honor buff BladeOfHonor.IsActive = BladeOfHonor.Left > 0; //Check if the Blade of Honor buff is active BladeOfHonor.IsReady = Unlocked(AID.BladeOfHonor) && IsOffCooldown(AID.BladeOfHonor); //Blade of Honor ability @@ -395,7 +403,7 @@ public override void Execute(StrategyValues strategy, Actor? primaryTarget, floa ShouldUseDMHolyCircle = DivineMight.IsActive && TargetsHitByPlayerAOE() > 2; #region Strategy Options - var AOE = strategy.Option(Track.AoE); //Retrieves AOE track + var AOE = strategy.Option(Track.AOE); //Retrieves AOE track var AOEStrategy = AOE.As(); //Retrieves AOE strategy var cd = strategy.Option(Track.Cooldowns); //Retrieves Cooldowns track var cdStrat = cd.As(); //Retrieves Cooldowns strategy @@ -519,29 +527,24 @@ gbStrat is GCDStrategy.Force : GCDPriority.GoringBlade); } - if (canBlade && - ShouldUseBladeCombo(bladeStrat, primaryTarget)) + if (ShouldUseBladeCombo(bladeStrat, primaryTarget)) { if (bladeStrat is BladeComboStrategy.Automatic) QueueGCD(BestBlade, TargetChoice(blade) ?? primaryTarget, - GCDPriority.Confiteor); + GCDPriority.Blades); if (bladeStrat is BladeComboStrategy.ForceFaith) QueueGCD(AID.BladeOfFaith, TargetChoice(blade) ?? primaryTarget, GCDPriority.ForcedGCD); - if (BladeComboStep is 2) + if (bladeStrat is BladeComboStrategy.ForceTruth) QueueGCD(AID.BladeOfTruth, TargetChoice(blade) ?? primaryTarget, - bladeStrat is BladeComboStrategy.ForceTruth - ? GCDPriority.ForcedGCD - : GCDPriority.Truth); - if (BladeComboStep is 3) + GCDPriority.ForcedGCD); + if (bladeStrat is BladeComboStrategy.ForceValor) QueueGCD(AID.BladeOfValor, TargetChoice(blade) ?? primaryTarget, - bladeStrat is BladeComboStrategy.ForceValor - ? GCDPriority.ForcedGCD - : GCDPriority.Valor); + GCDPriority.ForcedGCD); } if (ShouldUseAtonement(atoneStrat, primaryTarget)) { @@ -566,8 +569,9 @@ bladeStrat is BladeComboStrategy.ForceValor if (ShouldUseHoly(holyStrat, primaryTarget)) { + var HSoverAtone = FightOrFlight.Left is <= 2.5f and >= 0.01f && !Supplication.IsActive && !Sepulchre.IsActive; if (holyStrat == HolyStrategy.Automatic) - QueueGCD(BestHoly, TargetChoice(holy) ?? primaryTarget, GCDPriority.HolySpirit); + QueueGCD(BestHoly, TargetChoice(holy) ?? primaryTarget, HSoverAtone ? GCDPriority.GoringBlade : GCDPriority.HolySpirit); if (holyStrat == HolyStrategy.Spirit) QueueGCD(AID.HolySpirit, TargetChoice(holy) ?? primaryTarget, GCDPriority.ForcedGCD); if (holyStrat == HolyStrategy.Circle) @@ -578,8 +582,14 @@ bladeStrat is BladeComboStrategy.ForceValor QueueGCD(AID.ShieldLob, TargetChoice(ranged) ?? primaryTarget, rangedStrat is RangedStrategy.Force ? GCDPriority.ForcedGCD : GCDPriority.Combo123); if (ShouldUseRangedCast(primaryTarget, rangedStrat)) QueueGCD(AID.HolySpirit, TargetChoice(ranged) ?? primaryTarget, rangedStrat is RangedStrategy.ForceCast ? GCDPriority.ForcedGCD : GCDPriority.Combo123); - if (ShouldUsePotion(strategy.Option(Track.Potion).As())) - Hints.ActionsToExecute.Push(ActionDefinitions.IDPotionStr, Player, ActionQueue.Priority.VeryHigh + (int)OGCDPriority.Potion, 0, GCD - 0.9f); + + if (ShouldUsePotion(potStrat)) + Hints.ActionsToExecute.Push( + ActionDefinitions.IDPotionStr, + Player, + ActionQueue.Priority.VeryHigh + (int)OGCDPriority.Potion, + 0, + GCD - 0.9f); #endregion } @@ -646,8 +656,8 @@ public bool QueueAction(AID aid, Actor? target, float priority, float delay) AID.RiotBlade => RotationST(), AID.FastBlade => RotationST(), //AOE - AID.TotalEclipse => ShouldUseAOE ? RotationAOE() : RotationST(), - AID.Prominence => RotationAOE(), + AID.Prominence => ShouldUseAOE ? RotationAOE() : RotationST(), + AID.TotalEclipse => RotationAOE(), _ => ShouldUseAOE ? RotationAOE() : RotationST(), }; #endregion @@ -677,10 +687,10 @@ public bool QueueAction(AID aid, Actor? target, float priority, float delay) target != null && FightOrFlight.IsReady && CombatTimer >= GCDLength * 2 + 0.5f, - OGCDStrategy.Force => true, - OGCDStrategy.AnyWeave => canWeaveIn, - OGCDStrategy.EarlyWeave => canWeaveEarly, - OGCDStrategy.LateWeave => canWeaveLate, + OGCDStrategy.Force => FightOrFlight.IsReady, + OGCDStrategy.AnyWeave => FightOrFlight.IsReady && canWeaveIn, + OGCDStrategy.EarlyWeave => FightOrFlight.IsReady && canWeaveEarly, + OGCDStrategy.LateWeave => FightOrFlight.IsReady && canWeaveLate, OGCDStrategy.Delay => false, _ => false }; @@ -691,10 +701,10 @@ public bool QueueAction(AID aid, Actor? target, float priority, float delay) target != null && Requiescat.IsReady && FightOrFlight.IsActive, - OGCDStrategy.Force => true, - OGCDStrategy.AnyWeave => canWeaveIn, - OGCDStrategy.EarlyWeave => canWeaveEarly, - OGCDStrategy.LateWeave => canWeaveLate, + OGCDStrategy.Force => Requiescat.IsReady, + OGCDStrategy.AnyWeave => Requiescat.IsReady && canWeaveIn, + OGCDStrategy.EarlyWeave => Requiescat.IsReady && canWeaveEarly, + OGCDStrategy.LateWeave => Requiescat.IsReady && canWeaveLate, OGCDStrategy.Delay => false, _ => false }; @@ -706,10 +716,10 @@ public bool QueueAction(AID aid, Actor? target, float priority, float delay) In3y(target) && FightOrFlight.CD is < 57.55f and > 17 && SpiritsWithin.IsReady, - OGCDStrategy.Force => true, - OGCDStrategy.AnyWeave => canWeaveIn, - OGCDStrategy.EarlyWeave => canWeaveEarly, - OGCDStrategy.LateWeave => canWeaveLate, + OGCDStrategy.Force => SpiritsWithin.IsReady, + OGCDStrategy.AnyWeave => SpiritsWithin.IsReady && canWeaveIn, + OGCDStrategy.EarlyWeave => SpiritsWithin.IsReady && canWeaveEarly, + OGCDStrategy.LateWeave => SpiritsWithin.IsReady && canWeaveLate, OGCDStrategy.Delay => false, _ => false }; @@ -721,10 +731,10 @@ FightOrFlight.CD is < 57.55f and > 17 && CircleOfScorn.IsReady && In5y(target) && FightOrFlight.CD is < 57.55f and > 17, - OGCDStrategy.Force => true, - OGCDStrategy.AnyWeave => canWeaveIn, - OGCDStrategy.EarlyWeave => canWeaveEarly, - OGCDStrategy.LateWeave => canWeaveLate, + OGCDStrategy.Force => CircleOfScorn.IsReady, + OGCDStrategy.AnyWeave => CircleOfScorn.IsReady && canWeaveIn, + OGCDStrategy.EarlyWeave => CircleOfScorn.IsReady && canWeaveEarly, + OGCDStrategy.LateWeave => CircleOfScorn.IsReady && canWeaveLate, OGCDStrategy.Delay => false, _ => false }; @@ -735,7 +745,7 @@ FightOrFlight.CD is < 57.55f and > 17 && In3y(target) && GoringBlade.IsReady && FightOrFlight.IsActive, - GCDStrategy.Force => true, + GCDStrategy.Force => GoringBlade.IsReady, GCDStrategy.Delay => false, _ => false }; @@ -745,9 +755,9 @@ FightOrFlight.CD is < 57.55f and > 17 && Player.InCombat && target != null && In25y(target) && - Confiteor.IsReady && FightOrFlight.IsActive && - BladeComboStep is 0, + Requiescat.IsActive && + BladeComboStep is 0 or 1 or 2 or 3, BladeComboStrategy.ForceConfiteor => Confiteor.IsReady && BladeComboStep is 0, BladeComboStrategy.ForceFaith => BladeComboStep is 1, BladeComboStrategy.ForceTruth => BladeComboStep is 2, @@ -804,6 +814,8 @@ FightOrFlight.CD is < 57.55f and > 17 && DashStrategy.Automatic => Player.InCombat && target != null && + In3y(target) && + Intervene.IsReady && FightOrFlight.IsActive, DashStrategy.Force => true, DashStrategy.Force1 => Intervene.TotalCD < 1f, @@ -813,7 +825,7 @@ FightOrFlight.CD is < 57.55f and > 17 && }; private bool ShouldUsePotion(PotionStrategy strategy) => strategy switch { - PotionStrategy.AlignWithRaidBuffs => FightOrFlight.CD < 5 && Requiescat.CD < 15, //Align potions with major buffs + PotionStrategy.AlignWithRaidBuffs => FightOrFlight.CD < 5, //Align potions with buffs PotionStrategy.Immediate => true, //Force potion immediately _ => false, }; From deccd7f0e02d2517ce628d1f91bebdb2d9ef2565 Mon Sep 17 00:00:00 2001 From: ace Date: Sat, 4 Jan 2025 18:42:43 -0800 Subject: [PATCH 03/17] . --- BossMod/Autorotation/akechi/AkechiPLD.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BossMod/Autorotation/akechi/AkechiPLD.cs b/BossMod/Autorotation/akechi/AkechiPLD.cs index 205700d798..1732f9fb0f 100644 --- a/BossMod/Autorotation/akechi/AkechiPLD.cs +++ b/BossMod/Autorotation/akechi/AkechiPLD.cs @@ -137,7 +137,7 @@ public static RotationModuleDefinition Definition() res.Define(Track.Atonement).As("Atonement", "Atones", uiPriority: 160) .AddOption(AtonementStrategy.Automatic, "Automatic", "Normal use of Atonement & it's combo") .AddOption(AtonementStrategy.ForceAtonement, "Force Atonement", "Force use of Atonement", 0, 30, ActionTargets.Hostile, 76) - .AddOption(AtonementStrategy.ForceSupplication, "Force Supplication", "Force use of Supplication", 0, 0, ActionTargets.Hostile, 76) + .AddOption(AtonementStrategy.ForceSupplication, "Force Supplication", "Force use of Supplication", 0, 30, ActionTargets.Hostile, 76) .AddOption(AtonementStrategy.ForceSepulchre, "Force Sepulchre", "Force use of Sepulchre", 0, 0, ActionTargets.Hostile, 76) .AddOption(AtonementStrategy.Delay, "Delay", "Delay use of Atonement & its combo chain", 0, 0, ActionTargets.None, 60) .AddAssociatedActions(AID.Atonement, AID.Supplication, AID.Sepulchre); From 33afc2a1e5644744274cd5d7d5c81d5c467111af Mon Sep 17 00:00:00 2001 From: ace Date: Sat, 4 Jan 2025 20:22:40 -0800 Subject: [PATCH 04/17] . --- BossMod/Autorotation/akechi/AkechiPLD.cs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/BossMod/Autorotation/akechi/AkechiPLD.cs b/BossMod/Autorotation/akechi/AkechiPLD.cs index 1732f9fb0f..34ffbef413 100644 --- a/BossMod/Autorotation/akechi/AkechiPLD.cs +++ b/BossMod/Autorotation/akechi/AkechiPLD.cs @@ -121,7 +121,7 @@ public static RotationModuleDefinition Definition() res.Define(Track.AOE).As("AOE", uiPriority: 200) .AddOption(AOEStrategy.AutoFinishCombo, "Auto (Finish Combo)", "Auto-selects best rotation dependant on targets; Finishes combo first", supportedTargets: ActionTargets.Hostile) .AddOption(AOEStrategy.AutoBreakCombo, "Auto (Break Combo)", "Auto-selects best rotation dependant on targets; Breaks combo if needed", supportedTargets: ActionTargets.Hostile) - .AddOption(AOEStrategy.ForceST, "Use AOE", "Force single-target rotation") + .AddOption(AOEStrategy.ForceST, "Use AOE", "Force single-target rotation", supportedTargets: ActionTargets.Hostile) .AddOption(AOEStrategy.ForceAOE, "Force AOE", "Force AOE rotation"); //Cooldown definitions res.Define(Track.Cooldowns).As("Cooldowns", uiPriority: 190) @@ -190,10 +190,10 @@ public static RotationModuleDefinition Definition() //Requiescat definitions res.Define(Track.Requiescat).As("Requiescat", "R.scat", uiPriority: 170) .AddOption(OGCDStrategy.Automatic, "Automatic", "Use Requiescat normally") - .AddOption(OGCDStrategy.Force, "Force", "Force use of Requiescat / Imperator", 60, 30, ActionTargets.Self, 68) - .AddOption(OGCDStrategy.AnyWeave, "Any Weave", "Force use of Requiescat / Imperator in any weave slot", 60, 30, ActionTargets.Self, 68) - .AddOption(OGCDStrategy.EarlyWeave, "Early Weave", "Force use of Requiescat / Imperator in the first weave slot", 60, 30, ActionTargets.Self, 68) - .AddOption(OGCDStrategy.LateWeave, "Late Weave", "Force use of Requiescat / Imperator in the last weave slot", 60, 30, ActionTargets.Self, 68) + .AddOption(OGCDStrategy.Force, "Force", "Force use of Requiescat / Imperator", 60, 30, ActionTargets.Hostile, 68) + .AddOption(OGCDStrategy.AnyWeave, "Any Weave", "Force use of Requiescat / Imperator in any weave slot", 60, 30, ActionTargets.Hostile, 68) + .AddOption(OGCDStrategy.EarlyWeave, "Early Weave", "Force use of Requiescat / Imperator in the first weave slot", 60, 30, ActionTargets.Hostile, 68) + .AddOption(OGCDStrategy.LateWeave, "Late Weave", "Force use of Requiescat / Imperator in the last weave slot", 60, 30, ActionTargets.Hostile, 68) .AddOption(OGCDStrategy.Delay, "Delay", "Delay use of Requiescat / Imperator", 0, 0, ActionTargets.None, 68) .AddAssociatedActions(AID.Requiescat, AID.Imperator); //Spirits Within definitions @@ -208,10 +208,10 @@ public static RotationModuleDefinition Definition() //Circle of Scorn definitions res.Define(Track.CircleOfScorn).As("Circle of Scorn", "C.Scorn", uiPriority: 150) .AddOption(OGCDStrategy.Automatic, "Automatic", "Use Circle of Scorn normally") - .AddOption(OGCDStrategy.Force, "Force", "Force use of Circle of Scorn ASAP", 30, 15, ActionTargets.Hostile, 50) - .AddOption(OGCDStrategy.AnyWeave, "Any Weave", "Force use of Circle of Scorn in any weave slot", 30, 15, ActionTargets.Hostile, 50) - .AddOption(OGCDStrategy.EarlyWeave, "Early Weave", "Force use of Circle of Scorn in the first weave slot", 30, 15, ActionTargets.Hostile, 50) - .AddOption(OGCDStrategy.LateWeave, "Late Weave", "Force use of Circle of Scorn in the last weave slot", 30, 15, ActionTargets.Hostile, 50) + .AddOption(OGCDStrategy.Force, "Force", "Force use of Circle of Scorn ASAP", 30, 15, ActionTargets.Self, 50) + .AddOption(OGCDStrategy.AnyWeave, "Any Weave", "Force use of Circle of Scorn in any weave slot", 30, 15, ActionTargets.Self, 50) + .AddOption(OGCDStrategy.EarlyWeave, "Early Weave", "Force use of Circle of Scorn in the first weave slot", 30, 15, ActionTargets.Self, 50) + .AddOption(OGCDStrategy.LateWeave, "Late Weave", "Force use of Circle of Scorn in the last weave slot", 30, 15, ActionTargets.Self, 50) .AddOption(OGCDStrategy.Delay, "Delay", "Delay use of Circle of Scorn", 0, 0, ActionTargets.None, 50) .AddAssociatedActions(AID.CircleOfScorn); //Goring Blade definitions From 5e7960a4ffee395de045ec976d6ead4e7ac678b6 Mon Sep 17 00:00:00 2001 From: AceAkechi123 Date: Sat, 4 Jan 2025 23:28:38 -0800 Subject: [PATCH 05/17] final touchups --- BossMod/Autorotation/akechi/AkechiPLD.cs | 524 ++++++++++++----------- 1 file changed, 273 insertions(+), 251 deletions(-) diff --git a/BossMod/Autorotation/akechi/AkechiPLD.cs b/BossMod/Autorotation/akechi/AkechiPLD.cs index 34ffbef413..bb9f0735d2 100644 --- a/BossMod/Autorotation/akechi/AkechiPLD.cs +++ b/BossMod/Autorotation/akechi/AkechiPLD.cs @@ -296,8 +296,6 @@ public static RotationModuleDefinition Definition() #region Module Helpers private bool Unlocked(AID aid) => ActionUnlocked(ActionID.MakeSpell(aid)); //Check if the desired ability is unlocked private float CD(AID aid) => World.Client.Cooldowns[ActionDefinitions.Instance.Spell(aid)!.MainCooldownGroup].Remaining; //Get remaining cooldown time for the specified action - private bool IsOffCooldown(AID aid) => World.Client.Cooldowns[ActionDefinitions.Instance.Spell(aid)!.MainCooldownGroup].Remaining < 0.6f; //Check if the desired action is ready (cooldown less than 0.6 seconds) - private bool ActionReady(AID aid) => Unlocked(aid) && IsOffCooldown(aid); //Check if the desired action is unlocked and off cooldown private AID ComboLastMove => (AID)World.Client.ComboState.Action; //Get the last action used in the combo sequence private bool In3y(Actor? target) => Player.DistanceToHitbox(target) <= 2.99f; //Check if the target is within ST melee range (3 yalms) private bool In5y(Actor? target) => Player.DistanceToHitbox(target) <= 4.99f; //Check if the target is within AOE melee range (5 yalms) @@ -306,7 +304,7 @@ public static RotationModuleDefinition Definition() private int TargetsHitByPlayerAOE() => Hints.NumPriorityTargetsInAOECircle(Player.Position, 5); //Returns the number of targets hit by AOE within a 5-yalm radius around the player public bool HasEffect(SID sid) => SelfStatusLeft(sid) > 0; //Checks if Status effect is on self public float CombatTimer => (float)(World.CurrentTime - Manager.CombatStart).TotalSeconds; //Calculates the elapsed time since combat started in seconds - public Actor? TargetChoice(StrategyValues.OptionRef strategy) => ResolveTargetOverride(strategy.Value); + public Actor? TargetChoice(StrategyValues.OptionRef strategy) => ResolveTargetOverride(strategy.Value); //Resolves the target choice based on the strategy //TODO: add better targeting for Blades //public Actor? BestSplashTarget() @@ -323,7 +321,7 @@ public AID BestRequiescat : AID.Requiescat; //otherwise use Requiescat public AID BestHoly => ShouldUseDMHolyCircle || ShouldNormalHolyCircle //if Holy Circle should be used - ? AID.HolyCircle //then use Holy Circle + ? BestHolyCircle //then use Holy Circle : AID.HolySpirit; //otherwise use Holy Spirit public AID BestHolyCircle //for AOE use from Lv64-Lv71 => HolyCircle.IsReady //if Holy Circle is ready @@ -336,31 +334,31 @@ public AID BestAtonement ? AID.Supplication //then use Supplication : AID.Atonement; //otherwise use Atonement public AID BestBlade - => BladeComboStep is 3 - ? AID.BladeOfValor - : BladeComboStep is 2 - ? AID.BladeOfTruth - : BladeComboStep is 1 - ? AID.BladeOfFaith - : AID.Confiteor; + => BladeComboStep is 3 //if Confiteor combo is at step 3 + ? AID.BladeOfValor //then use Blade of Valor + : BladeComboStep is 2 //if Confiteor combo is at step 2 + ? AID.BladeOfTruth //then use Blade of Truth + : BladeComboStep is 1 //if Confiteor combo is at step 1 + ? AID.BladeOfFaith //then use Blade of Faith + : AID.Confiteor; //otherwise use Confiteor #endregion public override void Execute(StrategyValues strategy, Actor? primaryTarget, float estimatedAnimLockDelay, bool isMoving) //Executes our actions { #region Variables - var gauge = World.Client.GetGauge(); //Retrieve current Paladin gauge - Oath = gauge.OathGauge; //Get the current value of the Oath gauge - BladeComboStep = gauge.ConfiteorComboStep; //Get the current step in the Confiteor/Blades combo - MP = Player.HPMP.CurMP; //Current mana points (MP) of the player + var gauge = World.Client.GetGauge(); //Retrieve Paladin gauge + Oath = gauge.OathGauge; //Retrieve current Oath gauge + BladeComboStep = gauge.ConfiteorComboStep; //Retrieve current step in the Confiteor/Blades combo + MP = Player.HPMP.CurMP; //Current MP of the player DivineMight.Left = SelfStatusLeft(SID.DivineMight, 30); //Remaining duration of the Divine Might buff DivineMight.IsActive = DivineMight.Left > 0; //Check if the Divine Might buff is active FightOrFlight.CD = CD(AID.FightOrFlight); //Remaining cooldown for the Fight or Flight ability FightOrFlight.Left = SelfStatusLeft(SID.FightOrFlight, 20); //Remaining duration of the Fight or Flight buff FightOrFlight.IsActive = FightOrFlight.CD is >= 39.5f and <= 60; //Check if the Fight or Flight buff is active - FightOrFlight.IsReady = ActionReady(AID.FightOrFlight); //Fight or Flight ability - SpiritsWithin.CD = CD(AID.SpiritsWithin); //Remaining cooldown for the Spirits Within ability - SpiritsWithin.IsReady = Unlocked(AID.SpiritsWithin) && IsOffCooldown(BestSpirits); //Spirits Within ability + FightOrFlight.IsReady = FightOrFlight.CD < 0.6f; //Fight or Flight ability + SpiritsWithin.CD = CD(BestSpirits); //Remaining cooldown for the Spirits Within ability + SpiritsWithin.IsReady = Unlocked(AID.SpiritsWithin) && SpiritsWithin.CD < 0.6f; //Spirits Within ability CircleOfScorn.CD = CD(AID.CircleOfScorn); //Remaining cooldown for the Circle of Scorn ability - CircleOfScorn.IsReady = Unlocked(AID.CircleOfScorn) && IsOffCooldown(AID.CircleOfScorn); //Circle of Scorn ability + CircleOfScorn.IsReady = Unlocked(AID.CircleOfScorn) && CircleOfScorn.CD < 0.6f; //Circle of Scorn ability GoringBlade.CD = CD(AID.GoringBlade); //Remaining cooldown for the Goring Blade ability GoringBlade.Left = SelfStatusLeft(SID.GoringBladeReady, 30); //Remaining duration of the Goring Blade buff GoringBlade.IsActive = GoringBlade.Left > 0; //Check if the Goring Blade buff is active @@ -386,7 +384,7 @@ public override void Execute(StrategyValues strategy, Actor? primaryTarget, floa Confiteor.IsReady = Unlocked(AID.Confiteor) && Confiteor.IsActive && MP >= 1000; //Confiteor ability BladeOfHonor.Left = SelfStatusLeft(SID.BladeOfHonorReady, 30); //Remaining duration of the Blade of Honor buff BladeOfHonor.IsActive = BladeOfHonor.Left > 0; //Check if the Blade of Honor buff is active - BladeOfHonor.IsReady = Unlocked(AID.BladeOfHonor) && IsOffCooldown(AID.BladeOfHonor); //Blade of Honor ability + BladeOfHonor.IsReady = Unlocked(AID.BladeOfHonor) && CD(AID.BladeOfHonor) < 0.6f; //Blade of Honor ability HolySpirit.HasMP = MP >= 1000; //Check if the player has enough mana points for Holy Spirit HolySpirit.IsReady = Unlocked(AID.HolySpirit) && HolySpirit.HasMP; //Holy Spirit ability HolyCircle.HasMP = MP >= 1000; //Check if the player has enough mana points for Holy Circle @@ -409,28 +407,28 @@ public override void Execute(StrategyValues strategy, Actor? primaryTarget, floa var cdStrat = cd.As(); //Retrieves Cooldowns strategy var pot = strategy.Option(Track.Potion); //Retrieves Potion track var potStrat = pot.As(); //Retrieves Potion strategy - var fof = strategy.Option(Track.FightOrFlight); - var fofStrat = fof.As(); - var req = strategy.Option(Track.Requiescat); - var reqStrat = req.As(); + var fof = strategy.Option(Track.FightOrFlight); //Retrieves Fight or Flight track + var fofStrat = fof.As(); //Retrieves Fight or Flight strategy + var req = strategy.Option(Track.Requiescat); //Retrieves Requiescat track + var reqStrat = req.As(); //Retrieves Requiescat strategy var atone = strategy.Option(Track.Atonement); //Retrieves Atonement track var atoneStrat = atone.As(); //Retrieves Atonement strategy var blade = strategy.Option(Track.BladeCombo); //Retrieves Blade Combo track - var bladeStrat = blade.As(); - var cos = strategy.Option(Track.CircleOfScorn); - var cosStrat = cos.As(); - var sw = strategy.Option(Track.SpiritsWithin); - var swStrat = sw.As(); - var dash = strategy.Option(Track.Dash); - var dashStrat = dash.As(); - var gb = strategy.Option(Track.GoringBlade); - var gbStrat = gb.As(); - var boh = strategy.Option(Track.BladeOfHonor); - var bohStrat = boh.As(); - var holy = strategy.Option(Track.Holy); - var holyStrat = holy.As(); - var ranged = strategy.Option(Track.Ranged); - var rangedStrat = ranged.As(); + var bladeStrat = blade.As(); //Retrieves Blade Combo strategy + var cos = strategy.Option(Track.CircleOfScorn); //Retrieves Circle of Scorn track + var cosStrat = cos.As(); //Retrieves Circle of Scorn strategy + var sw = strategy.Option(Track.SpiritsWithin); //Retrieves Spirits Within track + var swStrat = sw.As(); //Retrieves Spirits Within strategy + var dash = strategy.Option(Track.Dash); //Retrieves Dash track + var dashStrat = dash.As(); //Retrieves Dash strategy + var gb = strategy.Option(Track.GoringBlade); //Retrieves Goring Blade track + var gbStrat = gb.As(); //Retrieves Goring Blade strategy + var boh = strategy.Option(Track.BladeOfHonor); //Retrieves Blade of Honor track + var bohStrat = boh.As(); //Retrieves Blade of Honor strategy + var holy = strategy.Option(Track.Holy); //Retrieves Holy track + var holyStrat = holy.As(); //Retrieves Holy strategy + var ranged = strategy.Option(Track.Ranged); //Retrieves Ranged track + var rangedStrat = ranged.As(); //Retrieves Ranged strategy #endregion #endregion @@ -441,155 +439,166 @@ public override void Execute(StrategyValues strategy, Actor? primaryTarget, floa if (ShouldUseAOE) //if AOE rotation should be used QueueGCD(RotationAOE(), //queue the next AOE combo action Player, //on Self (no target needed) - GCDPriority.Combo123); //with priority for 123/12 combo actions + GCDPriority.Combo123); //use priority for 123/12 combo actions if (!ShouldUseAOE) QueueGCD(RotationST(), //queue the next single-target combo action TargetChoice(AOE) //Get target choice ?? primaryTarget, //if none, choose primary target - GCDPriority.Combo123); //with priority for 123/12 combo actions + GCDPriority.Combo123); //use priority for 123/12 combo actions } if (AOEStrategy == AOEStrategy.AutoFinishCombo) //if Finish Combo option is selected { QueueGCD(BestRotation(), //queue the next single-target combo action only if combo is finished TargetChoice(AOE) //Get target choice ?? primaryTarget, //if none, choose primary target - GCDPriority.Combo123); //with priority for 123/12 combo actions + GCDPriority.Combo123); //use priority for 123/12 combo actions } #endregion #region Cooldowns Execution - var hold = cdStrat == CooldownStrategy.Hold; - if (!hold) + var hold = cdStrat == CooldownStrategy.Hold; //Check if Cooldowns should be held + if (!hold) //if Cooldowns should not be held { - if (ShouldUseFightOrFlight(fofStrat, primaryTarget)) - QueueOGCD(AID.FightOrFlight, - Player, - fofStrat is OGCDStrategy.Force - or OGCDStrategy.AnyWeave - or OGCDStrategy.EarlyWeave - or OGCDStrategy.LateWeave - ? OGCDPriority.ForcedOGCD - : OGCDPriority.FightOrFlight); - if (ShouldUseRequiescat(reqStrat, primaryTarget)) - QueueOGCD(BestRequiescat, - TargetChoice(req) ?? primaryTarget, - reqStrat is OGCDStrategy.Force - or OGCDStrategy.AnyWeave - or OGCDStrategy.EarlyWeave - or OGCDStrategy.LateWeave - ? OGCDPriority.ForcedOGCD - : OGCDPriority.Requiescat); - if (bladeStrat == BladeComboStrategy.ForceConfiteor) - QueueGCD(AID.Confiteor, - TargetChoice(blade) ?? primaryTarget, - GCDPriority.ForcedGCD); - if (ShouldUseCircleOfScorn(cosStrat, primaryTarget)) - QueueOGCD(AID.CircleOfScorn, - Player, - cosStrat is OGCDStrategy.Force - or OGCDStrategy.AnyWeave - or OGCDStrategy.EarlyWeave - or OGCDStrategy.LateWeave - ? OGCDPriority.ForcedOGCD - : OGCDPriority.CircleOfScorn); - if (ShouldUseSpiritsWithin(swStrat, primaryTarget)) - QueueOGCD(BestSpirits, - TargetChoice(sw) ?? primaryTarget, - swStrat is OGCDStrategy.Force - or OGCDStrategy.AnyWeave - or OGCDStrategy.EarlyWeave - or OGCDStrategy.LateWeave - ? OGCDPriority.ForcedOGCD - : OGCDPriority.SpiritsWithin); - if (ShouldUseDash(dashStrat, primaryTarget)) - QueueOGCD(AID.Intervene, - TargetChoice(dash) ?? primaryTarget, - dashStrat is DashStrategy.Force - or DashStrategy.Force1 - or DashStrategy.GapClose - or DashStrategy.GapClose1 - ? OGCDPriority.ForcedOGCD - : OGCDPriority.Intervene); - if (HasEffect(SID.BladeOfHonorReady)) - QueueOGCD(AID.BladeOfHonor, - TargetChoice(boh) ?? primaryTarget, - bohStrat is OGCDStrategy.Force - or OGCDStrategy.AnyWeave - or OGCDStrategy.EarlyWeave - or OGCDStrategy.LateWeave - ? OGCDPriority.ForcedOGCD - : OGCDPriority.BladeOfHonor); - if (ShouldUseGoringBlade(gbStrat, primaryTarget)) - QueueGCD(AID.GoringBlade, - TargetChoice(gb) ?? primaryTarget, - gbStrat is GCDStrategy.Force - ? GCDPriority.ForcedGCD - : GCDPriority.GoringBlade); + if (ShouldUseFightOrFlight(fofStrat, primaryTarget)) //if Fight or Flight should be used + QueueOGCD(AID.FightOrFlight, //queue Fight or Flight + Player, //on Self (no target needed) + fofStrat is OGCDStrategy.Force //if Force strategy is selected + or OGCDStrategy.AnyWeave //or Any Weave strategy is selected + or OGCDStrategy.EarlyWeave //or Early Weave strategy is selected + or OGCDStrategy.LateWeave //or Late Weave strategy is selected + ? OGCDPriority.ForcedOGCD //use priority for forced oGCDs + : OGCDPriority.FightOrFlight); //otherwise with normal priority + if (ShouldUseRequiescat(reqStrat, primaryTarget)) //if Requiescat should be used + QueueOGCD(BestRequiescat, //queue Requiescat + TargetChoice(req) ?? primaryTarget, //with target choice + reqStrat is OGCDStrategy.Force //if Force strategy is selected + or OGCDStrategy.AnyWeave //or Any Weave strategy is selected + or OGCDStrategy.EarlyWeave //or Early Weave strategy is selected + or OGCDStrategy.LateWeave //or Late Weave strategy is selected + ? OGCDPriority.ForcedOGCD //use priority for forced oGCDs + : OGCDPriority.Requiescat); //otherwise with normal priority + if (bladeStrat == BladeComboStrategy.ForceConfiteor) //if Confiteor should be forced + QueueGCD(AID.Confiteor, //queue Confiteor + TargetChoice(blade) ?? primaryTarget, //with target choice + GCDPriority.ForcedGCD); //use priority for forced GCDs + if (ShouldUseCircleOfScorn(cosStrat, primaryTarget)) //if Circle of Scorn should be used + QueueOGCD(AID.CircleOfScorn, //queue Circle of Scorn + Player, //on Self (no target needed) + cosStrat is OGCDStrategy.Force //if Force strategy is selected + or OGCDStrategy.AnyWeave //or Any Weave strategy is selected + or OGCDStrategy.EarlyWeave //or Early Weave strategy is selected + or OGCDStrategy.LateWeave //or Late Weave strategy is selected + ? OGCDPriority.ForcedOGCD //use priority for forced oGCDs + : OGCDPriority.CircleOfScorn); //otherwise with normal priority + if (ShouldUseSpiritsWithin(swStrat, primaryTarget)) //if Spirits Within should be used + QueueOGCD(BestSpirits, //queue Spirits Within + TargetChoice(sw) ?? primaryTarget, //with target choice + swStrat is OGCDStrategy.Force //if Force strategy is selected + or OGCDStrategy.AnyWeave //or Any Weave strategy is selected + or OGCDStrategy.EarlyWeave //or Early Weave strategy is selected + or OGCDStrategy.LateWeave //or Late Weave strategy is selected + ? OGCDPriority.ForcedOGCD //use priority for forced oGCDs + : OGCDPriority.SpiritsWithin); //otherwise with normal priority + if (ShouldUseDash(dashStrat, primaryTarget)) //if Dash should be used + QueueOGCD(AID.Intervene, //queue Dash + TargetChoice(dash) ?? primaryTarget, //with target choice + dashStrat is DashStrategy.Force //if Force strategy is selected + or DashStrategy.Force1 //or Force1 strategy is selected + or DashStrategy.GapClose //or GapClose strategy is selected + or DashStrategy.GapClose1 //or GapClose1 strategy is selected + ? OGCDPriority.ForcedOGCD //use priority for forced oGCDs + : OGCDPriority.Intervene); //otherwise with normal priority + if (ShouldUseBladeOfHonor(bohStrat, primaryTarget)) //if Blade of Honor should be used + QueueOGCD(AID.BladeOfHonor, //queue Blade of Honor + TargetChoice(boh) ?? primaryTarget, //with target choice + bohStrat is OGCDStrategy.Force //if Force strategy is selected + or OGCDStrategy.AnyWeave //or Any Weave strategy is selected + or OGCDStrategy.EarlyWeave //or Early Weave strategy is selected + or OGCDStrategy.LateWeave //or Late Weave strategy is selected + ? OGCDPriority.ForcedOGCD //use priority for forced oGCDs + : OGCDPriority.BladeOfHonor); //otherwise with normal priority + if (ShouldUseGoringBlade(gbStrat, primaryTarget)) //if Goring Blade should be used + QueueGCD(AID.GoringBlade, //queue Goring Blade + TargetChoice(gb) ?? primaryTarget, //with target choice + gbStrat is GCDStrategy.Force //if Force strategy is selected + ? GCDPriority.ForcedGCD //use priority for forced GCDs + : GCDPriority.GoringBlade); //otherwise with normal priority } - - if (ShouldUseBladeCombo(bladeStrat, primaryTarget)) + if (ShouldUseBladeCombo(bladeStrat, primaryTarget)) //if Blade Combo should be used { - if (bladeStrat is BladeComboStrategy.Automatic) - QueueGCD(BestBlade, - TargetChoice(blade) ?? primaryTarget, - GCDPriority.Blades); - if (bladeStrat is BladeComboStrategy.ForceFaith) - QueueGCD(AID.BladeOfFaith, - TargetChoice(blade) ?? primaryTarget, - GCDPriority.ForcedGCD); - if (bladeStrat is BladeComboStrategy.ForceTruth) - QueueGCD(AID.BladeOfTruth, - TargetChoice(blade) ?? primaryTarget, - GCDPriority.ForcedGCD); - if (bladeStrat is BladeComboStrategy.ForceValor) - QueueGCD(AID.BladeOfValor, - TargetChoice(blade) ?? primaryTarget, - GCDPriority.ForcedGCD); + if (bladeStrat is BladeComboStrategy.Automatic) //if Automatic strategy is selected + QueueGCD(BestBlade, //queue the best Blade combo action + TargetChoice(blade) ?? primaryTarget, //with target choice + GCDPriority.Blades); //use priority for Blade combo actions + if (bladeStrat is BladeComboStrategy.ForceFaith) //if Force Faith strategy is selected + QueueGCD(AID.BladeOfFaith, //queue Blade of Faith + TargetChoice(blade) ?? primaryTarget, //with target choice + GCDPriority.ForcedGCD); //use priority for forced GCDs + if (bladeStrat is BladeComboStrategy.ForceTruth) //if Force Truth strategy is selected + QueueGCD(AID.BladeOfTruth, //queue Blade of Truth + TargetChoice(blade) ?? primaryTarget, //with target choice + GCDPriority.ForcedGCD); //use priority for forced GCDs + if (bladeStrat is BladeComboStrategy.ForceValor) //if Force Valor strategy is selected + QueueGCD(AID.BladeOfValor, //queue Blade of Valor + TargetChoice(blade) ?? primaryTarget, //with target choice + GCDPriority.ForcedGCD); //use priority for forced GCDs } - if (ShouldUseAtonement(atoneStrat, primaryTarget)) + if (ShouldUseAtonement(atoneStrat, primaryTarget)) //if Atonement should be used { - if (atoneStrat == AtonementStrategy.Automatic) - QueueGCD(BestAtonement, - TargetChoice(atone) ?? primaryTarget, - GCDPriority.Atonement); - if (atoneStrat is AtonementStrategy.ForceAtonement) - QueueGCD(AID.Atonement, - TargetChoice(atone) ?? primaryTarget, - GCDPriority.ForcedGCD); - if (atoneStrat is AtonementStrategy.ForceSupplication) - QueueGCD(AID.Supplication, - TargetChoice(atone) ?? primaryTarget, - GCDPriority.ForcedGCD); - if (atoneStrat is AtonementStrategy.ForceSepulchre) - QueueGCD(AID.Sepulchre, - TargetChoice(atone) ?? primaryTarget, - GCDPriority.ForcedGCD); - + if (atoneStrat == AtonementStrategy.Automatic) //if Automatic strategy is selected + QueueGCD(BestAtonement, //queue the best Atonement action + TargetChoice(atone) ?? primaryTarget, //with target choice + GCDPriority.Atonement); //use priority for Atonement actions + if (atoneStrat is AtonementStrategy.ForceAtonement) //if Force Atonement strategy is selected + QueueGCD(AID.Atonement, //queue Atonement + TargetChoice(atone) ?? primaryTarget, //with target choice + GCDPriority.ForcedGCD); //use priority for forced GCDs + if (atoneStrat is AtonementStrategy.ForceSupplication) //if Force Supplication strategy is selected + QueueGCD(AID.Supplication, //queue Supplication + TargetChoice(atone) ?? primaryTarget, //with target choice + GCDPriority.ForcedGCD); //use priority for forced GCDs + if (atoneStrat is AtonementStrategy.ForceSepulchre) //if Force Sepulchre strategy is selected + QueueGCD(AID.Sepulchre, //queue Sepulchre + TargetChoice(atone) ?? primaryTarget, //with target choice + GCDPriority.ForcedGCD); //use priority for forced GCDs } - - if (ShouldUseHoly(holyStrat, primaryTarget)) + if (ShouldUseHoly(holyStrat, primaryTarget)) //if Holy Spirit / Circle should be used { - var HSoverAtone = FightOrFlight.Left is <= 2.5f and >= 0.01f && !Supplication.IsActive && !Sepulchre.IsActive; - if (holyStrat == HolyStrategy.Automatic) - QueueGCD(BestHoly, TargetChoice(holy) ?? primaryTarget, HSoverAtone ? GCDPriority.GoringBlade : GCDPriority.HolySpirit); - if (holyStrat == HolyStrategy.Spirit) - QueueGCD(AID.HolySpirit, TargetChoice(holy) ?? primaryTarget, GCDPriority.ForcedGCD); - if (holyStrat == HolyStrategy.Circle) - QueueGCD(BestHolyCircle, Player, GCDPriority.ForcedGCD); + if (holyStrat == HolyStrategy.Automatic) //if Automatic strategy is selected + QueueGCD(BestHoly, //queue the best Holy action + TargetChoice(holy) ?? primaryTarget, //with target choice + FightOrFlight.Left is <= 2.5f and >= 0.01f //if Fight or Flight is active + && !Supplication.IsActive //and Supplication is not active + && !Sepulchre.IsActive //and Sepulchre is not active + ? GCDPriority.GoringBlade //use priority for Goring Blade + : GCDPriority.HolySpirit); //otherwise use priority for Holy Spirit + if (holyStrat == HolyStrategy.Spirit) //if Spirit strategy is selected + QueueGCD(AID.HolySpirit, //queue Holy Spirit + TargetChoice(holy) ?? primaryTarget, //with target choice + GCDPriority.ForcedGCD); //use priority for forced GCDs + if (holyStrat == HolyStrategy.Circle) //if Circle strategy is selected + QueueGCD(BestHolyCircle, //queue Holy Circle + Player, //on Self (no target needed) + GCDPriority.ForcedGCD); //use priority } - - if (ShouldUseRangedLob(primaryTarget, rangedStrat)) - QueueGCD(AID.ShieldLob, TargetChoice(ranged) ?? primaryTarget, rangedStrat is RangedStrategy.Force ? GCDPriority.ForcedGCD : GCDPriority.Combo123); - if (ShouldUseRangedCast(primaryTarget, rangedStrat)) - QueueGCD(AID.HolySpirit, TargetChoice(ranged) ?? primaryTarget, rangedStrat is RangedStrategy.ForceCast ? GCDPriority.ForcedGCD : GCDPriority.Combo123); - - if (ShouldUsePotion(potStrat)) - Hints.ActionsToExecute.Push( - ActionDefinitions.IDPotionStr, - Player, - ActionQueue.Priority.VeryHigh + (int)OGCDPriority.Potion, - 0, - GCD - 0.9f); + if (ShouldUseRangedLob(primaryTarget, rangedStrat)) //if Shield Lob should be used + QueueGCD(AID.ShieldLob, //queue Shield Lob + TargetChoice(ranged) ?? primaryTarget, //with target choice + rangedStrat is RangedStrategy.Force //if Force strategy is selected + ? GCDPriority.ForcedGCD //use priority for forced GCDs + : GCDPriority.Combo123); //otherwise use priority for 123/12 combo actions + if (ShouldUseRangedCast(primaryTarget, rangedStrat)) //if Shield Cast should be used + QueueGCD(AID.HolySpirit, //queue Holy Spirit + TargetChoice(ranged) ?? primaryTarget, //with target choice + rangedStrat is RangedStrategy.ForceCast //if Force Cast strategy is selected + ? GCDPriority.ForcedGCD //use priority for forced GCDs + : GCDPriority.Combo123); //otherwise use priority for 123/12 combo actions + if (ShouldUsePotion(potStrat)) //if Potion should be used + Hints.ActionsToExecute.Push(ActionDefinitions.IDPotionStr, //queue the potion action + Player, //on Self (no target needed) + ActionQueue.Priority.VeryHigh + (int)OGCDPriority.Potion, //use priority for potions + 0, //no delay + GCD - 0.9f); //Lateweave #endregion } @@ -651,14 +660,14 @@ public bool QueueAction(AID aid, Actor? target, float priority, float delay) private AID BestRotation() => ComboLastMove switch { //ST - AID.RoyalAuthority => ShouldUseAOE ? RotationAOE() : RotationST(), - AID.RageOfHalone => ShouldUseAOE ? RotationAOE() : RotationST(), - AID.RiotBlade => RotationST(), - AID.FastBlade => RotationST(), + AID.RoyalAuthority => ShouldUseAOE ? RotationAOE() : RotationST(), //If Royal Authority was last used, choose between AOE and ST rotations + AID.RageOfHalone => ShouldUseAOE ? RotationAOE() : RotationST(), //If Rage of Halone was last used, choose between AOE and ST rotations + AID.RiotBlade => RotationST(), //If Riot Blade was last used, continue ST rotation + AID.FastBlade => RotationST(), //If Fast Blade was last used, continue ST rotation //AOE - AID.Prominence => ShouldUseAOE ? RotationAOE() : RotationST(), - AID.TotalEclipse => RotationAOE(), - _ => ShouldUseAOE ? RotationAOE() : RotationST(), + AID.Prominence => ShouldUseAOE ? RotationAOE() : RotationST(), //If Prominence was last used, choose between AOE and ST rotations + AID.TotalEclipse => RotationAOE(), //If Total Eclipse was last used, continue AOE rotation + _ => ShouldUseAOE ? RotationAOE() : RotationST(), //Default to AOE or ST rotation based on conditions }; #endregion @@ -683,110 +692,123 @@ public bool QueueAction(AID aid, Actor? target, float priority, float delay) private bool ShouldUseFightOrFlight(OGCDStrategy strategy, Actor? target) => strategy switch { OGCDStrategy.Automatic => - Player.InCombat && - target != null && - FightOrFlight.IsReady && - CombatTimer >= GCDLength * 2 + 0.5f, - OGCDStrategy.Force => FightOrFlight.IsReady, - OGCDStrategy.AnyWeave => FightOrFlight.IsReady && canWeaveIn, - OGCDStrategy.EarlyWeave => FightOrFlight.IsReady && canWeaveEarly, - OGCDStrategy.LateWeave => FightOrFlight.IsReady && canWeaveLate, - OGCDStrategy.Delay => false, + Player.InCombat && //In combat + target != null && //Target exists + FightOrFlight.IsReady && //Fight or Flight is ready + CombatTimer >= GCDLength * 2 + 0.5f, //After 2+ GCDs + OGCDStrategy.Force => FightOrFlight.IsReady, //Force Fight or Flight + OGCDStrategy.AnyWeave => FightOrFlight.IsReady && canWeaveIn, //Force Weave Fight or Flight + OGCDStrategy.EarlyWeave => FightOrFlight.IsReady && canWeaveEarly, //Force Early Weave Fight or Flight + OGCDStrategy.LateWeave => FightOrFlight.IsReady && canWeaveLate, //Force Late Weave Fight or Flight + OGCDStrategy.Delay => false, //Delay Fight or Flight _ => false }; private bool ShouldUseRequiescat(OGCDStrategy strategy, Actor? target) => strategy switch { OGCDStrategy.Automatic => - Player.InCombat && - target != null && - Requiescat.IsReady && - FightOrFlight.IsActive, - OGCDStrategy.Force => Requiescat.IsReady, - OGCDStrategy.AnyWeave => Requiescat.IsReady && canWeaveIn, - OGCDStrategy.EarlyWeave => Requiescat.IsReady && canWeaveEarly, - OGCDStrategy.LateWeave => Requiescat.IsReady && canWeaveLate, - OGCDStrategy.Delay => false, + Player.InCombat && //In combat + target != null && //Target exists + Requiescat.IsReady && //Requiescat is ready + FightOrFlight.IsActive, //Fight or Flight is active + OGCDStrategy.Force => Requiescat.IsReady, //Force Requiescat + OGCDStrategy.AnyWeave => Requiescat.IsReady && canWeaveIn, //Force Weave Requiescat + OGCDStrategy.EarlyWeave => Requiescat.IsReady && canWeaveEarly, //Force Early Weave Requiescat + OGCDStrategy.LateWeave => Requiescat.IsReady && canWeaveLate, //Force Late Weave Requiescat + OGCDStrategy.Delay => false, //Delay Requiescat _ => false }; private bool ShouldUseSpiritsWithin(OGCDStrategy strategy, Actor? target) => strategy switch { OGCDStrategy.Automatic => - Player.InCombat && - target != null && - In3y(target) && - FightOrFlight.CD is < 57.55f and > 17 && - SpiritsWithin.IsReady, - OGCDStrategy.Force => SpiritsWithin.IsReady, - OGCDStrategy.AnyWeave => SpiritsWithin.IsReady && canWeaveIn, - OGCDStrategy.EarlyWeave => SpiritsWithin.IsReady && canWeaveEarly, - OGCDStrategy.LateWeave => SpiritsWithin.IsReady && canWeaveLate, - OGCDStrategy.Delay => false, + Player.InCombat && //In combat + target != null && //Target exists + In3y(target) && //Target in range + FightOrFlight.CD is < 57.55f and > 17 && //One use inside FoF, one use outside FoF + SpiritsWithin.IsReady, //Spirits Within is ready + OGCDStrategy.Force => SpiritsWithin.IsReady, //Force Spirits Within + OGCDStrategy.AnyWeave => SpiritsWithin.IsReady && canWeaveIn, //Force Weave Spirits Within + OGCDStrategy.EarlyWeave => SpiritsWithin.IsReady && canWeaveEarly, //Force Early Weave Spirits Within + OGCDStrategy.LateWeave => SpiritsWithin.IsReady && canWeaveLate, //Force Late Weave Spirits Within + OGCDStrategy.Delay => false, //Delay Spirits Within _ => false }; private bool ShouldUseCircleOfScorn(OGCDStrategy strategy, Actor? target) => strategy switch { OGCDStrategy.Automatic => - Player.InCombat && - target != null && - CircleOfScorn.IsReady && - In5y(target) && - FightOrFlight.CD is < 57.55f and > 17, - OGCDStrategy.Force => CircleOfScorn.IsReady, - OGCDStrategy.AnyWeave => CircleOfScorn.IsReady && canWeaveIn, - OGCDStrategy.EarlyWeave => CircleOfScorn.IsReady && canWeaveEarly, - OGCDStrategy.LateWeave => CircleOfScorn.IsReady && canWeaveLate, - OGCDStrategy.Delay => false, + Player.InCombat && //In combat + target != null && //Target exists + CircleOfScorn.IsReady && //Circle of Scorn is ready + In5y(target) && //Target in range + FightOrFlight.CD is < 57.55f and > 17, //One use inside FoF, one use outside FoF + OGCDStrategy.Force => CircleOfScorn.IsReady, //Force Circle of Scorn + OGCDStrategy.AnyWeave => CircleOfScorn.IsReady && canWeaveIn, //Force Weave Circle of Scorn + OGCDStrategy.EarlyWeave => CircleOfScorn.IsReady && canWeaveEarly, //Force Early Weave Circle of Scorn + OGCDStrategy.LateWeave => CircleOfScorn.IsReady && canWeaveLate, //Force Late Weave Circle of Scorn + OGCDStrategy.Delay => false, //Delay Circle of Scorn + _ => false + }; + private bool ShouldUseBladeOfHonor(OGCDStrategy strategy, Actor? target) => strategy switch + { + OGCDStrategy.Automatic => + Player.InCombat && //In combat + target != null && //Target exists + BladeOfHonor.IsReady, //Blade of Honor is ready + OGCDStrategy.Force => BladeOfHonor.IsReady, //Force Blade of Honor + OGCDStrategy.AnyWeave => BladeOfHonor.IsReady && canWeaveIn, //Force Weave Blade of Honor + OGCDStrategy.EarlyWeave => BladeOfHonor.IsReady && canWeaveEarly, //Force Early Weave Blade of Honor + OGCDStrategy.LateWeave => BladeOfHonor.IsReady && canWeaveLate, //Force Late Weave Blade of Honor + OGCDStrategy.Delay => false, //Delay Blade of Honor _ => false }; private bool ShouldUseGoringBlade(GCDStrategy strategy, Actor? target) => strategy switch { GCDStrategy.Automatic => - Player.InCombat && - In3y(target) && - GoringBlade.IsReady && - FightOrFlight.IsActive, - GCDStrategy.Force => GoringBlade.IsReady, - GCDStrategy.Delay => false, + Player.InCombat && //In combat + In3y(target) && //Target in range + GoringBlade.IsReady && //Goring Blade is ready + FightOrFlight.IsActive, //Fight or Flight is active + GCDStrategy.Force => GoringBlade.IsReady, //Force Goring Blade + GCDStrategy.Delay => false, //Delay Goring Blade _ => false }; private bool ShouldUseBladeCombo(BladeComboStrategy strategy, Actor? target) => strategy switch { BladeComboStrategy.Automatic => - Player.InCombat && - target != null && - In25y(target) && - FightOrFlight.IsActive && - Requiescat.IsActive && - BladeComboStep is 0 or 1 or 2 or 3, - BladeComboStrategy.ForceConfiteor => Confiteor.IsReady && BladeComboStep is 0, - BladeComboStrategy.ForceFaith => BladeComboStep is 1, - BladeComboStrategy.ForceTruth => BladeComboStep is 2, - BladeComboStrategy.ForceValor => BladeComboStep is 3, - BladeComboStrategy.Delay => false, + Player.InCombat && //In combat + target != null && //Target exists + In25y(target) && //Target in range + FightOrFlight.IsActive && //Fight or Flight is active + Requiescat.IsActive && //Requiescat is active + BladeComboStep is 0 or 1 or 2 or 3, //Blade Combo conditions are met + BladeComboStrategy.ForceConfiteor => Confiteor.IsReady && BladeComboStep is 0, //Force Confiteor + BladeComboStrategy.ForceFaith => BladeComboStep is 1, //Force Blade of Faith + BladeComboStrategy.ForceTruth => BladeComboStep is 2, //Force Blade of Truth + BladeComboStrategy.ForceValor => BladeComboStep is 3, //Force Blade of Valor + BladeComboStrategy.Delay => false, //Delay Blade Combo _ => false }; private bool ShouldUseAtonement(AtonementStrategy strategy, Actor? target) => strategy switch { AtonementStrategy.Automatic => - Player.InCombat && - target != null && - In3y(target) && - Atonement.IsReady || Supplication.IsReady || Sepulchre.IsReady, - AtonementStrategy.ForceAtonement => Atonement.IsReady, - AtonementStrategy.ForceSupplication => Supplication.IsReady, - AtonementStrategy.ForceSepulchre => Sepulchre.IsReady, - AtonementStrategy.Delay => false, + Player.InCombat && //In combat + target != null && //Target exists + In3y(target) && //Target in range + Atonement.IsReady || Supplication.IsReady || Sepulchre.IsReady, //if any of the three are ready + AtonementStrategy.ForceAtonement => Atonement.IsReady, //Force Atonement + AtonementStrategy.ForceSupplication => Supplication.IsReady, //Force Supplication + AtonementStrategy.ForceSepulchre => Sepulchre.IsReady, //Force Sepulchre + AtonementStrategy.Delay => false, //Delay Atonement _ => false }; private bool ShouldUseHoly(HolyStrategy strategy, Actor? target) => strategy switch { HolyStrategy.Automatic => - ShouldUseDMHolyCircle || ShouldNormalHolyCircle - ? ShouldUseHolyCircle(HolyStrategy.Automatic, target) - : ShouldUseHolySpirit(HolyStrategy.Automatic, target), - HolyStrategy.Spirit => HolySpirit.IsReady, - HolyStrategy.Circle => HolyCircle.IsReady, - HolyStrategy.Delay => false, + ShouldUseDMHolyCircle || ShouldNormalHolyCircle //if Holy Circle should be used + ? ShouldUseHolyCircle(HolyStrategy.Automatic, target) //then use Holy Circle + : ShouldUseHolySpirit(HolyStrategy.Automatic, target), //otherwise use Holy Spirit + HolyStrategy.Spirit => HolySpirit.IsReady, //Force Holy Spirit + HolyStrategy.Circle => HolyCircle.IsReady, //Force Holy Circle + HolyStrategy.Delay => false, //Delay Holy Spirit _ => false }; private bool ShouldUseHolySpirit(HolyStrategy strategy, Actor? target) => strategy switch @@ -812,15 +834,15 @@ FightOrFlight.CD is < 57.55f and > 17 && private bool ShouldUseDash(DashStrategy strategy, Actor? target) => strategy switch { DashStrategy.Automatic => - Player.InCombat && - target != null && - In3y(target) && - Intervene.IsReady && - FightOrFlight.IsActive, - DashStrategy.Force => true, - DashStrategy.Force1 => Intervene.TotalCD < 1f, - DashStrategy.GapClose => !In3y(target), - DashStrategy.GapClose1 => Intervene.TotalCD < 1f && !In3y(target), + Player.InCombat && //In combat + target != null && //Target exists + In3y(target) && //Target in range + Intervene.IsReady && //can execute Intervene + FightOrFlight.IsActive, //Fight or Flight is active + DashStrategy.Force => true, //Force all charges + DashStrategy.Force1 => Intervene.TotalCD < 1f, //Force 1 charge + DashStrategy.GapClose => !In3y(target), //Force gap close + DashStrategy.GapClose1 => Intervene.TotalCD < 1f && !In3y(target), //Force gap close only if at max charges _ => false }; private bool ShouldUsePotion(PotionStrategy strategy) => strategy switch From 4ed59b7f1b634d962fadeb6564b86d216527d854 Mon Sep 17 00:00:00 2001 From: ace Date: Mon, 6 Jan 2025 10:07:30 -0800 Subject: [PATCH 06/17] AkechiGNB fixes post-refactor --- BossMod/Autorotation/akechi/AkechiGNB.cs | 211 ++++++++++++----------- 1 file changed, 106 insertions(+), 105 deletions(-) diff --git a/BossMod/Autorotation/akechi/AkechiGNB.cs b/BossMod/Autorotation/akechi/AkechiGNB.cs index 97b2e1f4bd..f7e4fd1c94 100644 --- a/BossMod/Autorotation/akechi/AkechiGNB.cs +++ b/BossMod/Autorotation/akechi/AkechiGNB.cs @@ -6,8 +6,6 @@ namespace BossMod.Autorotation.akechi; //Contribution by Akechi //Discord: @akechdz or 'Akechi' on Puni.sh for maintenance -//This module supports <=2.47 SkS rotation as default (or 'Automatic') -//With user adjustment, 'SlowGNB' or 'FastGNB' usage is easily achievable public sealed class AkechiGNB(RotationModuleManager manager, Actor player) : RotationModule(manager, player) { @@ -53,10 +51,10 @@ public enum CooldownStrategy public enum CartridgeStrategy { Automatic, //Automatically decide when to use Burst Strike & Fated Circle - BurstStrike, //Force the use of Burst Strike; consumes 1 cartridge - FatedCircle, //Force the use of Fated Circle; consumes 1 cartridge - GnashingFang, //Force the use of Gnashing Fang (cooldown only); consumes 1 cartridge - DoubleDown, //Force the use of Double Down; consumes 1 cartridge (yay) + OnlyBS, //Force the use of Burst Strike; consumes 1 cartridge + OnlyFC, //Force the use of Fated Circle; consumes 1 cartridge + ForceBS, //Force the use of Gnashing Fang (cooldown only); consumes 1 cartridge + ForceFC, //Force the use of Double Down; consumes 1 cartridge (yay) Conserve //Conserves all cartridge-related abilities as much as possible } @@ -185,13 +183,13 @@ public static RotationModuleDefinition Definition() //Cartridges strategy res.Define(Track.Cartridges).As("Cartridges", "Carts", uiPriority: 180) - .AddOption(CartridgeStrategy.Automatic, "Automatic", "Automatically decide when to use cartridges; uses them optimally", supportedTargets: ActionTargets.Hostile) - .AddOption(CartridgeStrategy.BurstStrike, "Burst Strike", "Force the use of Burst Strike; consumes 1 cartridge", supportedTargets: ActionTargets.Hostile) - .AddOption(CartridgeStrategy.FatedCircle, "Fated Circle", "Force the use of Fated Circle; consumes 1 cartridge") - .AddOption(CartridgeStrategy.GnashingFang, "Gnashing Fang", "Force the use of Gnashing Fang (cooldown only, no combo or CDs); consumes 1 cartridge", supportedTargets: ActionTargets.Hostile) - .AddOption(CartridgeStrategy.DoubleDown, "Double Down", "Force the use of Double Down; consumes 1 cartridge") + .AddOption(CartridgeStrategy.Automatic, "Automatic", "Automatically decide when to use cartridges; uses them optimally") + .AddOption(CartridgeStrategy.OnlyBS, "Only Burst Strike", "Uses Burst Strike optimally as cartridge spender only, regardless of targets", 0, 0, ActionTargets.Hostile, 30) + .AddOption(CartridgeStrategy.OnlyFC, "Only Fated Circle", "Uses Fated Circle optimally as cartridge spender only, regardless of targets", 0, 0, ActionTargets.Hostile, 72) + .AddOption(CartridgeStrategy.ForceBS, "Force Burst Strike", "Force use of Burst Strike; consumes 1 cartridge", 0, 0, ActionTargets.Hostile, 30) + .AddOption(CartridgeStrategy.ForceFC, "Force Fated Circle", "Force use of Fated Circle; consumes 1 cartridge", 0, 0, ActionTargets.Hostile, 72) .AddOption(CartridgeStrategy.Conserve, "Conserve", "Prohibit use of all cartridge-related abilities; will not use any of these actions listed above") - .AddAssociatedActions(AID.BurstStrike, AID.FatedCircle, AID.GnashingFang, AID.DoubleDown); + .AddAssociatedActions(AID.BurstStrike, AID.FatedCircle); //Potion strategy res.Define(Track.Potion).As("Potion", uiPriority: 20) @@ -334,6 +332,7 @@ public static RotationModuleDefinition Definition() private float bfCD; //Time left on Bloodfest cooldown (120s base) private float nmLeft; //Time left on No Mercy buff (20s base) private float nmCD; //Time left on No Mercy cooldown (60s base) + private bool inOdd; //Checks if player is in an odd-minute window private bool hasNM; //Checks self for No Mercy buff private bool hasBreak; //Checks self for Ready To Break buff private bool hasReign; //Checks self for Ready To Reign buff @@ -368,7 +367,6 @@ public static RotationModuleDefinition Definition() public float BurstWindowLeft; //Time left in current burst window (typically 20s-22s) public float BurstWindowIn; //Time until next burst window (typically 20s-22s) public AID NextGCD; //Next global cooldown action to be used (needed for cartridge management) - private GCDPriority NextGCDPrio; //Priority of the next GCD, used for decision making on cooldowns #endregion #region Module Helpers @@ -381,12 +379,10 @@ public static RotationModuleDefinition Definition() private bool ActionReady(AID aid) => World.Client.Cooldowns[ActionDefinitions.Instance.Spell(aid)!.MainCooldownGroup].Remaining < 0.6f; //Check if the desired action is ready (cooldown less than 0.6 seconds) private bool IsFirstGCD() => !Player.InCombat || (World.CurrentTime - Manager.CombatStart).TotalSeconds < 0.1f; //Check if this is the first GCD in combat private int TargetsInAOERange() => Hints.NumPriorityTargetsInAOECircle(Player.Position, 5); //Returns the number of targets hit by AOE within a 5-yalm radius around the player - public bool HasEffect(SID sid) => SelfStatusLeft(sid, 1000) > 0; //Checks if Status effect is on self - - //TODO: try new things... - //public bool JustDid(AID aid) => Manager?.LastCast.Data?.IsSpell(aid) ?? false; //Check if the last action used was the desired ability - //public bool DidWithin(float variance) => (World.CurrentTime - Manager.LastCast.Time).TotalSeconds <= variance; //Check if the last action was used within a certain timeframe - //public bool JustUsed(AID aid, float variance) => JustDid(aid) && DidWithin(variance); //Check if the last action used was the desired ability & was used within a certain timeframe + public bool HasEffect(SID sid, float duration) => SelfStatusLeft(sid, duration) > 0; //Checks if Status effect is on self + public bool JustDid(AID aid) => Manager?.LastCast.Data?.IsSpell(aid) ?? false; //Check if the last action used was the desired ability + public bool DidWithin(float variance) => (World.CurrentTime - Manager.LastCast.Time).TotalSeconds <= variance; //Check if the last action was used within a certain timeframe + public bool JustUsed(AID aid, float variance) => JustDid(aid) && DidWithin(variance); //Check if the last action used was the desired ability & was used within a certain timeframe #endregion #region Upgrade Paths @@ -395,21 +391,22 @@ private AID BestZone //Determine the best Zone to use ? AID.BlastingZone //Use Blasting Zone : AID.DangerZone; //Otherwise, use Danger Zone private AID BestCartSpender //Determine the best cartridge spender to use - => Unlocked(AID.FatedCircle) //If Fated Circle is unlocked - && ShouldUseFC //And we should use Fated Circle because of targets nearby - ? AID.FatedCircle //Use Fated Circle + => ShouldUseFC //And we should use Fated Circle because of targets nearby + ? BestFatedCircle //Use Fated Circle : canBS //Otherwise, if Burst Strike is available ? AID.BurstStrike //Use Burst Strike : NextBestRotation(); //Otherwise, use the next best rotation - + private AID BestFatedCircle //for AOE cart spending Lv30-71 + => Unlocked(AID.FatedCircle) //If Fated Circle is unlocked + ? AID.FatedCircle //Use Fated Circle + : AID.BurstStrike; //Otherwise, use Burst Strike private AID BestContinuation //Determine the best Continuation to use - => canContinue //And we can use Continuation - && hasBlast ? AID.Hypervelocity //If we have Ready To Blast buff - : hasRaze ? AID.FatedBrand //If we have Ready To Raze buff - : hasRip ? AID.JugularRip //If we have Ready To Rip buff - : hasTear ? AID.AbdomenTear //If we have Ready To Tear buff + => hasRaze ? AID.FatedBrand //If we have Ready To Raze buff + : hasBlast ? AID.Hypervelocity //If we have Ready To Blast buff : hasGouge ? AID.EyeGouge //If we have Ready To Gouge buff - : AID.Continuation; //Otherwise, dfault to original hook + : hasTear ? AID.AbdomenTear //If we have Ready To Tear buff + : hasRip ? AID.JugularRip //If we have Ready To Rip buff + : AID.Continuation; //Otherwise, default to original hook #endregion public override void Execute(StrategyValues strategy, Actor? primaryTarget, float estimatedAnimLockDelay, bool isMoving) //Executes our actions @@ -425,14 +422,14 @@ public override void Execute(StrategyValues strategy, Actor? primaryTarget, floa bfCD = CD(AID.Bloodfest); //Bloodfest cooldown (120s) nmCD = CD(AID.NoMercy); //No Mercy cooldown (60s) nmLeft = SelfStatusLeft(SID.NoMercy, 20); //Remaining time for No Mercy buff (20s) - hasBreak = HasEffect(SID.ReadyToBreak); //Checks for Ready To Break buff - hasReign = HasEffect(SID.ReadyToReign); //Checks for Ready To Reign buff + hasBreak = HasEffect(SID.ReadyToBreak, 30); //Checks for Ready To Break buff + hasReign = HasEffect(SID.ReadyToReign, 30); //Checks for Ready To Reign buff hasNM = nmCD is >= 39.5f and <= 60; //Checks if No Mercy is active - hasBlast = Unlocked(AID.Hypervelocity) && HasEffect(SID.ReadyToBlast); //Checks for Ready To Blast buff - hasRaze = Unlocked(AID.FatedBrand) && HasEffect(SID.ReadyToRaze); //Checks for Ready To Raze buff - hasRip = HasEffect(SID.ReadyToRip); //Checks for Ready To Rip buff - hasTear = HasEffect(SID.ReadyToTear); //Checks for Ready To Tear buff - hasGouge = HasEffect(SID.ReadyToGouge); //Checks for Ready To Gouge buff + hasBlast = Unlocked(AID.Hypervelocity) && HasEffect(SID.ReadyToBlast, 10f) && !JustUsed(AID.Hypervelocity, 10f); //Checks for Ready To Blast buff + hasRaze = Unlocked(AID.FatedBrand) && HasEffect(SID.ReadyToRaze, 10f) && !JustUsed(AID.FatedBrand, 10f); //Checks for Ready To Raze buff + hasRip = HasEffect(SID.ReadyToRip, 10f) && !JustUsed(AID.JugularRip, 10f); //Checks for Ready To Rip buff + hasTear = HasEffect(SID.ReadyToTear, 10f) && !JustUsed(AID.AbdomenTear, 10f); //Checks for Ready To Tear buff + hasGouge = HasEffect(SID.ReadyToGouge, 10f) && !JustUsed(AID.EyeGouge, 10f); //Checks for Ready To Gouge buff //GCD & Weaving canWeaveIn = GCD is <= 2.5f and >= 0.1f; //Can weave in oGCDs @@ -441,9 +438,9 @@ public override void Execute(StrategyValues strategy, Actor? primaryTarget, floa quarterWeave = GCD < 0.9f; //Can last second weave oGCDs GCDLength = ActionSpeed.GCDRounded(World.Client.PlayerStats.SkillSpeed, World.Client.PlayerStats.Haste, Player.Level); //GCD based on skill speed and haste NextGCD = AID.None; //Next global cooldown action to be used - NextGCDPrio = GCDPriority.None; //Priority of the next GCD, used for decision making on cooldowns //Misc + inOdd = bfCD is <= 90 and >= 30; //Checks if we are in an odd-minute window PotionLeft = PotionStatusLeft(); //Remaining time for potion buff (30s) ShouldUseAOE = //Determine if we should use AOE Unlocked(TraitID.MeleeMastery) //if Melee Mastery trait unlocked @@ -454,7 +451,7 @@ public override void Execute(StrategyValues strategy, Actor? primaryTarget, floa #region Minimal Requirements //Ammo-relative - canNM = ActionReady(AID.NoMercy); //No Mercy conditions + canNM = CD(AID.NoMercy) < 1; //No Mercy conditions canBS = Unlocked(AID.BurstStrike) && Ammo > 0; //Burst Strike conditions; -1 Ammo ST canGF = Unlocked(AID.GnashingFang) && ActionReady(AID.GnashingFang) && Ammo > 0; //Gnashing Fang conditions; -1 Ammo ST canFC = Unlocked(AID.FatedCircle) && Ammo > 0; //Fated Circle conditions; -1 Ammo AOE @@ -503,21 +500,21 @@ public override void Execute(StrategyValues strategy, Actor? primaryTarget, floa #region Force Execution if (AOEStrategy is AOEStrategy.ForceSTwithO) //if Single-target (with overcap protection) option is selected - QueueGCD(NextComboSingleTarget(), //queue the next single-target combo action with overcap protection + QueueGCD(STwithOvercap(), //queue the next single-target combo action with overcap protection ResolveTargetOverride(AOE.Value) //Get target choice ?? primaryTarget, //if none, choose primary target GCDPriority.ForcedGCD); //with priority for forced GCDs if (AOEStrategy is AOEStrategy.ForceSTwithoutO) //if Single-target (without overcap protection) option is selected - QueueGCD(NextForceSingleTarget(), //queue the next single-target combo action without overcap protection + QueueGCD(STwithoutOvercap(), //queue the next single-target combo action without overcap protection ResolveTargetOverride(AOE.Value) //Get target choice ?? primaryTarget, //if none, choose primary target GCDPriority.ForcedGCD); //with priority for forced GCDs if (AOEStrategy is AOEStrategy.ForceAOEwithO) //if AOE (with overcap protection) option is selected - QueueGCD(NextComboAOE(), //queue the next AOE combo action with overcap protection + QueueGCD(AOEwithOvercap(), //queue the next AOE combo action with overcap protection Player, //on Self (no target needed) GCDPriority.ForcedGCD); //with priority for forced GCDs if (AOEStrategy is AOEStrategy.ForceAOEwithoutO) //if AOE (without overcap protection) option is selected - QueueGCD(NextForceAOE(), //queue the next AOE combo action without overcap protection + QueueGCD(AOEwithoutOvercap(), //queue the next AOE combo action without overcap protection Player, //on Self (no target needed) GCDPriority.ForcedGCD); //with priority for forced GCDs #endregion @@ -569,7 +566,7 @@ public override void Execute(StrategyValues strategy, Actor? primaryTarget, floa } if (Ammo == MaxCartridges) //if at max cartridges - QueueGCD(NextForceSingleTarget(), //queue the next single-target combo action without overcap protection to save resources for uptime + QueueGCD(STwithoutOvercap(), //queue the next single-target combo action without overcap protection to save resources for uptime primaryTarget, //on the primary target GCDPriority.ForcedGCD); //with priority for forced GCDs } @@ -579,11 +576,11 @@ public override void Execute(StrategyValues strategy, Actor? primaryTarget, floa if (AOEStrategy == AOEStrategy.AutoBreakCombo) //if Break Combo option is selected { if (ShouldUseAOE) //if AOE rotation should be used - QueueGCD(NextComboAOE(), //queue the next AOE combo action + QueueGCD(AOEwithoutOvercap(), //queue the next AOE combo action Player, //on Self (no target needed) GCDPriority.Combo123); //with priority for 123/12 combo actions if (!ShouldUseAOE) - QueueGCD(NextComboSingleTarget(), //queue the next single-target combo action + QueueGCD(STwithoutOvercap(), //queue the next single-target combo action ResolveTargetOverride(AOE.Value) //Get target choice ?? primaryTarget, //if none, choose primary target GCDPriority.Combo123); //with priority for 123/12 combo actions @@ -659,15 +656,15 @@ or BloodfestStrategy.Force0W //or Force weave with 0 cartridges //Continuation execution if (canContinue && //if Continuation is available - hasBlast || //and Ready To Blast buff is active + (hasBlast || //and Ready To Blast buff is active hasRaze || //or Ready To Raze buff is active hasRip || //or Ready To Rip buff is active hasTear || //or Ready To Tear buff is active - hasGouge) //or Ready To Gouge buff is active + hasGouge)) //or Ready To Gouge buff is active QueueOGCD(BestContinuation, //queue the best Continuation action primaryTarget, //on the primary target - canWeaveLate //if inside second weave slot & still havent used - ? OGCDPriority.ForcedOGCD //use priority for forced oGCDs + canWeaveLate || GCD is 0 //if inside second weave slot & still havent used + ? OGCDPriority.Continuation + 1201 //force the fuck out of this to prevent loss, any loss is very bad : OGCDPriority.Continuation); //otherwise, use intended priority #endregion @@ -681,7 +678,6 @@ or BloodfestStrategy.Force0W //or Force weave with 0 cartridges if (ShouldUseDoubleDown(ddStrat, primaryTarget)) //if Double Down should be used QueueGCD(AID.DoubleDown, //queue Double Down primaryTarget, //on the primary target - cartStrat == CartridgeStrategy.DoubleDown || //if Double Down is selected on Cartridge strategy ddStrat == GCDStrategy.Force || //or Force Double Down is selected on Double Down strategy Ammo == 1 //or only 1 cartridge is available ? GCDPriority.ForcedGCD //use priority for forced GCDs @@ -691,7 +687,6 @@ or BloodfestStrategy.Force0W //or Force weave with 0 cartridges QueueGCD(AID.GnashingFang, //queue Gnashing Fang ResolveTargetOverride(gf.Value) //Get target choice ?? primaryTarget, //if none, choose primary target - cartStrat == CartridgeStrategy.GnashingFang || //if Gnashing Fang is selected on Cartridge strategy gfStrat == GnashingStrategy.ForceGnash //or Force Gnashing Fang is selected on Gnashing Fang strategy ? GCDPriority.ForcedGCD //use priority for forced GCDs : GCDPriority.GF1); //otherwise, use intended priority @@ -707,15 +702,15 @@ or BloodfestStrategy.Force0W //or Force weave with 0 cartridges ? GCDPriority.ForcedGCD //use priority for forced GCDs : GCDPriority.Gauge); //otherwise, use priority for gauge actions //Burst Strike forced execution - if (cartStrat == CartridgeStrategy.BurstStrike) //if Burst Strike Cartridge strategy is selected + if (cartStrat is CartridgeStrategy.OnlyBS or CartridgeStrategy.ForceBS) //if Burst Strike Cartridge strategies are selected QueueGCD(AID.BurstStrike, //queue Burst Strike ResolveTargetOverride(carts.Value) //Get target choice ?? primaryTarget, //if none, choose primary target GCDPriority.Gauge); //with priority for gauge actions //Fated Circle forced execution - if (cartStrat == CartridgeStrategy.FatedCircle) //if Fated Circle Cartridge strategy is selected - QueueGCD(AID.FatedCircle, //queue Fated Circle - Player, //on Self (no target needed) + if (cartStrat is CartridgeStrategy.ForceFC or CartridgeStrategy.OnlyFC) //if Fated Circle Cartridge strategies are selected + QueueGCD(BestFatedCircle, //queue Fated Circle + primaryTarget ?? Player, //on Self (no target needed) if Fated Circle, on target if Burst Strike GCDPriority.Gauge); //with priority for gauge actions } } @@ -786,80 +781,85 @@ or LightningShotStrategy.Allow //or Allow } #region Core Execution Helpers - private void QueueGCD(AID aid, Actor? target, GCDPriority prio) //QueueGCD execution + public void QueueGCD

(AID aid, Actor? target, P priority, float delay = 0) where P : Enum => QueueGCD(aid, target, (int)(object)priority, delay); + public void QueueOGCD

(AID aid, Actor? target, P priority, float delay = 0) where P : Enum => QueueOGCD(aid, target, (int)(object)priority, delay); + public void QueueGCD(AID aid, Actor? target, int priority = 8, float delay = 0) { - if (prio != GCDPriority.None) //if priority is not None + var NextGCDPrio = 0; + if (priority == 0) + return; + if (QueueAction(aid, target, ActionQueue.Priority.High + priority, delay) && priority > NextGCDPrio) { - Hints.ActionsToExecute.Push(ActionID.MakeSpell(aid), //queue the action - target, //on the target - ActionQueue.Priority.High //with high priority - + (int)prio); //and the specified priority - if (prio > NextGCDPrio) //if the priority is higher than the current next GCD priority - { - NextGCD = aid; //set the next GCD to this action - NextGCDPrio = prio; //set the next GCD priority to this priority - } + NextGCD = aid; } } - - private void QueueOGCD(AID aid, Actor? target, OGCDPriority prio, float basePrio = ActionQueue.Priority.Medium) //QueueOGCD execution + public void QueueOGCD(AID aid, Actor? target, int priority = 4, float delay = 0) { - if (prio != OGCDPriority.None) //if priority is not None + if (priority == 0) + return; + QueueAction(aid, target, ActionQueue.Priority.Medium + priority, delay); + } + public bool QueueAction(AID aid, Actor? target, float priority, float delay) + { + Vector3 targetPos = default; + var def = ActionDefinitions.Instance.Spell(aid); + if ((uint)(object)aid == 0) + return false; + if (def == null) + return false; + if (def.Range != 0 && target == null) + { + return false; + } + if (def.AllowedTargets.HasFlag(ActionTargets.Area)) { - Hints.ActionsToExecute.Push(ActionID.MakeSpell(aid), //queue the action - target, //on the target - basePrio //with the specified base priority - + (int)prio); //and the specified priority + if (def.Range == 0) + targetPos = Player.PosRot.XYZ(); + else if (target != null) + targetPos = target.PosRot.XYZ(); } + Hints.ActionsToExecute.Push(ActionID.MakeSpell(aid), target, priority, delay: delay, targetPos: targetPos); + return true; } private AID NextBestRotation() => ComboLastMove switch { //ST - AID.SolidBarrel => ShouldUseAOE ? NextComboAOE() : NextComboSingleTarget(), - AID.BrutalShell => NextComboSingleTarget(), - AID.KeenEdge => NextComboSingleTarget(), + AID.SolidBarrel => ShouldUseAOE ? AOEwithoutOvercap() : STwithoutOvercap(), + AID.BrutalShell => STwithoutOvercap(), + AID.KeenEdge => STwithoutOvercap(), //AOE - AID.DemonSlaughter => ShouldUseAOE ? NextComboAOE() : NextComboSingleTarget(), - AID.DemonSlice => NextComboAOE(), - _ => ShouldUseAOE ? NextComboAOE() : NextComboSingleTarget(), + AID.DemonSlaughter => ShouldUseAOE ? AOEwithoutOvercap() : STwithoutOvercap(), + AID.DemonSlice => AOEwithoutOvercap(), + _ => ShouldUseAOE ? AOEwithoutOvercap() : STwithoutOvercap(), }; #endregion #region Single-Target Helpers - private AID NextComboSingleTarget() => ComboLastMove switch //with Overcap protection + private AID STwithOvercap() => ComboLastMove switch //with Overcap protection { - AID.BrutalShell => - Ammo == MaxCartridges //if Brutal Shell is last move, check ammo count - ? (TargetsInAOERange() > 1 //if 2+ targets in AOE range - ? AID.FatedCircle //use Fated Circle - : AID.BurstStrike) //otherwise, use Burst Strike - : AID.SolidBarrel, //if not at max ammo, use Solid Barrel + AID.BrutalShell => Ammo == MaxCartridges ? BestCartSpender : AID.SolidBarrel, //if Brutal Shell is last move, use Solid Barrel regardless of ammo count AID.KeenEdge => AID.BrutalShell, //if Keen Edge is last move, use Brutal Shell _ => AID.KeenEdge, //start with Keen Edge }; - private AID NextForceSingleTarget() => ComboLastMove switch //without Overcap protection + private AID STwithoutOvercap() => ComboLastMove switch //without Overcap protection { - AID.BrutalShell => AID.SolidBarrel, //if Brutal Shell is last move, use Solid Barrel regardless of ammo count + AID.BrutalShell => AID.SolidBarrel, //if Brutal Shell is last move, use Solid Barrel AID.KeenEdge => AID.BrutalShell, //if Keen Edge is last move, use Brutal Shell _ => AID.KeenEdge, //start with Keen Edge }; #endregion #region AOE Helpers - private AID NextComboAOE() => ComboLastMove switch //with Overcap protection + private AID AOEwithOvercap() => ComboLastMove switch //with Overcap protection { - AID.DemonSlice => Ammo == MaxCartridges //if Demon Slice is last move, check ammo count - ? Unlocked(AID.FatedCircle) //if Fated Circle is unlocked - ? AID.FatedCircle //use Fated Circle - : AID.BurstStrike //otherwise, use Burst Strike - : AID.DemonSlaughter, //if not at max ammo, use Demon Slaughter + AID.DemonSlice => Ammo == MaxCartridges ? BestCartSpender : AID.DemonSlaughter, //if full ammo & Demon Slice is last move, use best cartridge spender _ => AID.DemonSlice, //start with Demon Slice }; - private AID NextForceAOE() => ComboLastMove switch //without Overcap protection + private AID AOEwithoutOvercap() => ComboLastMove switch //without Overcap protection { - AID.DemonSlice => AID.DemonSlaughter, //if Demon Slice is last move, use Demon Slaughter regardless of ammo count + AID.DemonSlice => AID.DemonSlaughter, //if not at max ammo, use Demon Slaughter _ => AID.DemonSlice, //start with Demon Slice }; #endregion @@ -873,10 +873,9 @@ private void QueueOGCD(AID aid, Actor? target, OGCDPriority prio, float basePrio Player.InCombat && //In combat target != null && //Target exists canNM && //No Mercy is available - GCD < 0.9f && //GCD is less than 0.9s ((Unlocked(AID.DoubleDown) && //Double Down is unlocked, indicating Lv90 or above - (((bfCD <= 90 && bfCD >= 30) && (Ammo >= 2 || (Ammo == 1 && ComboLastMove is AID.BrutalShell))) || //In Odd Window & conditions are met - (!(bfCD <= 90 && bfCD >= 30) && Ammo < 3))) || //In Even Window & conditions are met + (inOdd && Ammo >= 2) || //In Odd Window & conditions are met + (!inOdd && Ammo < 3)) || //In Even Window & conditions are met (!Unlocked(AID.DoubleDown) && Unlocked(AID.Bloodfest) && //Double Down is not unlocked but Bloodfest is, indicating Lv80-89 Ammo >= 1) || //Ammo is 1 or more (!Unlocked(AID.Bloodfest) && canGF) || //Bloodfest is not unlocked but Gnashing Fang is, indicating Lv60-79 @@ -951,10 +950,10 @@ private void QueueOGCD(AID aid, Actor? target, OGCDPriority prio, float basePrio ShouldUseFC //enough targets for optimal use of Fated Circle ? ShouldUseFatedCircle(CartridgeStrategy.Automatic, target) //use Fated Circle : ShouldUseBurstStrike(CartridgeStrategy.Automatic, target), //otherwise, use Burst Strike - CartridgeStrategy.BurstStrike => canBS, //Force Burst Strike if available - CartridgeStrategy.FatedCircle => canFC, //Force Fated Circle if available - CartridgeStrategy.GnashingFang => canGF && GunComboStep == 0, //Force Gnashing Fang if available and not in Reign combo - CartridgeStrategy.DoubleDown => canDD, //Force Double Down if available + CartridgeStrategy.OnlyBS => ShouldUseBurstStrike(CartridgeStrategy.Automatic, target), //Optimally use Burst Strike + CartridgeStrategy.OnlyFC => ShouldUseFatedCircle(CartridgeStrategy.Automatic, target), //Optimally use Fated Circle + CartridgeStrategy.ForceBS => canBS, //Force Burst Strike + CartridgeStrategy.ForceFC => canFC, //Force Fated Circle CartridgeStrategy.Conserve => false, //Conserve cartridges _ => false }; @@ -1001,7 +1000,8 @@ private void QueueOGCD(AID aid, Actor? target, OGCDPriority prio, float basePrio (hasNM || //No Mercy is active (!(bfCD is <= 90 and >= 30) && nmCD < 1 && - Ammo == 3)), //No Mercy is almost ready and full carts + Ammo == 3)) || //No Mercy is almost ready and full carts + Ammo == MaxCartridges && ComboLastMove is AID.BrutalShell or AID.DemonSlice, //Full carts and last move was Brutal Shell or Demon Slice _ => false }; @@ -1016,7 +1016,8 @@ private void QueueOGCD(AID aid, Actor? target, OGCDPriority prio, float basePrio (hasNM || //No Mercy is active (!(bfCD is <= 90 and >= 30) && nmCD < 1 && - Ammo == 3)), //No Mercy is almost ready and full carts + Ammo == 3)) || //No Mercy is almost ready and full carts + Ammo == MaxCartridges && ComboLastMove is AID.BrutalShell or AID.DemonSlice, //Full carts and last move was Brutal Shell or Demon Slice _ => false }; From 00835ac2381ad3a6c81d3f8352e3ed73b4e3384e Mon Sep 17 00:00:00 2001 From: ace Date: Mon, 6 Jan 2025 10:10:33 -0800 Subject: [PATCH 07/17] subLv80 SkS --- BossMod/Autorotation/akechi/AkechiGNB.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/BossMod/Autorotation/akechi/AkechiGNB.cs b/BossMod/Autorotation/akechi/AkechiGNB.cs index f7e4fd1c94..f1b0e8b6e3 100644 --- a/BossMod/Autorotation/akechi/AkechiGNB.cs +++ b/BossMod/Autorotation/akechi/AkechiGNB.cs @@ -876,10 +876,11 @@ public bool QueueAction(AID aid, Actor? target, float priority, float delay) ((Unlocked(AID.DoubleDown) && //Double Down is unlocked, indicating Lv90 or above (inOdd && Ammo >= 2) || //In Odd Window & conditions are met (!inOdd && Ammo < 3)) || //In Even Window & conditions are met - (!Unlocked(AID.DoubleDown) && Unlocked(AID.Bloodfest) && //Double Down is not unlocked but Bloodfest is, indicating Lv80-89 + (!Unlocked(AID.DoubleDown) && GCD < 0.9f && //Double Down is not unlocked, so we late weave it + ((Unlocked(AID.Bloodfest) && //but Bloodfest is, indicating Lv80-89 Ammo >= 1) || //Ammo is 1 or more (!Unlocked(AID.Bloodfest) && canGF) || //Bloodfest is not unlocked but Gnashing Fang is, indicating Lv60-79 - !Unlocked(AID.GnashingFang)), //Gnashing Fang is not unlocked, indicating Lv59 and below + !Unlocked(AID.GnashingFang)))), //Gnashing Fang is not unlocked, indicating Lv59 and below NoMercyStrategy.Force => canNM, //Force No Mercy, regardless of correct weaving NoMercyStrategy.ForceW => canNM && canWeaveIn, //Force No Mercy into any weave slot NoMercyStrategy.ForceQW => canNM && quarterWeave, //Force No Mercy into last possible second weave slot From 60ec6559c299fef9e5632ea001f1d884549f256d Mon Sep 17 00:00:00 2001 From: ace Date: Mon, 6 Jan 2025 10:11:50 -0800 Subject: [PATCH 08/17] . --- BossMod/Autorotation/akechi/AkechiGNB.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/BossMod/Autorotation/akechi/AkechiGNB.cs b/BossMod/Autorotation/akechi/AkechiGNB.cs index f1b0e8b6e3..3c34b469c6 100644 --- a/BossMod/Autorotation/akechi/AkechiGNB.cs +++ b/BossMod/Autorotation/akechi/AkechiGNB.cs @@ -51,10 +51,10 @@ public enum CooldownStrategy public enum CartridgeStrategy { Automatic, //Automatically decide when to use Burst Strike & Fated Circle - OnlyBS, //Force the use of Burst Strike; consumes 1 cartridge - OnlyFC, //Force the use of Fated Circle; consumes 1 cartridge - ForceBS, //Force the use of Gnashing Fang (cooldown only); consumes 1 cartridge - ForceFC, //Force the use of Double Down; consumes 1 cartridge (yay) + OnlyBS, //Force the use of Burst Strike; consumes 1 cartridge + OnlyFC, //Force the use of Fated Circle; consumes 1 cartridge + ForceBS, //Force the use of Gnashing Fang (cooldown only); consumes 1 cartridge + ForceFC, //Force the use of Double Down; consumes 1 cartridge (yay) Conserve //Conserves all cartridge-related abilities as much as possible } From c7f73ea7512cf609764ea65354179b38a3612b3d Mon Sep 17 00:00:00 2001 From: ace Date: Mon, 6 Jan 2025 10:15:43 -0800 Subject: [PATCH 09/17] lil cleanup --- BossMod/Autorotation/akechi/AkechiGNB.cs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/BossMod/Autorotation/akechi/AkechiGNB.cs b/BossMod/Autorotation/akechi/AkechiGNB.cs index 3c34b469c6..2fc74fa3e9 100644 --- a/BossMod/Autorotation/akechi/AkechiGNB.cs +++ b/BossMod/Autorotation/akechi/AkechiGNB.cs @@ -154,7 +154,7 @@ public enum OGCDStrategy //Off-Global Cooldown Strategy } #endregion - //Module Definitions + #region Module Definitions & Strategies public static RotationModuleDefinition Definition() { var res = new RotationModuleDefinition("Akechi GNB", //Title @@ -295,6 +295,7 @@ public static RotationModuleDefinition Definition() return res; } + #endregion #region Priorities public enum GCDPriority //priorities for GCDs (higher number = higher priority) @@ -822,6 +823,10 @@ public bool QueueAction(AID aid, Actor? target, float priority, float delay) return true; } + + #endregion + + #region Rotation Helpers private AID NextBestRotation() => ComboLastMove switch { //ST @@ -834,8 +839,6 @@ public bool QueueAction(AID aid, Actor? target, float priority, float delay) _ => ShouldUseAOE ? AOEwithoutOvercap() : STwithoutOvercap(), }; - #endregion - #region Single-Target Helpers private AID STwithOvercap() => ComboLastMove switch //with Overcap protection { @@ -864,6 +867,8 @@ public bool QueueAction(AID aid, Actor? target, float priority, float delay) }; #endregion + #endregion + #region Cooldown Helpers //No Mercy full strategy & conditions private bool ShouldUseNoMercy(NoMercyStrategy strategy, Actor? target) => strategy switch From 33db57f9108e6e3547f4fd57c2ef82e0bc65a584 Mon Sep 17 00:00:00 2001 From: ace Date: Mon, 6 Jan 2025 10:21:49 -0800 Subject: [PATCH 10/17] more cleanup, done with both modules yippie --- BossMod/Autorotation/akechi/AkechiGNB.cs | 52 +++++++++--------- BossMod/Autorotation/akechi/AkechiPLD.cs | 67 ++++++++++++------------ 2 files changed, 59 insertions(+), 60 deletions(-) diff --git a/BossMod/Autorotation/akechi/AkechiGNB.cs b/BossMod/Autorotation/akechi/AkechiGNB.cs index 2fc74fa3e9..0c8905db35 100644 --- a/BossMod/Autorotation/akechi/AkechiGNB.cs +++ b/BossMod/Autorotation/akechi/AkechiGNB.cs @@ -324,7 +324,31 @@ public static RotationModuleDefinition Definition() } #endregion - #region Placeholders for Variables + #region Upgrade Paths + private AID BestZone //Determine the best Zone to use + => Unlocked(AID.BlastingZone) //If Blasting Zone is unlocked + ? AID.BlastingZone //Use Blasting Zone + : AID.DangerZone; //Otherwise, use Danger Zone + private AID BestCartSpender //Determine the best cartridge spender to use + => ShouldUseFC //And we should use Fated Circle because of targets nearby + ? BestFatedCircle //Use Fated Circle + : canBS //Otherwise, if Burst Strike is available + ? AID.BurstStrike //Use Burst Strike + : NextBestRotation(); //Otherwise, use the next best rotation + private AID BestFatedCircle //for AOE cart spending Lv30-71 + => Unlocked(AID.FatedCircle) //If Fated Circle is unlocked + ? AID.FatedCircle //Use Fated Circle + : AID.BurstStrike; //Otherwise, use Burst Strike + private AID BestContinuation //Determine the best Continuation to use + => hasRaze ? AID.FatedBrand //If we have Ready To Raze buff + : hasBlast ? AID.Hypervelocity //If we have Ready To Blast buff + : hasGouge ? AID.EyeGouge //If we have Ready To Gouge buff + : hasTear ? AID.AbdomenTear //If we have Ready To Tear buff + : hasRip ? AID.JugularRip //If we have Ready To Rip buff + : AID.Continuation; //Otherwise, default to original hook + #endregion + + #region Module Variables //Gauge public byte Ammo; //Range: 0-2 or 0-3 max; this counts current ammo count public byte GunComboStep; //0 = Gnashing Fang & Reign of Beasts, 1 = Savage Claw, 2 = Wicked Talon, 4 = NobleBlood, 5 = LionHeart @@ -386,30 +410,6 @@ public static RotationModuleDefinition Definition() public bool JustUsed(AID aid, float variance) => JustDid(aid) && DidWithin(variance); //Check if the last action used was the desired ability & was used within a certain timeframe #endregion - #region Upgrade Paths - private AID BestZone //Determine the best Zone to use - => Unlocked(AID.BlastingZone) //If Blasting Zone is unlocked - ? AID.BlastingZone //Use Blasting Zone - : AID.DangerZone; //Otherwise, use Danger Zone - private AID BestCartSpender //Determine the best cartridge spender to use - => ShouldUseFC //And we should use Fated Circle because of targets nearby - ? BestFatedCircle //Use Fated Circle - : canBS //Otherwise, if Burst Strike is available - ? AID.BurstStrike //Use Burst Strike - : NextBestRotation(); //Otherwise, use the next best rotation - private AID BestFatedCircle //for AOE cart spending Lv30-71 - => Unlocked(AID.FatedCircle) //If Fated Circle is unlocked - ? AID.FatedCircle //Use Fated Circle - : AID.BurstStrike; //Otherwise, use Burst Strike - private AID BestContinuation //Determine the best Continuation to use - => hasRaze ? AID.FatedBrand //If we have Ready To Raze buff - : hasBlast ? AID.Hypervelocity //If we have Ready To Blast buff - : hasGouge ? AID.EyeGouge //If we have Ready To Gouge buff - : hasTear ? AID.AbdomenTear //If we have Ready To Tear buff - : hasRip ? AID.JugularRip //If we have Ready To Rip buff - : AID.Continuation; //Otherwise, default to original hook - #endregion - public override void Execute(StrategyValues strategy, Actor? primaryTarget, float estimatedAnimLockDelay, bool isMoving) //Executes our actions { #region Variables @@ -822,8 +822,6 @@ public bool QueueAction(AID aid, Actor? target, float priority, float delay) Hints.ActionsToExecute.Push(ActionID.MakeSpell(aid), target, priority, delay: delay, targetPos: targetPos); return true; } - - #endregion #region Rotation Helpers diff --git a/BossMod/Autorotation/akechi/AkechiPLD.cs b/BossMod/Autorotation/akechi/AkechiPLD.cs index bb9f0735d2..7ec983fc91 100644 --- a/BossMod/Autorotation/akechi/AkechiPLD.cs +++ b/BossMod/Autorotation/akechi/AkechiPLD.cs @@ -260,7 +260,40 @@ public static RotationModuleDefinition Definition() } #endregion - #region Variables + #region Upgrade Paths + public AID BestSpirits + => Unlocked(AID.Expiacion) //if Expiacion is unlocked + ? AID.Expiacion //then use Expiacion + : AID.SpiritsWithin; //otherwise use Spirits Within + public AID BestRequiescat + => Unlocked(AID.Imperator) //if Imperator is unlocked + ? AID.Imperator //then use Imperator + : AID.Requiescat; //otherwise use Requiescat + public AID BestHoly + => ShouldUseDMHolyCircle || ShouldNormalHolyCircle //if Holy Circle should be used + ? BestHolyCircle //then use Holy Circle + : AID.HolySpirit; //otherwise use Holy Spirit + public AID BestHolyCircle //for AOE use from Lv64-Lv71 + => HolyCircle.IsReady //if Holy Circle is ready + ? AID.HolyCircle //then use Holy Circle + : AID.HolySpirit; //then use Holy Spirit + public AID BestAtonement + => Sepulchre.IsReady //if Sepulchre is ready + ? AID.Sepulchre //then use Sepulchre + : Supplication.IsReady //if Supplication is ready + ? AID.Supplication //then use Supplication + : AID.Atonement; //otherwise use Atonement + public AID BestBlade + => BladeComboStep is 3 //if Confiteor combo is at step 3 + ? AID.BladeOfValor //then use Blade of Valor + : BladeComboStep is 2 //if Confiteor combo is at step 2 + ? AID.BladeOfTruth //then use Blade of Truth + : BladeComboStep is 1 //if Confiteor combo is at step 1 + ? AID.BladeOfFaith //then use Blade of Faith + : AID.Confiteor; //otherwise use Confiteor + #endregion + + #region Module Variables public int Oath; //Current value of the oath gauge public int BladeComboStep; //Current step in the Confiteor combo sequence public float GCDLength; //Length of the global cooldown, adjusted by skill speed and haste (baseline: 2.5s) @@ -310,38 +343,6 @@ public static RotationModuleDefinition Definition() //public Actor? BestSplashTarget() #endregion - #region Upgrade Paths - public AID BestSpirits - => Unlocked(AID.Expiacion) //if Expiacion is unlocked - ? AID.Expiacion //then use Expiacion - : AID.SpiritsWithin; //otherwise use Spirits Within - public AID BestRequiescat - => Unlocked(AID.Imperator) //if Imperator is unlocked - ? AID.Imperator //then use Imperator - : AID.Requiescat; //otherwise use Requiescat - public AID BestHoly - => ShouldUseDMHolyCircle || ShouldNormalHolyCircle //if Holy Circle should be used - ? BestHolyCircle //then use Holy Circle - : AID.HolySpirit; //otherwise use Holy Spirit - public AID BestHolyCircle //for AOE use from Lv64-Lv71 - => HolyCircle.IsReady //if Holy Circle is ready - ? AID.HolyCircle //then use Holy Circle - : AID.HolySpirit; //then use Holy Spirit - public AID BestAtonement - => Sepulchre.IsReady //if Sepulchre is ready - ? AID.Sepulchre //then use Sepulchre - : Supplication.IsReady //if Supplication is ready - ? AID.Supplication //then use Supplication - : AID.Atonement; //otherwise use Atonement - public AID BestBlade - => BladeComboStep is 3 //if Confiteor combo is at step 3 - ? AID.BladeOfValor //then use Blade of Valor - : BladeComboStep is 2 //if Confiteor combo is at step 2 - ? AID.BladeOfTruth //then use Blade of Truth - : BladeComboStep is 1 //if Confiteor combo is at step 1 - ? AID.BladeOfFaith //then use Blade of Faith - : AID.Confiteor; //otherwise use Confiteor - #endregion public override void Execute(StrategyValues strategy, Actor? primaryTarget, float estimatedAnimLockDelay, bool isMoving) //Executes our actions { #region Variables From d78a39c50362ad2b9471c981dbacecf4c2c9de7a Mon Sep 17 00:00:00 2001 From: AceAkechi123 Date: Fri, 10 Jan 2025 04:34:23 -0800 Subject: [PATCH 11/17] . --- BossMod/Autorotation/akechi/AkechiGNB.cs | 160 +++++++++++------------ 1 file changed, 80 insertions(+), 80 deletions(-) diff --git a/BossMod/Autorotation/akechi/AkechiGNB.cs b/BossMod/Autorotation/akechi/AkechiGNB.cs index 0c8905db35..060740d435 100644 --- a/BossMod/Autorotation/akechi/AkechiGNB.cs +++ b/BossMod/Autorotation/akechi/AkechiGNB.cs @@ -13,144 +13,144 @@ public sealed class AkechiGNB(RotationModuleManager manager, Actor player) : Rot //Abilities tracked for Cooldown Planner & Autorotation execution public enum Track { - AOE, //ST&AOE rotations tracking - Cooldowns, //Cooldown abilities tracking - Cartridges, //Cartridge abilities tracking - Potion, //Potion item tracking - LightningShot, //Ranged ability tracking - NoMercy, //No Mercy ability tracking - SonicBreak, //Sonic Break ability tracking - GnashingFang, //Gnashing Fang abilities tracking - Reign, //Reign abilities tracking - Bloodfest, //Bloodfest ability tracking - DoubleDown, //Double Down ability tracking - Zone, //Blasting Zone or Danger Zone ability tracking - BowShock, //Bow Shock ability tracking + AOE, //ST&AOE rotations tracking + Cooldowns, //Cooldown abilities tracking + Cartridges, //Cartridge abilities tracking + Potion, //Potion item tracking + LightningShot, //Ranged ability tracking + NoMercy, //No Mercy ability tracking + SonicBreak, //Sonic Break ability tracking + GnashingFang, //Gnashing Fang abilities tracking + Reign, //Reign abilities tracking + Bloodfest, //Bloodfest ability tracking + DoubleDown, //Double Down ability tracking + Zone, //Blasting Zone or Danger Zone ability tracking + BowShock, //Bow Shock ability tracking } //Defines the strategy for using ST/AOE actions based on the current target selection and conditions public enum AOEStrategy { - AutoFinishCombo, //Decide action based on target count but finish current combo if possible - AutoBreakCombo, //Decide action based on target count; breaks combo if needed - ForceSTwithO, //Force single-target rotation with overcap protection on cartridges - ForceSTwithoutO, //Force single-target rotation without overcap protection on cartridges - ForceAOEwithO, //Force AOE rotation with overcap protection on cartridges - ForceAOEwithoutO, //Force AOE rotation without overcap protection on cartridges - GenerateDowntime //Generate cartridges before downtime + AutoFinishCombo, //Decide action based on target count but finish current combo if possible + AutoBreakCombo, //Decide action based on target count; breaks combo if needed + ForceSTwithO, //Force single-target rotation with overcap protection on cartridges + ForceSTwithoutO, //Force single-target rotation without overcap protection on cartridges + ForceAOEwithO, //Force AOE rotation with overcap protection on cartridges + ForceAOEwithoutO, //Force AOE rotation without overcap protection on cartridges + GenerateDowntime //Generate cartridges before downtime } //Defines different strategies for executing burst damage actions based on cooldown and resource availability public enum CooldownStrategy { - Automatic, //Automatically execute based on conditions - Hold, //Hold all resources + Automatic, //Automatically execute based on conditions + Hold, //Hold all resources } //Defines the strategy for using abilities that consume cartridges, allowing for different behaviors based on combat scenarios public enum CartridgeStrategy { - Automatic, //Automatically decide when to use Burst Strike & Fated Circle - OnlyBS, //Force the use of Burst Strike; consumes 1 cartridge - OnlyFC, //Force the use of Fated Circle; consumes 1 cartridge - ForceBS, //Force the use of Gnashing Fang (cooldown only); consumes 1 cartridge - ForceFC, //Force the use of Double Down; consumes 1 cartridge (yay) - Conserve //Conserves all cartridge-related abilities as much as possible + Automatic, //Automatically decide when to use Burst Strike & Fated Circle + OnlyBS, //Only use Burst Strike as cartridge spender + OnlyFC, //Only use Fated Circle as cartridge spender + ForceBS, //Force the use of Burst Strike + ForceFC, //Force the use of Fated Circle + Conserve //Conserves all cartridge-related abilities as much as possible } //Defines strategies for potion usage in combat, determining when and how to consume potions based on the situation public enum PotionStrategy { - Manual, //Manual potion usage - AlignWithRaidBuffs, //Align potion usage with raid buffs - Immediate //Use potions immediately when available + Manual, //Manual potion usage + AlignWithRaidBuffs, //Align potion usage with raid buffs + Immediate //Use potions immediately when available } //Defines strategies for using Lightning Shot during combat based on various conditions public enum LightningShotStrategy { - OpenerFar, //Only use Lightning Shot in pre-pull & out of melee range - OpenerForce, //Force use Lightning Shot in pre-pull in any range - Force, //Force the use of Lightning Shot in any range - Allow, //Allow the use of Lightning Shot when out of melee range - Forbid //Prohibit the use of Lightning Shot + OpenerFar, //Only use Lightning Shot in pre-pull & out of melee range + OpenerForce, //Force use Lightning Shot in pre-pull in any range + Force, //Force the use of Lightning Shot in any range + Allow, //Allow the use of Lightning Shot when out of melee range + Forbid //Prohibit the use of Lightning Shot } //Defines the strategy for using No Mercy, allowing for different behaviors based on combat scenarios public enum NoMercyStrategy { - Automatic, //Automatically decide when to use No Mercy - Force, //Force the use of No Mercy regardless of conditions - ForceW, //Force the use of No Mercy in next possible weave slot - ForceQW, //Force the use of No Mercy in next last possible second weave slot - Force1, //Force the use of No Mercy when 1 cartridge is available - Force1W, //Force the use of No Mercy when 1 cartridge is available in next possible weave slot - Force1QW, //Force the use of No Mercy when 1 cartridge is available in next last possible second weave slot - Force2, //Force the use of No Mercy when 2 cartridges are available - Force2W, //Force the use of No Mercy when 2 cartridges are available in next possible weave slot - Force2QW, //Force the use of No Mercy when 2 cartridges are available in next last possible second weave slot - Force3, //Force the use of No Mercy when 3 cartridges are available - Force3W, //Force the use of No Mercy when 3 cartridges are available in next possible weave slot - Force3QW, //Force the use of No Mercy when 3 cartridges are available in next last possible second weave slot - Delay //Delay the use of No Mercy for strategic reasons + Automatic, //Automatically decide when to use No Mercy + Force, //Force the use of No Mercy regardless of conditions + ForceW, //Force the use of No Mercy in next possible weave slot + ForceQW, //Force the use of No Mercy in next last possible second weave slot + Force1, //Force the use of No Mercy when 1 cartridge is available + Force1W, //Force the use of No Mercy when 1 cartridge is available in next possible weave slot + Force1QW, //Force the use of No Mercy when 1 cartridge is available in next last possible second weave slot + Force2, //Force the use of No Mercy when 2 cartridges are available + Force2W, //Force the use of No Mercy when 2 cartridges are available in next possible weave slot + Force2QW, //Force the use of No Mercy when 2 cartridges are available in next last possible second weave slot + Force3, //Force the use of No Mercy when 3 cartridges are available + Force3W, //Force the use of No Mercy when 3 cartridges are available in next possible weave slot + Force3QW, //Force the use of No Mercy when 3 cartridges are available in next last possible second weave slot + Delay //Delay the use of No Mercy for strategic reasons } //Defines the strategy for using Sonic Break, allowing for different behaviors based on combat scenarios public enum SonicBreakStrategy { - Automatic, //Automatically decide when to use Sonic Break - Force, //Force the use of Sonic Break regardless of conditions - Early, //Force the use of Sonic Break on the first GCD slot inside No Mercy window - Late, //Force the use of Sonic Break on the last GCD slot inside No Mercy window - Delay //Delay the use of Sonic Break for strategic reasons + Automatic, //Automatically decide when to use Sonic Break + Force, //Force the use of Sonic Break regardless of conditions + Early, //Force the use of Sonic Break on the first GCD slot inside No Mercy window + Late, //Force the use of Sonic Break on the last GCD slot inside No Mercy window + Delay //Delay the use of Sonic Break for strategic reasons } //Defines the strategy for using Gnashing Fang in combos, allowing for different behaviors based on combat scenarios public enum GnashingStrategy { - Automatic, //Automatically decide when to use Gnashing Fang - ForceGnash, //Force the use of Gnashing Fang regardless of conditions - ForceClaw, //Force the use of Savage Claw action when in combo - ForceTalon, //Force the use of Wicked Talon action when in combo - Delay //Delay the use of Gnashing Fang for strategic reasons + Automatic, //Automatically decide when to use Gnashing Fang + ForceGnash, //Force the use of Gnashing Fang regardless of conditions + ForceClaw, //Force the use of Savage Claw action when in combo + ForceTalon, //Force the use of Wicked Talon action when in combo + Delay //Delay the use of Gnashing Fang for strategic reasons } //Defines the strategy for using Reign of Beasts & it's combo chain, allowing for different behaviors based on combat scenarios public enum ReignStrategy { - Automatic, //Automatically decide when to use Reign of Beasts - ForceReign, //Force the use of Reign of Beasts when available - ForceNoble, //Force the use of Noble Blood when in available - ForceLion, //Force the use of Lion Heart when in available - Delay //Delay the use of Reign combo for strategic reasons + Automatic, //Automatically decide when to use Reign of Beasts + ForceReign, //Force the use of Reign of Beasts when available + ForceNoble, //Force the use of Noble Blood when in available + ForceLion, //Force the use of Lion Heart when in available + Delay //Delay the use of Reign combo for strategic reasons } //Defines the strategy for using Bloodfest, allowing for different behaviors based on combat scenarios public enum BloodfestStrategy { - Automatic, //Automatically decide when to use Bloodfest - Force, //Force the use of Bloodfest regardless of conditions - ForceW, //Force the use of Bloodfest in next possible weave slot - Force0, //Force the use of Bloodfest only when ammo is empty - Force0W, //Force the use of Bloodfest only when ammo is empty in next possible weave slot - Delay //Delay the use of Sonic Break for strategic reasons + Automatic, //Automatically decide when to use Bloodfest + Force, //Force the use of Bloodfest regardless of conditions + ForceW, //Force the use of Bloodfest in next possible weave slot + Force0, //Force the use of Bloodfest only when ammo is empty + Force0W, //Force the use of Bloodfest only when ammo is empty in next possible weave slot + Delay //Delay the use of Sonic Break for strategic reasons } //Defines different offensive strategies that dictate how abilities and resources are used during combat public enum GCDStrategy //Global Cooldown Strategy { - Automatic, //Automatically decide when to use global offensive abilities - Force, //Force the use of global offensive abilities regardless of conditions - Delay //Delay the use of global offensive abilities for strategic reasons + Automatic, //Automatically decide when to use global offensive abilities + Force, //Force the use of global offensive abilities regardless of conditions + Delay //Delay the use of global offensive abilities for strategic reasons } public enum OGCDStrategy //Off-Global Cooldown Strategy { - Automatic, //Automatically decide when to use off-global offensive abilities - Force, //Force the use of off-global offensive abilities, regardless of weaving conditions - AnyWeave, //Force the use of off-global offensive abilities in any next possible weave slot - EarlyWeave, //Force the use of off-global offensive abilities in very next FIRST weave slot only - LateWeave, //Force the use of off-global offensive abilities in very next LAST weave slot only - Delay //Delay the use of offensive abilities for strategic reasons + Automatic, //Automatically decide when to use off-global offensive abilities + Force, //Force the use of off-global offensive abilities, regardless of weaving conditions + AnyWeave, //Force the use of off-global offensive abilities in any next possible weave slot + EarlyWeave, //Force the use of off-global offensive abilities in very next FIRST weave slot only + LateWeave, //Force the use of off-global offensive abilities in very next LAST weave slot only + Delay //Delay the use of offensive abilities for strategic reasons } #endregion From a4b218eb29a8c3fc9fe5617c4c4f9f3f2b570ce0 Mon Sep 17 00:00:00 2001 From: AceAkechi123 Date: Fri, 10 Jan 2025 04:46:40 -0800 Subject: [PATCH 12/17] oh shit --- BossMod/Autorotation/akechi/AkechiPLD.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BossMod/Autorotation/akechi/AkechiPLD.cs b/BossMod/Autorotation/akechi/AkechiPLD.cs index 7ec983fc91..67c0177da8 100644 --- a/BossMod/Autorotation/akechi/AkechiPLD.cs +++ b/BossMod/Autorotation/akechi/AkechiPLD.cs @@ -818,7 +818,7 @@ public bool QueueAction(AID aid, Actor? target, float priority, float delay) Player.InCombat && //In combat target != null && //Target exists In25y(target) && //Target in range - HolyCircle.IsReady && //can execute Holy Circle + HolySpirit.IsReady && //can execute Holy Circle DivineMight.IsActive, //Divine Might is active _ => false }; From 38b43c4f89bdbb8bc1d58340e230e6fb987ab4a2 Mon Sep 17 00:00:00 2001 From: AceAkechi123 Date: Fri, 10 Jan 2025 04:52:35 -0800 Subject: [PATCH 13/17] LowLevel Fixes --- BossMod/Autorotation/akechi/AkechiPLD.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/BossMod/Autorotation/akechi/AkechiPLD.cs b/BossMod/Autorotation/akechi/AkechiPLD.cs index 67c0177da8..c7eab97a35 100644 --- a/BossMod/Autorotation/akechi/AkechiPLD.cs +++ b/BossMod/Autorotation/akechi/AkechiPLD.cs @@ -289,8 +289,11 @@ public AID BestBlade : BladeComboStep is 2 //if Confiteor combo is at step 2 ? AID.BladeOfTruth //then use Blade of Truth : BladeComboStep is 1 //if Confiteor combo is at step 1 + && Unlocked(AID.BladeOfFaith) ? AID.BladeOfFaith //then use Blade of Faith - : AID.Confiteor; //otherwise use Confiteor + : Unlocked(AID.Confiteor) //if Confiteor is unlocked + ? AID.Confiteor //otherwise use Confiteor + : BestHoly; #endregion #region Module Variables @@ -818,7 +821,7 @@ public bool QueueAction(AID aid, Actor? target, float priority, float delay) Player.InCombat && //In combat target != null && //Target exists In25y(target) && //Target in range - HolySpirit.IsReady && //can execute Holy Circle + HolySpirit.IsReady && //can execute Holy Spirit DivineMight.IsActive, //Divine Might is active _ => false }; From a8c8db747ea7f620af5e29eefedeb7248da6673c Mon Sep 17 00:00:00 2001 From: AceAkechi123 Date: Fri, 10 Jan 2025 04:59:13 -0800 Subject: [PATCH 14/17] last touchups --- BossMod/Autorotation/akechi/AkechiPLD.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/BossMod/Autorotation/akechi/AkechiPLD.cs b/BossMod/Autorotation/akechi/AkechiPLD.cs index c7eab97a35..332ad46602 100644 --- a/BossMod/Autorotation/akechi/AkechiPLD.cs +++ b/BossMod/Autorotation/akechi/AkechiPLD.cs @@ -319,7 +319,7 @@ public AID BestBlade public (float Left, bool IsReady, bool IsActive) BladeOfHonor; //Conditions for Blade of Honor ability public (bool HasMP, bool IsReady) HolySpirit; //Conditions for Holy Spirit ability public (bool HasMP, bool IsReady) HolyCircle; //Conditions for Holy Circle ability - public uint MP; //Current MP (mana points) of the player + public uint MP; //Current MP of the player public bool ShouldUseAOE; //Check if AOE rotation should be used public bool ShouldNormalHolyCircle; //Check if Holy Circle should be used public bool ShouldUseDMHolyCircle; //Check if Holy Circle should be used under Divine Might @@ -388,10 +388,10 @@ public override void Execute(StrategyValues strategy, Actor? primaryTarget, floa Confiteor.IsReady = Unlocked(AID.Confiteor) && Confiteor.IsActive && MP >= 1000; //Confiteor ability BladeOfHonor.Left = SelfStatusLeft(SID.BladeOfHonorReady, 30); //Remaining duration of the Blade of Honor buff BladeOfHonor.IsActive = BladeOfHonor.Left > 0; //Check if the Blade of Honor buff is active - BladeOfHonor.IsReady = Unlocked(AID.BladeOfHonor) && CD(AID.BladeOfHonor) < 0.6f; //Blade of Honor ability - HolySpirit.HasMP = MP >= 1000; //Check if the player has enough mana points for Holy Spirit + BladeOfHonor.IsReady = Unlocked(AID.BladeOfHonor) && BladeOfHonor.IsActive; //Checks if Blade of Honor is ready + HolySpirit.HasMP = MP >= 1000; //Check if the player has enough MP for Holy Spirit HolySpirit.IsReady = Unlocked(AID.HolySpirit) && HolySpirit.HasMP; //Holy Spirit ability - HolyCircle.HasMP = MP >= 1000; //Check if the player has enough mana points for Holy Circle + HolyCircle.HasMP = MP >= 1000; //Check if the player has enough MP for Holy Circle HolyCircle.IsReady = Unlocked(AID.HolyCircle) && HolyCircle.HasMP; //Holy Circle ability GCDLength = ActionSpeed.GCDRounded(World.Client.PlayerStats.SkillSpeed, World.Client.PlayerStats.Haste, Player.Level); //Calculate GCD based on skill speed and haste PotionLeft = PotionStatusLeft(); //Remaining duration of the potion buff (typically 30s) @@ -401,8 +401,8 @@ public override void Execute(StrategyValues strategy, Actor? primaryTarget, floa canWeaveEarly = GCD is <= 2.5f and >= 1.25f; //Can weave in oGCDs early canWeaveLate = GCD is <= 1.25f and >= 0.1f; //Can weave in oGCDs late ShouldUseAOE = TargetsHitByPlayerAOE() > 2; //Check if AOE rotation should be used - ShouldNormalHolyCircle = !DivineMight.IsActive && TargetsHitByPlayerAOE() > 3; //Check if Holy Circle should be used - ShouldUseDMHolyCircle = DivineMight.IsActive && TargetsHitByPlayerAOE() > 2; + ShouldNormalHolyCircle = !DivineMight.IsActive && TargetsHitByPlayerAOE() > 3; //Check if Holy Circle should be used (very niche) + ShouldUseDMHolyCircle = DivineMight.IsActive && TargetsHitByPlayerAOE() > 2; //Check if Holy Circle should be used under Divine Might #region Strategy Options var AOE = strategy.Option(Track.AOE); //Retrieves AOE track From 4266a95e0d6304ed29fd7bd29061965b258ea38d Mon Sep 17 00:00:00 2001 From: AceAkechi123 Date: Fri, 10 Jan 2025 05:37:51 -0800 Subject: [PATCH 15/17] oh right, needed to fix this too --- BossMod/Autorotation/akechi/AkechiPLD.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/BossMod/Autorotation/akechi/AkechiPLD.cs b/BossMod/Autorotation/akechi/AkechiPLD.cs index 332ad46602..cb8f66cf6d 100644 --- a/BossMod/Autorotation/akechi/AkechiPLD.cs +++ b/BossMod/Autorotation/akechi/AkechiPLD.cs @@ -699,7 +699,8 @@ public bool QueueAction(AID aid, Actor? target, float priority, float delay) Player.InCombat && //In combat target != null && //Target exists FightOrFlight.IsReady && //Fight or Flight is ready - CombatTimer >= GCDLength * 2 + 0.5f, //After 2+ GCDs + (CombatTimer <= 30 && ComboLastMove is AID.RoyalAuthority or AID.RageOfHalone || //Use within 30s of combat and after Royal Authority or Rage of Halone + CombatTimer > 30), //Use after 30s of combat OGCDStrategy.Force => FightOrFlight.IsReady, //Force Fight or Flight OGCDStrategy.AnyWeave => FightOrFlight.IsReady && canWeaveIn, //Force Weave Fight or Flight OGCDStrategy.EarlyWeave => FightOrFlight.IsReady && canWeaveEarly, //Force Early Weave Fight or Flight From 7c3d813ef30e19c23b040338ada7d6e745146b2a Mon Sep 17 00:00:00 2001 From: AceAkechi123 Date: Fri, 10 Jan 2025 05:42:34 -0800 Subject: [PATCH 16/17] redundant condition --- BossMod/Autorotation/akechi/AkechiPLD.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/BossMod/Autorotation/akechi/AkechiPLD.cs b/BossMod/Autorotation/akechi/AkechiPLD.cs index cb8f66cf6d..318d21ff96 100644 --- a/BossMod/Autorotation/akechi/AkechiPLD.cs +++ b/BossMod/Autorotation/akechi/AkechiPLD.cs @@ -782,7 +782,6 @@ public bool QueueAction(AID aid, Actor? target, float priority, float delay) Player.InCombat && //In combat target != null && //Target exists In25y(target) && //Target in range - FightOrFlight.IsActive && //Fight or Flight is active Requiescat.IsActive && //Requiescat is active BladeComboStep is 0 or 1 or 2 or 3, //Blade Combo conditions are met BladeComboStrategy.ForceConfiteor => Confiteor.IsReady && BladeComboStep is 0, //Force Confiteor From 838e3fcdc9101b25f5e287e28204a1578a4c6469 Mon Sep 17 00:00:00 2001 From: AceAkechi123 Date: Sat, 11 Jan 2025 01:41:29 -0800 Subject: [PATCH 17/17] some typos, oopys, & ranged moving stuff --- BossMod/Autorotation/akechi/AkechiPLD.cs | 14 +++++++++++--- BossMod/Autorotation/akechi/AkechiSCH.cs | 6 +++--- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/BossMod/Autorotation/akechi/AkechiPLD.cs b/BossMod/Autorotation/akechi/AkechiPLD.cs index 318d21ff96..82e006e840 100644 --- a/BossMod/Autorotation/akechi/AkechiPLD.cs +++ b/BossMod/Autorotation/akechi/AkechiPLD.cs @@ -79,6 +79,7 @@ public enum DashStrategy } public enum RangedStrategy { + Automatic, //Automatically decide on ranged attacks based on conditions OpenerRangedCast, //Use Holy Spirit at the start of combat only if outside melee range OpenerCast, //Use Holy Spirit at the start of combat regardless of range ForceCast, //Force Holy Spirit when possible @@ -135,7 +136,7 @@ public static RotationModuleDefinition Definition() .AddAssociatedAction(ActionDefinitions.IDPotionStr); //Atonement Combo definitions res.Define(Track.Atonement).As("Atonement", "Atones", uiPriority: 160) - .AddOption(AtonementStrategy.Automatic, "Automatic", "Normal use of Atonement & it's combo") + .AddOption(AtonementStrategy.Automatic, "Automatic", "Normal use of Atonement & its combo chain") .AddOption(AtonementStrategy.ForceAtonement, "Force Atonement", "Force use of Atonement", 0, 30, ActionTargets.Hostile, 76) .AddOption(AtonementStrategy.ForceSupplication, "Force Supplication", "Force use of Supplication", 0, 30, ActionTargets.Hostile, 76) .AddOption(AtonementStrategy.ForceSepulchre, "Force Sepulchre", "Force use of Sepulchre", 0, 0, ActionTargets.Hostile, 76) @@ -143,12 +144,12 @@ public static RotationModuleDefinition Definition() .AddAssociatedActions(AID.Atonement, AID.Supplication, AID.Sepulchre); //Blade Combo definitions res.Define(Track.BladeCombo).As("Blade Combo", "Blades", uiPriority: 160) - .AddOption(BladeComboStrategy.Automatic, "Automatic", "Normal use of Confiteor & Blades Combo") + .AddOption(BladeComboStrategy.Automatic, "Automatic", "Normal use of Confiteor & Blades combo chain") .AddOption(BladeComboStrategy.ForceConfiteor, "Force", "Force use of Confiteor", 0, 0, ActionTargets.Hostile, 80) .AddOption(BladeComboStrategy.ForceFaith, "Force Faith", "Force use of Blade of Faith", 0, 0, ActionTargets.Hostile, 90) .AddOption(BladeComboStrategy.ForceTruth, "Force Truth", "Force use of Blade of Truth", 0, 0, ActionTargets.Hostile, 90) .AddOption(BladeComboStrategy.ForceValor, "Force Valor", "Force use of Blade of Valor", 0, 0, ActionTargets.Hostile, 90) - .AddOption(BladeComboStrategy.Delay, "Delay", "Delay use of Confiteor & Blade Combo", 0, 0, ActionTargets.None, 80) + .AddOption(BladeComboStrategy.Delay, "Delay", "Delay use of Confiteor & Blades combo chain", 0, 0, ActionTargets.None, 80) .AddAssociatedActions(AID.Confiteor, AID.BladeOfFaith, AID.BladeOfTruth, AID.BladeOfValor); //Holy action definitions res.Define(Track.Holy).As("Holy Spirit / Circle", "Holy S/C", uiPriority: 150) @@ -168,6 +169,7 @@ public static RotationModuleDefinition Definition() .AddAssociatedActions(AID.Intervene); //Ranged attack definitions res.Define(Track.Ranged).As("Ranged", "Ranged", uiPriority: 140) + .AddOption(RangedStrategy.Automatic, "Automatic", "Uses Holy Spirit when standing still; Uses Shield Lob if moving") .AddOption(RangedStrategy.OpenerRangedCast, "Opener (Cast)", "Use Holy Spirit at the start of combat if outside melee range", 0, 0, ActionTargets.Hostile, 64) .AddOption(RangedStrategy.OpenerCast, "Opener", "Use Holy Spirit at the start of combat regardless of range", 0, 0, ActionTargets.Hostile, 64) .AddOption(RangedStrategy.ForceCast, "Force Cast", "Force use of Holy Spirit", 0, 0, ActionTargets.Hostile, 64) @@ -585,6 +587,12 @@ gbStrat is GCDStrategy.Force //if Force strategy is selected Player, //on Self (no target needed) GCDPriority.ForcedGCD); //use priority } + if (rangedStrat is RangedStrategy.Automatic && //if Automatic strategy is selected + !In3y(TargetChoice(ranged) ?? primaryTarget)) //and target is not in melee range + QueueGCD(isMoving ? AID.ShieldLob //queue Shield Lob if moving + : AID.HolySpirit, //otherwise queue Holy Spirit + TargetChoice(ranged) ?? primaryTarget, //with target choice + GCDPriority.Combo123); //use priority for 123/12 combo actions if (ShouldUseRangedLob(primaryTarget, rangedStrat)) //if Shield Lob should be used QueueGCD(AID.ShieldLob, //queue Shield Lob TargetChoice(ranged) ?? primaryTarget, //with target choice diff --git a/BossMod/Autorotation/akechi/AkechiSCH.cs b/BossMod/Autorotation/akechi/AkechiSCH.cs index e15035b18f..c4672e8de1 100644 --- a/BossMod/Autorotation/akechi/AkechiSCH.cs +++ b/BossMod/Autorotation/akechi/AkechiSCH.cs @@ -338,9 +338,9 @@ public bool QueueAction(AID aid, Actor? target, float priority, float delay) private bool ShouldUseBio(Actor? target, BioStrategy strategy) => strategy switch { BioStrategy.Bio3 => Player.InCombat && target != null && bioLeft <= 3 && In25y(target), - BioStrategy.Bio6 => Player.InCombat && target != null && bioLeft <= 3 && In25y(target), - BioStrategy.Bio9 => Player.InCombat && target != null && bioLeft <= 3 && In25y(target), - BioStrategy.Bio0 => Player.InCombat && target != null && bioLeft <= 3 && In25y(target), + BioStrategy.Bio6 => Player.InCombat && target != null && bioLeft <= 6 && In25y(target), + BioStrategy.Bio9 => Player.InCombat && target != null && bioLeft <= 9 && In25y(target), + BioStrategy.Bio0 => Player.InCombat && target != null && bioLeft is 0 && In25y(target), BioStrategy.Force => true, BioStrategy.Delay => false, _ => false