diff --git a/Resources/HostileCastingArea.json b/Resources/HostileCastingArea.json
index 58db71b49..fa68e2458 100644
--- a/Resources/HostileCastingArea.json
+++ b/Resources/HostileCastingArea.json
@@ -640,5 +640,12 @@
36610,
36612,
27145,
- 27181
+ 27181,
+ 24522,
+ 13066,
+ 13073,
+ 13085,
+ 13074,
+ 26050,
+ 26049
]
\ No newline at end of file
diff --git a/Resources/HostileCastingTank.json b/Resources/HostileCastingTank.json
index 015779de9..61557738c 100644
--- a/Resources/HostileCastingTank.json
+++ b/Resources/HostileCastingTank.json
@@ -22,5 +22,8 @@
33965,
35715,
37845,
- 29023
+ 29023,
+ 10542,
+ 26040,
+ 26041
]
\ No newline at end of file
diff --git a/RotationSolver.Basic/Configuration/Configs.cs b/RotationSolver.Basic/Configuration/Configs.cs
index 5b58c2a8e..c1c2be7bb 100644
--- a/RotationSolver.Basic/Configuration/Configs.cs
+++ b/RotationSolver.Basic/Configuration/Configs.cs
@@ -102,14 +102,6 @@ public const string
[UI("", Action = ActionID.ImprovisationPvE, Parent = nameof(PoslockCasting))]
public bool PosImprovisation { get; set; } = false;
- [ConditionBool, UI("Add enemy list to the hostile targets.",
- Filter = TargetConfig)]
- private static readonly bool _addEnemyListToHostile = true;
-
- [ConditionBool, UI("Only attack the targets in enemy list.",
- Parent = nameof(AddEnemyListToHostile))]
- private static readonly bool _onlyAttackInEnemyList = false;
-
[JobConfig, UI("Only used automatically if coded into the rotation", Filter = AutoActionUsage, PvPFilter = JobFilterType.NoJob)]
private readonly TinctureUseType _TinctureType = TinctureUseType.Nowhere;
diff --git a/RotationSolver.Basic/Data/TargetHostileType.cs b/RotationSolver.Basic/Data/TargetHostileType.cs
index c103a256c..48f85e1af 100644
--- a/RotationSolver.Basic/Data/TargetHostileType.cs
+++ b/RotationSolver.Basic/Data/TargetHostileType.cs
@@ -28,4 +28,16 @@ public enum TargetHostileType : byte
///
[Description("All targets when solo, or previously engaged.")]
AllTargetsWhenSolo,
+
+ ///
+ /// Targets in your enemy list.
+ ///
+ [Description("Only attack targets in your parties enemy list")]
+ TargetIsInEnemiesList,
+
+ ///
+ /// All targets when solo, or only attack targets in your parties enemy list.
+ ///
+ [Description("All targets when solo, or only attack targets in your parties enemy list")]
+ AllTargetsWhenSoloTargetIsInEnemiesList,
}
\ No newline at end of file
diff --git a/RotationSolver.Basic/DataCenter.cs b/RotationSolver.Basic/DataCenter.cs
index 8d7712f9c..d9b1b87d7 100644
--- a/RotationSolver.Basic/DataCenter.cs
+++ b/RotationSolver.Basic/DataCenter.cs
@@ -471,12 +471,12 @@ public static ulong[] TreasureCharas
public static bool HasHostilesInRange => NumberOfHostilesInRange > 0;
public static bool HasHostilesInMaxRange => NumberOfHostilesInMaxRange > 0;
- public static int NumberOfHostilesInRange => AllHostileTargets.Count(o => o.DistanceToPlayer() <= JobRange);
- public static int NumberOfHostilesInMaxRange => AllHostileTargets.Count(o => o.DistanceToPlayer() <= 25);
- public static int NumberOfAllHostilesInRange => AllHostileTargets.Count(o => o.DistanceToPlayer() <= JobRange);
- public static int NumberOfAllHostilesInMaxRange => AllHostileTargets.Count(o => o.DistanceToPlayer() <= 25);
+ public static int NumberOfHostilesInRange => AllHostileTargets.Count(o => o.DistanceToPlayer() < JobRange);
+ public static int NumberOfHostilesInMaxRange => AllHostileTargets.Count(o => o.DistanceToPlayer() < 25);
+ public static int NumberOfAllHostilesInRange => AllHostileTargets.Count(o => o.DistanceToPlayer() < JobRange);
+ public static int NumberOfAllHostilesInMaxRange => AllHostileTargets.Count(o => o.DistanceToPlayer() < 25);
- public static bool MobsTime => AllHostileTargets.Count(o => o.DistanceToPlayer() <= JobRange && o.CanSee())
+ public static bool MobsTime => AllHostileTargets.Count(o => o.DistanceToPlayer() < JobRange && o.CanSee())
>= Service.Config.AutoDefenseNumber;
public static bool AreHostilesCastingKnockback => AllHostileTargets.Any(IsHostileCastingKnockback);
diff --git a/RotationSolver.Basic/Helpers/ObjectHelper.cs b/RotationSolver.Basic/Helpers/ObjectHelper.cs
index 343b0bebb..0fa594a24 100644
--- a/RotationSolver.Basic/Helpers/ObjectHelper.cs
+++ b/RotationSolver.Basic/Helpers/ObjectHelper.cs
@@ -10,8 +10,11 @@
using FFXIVClientStructs.FFXIV.Client.Graphics;
using FFXIVClientStructs.FFXIV.Client.UI;
using FFXIVClientStructs.FFXIV.Common.Component.BGCollision;
+using FFXIVClientStructs.FFXIV.Component.GUI;
using RotationSolver.Basic.Configuration;
using System.Collections.Concurrent;
+using System.Runtime.InteropServices;
+using System.Text;
using System.Text.RegularExpressions;
namespace RotationSolver.Basic.Helpers;
@@ -95,53 +98,123 @@ internal static bool IsAttackable(this IBattleChara battleChara)
if (tarFateId != 0 && tarFateId != DataCenter.FateId) return false;
}
- if (Service.Config.AddEnemyListToHostile)
- {
- if (battleChara.IsInEnemiesList()) return true;
- // Only attack
- if (Service.Config.OnlyAttackInEnemyList) return false;
- }
-
- // Tar on me
- if (battleChara.TargetObject == Player.Object
- || battleChara.TargetObject?.OwnerId == Player.Object.GameObjectId) return true;
-
if (battleChara.IsOthersPlayers()) return false;
if (battleChara.IsTopPriorityHostile()) return true;
if (Service.CountDownTime > 0 || DataCenter.IsPvP) return true;
- return DataCenter.RightNowTargetToHostileType switch {
+ // Tar on me
+ if (battleChara.TargetObject == Player.Object
+ || battleChara.TargetObject?.OwnerId == Player.Object.GameObjectId) return true;
+
+ return DataCenter.RightNowTargetToHostileType switch
+ {
TargetHostileType.AllTargetsCanAttack => true,
TargetHostileType.TargetsHaveTarget => battleChara.TargetObject is IBattleChara,
TargetHostileType.AllTargetsWhenSolo => DataCenter.PartyMembers.Length < 2 || battleChara.TargetObject is IBattleChara,
TargetHostileType.AllTargetsWhenSoloInDuty => (DataCenter.PartyMembers.Length < 2 && Svc.Condition[ConditionFlag.BoundByDuty])
|| battleChara.TargetObject is IBattleChara,
+ TargetHostileType.TargetIsInEnemiesList => battleChara.TargetObject is IBattleChara target && target.IsInEnemiesList(),
+ TargetHostileType.AllTargetsWhenSoloTargetIsInEnemiesList => DataCenter.PartyMembers.Length < 2 || battleChara.TargetObject is IBattleChara target && target.IsInEnemiesList(),
_ => true,
};
}
- internal static unsafe bool IsInEnemiesList(this IBattleChara IBattleChara)
+ private static string RemoveControlCharacters(string input)
+ {
+ if (string.IsNullOrEmpty(input))
+ return input;
+
+ // Use a StringBuilder for efficient string manipulation
+ var output = new StringBuilder(input.Length);
+ foreach (char c in input)
+ {
+ // Exclude control characters and private use area characters
+ if (!char.IsControl(c) && (c < '\uE000' || c > '\uF8FF'))
+ {
+ output.Append(c);
+ }
+ }
+ return output.ToString();
+ }
+
+ //Below never returns true
+ internal static unsafe bool IsInEnemiesList(this IBattleChara battleChara)
{
var addons = Service.GetAddons();
- if (!addons.Any()) return false;
+ if (!addons.Any())
+ {
+ return false;
+ }
+
+ if (!addons.Any())
+ {
+ return false;
+ }
+
var addon = addons.FirstOrDefault();
- var enemy = (AddonEnemyList*)addon;
+ if (addon == IntPtr.Zero)
+ {
+ return false;
+ }
- var numArray = FFXIVClientStructs.FFXIV.Client.System.Framework.Framework.Instance()->GetUIModule()->GetRaptureAtkModule()->AtkModule.AtkArrayDataHolder.NumberArrays[19];
- if (numArray == null) return false;
+ var enemyList = (AddonEnemyList*)addon;
- const int baseIndex = 8;
- const int step = 6;
+ // Ensure that EnemyOneComponent is valid
+ if (enemyList->EnemyOneComponent == null)
+ {
+ return false;
+ }
+
+ // EnemyCount indicates how many enemies are in the list
+ var enemyCount = enemyList->EnemyCount;
- for (var i = 0; i < enemy->EnemyCount; i++)
+ for (int i = 0; i < enemyCount; i++)
{
- var id = (uint)numArray->IntArray[baseIndex + i * step];
+ // Access each enemy component
+ var enemyComponentPtr = enemyList->EnemyOneComponent + i;
+ if (enemyComponentPtr == null || *enemyComponentPtr == null)
+ {
+ continue;
+ }
+
+ var enemyComponent = *enemyComponentPtr;
+ var atkComponentBase = enemyComponent->AtkComponentBase;
- if (IBattleChara.GameObjectId == id) return true;
+ // Access the UldManager's NodeList
+ var uldManager = atkComponentBase.UldManager;
+
+ for (int j = 0; j < uldManager.NodeListCount; j++)
+ {
+ var node = uldManager.NodeList[j];
+ if (node == null)
+ continue;
+
+ if (node->Type == NodeType.Text)
+ {
+ var textNode = (AtkTextNode*)node;
+ if (textNode->NodeText.StringPtr == null)
+ continue;
+
+ // Read the enemy's name
+ var enemyNameRaw = Marshal.PtrToStringUTF8((IntPtr)textNode->NodeText.StringPtr);
+ if (string.IsNullOrEmpty(enemyNameRaw))
+ continue;
+
+ // Remove control characters from the enemy's name
+ var enemyName = RemoveControlCharacters(enemyNameRaw);
+
+ // Compare with battleChara's name
+ if (string.Equals(enemyName, battleChara.Name.TextValue, StringComparison.OrdinalIgnoreCase))
+ {
+ return true;
+ }
+ }
+ }
}
+
return false;
}
diff --git a/RotationSolver/RotationSolverPlugin.cs b/RotationSolver/RotationSolverPlugin.cs
index 2435cc26e..e4de69828 100644
--- a/RotationSolver/RotationSolverPlugin.cs
+++ b/RotationSolver/RotationSolverPlugin.cs
@@ -12,12 +12,10 @@
using RotationSolver.Commands;
using RotationSolver.Data;
using RotationSolver.Helpers;
-
using RotationSolver.UI;
using RotationSolver.UI.HighlightTeachingMode;
using RotationSolver.UI.HighlightTeachingMode.ElementSpecial;
using RotationSolver.Updaters;
-using static FFXIVClientStructs.FFXIV.Client.UI.Agent.AgentPartyMember.Delegates;
using WelcomeWindow = RotationSolver.UI.WelcomeWindow;
namespace RotationSolver;
@@ -249,7 +247,7 @@ internal static void UpdateDisplayWindow()
isValid &= !Service.Config.OnlyShowWithHostileOrInDuty
|| Svc.Condition[ConditionFlag.BoundByDuty]
- || DataCenter.AllHostileTargets.Any(o => o.DistanceToPlayer() <= 25);
+ || DataCenter.AllHostileTargets.Any(o => o.DistanceToPlayer() < 25);
_controlWindow!.IsOpen = isValid && Service.Config.ShowControlWindow;
_cooldownWindow!.IsOpen = isValid && Service.Config.ShowCooldownWindow;
diff --git a/RotationSolver/UI/RotationConfigWindow.cs b/RotationSolver/UI/RotationConfigWindow.cs
index 507c6ca7a..09c3b5d1f 100644
--- a/RotationSolver/UI/RotationConfigWindow.cs
+++ b/RotationSolver/UI/RotationConfigWindow.cs
@@ -2607,21 +2607,21 @@ private static void DrawDebug()
}
private static readonly CollapsingHeaderGroup _debugHeader = new(new()
-{
- {() => DataCenter.RightNowRotation != null ? "Rotation" : string.Empty, DrawDebugRotationStatus},
- {() => "Status", DrawStatus },
- {() => "Party", DrawParty },
- {() => "Target Data", DrawTargetData },
- {() => "Next Action", DrawNextAction },
- {() => "Last Action", DrawLastAction },
- {() => "Others", DrawOthers },
- {() => "Effect", () =>
- {
- ImGui.Text(Watcher.ShowStrSelf);
- ImGui.Separator();
- ImGui.Text(DataCenter.Role.ToString());
- } },
-});
+ {
+ {() => DataCenter.RightNowRotation != null ? "Rotation" : string.Empty, DrawDebugRotationStatus},
+ {() => "Status", DrawStatus },
+ {() => "Party", DrawParty },
+ {() => "Target Data", DrawTargetData },
+ {() => "Next Action", DrawNextAction },
+ {() => "Last Action", DrawLastAction },
+ {() => "Others", DrawOthers },
+ {() => "Effect", () =>
+ {
+ ImGui.Text(Watcher.ShowStrSelf);
+ ImGui.Separator();
+ ImGui.Text(DataCenter.Role.ToString());
+ } },
+ });
private static void DrawDebugRotationStatus()
{