diff --git a/BasicRotations/Healer/AST_Default.cs b/BasicRotations/Healer/AST_Default.cs index a65c62b..517cfa5 100644 --- a/BasicRotations/Healer/AST_Default.cs +++ b/BasicRotations/Healer/AST_Default.cs @@ -5,10 +5,13 @@ namespace DefaultRotations.Healer; [Api(1)] public sealed class AST_Default : AstrologianRotation { + #region Config Options [Range(4, 20, ConfigUnitType.Seconds)] [RotationConfig(CombatType.PvE, Name = "Use Earthly Star during countdown timer.")] public float UseEarthlyStarTime { get; set; } = 15; + #endregion + #region Countdown Logic protected override IAction? CountDownAction(float remainTime) { if (remainTime < MaleficPvE.Info.CastTime + CountDownAhead @@ -21,7 +24,9 @@ public sealed class AST_Default : AstrologianRotation return base.CountDownAction(remainTime); } + #endregion + #region Defensive Logic [RotationDesc(ActionID.CelestialIntersectionPvE, ActionID.ExaltationPvE)] protected override bool DefenseSingleAbility(IAction nextGCD, out IAction? act) { @@ -51,7 +56,9 @@ protected override bool DefenseAreaAbility(IAction nextGCD, out IAction? act) if (CollectiveUnconsciousPvE.CanUse(out act)) return true; return base.DefenseAreaAbility(nextGCD, out act); } + #endregion + #region GCD Logic protected override bool GeneralGCD(out IAction? act) { ////Add AspectedBeneficwhen not in combat. @@ -66,6 +73,19 @@ protected override bool GeneralGCD(out IAction? act) return base.GeneralGCD(out act); } + [RotationDesc(ActionID.AspectedBeneficPvE, ActionID.BeneficIiPvE, ActionID.BeneficPvE)] + protected override bool HealSingleGCD(out IAction? act) + { + if (AspectedBeneficPvE.CanUse(out act) + && (IsMoving + || AspectedBeneficPvE.Target.Target?.GetHealthRatio() > 0.4)) return true; + + if (BeneficIiPvE.CanUse(out act)) return true; + if (BeneficPvE.CanUse(out act)) return true; + + return base.HealSingleGCD(out act); + } + [RotationDesc(ActionID.AspectedHeliosPvE, ActionID.HeliosPvE)] protected override bool HealAreaGCD(out IAction? act) { @@ -73,7 +93,9 @@ protected override bool HealAreaGCD(out IAction? act) if (HeliosPvE.CanUse(out act)) return true; return base.HealAreaGCD(out act); } + #endregion + #region oGCD Logic protected override bool EmergencyAbility(IAction nextGCD, out IAction? act) { if (base.EmergencyAbility(nextGCD, out act)) return true; @@ -100,19 +122,6 @@ protected override bool GeneralAbility(IAction nextGCD, out IAction? act) return base.GeneralAbility(nextGCD, out act); } - [RotationDesc(ActionID.AspectedBeneficPvE, ActionID.BeneficIiPvE, ActionID.BeneficPvE)] - protected override bool HealSingleGCD(out IAction? act) - { - if (AspectedBeneficPvE.CanUse(out act) - && (IsMoving - || AspectedBeneficPvE.Target.Target?.GetHealthRatio() > 0.4)) return true; - - if (BeneficIiPvE.CanUse(out act)) return true; - if (BeneficPvE.CanUse(out act)) return true; - - return base.HealSingleGCD(out act); - } - protected override bool AttackAbility(IAction nextGCD, out IAction? act) { if (IsBurst && !IsMoving @@ -191,4 +200,5 @@ protected override bool HealAreaAbility(IAction nextGCD, out IAction? act) return base.HealAreaAbility(nextGCD, out act); } + #endregion } diff --git a/BasicRotations/Healer/SCH_Default.cs b/BasicRotations/Healer/SCH_Default.cs index 784cdd6..49752e4 100644 --- a/BasicRotations/Healer/SCH_Default.cs +++ b/BasicRotations/Healer/SCH_Default.cs @@ -5,6 +5,7 @@ namespace DefaultRotations.Healer; [Api(1)] public sealed class SCH_Default : ScholarRotation { + #region Config Options [RotationConfig(CombatType.PvE, Name = "Use spells with cast times to heal.")] public bool GCDHeal { get; set; } = false; @@ -13,29 +14,57 @@ public sealed class SCH_Default : ScholarRotation [RotationConfig(CombatType.PvE, Name = "Give Recitation to Tank")] public bool GiveT { get; set; } = false; + #endregion - public override bool CanHealSingleSpell => base.CanHealSingleSpell && (GCDHeal || PartyMembers.GetJobCategory(JobRole.Healer).Count() < 2); - public override bool CanHealAreaSpell => base.CanHealAreaSpell && (GCDHeal || PartyMembers.GetJobCategory(JobRole.Healer).Count() < 2); - - protected override bool EmergencyAbility(IAction nextGCD, out IAction? act) + #region Countdown Logic + protected override IAction? CountDownAction(float remainTime) { - if (nextGCD.IsTheSameTo(true, SuccorPvE, AdloquiumPvE)) - { - if (RecitationPvE.CanUse(out act)) return true; - } + if (remainTime < RuinPvE.Info.CastTime + CountDownAhead + && RuinPvE.CanUse(out var act)) return act; - //Remove Aetherpact - foreach (var item in PartyMembers) + if (PrevDUN && remainTime <= 15 && !DeploymentTacticsPvE.Cooldown.IsCoolingDown && PartyMembers.Count() > 1) { - if (item.GetHealthRatio() < 0.9) continue; - if (item.HasStatus(true, StatusID.FeyUnion_1223)) + + if (!RecitationPvE.Cooldown.IsCoolingDown) return RecitationPvE; + if (!PartyMembers.Any((n) => n.HasStatus(true, StatusID.Galvanize))) { - act = AetherpactPvE; - return true; + if (GiveT) + { + return AdloquiumPvE; + } + } + else + { + return DeploymentTacticsPvE; } } + return base.CountDownAction(remainTime); + } + #endregion - return base.EmergencyAbility(nextGCD, out act); + #region GCD Logic + [RotationDesc(ActionID.SuccorPvE)] + protected override bool HealAreaGCD(out IAction? act) + { + if (SuccorPvE.CanUse(out act)) return true; + + return base.HealAreaGCD(out act); + } + + [RotationDesc(ActionID.AdloquiumPvE, ActionID.PhysickPvE)] + protected override bool HealSingleGCD(out IAction? act) + { + if (AdloquiumPvE.CanUse(out act)) return true; + if (PhysickPvE.CanUse(out act)) return true; + + return base.HealSingleGCD(out act); + } + + [RotationDesc(ActionID.SuccorPvE)] + protected override bool DefenseAreaGCD(out IAction? act) + { + if (SuccorPvE.CanUse(out act)) return true; + return base.DefenseAreaGCD(out act); } protected override bool GeneralGCD(out IAction? act) @@ -55,51 +84,33 @@ protected override bool GeneralGCD(out IAction? act) return base.GeneralGCD(out act); } + #endregion - [RotationDesc(ActionID.AdloquiumPvE, ActionID.PhysickPvE)] - protected override bool HealSingleGCD(out IAction? act) - { - if (AdloquiumPvE.CanUse(out act)) return true; - if (PhysickPvE.CanUse(out act)) return true; - - return base.HealSingleGCD(out act); - } - - [RotationDesc(ActionID.AetherpactPvE, ActionID.ProtractionPvE, ActionID.SacredSoilPvE, ActionID.ExcogitationPvE, ActionID.LustratePvE, ActionID.AetherpactPvE)] - protected override bool HealSingleAbility(IAction nextGCD, out IAction? act) - { - var haveLink = PartyMembers.Any(p => p.HasStatus(true, StatusID.FeyUnion_1223)); - - if (AetherpactPvE.CanUse(out act) && FairyGauge >= 70 && !haveLink) return true; - if (ProtractionPvE.CanUse(out act)) return true; - if (SacredSoilPvE.CanUse(out act)) return true; - if (ExcogitationPvE.CanUse(out act)) return true; - if (LustratePvE.CanUse(out act)) return true; - if (AetherpactPvE.CanUse(out act) && !haveLink) return true; - - return base.HealSingleAbility(nextGCD, out act); - } - - [RotationDesc(ActionID.ExcogitationPvE)] - protected override bool DefenseSingleAbility(IAction nextGCD, out IAction? act) + #region oGCD Logic + protected override bool EmergencyAbility(IAction nextGCD, out IAction? act) { - if (ExcogitationPvE.CanUse(out act)) return true; - return base.DefenseSingleAbility(nextGCD, out act); - } + if (nextGCD.IsTheSameTo(true, SuccorPvE, AdloquiumPvE)) + { + if (RecitationPvE.CanUse(out act)) return true; + } - [RotationDesc(ActionID.SuccorPvE)] - protected override bool HealAreaGCD(out IAction? act) - { - if (SuccorPvE.CanUse(out act)) return true; + //Remove Aetherpact + foreach (var item in PartyMembers) + { + if (item.GetHealthRatio() < 0.9) continue; + if (item.HasStatus(true, StatusID.FeyUnion_1223)) + { + act = AetherpactPvE; + return true; + } + } - return base.HealAreaGCD(out act); + return base.EmergencyAbility(nextGCD, out act); } - [RotationDesc(ActionID.SummonSeraphPvE, ActionID.ConsolationPvE, ActionID.WhisperingDawnPvE, ActionID.SacredSoilPvE, ActionID.IndomitabilityPvE)] protected override bool HealAreaAbility(IAction nextGCD, out IAction? act) { - //慰藉 if (WhisperingDawnPvE.Cooldown.ElapsedOneChargeAfterGCD(1) || FeyIlluminationPvE.Cooldown.ElapsedOneChargeAfterGCD(1) || FeyBlessingPvE.Cooldown.ElapsedOneChargeAfterGCD(1)) { if (SummonSeraphPvE.CanUse(out act)) return true; @@ -114,11 +125,19 @@ protected override bool HealAreaAbility(IAction nextGCD, out IAction? act) return base.HealAreaAbility(nextGCD, out act); } - [RotationDesc(ActionID.SuccorPvE)] - protected override bool DefenseAreaGCD(out IAction? act) + [RotationDesc(ActionID.AetherpactPvE, ActionID.ProtractionPvE, ActionID.SacredSoilPvE, ActionID.ExcogitationPvE, ActionID.LustratePvE, ActionID.AetherpactPvE)] + protected override bool HealSingleAbility(IAction nextGCD, out IAction? act) { - if (SuccorPvE.CanUse(out act)) return true; - return base.DefenseAreaGCD(out act); + var haveLink = PartyMembers.Any(p => p.HasStatus(true, StatusID.FeyUnion_1223)); + + if (AetherpactPvE.CanUse(out act) && FairyGauge >= 70 && !haveLink) return true; + if (ProtractionPvE.CanUse(out act)) return true; + if (SacredSoilPvE.CanUse(out act)) return true; + if (ExcogitationPvE.CanUse(out act)) return true; + if (LustratePvE.CanUse(out act)) return true; + if (AetherpactPvE.CanUse(out act) && !haveLink) return true; + + return base.HealSingleAbility(nextGCD, out act); } [RotationDesc(ActionID.FeyIlluminationPvE, ActionID.ExpedientPvE, ActionID.SummonSeraphPvE, ActionID.ConsolationPvE, ActionID.SacredSoilPvE)] @@ -137,6 +156,12 @@ protected override bool DefenseAreaAbility(IAction nextGCD, out IAction? act) return base.DefenseAreaAbility(nextGCD, out act); } + [RotationDesc(ActionID.ExcogitationPvE)] + protected override bool DefenseSingleAbility(IAction nextGCD, out IAction? act) + { + if (ExcogitationPvE.CanUse(out act)) return true; + return base.DefenseSingleAbility(nextGCD, out act); + } protected override bool AttackAbility(IAction nextGCD, out IAction? act) { @@ -155,28 +180,11 @@ protected override bool AttackAbility(IAction nextGCD, out IAction? act) return base.AttackAbility(nextGCD, out act); } + #endregion - protected override IAction? CountDownAction(float remainTime) - { - if (remainTime < RuinPvE.Info.CastTime + CountDownAhead - && RuinPvE.CanUse(out var act)) return act; - - if (PrevDUN && remainTime <= 15 && !DeploymentTacticsPvE.Cooldown.IsCoolingDown && PartyMembers.Count() > 1) - { + #region Extra Methods + public override bool CanHealSingleSpell => base.CanHealSingleSpell && (GCDHeal || PartyMembers.GetJobCategory(JobRole.Healer).Count() < 2); + public override bool CanHealAreaSpell => base.CanHealAreaSpell && (GCDHeal || PartyMembers.GetJobCategory(JobRole.Healer).Count() < 2); - if (!RecitationPvE.Cooldown.IsCoolingDown) return RecitationPvE; - if (!PartyMembers.Any((n) => n.HasStatus(true, StatusID.Galvanize))) - { - if (GiveT) - { - return AdloquiumPvE; - } - } - else - { - return DeploymentTacticsPvE; - } - } - return base.CountDownAction(remainTime); - } + #endregion } diff --git a/BasicRotations/Healer/SGE_Default.cs b/BasicRotations/Healer/SGE_Default.cs index 9a6b21d..55575a7 100644 --- a/BasicRotations/Healer/SGE_Default.cs +++ b/BasicRotations/Healer/SGE_Default.cs @@ -5,18 +5,21 @@ namespace DefaultRotations.Healer; [Api(1)] public sealed class SGE_Default : SageRotation { + #region Config Options [RotationConfig(CombatType.PvE, Name = "Use spells with cast times to heal.")] public bool GCDHeal { get; set; } = false; + #endregion - public override bool CanHealSingleSpell => base.CanHealSingleSpell && (GCDHeal || PartyMembers.GetJobCategory(JobRole.Healer).Count() < 2); - public override bool CanHealAreaSpell => base.CanHealAreaSpell && (GCDHeal || PartyMembers.GetJobCategory(JobRole.Healer).Count() < 2); - + #region Countdown Logic protected override IAction? CountDownAction(float remainTime) { if (remainTime <= 1.5 && DosisPvE.CanUse(out var act)) return act; if (remainTime <= 3 && UseBurstMedicine(out act)) return act; return base.CountDownAction(remainTime); } + #endregion + + #region oGCD Logic protected override bool EmergencyAbility(IAction nextGCD, out IAction? act) { if (base.EmergencyAbility(nextGCD, out act)) return true; @@ -35,6 +38,21 @@ protected override bool EmergencyAbility(IAction nextGCD, out IAction? act) return base.EmergencyAbility(nextGCD, out act); } + [RotationDesc(ActionID.PanhaimaPvE, ActionID.KeracholePvE, ActionID.HolosPvE)] + protected override bool DefenseAreaAbility(IAction nextGCD, out IAction? act) + { + if (Addersgall <= 1) + { + if (PanhaimaPvE.CanUse(out act, onLastAbility: true)) return true; + } + + if (KeracholePvE.CanUse(out act, onLastAbility: true)) return true; + + if (HolosPvE.CanUse(out act, onLastAbility: true)) return true; + + return base.DefenseAreaAbility(nextGCD, out act); + } + [RotationDesc(ActionID.HaimaPvE, ActionID.TaurocholePvE, ActionID.PanhaimaPvE, ActionID.KeracholePvE, ActionID.HolosPvE)] protected override bool DefenseSingleAbility(IAction nextGCD, out IAction? act) { @@ -57,43 +75,80 @@ protected override bool DefenseSingleAbility(IAction nextGCD, out IAction? act) return base.DefenseSingleAbility(nextGCD, out act); } - [RotationDesc(ActionID.EukrasianDiagnosisPvE)] - protected override bool DefenseSingleGCD(out IAction? act) + [RotationDesc(ActionID.KeracholePvE, ActionID.PhysisPvE, ActionID.HolosPvE, ActionID.IxocholePvE)] + protected override bool HealAreaAbility(IAction nextGCD, out IAction? act) { - if (EukrasianDiagnosisPvE.CanUse(out act)) - { - if (EukrasianDiagnosisPvE.Target.Target?.HasStatus(true, - StatusID.EukrasianDiagnosis, - StatusID.DifferentialDiagnosis, - StatusID.EukrasianPrognosis, - StatusID.Galvanize - ) ?? false) return false; + if (PhysisIiPvE.CanUse(out act)) return true; + if (!PhysisIiPvE.EnoughLevel && PhysisPvE.CanUse(out act)) return true; - if (EukrasiaPvE.CanUse(out act)) return true; + if (KeracholePvE.CanUse(out act, onLastAbility: true) && EnhancedKeracholeTrait.EnoughLevel) return true; - act = EukrasianDiagnosisPvE; - return true; - } + if (HolosPvE.CanUse(out act, onLastAbility: true) && PartyMembersAverHP < 0.50f) return true; - return base.DefenseSingleGCD(out act); + if (IxocholePvE.CanUse(out act, onLastAbility: true)) return true; + + if (KeracholePvE.CanUse(out act, onLastAbility: true)) return true; + + return base.HealAreaAbility(nextGCD, out act); } - [RotationDesc(ActionID.PanhaimaPvE, ActionID.KeracholePvE, ActionID.HolosPvE)] - protected override bool DefenseAreaAbility(IAction nextGCD, out IAction? act) + [RotationDesc(ActionID.TaurocholePvE, ActionID.KeracholePvE, ActionID.DruocholePvE, ActionID.HolosPvE, ActionID.PhysisPvE, ActionID.PanhaimaPvE)] + protected override bool HealSingleAbility(IAction nextGCD, out IAction? act) { - if (Addersgall <= 1) + if (TaurocholePvE.CanUse(out act)) return true; + + if (KeracholePvE.CanUse(out act) && EnhancedKeracholeTrait.EnoughLevel) return true; + + if ((!TaurocholePvE.EnoughLevel || TaurocholePvE.Cooldown.IsCoolingDown) && DruocholePvE.CanUse(out act)) return true; + + if (SoteriaPvE.CanUse(out act) && PartyMembers.Any(b => b.HasStatus(true, StatusID.Kardion) && b.GetHealthRatio() < 0.85f)) return true; + + + var tank = PartyMembers.GetJobCategory(JobRole.Tank); + if (Addersgall < 1 && (tank.Any(t => t.GetHealthRatio() < 0.65f) || PartyMembers.Any(b => b.GetHealthRatio() < 0.20f))) { - if (PanhaimaPvE.CanUse(out act, onLastAbility: true)) return true; + if (HaimaPvE.CanUse(out act, onLastAbility: true)) return true; + + if (PhysisIiPvE.CanUse(out act)) return true; + if (!PhysisIiPvE.EnoughLevel && PhysisPvE.CanUse(out act)) return true; + + if (HolosPvE.CanUse(out act, onLastAbility: true)) return true; + + if ((!HaimaPvE.EnoughLevel || HaimaPvE.Cooldown.ElapsedAfter(20)) && PanhaimaPvE.CanUse(out act, onLastAbility: true)) return true; } - if (KeracholePvE.CanUse(out act, onLastAbility: true)) return true; + if (tank.Any(t => t.GetHealthRatio() < 0.60f)) + { + if (ZoePvE.CanUse(out act)) return true; + } - if (HolosPvE.CanUse(out act, onLastAbility: true)) return true; + if (tank.Any(t => t.GetHealthRatio() < 0.70f) || PartyMembers.Any(b => b.GetHealthRatio() < 0.30f)) + { + if (KrasisPvE.CanUse(out act)) return true; + } - return base.DefenseAreaAbility(nextGCD, out act); + if (KeracholePvE.CanUse(out act)) return true; + + return base.HealSingleAbility(nextGCD, out act); } [RotationDesc(ActionID.EukrasianPrognosisPvE)] + + protected override bool GeneralAbility(IAction nextGCD, out IAction? act) + { + if (KardiaPvE.CanUse(out act)) return true; + + if (Addersgall <= 1 && RhizomataPvE.CanUse(out act)) return true; + + if (SoteriaPvE.CanUse(out act) && PartyMembers.Any(b => b.HasStatus(true, StatusID.Kardion) && b.GetHealthRatio() < HealthSingleAbility)) return true; + + if (PepsisPvE.CanUse(out act)) return true; + + return base.GeneralAbility(nextGCD, out act); + } + #endregion + + #region GCD Logic protected override bool DefenseAreaGCD(out IAction? act) { if (EukrasianPrognosisPvE.CanUse(out act)) @@ -113,17 +168,25 @@ protected override bool DefenseAreaGCD(out IAction? act) return base.DefenseAreaGCD(out act); } - protected override bool GeneralAbility(IAction nextGCD, out IAction? act) + [RotationDesc(ActionID.EukrasianDiagnosisPvE)] + protected override bool DefenseSingleGCD(out IAction? act) { - if (KardiaPvE.CanUse(out act)) return true; - - if (Addersgall <= 1 && RhizomataPvE.CanUse(out act)) return true; + if (EukrasianDiagnosisPvE.CanUse(out act)) + { + if (EukrasianDiagnosisPvE.Target.Target?.HasStatus(true, + StatusID.EukrasianDiagnosis, + StatusID.DifferentialDiagnosis, + StatusID.EukrasianPrognosis, + StatusID.Galvanize + ) ?? false) return false; - if (SoteriaPvE.CanUse(out act) && PartyMembers.Any(b => b.HasStatus(true, StatusID.Kardion) && b.GetHealthRatio() < HealthSingleAbility)) return true; + if (EukrasiaPvE.CanUse(out act)) return true; - if (PepsisPvE.CanUse(out act)) return true; + act = EukrasianDiagnosisPvE; + return true; + } - return base.GeneralAbility(nextGCD, out act); + return base.DefenseSingleGCD(out act); } protected override bool GeneralGCD(out IAction? act) @@ -176,53 +239,6 @@ protected override bool GeneralGCD(out IAction? act) return base.GeneralGCD(out act); } - [RotationDesc(ActionID.TaurocholePvE, ActionID.KeracholePvE, ActionID.DruocholePvE, ActionID.HolosPvE, ActionID.PhysisPvE, ActionID.PanhaimaPvE)] - protected override bool HealSingleAbility(IAction nextGCD, out IAction? act) - { - if (TaurocholePvE.CanUse(out act)) return true; - - if (KeracholePvE.CanUse(out act) && EnhancedKeracholeTrait.EnoughLevel) return true; - - if ((!TaurocholePvE.EnoughLevel || TaurocholePvE.Cooldown.IsCoolingDown) && DruocholePvE.CanUse(out act)) return true; - - if (SoteriaPvE.CanUse(out act) && PartyMembers.Any(b => b.HasStatus(true, StatusID.Kardion) && b.GetHealthRatio() < 0.85f)) return true; - - - var tank = PartyMembers.GetJobCategory(JobRole.Tank); - if (Addersgall < 1 && (tank.Any(t => t.GetHealthRatio() < 0.65f) || PartyMembers.Any(b => b.GetHealthRatio() < 0.20f))) - { - if (HaimaPvE.CanUse(out act, onLastAbility: true)) return true; - - if (PhysisIiPvE.CanUse(out act)) return true; - if (!PhysisIiPvE.EnoughLevel && PhysisPvE.CanUse(out act)) return true; - - if (HolosPvE.CanUse(out act, onLastAbility: true)) return true; - - if ((!HaimaPvE.EnoughLevel || HaimaPvE.Cooldown.ElapsedAfter(20)) && PanhaimaPvE.CanUse(out act, onLastAbility: true)) return true; - } - - if (tank.Any(t => t.GetHealthRatio() < 0.60f)) - { - if (ZoePvE.CanUse(out act)) return true; - } - - if (tank.Any(t => t.GetHealthRatio() < 0.70f) || PartyMembers.Any(b => b.GetHealthRatio() < 0.30f)) - { - if (KrasisPvE.CanUse(out act)) return true; - } - - if (KeracholePvE.CanUse(out act)) return true; - - return base.HealSingleAbility(nextGCD, out act); - } - - [RotationDesc(ActionID.DiagnosisPvE)] - protected override bool HealSingleGCD(out IAction? act) - { - if (DiagnosisPvE.CanUse(out act)) return true; - return base.HealSingleGCD(out act); - } - [RotationDesc(ActionID.PneumaPvE, ActionID.PrognosisPvE, ActionID.EukrasianPrognosisPvE)] protected override bool HealAreaGCD(out IAction? act) { @@ -246,20 +262,16 @@ protected override bool HealAreaGCD(out IAction? act) return base.HealAreaGCD(out act); } - [RotationDesc(ActionID.KeracholePvE, ActionID.PhysisPvE, ActionID.HolosPvE, ActionID.IxocholePvE)] - protected override bool HealAreaAbility(IAction nextGCD, out IAction? act) + [RotationDesc(ActionID.DiagnosisPvE)] + protected override bool HealSingleGCD(out IAction? act) { - if (PhysisIiPvE.CanUse(out act)) return true; - if (!PhysisIiPvE.EnoughLevel && PhysisPvE.CanUse(out act)) return true; - - if (KeracholePvE.CanUse(out act, onLastAbility: true) && EnhancedKeracholeTrait.EnoughLevel) return true; - - if (HolosPvE.CanUse(out act, onLastAbility: true) && PartyMembersAverHP < 0.50f) return true; - - if (IxocholePvE.CanUse(out act, onLastAbility: true)) return true; - - if (KeracholePvE.CanUse(out act, onLastAbility: true)) return true; - - return base.HealAreaAbility(nextGCD, out act); + if (DiagnosisPvE.CanUse(out act)) return true; + return base.HealSingleGCD(out act); } + #endregion + + #region Extra Methods + public override bool CanHealSingleSpell => base.CanHealSingleSpell && (GCDHeal || PartyMembers.GetJobCategory(JobRole.Healer).Count() < 2); + public override bool CanHealAreaSpell => base.CanHealAreaSpell && (GCDHeal || PartyMembers.GetJobCategory(JobRole.Healer).Count() < 2); + #endregion } diff --git a/BasicRotations/Healer/WHM_Default.cs b/BasicRotations/Healer/WHM_Default.cs index cbb70c0..a1dfdcd 100644 --- a/BasicRotations/Healer/WHM_Default.cs +++ b/BasicRotations/Healer/WHM_Default.cs @@ -5,65 +5,30 @@ namespace DefaultRotations.Healer; [Api(1)] public sealed class WHM_Default :WhiteMageRotation { + #region Config Options [RotationConfig(CombatType.PvE, Name = "Use Lily at max stacks.")] public bool UseLilyWhenFull { get; set; } = true; [RotationConfig(CombatType.PvE, Name = "Regen on Tank at 5 seconds remaining on Countdown.")] public bool UsePreRegen { get; set; } = true; + #endregion - public WHM_Default() - { - AfflatusRapturePvE.Setting.RotationCheck = () => BloodLily < 3; - AfflatusSolacePvE.Setting.RotationCheck = () => BloodLily < 3; - } - - protected override bool GeneralGCD(out IAction? act) - { - //if (NotInCombatDelay && RegenDefense.CanUse(out act)) return true; - - if (AfflatusMiseryPvE.CanUse(out act, skipAoeCheck: true)) return true; - - bool liliesNearlyFull = Lily == 2 && LilyTime > 13; - bool liliesFullNoBlood = Lily == 3; - if (UseLilyWhenFull && (liliesNearlyFull || liliesFullNoBlood) && AfflatusMiseryPvE.EnoughLevel && BloodLily < 3) - { - if (UseLily(out act)) return true; - } - - if (HolyPvE.CanUse(out act)) return true; - - if (AeroPvE.CanUse(out act)) return true; - - if (StonePvE.CanUse(out act)) return true; - - if (Lily >= 2) - { - if (UseLily(out act)) return true; - } - - if (AeroPvE.CanUse(out act, skipStatusProvideCheck: true)) return true; - - return base.GeneralGCD(out act); - } - - private bool UseLily(out IAction? act) + #region Countdown Logic + protected override IAction? CountDownAction(float remainTime) { - if (AfflatusRapturePvE.CanUse(out act, skipAoeCheck: true)) return true; - if (AfflatusSolacePvE.CanUse(out act)) return true; - return false; - } + if (remainTime < StonePvE.Info.CastTime + CountDownAhead + && StonePvE.CanUse(out var act)) return act; - protected override bool AttackAbility(IAction nextGCD, out IAction? act) - { - if (InCombat) + if (UsePreRegen && remainTime <= 5 && remainTime > 3) { - if (PresenceOfMindPvE.CanUse(out act)) return true; - if (AssizePvE.CanUse(out act, skipAoeCheck: true)) return true; + if (RegenPvE.CanUse(out act)) return act; + if (DivineBenisonPvE.CanUse(out act)) return act; } - - return base.AttackAbility(nextGCD, out act); + return base.CountDownAction(remainTime); } + #endregion + #region oGCD Logic protected override bool EmergencyAbility(IAction nextGCD, out IAction? act) { if (nextGCD is IBaseAction action && action.Info.MPNeed >= 1000 && @@ -78,18 +43,37 @@ protected override bool EmergencyAbility(IAction nextGCD, out IAction? act) return base.EmergencyAbility(nextGCD, out act); } - [RotationDesc(ActionID.AfflatusSolacePvE, ActionID.RegenPvE, ActionID.CureIiPvE, ActionID.CurePvE)] - protected override bool HealSingleGCD(out IAction? act) + [RotationDesc(ActionID.TemperancePvE, ActionID.LiturgyOfTheBellPvE)] + protected override bool DefenseAreaAbility(IAction nextGCD, out IAction? act) { - if (AfflatusSolacePvE.CanUse(out act)) return true; + act = null; + if (TemperancePvE.Cooldown.IsCoolingDown && !TemperancePvE.Cooldown.WillHaveOneCharge(100) + || LiturgyOfTheBellPvE.Cooldown.IsCoolingDown && !LiturgyOfTheBellPvE.Cooldown.WillHaveOneCharge(160)) return false; - if (RegenPvE.CanUse(out act) && (RegenPvE.Target.Target?.GetHealthRatio() > 0.3)) return true; + if (TemperancePvE.CanUse(out act)) return true; - if (CureIiPvE.CanUse(out act)) return true; + if (LiturgyOfTheBellPvE.CanUse(out act, skipAoeCheck: true)) return true; + return base.DefenseAreaAbility(nextGCD, out act); + } - if (CurePvE.CanUse(out act)) return true; + [RotationDesc(ActionID.DivineBenisonPvE, ActionID.AquaveilPvE)] + protected override bool DefenseSingleAbility(IAction nextGCD, out IAction? act) + { + act = null; + if (DivineBenisonPvE.Cooldown.IsCoolingDown && !DivineBenisonPvE.Cooldown.WillHaveOneCharge(15) + || AquaveilPvE.Cooldown.IsCoolingDown && !AquaveilPvE.Cooldown.WillHaveOneCharge(52)) return false; - return base.HealSingleGCD(out act); + if (DivineBenisonPvE.CanUse(out act)) return true; + + if (AquaveilPvE.CanUse(out act)) return true; + return base.DefenseSingleAbility(nextGCD, out act); + } + + [RotationDesc(ActionID.AsylumPvE)] + protected override bool HealAreaAbility(IAction nextGCD, out IAction? act) + { + if (AsylumPvE.CanUse(out act)) return true; + return base.HealAreaAbility(nextGCD, out act); } [RotationDesc(ActionID.BenedictionPvE, ActionID.AsylumPvE, ActionID.DivineBenisonPvE, ActionID.TetragrammatonPvE)] @@ -106,6 +90,20 @@ protected override bool HealSingleAbility(IAction nextGCD, out IAction? act) return base.HealSingleAbility(nextGCD, out act); } + protected override bool AttackAbility(IAction nextGCD, out IAction? act) + { + if (InCombat) + { + if (PresenceOfMindPvE.CanUse(out act)) return true; + if (AssizePvE.CanUse(out act, skipAoeCheck: true)) return true; + } + + return base.AttackAbility(nextGCD, out act); + } + #endregion + + #region GCD Logic + [RotationDesc(ActionID.AfflatusRapturePvE, ActionID.MedicaIiPvE, ActionID.CureIiiPvE, ActionID.MedicaPvE)] protected override bool HealAreaGCD(out IAction? act) { @@ -122,54 +120,67 @@ protected override bool HealAreaGCD(out IAction? act) return base.HealAreaGCD(out act); } - [RotationDesc(ActionID.AsylumPvE)] - protected override bool HealAreaAbility(IAction nextGCD, out IAction? act) + [RotationDesc(ActionID.AfflatusSolacePvE, ActionID.RegenPvE, ActionID.CureIiPvE, ActionID.CurePvE)] + protected override bool HealSingleGCD(out IAction? act) { - if (AsylumPvE.CanUse(out act)) return true; - return base.HealAreaAbility(nextGCD, out act); - } + if (AfflatusSolacePvE.CanUse(out act)) return true; - [RotationDesc(ActionID.DivineBenisonPvE, ActionID.AquaveilPvE)] - protected override bool DefenseSingleAbility(IAction nextGCD, out IAction? act) - { - act = null; - if (DivineBenisonPvE.Cooldown.IsCoolingDown && !DivineBenisonPvE.Cooldown.WillHaveOneCharge(15) - || AquaveilPvE.Cooldown.IsCoolingDown && !AquaveilPvE.Cooldown.WillHaveOneCharge(52)) return false; + if (RegenPvE.CanUse(out act) && (RegenPvE.Target.Target?.GetHealthRatio() > 0.3)) return true; - if (DivineBenisonPvE.CanUse(out act)) return true; + if (CureIiPvE.CanUse(out act)) return true; - if (AquaveilPvE.CanUse(out act)) return true; - return base.DefenseSingleAbility(nextGCD, out act); + if (CurePvE.CanUse(out act)) return true; + + return base.HealSingleGCD(out act); } - [RotationDesc(ActionID.TemperancePvE, ActionID.LiturgyOfTheBellPvE)] - protected override bool DefenseAreaAbility(IAction nextGCD, out IAction? act) + protected override bool GeneralGCD(out IAction? act) { - act = null; - if (TemperancePvE.Cooldown.IsCoolingDown && !TemperancePvE.Cooldown.WillHaveOneCharge(100) - || LiturgyOfTheBellPvE.Cooldown.IsCoolingDown && !LiturgyOfTheBellPvE.Cooldown.WillHaveOneCharge(160)) return false; + //if (NotInCombatDelay && RegenDefense.CanUse(out act)) return true; - if (TemperancePvE.CanUse(out act)) return true; + if (AfflatusMiseryPvE.CanUse(out act, skipAoeCheck: true)) return true; - if (LiturgyOfTheBellPvE.CanUse(out act, skipAoeCheck: true)) return true; - return base.DefenseAreaAbility(nextGCD, out act); - } + bool liliesNearlyFull = Lily == 2 && LilyTime > 13; + bool liliesFullNoBlood = Lily == 3; + if (UseLilyWhenFull && (liliesNearlyFull || liliesFullNoBlood) && AfflatusMiseryPvE.EnoughLevel && BloodLily < 3) + { + if (UseLily(out act)) return true; + } - protected override IAction? CountDownAction(float remainTime) - { - if (remainTime < StonePvE.Info.CastTime + CountDownAhead - && StonePvE.CanUse(out var act)) return act; + if (HolyPvE.CanUse(out act)) return true; - if (UsePreRegen && remainTime <= 5 && remainTime > 3) + if (AeroPvE.CanUse(out act)) return true; + + if (StonePvE.CanUse(out act)) return true; + + if (Lily >= 2) { - if (RegenPvE.CanUse(out act)) return act; - if (DivineBenisonPvE.CanUse(out act)) return act; + if (UseLily(out act)) return true; } - return base.CountDownAction(remainTime); + + if (AeroPvE.CanUse(out act, skipStatusProvideCheck: true)) return true; + + return base.GeneralGCD(out act); + } + #endregion + + #region Extra Methods + public WHM_Default() + { + AfflatusRapturePvE.Setting.RotationCheck = () => BloodLily < 3; + AfflatusSolacePvE.Setting.RotationCheck = () => BloodLily < 3; + } + + private bool UseLily(out IAction? act) + { + if (AfflatusRapturePvE.CanUse(out act, skipAoeCheck: true)) return true; + if (AfflatusSolacePvE.CanUse(out act)) return true; + return false; } - //public override void DisplayStatus() - //{ - // ImGui.Text(LilyTime.ToString()); - //} + /*public override void DisplayStatus() + { + ImGui.Text(LilyTime.ToString()); + }*/ + #endregion } diff --git a/BasicRotations/Magical/BLM_Beta.cs b/BasicRotations/Magical/BLM_Beta.cs index a085fc3..81d7120 100644 --- a/BasicRotations/Magical/BLM_Beta.cs +++ b/BasicRotations/Magical/BLM_Beta.cs @@ -5,33 +5,7 @@ [Api(1)] public class BLM_Beta : BlackMageRotation { - private bool NeedToGoIce - { - get - { - //Can use Despair. - if (DespairPvE.EnoughLevel && CurrentMp >= DespairPvE.Info.MPNeed) return false; - - //Can use Fire1 - if (FirePvE.EnoughLevel && CurrentMp >= FirePvE.Info.MPNeed) return false; - - return true; - } - } - - private bool NeedToTransposeGoIce(bool usedOne) - { - if (!NeedToGoIce) return false; - if (!ParadoxPvE.EnoughLevel) return false; - var compare = usedOne ? -1 : 0; - var count = PolyglotStacks; - if (count == compare++) return false; - if (count == compare++ && !EnchinaEndAfterGCD(2)) return false; - if (count >= compare && (HasFire || SwiftcastPvE.Cooldown.WillHaveOneChargeGCD(2) || TriplecastPvE.Cooldown.WillHaveOneChargeGCD(2))) return true; - if (!HasFire && !SwiftcastPvE.Cooldown.WillHaveOneChargeGCD(2) && !TriplecastPvE.CanUse(out _, gcdCountForAbility: 8)) return false; - return true; - } - + #region Config Options [RotationConfig(CombatType.PvE, Name = "Use Transpose to Astral Fire before Paradox")] public bool UseTransposeForParadox { get; set; } = true; @@ -40,7 +14,9 @@ private bool NeedToTransposeGoIce(bool usedOne) [RotationConfig(CombatType.PvE, Name = @"Use ""Double Paradox"" rotation [N15]")] public bool UseN15 { get; set; } = false; + #endregion + #region Countdown Logic protected override IAction? CountDownAction(float remainTime) { IAction act; @@ -51,6 +27,31 @@ private bool NeedToTransposeGoIce(bool usedOne) if (remainTime <= 12 && SharpcastPvE.CanUse(out act, usedUp: true)) return act; return base.CountDownAction(remainTime); } + #endregion + + #region oGCD Logic + protected override bool EmergencyAbility(IAction nextGCD, out IAction? act) + { + //To Fire + if (CurrentMp >= 7200 && UmbralIceStacks == 2 && ParadoxPvE.EnoughLevel) + { + if ((HasFire || HasSwift) && TransposePvE.CanUse(out act, onLastAbility: true)) return true; + } + if (nextGCD.IsTheSameTo(false, FireIiiPvE) && HasFire) + { + if (TransposePvE.CanUse(out act)) return true; + } + + //Using Manafont + if (InAstralFire) + { + if (CurrentMp == 0 && ManafontPvE.CanUse(out act)) return true; + //To Ice + if (NeedToTransposeGoIce(true) && TransposePvE.CanUse(out act)) return true; + } + + return base.EmergencyAbility(nextGCD, out act); + } protected override bool AttackAbility(IAction nextGCD, out IAction? act) { @@ -75,30 +76,9 @@ protected override bool AttackAbility(IAction nextGCD, out IAction? act) if (AmplifierPvE.CanUse(out act)) return true; return base.AttackAbility(nextGCD, out act); } + #endregion - protected override bool EmergencyAbility(IAction nextGCD, out IAction? act) - { - //To Fire - if (CurrentMp >= 7200 && UmbralIceStacks == 2 && ParadoxPvE.EnoughLevel) - { - if ((HasFire || HasSwift) && TransposePvE.CanUse(out act, onLastAbility: true)) return true; - } - if (nextGCD.IsTheSameTo(false, FireIiiPvE) && HasFire) - { - if (TransposePvE.CanUse(out act)) return true; - } - - //Using Manafont - if (InAstralFire) - { - if (CurrentMp == 0 && ManafontPvE.CanUse(out act)) return true; - //To Ice - if (NeedToTransposeGoIce(true) && TransposePvE.CanUse(out act)) return true; - } - - return base.EmergencyAbility(nextGCD, out act); - } - + #region GCD Logic protected override bool GeneralGCD(out IAction? act) { if (InFireOrIce(out act, out var mustGo)) return true; @@ -112,26 +92,9 @@ protected override bool GeneralGCD(out IAction? act) return base.GeneralGCD(out act); } + #endregion - private bool InFireOrIce(out IAction? act, out bool mustGo) - { - act = null; - mustGo = false; - if (InUmbralIce) - { - if (GoFire(out act)) return true; - if (MaintainIce(out act)) return true; - if (DoIce(out act)) return true; - } - if (InAstralFire) - { - if (GoIce(out act)) return true; - if (MaintainFire(out act)) return true; - if (DoFire(out act)) return true; - } - return false; - } - + #region Ice Logic private bool GoIce(out IAction? act) { act = null; @@ -197,7 +160,9 @@ private bool DoIce(out IAction? act) if (BlizzardPvE.CanUse(out act)) return true; return false; } + #endregion + #region Fire Logic private bool GoFire(out IAction? act) { act = null; @@ -287,7 +252,27 @@ private bool DoFire(out IAction? act) return false; } + #endregion + #region Extra Methods + private bool InFireOrIce(out IAction? act, out bool mustGo) + { + act = null; + mustGo = false; + if (InUmbralIce) + { + if (GoFire(out act)) return true; + if (MaintainIce(out act)) return true; + if (DoIce(out act)) return true; + } + if (InAstralFire) + { + if (GoIce(out act)) return true; + if (MaintainFire(out act)) return true; + if (DoFire(out act)) return true; + } + return false; + } private bool UseInstanceSpell(out IAction? act) { if (UsePolyglot(out act)) return true; @@ -354,6 +339,32 @@ private bool MaintainStatus(out IAction? act) return false; } + private bool NeedToGoIce + { + get + { + //Can use Despair. + if (DespairPvE.EnoughLevel && CurrentMp >= DespairPvE.Info.MPNeed) return false; + + //Can use Fire1 + if (FirePvE.EnoughLevel && CurrentMp >= FirePvE.Info.MPNeed) return false; + + return true; + } + } + + private bool NeedToTransposeGoIce(bool usedOne) + { + if (!NeedToGoIce) return false; + if (!ParadoxPvE.EnoughLevel) return false; + var compare = usedOne ? -1 : 0; + var count = PolyglotStacks; + if (count == compare++) return false; + if (count == compare++ && !EnchinaEndAfterGCD(2)) return false; + if (count >= compare && (HasFire || SwiftcastPvE.Cooldown.WillHaveOneChargeGCD(2) || TriplecastPvE.Cooldown.WillHaveOneChargeGCD(2))) return true; + if (!HasFire && !SwiftcastPvE.Cooldown.WillHaveOneChargeGCD(2) && !TriplecastPvE.CanUse(out _, gcdCountForAbility: 8)) return false; + return true; + } [RotationDesc(ActionID.BetweenTheLinesPvE, ActionID.LeyLinesPvE)] protected override bool HealSingleAbility(IAction nextGCD, out IAction? act) @@ -363,4 +374,5 @@ protected override bool HealSingleAbility(IAction nextGCD, out IAction? act) return base.HealSingleAbility(nextGCD, out act); } + #endregion } \ No newline at end of file diff --git a/BasicRotations/Magical/PTM_Default.cs b/BasicRotations/Magical/PTM_Default.cs index 30b5151..efe7f85 100644 --- a/BasicRotations/Magical/PTM_Default.cs +++ b/BasicRotations/Magical/PTM_Default.cs @@ -1,76 +1,76 @@ -//namespace DefaultRotations.Magical; - -//[Rotation("LTS's Default", CombatType.PvE, GameVersion = "7.0")] -//[SourceCode(Path = "main/DefaultRotations/Magical/PTM_Default.cs")] -//[Api(1)] -//public sealed class PTM_Default : PictomancerRotation -//{ -// #region Countdown logic -// // Defines logic for actions to take during the countdown before combat starts. -// protected override IAction? CountDownAction(float remainTime) -// { - -// return base.CountDownAction(remainTime); -// } -// #endregion - -// #region Emergency Logic -// // Determines emergency actions to take based on the next planned GCD action. -// protected override bool EmergencyAbility(IAction nextGCD, out IAction? act) -// { -// act = null; - -// return base.EmergencyAbility(nextGCD, out act); -// } -// #endregion - -// #region oGCD Logic -// protected override bool AttackAbility(IAction nextGCD, out IAction? act) -// { -// act = null; - - -// return base.AttackAbility(nextGCD, out act); -// } - -// protected override bool MoveForwardAbility(IAction nextGCD, out IAction? act) -// { -// act = null; - - -// return base.MoveForwardAbility(nextGCD, out act); -// } -// #endregion - -// #region GCD Logic -// protected override bool MoveForwardGCD(out IAction? act) -// { -// act = null; - -// return base.MoveForwardGCD(out act); -// } - -// protected override bool GeneralGCD(out IAction? act) -// { -// act = null; - -// return base.GeneralGCD(out act); -// } - -// private bool AttackGCD(out IAction? act, bool burst) -// { -// act = null; - -// return false; -// } -// #endregion - -// #region Extra Methods -// // Extra private helper methods for determining the usability of specific abilities under certain conditions. -// // These methods simplify the main logic by encapsulating specific checks related to abilities' cooldowns and prerequisites. -// private bool CanUseExamplePvE(out IAction? act) -// { - -// } -// #endregion -//} \ No newline at end of file +/*namespace DefaultRotations.Magical; + +[Rotation("LTS's Default", CombatType.PvE, GameVersion = "7.0")] +[SourceCode(Path = "main/DefaultRotations/Magical/PTM_Default.cs")] +[Api(1)] +public sealed class PTM_Default : PictomancerRotation +{ + #region Countdown logic + // Defines logic for actions to take during the countdown before combat starts. + protected override IAction? CountDownAction(float remainTime) + { + + return base.CountDownAction(remainTime); + } + #endregion + + #region Emergency Logic + // Determines emergency actions to take based on the next planned GCD action. + protected override bool EmergencyAbility(IAction nextGCD, out IAction? act) + { + act = null; + + return base.EmergencyAbility(nextGCD, out act); + } + #endregion + + #region oGCD Logic + protected override bool AttackAbility(IAction nextGCD, out IAction? act) + { + act = null; + + + return base.AttackAbility(nextGCD, out act); + } + + protected override bool MoveForwardAbility(IAction nextGCD, out IAction? act) + { + act = null; + + + return base.MoveForwardAbility(nextGCD, out act); + } + #endregion + + #region GCD Logic + protected override bool MoveForwardGCD(out IAction? act) + { + act = null; + + return base.MoveForwardGCD(out act); + } + + protected override bool GeneralGCD(out IAction? act) + { + act = null; + + return base.GeneralGCD(out act); + } + + private bool AttackGCD(out IAction? act, bool burst) + { + act = null; + + return false; + } + #endregion + + #region Extra Methods + // Extra private helper methods for determining the usability of specific abilities under certain conditions. + // These methods simplify the main logic by encapsulating specific checks related to abilities' cooldowns and prerequisites. + private bool CanUseExamplePvE(out IAction? act) + { + + } + #endregion +}*/ \ No newline at end of file diff --git a/BasicRotations/Magical/RDM_Default.cs b/BasicRotations/Magical/RDM_Default.cs index 7fe6ca8..956c3d1 100644 --- a/BasicRotations/Magical/RDM_Default.cs +++ b/BasicRotations/Magical/RDM_Default.cs @@ -5,38 +5,14 @@ namespace DefaultRotations.Magical; [Api(1)] public sealed class RDM_Default : RedMageRotation { + #region Config Options private static BaseAction VerthunderStartUp { get; } = new BaseAction(ActionID.VerthunderPvE, false); - private bool CanStartMeleeCombo - { - get - { - if (Player.HasStatus(true, StatusID.Manafication, StatusID.Embolden) || - BlackMana == 100 || WhiteMana == 100) return true; - - if (BlackMana == WhiteMana) return false; - - else if (WhiteMana < BlackMana) - { - if (Player.HasStatus(true, StatusID.VerstoneReady)) return false; - } - else - { - if (Player.HasStatus(true, StatusID.VerfireReady)) return false; - } - - if (Player.HasStatus(true, VercurePvE.Setting.StatusProvide ?? [])) return false; - - //Waiting for embolden. - if (EmboldenPvE.EnoughLevel && EmboldenPvE.Cooldown.WillHaveOneChargeGCD(5)) return false; - - return true; - } - } - [RotationConfig(CombatType.PvE, Name = "Use Vercure for Dualcast when out of combat.")] public bool UseVercure { get; set; } + #endregion + #region Countdown Logic protected override IAction? CountDownAction(float remainTime) { if (remainTime < VerthunderStartUp.Info.CastTime + CountDownAhead @@ -49,34 +25,50 @@ private bool CanStartMeleeCombo return base.CountDownAction(remainTime); } + #endregion - protected override bool GeneralGCD(out IAction? act) + #region oGCD Logic + protected override bool EmergencyAbility(IAction nextGCD, out IAction? act) { act = null; - if (ManaStacks == 3) return false; + if (CombatElapsedLess(4)) return false; - if (!VerthunderIiPvE.CanUse(out _)) - { - if (VerfirePvE.CanUse(out act)) return true; - if (VerstonePvE.CanUse(out act)) return true; - } + if (IsBurst && HasHostilesInRange && EmboldenPvE.CanUse(out act, skipAoeCheck: true)) return true; - if (ScatterPvE.CanUse(out act)) return true; - if (WhiteMana < BlackMana) + //Use Manafication after embolden. + if ((Player.HasStatus(true, StatusID.Embolden) || IsLastAbility(ActionID.EmboldenPvE)) + && ManaficationPvE.CanUse(out act)) return true; + + return base.EmergencyAbility(nextGCD, out act); + } + + protected override bool AttackAbility(IAction nextGCD, out IAction? act) + { + //Swift + if (ManaStacks == 0 && (BlackMana < 50 || WhiteMana < 50) + && (CombatElapsedLess(4) || !ManaficationPvE.EnoughLevel || !ManaficationPvE.Cooldown.WillHaveOneChargeGCD(0, 1))) { - if (VeraeroIiPvE.CanUse(out act) && BlackMana - WhiteMana != 5) return true; - if (VeraeroPvE.CanUse(out act) && BlackMana - WhiteMana != 6) return true; + if (InCombat && !Player.HasStatus(true, StatusID.VerfireReady, StatusID.VerstoneReady)) + { + if (SwiftcastPvE.CanUse(out act)) return true; + if (AccelerationPvE.CanUse(out act, usedUp: true)) return true; + } } - if (VerthunderIiPvE.CanUse(out act)) return true; - if (VerthunderPvE.CanUse(out act)) return true; - if (JoltPvE.CanUse(out act)) return true; + if (IsBurst && UseBurstMedicine(out act)) return true; - if (UseVercure && NotInCombatDelay && VercurePvE.CanUse(out act)) return true; + //Attack abilities. + if (ContreSixtePvE.CanUse(out act, skipAoeCheck: true)) return true; + if (FlechePvE.CanUse(out act)) return true; - return base.GeneralGCD(out act); + if (EngagementPvE.CanUse(out act, usedUp: true)) return true; + if (CorpsacorpsPvE.CanUse(out act) && !IsMoving) return true; + + return base.AttackAbility(nextGCD, out act); } + #endregion + #region GCD Logic protected override bool EmergencyGCD(out IAction? act) { if (ManaStacks == 3) @@ -111,42 +103,60 @@ protected override bool EmergencyGCD(out IAction? act) return base.EmergencyGCD(out act); } - protected override bool EmergencyAbility(IAction nextGCD, out IAction? act) + protected override bool GeneralGCD(out IAction? act) { act = null; - if (CombatElapsedLess(4)) return false; + if (ManaStacks == 3) return false; - if (IsBurst && HasHostilesInRange && EmboldenPvE.CanUse(out act, skipAoeCheck: true)) return true; + if (!VerthunderIiPvE.CanUse(out _)) + { + if (VerfirePvE.CanUse(out act)) return true; + if (VerstonePvE.CanUse(out act)) return true; + } - //Use Manafication after embolden. - if ((Player.HasStatus(true, StatusID.Embolden) || IsLastAbility(ActionID.EmboldenPvE)) - && ManaficationPvE.CanUse(out act)) return true; + if (ScatterPvE.CanUse(out act)) return true; + if (WhiteMana < BlackMana) + { + if (VeraeroIiPvE.CanUse(out act) && BlackMana - WhiteMana != 5) return true; + if (VeraeroPvE.CanUse(out act) && BlackMana - WhiteMana != 6) return true; + } + if (VerthunderIiPvE.CanUse(out act)) return true; + if (VerthunderPvE.CanUse(out act)) return true; - return base.EmergencyAbility(nextGCD, out act); + if (JoltPvE.CanUse(out act)) return true; + + if (UseVercure && NotInCombatDelay && VercurePvE.CanUse(out act)) return true; + + return base.GeneralGCD(out act); } + #endregion - protected override bool AttackAbility(IAction nextGCD, out IAction? act) + #region Extra Methods + private bool CanStartMeleeCombo { - //Swift - if (ManaStacks == 0 && (BlackMana < 50 || WhiteMana < 50) - && (CombatElapsedLess(4) || !ManaficationPvE.EnoughLevel || !ManaficationPvE.Cooldown.WillHaveOneChargeGCD(0, 1))) + get { - if (InCombat && !Player.HasStatus(true, StatusID.VerfireReady, StatusID.VerstoneReady)) + if (Player.HasStatus(true, StatusID.Manafication, StatusID.Embolden) || + BlackMana == 100 || WhiteMana == 100) return true; + + if (BlackMana == WhiteMana) return false; + + else if (WhiteMana < BlackMana) { - if (SwiftcastPvE.CanUse(out act)) return true; - if (AccelerationPvE.CanUse(out act, usedUp: true)) return true; + if (Player.HasStatus(true, StatusID.VerstoneReady)) return false; + } + else + { + if (Player.HasStatus(true, StatusID.VerfireReady)) return false; } - } - - if (IsBurst && UseBurstMedicine(out act)) return true; - //Attack abilities. - if (ContreSixtePvE.CanUse(out act, skipAoeCheck: true)) return true; - if (FlechePvE.CanUse(out act)) return true; + if (Player.HasStatus(true, VercurePvE.Setting.StatusProvide ?? [])) return false; - if (EngagementPvE.CanUse(out act, usedUp: true)) return true; - if (CorpsacorpsPvE.CanUse(out act) && !IsMoving) return true; + //Waiting for embolden. + if (EmboldenPvE.EnoughLevel && EmboldenPvE.Cooldown.WillHaveOneChargeGCD(5)) return false; - return base.AttackAbility(nextGCD, out act); + return true; + } } + #endregion } diff --git a/BasicRotations/Magical/SMN_Default.cs b/BasicRotations/Magical/SMN_Default.cs index 7013b3e..6d869a5 100644 --- a/BasicRotations/Magical/SMN_Default.cs +++ b/BasicRotations/Magical/SMN_Default.cs @@ -1,5 +1,4 @@ -using RotationSolver.Basic.Helpers; -using System.ComponentModel; +using System.ComponentModel; namespace DefaultRotations.Magical; @@ -8,6 +7,7 @@ namespace DefaultRotations.Magical; [Api(1)] public sealed class SMN_Default : SummonerRotation { + #region Config Options public enum SwiftType : byte { No, @@ -36,21 +36,66 @@ public enum SummonOrderType : byte [RotationConfig(CombatType.PvE, Name = "Order")] public SummonOrderType SummonOrder { get; set; } = SummonOrderType.EmeraldTopazRuby; + #endregion - public override bool CanHealSingleSpell => false; + #region Countdown Logic + protected override IAction? CountDownAction(float remainTime) + { + if (SummonCarbunclePvE.CanUse(out var act)) return act; + + if (remainTime <= RuinPvE.Info.CastTime + CountDownAhead + && RuinPvE.CanUse(out act)) return act; + return base.CountDownAction(remainTime); + } + #endregion + #region Move Logic [RotationDesc(ActionID.CrimsonCyclonePvE)] protected override bool MoveForwardGCD(out IAction? act) { if (CrimsonCyclonePvE.CanUse(out act, skipAoeCheck: true)) return true; return base.MoveForwardGCD(out act); } + #endregion + #region oGCD Logic + protected override bool AttackAbility(IAction nextGCD, out IAction? act) + { + if (IsBurst && !Player.HasStatus(false, StatusID.SearingLight)) + { + if (SearingLightPvE.CanUse(out act, skipAoeCheck: true)) return true; + } + + var IsTargetBoss = HostileTarget?.IsBossFromTTK() ?? false; + var IsTargetDying = HostileTarget?.IsDying() ?? false; + + if ((InBahamut && SummonBahamutPvE.Cooldown.ElapsedOneChargeAfterGCD(3) || InPhoenix || + IsTargetBoss && IsTargetDying) && EnkindleBahamutPvE.CanUse(out act, skipAoeCheck: true)) return true; + + if ((SummonBahamutPvE.Cooldown.ElapsedOneChargeAfterGCD(3) || IsTargetBoss && IsTargetDying) && DeathflarePvE.CanUse(out act, skipAoeCheck: true)) return true; + if (RekindlePvE.CanUse(out act, skipAoeCheck: true)) return true; + if (MountainBusterPvE.CanUse(out act, skipAoeCheck: true)) return true; + + if ((Player.HasStatus(false, StatusID.SearingLight) && InBahamut && (SummonBahamutPvE.Cooldown.ElapsedOneChargeAfterGCD(3) || !EnergyDrainPvE.Cooldown.IsCoolingDown) || + !SearingLightPvE.EnoughLevel || IsTargetBoss && IsTargetDying) && PainflarePvE.CanUse(out act)) return true; + + if ((Player.HasStatus(false, StatusID.SearingLight) && InBahamut && (SummonBahamutPvE.Cooldown.ElapsedOneChargeAfterGCD(3) || !EnergyDrainPvE.Cooldown.IsCoolingDown) || + !SearingLightPvE.EnoughLevel || IsTargetBoss && IsTargetDying) && FesterPvE.CanUse(out act)) return true; + + if (EnergySiphonPvE.CanUse(out act)) return true; + if (EnergyDrainPvE.CanUse(out act)) return true; + + return base.AttackAbility(nextGCD, out act); + } + #endregion + + #region GCD Logic protected override bool GeneralGCD(out IAction? act) { if (SummonCarbunclePvE.CanUse(out act)) return true; if (SlipstreamPvE.CanUse(out act, skipAoeCheck: true)) return true; + if (CrimsonStrikePvE.CanUse(out act, skipAoeCheck: true)) return true; //AOE @@ -61,6 +106,7 @@ protected override bool GeneralGCD(out IAction? act) if (!IsMoving && AddCrimsonCyclone && CrimsonCyclonePvE.CanUse(out act, skipAoeCheck: true)) return true; if ((Player.HasStatus(false, StatusID.SearingLight) || SearingLightPvE.Cooldown.IsCoolingDown) && SummonBahamutPvE.CanUse(out act)) return true; + if (!SummonBahamutPvE.EnoughLevel && HasHostilesInRange && AetherchargePvE.CanUse(out act)) return true; if (IsMoving && (Player.HasStatus(true, StatusID.GarudasFavor) || InIfrit) @@ -89,83 +135,20 @@ protected override bool GeneralGCD(out IAction? act) break; } - if (SummonTimeEndAfterGCD() && AttunmentTimeEndAfterGCD() && !Player.HasStatus(true, StatusID.Swiftcast) && !InBahamut && !InPhoenix && RuinIvPvE.CanUse(out act, skipAoeCheck: true)) return true; if (OutburstPvE.CanUse(out act)) return true; - //毁123 if (RuinPvE.CanUse(out act)) return true; - return base.GeneralGCD(out act); - } - protected override bool AttackAbility(IAction nextGCD, out IAction? act) - { - if (IsBurst && !Player.HasStatus(false, StatusID.SearingLight)) - { - if (SearingLightPvE.CanUse(out act, skipAoeCheck: true)) return true; - } - - var IsTargetBoss = HostileTarget?.IsBossFromTTK() ?? false; - var IsTargetDying = HostileTarget?.IsDying() ?? false; - - if ((InBahamut && SummonBahamutPvE.Cooldown.ElapsedOneChargeAfterGCD(3) || InPhoenix || - IsTargetBoss && IsTargetDying) && EnkindleBahamutPvE.CanUse(out act, skipAoeCheck: true)) return true; - - if ((SummonBahamutPvE.Cooldown.ElapsedOneChargeAfterGCD(3) || IsTargetBoss && IsTargetDying) && DeathflarePvE.CanUse(out act, skipAoeCheck: true)) return true; - if (RekindlePvE.CanUse(out act, skipAoeCheck: true)) return true; - if (MountainBusterPvE.CanUse(out act, skipAoeCheck: true)) return true; - - if ((Player.HasStatus(false, StatusID.SearingLight) && InBahamut && (SummonBahamutPvE.Cooldown.ElapsedOneChargeAfterGCD(3) || !EnergyDrainPvE.Cooldown.IsCoolingDown) || - !SearingLightPvE.EnoughLevel || IsTargetBoss && IsTargetDying) && PainflarePvE.CanUse(out act)) return true; - - if ((Player.HasStatus(false, StatusID.SearingLight) && InBahamut && (SummonBahamutPvE.Cooldown.ElapsedOneChargeAfterGCD(3) || !EnergyDrainPvE.Cooldown.IsCoolingDown) || - !SearingLightPvE.EnoughLevel || IsTargetBoss && IsTargetDying) && FesterPvE.CanUse(out act)) return true; - - if (EnergySiphonPvE.CanUse(out act)) return true; - if (EnergyDrainPvE.CanUse(out act)) return true; - - return base.AttackAbility(nextGCD, out act); - } - protected override bool EmergencyAbility(IAction nextGCD, out IAction? act) - { - switch (AddSwiftcast) - { - case SwiftType.No: - default: - break; - case SwiftType.Emerald: - if (nextGCD.IsTheSameTo(true, SlipstreamPvE) || Attunement == 0 && Player.HasStatus(true, StatusID.GarudasFavor)) - { - if (SwiftcastPvE.CanUse(out act)) return true; - } - break; - case SwiftType.Ruby: - if (InIfrit && (nextGCD.IsTheSameTo(true, GemshinePvE, PreciousBrilliancePvE) || IsMoving)) - { - if (SwiftcastPvE.CanUse(out act)) return true; - } - break; - - case SwiftType.All: - if (nextGCD.IsTheSameTo(true, SlipstreamPvE) || Attunement == 0 && Player.HasStatus(true, StatusID.GarudasFavor) || - InIfrit && (nextGCD.IsTheSameTo(true, GemshinePvE, PreciousBrilliancePvE) || IsMoving)) - { - if (SwiftcastPvE.CanUse(out act)) return true; - } - break; - } - return base.EmergencyAbility(nextGCD, out act); + return base.GeneralGCD(out act); } + #endregion - protected override IAction? CountDownAction(float remainTime) - { - if (SummonCarbunclePvE.CanUse(out var act)) return act; + #region Extra Methods + public override bool CanHealSingleSpell => false; - if (remainTime <= RuinPvE.Info.CastTime + CountDownAhead - && RuinPvE.CanUse(out act)) return act; - return base.CountDownAction(remainTime); - } + #endregion } \ No newline at end of file diff --git a/BasicRotations/Melee/DRG_Default.cs b/BasicRotations/Melee/DRG_Default.cs index aef1109..dcdaa74 100644 --- a/BasicRotations/Melee/DRG_Default.cs +++ b/BasicRotations/Melee/DRG_Default.cs @@ -6,7 +6,11 @@ namespace DefaultRotations.Melee; public sealed class DRG_Default : DragoonRotation { + #region Config Options [RotationDesc(ActionID.SpineshatterDivePvE, ActionID.DragonfireDivePvE)] + #endregion + + #region Move Logic protected override bool MoveForwardAbility(IAction nextGCD, out IAction act) { if (SpineshatterDivePvE.CanUse(out act)) return true; @@ -14,6 +18,10 @@ protected override bool MoveForwardAbility(IAction nextGCD, out IAction act) return false; } + + #endregion + + #region oGCD Logic protected override bool EmergencyAbility(IAction nextGCD, out IAction? act) { if (nextGCD.IsTheSameTo(true, FullThrustPvE, CoerthanTormentPvE) @@ -25,6 +33,8 @@ protected override bool EmergencyAbility(IAction nextGCD, out IAction? act) return base.EmergencyAbility(nextGCD, out act); } + + protected override bool AttackAbility(IAction nextGCD, out IAction? act) { if (IsBurst && InCombat) @@ -68,7 +78,9 @@ protected override bool AttackAbility(IAction nextGCD, out IAction? act) return base.AttackAbility(nextGCD, out act); } + #endregion + #region GCD Logic protected override bool GeneralGCD(out IAction? act) { if (CoerthanTormentPvE.CanUse(out act)) return true; @@ -94,4 +106,5 @@ protected override bool GeneralGCD(out IAction? act) return base.GeneralGCD(out act); } + #endregion } diff --git a/BasicRotations/Melee/MNK_Default.cs b/BasicRotations/Melee/MNK_Default.cs index c941e01..23fd29e 100644 --- a/BasicRotations/Melee/MNK_Default.cs +++ b/BasicRotations/Melee/MNK_Default.cs @@ -5,9 +5,12 @@ namespace DefaultRotations.Melee; [Api(1)] public sealed class MNK_Default : MonkRotation { + #region Config Options [RotationConfig(CombatType.PvE, Name = "Use Form Shift")] public bool AutoFormShift { get; set; } = true; + #endregion + #region Countdown Logic protected override IAction? CountDownAction(float remainTime) { if (remainTime < 0.2) @@ -21,7 +24,47 @@ public sealed class MNK_Default : MonkRotation return base.CountDownAction(remainTime); } + #endregion + #region oGCD Logic + protected override bool EmergencyAbility(IAction nextGCD, out IAction? act) + { + if (InCombat) + { + if (UseBurstMedicine(out act)) return true; + if (IsBurst && !CombatElapsedLessGCD(2) && RiddleOfFirePvE.CanUse(out act, onLastAbility: true)) return true; + } + return base.EmergencyAbility(nextGCD, out act); + } + + protected override bool AttackAbility(IAction nextGCD, out IAction? act) + { + act = null; + + if (CombatElapsedLessGCD(3)) return false; // Prevents the use of abilities if 3 GCDs have not been used + + if (BeastChakras.Contains(BeastChakra.NONE) && Player.HasStatus(true, StatusID.RaptorForm) + && (!RiddleOfFirePvE.EnoughLevel || Player.HasStatus(false, StatusID.RiddleOfFire) && !Player.WillStatusEndGCD(3, 0, false, StatusID.RiddleOfFire) + || RiddleOfFirePvE.Cooldown.WillHaveOneChargeGCD(1) && (PerfectBalancePvE.Cooldown.ElapsedAfter(60) || !PerfectBalancePvE.Cooldown.IsCoolingDown))) + { + if (PerfectBalancePvE.CanUse(out act, usedUp: true)) return true; // Perfect Balance + } + + if (BrotherhoodPvE.CanUse(out act, skipAoeCheck: true)) return true; // Brotherhood + + if (HowlingFistPvE.CanUse(out act)) return true; // Howling Fist + if (SteelPeakPvE.CanUse(out act)) return true; // Steel Peak + if (HowlingFistPvE.CanUse(out act, skipAoeCheck: true)) return true; // Howling Fist AOE + + if (RiddleOfWindPvE.CanUse(out act)) return true; // Riddle Of Wind + + if (MergedStatus.HasFlag(AutoStatus.MoveForward) && MoveForwardAbility(nextGCD, out act)) return true; + + return base.AttackAbility(nextGCD, out act); + } + #endregion + + #region GCD Logic private bool OpoOpoForm(out IAction? act) { if (ArmOfTheDestroyerPvE.CanUse(out act)) return true; // Arm Of The Destoryer @@ -166,40 +209,5 @@ bool SolarNadi(out IAction? act) return CoerlForm(out act); } - - protected override bool EmergencyAbility(IAction nextGCD, out IAction? act) - { - if (InCombat) - { - if (UseBurstMedicine(out act)) return true; - if (IsBurst && !CombatElapsedLessGCD(2) && RiddleOfFirePvE.CanUse(out act, onLastAbility: true)) return true; - } - return base.EmergencyAbility(nextGCD, out act); - } - - protected override bool AttackAbility(IAction nextGCD, out IAction? act) - { - act = null; - - if (CombatElapsedLessGCD(3)) return false; // Prevents the use of abilities if 3 GCDs have not been used - - if (BeastChakras.Contains(BeastChakra.NONE) && Player.HasStatus(true, StatusID.RaptorForm) - && (!RiddleOfFirePvE.EnoughLevel || Player.HasStatus(false, StatusID.RiddleOfFire) && !Player.WillStatusEndGCD(3, 0, false, StatusID.RiddleOfFire) - || RiddleOfFirePvE.Cooldown.WillHaveOneChargeGCD(1) && (PerfectBalancePvE.Cooldown.ElapsedAfter(60) || !PerfectBalancePvE.Cooldown.IsCoolingDown))) - { - if (PerfectBalancePvE.CanUse(out act, usedUp: true)) return true; // Perfect Balance - } - - if (BrotherhoodPvE.CanUse(out act, skipAoeCheck: true)) return true; // Brotherhood - - if (HowlingFistPvE.CanUse(out act)) return true; // Howling Fist - if (SteelPeakPvE.CanUse(out act)) return true; // Steel Peak - if (HowlingFistPvE.CanUse(out act, skipAoeCheck: true)) return true; // Howling Fist AOE - - if (RiddleOfWindPvE.CanUse(out act)) return true; // Riddle Of Wind - - if (MergedStatus.HasFlag(AutoStatus.MoveForward) && MoveForwardAbility(nextGCD, out act)) return true; - - return base.AttackAbility(nextGCD, out act); - } + #endregion } diff --git a/BasicRotations/Melee/NIN_Beta.cs b/BasicRotations/Melee/NIN_Beta.cs index 7b48f4d..5f70ec5 100644 --- a/BasicRotations/Melee/NIN_Beta.cs +++ b/BasicRotations/Melee/NIN_Beta.cs @@ -5,25 +5,16 @@ [Api(1)] public sealed class NIN_Beta : NinjaRotation { - private IBaseAction? _ninActionAim = null; // Holds the next ninjutsu action to perform. - - // Determines if Trick Attack is in its effective period. - private bool InTrickAttack => TrickAttackPvE.Cooldown.IsCoolingDown && !TrickAttackPvE.Cooldown.ElapsedAfter(17); - - // Determines if Mug is in its effective period. - private bool InMug => MugPvE.Cooldown.IsCoolingDown && !MugPvE.Cooldown.ElapsedAfter(19); - - // Checks if no ninjutsu action is currently selected or if the Rabbit Medium has been invoked. - private static bool NoNinjutsu => AdjustId(ActionID.NinjutsuPvE) is ActionID.NinjutsuPvE or ActionID.RabbitMediumPvE; - + #region Config Options // Configuration properties for rotation behavior. [RotationConfig(CombatType.PvE, Name = "Use Hide")] public bool UseHide { get; set; } = true; [RotationConfig(CombatType.PvE, Name = "Use Unhide")] public bool AutoUnhide { get; set; } = true; + #endregion + #region CountDown Logic // Logic to determine the action to take during the countdown phase before combat starts. - #region CountDown protected override IAction? CountDownAction(float remainTime) { @@ -56,7 +47,7 @@ public sealed class NIN_Beta : NinjaRotation } #endregion - #region Ninjutsu Management + #region Ninjutsu Logic // Sets the target ninjutsu action to be performed next. // If the action is null, or currently set to Rabbit Medium (indicating a failed Ninjutsu attempt), it exits early. // If the current action aim is not null and the last action matches certain conditions, it exits early. @@ -192,7 +183,9 @@ private bool ChoiceNinjutsu(out IAction? act) } return false; // Indicates that no specific Ninjutsu action was chosen in this cycle. } + #endregion + #region Ninjutsu Execution // Attempts to perform a ninjutsu action, based on the current game state and conditions. private bool DoNinjutsu(out IAction? act) { @@ -299,56 +292,8 @@ private bool DoNinjutsu(out IAction? act) } #endregion - - // Main method for determining the general action to take during the combat's global cooldown phase. - #region GeneralGCD - protected override bool GeneralGCD(out IAction? act) - { - var hasRaijuReady = Player.HasStatus(true, StatusID.RaijuReady); - - if ((InTrickAttack || InMug) && NoNinjutsu && !hasRaijuReady - && !Player.HasStatus(true, StatusID.TenChiJin) - && PhantomKamaitachiPvE.CanUse(out act)) return true; - - if (ChoiceNinjutsu(out act)) return true; - if ((!InCombat || !CombatElapsedLess(7)) && DoNinjutsu(out act)) return true; - - //No Ninjutsu - if (NoNinjutsu) - { - if (!CombatElapsedLess(10) && FleetingRaijuPvE.CanUse(out act)) return true; - if (hasRaijuReady) return false; - } - - if (HuraijinPvE.CanUse(out act)) return true; - - //AOE - if (HakkeMujinsatsuPvE.CanUse(out act)) return true; - if (DeathBlossomPvE.CanUse(out act)) return true; - - //Single - if (ArmorCrushPvE.CanUse(out act)) return true; - if (AeolianEdgePvE.CanUse(out act)) return true; - if (GustSlashPvE.CanUse(out act)) return true; - if (SpinningEdgePvE.CanUse(out act)) return true; - - //Range - - if (ThrowingDaggerPvE.CanUse(out act)) return true; - - if (AutoUnhide) - { - StatusHelper.StatusOff(StatusID.Hidden); - } - if (!InCombat && _ninActionAim == null && UseHide - && TenPvE.Cooldown.IsCoolingDown && HidePvE.CanUse(out act)) return true; - - return base.GeneralGCD(out act); - } - #endregion - + #region Move Logic // Defines logic for actions to take when moving forward during combat. - #region MoveForwardGCD // This attribute associates the method with the Forked Raiju PvE action, // indicating it's a relevant ability when considering movement-based actions. [RotationDesc(ActionID.ForkedRaijuPvE)] @@ -367,8 +312,7 @@ protected override bool MoveForwardGCD(out IAction? act) } #endregion - - #region EmergencyAbility + #region oGCD Logic // Determines the emergency abilities to use, overriding the base class implementation. protected override bool EmergencyAbility(IAction nextGCD, out IAction? act) { @@ -400,10 +344,8 @@ protected override bool EmergencyAbility(IAction nextGCD, out IAction? act) // If none of the specific conditions are met, falls back to the base class's emergency ability logic. return base.EmergencyAbility(nextGCD, out act); } - #endregion // Defines attack abilities to use during combat, overriding the base class implementation. - #region AttackAbility protected override bool AttackAbility(IAction nextGCD, out IAction? act) { act = null; @@ -447,6 +389,66 @@ protected override bool AttackAbility(IAction nextGCD, out IAction? act) } #endregion + #region GCD Logic + // Main method for determining the general action to take during the combat's global cooldown phase. + protected override bool GeneralGCD(out IAction? act) + { + var hasRaijuReady = Player.HasStatus(true, StatusID.RaijuReady); + + if ((InTrickAttack || InMug) && NoNinjutsu && !hasRaijuReady + && !Player.HasStatus(true, StatusID.TenChiJin) + && PhantomKamaitachiPvE.CanUse(out act)) return true; + + if (ChoiceNinjutsu(out act)) return true; + if ((!InCombat || !CombatElapsedLess(7)) && DoNinjutsu(out act)) return true; + + //No Ninjutsu + if (NoNinjutsu) + { + if (!CombatElapsedLess(10) && FleetingRaijuPvE.CanUse(out act)) return true; + if (hasRaijuReady) return false; + } + + if (HuraijinPvE.CanUse(out act)) return true; + + //AOE + if (HakkeMujinsatsuPvE.CanUse(out act)) return true; + if (DeathBlossomPvE.CanUse(out act)) return true; + + //Single + if (ArmorCrushPvE.CanUse(out act)) return true; + if (AeolianEdgePvE.CanUse(out act)) return true; + if (GustSlashPvE.CanUse(out act)) return true; + if (SpinningEdgePvE.CanUse(out act)) return true; + + //Range + + if (ThrowingDaggerPvE.CanUse(out act)) return true; + + if (AutoUnhide) + { + StatusHelper.StatusOff(StatusID.Hidden); + } + if (!InCombat && _ninActionAim == null && UseHide + && TenPvE.Cooldown.IsCoolingDown && HidePvE.CanUse(out act)) return true; + + return base.GeneralGCD(out act); + } + #endregion + + #region Extra Methods + // Holds the next ninjutsu action to perform. + private IBaseAction? _ninActionAim = null; + + // Determines if Trick Attack is in its effective period. + private bool InTrickAttack => TrickAttackPvE.Cooldown.IsCoolingDown && !TrickAttackPvE.Cooldown.ElapsedAfter(17); + + // Determines if Mug is in its effective period. + private bool InMug => MugPvE.Cooldown.IsCoolingDown && !MugPvE.Cooldown.ElapsedAfter(19); + + // Checks if no ninjutsu action is currently selected or if the Rabbit Medium has been invoked. + private static bool NoNinjutsu => AdjustId(ActionID.NinjutsuPvE) is ActionID.NinjutsuPvE or ActionID.RabbitMediumPvE; + // Displays the current status of the rotation, including the aimed ninjutsu action, if any. public override void DisplayStatus() { @@ -456,4 +458,5 @@ public override void DisplayStatus() } base.DisplayStatus(); } -} + #endregion +} \ No newline at end of file diff --git a/BasicRotations/Melee/RPR_Default.cs b/BasicRotations/Melee/RPR_Default.cs index 1675532..9b23cc7 100644 --- a/BasicRotations/Melee/RPR_Default.cs +++ b/BasicRotations/Melee/RPR_Default.cs @@ -5,6 +5,7 @@ [Api(1)] public sealed class RPR_Default : ReaperRotation { + #region Countdown Logic [RotationConfig(CombatType.PvE, Name = "Wait until 50 stacks of Shroud to use Enshroud.")] public bool EnshroudPooling { get; set; } = false; @@ -17,21 +18,65 @@ public sealed class RPR_Default : ReaperRotation return base.CountDownAction(remainTime); } + #endregion - private bool Reaping(out IAction? act) + #region oGCD Logic + protected override bool AttackAbility(IAction nextGCD, out IAction? act) { - if (GrimReapingPvE.CanUse(out act)) return true; - if (Player.HasStatus(true, StatusID.EnhancedCrossReaping) || !Player.HasStatus(true, StatusID.EnhancedVoidReaping)) + var IsTargetBoss = HostileTarget?.IsBossFromTTK() ?? false; + var IsTargetDying = HostileTarget?.IsDying() ?? false; + + if (IsBurst) { - if (CrossReapingPvE.CanUse(out act)) return true; + if (UseBurstMedicine(out act)) + { + if (CombatElapsedLess(10)) + { + if (!CombatElapsedLess(5)) return true; + } + else + { + if (ArcaneCirclePvE.Cooldown.WillHaveOneCharge(5)) return true; + } + } + if ((HostileTarget?.HasStatus(true, StatusID.DeathsDesign) ?? false) + && ArcaneCirclePvE.CanUse(out act, skipAoeCheck: true)) return true; } - else + + if (IsTargetBoss && IsTargetDying || + !EnshroudPooling && Shroud >= 50 || + EnshroudPooling && Shroud >= 50 && + (!PlentifulHarvestPvE.EnoughLevel || + Player.HasStatus(true, StatusID.ArcaneCircle) || + ArcaneCirclePvE.Cooldown.WillHaveOneCharge(8) || + !Player.HasStatus(true, StatusID.ArcaneCircle) && ArcaneCirclePvE.Cooldown.WillHaveOneCharge(65) && !ArcaneCirclePvE.Cooldown.WillHaveOneCharge(50) || + !Player.HasStatus(true, StatusID.ArcaneCircle) && Shroud >= 90)) { - if (VoidReapingPvE.CanUse(out act)) return true; + if (EnshroudPvE.CanUse(out act)) return true; } - return false; + + if (HasEnshrouded && (Player.HasStatus(true, StatusID.ArcaneCircle) || LemureShroud < 3)) + { + if (LemuresScythePvE.CanUse(out act, usedUp: true)) return true; + if (LemuresSlicePvE.CanUse(out act, usedUp: true)) return true; + } + + if (PlentifulHarvestPvE.EnoughLevel && !Player.HasStatus(true, StatusID.ImmortalSacrifice) && !Player.HasStatus(true, StatusID.BloodsownCircle_2972) || !PlentifulHarvestPvE.EnoughLevel) + { + if (GluttonyPvE.CanUse(out act, skipAoeCheck: true)) return true; + } + + if (!Player.HasStatus(true, StatusID.BloodsownCircle_2972) && !Player.HasStatus(true, StatusID.ImmortalSacrifice) && (GluttonyPvE.EnoughLevel && !GluttonyPvE.Cooldown.WillHaveOneChargeGCD(4) || !GluttonyPvE.EnoughLevel || Soul == 100)) + { + if (GrimSwathePvE.CanUse(out act)) return true; + if (BloodStalkPvE.CanUse(out act)) return true; + } + + return base.AttackAbility(nextGCD, out act); } + #endregion + #region GCD Logic protected override bool GeneralGCD(out IAction? act) { if (SoulsowPvE.CanUse(out act)) return true; @@ -103,58 +148,21 @@ protected override bool GeneralGCD(out IAction? act) return base.GeneralGCD(out act); } +#endregion - protected override bool AttackAbility(IAction nextGCD, out IAction? act) + #region Extra Methods + private bool Reaping(out IAction? act) { - var IsTargetBoss = HostileTarget?.IsBossFromTTK() ?? false; - var IsTargetDying = HostileTarget?.IsDying() ?? false; - - if (IsBurst) - { - if (UseBurstMedicine(out act)) - { - if (CombatElapsedLess(10)) - { - if (!CombatElapsedLess(5)) return true; - } - else - { - if (ArcaneCirclePvE.Cooldown.WillHaveOneCharge(5)) return true; - } - } - if ((HostileTarget?.HasStatus(true, StatusID.DeathsDesign) ?? false) - && ArcaneCirclePvE.CanUse(out act, skipAoeCheck: true)) return true; - } - - if (IsTargetBoss && IsTargetDying || - !EnshroudPooling && Shroud >= 50 || - EnshroudPooling && Shroud >= 50 && - (!PlentifulHarvestPvE.EnoughLevel || - Player.HasStatus(true, StatusID.ArcaneCircle) || - ArcaneCirclePvE.Cooldown.WillHaveOneCharge(8) || - !Player.HasStatus(true, StatusID.ArcaneCircle) && ArcaneCirclePvE.Cooldown.WillHaveOneCharge(65) && !ArcaneCirclePvE.Cooldown.WillHaveOneCharge(50) || - !Player.HasStatus(true, StatusID.ArcaneCircle) && Shroud >= 90)) - { - if (EnshroudPvE.CanUse(out act)) return true; - } - - if (HasEnshrouded && (Player.HasStatus(true, StatusID.ArcaneCircle) || LemureShroud < 3)) - { - if (LemuresScythePvE.CanUse(out act, usedUp: true)) return true; - if (LemuresSlicePvE.CanUse(out act, usedUp: true)) return true; - } - - if (PlentifulHarvestPvE.EnoughLevel && !Player.HasStatus(true, StatusID.ImmortalSacrifice) && !Player.HasStatus(true, StatusID.BloodsownCircle_2972) || !PlentifulHarvestPvE.EnoughLevel) + if (GrimReapingPvE.CanUse(out act)) return true; + if (Player.HasStatus(true, StatusID.EnhancedCrossReaping) || !Player.HasStatus(true, StatusID.EnhancedVoidReaping)) { - if (GluttonyPvE.CanUse(out act, skipAoeCheck: true)) return true; + if (CrossReapingPvE.CanUse(out act)) return true; } - - if (!Player.HasStatus(true, StatusID.BloodsownCircle_2972) && !Player.HasStatus(true, StatusID.ImmortalSacrifice) && (GluttonyPvE.EnoughLevel && !GluttonyPvE.Cooldown.WillHaveOneChargeGCD(4) || !GluttonyPvE.EnoughLevel || Soul == 100)) + else { - if (GrimSwathePvE.CanUse(out act)) return true; - if (BloodStalkPvE.CanUse(out act)) return true; + if (VoidReapingPvE.CanUse(out act)) return true; } - - return base.AttackAbility(nextGCD, out act); + return false; } + #endregion } diff --git a/BasicRotations/Melee/SAM_Beta.cs b/BasicRotations/Melee/SAM_Beta.cs deleted file mode 100644 index 3fba01f..0000000 --- a/BasicRotations/Melee/SAM_Beta.cs +++ /dev/null @@ -1,112 +0,0 @@ -namespace DefaultRotations.Melee; - -[Rotation("Testing Rotations", CombatType.PvE, GameVersion = "6.58")] -[SourceCode(Path = "main/DefaultRotations/Melee/SAM_Beta.cs")] -[Api(1)] -public sealed class SAM_Beta : SamuraiRotation -{ - [Range(0, 85, ConfigUnitType.None, 5)] - [RotationConfig(CombatType.PvE, Name = "Use Kenki above.")] - public int AddKenki { get; set; } = 50; - - private static bool HaveMeikyoShisui => Player.HasStatus(true, StatusID.MeikyoShisui); - - protected override bool GeneralGCD(out IAction? act) - { - if (KaeshiNamikiriPvE.CanUse(out act, skipAoeCheck: true, usedUp: true)) return true; - - var IsTargetBoss = HostileTarget?.IsBossFromTTK() ?? false; - var IsTargetDying = HostileTarget?.IsDying() ?? false; - - if (KaeshiGokenPvE.CanUse(out act, skipAoeCheck: true, usedUp: true)) return true; - if (KaeshiSetsugekkaPvE.CanUse(out act, skipAoeCheck: true, usedUp: true)) return true; - - if ((!IsTargetBoss || (HostileTarget?.HasStatus(true, StatusID.Higanbana) ?? false)) && HasMoon && HasFlower - && OgiNamikiriPvE.CanUse(out act, skipAoeCheck: true)) return true; - - if (SenCount == 1 && IsTargetBoss && !IsTargetDying) - { - if (HasMoon && HasFlower && HiganbanaPvE.CanUse(out act)) return true; - } - if (SenCount == 2) - { - if (TenkaGokenPvE.CanUse(out act, skipAoeCheck: !MidareSetsugekkaPvE.EnoughLevel)) return true; - } - if (SenCount == 3) - { - if (MidareSetsugekkaPvE.CanUse(out act)) return true; - } - - if ((!HasMoon || IsMoonTimeLessThanFlower || !OkaPvE.EnoughLevel) && MangetsuPvE.CanUse(out act, skipAoeCheck: HaveMeikyoShisui && !HasGetsu)) return true; - if ((!HasFlower || !IsMoonTimeLessThanFlower) && OkaPvE.CanUse(out act, skipAoeCheck: HaveMeikyoShisui && !HasKa)) return true; - - if (!HasSetsu && YukikazePvE.CanUse(out act, skipComboCheck: HaveMeikyoShisui && HasGetsu && HasKa)) return true; - - if (GekkoPvE.CanUse(out act, skipComboCheck: HaveMeikyoShisui && !HasGetsu)) return true; - if (KashaPvE.CanUse(out act, skipComboCheck: HaveMeikyoShisui && !HasKa)) return true; - - if ((!HasMoon || IsMoonTimeLessThanFlower || !ShifuPvE.EnoughLevel) && JinpuPvE.CanUse(out act)) return true; - if ((!HasFlower || !IsMoonTimeLessThanFlower) && ShifuPvE.CanUse(out act)) return true; - - if (FukoPvE.CanUse(out act, skipComboCheck: true)) return true; - if (!FukoPvE.EnoughLevel && FugaPvE.CanUse(out act, skipComboCheck: true)) return true; - - if (!HaveMeikyoShisui) - { - if (HakazePvE.CanUse(out act)) return true; - - if (EnpiPvE.CanUse(out act)) return true; - } - - return base.GeneralGCD(out act); - } - - protected override bool AttackAbility(IAction nextGCD, out IAction? act) - { - var IsTargetBoss = HostileTarget?.IsBossFromTTK() ?? false; - var IsTargetDying = HostileTarget?.IsDying() ?? false; - - if (Kenki <= 50 && IkishotenPvE.CanUse(out act)) return true; - - if ((HostileTarget?.HasStatus(true, StatusID.Higanbana) ?? false) && (HostileTarget?.WillStatusEnd(32, true, StatusID.Higanbana) ?? false) && !(HostileTarget?.WillStatusEnd(28, true, StatusID.Higanbana) ?? false) && SenCount == 1 && IsLastAction(true, YukikazePvE) && !HaveMeikyoShisui) - { - if (HagakurePvE.CanUse(out act)) return true; - } - - if (HasMoon && HasFlower) - { - if (HissatsuGurenPvE.CanUse(out act, skipAoeCheck: !HissatsuSeneiPvE.EnoughLevel)) return true; - if (HissatsuSeneiPvE.CanUse(out act)) return true; - } - - if (ShohaIiPvE.CanUse(out act)) return true; - if (ShohaPvE.CanUse(out act)) return true; - - if (Kenki >= 50 && IkishotenPvE.Cooldown.WillHaveOneCharge(10) || Kenki >= AddKenki || IsTargetBoss && IsTargetDying) - { - if (HissatsuKyutenPvE.CanUse(out act)) return true; - if (HissatsuShintenPvE.CanUse(out act)) return true; - } - - return base.AttackAbility(nextGCD, out act); - } - protected override bool EmergencyAbility(IAction nextGCD, out IAction? act) - { - var IsTargetBoss = HostileTarget?.IsBossFromTTK() ?? false; - var IsTargetDying = HostileTarget?.IsDying() ?? false; - - if (HasHostilesInRange && IsLastGCD(true, YukikazePvE, MangetsuPvE, OkaPvE) && - (!IsTargetBoss || (HostileTarget?.HasStatus(true, StatusID.Higanbana) ?? false) && !(HostileTarget?.WillStatusEnd(40, true, StatusID.Higanbana) ?? false) || !HasMoon && !HasFlower || IsTargetBoss && IsTargetDying)) - { - if (MeikyoShisuiPvE.CanUse(out act, usedUp: true)) return true; - } - return base.EmergencyAbility(nextGCD, out act); - } - - protected override IAction? CountDownAction(float remainTime) - { - if (remainTime <= 5 && MeikyoShisuiPvE.CanUse(out var act)) return act; - if (remainTime <= 2 && TrueNorthPvE.CanUse(out act)) return act; - return base.CountDownAction(remainTime); - } -} \ No newline at end of file diff --git a/BasicRotations/Melee/SAM_Default.cs b/BasicRotations/Melee/SAM_Default.cs index 5eb81cd..bca0578 100644 --- a/BasicRotations/Melee/SAM_Default.cs +++ b/BasicRotations/Melee/SAM_Default.cs @@ -5,11 +5,72 @@ [Api(1)] public sealed class SAM_Default : SamuraiRotation { + #region Config Options + [Range(0, 85, ConfigUnitType.None, 5)] [RotationConfig(CombatType.PvE, Name = "Use Kenki above.")] public int AddKenki { get; set; } = 50; - private static bool HaveMeikyoShisui => Player.HasStatus(true, StatusID.MeikyoShisui); + #endregion + + #region Countdown Logic + + protected override IAction? CountDownAction(float remainTime) + { + if (remainTime <= 5 && MeikyoShisuiPvE.CanUse(out var act)) return act; + if (remainTime <= 2 && TrueNorthPvE.CanUse(out act)) return act; + return base.CountDownAction(remainTime); + } + + #endregion + + #region oGCD Logic + + protected override bool AttackAbility(IAction nextGCD, out IAction? act) + { + var IsTargetBoss = HostileTarget?.IsBossFromTTK() ?? false; + var IsTargetDying = HostileTarget?.IsDying() ?? false; + + if (Kenki <= 50 && IkishotenPvE.CanUse(out act)) return true; + + if ((HostileTarget?.HasStatus(true, StatusID.Higanbana) ?? false) && (HostileTarget?.WillStatusEnd(32, true, StatusID.Higanbana) ?? false) && !(HostileTarget?.WillStatusEnd(28, true, StatusID.Higanbana) ?? false) && SenCount == 1 && IsLastAction(true, YukikazePvE) && !HaveMeikyoShisui) + { + if (HagakurePvE.CanUse(out act)) return true; + } + + if (HasMoon && HasFlower) + { + if (HissatsuGurenPvE.CanUse(out act, skipAoeCheck: !HissatsuSeneiPvE.EnoughLevel)) return true; + if (HissatsuSeneiPvE.CanUse(out act)) return true; + } + + if (ShohaIiPvE.CanUse(out act)) return true; + if (ShohaPvE.CanUse(out act)) return true; + + if (Kenki >= 50 && IkishotenPvE.Cooldown.WillHaveOneCharge(10) || Kenki >= AddKenki || IsTargetBoss && IsTargetDying) + { + if (HissatsuKyutenPvE.CanUse(out act)) return true; + if (HissatsuShintenPvE.CanUse(out act)) return true; + } + + return base.AttackAbility(nextGCD, out act); + } + protected override bool EmergencyAbility(IAction nextGCD, out IAction? act) + { + var IsTargetBoss = HostileTarget?.IsBossFromTTK() ?? false; + var IsTargetDying = HostileTarget?.IsDying() ?? false; + + if (HasHostilesInRange && IsLastGCD(true, YukikazePvE, MangetsuPvE, OkaPvE) && + (!IsTargetBoss || (HostileTarget?.HasStatus(true, StatusID.Higanbana) ?? false) && !(HostileTarget?.WillStatusEnd(40, true, StatusID.Higanbana) ?? false) || !HasMoon && !HasFlower || IsTargetBoss && IsTargetDying)) + { + if (MeikyoShisuiPvE.CanUse(out act, usedUp: true)) return true; + } + return base.EmergencyAbility(nextGCD, out act); + } + + #endregion + + #region GCD Logic protected override bool GeneralGCD(out IAction? act) { @@ -48,8 +109,8 @@ protected override bool GeneralGCD(out IAction? act) if ((!HasMoon || IsMoonTimeLessThanFlower || !ShifuPvE.EnoughLevel) && JinpuPvE.CanUse(out act)) return true; if ((!HasFlower || !IsMoonTimeLessThanFlower) && ShifuPvE.CanUse(out act)) return true; - if (FukoPvE.CanUse(out act)) return true; - if (!FukoPvE.EnoughLevel && FugaPvE.CanUse(out act)) return true; + if (FukoPvE.CanUse(out act, skipComboCheck: true)) return true; + if (!FukoPvE.EnoughLevel && FugaPvE.CanUse(out act, skipComboCheck: true)) return true; if (!HaveMeikyoShisui) { @@ -61,52 +122,10 @@ protected override bool GeneralGCD(out IAction? act) return base.GeneralGCD(out act); } - protected override bool AttackAbility(IAction nextGCD, out IAction? act) - { - var IsTargetBoss = HostileTarget?.IsBossFromTTK() ?? false; - var IsTargetDying = HostileTarget?.IsDying() ?? false; - - if (Kenki <= 50 && IkishotenPvE.CanUse(out act)) return true; - - if ((HostileTarget?.HasStatus(true, StatusID.Higanbana) ?? false) && (HostileTarget?.WillStatusEnd(32, true, StatusID.Higanbana) ?? false) && !(HostileTarget?.WillStatusEnd(28, true, StatusID.Higanbana) ?? false) && SenCount == 1 && IsLastAction(true, YukikazePvE) && !HaveMeikyoShisui) - { - if (HagakurePvE.CanUse(out act)) return true; - } - - if (HasMoon && HasFlower) - { - if (HissatsuGurenPvE.CanUse(out act, skipAoeCheck: !HissatsuSeneiPvE.EnoughLevel)) return true; - if (HissatsuSeneiPvE.CanUse(out act)) return true; - } - - if (ShohaIiPvE.CanUse(out act)) return true; - if (ShohaPvE.CanUse(out act)) return true; + #endregion - if (Kenki >= 50 && IkishotenPvE.Cooldown.WillHaveOneCharge(10) || Kenki >= AddKenki || IsTargetBoss && IsTargetDying) - { - if (HissatsuKyutenPvE.CanUse(out act)) return true; - if (HissatsuShintenPvE.CanUse(out act)) return true; - } - - return base.AttackAbility(nextGCD, out act); - } - protected override bool EmergencyAbility(IAction nextGCD, out IAction? act) - { - var IsTargetBoss = HostileTarget?.IsBossFromTTK() ?? false; - var IsTargetDying = HostileTarget?.IsDying() ?? false; - - if (HasHostilesInRange && IsLastGCD(true, YukikazePvE, MangetsuPvE, OkaPvE) && - (!IsTargetBoss || (HostileTarget?.HasStatus(true, StatusID.Higanbana) ?? false) && !(HostileTarget?.WillStatusEnd(40, true, StatusID.Higanbana) ?? false) || !HasMoon && !HasFlower || IsTargetBoss && IsTargetDying)) - { - if (MeikyoShisuiPvE.CanUse(out act, usedUp: true)) return true; - } - return base.EmergencyAbility(nextGCD, out act); - } + #region Extra Methods + private static bool HaveMeikyoShisui => Player.HasStatus(true, StatusID.MeikyoShisui); - protected override IAction? CountDownAction(float remainTime) - { - if (remainTime <= 5 && MeikyoShisuiPvE.CanUse(out var act)) return act; - if (remainTime <= 2 && TrueNorthPvE.CanUse(out act)) return act; - return base.CountDownAction(remainTime); - } + #endregion } \ No newline at end of file diff --git a/BasicRotations/Melee/VPR_Default.cs b/BasicRotations/Melee/VPR_Default.cs index 8519aa3..5fdb02b 100644 --- a/BasicRotations/Melee/VPR_Default.cs +++ b/BasicRotations/Melee/VPR_Default.cs @@ -1,76 +1,76 @@ -//namespace DefaultRotations.Melee; - -//[Rotation("LTS's Default", CombatType.PvE, GameVersion = "7.0")] -//[SourceCode(Path = "main/DefaultRotations/Melee/VPR_Default.cs")] -//[Api(1)] -//public sealed class VPR_Default : ViperRotation -//{ -// #region Countdown logic -// // Defines logic for actions to take during the countdown before combat starts. -// protected override IAction? CountDownAction(float remainTime) -// { - -// return base.CountDownAction(remainTime); -// } -// #endregion - -// #region Emergency Logic -// // Determines emergency actions to take based on the next planned GCD action. -// protected override bool EmergencyAbility(IAction nextGCD, out IAction? act) -// { -// act = null; - -// return base.EmergencyAbility(nextGCD, out act); -// } -// #endregion - -// #region oGCD Logic -// protected override bool AttackAbility(IAction nextGCD, out IAction? act) -// { -// act = null; - - -// return base.AttackAbility(nextGCD, out act); -// } - -// protected override bool MoveForwardAbility(IAction nextGCD, out IAction? act) -// { -// act = null; - - -// return base.MoveForwardAbility(nextGCD, out act); -// } -// #endregion - -// #region GCD Logic -// protected override bool MoveForwardGCD(out IAction? act) -// { -// act = null; - -// return base.MoveForwardGCD(out act); -// } - -// protected override bool GeneralGCD(out IAction? act) -// { -// act = null; - -// return base.GeneralGCD(out act); -// } - -// private bool AttackGCD(out IAction? act, bool burst) -// { -// act = null; - -// return false; -// } -// #endregion - -// #region Extra Methods -// // Extra private helper methods for determining the usability of specific abilities under certain conditions. -// // These methods simplify the main logic by encapsulating specific checks related to abilities' cooldowns and prerequisites. -// private bool CanUseExamplePvE(out IAction? act) -// { - -// } -// #endregion -//} \ No newline at end of file +/*namespace DefaultRotations.Melee; + +[Rotation("LTS's Default", CombatType.PvE, GameVersion = "7.0")] +[SourceCode(Path = "main/DefaultRotations/Melee/VPR_Default.cs")] +[Api(1)] +public sealed class VPR_Default : ViperRotation +{ + #region Countdown logic + // Defines logic for actions to take during the countdown before combat starts. + protected override IAction? CountDownAction(float remainTime) + { + + return base.CountDownAction(remainTime); + } + #endregion + + #region Emergency Logic + // Determines emergency actions to take based on the next planned GCD action. + protected override bool EmergencyAbility(IAction nextGCD, out IAction? act) + { + act = null; + + return base.EmergencyAbility(nextGCD, out act); + } + #endregion + + #region oGCD Logic + protected override bool AttackAbility(IAction nextGCD, out IAction? act) + { + act = null; + + + return base.AttackAbility(nextGCD, out act); + } + + protected override bool MoveForwardAbility(IAction nextGCD, out IAction? act) + { + act = null; + + + return base.MoveForwardAbility(nextGCD, out act); + } + #endregion + + #region GCD Logic + protected override bool MoveForwardGCD(out IAction? act) + { + act = null; + + return base.MoveForwardGCD(out act); + } + + protected override bool GeneralGCD(out IAction? act) + { + act = null; + + return base.GeneralGCD(out act); + } + + private bool AttackGCD(out IAction? act, bool burst) + { + act = null; + + return false; + } + #endregion + + #region Extra Methods + // Extra private helper methods for determining the usability of specific abilities under certain conditions. + // These methods simplify the main logic by encapsulating specific checks related to abilities' cooldowns and prerequisites. + private bool CanUseExamplePvE(out IAction? act) + { + + } + #endregion +}*/ \ No newline at end of file diff --git a/BasicRotations/Ranged/BRD_Default.cs b/BasicRotations/Ranged/BRD_Default.cs index 43bce72..03e1879 100644 --- a/BasicRotations/Ranged/BRD_Default.cs +++ b/BasicRotations/Ranged/BRD_Default.cs @@ -31,7 +31,7 @@ public sealed class BRD_Default : BardRotation private float ARMYRemainTime => 45 - ARMYTime; #endregion - #region Emergency Logic + #region oGCD Logic protected override bool EmergencyAbility(IAction nextGCD, out IAction? act) { if (nextGCD.IsTheSameTo(true, StraightShotPvE, VenomousBitePvE, WindbitePvE, IronJawsPvE)) @@ -48,9 +48,7 @@ protected override bool EmergencyAbility(IAction nextGCD, out IAction? act) return base.EmergencyAbility(nextGCD, out act); } - #endregion - #region oGCD Logic protected override bool AttackAbility(IAction nextGCD, out IAction? act) { act = null; diff --git a/BasicRotations/Ranged/DNC_Default.cs b/BasicRotations/Ranged/DNC_Default.cs index 2ae303a..f657056 100644 --- a/BasicRotations/Ranged/DNC_Default.cs +++ b/BasicRotations/Ranged/DNC_Default.cs @@ -11,7 +11,9 @@ public sealed class DNC_Default : DancerRotation [RotationConfig(CombatType.PvE, Name = "Holds Standard Step if no targets in range (Warning, will drift & Buff may fall off)")] public bool HoldStepForTargets { get; set; } = false; + #endregion + #region Countdown Logic // Override the method for actions to be taken during countdown phase of combat protected override IAction? CountDownAction(float remainTime) { @@ -28,10 +30,15 @@ public sealed class DNC_Default : DancerRotation } #endregion - #region Emergency Logic + #region oGCD Logic // Override the method for handling emergency abilities protected override bool EmergencyAbility(IAction nextGCD, out IAction? act) { + if (Player.HasStatus(true, StatusID.TechnicalFinish)) + { + if (DevilmentPvE.CanUse(out act, skipClippingCheck: true)) return true; + } + // Special handling if the last action was Quadruple Technical Finish and level requirement is met if (IsLastGCD(ActionID.QuadrupleTechnicalFinishPvE) && TechnicalStepPvE.EnoughLevel) { @@ -60,9 +67,7 @@ protected override bool EmergencyAbility(IAction nextGCD, out IAction? act) // Fallback to base class method if none of the above conditions are met return base.EmergencyAbility(nextGCD, out act); } - #endregion - #region oGCD Logic // Override the method for handling attack abilities protected override bool AttackAbility(IAction nextGCD, out IAction? act) { diff --git a/BasicRotations/Ranged/MCH_Default.cs b/BasicRotations/Ranged/MCH_Default.cs index fefe014..6af91d3 100644 --- a/BasicRotations/Ranged/MCH_Default.cs +++ b/BasicRotations/Ranged/MCH_Default.cs @@ -1,5 +1,3 @@ -using RotationSolver.Basic.Data; - namespace DefaultRotations.Ranged; [Rotation("LTS's Default", CombatType.PvE, GameVersion = "6.58", Description = "Additonal contributions to this rotation thanks to Toshi!")] @@ -7,8 +5,10 @@ namespace DefaultRotations.Ranged; [Api(1)] public sealed class MCH_Default : MachinistRotation { + #region Config Options [RotationConfig(CombatType.PvE, Name = "Uses Rook Autoturret/Automaton Queen immediately whenever you get 50 battery")] public bool UseQueenWhenever { get; set; } = true; + #endregion #region Countdown logic // Defines logic for actions to take during the countdown before combat starts. @@ -26,7 +26,7 @@ public sealed class MCH_Default : MachinistRotation } #endregion - #region Emergency Logic + #region oGCD Logic // Determines emergency actions to take based on the next planned GCD action. protected override bool EmergencyAbility(IAction nextGCD, out IAction? act) { @@ -48,7 +48,8 @@ protected override bool EmergencyAbility(IAction nextGCD, out IAction? act) // Keeps Ricochet and Gauss cannon Even bool isRicochetMore = (GaussRoundPvE.Cooldown.CurrentCharges <= RicochetPvE.Cooldown.CurrentCharges); - bool isGaussMore = (GaussRoundPvE.Cooldown.CurrentCharges > RicochetPvE.Cooldown.CurrentCharges); + bool isGaussMore = (!RicochetPvE.EnoughLevel /*Check to use Gauss below lvl50 */ || + (GaussRoundPvE.Cooldown.CurrentCharges > RicochetPvE.Cooldown.CurrentCharges)); // Attempt to use Reassemble if it's ready if (isReassembleUsable) @@ -68,9 +69,7 @@ protected override bool EmergencyAbility(IAction nextGCD, out IAction? act) } return base.EmergencyAbility(nextGCD, out act); } - #endregion - #region oGCD Logic // Logic for using attack abilities outside of GCD, focusing on burst windows and cooldown management. protected override bool AttackAbility(IAction nextGCD, out IAction? act) { diff --git a/BasicRotations/Tank/DRK_Default.cs b/BasicRotations/Tank/DRK_Default.cs index b4d7f4e..6355178 100644 --- a/BasicRotations/Tank/DRK_Default.cs +++ b/BasicRotations/Tank/DRK_Default.cs @@ -5,55 +5,12 @@ namespace DefaultRotations.Tank; [Api(1)] public sealed class DRK_Default : DarkKnightRotation { - // Indicates whether the Dark Knight can heal using a single ability. - public override bool CanHealSingleAbility => false; - - // Determines if currently in a burst phase based on cooldowns of key abilities. - private bool InTwoMIsBurst() - { - if ((BloodWeaponPvE.Cooldown.IsCoolingDown && DeliriumPvE.Cooldown.IsCoolingDown && ((LivingShadowPvE.Cooldown.IsCoolingDown && !(LivingShadowPvE.Cooldown.ElapsedAfter(15))) || !LivingShadowPvE.EnoughLevel))) return true; - else return false; - } - - // Checks if combat time is less than 3 seconds. - private static bool CombatLess => CombatElapsedLess(3); - - // Manages DarkSide ability based on several conditions. - private bool CheckDarkSide - { - get - { - if (DarkSideEndAfterGCD(3)) return true; - - if (CombatLess) return false; - - if ((InTwoMIsBurst() && HasDarkArts) || (HasDarkArts && Player.HasStatus(true, StatusID.BlackestNight)) || (HasDarkArts && DarkSideEndAfterGCD(3))) return true; - - if ((InTwoMIsBurst() && BloodWeaponPvE.Cooldown.IsCoolingDown && LivingShadowPvE.Cooldown.IsCoolingDown && SaltedEarthPvE.Cooldown.IsCoolingDown && ShadowbringerPvE.Cooldown.CurrentCharges == 0 && CarveAndSpitPvE.Cooldown.IsCoolingDown)) return true; - - if (TheBlackestNight && CurrentMp < 6000) return false; - - return CurrentMp >= 8500; - } - } - - // Logic to determine when to use blood-based abilities. - private bool UseBlood - { - get - { - // Conditions based on player statuses and ability cooldowns. - if (!DeliriumPvE.EnoughLevel) return true; - if (Player.HasStatus(true, StatusID.Delirium_1972) && LivingShadowPvE.Cooldown.IsCoolingDown) return true; - if ((DeliriumPvE.Cooldown.WillHaveOneChargeGCD(1) && !LivingShadowPvE.Cooldown.WillHaveOneChargeGCD(3)) || Blood >= 90 && !LivingShadowPvE.Cooldown.WillHaveOneChargeGCD(1)) return true; - - return false; - } - } - + #region Config Options [RotationConfig(CombatType.PvE, Name = "Keep at least 3000 MP")] public bool TheBlackestNight { get; set; } = true; + #endregion + #region Countdown Logic // Countdown logic to prepare for combat. // Includes logic for using Provoke, tank stances, and burst medicines. protected override IAction? CountDownAction(float remainTime) @@ -75,7 +32,9 @@ private bool UseBlood if (remainTime <= 4 && BloodWeaponPvE.CanUse(out act)) return act; return base.CountDownAction(remainTime); } + #endregion + #region oGCD Logic // Decision-making for emergency abilities, focusing on Blood Weapon usage. protected override bool EmergencyAbility(IAction nextGCD, out IAction? act) { @@ -142,29 +101,6 @@ protected override bool DefenseSingleAbility(IAction nextGCD, out IAction? act) return base.DefenseAreaAbility(nextGCD, out act); } - protected override bool GeneralGCD(out IAction? act) - { - //Use Blood - if (UseBlood) - { - if (QuietusPvE.CanUse(out act, skipClippingCheck: true, skipComboCheck: true)) return true; - if (BloodspillerPvE.CanUse(out act, skipClippingCheck: true, skipComboCheck: true)) return true; - } - - //AOE - if (StalwartSoulPvE.CanUse(out act)) return true; - if (UnleashPvE.CanUse(out act)) return true; - - //单体 - if (SouleaterPvE.CanUse(out act)) return true; - if (SyphonStrikePvE.CanUse(out act)) return true; - if (HardSlashPvE.CanUse(out act)) return true; - - if (BloodWeaponPvE.Cooldown.IsCoolingDown && !Player.HasStatus(true, StatusID.BloodWeapon) && UnmendPvE.CanUse(out act)) return true; - - return base.GeneralGCD(out act); - } - protected override bool AttackAbility(IAction nextGCD, out IAction? act) { //if (InCombat && CombatElapsedLess(2) && BloodWeapon.CanUse(out act)) return true; @@ -214,4 +150,77 @@ protected override bool AttackAbility(IAction nextGCD, out IAction? act) if (MergedStatus.HasFlag(AutoStatus.MoveForward) && MoveForwardAbility(nextGCD, out act)) return true; return base.AttackAbility(nextGCD, out act); } + #endregion + + #region GCD Logic + protected override bool GeneralGCD(out IAction? act) + { + //Use Blood + if (UseBlood) + { + if (QuietusPvE.CanUse(out act, skipClippingCheck: true, skipComboCheck: true)) return true; + if (BloodspillerPvE.CanUse(out act, skipClippingCheck: true, skipComboCheck: true)) return true; + } + + //AOE + if (StalwartSoulPvE.CanUse(out act)) return true; + if (UnleashPvE.CanUse(out act)) return true; + + //单体 + if (SouleaterPvE.CanUse(out act)) return true; + if (SyphonStrikePvE.CanUse(out act)) return true; + if (HardSlashPvE.CanUse(out act)) return true; + + if (BloodWeaponPvE.Cooldown.IsCoolingDown && !Player.HasStatus(true, StatusID.BloodWeapon) && UnmendPvE.CanUse(out act)) return true; + + return base.GeneralGCD(out act); + } + #endregion + + #region Extra Methods + // Indicates whether the Dark Knight can heal using a single ability. + public override bool CanHealSingleAbility => false; + + // Logic to determine when to use blood-based abilities. + private bool UseBlood + { + get + { + // Conditions based on player statuses and ability cooldowns. + if (!DeliriumPvE.EnoughLevel) return true; + if (Player.HasStatus(true, StatusID.Delirium_1972) && LivingShadowPvE.Cooldown.IsCoolingDown) return true; + if ((DeliriumPvE.Cooldown.WillHaveOneChargeGCD(1) && !LivingShadowPvE.Cooldown.WillHaveOneChargeGCD(3)) || Blood >= 90 && !LivingShadowPvE.Cooldown.WillHaveOneChargeGCD(1)) return true; + + return false; + } + } + // Determines if currently in a burst phase based on cooldowns of key abilities. + private bool InTwoMIsBurst() + { + if ((BloodWeaponPvE.Cooldown.IsCoolingDown && DeliriumPvE.Cooldown.IsCoolingDown && ((LivingShadowPvE.Cooldown.IsCoolingDown && !(LivingShadowPvE.Cooldown.ElapsedAfter(15))) || !LivingShadowPvE.EnoughLevel))) return true; + else return false; + } + + // Checks if combat time is less than 3 seconds. + private static bool CombatLess => CombatElapsedLess(3); + + // Manages DarkSide ability based on several conditions. + private bool CheckDarkSide + { + get + { + if (DarkSideEndAfterGCD(3)) return true; + + if (CombatLess) return false; + + if ((InTwoMIsBurst() && HasDarkArts) || (HasDarkArts && Player.HasStatus(true, StatusID.BlackestNight)) || (HasDarkArts && DarkSideEndAfterGCD(3))) return true; + + if ((InTwoMIsBurst() && BloodWeaponPvE.Cooldown.IsCoolingDown && LivingShadowPvE.Cooldown.IsCoolingDown && SaltedEarthPvE.Cooldown.IsCoolingDown && ShadowbringerPvE.Cooldown.CurrentCharges == 0 && CarveAndSpitPvE.Cooldown.IsCoolingDown)) return true; + + if (TheBlackestNight && CurrentMp < 6000) return false; + + return CurrentMp >= 8500; + } + } + #endregion } \ No newline at end of file diff --git a/BasicRotations/Tank/GNB_Default.cs b/BasicRotations/Tank/GNB_Default.cs index 9902f57..11db610 100644 --- a/BasicRotations/Tank/GNB_Default.cs +++ b/BasicRotations/Tank/GNB_Default.cs @@ -7,17 +7,16 @@ namespace DefaultRotations.Tank; [Api(1)] public sealed class GNB_Default : GunbreakerRotation { - public override bool CanHealSingleSpell => false; - - public override bool CanHealAreaSpell => false; - + #region Countdown Logic protected override IAction? CountDownAction(float remainTime) { if (remainTime <= 0.7 && LightningShotPvE.CanUse(out var act)) return act; if (remainTime <= 1.2 && UseBurstMedicine(out act)) return act; return base.CountDownAction(remainTime); } + #endregion + #region oGCD Logic protected override bool EmergencyAbility(IAction nextGCD, out IAction? act) { if (base.EmergencyAbility(nextGCD, out act)) return true; @@ -31,34 +30,38 @@ protected override bool EmergencyAbility(IAction nextGCD, out IAction? act) return base.EmergencyAbility(nextGCD, out act); } - protected override bool GeneralGCD(out IAction? act) + [RotationDesc(ActionID.HeartOfLightPvE, ActionID.ReprisalPvE)] + protected override bool DefenseAreaAbility(IAction nextGCD, out IAction? act) { - if (FatedCirclePvE.CanUse(out act)) return true; - if (CanUseGnashingFang(out act)) return true; - - if (DemonSlaughterPvE.CanUse(out act)) return true; - if (DemonSlicePvE.CanUse(out act)) return true; - - if (Player.HasStatus(true, StatusID.NoMercy) && CanUseSonicBreak(out act)) return true; - - if (Player.HasStatus(true, StatusID.NoMercy) && CanUseDoubleDown(out act)) return true; - - if (SavageClawPvE.CanUse(out act, skipComboCheck: true)) return true; - if (WickedTalonPvE.CanUse(out act, skipComboCheck: true)) return true; - - if (CanUseBurstStrike(out act)) return true; - - if (SolidBarrelPvE.CanUse(out act)) return true; - if (BrutalShellPvE.CanUse(out act)) return true; - if (KeenEdgePvE.CanUse(out act)) return true; + if (!Player.HasStatus(true, StatusID.NoMercy) && HeartOfLightPvE.CanUse(out act, skipAoeCheck: true)) return true; + if (!Player.HasStatus(true, StatusID.NoMercy) && ReprisalPvE.CanUse(out act, skipAoeCheck: true)) return true; + return base.DefenseAreaAbility(nextGCD, out act); + } + [RotationDesc(ActionID.HeartOfStonePvE, ActionID.NebulaPvE, ActionID.RampartPvE, ActionID.CamouflagePvE, ActionID.ReprisalPvE)] + protected override bool DefenseSingleAbility(IAction nextGCD, out IAction? act) + { + //10 + if (CamouflagePvE.CanUse(out act, onLastAbility: true)) return true; + //15 + if (HeartOfStonePvE.CanUse(out act, onLastAbility: true)) return true; + //30 + if ((!RampartPvE.Cooldown.IsCoolingDown || RampartPvE.Cooldown.ElapsedAfter(60)) && NebulaPvE.CanUse(out act)) return true; + //20 + if (NebulaPvE.Cooldown.IsCoolingDown && NebulaPvE.Cooldown.ElapsedAfter(60) && RampartPvE.CanUse(out act)) return true; - if (LightningShotPvE.CanUse(out act)) return true; + if (ReprisalPvE.CanUse(out act)) return true; - return base.GeneralGCD(out act); + return base.DefenseSingleAbility(nextGCD, out act); } + [RotationDesc(ActionID.AuroraPvE)] + protected override bool HealSingleAbility(IAction nextGCD, out IAction? act) + { + if (AuroraPvE.CanUse(out act, usedUp: true, onLastAbility: true)) return true; + return base.HealSingleAbility(nextGCD, out act); + } protected override bool AttackAbility(IAction nextGCD, out IAction? act) { //if (IsBurst && CanUseNoMercy(out act)) return true; @@ -95,39 +98,42 @@ protected override bool AttackAbility(IAction nextGCD, out IAction? act) if (MergedStatus.HasFlag(AutoStatus.MoveForward) && MoveForwardAbility(nextGCD, out act)) return true; return base.AttackAbility(nextGCD, out act); } + #endregion - [RotationDesc(ActionID.HeartOfLightPvE, ActionID.ReprisalPvE)] - protected override bool DefenseAreaAbility(IAction nextGCD, out IAction? act) + #region GCD Logic + protected override bool GeneralGCD(out IAction? act) { - if (!Player.HasStatus(true, StatusID.NoMercy) && HeartOfLightPvE.CanUse(out act, skipAoeCheck: true)) return true; - if (!Player.HasStatus(true, StatusID.NoMercy) && ReprisalPvE.CanUse(out act, skipAoeCheck: true)) return true; - return base.DefenseAreaAbility(nextGCD, out act); - } + if (FatedCirclePvE.CanUse(out act)) return true; + if (CanUseGnashingFang(out act)) return true; - [RotationDesc(ActionID.HeartOfStonePvE, ActionID.NebulaPvE, ActionID.RampartPvE, ActionID.CamouflagePvE, ActionID.ReprisalPvE)] - protected override bool DefenseSingleAbility(IAction nextGCD, out IAction? act) - { - //10 - if (CamouflagePvE.CanUse(out act, onLastAbility: true)) return true; - //15 - if (HeartOfStonePvE.CanUse(out act, onLastAbility: true)) return true; + if (DemonSlaughterPvE.CanUse(out act)) return true; + if (DemonSlicePvE.CanUse(out act)) return true; - //30 - if ((!RampartPvE.Cooldown.IsCoolingDown || RampartPvE.Cooldown.ElapsedAfter(60)) && NebulaPvE.CanUse(out act)) return true; - //20 - if (NebulaPvE.Cooldown.IsCoolingDown && NebulaPvE.Cooldown.ElapsedAfter(60) && RampartPvE.CanUse(out act)) return true; + if (Player.HasStatus(true, StatusID.NoMercy) && CanUseSonicBreak(out act)) return true; - if (ReprisalPvE.CanUse(out act)) return true; + if (Player.HasStatus(true, StatusID.NoMercy) && CanUseDoubleDown(out act)) return true; - return base.DefenseSingleAbility(nextGCD, out act); - } + if (SavageClawPvE.CanUse(out act, skipComboCheck: true)) return true; + if (WickedTalonPvE.CanUse(out act, skipComboCheck: true)) return true; - [RotationDesc(ActionID.AuroraPvE)] - protected override bool HealSingleAbility(IAction nextGCD, out IAction? act) - { - if (AuroraPvE.CanUse(out act, usedUp: true, onLastAbility: true)) return true; - return base.HealSingleAbility(nextGCD, out act); + if (CanUseBurstStrike(out act)) return true; + + if (SolidBarrelPvE.CanUse(out act)) return true; + if (BrutalShellPvE.CanUse(out act)) return true; + if (KeenEdgePvE.CanUse(out act)) return true; + + + + if (LightningShotPvE.CanUse(out act)) return true; + + return base.GeneralGCD(out act); } + #endregion + + #region Extra Methods + public override bool CanHealSingleSpell => false; + + public override bool CanHealAreaSpell => false; //private bool CanUseNoMercy(out IAction act) //{ @@ -234,4 +240,5 @@ private bool CanUseBowShock(out IAction act) } return false; } +#endregion } \ No newline at end of file diff --git a/BasicRotations/Tank/PLD_Default.cs b/BasicRotations/Tank/PLD_Default.cs index f0019ab..7b25c6e 100644 --- a/BasicRotations/Tank/PLD_Default.cs +++ b/BasicRotations/Tank/PLD_Default.cs @@ -5,6 +5,7 @@ [Api(1)] public class PLD_Default : PaladinRotation { + #region Config Options [RotationConfig(CombatType.PvE, Name = "Use Divine Veil at 15 seconds remaining on Countdown")] public bool UseDivineVeilPre { get; set; } = false; @@ -13,7 +14,9 @@ public class PLD_Default : PaladinRotation [RotationConfig(CombatType.PvE, Name = "Use Shield Bash when Low Blow is cooling down")] public bool UseShieldBash { get; set; } = true; + #endregion + #region Countdown Logic protected override IAction? CountDownAction(float remainTime) { if (remainTime < HolySpiritPvE.Info.CastTime + CountDownAhead @@ -24,7 +27,9 @@ public class PLD_Default : PaladinRotation return base.CountDownAction(remainTime); } + #endregion + #region oGCD Logic protected override bool EmergencyAbility(IAction nextGCD, out IAction? act) { if (InCombat) @@ -64,6 +69,45 @@ protected override bool AttackAbility(IAction nextGCD, out IAction? act) return base.AttackAbility(nextGCD, out act); } + [RotationDesc(ActionID.ReprisalPvE, ActionID.DivineVeilPvE)] + protected override bool DefenseAreaAbility(IAction nextGCD, out IAction? act) + { + + if (DivineVeilPvE.CanUse(out act)) return true; + + if (PassageOfArmsPvE.CanUse(out act)) return true; + return base.DefenseAreaAbility(nextGCD, out act); + } + + [RotationDesc(ActionID.SentinelPvE, ActionID.RampartPvE, ActionID.BulwarkPvE, ActionID.SheltronPvE, ActionID.ReprisalPvE)] + protected override bool DefenseSingleAbility(IAction nextGCD, out IAction? act) + { + + // If the player has the Hallowed Ground status, don't use any abilities. + if (!Player.HasStatus(true, StatusID.HallowedGround)) + { + // If Bulwark can be used and there are more than 2 hostiles in range, use it and return true. + if (BulwarkPvE.CanUse(out act, true) && NumberOfHostilesInRange > 2) return true; + + // If Oath can be used, use it and return true. + //if (UseOath(out act, true)) return true; + + // If Rampart is not cooling down or has been cooling down for more than 60 seconds, and Sentinel can be used, use Sentinel and return true. + if ((!RampartPvE.Cooldown.IsCoolingDown || RampartPvE.Cooldown.ElapsedAfter(60)) && SentinelPvE.CanUse(out act)) return true; + + // If Sentinel is at an enough level and is cooling down for more than 60 seconds, or if Sentinel is not at an enough level, and Rampart can be used, use Rampart and return true. + if ((SentinelPvE.EnoughLevel && SentinelPvE.Cooldown.IsCoolingDown && SentinelPvE.Cooldown.ElapsedAfter(60) || !SentinelPvE.EnoughLevel) && RampartPvE.CanUse(out act)) return true; + + // If Reprisal can be used, use it and return true. + if (ReprisalPvE.CanUse(out act, skipAoeCheck: true, skipStatusProvideCheck: true)) return true; + + } + + return base.DefenseSingleAbility(nextGCD, out act); + } + #endregion + + #region GCD Logic protected override bool GeneralGCD(out IAction? act) { if (Player.HasStatus(true, StatusID.Requiescat)) @@ -108,44 +152,9 @@ protected override bool GeneralGCD(out IAction? act) return base.GeneralGCD(out act); } + #endregion - [RotationDesc(ActionID.ReprisalPvE, ActionID.DivineVeilPvE)] - protected override bool DefenseAreaAbility(IAction nextGCD, out IAction? act) - { - - if (DivineVeilPvE.CanUse(out act)) return true; - - if (PassageOfArmsPvE.CanUse(out act)) return true; - return base.DefenseAreaAbility(nextGCD, out act); - } - - [RotationDesc(ActionID.SentinelPvE, ActionID.RampartPvE, ActionID.BulwarkPvE, ActionID.SheltronPvE, ActionID.ReprisalPvE)] - protected override bool DefenseSingleAbility(IAction nextGCD, out IAction? act) - { - - // If the player has the Hallowed Ground status, don't use any abilities. - if (!Player.HasStatus(true, StatusID.HallowedGround)) - { - // If Bulwark can be used and there are more than 2 hostiles in range, use it and return true. - if (BulwarkPvE.CanUse(out act, true) && NumberOfHostilesInRange > 2) return true; - - // If Oath can be used, use it and return true. - //if (UseOath(out act, true)) return true; - - // If Rampart is not cooling down or has been cooling down for more than 60 seconds, and Sentinel can be used, use Sentinel and return true. - if ((!RampartPvE.Cooldown.IsCoolingDown || RampartPvE.Cooldown.ElapsedAfter(60)) && SentinelPvE.CanUse(out act)) return true; - - // If Sentinel is at an enough level and is cooling down for more than 60 seconds, or if Sentinel is not at an enough level, and Rampart can be used, use Rampart and return true. - if ((SentinelPvE.EnoughLevel && SentinelPvE.Cooldown.IsCoolingDown && SentinelPvE.Cooldown.ElapsedAfter(60) || !SentinelPvE.EnoughLevel) && RampartPvE.CanUse(out act)) return true; - - // If Reprisal can be used, use it and return true. - if (ReprisalPvE.CanUse(out act, skipAoeCheck: true, skipStatusProvideCheck: true)) return true; - - } - - return base.DefenseSingleAbility(nextGCD, out act); - } - + #region Extra Methods private bool UseOath(out IAction act, bool onLast = false) { if (SheltronPvE.CanUse(out act, onLastAbility: onLast)) return true; @@ -153,4 +162,5 @@ private bool UseOath(out IAction act, bool onLast = false) return false; } + #endregion } \ No newline at end of file diff --git a/BasicRotations/Tank/WAR_Default.cs b/BasicRotations/Tank/WAR_Default.cs index 3ea2e81..3a4bafc 100644 --- a/BasicRotations/Tank/WAR_Default.cs +++ b/BasicRotations/Tank/WAR_Default.cs @@ -5,8 +5,8 @@ namespace DefaultRotations.Tank; [Api(1)] public sealed class WAR_Default : WarriorRotation { - private static bool IsBurstStatus => !Player.WillStatusEndGCD(0, 0, false, StatusID.InnerStrength); + #region Countdown Logic protected override IAction? CountDownAction(float remainTime) { if (remainTime <= CountDownAhead) @@ -22,40 +22,9 @@ public sealed class WAR_Default : WarriorRotation } return base.CountDownAction(remainTime); } + #endregion - protected override bool GeneralGCD(out IAction? act) - { - // If the player's Surging Tempest status will not end in the next 3 GCDs, consider using certain abilities. - if (!Player.WillStatusEndGCD(3, 0, true, StatusID.SurgingTempest)) - { - // If the player is not moving, is in a burst status, and Primal Rend can be used on a target within a distance of 1, use Primal Rend. - if (!IsMoving && IsBurstStatus && PrimalRendPvE.CanUse(out act, skipAoeCheck: true)) - { - if (PrimalRendPvE.Target.Target?.DistanceToPlayer() < 1) return true; - } - // If the player is in a burst status, does not have the Nascent Chaos status, or has a Beast Gauge greater than 80, consider using Steel Cyclone or Inner Beast. - if (IsBurstStatus || !Player.HasStatus(false, StatusID.NascentChaos) || BeastGauge > 80) - { - if (SteelCyclonePvE.CanUse(out act)) return true; - if (InnerBeastPvE.CanUse(out act)) return true; - } - } - - // If any of the following abilities can be used, use them and return true. - if (MythrilTempestPvE.CanUse(out act)) return true; - if (OverpowerPvE.CanUse(out act)) return true; - if (StormsEyePvE.CanUse(out act)) return true; - if (StormsPathPvE.CanUse(out act)) return true; - if (MaimPvE.CanUse(out act)) return true; - if (HeavySwingPvE.CanUse(out act)) return true; - - // If Tomahawk can be used, use it and return true. - if (TomahawkPvE.CanUse(out act)) return true; - - return base.GeneralGCD(out act); - } - - + #region oGCD Logic protected override bool AttackAbility(IAction nextGCD, out IAction? act) { // If Infuriate can be used, use it and return true. @@ -159,6 +128,40 @@ protected override bool DefenseAreaAbility(IAction nextGCD, out IAction? act) return base.DefenseAreaAbility(nextGCD, out act); } + #endregion + + #region GCD Logic + protected override bool GeneralGCD(out IAction? act) + { + // If the player's Surging Tempest status will not end in the next 3 GCDs, consider using certain abilities. + if (!Player.WillStatusEndGCD(3, 0, true, StatusID.SurgingTempest)) + { + // If the player is not moving, is in a burst status, and Primal Rend can be used on a target within a distance of 1, use Primal Rend. + if (!IsMoving && IsBurstStatus && PrimalRendPvE.CanUse(out act, skipAoeCheck: true)) + { + if (PrimalRendPvE.Target.Target?.DistanceToPlayer() < 1) return true; + } + // If the player is in a burst status, does not have the Nascent Chaos status, or has a Beast Gauge greater than 80, consider using Steel Cyclone or Inner Beast. + if (IsBurstStatus || !Player.HasStatus(false, StatusID.NascentChaos) || BeastGauge > 80) + { + if (SteelCyclonePvE.CanUse(out act)) return true; + if (InnerBeastPvE.CanUse(out act)) return true; + } + } + + // If any of the following abilities can be used, use them and return true. + if (MythrilTempestPvE.CanUse(out act)) return true; + if (OverpowerPvE.CanUse(out act)) return true; + if (StormsEyePvE.CanUse(out act)) return true; + if (StormsPathPvE.CanUse(out act)) return true; + if (MaimPvE.CanUse(out act)) return true; + if (HeavySwingPvE.CanUse(out act)) return true; + + // If Tomahawk can be used, use it and return true. + if (TomahawkPvE.CanUse(out act)) return true; + + return base.GeneralGCD(out act); + } [RotationDesc(ActionID.NascentFlashPvE)] protected override bool HealSingleGCD(out IAction? act) @@ -173,5 +176,9 @@ protected override bool HealSingleGCD(out IAction? act) return base.HealSingleGCD(out act); } + #endregion + #region Extra Methods + private static bool IsBurstStatus => !Player.WillStatusEndGCD(0, 0, false, StatusID.InnerStrength); + #endregion }