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
|
||||
{
|
||||
public const int PluginSetupVersion = 3;
|
||||
public const int PluginSetupVersion = 4;
|
||||
|
||||
public int Version { get; set; } = 1;
|
||||
public int PluginSetupCompleteVersion { get; set; }
|
||||
@ -23,7 +23,7 @@ internal sealed class Configuration : IPluginConfiguration
|
||||
|
||||
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 GrandCompany GrandCompany { get; set; } = GrandCompany.None;
|
||||
public bool HideInAllInstances { get; set; } = true;
|
||||
@ -51,6 +51,7 @@ internal sealed class Configuration : IPluginConfiguration
|
||||
{
|
||||
None,
|
||||
BossMod,
|
||||
WrathCombo,
|
||||
RotationSolverReborn,
|
||||
}
|
||||
}
|
||||
|
@ -13,8 +13,10 @@ using FFXIVClientStructs.FFXIV.Client.Game.UI;
|
||||
using FFXIVClientStructs.FFXIV.Common.Math;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Questionable.Controller.CombatModules;
|
||||
using Questionable.Controller.Steps;
|
||||
using Questionable.Controller.Utils;
|
||||
using Questionable.Functions;
|
||||
using Questionable.Model;
|
||||
using Questionable.Model.Questing;
|
||||
|
||||
namespace Questionable.Controller;
|
||||
@ -75,6 +77,7 @@ internal sealed class CombatController : IDisposable
|
||||
{
|
||||
Module = combatModule,
|
||||
Data = combatData,
|
||||
LastDistanceCheck = DateTime.Now,
|
||||
};
|
||||
_wasInCombat = combatData.SpawnType is EEnemySpawnType.QuestInterruption or EEnemySpawnType.FinishCombatIfAny;
|
||||
return true;
|
||||
@ -129,7 +132,18 @@ internal sealed class CombatController : IDisposable
|
||||
|
||||
if (nextTarget != null && nextTarget.Equals(target))
|
||||
{
|
||||
_currentFight.Module.Update(target);
|
||||
if (!IsMovingOrShouldMove(target))
|
||||
{
|
||||
try
|
||||
{
|
||||
_currentFight.Module.Update(target);
|
||||
}
|
||||
catch (TaskException e)
|
||||
{
|
||||
_logger.LogWarning(e, "Combat was interrupted, stopping: {Exception}", e.Message);
|
||||
SetTarget(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (nextTarget != null)
|
||||
{
|
||||
@ -323,14 +337,57 @@ internal sealed class CombatController : IDisposable
|
||||
{
|
||||
_logger.LogInformation("Moving to target, distance: {Distance:N2}",
|
||||
Vector3.Distance(_clientState.LocalPlayer!.Position, target.Position));
|
||||
_currentFight!.Module.MoveToTarget(target);
|
||||
MoveToTarget(target);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogInformation("Setting target to {TargetName} ({TargetId:X8})", target.Name.ToString(),
|
||||
target.GameObjectId);
|
||||
_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 CombatData Data { get; init; }
|
||||
public required DateTime LastDistanceCheck { get; set; }
|
||||
}
|
||||
|
||||
public sealed class CombatData
|
||||
|
@ -16,8 +16,6 @@ internal sealed class BossModModule : ICombatModule, IDisposable
|
||||
{
|
||||
private const string Name = "BossMod";
|
||||
private readonly ILogger<BossModModule> _logger;
|
||||
private readonly MovementController _movementController;
|
||||
private readonly IClientState _clientState;
|
||||
private readonly Configuration _configuration;
|
||||
private readonly ICallGateSubscriber<string, string?> _getPreset;
|
||||
private readonly ICallGateSubscriber<string, bool, bool> _createPreset;
|
||||
@ -25,18 +23,13 @@ internal sealed class BossModModule : ICombatModule, IDisposable
|
||||
private readonly ICallGateSubscriber<bool> _clearPreset;
|
||||
|
||||
private static Stream Preset => typeof(BossModModule).Assembly.GetManifestResourceStream("Questionable.Controller.CombatModules.BossModPreset")!;
|
||||
private DateTime _lastDistanceCheck = DateTime.MinValue;
|
||||
|
||||
public BossModModule(
|
||||
ILogger<BossModModule> logger,
|
||||
MovementController movementController,
|
||||
IClientState clientState,
|
||||
IDalamudPluginInterface pluginInterface,
|
||||
Configuration configuration)
|
||||
{
|
||||
_logger = logger;
|
||||
_movementController = movementController;
|
||||
_clientState = clientState;
|
||||
_configuration = configuration;
|
||||
|
||||
_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));
|
||||
}
|
||||
_setPreset.InvokeFunc("Questionable");
|
||||
_lastDistanceCheck = DateTime.Now;
|
||||
return true;
|
||||
}
|
||||
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)
|
||||
{
|
||||
if (_movementController.IsPathfinding || _movementController.IsPathRunning)
|
||||
return;
|
||||
|
||||
if (DateTime.Now > _lastDistanceCheck.AddSeconds(10))
|
||||
{
|
||||
MoveToTarget(gameObject);
|
||||
_lastDistanceCheck = DateTime.Now;
|
||||
}
|
||||
}
|
||||
|
||||
public bool CanAttack(IBattleNpc target) => true;
|
||||
|
@ -12,7 +12,5 @@ internal interface ICombatModule
|
||||
|
||||
void Update(IGameObject nextTarget);
|
||||
|
||||
void MoveToTarget(IGameObject nextTarget);
|
||||
|
||||
bool CanAttack(IBattleNpc target);
|
||||
}
|
||||
|
@ -152,7 +152,5 @@ internal sealed class ItemUseModule : ICombatModule
|
||||
return false;
|
||||
}
|
||||
|
||||
public void MoveToTarget(IGameObject nextTarget) => _delegate!.MoveToTarget(nextTarget);
|
||||
|
||||
public bool CanAttack(IBattleNpc target) => _delegate!.CanAttack(target);
|
||||
}
|
||||
|
@ -15,13 +15,10 @@ internal sealed class Mount128Module : ICombatModule
|
||||
public const ushort MountId = 128;
|
||||
private readonly EAction[] _actions = [EAction.MagitekThunder, EAction.MagitekPulse];
|
||||
|
||||
private readonly MovementController _movementController;
|
||||
private readonly GameFunctions _gameFunctions;
|
||||
|
||||
|
||||
public Mount128Module(MovementController movementController, GameFunctions gameFunctions)
|
||||
public Mount128Module(GameFunctions gameFunctions)
|
||||
{
|
||||
_movementController = movementController;
|
||||
_gameFunctions = gameFunctions;
|
||||
}
|
||||
|
||||
@ -33,9 +30,6 @@ internal sealed class Mount128Module : ICombatModule
|
||||
|
||||
public void Update(IGameObject gameObject)
|
||||
{
|
||||
if (_movementController.IsPathfinding || _movementController.IsPathRunning)
|
||||
return;
|
||||
|
||||
foreach (EAction action in _actions)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
@ -15,13 +15,11 @@ internal sealed class Mount147Module : ICombatModule
|
||||
public const ushort MountId = 147;
|
||||
private readonly EAction[] _actions = [EAction.Trample];
|
||||
|
||||
private readonly MovementController _movementController;
|
||||
private readonly GameFunctions _gameFunctions;
|
||||
|
||||
|
||||
public Mount147Module(MovementController movementController, GameFunctions gameFunctions)
|
||||
public Mount147Module(GameFunctions gameFunctions)
|
||||
{
|
||||
_movementController = movementController;
|
||||
_gameFunctions = gameFunctions;
|
||||
}
|
||||
|
||||
@ -33,9 +31,6 @@ internal sealed class Mount147Module : ICombatModule
|
||||
|
||||
public void Update(IGameObject gameObject)
|
||||
{
|
||||
if (_movementController.IsPathfinding || _movementController.IsPathRunning)
|
||||
return;
|
||||
|
||||
foreach (EAction action in _actions)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
@ -14,19 +14,15 @@ namespace Questionable.Controller.CombatModules;
|
||||
internal sealed class RotationSolverRebornModule : ICombatModule, IDisposable
|
||||
{
|
||||
private readonly ILogger<RotationSolverRebornModule> _logger;
|
||||
private readonly MovementController _movementController;
|
||||
private readonly IClientState _clientState;
|
||||
private readonly Configuration _configuration;
|
||||
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, Configuration configuration)
|
||||
{
|
||||
_logger = logger;
|
||||
_movementController = movementController;
|
||||
_clientState = clientState;
|
||||
_configuration = configuration;
|
||||
_test = pluginInterface.GetIpcSubscriber<string, object>("RotationSolverReborn.Test");
|
||||
@ -55,7 +51,6 @@ internal sealed class RotationSolverRebornModule : ICombatModule, IDisposable
|
||||
try
|
||||
{
|
||||
_changeOperationMode.InvokeAction(StateCommandType.Manual);
|
||||
_lastDistanceCheck = DateTime.Now;
|
||||
return true;
|
||||
}
|
||||
catch (IpcError e)
|
||||
@ -67,6 +62,9 @@ internal sealed class RotationSolverRebornModule : ICombatModule, IDisposable
|
||||
|
||||
public bool Stop()
|
||||
{
|
||||
if (!_changeOperationMode.HasAction)
|
||||
return true;
|
||||
|
||||
try
|
||||
{
|
||||
_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)
|
||||
{
|
||||
if (_movementController.IsPathfinding || _movementController.IsPathRunning)
|
||||
return;
|
||||
|
||||
if (DateTime.Now > _lastDistanceCheck.AddSeconds(10))
|
||||
{
|
||||
MoveToTarget(gameObject);
|
||||
_lastDistanceCheck = DateTime.Now;
|
||||
}
|
||||
}
|
||||
|
||||
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.Interactions;
|
||||
using Questionable.Controller.Steps.Leves;
|
||||
using Questionable.Controller.Utils;
|
||||
using Questionable.Data;
|
||||
using Questionable.External;
|
||||
using Questionable.Functions;
|
||||
@ -249,6 +248,7 @@ public sealed class QuestionablePlugin : IDalamudPlugin
|
||||
serviceCollection.AddSingleton<ICombatModule, Mount147Module>();
|
||||
serviceCollection.AddSingleton<ICombatModule, ItemUseModule>();
|
||||
serviceCollection.AddSingleton<ICombatModule, BossModModule>();
|
||||
serviceCollection.AddSingleton<ICombatModule, WrathComboModule>();
|
||||
serviceCollection.AddSingleton<ICombatModule, RotationSolverRebornModule>();
|
||||
}
|
||||
|
||||
|
@ -29,7 +29,7 @@ internal sealed class ConfigWindow : LWindow, IPersistableWindowConfig
|
||||
private readonly uint[] _mountIds;
|
||||
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 =
|
||||
["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://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,
|
||||
new("Rotation Solver Reborn",
|
||||
@ -143,6 +151,7 @@ internal sealed class OneTimeSetupWindow : LWindow
|
||||
}
|
||||
|
||||
DrawCombatPlugin(Configuration.ECombatModule.BossMod, checklistPadding);
|
||||
DrawCombatPlugin(Configuration.ECombatModule.WrathCombo, checklistPadding);
|
||||
DrawCombatPlugin(Configuration.ECombatModule.RotationSolverReborn, checklistPadding);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user