1
0
Fork 0
forked from aly/qstbak
qstbak/Questionable/Questionable.Controller/FateController.cs
2026-08-17 20:29:32 +10:00

146 lines
5.1 KiB
C#

using System;
using System.Globalization;
using Dalamud.Plugin.Services;
using Microsoft.Extensions.Logging;
using Questionable.Controller.Steps;
using Questionable.Controller.Steps.Common;
using Questionable.Controller.Steps.Interactions;
using Questionable.Controller.Steps.Movement;
using Questionable.Controller.Steps.Shared;
using Questionable.Functions;
using Questionable.Model.Questing;
using Questionable.Navigation;
namespace Questionable.Controller;
internal sealed class FateController : MiniTaskController<FateController>
{
private readonly MovementController _movementController;
private readonly GameFunctions _gameFunctions;
private readonly SmartNavRouteEnqueuer _routeEnqueuer;
private FateDefinition? _currentFate;
private int _completedCycles;
private int? _cycleLimit;
private DateTime _startTime;
public bool IsRunning => _currentFate != null;
public FateDefinition? CurrentFate => _currentFate;
public TaskQueue TaskQueue => _taskQueue;
public int CompletedCycles => _completedCycles;
public int? CycleLimit => _cycleLimit;
public TimeSpan ElapsedTime
{
get
{
if (!IsRunning)
{
return TimeSpan.Zero;
}
return DateTime.UtcNow - _startTime;
}
}
public FateController(IChatGui chatGui, ICondition condition, IServiceProvider serviceProvider, InterruptHandler interruptHandler, IDataManager dataManager, Configuration configuration, ILogger<FateController> logger, MovementController movementController, GameFunctions gameFunctions, SmartNavRouteEnqueuer routeEnqueuer)
: base(chatGui, condition, serviceProvider, interruptHandler, dataManager, configuration, logger)
{
_movementController = movementController;
_gameFunctions = gameFunctions;
_routeEnqueuer = routeEnqueuer;
}
public void Start(FateDefinition fate, int? cycleLimit = null)
{
_currentFate = fate;
_completedCycles = 0;
_cycleLimit = cycleLimit;
_startTime = DateTime.UtcNow;
_logger.LogInformation("Starting FATE farming: {FateName} (limit: {Limit})", fate.Name, cycleLimit?.ToString(CultureInfo.InvariantCulture) ?? "unlimited");
EnqueueFateCycle();
}
public void Update()
{
if (_currentFate == null || _movementController.IsPathfinding || _movementController.IsPathRunning || _gameFunctions.IsOccupied())
{
return;
}
if (_taskQueue.AllTasksComplete)
{
_completedCycles++;
if (_cycleLimit.HasValue && _completedCycles >= _cycleLimit.Value)
{
_logger.LogInformation("FATE cycle limit reached ({Cycles}/{Limit})", _completedCycles, _cycleLimit.Value);
Stop("Cycle limit reached");
return;
}
EnqueueFateCycle();
}
UpdateCurrentTask();
}
private void EnqueueFateCycle()
{
if (_currentFate != null)
{
_logger.LogDebug("Enqueuing FATE cycle for {FateName}", _currentFate.Name);
_routeEnqueuer.Enqueue(_taskQueue, _currentFate.TerritoryId, _currentFate.Position, 5f);
if (_currentFate.RequiredStatusId.HasValue && _currentFate.TransformNpcDataId.HasValue && _currentFate.TransformNpcPosition.HasValue && !_gameFunctions.HasStatus(_currentFate.RequiredStatusId.Value))
{
_logger.LogDebug("Player missing required status {StatusId}, enqueuing transform", _currentFate.RequiredStatusId.Value);
_taskQueue.Enqueue(new MoveTask(_currentFate.TerritoryId, _currentFate.TransformNpcPosition.Value, null, MountRequired: false, DismountRequired: false, 3f));
_taskQueue.Enqueue(new Mount.UnmountTask());
TaskQueue taskQueue = _taskQueue;
uint value = _currentFate.TransformNpcDataId.Value;
EStatus? requiredStatusId = _currentFate.RequiredStatusId;
taskQueue.Enqueue(new Interact.Task(value, null, EInteractionType.Interact, SkipMarkerCheck: true, null, null, null, null, requiredStatusId));
_taskQueue.Enqueue(new WaitAtEnd.WaitDelay(TimeSpan.FromSeconds(2L)));
_taskQueue.Enqueue(new MoveTask(_currentFate.TerritoryId, _currentFate.Position, null, MountRequired: false, DismountRequired: false, 5f));
}
_taskQueue.Enqueue(new Mount.UnmountTask());
_taskQueue.Enqueue(new FateFarming.WaitForFateTargets(_currentFate.Targets));
_taskQueue.Enqueue(new FateFarming.SyncFateLevel());
_taskQueue.Enqueue(new FateFarming.FateActionLoop(_currentFate.Targets, _currentFate.RequiredStatusId));
_taskQueue.Enqueue(new WaitAtEnd.WaitDelay(TimeSpan.FromSeconds(3L)));
}
}
public void Replan()
{
if (_currentFate != null)
{
_logger.LogInformation("Re-planning FATE cycle for {FateName}", _currentFate.Name);
_taskQueue.Reset();
EnqueueFateCycle();
}
}
public override void Stop(string label)
{
base.Stop(label);
if (_currentFate != null)
{
_logger.LogInformation("Stopping FATE farming: {Label} (completed {Cycles} cycles)", label, _completedCycles);
if (_currentFate.StopAction.HasValue && _currentFate.RequiredStatusId.HasValue && _gameFunctions.HasStatus(_currentFate.RequiredStatusId.Value))
{
_logger.LogInformation("Using stop action {Action} to remove transformation", _currentFate.StopAction.Value);
_gameFunctions.UseAction(_currentFate.StopAction.Value);
}
_routeEnqueuer.ClearDestination();
_currentFate = null;
_completedCycles = 0;
_cycleLimit = null;
_taskQueue.Reset();
}
}
}