Skip to content

Commit

Permalink
Merge pull request #572 from FFXIV-CombatReborn/moarSGE
Browse files Browse the repository at this point in the history
Refactor Swiftcast/Raise logic, add SGE options, enhance robustness
  • Loading branch information
LTS-FFXIV authored Jan 15, 2025
2 parents e7b6964 + 8726435 commit e687702
Show file tree
Hide file tree
Showing 11 changed files with 169 additions and 124 deletions.
6 changes: 3 additions & 3 deletions BasicRotations/Healer/AST_Default.cs
Original file line number Diff line number Diff line change
Expand Up @@ -237,8 +237,8 @@ protected override bool HealSingleGCD(out IAction? act)
{
act = null;
if (BubbleProtec && Player.HasStatus(true, StatusID.CollectiveUnconscious_848)) return false;
if (HasSwift && SwiftLogic && MergedStatus.HasFlag(AutoStatus.Raise)) 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
Expand All @@ -255,8 +255,8 @@ protected override bool HealAreaGCD(out IAction? act)
{
act = null;
if (BubbleProtec && Player.HasStatus(true, StatusID.CollectiveUnconscious_848)) return false;
if (HasSwift && SwiftLogic && MergedStatus.HasFlag(AutoStatus.Raise)) 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;
Expand All @@ -267,7 +267,7 @@ 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 (HasSwift && SwiftLogic && MergedStatus.HasFlag(AutoStatus.Raise)) return false;

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

Expand Down
12 changes: 4 additions & 8 deletions BasicRotations/Healer/SCH_Default.cs
Original file line number Diff line number Diff line change
Expand Up @@ -171,8 +171,7 @@ protected override bool AttackAbility(IAction nextGCD, out IAction? act)
protected override bool HealAreaGCD(out IAction? act)
{
act = null;

if (HasSwift && SwiftLogic && ResurrectionPvE.CanUse(out _)) return false;
if (HasSwift && SwiftLogic && MergedStatus.HasFlag(AutoStatus.Raise)) return false;

if (SuccorPvE.CanUse(out act)) return true;
if (ConcitationPvE.CanUse(out act, skipCastingCheck: true)) return true;
Expand All @@ -185,8 +184,7 @@ protected override bool HealAreaGCD(out IAction? act)
protected override bool HealSingleGCD(out IAction? act)
{
act = null;

if (HasSwift && SwiftLogic && ResurrectionPvE.CanUse(out _)) return false;
if (HasSwift && SwiftLogic && MergedStatus.HasFlag(AutoStatus.Raise)) return false;

if (AdloquiumPvE.CanUse(out act)) return true;
if (ManifestationPvE.CanUse(out act, skipCastingCheck: true)) return true;
Expand All @@ -199,8 +197,7 @@ protected override bool HealSingleGCD(out IAction? act)
protected override bool DefenseAreaGCD(out IAction? act)
{
act = null;

if (HasSwift && SwiftLogic && ResurrectionPvE.CanUse(out _)) return false;
if (HasSwift && SwiftLogic && MergedStatus.HasFlag(AutoStatus.Raise)) return false;

if (SuccorPvE.CanUse(out act)) return true;
if (ConcitationPvE.CanUse(out act, skipCastingCheck: true)) return true;
Expand All @@ -212,8 +209,7 @@ protected override bool DefenseAreaGCD(out IAction? act)
protected override bool GeneralGCD(out IAction? act)
{
act = null;

if (HasSwift && SwiftLogic && ResurrectionPvE.CanUse(out _)) return false;
if (HasSwift && SwiftLogic && MergedStatus.HasFlag(AutoStatus.Raise)) return false;

// Summon Eos
if (SummonEosPvE.CanUse(out act)) return true;
Expand Down
106 changes: 82 additions & 24 deletions BasicRotations/Healer/SGE_Default.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
using static FFXIVClientStructs.FFXIV.Client.UI.Misc.DataCenterHelper;

namespace RebornRotations.Healer;

[Rotation("Default", CombatType.PvE, GameVersion = "7.15")]
Expand All @@ -8,6 +6,9 @@ namespace RebornRotations.Healer;
public sealed class SGE_Default : SageRotation
{
#region Config Options
[RotationConfig(CombatType.PvE, Name = "Use new Eukrasian Logic")]
public bool NewELogic { 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;

Expand Down Expand Up @@ -80,22 +81,8 @@ public sealed class SGE_Default : SageRotation
#endregion

#region oGCD Logic
[RotationDesc(ActionID.PsychePvE)]
protected override bool AttackAbility(IAction nextGCD, out IAction? act)
{
if (PsychePvE.CanUse(out act)) return true;

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

protected override bool EmergencyAbility(IAction nextGCD, out IAction? act)
{
if ((_EukrasiaActionAim == EukrasianDosisIiiPvE || _EukrasiaActionAim == EukrasianDosisIiPvE || _EukrasiaActionAim == EukrasianDosisPvE)
&& (DyskrasiaPvE.CanUse(out _) || DyskrasiaIiPvE.CanUse(out _) || EukrasianDyskrasiaPvE.CanUse(out _)))
{
ClearEukrasia();
}

// If the last action performed matches any of a list of specific actions, it clears the Eukrasia aim.
// This serves as a reset/cleanup mechanism to ensure the decision logic starts fresh for the next cycle.
if (IsLastGCD(false, EukrasianPrognosisIiPvE, EukrasianPrognosisPvE,
Expand Down Expand Up @@ -127,6 +114,14 @@ protected override bool EmergencyAbility(IAction nextGCD, out IAction? act)
return base.EmergencyAbility(nextGCD, out act);
}

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

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

[RotationDesc(ActionID.PanhaimaPvE, ActionID.KeracholePvE, ActionID.HolosPvE)]
protected override bool DefenseAreaAbility(IAction nextGCD, out IAction? act)
{
Expand Down Expand Up @@ -340,22 +335,81 @@ private bool DoEukrasia(out IAction? act)
}
return false;
}

// Attempts to perform a Eukrasia action, based on the current game state and conditions.
private bool DoEukrasianPrognosis(out IAction? act)
{
act = null;

if (_EukrasiaActionAim != null && (_EukrasiaActionAim == EukrasianPrognosisPvE || _EukrasiaActionAim == EukrasianPrognosisIiPvE) && _EukrasiaActionAim.CanUse(out act))
{
if (EukrasiaPvE.CanUse(out act)) return true;

act = _EukrasiaActionAim;
return true;
}
return false;
}

// Attempts to perform a Eukrasia action, based on the current game state and conditions.
private bool DoEukrasianDiagnosis(out IAction? act)
{
act = null;

if (_EukrasiaActionAim != null && _EukrasiaActionAim == EukrasianDiagnosisPvE && _EukrasiaActionAim.CanUse(out act))
{
if (EukrasiaPvE.CanUse(out act)) return true;

act = _EukrasiaActionAim;
return true;
}
return false;
}

// Attempts to perform a Eukrasia action, based on the current game state and conditions.
private bool DoEukrasianDyskrasia(out IAction? act)
{
act = null;

if (_EukrasiaActionAim != null && _EukrasiaActionAim == EukrasianDyskrasiaPvE && _EukrasiaActionAim.CanUse(out act))
{
if (EukrasiaPvE.CanUse(out act)) return true;

act = _EukrasiaActionAim;
return true;
}
return false;
}

// Attempts to perform a Eukrasia action, based on the current game state and conditions.
private bool DoEukrasianDosis(out IAction? act)
{
act = null;

if (_EukrasiaActionAim != null && (_EukrasiaActionAim == EukrasianDosisPvE || _EukrasiaActionAim == EukrasianDosisIiPvE || _EukrasiaActionAim == EukrasianDosisIiiPvE) && _EukrasiaActionAim.CanUse(out act))
{
if (EukrasiaPvE.CanUse(out act)) return true;

act = _EukrasiaActionAim;
return true;
}
return false;
}
#endregion

#region GCD Logic
[RotationDesc(ActionID.PneumaPvE, ActionID.PrognosisPvE, ActionID.EukrasianPrognosisPvE, ActionID.EukrasianPrognosisIiPvE)]
protected override bool HealAreaGCD(out IAction? act)
{
act = null;

if (HasSwift && SwiftLogic && EgeiroPvE.CanUse(out _)) return false;
if (HasSwift && SwiftLogic && MergedStatus.HasFlag(AutoStatus.Raise)) return false;

if (PartyMembersAverHP < PneumaAOEPartyHeal || DyskrasiaPvE.CanUse(out _) && PartyMembers.GetJobCategory(JobRole.Tank).Any(t => t.GetHealthRatio() < PneumaAOETankHeal))
{
if (PneumaPvE.CanUse(out act)) return true;
}

if (!DoEukrasia(out _) && PrognosisPvE.CanUse(out act))
if (_EukrasiaActionAim != null && PrognosisPvE.CanUse(out act))
{
return true;
}
Expand All @@ -367,10 +421,9 @@ protected override bool HealAreaGCD(out IAction? act)
protected override bool HealSingleGCD(out IAction? act)
{
act = null;
if (HasSwift && SwiftLogic && MergedStatus.HasFlag(AutoStatus.Raise)) return false;

if (HasSwift && SwiftLogic && EgeiroPvE.CanUse(out _)) return false;

if (!DoEukrasia(out _) && DiagnosisPvE.CanUse(out act))
if (_EukrasiaActionAim != null && DiagnosisPvE.CanUse(out act))
{
return true;
}
Expand All @@ -380,7 +433,7 @@ protected override bool HealSingleGCD(out IAction? act)
protected override bool GeneralGCD(out IAction? act)
{
act = null;
if (HasSwift && SwiftLogic && EgeiroPvE.CanUse(out _)) return false;
if (HasSwift && SwiftLogic && MergedStatus.HasFlag(AutoStatus.Raise)) return false;

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

Expand All @@ -391,11 +444,16 @@ protected override bool GeneralGCD(out IAction? act)

if (IsMoving && ToxikonPvE.CanUse(out act)) return true;

if (NewELogic && DoEukrasianDyskrasia(out act)) return true;

if ((_EukrasiaActionAim != EukrasianDiagnosisPvE || _EukrasiaActionAim != EukrasianPrognosisPvE || _EukrasiaActionAim != EukrasianPrognosisIiPvE || _EukrasiaActionAim != EukrasianDyskrasiaPvE)
&& DyskrasiaPvE.CanUse(out act)) return true;

if (DoEukrasia(out act)) return true;
if (NewELogic && DoEukrasianPrognosis(out act)) return true;
if (NewELogic && DoEukrasianDiagnosis(out act)) return true;
if (!NewELogic && DoEukrasia(out act)) return true;

if (NewELogic && DoEukrasianDosis(out act)) return true;
if (DosisPvE.CanUse(out act)) return true;

if (!InCombat && !Player.HasStatus(true, StatusID.Eukrasia) && EukrasiaPvE.CanUse(out act)) return true;
Expand Down
9 changes: 3 additions & 6 deletions BasicRotations/Healer/WHM_Default.cs
Original file line number Diff line number Diff line change
Expand Up @@ -170,8 +170,7 @@ protected override bool AttackAbility(IAction nextGCD, out IAction? act)
protected override bool HealAreaGCD(out IAction? act)
{
act = null;

if (HasSwift && SwiftLogic && RaisePvE.CanUse(out _)) return false;
if (HasSwift && SwiftLogic && MergedStatus.HasFlag(AutoStatus.Raise)) return false;

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

Expand All @@ -190,8 +189,7 @@ protected override bool HealAreaGCD(out IAction? act)
protected override bool HealSingleGCD(out IAction? act)
{
act = null;

if (HasSwift && SwiftLogic && RaisePvE.CanUse(out _)) return false;
if (HasSwift && SwiftLogic && MergedStatus.HasFlag(AutoStatus.Raise)) return false;

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

Expand All @@ -206,9 +204,8 @@ protected override bool HealSingleGCD(out IAction? act)

protected override bool GeneralGCD(out IAction? act)
{

act = null;
if (HasSwift && SwiftLogic && RaisePvE.CanUse(out _)) return false;
if (HasSwift && SwiftLogic && MergedStatus.HasFlag(AutoStatus.Raise)) return false;

//if (NotInCombatDelay && RegenDefense.CanUse(out act)) return true;

Expand Down
4 changes: 2 additions & 2 deletions BasicRotations/Ranged/BRD_Default.cs
Original file line number Diff line number Diff line change
Expand Up @@ -243,8 +243,8 @@ protected override bool GeneralGCD(out IAction? act)
}
else
{
if (WindbitePvE.CanUse(out act)) return true;
if (VenomousBitePvE.CanUse(out act)) return true;
if (WindbitePvE.CanUse(out act, skipTTKCheck: true)) return true;
if (VenomousBitePvE.CanUse(out act, skipTTKCheck: true)) return true;
}


Expand Down
18 changes: 12 additions & 6 deletions RotationSolver.Basic/DataCenter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -804,10 +804,7 @@ internal static void AddDamageRec(float damageRatio)

public static bool IsCastingTankVfx()
{
// Create a copy of the VfxDataQueue to avoid modification during enumeration
var vfxDataQueueCopy = VfxDataQueue.ToList();

return IsCastingVfx(vfxDataQueueCopy, s =>
return IsCastingVfx(VfxDataQueue, s =>
{
if (!s.Path.StartsWith("vfx/lockon/eff/tank_lockon")) return false;
if (!Player.Available) return false;
Expand Down Expand Up @@ -867,8 +864,17 @@ public static bool IsHostileCastingBase(IBattleChara h, Func<Action, bool> check
// Check if h is null
if (h == null) return false;

// Check if the hostile character is casting
if (!h.IsCasting) return false;
try
{
// Check if the hostile character is casting
if (!h.IsCasting) return false;
}
catch (AccessViolationException ex)
{
// Log the exception and return false
Svc.Log.Error($"AccessViolationException: {ex.Message}");
return false;
}

// Check if the cast is interruptible
if (h.IsCastInterruptible) return false;
Expand Down
31 changes: 21 additions & 10 deletions RotationSolver.Basic/Helpers/ObjectHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@ internal static bool IsAttackable(this IBattleChara battleChara)
// Check if the target is invincible.
if (battleChara.IsJeunoBossImmune()) return false;

// Ensure StatusList is not null before accessing it
if (battleChara.StatusList == null) return false;

foreach (var status in battleChara.StatusList)
{
if (StatusHelper.IsInvincible(status) && (DataCenter.IsPvP && !Service.Config.IgnorePvPInvincibility || !DataCenter.IsPvP)) return false;
Expand Down Expand Up @@ -427,20 +430,28 @@ internal static bool IsTopPriorityHostile(this IGameObject obj)
/// </returns>
internal static bool CanInterrupt(this IGameObject o)
{
if (o is not IBattleChara b) return false;
try
{
if (o is not IBattleChara b) return false;

var baseCheck = b.IsCasting && b.IsCastInterruptible && b.TotalCastTime >= 2;
if (!baseCheck) return false;
if (!Service.Config.InterruptibleMoreCheck) return false;
var baseCheck = b.IsCasting && b.IsCastInterruptible && b.TotalCastTime >= 2;
if (!baseCheck) return false;
if (!Service.Config.InterruptibleMoreCheck) return false;

var id = b.CastActionId;
if (_effectRangeCheck.TryGetValue(id, out var check)) return check;
var id = b.CastActionId;
if (_effectRangeCheck.TryGetValue(id, out var check)) return check;

var act = Service.GetSheet<Lumina.Excel.Sheets.Action>().GetRow(b.CastActionId);
if (act.RowId == 0) return _effectRangeCheck[id] = false;
if (act.CastType == 3 || act.CastType == 4 || (act.EffectRange > 0 && act.EffectRange < 8)) return _effectRangeCheck[id] = false;
var act = Service.GetSheet<Lumina.Excel.Sheets.Action>().GetRow(b.CastActionId);
if (act.RowId == 0) return _effectRangeCheck[id] = false;
if (act.CastType == 3 || act.CastType == 4 || (act.EffectRange > 0 && act.EffectRange < 8)) return _effectRangeCheck[id] = false;

return _effectRangeCheck[id] = true;
return _effectRangeCheck[id] = true;
}
catch (AccessViolationException ex)
{
Svc.Log.Error($"Access violation in CanInterrupt: {ex}");
return false;
}
}

internal static bool IsDummy(this IBattleChara obj) => obj?.NameId == 541;
Expand Down
14 changes: 12 additions & 2 deletions RotationSolver.Basic/Rotations/CustomRotation_Invoke.cs
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,18 @@ private void UpdateDefenseActions(out IAction? act)
ActionDefenseSingleGCD = DefenseSingleGCD(out act) ? act : null;
IBaseAction.TargetOverride = null;

ActionDefenseAreaAbility = DefenseAreaAbility(AddlePvE, out act) ? act : null;
ActionDefenseSingleAbility = DefenseSingleAbility(AddlePvE, out act) ? act : null;
try
{
ActionDefenseAreaAbility = DefenseAreaAbility(AddlePvE, out act) ? act : null;
ActionDefenseSingleAbility = DefenseSingleAbility(AddlePvE, out act) ? act : null;
}
catch (MissingMethodException ex)
{
// Log the exception or handle it as needed
WarningHelper.AddSystemWarning($"Exception in UpdateDefenseActions method: {ex.Message}");
// Optionally, set actions to null in case of an exception
ActionDefenseAreaAbility = ActionDefenseSingleAbility = null;
}
}

private void UpdateDispelAndRaiseActions(JobRole role, out IAction? act)
Expand Down
Loading

0 comments on commit e687702

Please sign in to comment.