Fix 'move to target' for objects too far away to be targeted
authorLiza Carvelli <liza@carvel.li>
Mon, 19 Aug 2024 09:26:55 +0000 (11:26 +0200)
committerLiza Carvelli <liza@carvel.li>
Mon, 19 Aug 2024 09:26:55 +0000 (11:26 +0200)
Questionable/Controller/CombatController.cs
Questionable/Controller/CombatModules/ICombatModule.cs
Questionable/Controller/CombatModules/RotationSolverRebornModule.cs
Questionable/Windows/DebugOverlay.cs

index 2e48057448de5086387247671a4fdf58710aaced..2a7c08d94d33360613a0f2567f2780f49bd59d5f 100644 (file)
@@ -21,6 +21,9 @@ namespace Questionable.Controller;
 
 internal sealed class CombatController : IDisposable
 {
+    private const float MaxTargetRange = 55f;
+    private const float MaxNameplateRange = 50f;
+
     private readonly List<ICombatModule> _combatModules;
     private readonly MovementController _movementController;
     private readonly ITargetManager _targetManager;
@@ -83,7 +86,7 @@ internal sealed class CombatController : IDisposable
         if (_currentFight == null)
             return EStatus.Complete;
 
-        if (_movementController.IsPathfinding || _movementController.IsPathRunning)
+        if (_movementController.IsPathfinding || _movementController.IsPathRunning || _movementController.MovementStartedAt > DateTime.Now.AddSeconds(-1))
             return EStatus.Moving;
 
         var target = _targetManager.Target;
@@ -100,29 +103,16 @@ internal sealed class CombatController : IDisposable
             else if (nextTarget != null)
             {
                 if (nextTargetPriority > currentTargetPriority)
-                {
-                    _logger.LogInformation("Changing next target to {TargetName} ({TargetId:X8})",
-                        nextTarget.Name.ToString(), nextTarget.GameObjectId);
-                    _targetManager.Target = nextTarget;
-                    _currentFight.Module.SetTarget(nextTarget);
-                }
+                    SetTarget(nextTarget);
             }
             else
-            {
-                _logger.LogInformation("Resetting next target");
-                _targetManager.Target = null;
-            }
+                SetTarget(null);
         }
         else
         {
             var nextTarget = FindNextTarget();
             if (nextTarget is { IsDead: false })
-            {
-                _logger.LogInformation("Setting next target to {TargetName} ({TargetId:X8})",
-                    nextTarget.Name.ToString(), nextTarget.GameObjectId);
-                _targetManager.Target = nextTarget;
-                _currentFight.Module.SetTarget(nextTarget);
-            }
+                SetTarget(nextTarget);
         }
 
         if (_condition[ConditionFlag.InCombat])
@@ -197,7 +187,7 @@ internal sealed class CombatController : IDisposable
             .FirstOrDefault();
     }
 
-    private unsafe int GetKillPriority(IGameObject gameObject)
+    public unsafe int GetKillPriority(IGameObject gameObject)
     {
         if (gameObject is IBattleNpc battleNpc)
         {
@@ -257,7 +247,7 @@ internal sealed class CombatController : IDisposable
 
                     // for enemies that are very far away, their nameplate doesn't render but they're in the object table
                     if (_currentFight?.Data.SpawnType == EEnemySpawnType.OverworldEnemies &&
-                        Vector3.Distance(_clientState.LocalPlayer?.Position ?? Vector3.Zero, battleNpc.Position) > 45)
+                        Vector3.Distance(_clientState.LocalPlayer?.Position ?? Vector3.Zero, battleNpc.Position) > MaxNameplateRange)
                         return 25;
                 }
                 else
@@ -288,6 +278,29 @@ internal sealed class CombatController : IDisposable
             return 0;
     }
 
+    private void SetTarget(IGameObject? target)
+    {
+        if (target == null)
+        {
+            if (_targetManager.Target != null)
+            {
+                _logger.LogInformation("Clearing target");
+                _targetManager.Target = null;
+            }
+        }
+        else if (Vector3.Distance(_clientState.LocalPlayer!.Position, target.Position) > MaxTargetRange)
+        {
+            _logger.LogInformation("Moving to target, distance: {Distance:N2}", Vector3.Distance(_clientState.LocalPlayer!.Position, target.Position));
+            _currentFight!.Module.MoveToTarget(target);
+        }
+        else
+        {
+            _logger.LogInformation("Setting target to {TargetName} ({TargetId:X8})", target.Name.ToString(), target.GameObjectId);
+            _targetManager.Target = target;
+            _currentFight!.Module.MoveToTarget(target);
+        }
+    }
+
     public void Stop(string label)
     {
         using var scope = _logger.BeginScope(label);
index 2553310b57a94b793b29d2e63378f6e1e8221fee..1aec57cc8e10619a04a7b7bbb764def32bdd92c0 100644 (file)
@@ -12,5 +12,5 @@ internal interface ICombatModule
 
     void Update(IGameObject nextTarget);
 
-    void SetTarget(IGameObject nextTarget);
+    void MoveToTarget(IGameObject nextTarget);
 }
index f09ac6eee1789e7b4dccafd7178a4654d4afcb21..0af5fda4bf0b54cc679aad44ec8c3b681c7238be 100644 (file)
@@ -77,7 +77,7 @@ internal sealed class RotationSolverRebornModule : ICombatModule, IDisposable
         }
     }
 
-    public void SetTarget(IGameObject gameObject)
+    public void MoveToTarget(IGameObject gameObject)
     {
         var player = _clientState.LocalPlayer;
         if (player == null)
@@ -114,7 +114,7 @@ internal sealed class RotationSolverRebornModule : ICombatModule, IDisposable
 
         if (DateTime.Now > _lastDistanceCheck.AddSeconds(10))
         {
-            SetTarget(gameObject);
+            MoveToTarget(gameObject);
             _lastDistanceCheck = DateTime.Now;
         }
     }
index ffefba17a25019d78a80cfe6984897d668f6a18b..e629fe0102671f50c9065ca2301cda10c6bec66e 100644 (file)
@@ -1,4 +1,5 @@
-using System.Diagnostics.CodeAnalysis;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
 using System.Globalization;
 using System.Numerics;
 using Dalamud.Game.ClientState.Conditions;
@@ -19,10 +20,12 @@ internal sealed class DebugOverlay : Window
     private readonly IClientState _clientState;
     private readonly ICondition _condition;
     private readonly AetheryteData _aetheryteData;
+    private readonly IObjectTable _objectTable;
+    private readonly CombatController _combatController;
     private readonly Configuration _configuration;
 
     public DebugOverlay(QuestController questController, QuestRegistry questRegistry, IGameGui gameGui,
-        IClientState clientState, ICondition condition, AetheryteData aetheryteData, Configuration configuration)
+        IClientState clientState, ICondition condition, AetheryteData aetheryteData, IObjectTable objectTable, CombatController combatController, Configuration configuration)
         : base("Questionable Debug Overlay###QuestionableDebugOverlay",
             ImGuiWindowFlags.NoTitleBar | ImGuiWindowFlags.NoScrollbar | ImGuiWindowFlags.NoBackground |
             ImGuiWindowFlags.NoInputs | ImGuiWindowFlags.NoSavedSettings, true)
@@ -33,6 +36,8 @@ internal sealed class DebugOverlay : Window
         _clientState = clientState;
         _condition = condition;
         _aetheryteData = aetheryteData;
+        _objectTable = objectTable;
+        _combatController = combatController;
         _configuration = configuration;
 
         Position = Vector2.Zero;
@@ -61,6 +66,7 @@ internal sealed class DebugOverlay : Window
 
         DrawCurrentQuest();
         DrawHighlightedQuest();
+        DrawCombatTargets();
     }
 
     private void DrawCurrentQuest()
@@ -119,6 +125,19 @@ internal sealed class DebugOverlay : Window
             $"{counter}: {step.InteractionType}\n{position.ToString("G", CultureInfo.InvariantCulture)} [{(position - _clientState.LocalPlayer!.Position).Length():N2}]\n{step.Comment}");
     }
 
+    [Conditional("false")]
+    private void DrawCombatTargets()
+    {
+        foreach (var x in _objectTable)
+        {
+            bool visible = _gameGui.WorldToScreen(x.Position, out Vector2 screenPos);
+            if (!visible)
+                continue;
+
+            ImGui.GetWindowDrawList() .AddText(screenPos + new Vector2(10, -8), 0xFFFFFFFF, $"{x.Name}/{x.GameObjectId:X}, {_combatController.GetKillPriority(x)}, {Vector3.Distance(x.Position, _clientState.LocalPlayer!.Position):N2}, {x.IsTargetable}");
+        }
+    }
+
     private bool TryGetPosition(QuestStep step, [NotNullWhen(true)] out Vector3? position)
     {
         if (step.Position != null)