Skip to content

Commit

Permalink
Merge pull request #579 from FFXIV-CombatReborn/CODandRedtext
Browse files Browse the repository at this point in the history
Add new configs, refactor, and enhance documentation
  • Loading branch information
LTS-FFXIV authored Jan 17, 2025
2 parents ab4242c + 485a079 commit 89aa664
Show file tree
Hide file tree
Showing 23 changed files with 7,421 additions and 803 deletions.
12 changes: 12 additions & 0 deletions RotationSolver.Basic/Configuration/Configs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,18 @@ public const string
Filter = TargetConfig)]
private static readonly bool _filterOneHPInvincible = true;

[ConditionBool, UI("Ignore immune Ark Angels in Jenuo: The First Walk.",
Filter = TargetConfig)]
private static readonly bool _jeunoTarget = true;

[ConditionBool, UI("Ignore immune targets in Cloud of Darkenss Chaotic.",
Filter = TargetConfig)]
private static readonly bool _cODTarget = true;

[ConditionBool, UI("Ignore Strong of Shield target (Hansel and Gretel) in The Tower at Paradigm's Breach if you will hit shield.",
Filter = TargetConfig)]
private static readonly bool _strongOfSheildTarget = true;

[ConditionBool, UI("Teaching mode", Filter = UiInformation)]
private static readonly bool _teachingMode = false;

Expand Down
78 changes: 77 additions & 1 deletion RotationSolver.Basic/Helpers/ObjectHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,9 @@ internal static bool IsAttackable(this IBattleChara battleChara)
if (Service.Config.FilterOneHpInvincible && battleChara.CurrentHp <= 1) return false;

// Check if the target is invincible.
if (battleChara.IsJeunoBossImmune()) return false;
if (Service.Config.CodTarget && battleChara.IsCODBossImmune()) return false;
if (Service.Config.JeunoTarget && battleChara.IsJeunoBossImmune()) return false;
if (Service.Config.StrongOfSheildTarget && battleChara.IsHanselorGretelSheilded()) return false;

// Ensure StatusList is not null before accessing it
if (battleChara.StatusList == null) return false;
Expand Down Expand Up @@ -437,6 +439,12 @@ internal static bool CanInterrupt(this IGameObject o)
{
if (o is not IBattleChara b) return false;

// Ensure the IBattleChara object is valid before accessing its properties
unsafe
{
if (b.Struct() == null) return false;
}

var baseCheck = b.IsCasting && b.IsCastInterruptible && b.TotalCastTime >= 2;
if (!baseCheck) return false;
if (!Service.Config.InterruptibleMoreCheck) return false;
Expand Down Expand Up @@ -504,6 +512,74 @@ public static bool IsJeunoBossImmune(this IBattleChara obj)
return false;
}

/// <summary>
/// Is target COD Boss immune.
/// </summary>
/// <param name="obj">the object.</param>
/// <returns></returns>
public static bool IsCODBossImmune(this IBattleChara obj)
{
var player = Player.Object;

var StygianStatus = StatusID.UnnamedStatus_4388;
var CloudOfDarknessStatus = StatusID.VeilOfDarkness;
var AntiCloudOfDarknessStatus = StatusID.Rsv41771100S74Cfc3B0E74Cfc3B0;
var AntiStygianStatus = StatusID.Rsv41771100S74Cfc3B0E74Cfc3B0;

if (obj.IsEnemy())
{
if (obj.HasStatus(false, CloudOfDarknessStatus) &&
player.HasStatus(false, AntiCloudOfDarknessStatus))
{
if (Service.Config.InDebug)
{
Svc.Log.Information("IsCODBossImmune: VeilOfDarkness status found, CloudOfDarkness immune");
}
return true;
}

if (obj.HasStatus(false, StygianStatus) &&
player.HasStatus(false, AntiStygianStatus))
{
if (Service.Config.InDebug)
{
Svc.Log.Information("IsCODBossImmune: UnnamedStatus4388 status found, Stygian immune");
}
return true;
}
}

return false;
}

/// <summary>
/// Is target Jeuno Boss immune.
/// </summary>
/// <param name="obj">the object.</param>
/// <returns></returns>
public static bool IsHanselorGretelSheilded(this IBattleChara obj)
{
var player = Player.Object;

var strongOfShieldPositional = EnemyPositional.Front;
var strongOfShieldStatus = StatusID.StrongOfShield;

if (obj.IsEnemy())
{
if (obj.HasStatus(false, strongOfShieldStatus) &&
strongOfShieldPositional != obj.FindEnemyPositional())
{
if (Service.Config.InDebug)
{
Svc.Log.Information("IsHanselorGretelSheilded: StrongOfShield status found, ignoring status haver if player is out of position");
}
return true;
}
}

return false;
}

/// <summary>
/// Is target a boss depends on the ttk.
/// </summary>
Expand Down
21 changes: 19 additions & 2 deletions RotationSolver.GameData/Getters/Actions/ActionCategoryGetter.cs
Original file line number Diff line number Diff line change
@@ -1,17 +1,29 @@
using Lumina.Excel.GeneratedSheets;

namespace RotationSolver.GameData.Getters.Actions;

/// <summary>
/// Class for getting ActionCategory rows from the game data.
/// </summary>
internal class ActionCategoryGetter(Lumina.GameData gameData)
: ExcelRowGetter<ActionCategory>(gameData)
{
private readonly List<string> _addedNames = [];
private readonly HashSet<string> _addedNames = new();

/// <summary>
/// Called before creating the list of items. Clears the list of added names.
/// </summary>
protected override void BeforeCreating()
{
_addedNames.Clear();
base.BeforeCreating();
}

/// <summary>
/// Determines whether the specified ActionCategory item should be added to the list.
/// </summary>
/// <param name="item">The ActionCategory item to check.</param>
/// <returns>True if the item should be added; otherwise, false.</returns>
protected override bool AddToList(ActionCategory item)
{
var name = item.Name.RawString;
Expand All @@ -20,6 +32,11 @@ protected override bool AddToList(ActionCategory item)
return true;
}

/// <summary>
/// Converts the specified ActionCategory item to its code representation.
/// </summary>
/// <param name="item">The ActionCategory item to convert.</param>
/// <returns>The code representation of the item.</returns>
protected override string ToCode(ActionCategory item)
{
var name = item.Name.RawString.ToPascalCase();
Expand All @@ -40,4 +57,4 @@ protected override string ToCode(ActionCategory item)
{name} = {item.RowId},
""";
}
}
}
72 changes: 46 additions & 26 deletions RotationSolver.GameData/Getters/Actions/ActionGetterBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,63 +3,79 @@

namespace RotationSolver.GameData.Getters.Actions;

internal abstract class ActionGetterBase(Lumina.GameData gameData)
: ExcelRowGetter<Action>(gameData)
/// <summary>
/// Abstract base class for getting action rows from the Excel sheet.
/// </summary>
internal abstract class ActionGetterBase : ExcelRowGetter<Action>
{
public List<string> AddedNames { get; } = [];
private string[] _notCombatJobs = [];
/// <summary>
/// Initializes a new instance of the <see cref="ActionGetterBase"/> class.
/// </summary>
/// <param name="gameData">The game data.</param>
protected ActionGetterBase(Lumina.GameData gameData) : base(gameData) { }

/// <summary>
/// Gets the list of added names.
/// </summary>
public List<string> AddedNames { get; } = new();

private string[] _notCombatJobs = Array.Empty<string>();

/// <summary>
/// Called before creating the list of items.
/// </summary>
protected override void BeforeCreating()
{
AddedNames.Clear();
_notCombatJobs = [.. _gameData.GetExcelSheet<ClassJob>()!.Where(c =>
{
return c.ClassJobCategory.Row is 32 or 33;
}).Select(c => c.Abbreviation.RawString)];
_notCombatJobs = _gameData.GetExcelSheet<ClassJob>()!
.Where(c => c.ClassJobCategory.Row is 32 or 33)
.Select(c => c.Abbreviation.RawString)
.ToArray();
base.BeforeCreating();
}

/// <summary>
/// Determines whether the specified action should be added to the list.
/// </summary>
/// <param name="item">The action to check.</param>
/// <returns>True if the action should be added; otherwise, false.</returns>
protected override bool AddToList(Action item)
{
if (item.RowId is 3 or 120) return true; //Sprint and cure.
if (item.RowId is 3 or 120) return true; // Sprint and cure.
if (item.ClassJobCategory.Row == 0) return false;

var name = item.Name.RawString;
if (string.IsNullOrEmpty(name)) return false;
if (!name.All(char.IsAscii)) return false;
if (item.Icon is 0 or 405) return false;

if (item.ActionCategory.Row
is 6 or 7 // No DoL or DoH Action
or 8 //No Event.
or 12 // No Mount,
or > 14 // No item manipulation and other thing.
or 9 //No LB,
) return false;
if (item.ActionCategory.Row is 6 or 7 or 8 or 12 or > 14 or 9) return false;

//No crafting or gathering.
var category = item.ClassJobCategory.Value;
if (category == null) return false;

if (category.RowId == 1) return true;

if (_notCombatJobs.Any(name =>
{
return (bool?)category.GetType().GetRuntimeProperty(name)?.GetValue(category) ?? false;
}))
if (_notCombatJobs.Any(jobName => (bool?)category.GetType().GetRuntimeProperty(jobName)?.GetValue(category) ?? false))
{
return false;
}

return true;
}

/// <summary>
/// Gets the name of the specified action.
/// </summary>
/// <param name="item">The action.</param>
/// <returns>The name of the action.</returns>
protected string GetName(Action item)
{
var name = item.Name.RawString.ToPascalCase()
+ (item.IsPvP ? "PvP" : "PvE");
var name = item.Name.RawString.ToPascalCase() + (item.IsPvP ? "PvP" : "PvE");

if (AddedNames.Contains(name))
{
name += "_" + item.RowId.ToString();
name += "_" + item.RowId;
}
else
{
Expand All @@ -68,10 +84,14 @@ protected string GetName(Action item)
return name;
}

/// <summary>
/// Gets the description of the specified action.
/// </summary>
/// <param name="item">The action.</param>
/// <returns>The description of the action.</returns>
protected string GetDesc(Action item)
{
var desc = _gameData.GetExcelSheet<ActionTransient>()?.GetRow(item.RowId)?.Description.RawString ?? string.Empty;

return $"<para>{desc.Replace("\n", "</para>\n/// <para>")}</para>";
}
}
}
22 changes: 19 additions & 3 deletions RotationSolver.GameData/Getters/Actions/ActionIdGetter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,25 @@

namespace RotationSolver.GameData.Getters.Actions;

internal class ActionIdGetter(Lumina.GameData gameData)
: ActionGetterBase(gameData)
/// <summary>
/// Class for getting action IDs from the Excel sheet.
/// </summary>
internal class ActionIdGetter : ActionGetterBase
{
/// <summary>
/// Initializes a new instance of the <see cref="ActionIdGetter"/> class.
/// </summary>
/// <param name="gameData">The game data.</param>
public ActionIdGetter(Lumina.GameData gameData)
: base(gameData)
{
}

/// <summary>
/// Converts the specified action to its code representation.
/// </summary>
/// <param name="item">The action to convert.</param>
/// <returns>The code representation of the action.</returns>
protected override string ToCode(Action item)
{
var name = GetName(item);
Expand All @@ -17,4 +33,4 @@ protected override string ToCode(Action item)
{name} = {item.RowId},
""";
}
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,24 @@
namespace RotationSolver.GameData.Getters.Actions;
internal abstract class ActionRotationGetterBase(Lumina.GameData gameData)
: ActionGetterBase(gameData)

/// <summary>
/// Abstract base class for getting action rotation rows from the Excel sheet.
/// </summary>
internal abstract class ActionRotationGetterBase : ActionGetterBase
{
/// <summary>
/// Initializes a new instance of the <see cref="ActionRotationGetterBase"/> class.
/// </summary>
/// <param name="gameData">The game data.</param>
protected ActionRotationGetterBase(Lumina.GameData gameData)
: base(gameData)
{
}

/// <summary>
/// Converts the specified action item to its code representation.
/// </summary>
/// <param name="item">The action item to convert.</param>
/// <returns>The code representation of the action item.</returns>
protected override string ToCode(Lumina.Excel.GeneratedSheets.Action item)
{
var name = GetName(item);
Expand All @@ -10,5 +27,8 @@ protected override string ToCode(Lumina.Excel.GeneratedSheets.Action item)
return item.ToCode(name, descName, GetDesc(item), IsDutyAction);
}

/// <summary>
/// Gets a value indicating whether the action is a duty action.
/// </summary>
public abstract bool IsDutyAction { get; }
}
}
Loading

0 comments on commit 89aa664

Please sign in to comment.