diff --git a/Questionable/Controller/CombatController.cs b/Questionable/Controller/CombatController.cs index 2e4805744..2a7c08d94 100644 --- a/Questionable/Controller/CombatController.cs +++ b/Questionable/Controller/CombatController.cs @@ -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 _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); diff --git a/Questionable/Controller/CombatModules/ICombatModule.cs b/Questionable/Controller/CombatModules/ICombatModule.cs index 2553310b5..1aec57cc8 100644 --- a/Questionable/Controller/CombatModules/ICombatModule.cs +++ b/Questionable/Controller/CombatModules/ICombatModule.cs @@ -12,5 +12,5 @@ internal interface ICombatModule void Update(IGameObject nextTarget); - void SetTarget(IGameObject nextTarget); + void MoveToTarget(IGameObject nextTarget); } diff --git a/Questionable/Controller/CombatModules/RotationSolverRebornModule.cs b/Questionable/Controller/CombatModules/RotationSolverRebornModule.cs index f09ac6eee..0af5fda4b 100644 --- a/Questionable/Controller/CombatModules/RotationSolverRebornModule.cs +++ b/Questionable/Controller/CombatModules/RotationSolverRebornModule.cs @@ -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; } } diff --git a/Questionable/Windows/DebugOverlay.cs b/Questionable/Windows/DebugOverlay.cs index ffefba17a..e629fe010 100644 --- a/Questionable/Windows/DebugOverlay.cs +++ b/Questionable/Windows/DebugOverlay.cs @@ -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)