forked from liza/Questionable
Add Wrath Combo as combat module
This commit is contained in:
parent
aa70f4c55a
commit
1578c5d197
@ -7,7 +7,7 @@ namespace Questionable;
|
|||||||
|
|
||||||
internal sealed class Configuration : IPluginConfiguration
|
internal sealed class Configuration : IPluginConfiguration
|
||||||
{
|
{
|
||||||
public const int PluginSetupVersion = 3;
|
public const int PluginSetupVersion = 4;
|
||||||
|
|
||||||
public int Version { get; set; } = 1;
|
public int Version { get; set; } = 1;
|
||||||
public int PluginSetupCompleteVersion { get; set; }
|
public int PluginSetupCompleteVersion { get; set; }
|
||||||
@ -23,7 +23,7 @@ internal sealed class Configuration : IPluginConfiguration
|
|||||||
|
|
||||||
internal sealed class GeneralConfiguration
|
internal sealed class GeneralConfiguration
|
||||||
{
|
{
|
||||||
public ECombatModule CombatModule { get; set; } = ECombatModule.BossMod;
|
public ECombatModule CombatModule { get; set; } = ECombatModule.None;
|
||||||
public uint MountId { get; set; } = 71;
|
public uint MountId { get; set; } = 71;
|
||||||
public GrandCompany GrandCompany { get; set; } = GrandCompany.None;
|
public GrandCompany GrandCompany { get; set; } = GrandCompany.None;
|
||||||
public bool HideInAllInstances { get; set; } = true;
|
public bool HideInAllInstances { get; set; } = true;
|
||||||
@ -51,6 +51,7 @@ internal sealed class Configuration : IPluginConfiguration
|
|||||||
{
|
{
|
||||||
None,
|
None,
|
||||||
BossMod,
|
BossMod,
|
||||||
|
WrathCombo,
|
||||||
RotationSolverReborn,
|
RotationSolverReborn,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,8 +13,10 @@ using FFXIVClientStructs.FFXIV.Client.Game.UI;
|
|||||||
using FFXIVClientStructs.FFXIV.Common.Math;
|
using FFXIVClientStructs.FFXIV.Common.Math;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Questionable.Controller.CombatModules;
|
using Questionable.Controller.CombatModules;
|
||||||
|
using Questionable.Controller.Steps;
|
||||||
using Questionable.Controller.Utils;
|
using Questionable.Controller.Utils;
|
||||||
using Questionable.Functions;
|
using Questionable.Functions;
|
||||||
|
using Questionable.Model;
|
||||||
using Questionable.Model.Questing;
|
using Questionable.Model.Questing;
|
||||||
|
|
||||||
namespace Questionable.Controller;
|
namespace Questionable.Controller;
|
||||||
@ -75,6 +77,7 @@ internal sealed class CombatController : IDisposable
|
|||||||
{
|
{
|
||||||
Module = combatModule,
|
Module = combatModule,
|
||||||
Data = combatData,
|
Data = combatData,
|
||||||
|
LastDistanceCheck = DateTime.Now,
|
||||||
};
|
};
|
||||||
_wasInCombat = combatData.SpawnType is EEnemySpawnType.QuestInterruption or EEnemySpawnType.FinishCombatIfAny;
|
_wasInCombat = combatData.SpawnType is EEnemySpawnType.QuestInterruption or EEnemySpawnType.FinishCombatIfAny;
|
||||||
return true;
|
return true;
|
||||||
@ -128,9 +131,20 @@ internal sealed class CombatController : IDisposable
|
|||||||
int nextTargetPriority = GetKillPriority(target);
|
int nextTargetPriority = GetKillPriority(target);
|
||||||
|
|
||||||
if (nextTarget != null && nextTarget.Equals(target))
|
if (nextTarget != null && nextTarget.Equals(target))
|
||||||
|
{
|
||||||
|
if (!IsMovingOrShouldMove(target))
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
_currentFight.Module.Update(target);
|
_currentFight.Module.Update(target);
|
||||||
}
|
}
|
||||||
|
catch (TaskException e)
|
||||||
|
{
|
||||||
|
_logger.LogWarning(e, "Combat was interrupted, stopping: {Exception}", e.Message);
|
||||||
|
SetTarget(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
else if (nextTarget != null)
|
else if (nextTarget != null)
|
||||||
{
|
{
|
||||||
if (nextTargetPriority > currentTargetPriority)
|
if (nextTargetPriority > currentTargetPriority)
|
||||||
@ -323,14 +337,57 @@ internal sealed class CombatController : IDisposable
|
|||||||
{
|
{
|
||||||
_logger.LogInformation("Moving to target, distance: {Distance:N2}",
|
_logger.LogInformation("Moving to target, distance: {Distance:N2}",
|
||||||
Vector3.Distance(_clientState.LocalPlayer!.Position, target.Position));
|
Vector3.Distance(_clientState.LocalPlayer!.Position, target.Position));
|
||||||
_currentFight!.Module.MoveToTarget(target);
|
MoveToTarget(target);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_logger.LogInformation("Setting target to {TargetName} ({TargetId:X8})", target.Name.ToString(),
|
_logger.LogInformation("Setting target to {TargetName} ({TargetId:X8})", target.Name.ToString(),
|
||||||
target.GameObjectId);
|
target.GameObjectId);
|
||||||
_targetManager.Target = target;
|
_targetManager.Target = target;
|
||||||
_currentFight!.Module.MoveToTarget(target);
|
MoveToTarget(target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsMovingOrShouldMove(IGameObject gameObject)
|
||||||
|
{
|
||||||
|
if (_movementController.IsPathfinding || _movementController.IsPathRunning)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (DateTime.Now > _currentFight!.LastDistanceCheck.AddSeconds(10))
|
||||||
|
{
|
||||||
|
MoveToTarget(gameObject);
|
||||||
|
_currentFight!.LastDistanceCheck = DateTime.Now;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void MoveToTarget(IGameObject gameObject)
|
||||||
|
{
|
||||||
|
var player = _clientState.LocalPlayer;
|
||||||
|
if (player == null)
|
||||||
|
return; // uh oh
|
||||||
|
|
||||||
|
float hitboxOffset = player.HitboxRadius + gameObject.HitboxRadius;
|
||||||
|
float actualDistance = Vector3.Distance(player.Position, gameObject.Position);
|
||||||
|
float maxDistance = player.ClassJob.ValueNullable?.Role is 3 or 4 ? 20f : 2.9f;
|
||||||
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -359,6 +416,7 @@ internal sealed class CombatController : IDisposable
|
|||||||
{
|
{
|
||||||
public required ICombatModule Module { get; init; }
|
public required ICombatModule Module { get; init; }
|
||||||
public required CombatData Data { get; init; }
|
public required CombatData Data { get; init; }
|
||||||
|
public required DateTime LastDistanceCheck { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed class CombatData
|
public sealed class CombatData
|
||||||
|
@ -16,8 +16,6 @@ internal sealed class BossModModule : ICombatModule, IDisposable
|
|||||||
{
|
{
|
||||||
private const string Name = "BossMod";
|
private const string Name = "BossMod";
|
||||||
private readonly ILogger<BossModModule> _logger;
|
private readonly ILogger<BossModModule> _logger;
|
||||||
private readonly MovementController _movementController;
|
|
||||||
private readonly IClientState _clientState;
|
|
||||||
private readonly Configuration _configuration;
|
private readonly Configuration _configuration;
|
||||||
private readonly ICallGateSubscriber<string, string?> _getPreset;
|
private readonly ICallGateSubscriber<string, string?> _getPreset;
|
||||||
private readonly ICallGateSubscriber<string, bool, bool> _createPreset;
|
private readonly ICallGateSubscriber<string, bool, bool> _createPreset;
|
||||||
@ -25,18 +23,13 @@ internal sealed class BossModModule : ICombatModule, IDisposable
|
|||||||
private readonly ICallGateSubscriber<bool> _clearPreset;
|
private readonly ICallGateSubscriber<bool> _clearPreset;
|
||||||
|
|
||||||
private static Stream Preset => typeof(BossModModule).Assembly.GetManifestResourceStream("Questionable.Controller.CombatModules.BossModPreset")!;
|
private static Stream Preset => typeof(BossModModule).Assembly.GetManifestResourceStream("Questionable.Controller.CombatModules.BossModPreset")!;
|
||||||
private DateTime _lastDistanceCheck = DateTime.MinValue;
|
|
||||||
|
|
||||||
public BossModModule(
|
public BossModModule(
|
||||||
ILogger<BossModModule> logger,
|
ILogger<BossModModule> logger,
|
||||||
MovementController movementController,
|
|
||||||
IClientState clientState,
|
|
||||||
IDalamudPluginInterface pluginInterface,
|
IDalamudPluginInterface pluginInterface,
|
||||||
Configuration configuration)
|
Configuration configuration)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_movementController = movementController;
|
|
||||||
_clientState = clientState;
|
|
||||||
_configuration = configuration;
|
_configuration = configuration;
|
||||||
|
|
||||||
_getPreset = pluginInterface.GetIpcSubscriber<string, string?>($"{Name}.Presets.Get");
|
_getPreset = pluginInterface.GetIpcSubscriber<string, string?>($"{Name}.Presets.Get");
|
||||||
@ -70,7 +63,6 @@ internal sealed class BossModModule : ICombatModule, IDisposable
|
|||||||
_logger.LogInformation("Loading Questionable BossMod Preset: {LoadedState}", _createPreset.InvokeFunc(reader.ReadToEnd(), true));
|
_logger.LogInformation("Loading Questionable BossMod Preset: {LoadedState}", _createPreset.InvokeFunc(reader.ReadToEnd(), true));
|
||||||
}
|
}
|
||||||
_setPreset.InvokeFunc("Questionable");
|
_setPreset.InvokeFunc("Questionable");
|
||||||
_lastDistanceCheck = DateTime.Now;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
catch (IpcError e)
|
catch (IpcError e)
|
||||||
@ -94,46 +86,8 @@ internal sealed class BossModModule : ICombatModule, IDisposable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void MoveToTarget(IGameObject gameObject)
|
|
||||||
{
|
|
||||||
var player = _clientState.LocalPlayer;
|
|
||||||
if (player == null)
|
|
||||||
return; // uh oh
|
|
||||||
|
|
||||||
float hitboxOffset = player.HitboxRadius + gameObject.HitboxRadius;
|
|
||||||
float actualDistance = Vector3.Distance(player.Position, gameObject.Position);
|
|
||||||
float maxDistance = player.ClassJob.ValueNullable?.Role is 3 or 4 ? 20f : 2.9f;
|
|
||||||
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)
|
public void Update(IGameObject gameObject)
|
||||||
{
|
{
|
||||||
if (_movementController.IsPathfinding || _movementController.IsPathRunning)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (DateTime.Now > _lastDistanceCheck.AddSeconds(10))
|
|
||||||
{
|
|
||||||
MoveToTarget(gameObject);
|
|
||||||
_lastDistanceCheck = DateTime.Now;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool CanAttack(IBattleNpc target) => true;
|
public bool CanAttack(IBattleNpc target) => true;
|
||||||
|
@ -12,7 +12,5 @@ internal interface ICombatModule
|
|||||||
|
|
||||||
void Update(IGameObject nextTarget);
|
void Update(IGameObject nextTarget);
|
||||||
|
|
||||||
void MoveToTarget(IGameObject nextTarget);
|
|
||||||
|
|
||||||
bool CanAttack(IBattleNpc target);
|
bool CanAttack(IBattleNpc target);
|
||||||
}
|
}
|
||||||
|
@ -152,7 +152,5 @@ internal sealed class ItemUseModule : ICombatModule
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void MoveToTarget(IGameObject nextTarget) => _delegate!.MoveToTarget(nextTarget);
|
|
||||||
|
|
||||||
public bool CanAttack(IBattleNpc target) => _delegate!.CanAttack(target);
|
public bool CanAttack(IBattleNpc target) => _delegate!.CanAttack(target);
|
||||||
}
|
}
|
||||||
|
@ -15,13 +15,10 @@ internal sealed class Mount128Module : ICombatModule
|
|||||||
public const ushort MountId = 128;
|
public const ushort MountId = 128;
|
||||||
private readonly EAction[] _actions = [EAction.MagitekThunder, EAction.MagitekPulse];
|
private readonly EAction[] _actions = [EAction.MagitekThunder, EAction.MagitekPulse];
|
||||||
|
|
||||||
private readonly MovementController _movementController;
|
|
||||||
private readonly GameFunctions _gameFunctions;
|
private readonly GameFunctions _gameFunctions;
|
||||||
|
|
||||||
|
public Mount128Module(GameFunctions gameFunctions)
|
||||||
public Mount128Module(MovementController movementController, GameFunctions gameFunctions)
|
|
||||||
{
|
{
|
||||||
_movementController = movementController;
|
|
||||||
_gameFunctions = gameFunctions;
|
_gameFunctions = gameFunctions;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -33,9 +30,6 @@ internal sealed class Mount128Module : ICombatModule
|
|||||||
|
|
||||||
public void Update(IGameObject gameObject)
|
public void Update(IGameObject gameObject)
|
||||||
{
|
{
|
||||||
if (_movementController.IsPathfinding || _movementController.IsPathRunning)
|
|
||||||
return;
|
|
||||||
|
|
||||||
foreach (EAction action in _actions)
|
foreach (EAction action in _actions)
|
||||||
{
|
{
|
||||||
if (_gameFunctions.UseAction(gameObject, action, checkCanUse: false))
|
if (_gameFunctions.UseAction(gameObject, action, checkCanUse: false))
|
||||||
@ -43,9 +37,5 @@ internal sealed class Mount128Module : ICombatModule
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void MoveToTarget(IGameObject gameObject)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool CanAttack(IBattleNpc target) => target.DataId is 7504 or 7505 or 14107;
|
public bool CanAttack(IBattleNpc target) => target.DataId is 7504 or 7505 or 14107;
|
||||||
}
|
}
|
||||||
|
@ -15,13 +15,11 @@ internal sealed class Mount147Module : ICombatModule
|
|||||||
public const ushort MountId = 147;
|
public const ushort MountId = 147;
|
||||||
private readonly EAction[] _actions = [EAction.Trample];
|
private readonly EAction[] _actions = [EAction.Trample];
|
||||||
|
|
||||||
private readonly MovementController _movementController;
|
|
||||||
private readonly GameFunctions _gameFunctions;
|
private readonly GameFunctions _gameFunctions;
|
||||||
|
|
||||||
|
|
||||||
public Mount147Module(MovementController movementController, GameFunctions gameFunctions)
|
public Mount147Module(GameFunctions gameFunctions)
|
||||||
{
|
{
|
||||||
_movementController = movementController;
|
|
||||||
_gameFunctions = gameFunctions;
|
_gameFunctions = gameFunctions;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -33,9 +31,6 @@ internal sealed class Mount147Module : ICombatModule
|
|||||||
|
|
||||||
public void Update(IGameObject gameObject)
|
public void Update(IGameObject gameObject)
|
||||||
{
|
{
|
||||||
if (_movementController.IsPathfinding || _movementController.IsPathRunning)
|
|
||||||
return;
|
|
||||||
|
|
||||||
foreach (EAction action in _actions)
|
foreach (EAction action in _actions)
|
||||||
{
|
{
|
||||||
if (_gameFunctions.UseAction(gameObject, action, checkCanUse: false))
|
if (_gameFunctions.UseAction(gameObject, action, checkCanUse: false))
|
||||||
@ -43,9 +38,5 @@ internal sealed class Mount147Module : ICombatModule
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void MoveToTarget(IGameObject gameObject)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool CanAttack(IBattleNpc target) => target.DataId is 8593;
|
public bool CanAttack(IBattleNpc target) => target.DataId is 8593;
|
||||||
}
|
}
|
||||||
|
@ -14,19 +14,15 @@ namespace Questionable.Controller.CombatModules;
|
|||||||
internal sealed class RotationSolverRebornModule : ICombatModule, IDisposable
|
internal sealed class RotationSolverRebornModule : ICombatModule, IDisposable
|
||||||
{
|
{
|
||||||
private readonly ILogger<RotationSolverRebornModule> _logger;
|
private readonly ILogger<RotationSolverRebornModule> _logger;
|
||||||
private readonly MovementController _movementController;
|
|
||||||
private readonly IClientState _clientState;
|
private readonly IClientState _clientState;
|
||||||
private readonly Configuration _configuration;
|
private readonly Configuration _configuration;
|
||||||
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, Configuration configuration)
|
IClientState clientState, IDalamudPluginInterface pluginInterface, Configuration configuration)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_movementController = movementController;
|
|
||||||
_clientState = clientState;
|
_clientState = clientState;
|
||||||
_configuration = configuration;
|
_configuration = configuration;
|
||||||
_test = pluginInterface.GetIpcSubscriber<string, object>("RotationSolverReborn.Test");
|
_test = pluginInterface.GetIpcSubscriber<string, object>("RotationSolverReborn.Test");
|
||||||
@ -55,7 +51,6 @@ 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)
|
||||||
@ -67,6 +62,9 @@ internal sealed class RotationSolverRebornModule : ICombatModule, IDisposable
|
|||||||
|
|
||||||
public bool Stop()
|
public bool Stop()
|
||||||
{
|
{
|
||||||
|
if (!_changeOperationMode.HasAction)
|
||||||
|
return true;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_changeOperationMode.InvokeAction(StateCommandType.Off);
|
_changeOperationMode.InvokeAction(StateCommandType.Off);
|
||||||
@ -79,46 +77,8 @@ internal sealed class RotationSolverRebornModule : ICombatModule, IDisposable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void MoveToTarget(IGameObject gameObject)
|
|
||||||
{
|
|
||||||
var player = _clientState.LocalPlayer;
|
|
||||||
if (player == null)
|
|
||||||
return; // uh oh
|
|
||||||
|
|
||||||
float hitboxOffset = player.HitboxRadius + gameObject.HitboxRadius;
|
|
||||||
float actualDistance = Vector3.Distance(player.Position, gameObject.Position);
|
|
||||||
float maxDistance = player.ClassJob.ValueNullable?.Role is 3 or 4 ? 20f : 2.9f;
|
|
||||||
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)
|
public void Update(IGameObject gameObject)
|
||||||
{
|
{
|
||||||
if (_movementController.IsPathfinding || _movementController.IsPathRunning)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (DateTime.Now > _lastDistanceCheck.AddSeconds(10))
|
|
||||||
{
|
|
||||||
MoveToTarget(gameObject);
|
|
||||||
_lastDistanceCheck = DateTime.Now;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool CanAttack(IBattleNpc target) => true;
|
public bool CanAttack(IBattleNpc target) => true;
|
||||||
|
123
Questionable/Controller/CombatModules/WrathComboModule.cs
Normal file
123
Questionable/Controller/CombatModules/WrathComboModule.cs
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
using System;
|
||||||
|
using Dalamud.Game.ClientState.Objects.Types;
|
||||||
|
using Dalamud.Plugin;
|
||||||
|
using Dalamud.Plugin.Ipc;
|
||||||
|
using Dalamud.Plugin.Ipc.Exceptions;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Questionable.Controller.Steps;
|
||||||
|
|
||||||
|
namespace Questionable.Controller.CombatModules;
|
||||||
|
|
||||||
|
internal sealed class WrathComboModule : ICombatModule, IDisposable
|
||||||
|
{
|
||||||
|
private const string CallbackPrefix = "Questionable$Wrath";
|
||||||
|
|
||||||
|
private readonly ILogger<WrathComboModule> _logger;
|
||||||
|
private readonly Configuration _configuration;
|
||||||
|
private readonly ICallGateSubscriber<object> _test;
|
||||||
|
private readonly ICallGateSubscriber<string, string, string, Guid?> _registerForLeaseWithCallback;
|
||||||
|
private readonly ICallGateSubscriber<Guid, object> _releaseControl;
|
||||||
|
private readonly ICallGateSubscriber<Guid,bool,object> _setAutoRotationState;
|
||||||
|
private readonly ICallGateSubscriber<Guid,object> _setCurrentJobAutoRotationReady;
|
||||||
|
private readonly ICallGateProvider<int, string, object> _callback;
|
||||||
|
|
||||||
|
private Guid? _lease;
|
||||||
|
|
||||||
|
public WrathComboModule(ILogger<WrathComboModule> logger, Configuration configuration,
|
||||||
|
IDalamudPluginInterface pluginInterface)
|
||||||
|
{
|
||||||
|
_logger = logger;
|
||||||
|
_configuration = configuration;
|
||||||
|
_test = pluginInterface.GetIpcSubscriber<object>("WrathCombo.Test");
|
||||||
|
_registerForLeaseWithCallback =
|
||||||
|
pluginInterface.GetIpcSubscriber<string, string, string, Guid?>("WrathCombo.RegisterForLeaseWithCallback");
|
||||||
|
_releaseControl = pluginInterface.GetIpcSubscriber<Guid, object>("WrathCombo.ReleaseControl");
|
||||||
|
_setAutoRotationState = pluginInterface.GetIpcSubscriber<Guid, bool, object>("WrathCombo.SetAutoRotationState");
|
||||||
|
_setCurrentJobAutoRotationReady =
|
||||||
|
pluginInterface.GetIpcSubscriber<Guid, object>("WrathCombo.SetCurrentJobAutoRotationReady");
|
||||||
|
|
||||||
|
_callback = pluginInterface.GetIpcProvider<int, string, object>($"{CallbackPrefix}.WrathComboCallback");
|
||||||
|
_callback.RegisterAction(Callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool CanHandleFight(CombatController.CombatData combatData)
|
||||||
|
{
|
||||||
|
if (_configuration.General.CombatModule != Configuration.ECombatModule.WrathCombo)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_test.InvokeAction();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (IpcError)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Start(CombatController.CombatData combatData)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_lease = _registerForLeaseWithCallback.InvokeFunc("Questionable", "Questionable", CallbackPrefix);
|
||||||
|
if (_lease != null)
|
||||||
|
{
|
||||||
|
_logger.LogDebug("Wrath combo lease: {Lease}", _lease.Value);
|
||||||
|
|
||||||
|
_setAutoRotationState.InvokeAction(_lease.Value, true);
|
||||||
|
_setCurrentJobAutoRotationReady.InvokeAction(_lease.Value);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.LogError("Wrath combo did not return a lease");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (IpcError e)
|
||||||
|
{
|
||||||
|
_logger.LogError(e, "Unable to use wrath combo for combat");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Stop()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (_lease != null)
|
||||||
|
{
|
||||||
|
_releaseControl.InvokeAction(_lease.Value);
|
||||||
|
_lease = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (IpcError e)
|
||||||
|
{
|
||||||
|
_logger.LogWarning(e, "Could not turn off wrath combo");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Update(IGameObject nextTarget)
|
||||||
|
{
|
||||||
|
if (_lease == null)
|
||||||
|
throw new TaskException("Wrath Combo Lease is cancelled");
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool CanAttack(IBattleNpc target) => true;
|
||||||
|
|
||||||
|
private void Callback(int reason, string additionalInfo)
|
||||||
|
{
|
||||||
|
_logger.LogWarning("WrathCombo callback: {Reason} ({Info})", reason, additionalInfo);
|
||||||
|
_lease = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Stop();
|
||||||
|
_callback.UnregisterAction();
|
||||||
|
}
|
||||||
|
}
|
@ -19,7 +19,6 @@ using Questionable.Controller.Steps.Common;
|
|||||||
using Questionable.Controller.Steps.Gathering;
|
using Questionable.Controller.Steps.Gathering;
|
||||||
using Questionable.Controller.Steps.Interactions;
|
using Questionable.Controller.Steps.Interactions;
|
||||||
using Questionable.Controller.Steps.Leves;
|
using Questionable.Controller.Steps.Leves;
|
||||||
using Questionable.Controller.Utils;
|
|
||||||
using Questionable.Data;
|
using Questionable.Data;
|
||||||
using Questionable.External;
|
using Questionable.External;
|
||||||
using Questionable.Functions;
|
using Questionable.Functions;
|
||||||
@ -249,6 +248,7 @@ public sealed class QuestionablePlugin : IDalamudPlugin
|
|||||||
serviceCollection.AddSingleton<ICombatModule, Mount147Module>();
|
serviceCollection.AddSingleton<ICombatModule, Mount147Module>();
|
||||||
serviceCollection.AddSingleton<ICombatModule, ItemUseModule>();
|
serviceCollection.AddSingleton<ICombatModule, ItemUseModule>();
|
||||||
serviceCollection.AddSingleton<ICombatModule, BossModModule>();
|
serviceCollection.AddSingleton<ICombatModule, BossModModule>();
|
||||||
|
serviceCollection.AddSingleton<ICombatModule, WrathComboModule>();
|
||||||
serviceCollection.AddSingleton<ICombatModule, RotationSolverRebornModule>();
|
serviceCollection.AddSingleton<ICombatModule, RotationSolverRebornModule>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ internal sealed class ConfigWindow : LWindow, IPersistableWindowConfig
|
|||||||
private readonly uint[] _mountIds;
|
private readonly uint[] _mountIds;
|
||||||
private readonly string[] _mountNames;
|
private readonly string[] _mountNames;
|
||||||
|
|
||||||
private readonly string[] _combatModuleNames = ["None", "Boss Mod (VBM)", "Rotation Solver Reborn"];
|
private readonly string[] _combatModuleNames = ["None", "Boss Mod (VBM)", "Wrath Combo", "Rotation Solver Reborn"];
|
||||||
|
|
||||||
private readonly string[] _grandCompanyNames =
|
private readonly string[] _grandCompanyNames =
|
||||||
["None (manually pick quest)", "Maelstrom", "Twin Adder", "Immortal Flames"];
|
["None (manually pick quest)", "Maelstrom", "Twin Adder", "Immortal Flames"];
|
||||||
|
@ -54,6 +54,14 @@ internal sealed class OneTimeSetupWindow : LWindow
|
|||||||
new Uri("https://github.com/awgil/ffxiv_bossmod"),
|
new Uri("https://github.com/awgil/ffxiv_bossmod"),
|
||||||
new Uri("https://puni.sh/api/repository/veyn"))
|
new Uri("https://puni.sh/api/repository/veyn"))
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Configuration.ECombatModule.WrathCombo,
|
||||||
|
new PluginInfo("Wrath Combo",
|
||||||
|
"WrathCombo",
|
||||||
|
string.Empty,
|
||||||
|
new Uri("https://github.com/PunishXIV/WrathCombo"),
|
||||||
|
new Uri("https://puni.sh/api/plugins"))
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Configuration.ECombatModule.RotationSolverReborn,
|
Configuration.ECombatModule.RotationSolverReborn,
|
||||||
new("Rotation Solver Reborn",
|
new("Rotation Solver Reborn",
|
||||||
@ -143,6 +151,7 @@ internal sealed class OneTimeSetupWindow : LWindow
|
|||||||
}
|
}
|
||||||
|
|
||||||
DrawCombatPlugin(Configuration.ECombatModule.BossMod, checklistPadding);
|
DrawCombatPlugin(Configuration.ECombatModule.BossMod, checklistPadding);
|
||||||
|
DrawCombatPlugin(Configuration.ECombatModule.WrathCombo, checklistPadding);
|
||||||
DrawCombatPlugin(Configuration.ECombatModule.RotationSolverReborn, checklistPadding);
|
DrawCombatPlugin(Configuration.ECombatModule.RotationSolverReborn, checklistPadding);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user