using Dalamud.Plugin.Services;
using FFXIVClientStructs.FFXIV.Client.Game;
using FFXIVClientStructs.FFXIV.Client.Game.Object;
+using FFXIVClientStructs.FFXIV.Common.Math;
using Microsoft.Extensions.Logging;
using Questionable.Controller.CombatModules;
using Questionable.Controller.Utils;
var target = _targetManager.Target;
if (target != null)
{
- if (IsEnemyToKill(target))
+ if (GetKillPriority(target) is >= 50)
return true;
var nextTarget = FindNextTarget();
- if (nextTarget != null)
+ if (nextTarget != null && nextTarget.Equals(target))
+ {
+ _currentFight.Module.Update(target);
+ }
+ else if (nextTarget != null)
{
_logger.LogInformation("Changing next target to {TargetName} ({TargetId:X8})",
nextTarget.Name.ToString(), nextTarget.GameObjectId);
}
}
- return _objectTable.Where(IsEnemyToKill).MinBy(x => (x.Position - _clientState.LocalPlayer!.Position).Length());
+ return _objectTable.Select(x => (GameObject: x, Priority: GetKillPriority(x)))
+ .Where(x => x.Priority != null)
+ .OrderByDescending(x => x.Priority!.Value)
+ .ThenByDescending(x => Vector3.Distance(x.GameObject.Position, _clientState.LocalPlayer!.Position))
+ .Select(x => x.GameObject)
+ .FirstOrDefault();
}
- private unsafe bool IsEnemyToKill(IGameObject gameObject)
+ private unsafe int? GetKillPriority(IGameObject gameObject)
{
if (gameObject is IBattleNpc battleNpc)
{
_currentFight.Data.ComplexCombatDatas.Count == 0)
{
if (battleNpc.IsDead)
- return false;
+ return null;
}
if (!battleNpc.IsTargetable)
- return false;
-
- if (battleNpc.TargetObjectId == _clientState.LocalPlayer?.GameObjectId)
- return true;
+ return null;
if (_currentFight != null)
{
continue;
if (complexCombatData[i].DataId == battleNpc.DataId)
- return true;
+ return 100;
}
}
else
{
if (_currentFight.Data.KillEnemyDataIds.Contains(battleNpc.DataId))
- return true;
+ return 90;
}
}
+ // enemies that we have aggro on
if (battleNpc.BattleNpcKind is BattleNpcSubKind.BattleNpcPart or BattleNpcSubKind.Enemy)
{
var gameObjectStruct = (GameObject*)gameObject.Address;
if (gameObjectStruct->NamePlateIconId is 60093 or 60732) // npc that starts a fate or does turn-ins
- return false;
+ return null;
var enemyData = _currentFight?.Data.ComplexCombatDatas.FirstOrDefault(x => x.DataId == battleNpc.DataId);
if (enemyData is { IgnoreQuestMarker: true })
- return battleNpc.StatusFlags.HasFlag(StatusFlags.InCombat);
+ return battleNpc.StatusFlags.HasFlag(StatusFlags.InCombat) ? 20 : null;
else
- return gameObjectStruct->NamePlateIconId != 0;
+ return gameObjectStruct->NamePlateIconId != 0 ? 30 : null;
}
- else
- return false;
+
+ // stuff trying to kill us
+ if (battleNpc.TargetObjectId == _clientState.LocalPlayer?.GameObjectId)
+ return 0;
+
}
- else
- return false;
+
+ return null;
}
public void Stop()
bool Stop();
+ void Update(IGameObject nextTarget);
+
void SetTarget(IGameObject nextTarget);
}
private readonly ICallGateSubscriber<string, object> _test;
private readonly ICallGateSubscriber<StateCommandType, object> _changeOperationMode;
+ private DateTime _lastDistanceCheck = DateTime.MinValue;
+
public RotationSolverRebornModule(ILogger<RotationSolverRebornModule> logger, MovementController movementController,
IClientState clientState, IDalamudPluginInterface pluginInterface)
{
try
{
_changeOperationMode.InvokeAction(StateCommandType.Manual);
+ _lastDistanceCheck = DateTime.Now;
return true;
}
catch (IpcError e)
float hitboxOffset = player.HitboxRadius + gameObject.HitboxRadius;
float actualDistance = Vector3.Distance(player.Position, gameObject.Position);
- float maxDistance = player.ClassJob.GameData?.Role is 3 or 4 ? 25f : 3f;
- if (actualDistance - hitboxOffset > maxDistance)
- _movementController.NavigateTo(EMovementType.Combat, null, [gameObject.Position], false, false,
- maxDistance + hitboxOffset - 0.25f, true);
+ float maxDistance = player.ClassJob.GameData?.Role is 3 or 4 ? 20f : 3f;
+ if (actualDistance - hitboxOffset >= maxDistance)
+ {
+ if (actualDistance - hitboxOffset <= 5)
+ {
+ _logger.LogInformation("Moving to {TargetName} ({DataId}) to attack", gameObject.Name,
+ gameObject.DataId);
+ _movementController.NavigateTo(EMovementType.Combat, null, [gameObject.Position], false, false,
+ maxDistance + hitboxOffset - 0.25f, true);
+ }
+ else
+ {
+ _logger.LogInformation("Moving to {TargetName} ({DataId}) to attack (with navmesh)", gameObject.Name,
+ gameObject.DataId);
+ _movementController.NavigateTo(EMovementType.Combat, null, gameObject.Position, false, false,
+ maxDistance + hitboxOffset - 0.25f, true);
+ }
+ }
+
+ _lastDistanceCheck = DateTime.Now;
+ }
+
+ public void Update(IGameObject gameObject)
+ {
+ if (_movementController.IsPathfinding || _movementController.IsPathRunning)
+ return;
+
+ if (DateTime.Now > _lastDistanceCheck.AddSeconds(10))
+ {
+ SetTarget(gameObject);
+ _lastDistanceCheck = DateTime.Now;
+ }
}
public void Dispose() => Stop();
using System;
using System.Collections.Generic;
using System.Linq;
+using Dalamud.Game.ClientState.Conditions;
using Dalamud.Game.ClientState.Keys;
using Dalamud.Plugin.Services;
using Microsoft.Extensions.Logging;
private readonly QuestRegistry _questRegistry;
private readonly IKeyState _keyState;
private readonly IChatGui _chatGui;
+ private readonly ICondition _condition;
private readonly Configuration _configuration;
private readonly YesAlreadyIpc _yesAlreadyIpc;
private readonly IReadOnlyList<ITaskFactory> _taskFactories;
QuestRegistry questRegistry,
IKeyState keyState,
IChatGui chatGui,
+ ICondition condition,
Configuration configuration,
YesAlreadyIpc yesAlreadyIpc,
IEnumerable<ITaskFactory> taskFactories)
_questRegistry = questRegistry;
_keyState = keyState;
_chatGui = chatGui;
+ _condition = condition;
_configuration = configuration;
_yesAlreadyIpc = yesAlreadyIpc;
_taskFactories = taskFactories.ToList().AsReadOnly();
{
UpdateCurrentQuest();
- if (_keyState[VirtualKey.ESCAPE])
+ if (!_clientState.IsLoggedIn || _condition[ConditionFlag.Unconscious])
+ {
+ if (_currentTask != null || _taskQueue.Count > 0)
+ {
+ Stop("HP = 0");
+ _movementController.Stop();
+ _combatController.Stop();
+ }
+ } else if (_keyState[VirtualKey.ESCAPE])
{
if (_currentTask != null || _taskQueue.Count > 0)
{