Skip to content

Commit

Permalink
Merge pull request #449 from FFXIV-CombatReborn/rotation-rollup
Browse files Browse the repository at this point in the history
Bake in default rotations
  • Loading branch information
NostraThomas99 authored Nov 23, 2024
2 parents 3e532dc + 141f9b2 commit 9db7f6f
Show file tree
Hide file tree
Showing 63 changed files with 9,248 additions and 98 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/publish.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ jobs:
- name: Restore Nuget Packages
run: dotnet restore RotationSolver/RotationSolver.csproj

- name: Build Rotations
run: dotnet build --no-restore -c Release BasicRotations/RebornRotations.csproj -p:AssemblyVersion=${{ env.tag }} -p:FileVersion=${{ env.tag }} -p:PackageVersion=${{ env.tag }} -p:InformationalVersion=${{ env.tag }} --output .\build
- name: Build Plugin
run: dotnet build --no-restore -c Release RotationSolver/RotationSolver.csproj -p:AssemblyVersion=${{ env.tag }} -p:FileVersion=${{ env.tag }} -p:PackageVersion=${{ env.tag }} -p:InformationalVersion=${{ env.tag }} --output .\build
- name: Push Nuget Package
Expand Down
1 change: 1 addition & 0 deletions BasicRotations/AssemblyInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[assembly: AssemblyLink(Donate = "", UserName = "FFXIV-CombatReborn", Repository = "RotationSolverReborn")]
42 changes: 42 additions & 0 deletions BasicRotations/Duty/BozjaDefault
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
using RotationSolver.Basic.Rotations.Duties;

namespace DefaultRotations.Duty;

[Rotation("Bozja Default", CombatType.PvE)]
internal class BozjaDefault : BozjaRotation
{
public override bool DefenseSingleGCD(out IAction? act)
{
if (LostStoneskinPvE.CanUse(out act)) return true;
return base.DefenseSingleGCD(out act);
}

public override bool DefenseAreaGCD(out IAction? act)
{
if (LostStoneskinIiPvE.CanUse(out act)) return true;
return base.DefenseAreaGCD(out act);
}

public override bool EmergencyGCD(out IAction? act)
{
#region Bozja
//if (LostSpellforge.CanUse(out act)) return true;
//if (LostSteelsting.CanUse(out act)) return true;
//if (LostRampage.CanUse(out act)) return true;
//if (LostBurst.CanUse(out act)) return true;

//if (LostBravery.CanUse(out act)) return true;
//if (LostBubble.CanUse(out act)) return true;
//if (LostShell2.CanUse(out act)) return true;
//if (LostShell.CanUse(out act)) return true;
//if (LostProtect2.CanUse(out act)) return true;
//if (LostProtect.CanUse(out act)) return true;

////Add your own logic here.
//if (LostFlarestar.CanUse(out act)) return true;
//if (LostSeraphStrike.CanUse(out act)) return true;

#endregion
return base.EmergencyGCD(out act);
}
}
26 changes: 26 additions & 0 deletions BasicRotations/Duty/EmanationDefault
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using RotationSolver.Basic.Rotations.Duties;

namespace DefaultRotations.Duty;

[Rotation("Emanation Default", CombatType.PvE)]

internal class EmanationDefault : EmanationRotation
{
public override bool EmergencyAbility(IAction nextGCD, out IAction? act)
{
// 8521 8522 8523
bool Lol1 = HostileTarget?.CastActionId == 8521;
bool Lol2 = HostileTarget?.CastActionId == 8522;
bool Lol3 = HostileTarget?.CastActionId == 8523;

if (Lol1 || Lol2 || Lol3)
{
if (VrilPvE.CanUse(out act)) return true; // Normal
if (VrilPvE_9345.CanUse(out act)) return true; // Extreme
return base.EmergencyAbility(nextGCD, out act);
}

act = null;
return base.EmergencyAbility(nextGCD, out act);
}
}
37 changes: 37 additions & 0 deletions BasicRotations/Duty/VariantDefault.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using RotationSolver.Basic.Rotations.Duties;

namespace DefaultRotations.Duty;

[Rotation("Variant Default", CombatType.PvE)]

internal class VariantDefault : VariantRotation
{
public override bool ProvokeAbility(IAction nextGCD, out IAction? act)
{
if (VariantUltimatumPvE.CanUse(out act)) return true;
return base.ProvokeAbility(nextGCD, out act);
}

public override bool AttackAbility(IAction nextGCD, out IAction? act)
{
if (VariantSpiritDartPvE.CanUse(out act, skipAoeCheck: true)) return true;
if (VariantSpiritDartPvE_33863.CanUse(out act, skipAoeCheck: true)) return true;
if (VariantRampartPvE.CanUse(out act)) return true;
if (VariantRampartPvE_33864.CanUse(out act)) return true;
return base.AttackAbility(nextGCD, out act);
}

public override bool HealSingleGCD(out IAction? act)
{
if (VariantCurePvE.CanUse(out act, skipStatusProvideCheck: true)) return true;
if (VariantCurePvE_33862.CanUse(out act, skipStatusProvideCheck: true)) return true;
return base.HealSingleGCD(out act);
}

public override bool RaiseGCD(out IAction? act)
{
if (VariantRaisePvE.CanUse(out act)) return true;
if (VariantRaiseIiPvE.CanUse(out act)) return true;
return base.RaiseGCD(out act);
}
}
276 changes: 276 additions & 0 deletions BasicRotations/Healer/AST_Default.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,276 @@
namespace DefaultRotations.Healer;

[Rotation("Default", CombatType.PvE, GameVersion = "7.05")]
[SourceCode(Path = "main/BasicRotations/Healer/AST_Default.cs")]
[Api(4)]
public sealed class AST_Default : AstrologianRotation
{
#region Config Options
[RotationConfig(CombatType.PvE, Name = "Enable Swiftcast Restriction Logic to attempt to prevent actions other than Raise when you have swiftcast")]
public bool SwiftLogic { get; set; } = true;

[RotationConfig(CombatType.PvE, Name = "Use both stacks of Lightspeed while moving")]
public bool LightspeedMove { get; set; } = true;

[RotationConfig(CombatType.PvE, Name = "Use experimental card logic to pool for divination buff if possible")]
public bool SmartCard { get; set; } = true;

[RotationConfig(CombatType.PvE, Name = "Use spells with cast times to heal. (Ignored if you are the only healer in party)")]
public bool GCDHeal { get; set; } = false;

[RotationConfig(CombatType.PvE, Name = "Prevent actions while you have the bubble mit up")]
public bool BubbleProtec { get; set; } = false;

[RotationConfig(CombatType.PvE, Name = "Prioritize Microcosmos over all other healing when available")]
public bool MicroPrio { get; set; } = false;

[Range(4, 20, ConfigUnitType.Seconds)]
[RotationConfig(CombatType.PvE, Name = "Use Earthly Star during countdown timer.")]
public float UseEarthlyStarTime { get; set; } = 15;

[Range(0, 1, ConfigUnitType.Percent)]
[RotationConfig(CombatType.PvE, Name = "Minimum HP threshold party member needs to be to use Aspected Benefic")]
public float AspectedBeneficHeal { get; set; } = 0.4f;

[Range(0, 1, ConfigUnitType.Percent)]
[RotationConfig(CombatType.PvE, Name = "Minimum HP threshold among party member needed to use Horoscope")]
public float HoroscopeHeal { get; set; } = 0.3f;

[RotationConfig(CombatType.PvE, Name = "Use DOT while moving even if it does not need refresh (disabling is a damage down)")]
public bool DOTUpkeep { get; set; } = true;
#endregion

private static bool InBurstStatus => !Player.WillStatusEnd(0, true, StatusID.Divination);

#region Countdown Logic
protected override IAction? CountDownAction(float remainTime)
{
if (remainTime < MaleficPvE.Info.CastTime + CountDownAhead
&& MaleficPvE.CanUse(out var act)) return act;
if (remainTime < 3 && UseBurstMedicine(out act)) return act;
if (remainTime is < 4 and > 3 && AspectedBeneficPvE.CanUse(out act)) return act;
if (remainTime < UseEarthlyStarTime
&& EarthlyStarPvE.CanUse(out act, skipTTKCheck: true)) return act;
if (remainTime < 30 && AstralDrawPvE.CanUse(out act)) return act;

return base.CountDownAction(remainTime);
}
#endregion

#region oGCD Logic
protected override bool EmergencyAbility(IAction nextGCD, out IAction? act)
{
act = null;
if (BubbleProtec && Player.HasStatus(true, StatusID.CollectiveUnconscious_848)) return false;
if (MicroPrio && Player.HasStatus(true, StatusID.Macrocosmos)) return false;

if (!InCombat) return false;

if (OraclePvE.CanUse(out act)) return true;
if (nextGCD.IsTheSameTo(true, AspectedHeliosPvE, HeliosPvE))
{
if (HoroscopePvE.CanUse(out act)) return true;
if (NeutralSectPvE.CanUse(out act)) return true;
}

if (nextGCD.IsTheSameTo(true, BeneficPvE, BeneficIiPvE, AspectedBeneficPvE))
{
if (SynastryPvE.CanUse(out act)) return true;
}
return base.EmergencyAbility(nextGCD, out act);
}

[RotationDesc(ActionID.ExaltationPvE, ActionID.TheArrowPvE, ActionID.TheSpirePvE, ActionID.TheBolePvE, ActionID.TheEwerPvE)]
protected override bool DefenseSingleAbility(IAction nextGCD, out IAction? act)
{
act = null;
if (BubbleProtec && Player.HasStatus(true, StatusID.CollectiveUnconscious_848)) return false;

if (InCombat && TheSpirePvE.CanUse(out act)) return true;
if (InCombat && TheBolePvE.CanUse(out act)) return true;

if (ExaltationPvE.CanUse(out act)) return true;
return base.DefenseSingleAbility(nextGCD, out act);
}

[RotationDesc(ActionID.MacrocosmosPvE)]
protected override bool DefenseAreaGCD(out IAction? act)
{
act = null;
if (BubbleProtec && Player.HasStatus(true, StatusID.CollectiveUnconscious_848)) return false;

if (MacrocosmosPvE.Cooldown.IsCoolingDown && !MacrocosmosPvE.Cooldown.WillHaveOneCharge(150)
|| CollectiveUnconsciousPvE.Cooldown.IsCoolingDown && !CollectiveUnconsciousPvE.Cooldown.WillHaveOneCharge(40)) return false;

if (MacrocosmosPvE.CanUse(out act)) return true;
return base.DefenseAreaGCD(out act);
}

[RotationDesc(ActionID.CollectiveUnconsciousPvE, ActionID.SunSignPvE)]
protected override bool DefenseAreaAbility(IAction nextGCD, out IAction? act)
{
if (SunSignPvE.CanUse(out act)) return true;

act = null;
if (BubbleProtec && Player.HasStatus(true, StatusID.CollectiveUnconscious_848)) return false;

if (MacrocosmosPvE.Cooldown.IsCoolingDown && !MacrocosmosPvE.Cooldown.WillHaveOneCharge(150)
|| CollectiveUnconsciousPvE.Cooldown.IsCoolingDown && !CollectiveUnconsciousPvE.Cooldown.WillHaveOneCharge(40)) return false;

if (CollectiveUnconsciousPvE.CanUse(out act)) return true;
return base.DefenseAreaAbility(nextGCD, out act);
}

[RotationDesc(ActionID.TheArrowPvE, ActionID.TheEwerPvE, ActionID.EssentialDignityPvE,
ActionID.CelestialIntersectionPvE)]
protected override bool HealSingleAbility(IAction nextGCD, out IAction? act)
{
act = null;
if (BubbleProtec && Player.HasStatus(true, StatusID.CollectiveUnconscious_848)) return false;
if (MicroPrio && Player.HasStatus(true, StatusID.Macrocosmos)) return false;

if (InCombat && TheArrowPvE.CanUse(out act)) return true;
if (InCombat && TheEwerPvE.CanUse(out act)) return true;

if (EssentialDignityPvE.CanUse(out act, usedUp: true)) return true;

if (CelestialIntersectionPvE.CanUse(out act, usedUp: true)) return true;

return base.HealSingleAbility(nextGCD, out act);
}

[RotationDesc(ActionID.CelestialOppositionPvE, ActionID.StellarDetonationPvE, ActionID.HoroscopePvE, ActionID.HoroscopePvE_16558, ActionID.LadyOfCrownsPvE, ActionID.HeliosConjunctionPvE)]
protected override bool HealAreaAbility(IAction nextGCD, out IAction? act)
{
act = null;
if (BubbleProtec && Player.HasStatus(true, StatusID.CollectiveUnconscious_848)) return false;

if (MicrocosmosPvE.CanUse(out act)) return true;
if (MicroPrio && Player.HasStatus(true, StatusID.Macrocosmos)) return false;

if (CelestialOppositionPvE.CanUse(out act)) return true;

if (StellarDetonationPvE.CanUse(out act)) return true;

if (HoroscopePvE.CanUse(out act)) return true;

if (HoroscopePvE_16558.CanUse(out act)) return true;

if (LadyOfCrownsPvE.CanUse(out act)) return true;

if (HeliosConjunctionPvE.CanUse(out act)) return true;
return base.HealAreaAbility(nextGCD, out act);
}

protected override bool GeneralAbility(IAction nextGCD, out IAction? act)
{
act = null;
if (BubbleProtec && Player.HasStatus(true, StatusID.CollectiveUnconscious_848)) return false;

if (AstralDrawPvE.CanUse(out act)) return true;
if (UmbralDrawPvE.CanUse(out act)) return true;
if (((Player.HasStatus(true, StatusID.Divination) || !DivinationPvE.Cooldown.WillHaveOneCharge(45) || !DivinationPvE.EnoughLevel || UmbralDrawPvE.Cooldown.WillHaveOneCharge(3)) && SmartCard || (!SmartCard)) && InCombat && TheBalancePvE.CanUse(out act)) return true;
if (((Player.HasStatus(true, StatusID.Divination) || !DivinationPvE.Cooldown.WillHaveOneCharge(45) || !DivinationPvE.EnoughLevel || UmbralDrawPvE.Cooldown.WillHaveOneCharge(3)) && SmartCard || (!SmartCard)) && InCombat && TheSpearPvE.CanUse(out act)) return true;
return base.GeneralAbility(nextGCD, out act);
}

protected override bool AttackAbility(IAction nextGCD, out IAction? act)
{
act = null;
if (BubbleProtec && Player.HasStatus(true, StatusID.CollectiveUnconscious_848)) return false;

if (!Player.HasStatus(true, StatusID.Lightspeed)
&& InCombat
&& DivinationPvE.Cooldown.ElapsedAfter(115)
&& LightspeedPvE.CanUse(out act, usedUp: true)) return true;

if (IsBurst && !IsMoving
&& DivinationPvE.CanUse(out act)) return true;

if (AstralDrawPvE.CanUse(out act, usedUp: IsBurst)) return true;

if (!Player.HasStatus(true, StatusID.Lightspeed)
&& (InBurstStatus || DivinationPvE.Cooldown.ElapsedAfter(115))
&& InCombat
&& LightspeedPvE.CanUse(out act, usedUp: true)) return true;

if (InCombat)
{
if (!Player.HasStatus(true, StatusID.Lightspeed) && IsMoving && LightspeedPvE.CanUse(out act, usedUp: LightspeedMove)) return true;

if (!IsMoving)
{
if (!Player.HasStatus(true, StatusID.EarthlyDominance, StatusID.GiantDominance))
{
if (EarthlyStarPvE.CanUse(out act)) return true;
}
}

{
if (((Player.HasStatus(true, StatusID.Divination) || !DivinationPvE.Cooldown.WillHaveOneCharge(45) || !DivinationPvE.EnoughLevel || UmbralDrawPvE.Cooldown.WillHaveOneCharge(3)) && SmartCard || (!SmartCard)) && LordOfCrownsPvE.CanUse(out act)) return true;
}
}
return base.AttackAbility(nextGCD, out act);
}
#endregion

#region GCD Logic
[RotationDesc(ActionID.AspectedBeneficPvE, ActionID.BeneficIiPvE, ActionID.BeneficPvE)]
protected override bool HealSingleGCD(out IAction? act)
{
act = null;
if (BubbleProtec && Player.HasStatus(true, StatusID.CollectiveUnconscious_848)) return false;
if (MicroPrio && Player.HasStatus(true, StatusID.Macrocosmos)) return false;
if (HasSwift && SwiftLogic && AscendPvE.CanUse(out _)) return false;

if (AspectedBeneficPvE.CanUse(out act)
&& (IsMoving
|| AspectedBeneficPvE.Target.Target?.GetHealthRatio() > AspectedBeneficHeal)) 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)
{
act = null;
if (BubbleProtec && Player.HasStatus(true, StatusID.CollectiveUnconscious_848)) return false;
if (MicroPrio && Player.HasStatus(true, StatusID.Macrocosmos)) return false;
if (HasSwift && SwiftLogic && AscendPvE.CanUse(out _)) return false;

if (AspectedHeliosPvE.CanUse(out act)) return true;
if (HeliosPvE.CanUse(out act)) return true;
return base.HealAreaGCD(out act);
}

protected override bool GeneralGCD(out IAction? act)
{
act = null;
if (BubbleProtec && Player.HasStatus(true, StatusID.CollectiveUnconscious_848)) return false;
if (HasSwift && SwiftLogic) return false;

if (GravityPvE.CanUse(out act)) return true;

if (CombustIiiPvE.CanUse(out act)) return true;
if (CombustIiPvE.CanUse(out act)) return true;
if (CombustPvE.CanUse(out act)) return true;
if (MaleficPvE.CanUse(out act)) return true;
if (CombustIiiPvE.CanUse(out act, skipStatusProvideCheck: DOTUpkeep)) return true;
if (CombustIiPvE.CanUse(out act, skipStatusProvideCheck: DOTUpkeep)) return true;
if (CombustPvE.CanUse(out act, skipStatusProvideCheck: DOTUpkeep)) return true;

return base.GeneralGCD(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
}
Loading

0 comments on commit 9db7f6f

Please sign in to comment.