184 lines
5.7 KiB
C#
184 lines
5.7 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Numerics;
|
|
using System.Runtime.InteropServices;
|
|
using Dalamud.Game.ClientState.Conditions;
|
|
using Dalamud.Game.ClientState.Objects.SubKinds;
|
|
using Dalamud.Plugin.Services;
|
|
using Microsoft.Extensions.Logging;
|
|
using Questionable.Controller.Steps.Movement;
|
|
using Questionable.Functions;
|
|
using SmartNav.Data;
|
|
using SmartNav.Model;
|
|
|
|
namespace Questionable.Controller.Steps.Shared;
|
|
|
|
internal static class AetheryteTeleport
|
|
{
|
|
internal sealed record Task(EAetheryteLocation TargetAetheryte, ushort ExpectedTerritoryId) : ISkippableTask, ITask
|
|
{
|
|
public override string ToString()
|
|
{
|
|
return $"UseAetheryte({TargetAetheryte})";
|
|
}
|
|
}
|
|
|
|
internal sealed class AetheryteTeleportExecutor(ILogger<AetheryteTeleportExecutor> logger, AetheryteFunctions aetheryteFunctions, IClientState clientState, IObjectTable objectTable, IChatGui chatGui, ICondition condition, AetheryteData aetheryteData) : TaskExecutor<Task>()
|
|
{
|
|
private bool _teleported;
|
|
|
|
private long _retryTeleportAt;
|
|
|
|
private int _teleportAttempts;
|
|
|
|
private const int MaxTeleportAttempts = 3;
|
|
|
|
protected override bool Start()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
public override ETaskResult Update()
|
|
{
|
|
if (!_teleported)
|
|
{
|
|
if (Environment.TickCount64 < _retryTeleportAt)
|
|
{
|
|
return ETaskResult.StillRunning;
|
|
}
|
|
_teleported = DoTeleport();
|
|
return ETaskResult.StillRunning;
|
|
}
|
|
if (clientState.TerritoryType == base.Task.ExpectedTerritoryId)
|
|
{
|
|
IPlayerCharacter localPlayer = objectTable.LocalPlayer;
|
|
if (localPlayer == null || aetheryteData.CalculateDistance(localPlayer.Position, clientState.TerritoryType, base.Task.TargetAetheryte) <= 50f)
|
|
{
|
|
ResetProgressTimer();
|
|
return ETaskResult.TaskComplete;
|
|
}
|
|
}
|
|
if (base.ProgressContext != null)
|
|
{
|
|
if (base.ProgressContext.WasInterrupted())
|
|
{
|
|
logger.LogDebug("Teleport to {Aetheryte} was interrupted", base.Task.TargetAetheryte);
|
|
return ETaskResult.StillRunning;
|
|
}
|
|
if (base.ProgressContext.WasSuccessful())
|
|
{
|
|
ResetProgressTimer();
|
|
}
|
|
}
|
|
return ETaskResult.StillRunning;
|
|
}
|
|
|
|
private bool DoTeleport()
|
|
{
|
|
if (!aetheryteFunctions.CanTeleport(base.Task.TargetAetheryte))
|
|
{
|
|
if (!aetheryteFunctions.IsTeleportUnlocked())
|
|
{
|
|
throw new TaskException("Teleport is not unlocked, attune to any aetheryte first.");
|
|
}
|
|
_retryTeleportAt = Environment.TickCount64 + 1000;
|
|
logger.LogTrace("Waiting for teleport cooldown...");
|
|
return false;
|
|
}
|
|
if (!aetheryteFunctions.IsAetheryteUnlocked(base.Task.TargetAetheryte))
|
|
{
|
|
chatGui.PrintError($"Aetheryte {base.Task.TargetAetheryte} is not unlocked.", "Questionable", 576);
|
|
throw new TaskException("Aetheryte is not unlocked");
|
|
}
|
|
base.ProgressContext = InteractionProgressContext.FromActionUseOrDefault(() => aetheryteFunctions.TeleportAetheryte(base.Task.TargetAetheryte));
|
|
if (base.ProgressContext != null)
|
|
{
|
|
logger.LogInformation("Travelling via aetheryte...");
|
|
return true;
|
|
}
|
|
if (++_teleportAttempts < 3)
|
|
{
|
|
_retryTeleportAt = Environment.TickCount64 + 1000;
|
|
logger.LogWarning("Teleport did not start (attempt {Attempt}/{Max}), retrying...", _teleportAttempts, 3);
|
|
return false;
|
|
}
|
|
chatGui.Print("Unable to teleport to aetheryte.", "Questionable", 576);
|
|
throw new TaskException("Unable to teleport to aetheryte");
|
|
}
|
|
|
|
public override bool WasInterrupted()
|
|
{
|
|
if (!condition[ConditionFlag.InCombat])
|
|
{
|
|
return base.WasInterrupted();
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public override bool ShouldInterruptOnDamage()
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
internal sealed record MoveAwayFromAetheryte(EAetheryteLocation TargetAetheryte) : ITask
|
|
{
|
|
public override string ToString()
|
|
{
|
|
return $"MoveAway({TargetAetheryte})";
|
|
}
|
|
}
|
|
|
|
internal sealed class MoveAwayFromAetheryteExecutor(MoveExecutor moveExecutor, AetheryteData aetheryteData, IClientState clientState, IObjectTable objectTable) : TaskExecutor<MoveAwayFromAetheryte>()
|
|
{
|
|
private static readonly Dictionary<EAetheryteLocation, List<Vector3>> AetherytesToMoveFrom;
|
|
|
|
public static bool AppliesTo(EAetheryteLocation location)
|
|
{
|
|
return AetherytesToMoveFrom.ContainsKey(location);
|
|
}
|
|
|
|
protected override bool Start()
|
|
{
|
|
IPlayerCharacter localPlayer = objectTable.LocalPlayer;
|
|
if (localPlayer == null)
|
|
{
|
|
return false;
|
|
}
|
|
Vector3 playerPosition = localPlayer.Position;
|
|
if (aetheryteData.CalculateDistance(playerPosition, clientState.TerritoryType, base.Task.TargetAetheryte) >= 20f)
|
|
{
|
|
return false;
|
|
}
|
|
Vector3 destination = AetherytesToMoveFrom[base.Task.TargetAetheryte].MinBy((Vector3 x) => Vector3.Distance(x, playerPosition));
|
|
MoveTask task = new MoveTask(aetheryteData.TerritoryIds[base.Task.TargetAetheryte], destination, false, MountRequired: false, DismountRequired: false, 0.25f, null, DisableNavmesh: true, null, Fly: false, Land: false, IgnoreDistanceToObject: false, RestartNavigation: false);
|
|
return moveExecutor.Start(task);
|
|
}
|
|
|
|
public override ETaskResult Update()
|
|
{
|
|
return moveExecutor.Update();
|
|
}
|
|
|
|
public override bool ShouldInterruptOnDamage()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
static MoveAwayFromAetheryteExecutor()
|
|
{
|
|
Dictionary<EAetheryteLocation, List<Vector3>> dictionary = new Dictionary<EAetheryteLocation, List<Vector3>>();
|
|
int num = 4;
|
|
List<Vector3> list = new List<Vector3>(num);
|
|
CollectionsMarshal.SetCount(list, num);
|
|
Span<Vector3> span = CollectionsMarshal.AsSpan(list);
|
|
span[0] = new Vector3(0f, 8.8f, 15.5f);
|
|
span[1] = new Vector3(0f, 8.8f, -15.5f);
|
|
span[2] = new Vector3(15.5f, 8.8f, 0f);
|
|
span[3] = new Vector3(-15.5f, 8.8f, 0f);
|
|
dictionary.Add(EAetheryteLocation.SolutionNine, list);
|
|
AetherytesToMoveFrom = dictionary;
|
|
}
|
|
}
|
|
}
|