178 lines
5.3 KiB
C#
178 lines
5.3 KiB
C#
using System;
|
|
using System.Numerics;
|
|
using Dalamud.Game.ClientState.Conditions;
|
|
using Dalamud.Game.ClientState.Objects.Types;
|
|
using Dalamud.Plugin.Services;
|
|
using Microsoft.Extensions.Logging;
|
|
using Questionable.Controller.GameUi;
|
|
using Questionable.Functions;
|
|
|
|
namespace Questionable.Controller.Steps.Shared;
|
|
|
|
internal static class TaxiInteract
|
|
{
|
|
internal sealed record Task(uint NpcDataId, uint DestStandRowId, string DestPlaceName, ushort SourceTerritoryId, ushort DestTerritoryId) : ITask
|
|
{
|
|
public bool ShouldRedoOnInterrupt()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
public override string ToString()
|
|
{
|
|
return $"TaxiInteract({NpcDataId}, dest={DestPlaceName}, {SourceTerritoryId}->{DestTerritoryId})";
|
|
}
|
|
}
|
|
|
|
internal sealed class DoTaxiInteract(GameFunctions gameFunctions, InteractionUiController interactionUiController, ICondition condition, IClientState clientState, IObjectTable objectTable, ILogger<DoTaxiInteract> logger) : TaskExecutor<Task>(), IConditionChangeAware, ITaskExecutor
|
|
{
|
|
private enum ETaxiPhase
|
|
{
|
|
None,
|
|
Unmounting,
|
|
Interacting,
|
|
Riding
|
|
}
|
|
|
|
private ETaxiPhase _phase;
|
|
|
|
private Vector3 _startPosition;
|
|
|
|
private long _interactingStartedAt;
|
|
|
|
private bool _wasRiding;
|
|
|
|
protected override bool Start()
|
|
{
|
|
_phase = ETaxiPhase.None;
|
|
_wasRiding = false;
|
|
_startPosition = objectTable.LocalPlayer?.Position ?? Vector3.Zero;
|
|
interactionUiController.SmartNavTaxiDestPlaceName = base.Task.DestPlaceName;
|
|
IGameObject gameObject = gameFunctions.FindObjectByDataId(base.Task.NpcDataId);
|
|
if (gameObject == null)
|
|
{
|
|
logger.LogDebug("TaxiInteract: NPC with DataId {DataId} not found yet, waiting", base.Task.NpcDataId);
|
|
return true;
|
|
}
|
|
if (condition[ConditionFlag.Mounted])
|
|
{
|
|
logger.LogDebug("TaxiInteract: Unmounting before taxi interaction");
|
|
gameFunctions.Unmount();
|
|
_phase = ETaxiPhase.Unmounting;
|
|
return true;
|
|
}
|
|
if (gameFunctions.InteractWith(gameObject))
|
|
{
|
|
logger.LogDebug("TaxiInteract: Interacting with NPC {DataId} for taxi to {Dest}", base.Task.NpcDataId, base.Task.DestPlaceName);
|
|
_phase = ETaxiPhase.Interacting;
|
|
_interactingStartedAt = Environment.TickCount64;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public override ETaskResult Update()
|
|
{
|
|
switch (_phase)
|
|
{
|
|
case ETaxiPhase.Unmounting:
|
|
{
|
|
if (condition[ConditionFlag.Mounted])
|
|
{
|
|
return ETaskResult.StillRunning;
|
|
}
|
|
IGameObject gameObject2 = gameFunctions.FindObjectByDataId(base.Task.NpcDataId);
|
|
if (gameObject2 == null)
|
|
{
|
|
logger.LogDebug("TaxiInteract: NPC not found after unmount, waiting");
|
|
_phase = ETaxiPhase.None;
|
|
return ETaskResult.StillRunning;
|
|
}
|
|
if (gameFunctions.InteractWith(gameObject2))
|
|
{
|
|
logger.LogDebug("TaxiInteract: Interacting with NPC {DataId} after unmount", base.Task.NpcDataId);
|
|
_phase = ETaxiPhase.Interacting;
|
|
_interactingStartedAt = Environment.TickCount64;
|
|
}
|
|
return ETaskResult.StillRunning;
|
|
}
|
|
case ETaxiPhase.Interacting:
|
|
if (condition[ConditionFlag.Mounted] && (condition[ConditionFlag.Occupied] || condition[ConditionFlag.OccupiedInEvent]))
|
|
{
|
|
logger.LogDebug("TaxiInteract: Taxi ride started");
|
|
_wasRiding = true;
|
|
_phase = ETaxiPhase.Riding;
|
|
return ETaskResult.StillRunning;
|
|
}
|
|
if (Environment.TickCount64 - _interactingStartedAt > 30000)
|
|
{
|
|
logger.LogWarning("TaxiInteract: Timed out waiting for taxi ride to start, retrying step");
|
|
ClearContext();
|
|
return ETaskResult.RetryStep;
|
|
}
|
|
return ETaskResult.StillRunning;
|
|
case ETaxiPhase.Riding:
|
|
if (clientState.TerritoryType != base.Task.SourceTerritoryId)
|
|
{
|
|
logger.LogDebug("TaxiInteract: Territory changed to {Territory}, taxi ride complete", clientState.TerritoryType);
|
|
ClearContext();
|
|
return ETaskResult.TaskComplete;
|
|
}
|
|
if ((!condition[ConditionFlag.Mounted] || (!condition[ConditionFlag.Occupied] && !condition[ConditionFlag.OccupiedInEvent])) && _wasRiding)
|
|
{
|
|
logger.LogDebug("TaxiInteract: Taxi ride ended (dismounted)");
|
|
ClearContext();
|
|
return ETaskResult.TaskComplete;
|
|
}
|
|
return ETaskResult.StillRunning;
|
|
case ETaxiPhase.None:
|
|
{
|
|
IGameObject gameObject = gameFunctions.FindObjectByDataId(base.Task.NpcDataId);
|
|
if (gameObject == null)
|
|
{
|
|
return ETaskResult.StillRunning;
|
|
}
|
|
_startPosition = objectTable.LocalPlayer?.Position ?? _startPosition;
|
|
if (condition[ConditionFlag.Mounted])
|
|
{
|
|
gameFunctions.Unmount();
|
|
_phase = ETaxiPhase.Unmounting;
|
|
return ETaskResult.StillRunning;
|
|
}
|
|
if (gameFunctions.InteractWith(gameObject))
|
|
{
|
|
logger.LogDebug("TaxiInteract: Interacting with NPC {DataId}", base.Task.NpcDataId);
|
|
_phase = ETaxiPhase.Interacting;
|
|
_interactingStartedAt = Environment.TickCount64;
|
|
}
|
|
return ETaskResult.StillRunning;
|
|
}
|
|
default:
|
|
return ETaskResult.StillRunning;
|
|
}
|
|
}
|
|
|
|
public void OnConditionChange(ConditionFlag flag, bool value)
|
|
{
|
|
bool flag2 = _phase == ETaxiPhase.Interacting;
|
|
if (flag2)
|
|
{
|
|
bool flag3 = (uint)(flag - 31) <= 1u;
|
|
flag2 = flag3;
|
|
}
|
|
if (flag2 && value)
|
|
{
|
|
logger.LogDebug("TaxiInteract: Interaction confirmed via condition flag");
|
|
}
|
|
}
|
|
|
|
public override bool ShouldInterruptOnDamage()
|
|
{
|
|
return false;
|
|
}
|
|
|
|
private void ClearContext()
|
|
{
|
|
interactionUiController.SmartNavTaxiDestPlaceName = null;
|
|
}
|
|
}
|
|
}
|