Give enemies kill priorities (defined inquest → aggro'd), occasionally check if we're stll in range, reduce cast distance

pull/14/head
Liza 2024-07-25 17:36:51 +02:00
parent 89b3110a28
commit 33f3147e42
Signed by: liza
GPG Key ID: 7199F8D727D55F67
4 changed files with 79 additions and 23 deletions

View File

@ -9,6 +9,7 @@ using Dalamud.Game.ClientState.Objects.Types;
using Dalamud.Plugin.Services; using Dalamud.Plugin.Services;
using FFXIVClientStructs.FFXIV.Client.Game; using FFXIVClientStructs.FFXIV.Client.Game;
using FFXIVClientStructs.FFXIV.Client.Game.Object; using FFXIVClientStructs.FFXIV.Client.Game.Object;
using FFXIVClientStructs.FFXIV.Common.Math;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Questionable.Controller.CombatModules; using Questionable.Controller.CombatModules;
using Questionable.Controller.Utils; using Questionable.Controller.Utils;
@ -75,11 +76,15 @@ internal sealed class CombatController : IDisposable
var target = _targetManager.Target; var target = _targetManager.Target;
if (target != null) if (target != null)
{ {
if (IsEnemyToKill(target)) if (GetKillPriority(target) is >= 50)
return true; return true;
var nextTarget = FindNextTarget(); 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})", _logger.LogInformation("Changing next target to {TargetName} ({TargetId:X8})",
nextTarget.Name.ToString(), nextTarget.GameObjectId); nextTarget.Name.ToString(), nextTarget.GameObjectId);
@ -154,10 +159,15 @@ internal sealed class CombatController : IDisposable
} }
} }
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) if (gameObject is IBattleNpc battleNpc)
{ {
@ -167,14 +177,11 @@ internal sealed class CombatController : IDisposable
_currentFight.Data.ComplexCombatDatas.Count == 0) _currentFight.Data.ComplexCombatDatas.Count == 0)
{ {
if (battleNpc.IsDead) if (battleNpc.IsDead)
return false; return null;
} }
if (!battleNpc.IsTargetable) if (!battleNpc.IsTargetable)
return false; return null;
if (battleNpc.TargetObjectId == _clientState.LocalPlayer?.GameObjectId)
return true;
if (_currentFight != null) if (_currentFight != null)
{ {
@ -187,33 +194,37 @@ internal sealed class CombatController : IDisposable
continue; continue;
if (complexCombatData[i].DataId == battleNpc.DataId) if (complexCombatData[i].DataId == battleNpc.DataId)
return true; return 100;
} }
} }
else else
{ {
if (_currentFight.Data.KillEnemyDataIds.Contains(battleNpc.DataId)) 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) if (battleNpc.BattleNpcKind is BattleNpcSubKind.BattleNpcPart or BattleNpcSubKind.Enemy)
{ {
var gameObjectStruct = (GameObject*)gameObject.Address; var gameObjectStruct = (GameObject*)gameObject.Address;
if (gameObjectStruct->NamePlateIconId is 60093 or 60732) // npc that starts a fate or does turn-ins 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); var enemyData = _currentFight?.Data.ComplexCombatDatas.FirstOrDefault(x => x.DataId == battleNpc.DataId);
if (enemyData is { IgnoreQuestMarker: true }) if (enemyData is { IgnoreQuestMarker: true })
return battleNpc.StatusFlags.HasFlag(StatusFlags.InCombat); return battleNpc.StatusFlags.HasFlag(StatusFlags.InCombat) ? 20 : null;
else 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() public void Stop()

View File

@ -10,5 +10,7 @@ internal interface ICombatModule
bool Stop(); bool Stop();
void Update(IGameObject nextTarget);
void SetTarget(IGameObject nextTarget); void SetTarget(IGameObject nextTarget);
} }

View File

@ -19,6 +19,8 @@ internal sealed class RotationSolverRebornModule : ICombatModule, IDisposable
private readonly ICallGateSubscriber<string, object> _test; private readonly ICallGateSubscriber<string, object> _test;
private readonly ICallGateSubscriber<StateCommandType, object> _changeOperationMode; private readonly ICallGateSubscriber<StateCommandType, object> _changeOperationMode;
private DateTime _lastDistanceCheck = DateTime.MinValue;
public RotationSolverRebornModule(ILogger<RotationSolverRebornModule> logger, MovementController movementController, public RotationSolverRebornModule(ILogger<RotationSolverRebornModule> logger, MovementController movementController,
IClientState clientState, IDalamudPluginInterface pluginInterface) IClientState clientState, IDalamudPluginInterface pluginInterface)
{ {
@ -51,6 +53,7 @@ internal sealed class RotationSolverRebornModule : ICombatModule, IDisposable
try try
{ {
_changeOperationMode.InvokeAction(StateCommandType.Manual); _changeOperationMode.InvokeAction(StateCommandType.Manual);
_lastDistanceCheck = DateTime.Now;
return true; return true;
} }
catch (IpcError e) catch (IpcError e)
@ -82,11 +85,39 @@ internal sealed class RotationSolverRebornModule : ICombatModule, IDisposable
float hitboxOffset = player.HitboxRadius + gameObject.HitboxRadius; float hitboxOffset = player.HitboxRadius + gameObject.HitboxRadius;
float actualDistance = Vector3.Distance(player.Position, gameObject.Position); float actualDistance = Vector3.Distance(player.Position, gameObject.Position);
float maxDistance = player.ClassJob.GameData?.Role is 3 or 4 ? 25f : 3f; float maxDistance = player.ClassJob.GameData?.Role is 3 or 4 ? 20f : 3f;
if (actualDistance - hitboxOffset > maxDistance) 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, _movementController.NavigateTo(EMovementType.Combat, null, [gameObject.Position], false, false,
maxDistance + hitboxOffset - 0.25f, true); 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(); public void Dispose() => Stop();

View File

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Dalamud.Game.ClientState.Conditions;
using Dalamud.Game.ClientState.Keys; using Dalamud.Game.ClientState.Keys;
using Dalamud.Plugin.Services; using Dalamud.Plugin.Services;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
@ -22,6 +23,7 @@ internal sealed class QuestController
private readonly QuestRegistry _questRegistry; private readonly QuestRegistry _questRegistry;
private readonly IKeyState _keyState; private readonly IKeyState _keyState;
private readonly IChatGui _chatGui; private readonly IChatGui _chatGui;
private readonly ICondition _condition;
private readonly Configuration _configuration; private readonly Configuration _configuration;
private readonly YesAlreadyIpc _yesAlreadyIpc; private readonly YesAlreadyIpc _yesAlreadyIpc;
private readonly IReadOnlyList<ITaskFactory> _taskFactories; private readonly IReadOnlyList<ITaskFactory> _taskFactories;
@ -44,6 +46,7 @@ internal sealed class QuestController
QuestRegistry questRegistry, QuestRegistry questRegistry,
IKeyState keyState, IKeyState keyState,
IChatGui chatGui, IChatGui chatGui,
ICondition condition,
Configuration configuration, Configuration configuration,
YesAlreadyIpc yesAlreadyIpc, YesAlreadyIpc yesAlreadyIpc,
IEnumerable<ITaskFactory> taskFactories) IEnumerable<ITaskFactory> taskFactories)
@ -56,6 +59,7 @@ internal sealed class QuestController
_questRegistry = questRegistry; _questRegistry = questRegistry;
_keyState = keyState; _keyState = keyState;
_chatGui = chatGui; _chatGui = chatGui;
_condition = condition;
_configuration = configuration; _configuration = configuration;
_yesAlreadyIpc = yesAlreadyIpc; _yesAlreadyIpc = yesAlreadyIpc;
_taskFactories = taskFactories.ToList().AsReadOnly(); _taskFactories = taskFactories.ToList().AsReadOnly();
@ -104,7 +108,15 @@ internal sealed class QuestController
{ {
UpdateCurrentQuest(); 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) if (_currentTask != null || _taskQueue.Count > 0)
{ {