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;
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;
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])
.FirstOrDefault();
}
- private unsafe int GetKillPriority(IGameObject gameObject)
+ public unsafe int GetKillPriority(IGameObject gameObject)
{
if (gameObject is IBattleNpc battleNpc)
{
// 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
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);
-using System.Diagnostics.CodeAnalysis;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Numerics;
using Dalamud.Game.ClientState.Conditions;
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)
_clientState = clientState;
_condition = condition;
_aetheryteData = aetheryteData;
+ _objectTable = objectTable;
+ _combatController = combatController;
_configuration = configuration;
Position = Vector2.Zero;
DrawCurrentQuest();
DrawHighlightedQuest();
+ DrawCombatTargets();
}
private void DrawCurrentQuest()
$"{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)