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

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;
}
}
}