Polish EW_A quests
This commit is contained in:
parent
5040242dea
commit
f542135c89
@ -1,10 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Dalamud.Game.ClientState.Conditions;
|
||||
using Dalamud.Plugin.Services;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game;
|
||||
using Questionable.External;
|
||||
|
||||
namespace Questionable.Controller;
|
||||
@ -15,16 +18,18 @@ internal sealed class MovementController : IDisposable
|
||||
private readonly NavmeshIpc _navmeshIpc;
|
||||
private readonly IClientState _clientState;
|
||||
private readonly GameFunctions _gameFunctions;
|
||||
private readonly ICondition _condition;
|
||||
private readonly IPluginLog _pluginLog;
|
||||
private CancellationTokenSource? _cancellationTokenSource;
|
||||
private Task<List<Vector3>>? _pathfindTask;
|
||||
|
||||
public MovementController(NavmeshIpc navmeshIpc, IClientState clientState, GameFunctions gameFunctions,
|
||||
IPluginLog pluginLog)
|
||||
ICondition condition, IPluginLog pluginLog)
|
||||
{
|
||||
_navmeshIpc = navmeshIpc;
|
||||
_clientState = clientState;
|
||||
_gameFunctions = gameFunctions;
|
||||
_condition = condition;
|
||||
_pluginLog = pluginLog;
|
||||
}
|
||||
|
||||
@ -33,6 +38,7 @@ internal sealed class MovementController : IDisposable
|
||||
public bool IsPathfinding => _pathfindTask is { IsCompleted: false };
|
||||
public Vector3? Destination { get; private set; }
|
||||
public float StopDistance { get; private set; }
|
||||
public bool IsFlying { get; private set; }
|
||||
|
||||
public void Update()
|
||||
{
|
||||
@ -41,8 +47,35 @@ internal sealed class MovementController : IDisposable
|
||||
if (_pathfindTask.IsCompletedSuccessfully)
|
||||
{
|
||||
_pluginLog.Information(
|
||||
$"Pathfinding complete, route: [{string.Join(" → ", _pathfindTask.Result.Select(x => x.ToString()))}]");
|
||||
_navmeshIpc.MoveTo(_pathfindTask.Result.Skip(1).ToList());
|
||||
string.Create(CultureInfo.InvariantCulture,
|
||||
$"Pathfinding complete, route: [{string.Join(" → ", _pathfindTask.Result.Select(x => x.ToString()))}]"));
|
||||
|
||||
var navPoints = _pathfindTask.Result.Skip(1).ToList();
|
||||
if (!IsFlying && !_condition[ConditionFlag.Mounted] && navPoints.Count > 0 &&
|
||||
!_gameFunctions.HasStatusPreventingSprintOrMount())
|
||||
{
|
||||
Vector3 start = _clientState.LocalPlayer?.Position ?? navPoints[0];
|
||||
float actualDistance = 0;
|
||||
foreach (Vector3 end in navPoints)
|
||||
{
|
||||
actualDistance += (start - end).Length();
|
||||
start = end;
|
||||
}
|
||||
|
||||
_pluginLog.Information($"Distance: {actualDistance}");
|
||||
unsafe
|
||||
{
|
||||
// 70 is ~10 seconds of sprint
|
||||
if (actualDistance > 100f &&
|
||||
ActionManager.Instance()->GetActionStatus(ActionType.GeneralAction, 4) == 0)
|
||||
{
|
||||
_pluginLog.Information("Triggering Sprint");
|
||||
ActionManager.Instance()->UseAction(ActionType.GeneralAction, 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_navmeshIpc.MoveTo(navPoints);
|
||||
ResetPathfinding();
|
||||
}
|
||||
else if (_pathfindTask.IsCompleted)
|
||||
@ -60,21 +93,32 @@ internal sealed class MovementController : IDisposable
|
||||
}
|
||||
}
|
||||
|
||||
public void NavigateTo(EMovementType type, Vector3 to, bool fly, float? stopDistance = null)
|
||||
private void PrepareNavigation(EMovementType type, Vector3 to, bool fly, float? stopDistance)
|
||||
{
|
||||
ResetPathfinding();
|
||||
|
||||
|
||||
_gameFunctions.ExecuteCommand("/automove off");
|
||||
|
||||
Destination = to;
|
||||
StopDistance = stopDistance ?? (DefaultStopDistance - 0.2f);
|
||||
IsFlying = fly;
|
||||
}
|
||||
|
||||
public void NavigateTo(EMovementType type, Vector3 to, bool fly, float? stopDistance = null)
|
||||
{
|
||||
PrepareNavigation(type, to, fly, stopDistance);
|
||||
_cancellationTokenSource = new();
|
||||
_cancellationTokenSource.CancelAfter(TimeSpan.FromSeconds(10));
|
||||
_pathfindTask =
|
||||
_navmeshIpc.Pathfind(_clientState.LocalPlayer!.Position, to, fly, _cancellationTokenSource.Token);
|
||||
}
|
||||
|
||||
public void NavigateTo(EMovementType type, List<Vector3> to, bool fly, float? stopDistance)
|
||||
{
|
||||
PrepareNavigation(type, to.Last(), fly, stopDistance);
|
||||
_navmeshIpc.MoveTo(to);
|
||||
}
|
||||
|
||||
public void ResetPathfinding()
|
||||
{
|
||||
if (_cancellationTokenSource != null)
|
||||
|
@ -10,47 +10,69 @@ using Dalamud.Plugin;
|
||||
using Dalamud.Plugin.Services;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.Object;
|
||||
using FFXIVClientStructs.FFXIV.Client.UI.Agent;
|
||||
using Questionable.Data;
|
||||
using Questionable.External;
|
||||
using Questionable.Model.V1;
|
||||
|
||||
namespace Questionable.Controller;
|
||||
|
||||
internal sealed class QuestController
|
||||
{
|
||||
private readonly DalamudPluginInterface _pluginInterface;
|
||||
private readonly IDataManager _dataManager;
|
||||
private readonly IClientState _clientState;
|
||||
private readonly GameFunctions _gameFunctions;
|
||||
private readonly MovementController _movementController;
|
||||
private readonly IPluginLog _pluginLog;
|
||||
private readonly ICondition _condition;
|
||||
private readonly IChatGui _chatGui;
|
||||
private readonly ICommandManager _commandManager;
|
||||
private readonly AetheryteData _aetheryteData;
|
||||
private readonly LifestreamIpc _lifestreamIpc;
|
||||
private readonly TerritoryData _territoryData;
|
||||
private readonly Dictionary<ushort, Quest> _quests = new();
|
||||
|
||||
public QuestController(DalamudPluginInterface pluginInterface, IDataManager dataManager, IClientState clientState,
|
||||
GameFunctions gameFunctions, MovementController movementController, IPluginLog pluginLog, ICondition condition,
|
||||
IChatGui chatGui, ICommandManager commandManager)
|
||||
IChatGui chatGui, AetheryteData aetheryteData, LifestreamIpc lifestreamIpc)
|
||||
{
|
||||
_pluginInterface = pluginInterface;
|
||||
_dataManager = dataManager;
|
||||
_clientState = clientState;
|
||||
_gameFunctions = gameFunctions;
|
||||
_movementController = movementController;
|
||||
_pluginLog = pluginLog;
|
||||
_condition = condition;
|
||||
_chatGui = chatGui;
|
||||
_commandManager = commandManager;
|
||||
_aetheryteData = new AetheryteData(dataManager);
|
||||
_aetheryteData = aetheryteData;
|
||||
_lifestreamIpc = lifestreamIpc;
|
||||
_territoryData = new TerritoryData(dataManager);
|
||||
|
||||
Reload();
|
||||
}
|
||||
|
||||
|
||||
public QuestProgress? CurrentQuest { get; set; }
|
||||
public string? DebugState { get; private set; }
|
||||
public string? Comment { get; private set; }
|
||||
|
||||
public void Reload()
|
||||
{
|
||||
_quests.Clear();
|
||||
|
||||
CurrentQuest = null;
|
||||
DebugState = null;
|
||||
|
||||
#if false
|
||||
LoadFromEmbeddedResources();
|
||||
#endif
|
||||
LoadFromDirectory(new DirectoryInfo(@"E:\ffxiv\Questionable\Questionable\QuestPaths"));
|
||||
LoadFromDirectory(pluginInterface.ConfigDirectory);
|
||||
LoadFromDirectory(_pluginInterface.ConfigDirectory);
|
||||
|
||||
foreach (var (questId, quest) in _quests)
|
||||
{
|
||||
var questData =
|
||||
dataManager.GetExcelSheet<Lumina.Excel.GeneratedSheets.Quest>()!.GetRow((uint)questId + 0x10000);
|
||||
_dataManager.GetExcelSheet<Lumina.Excel.GeneratedSheets.Quest>()!.GetRow((uint)questId + 0x10000);
|
||||
if (questData == null)
|
||||
continue;
|
||||
|
||||
@ -79,9 +101,6 @@ internal sealed class QuestController
|
||||
}
|
||||
#endif
|
||||
|
||||
public QuestProgress? CurrentQuest { get; set; }
|
||||
public string? DebugState { get; set; }
|
||||
|
||||
private void LoadFromDirectory(DirectoryInfo configDirectory)
|
||||
{
|
||||
foreach (FileInfo fileInfo in configDirectory.GetFiles("*.json"))
|
||||
@ -120,6 +139,9 @@ internal sealed class QuestController
|
||||
|
||||
public void Update()
|
||||
{
|
||||
Comment = null;
|
||||
DebugState = null;
|
||||
|
||||
(ushort currentQuestId, byte currentSequence) = _gameFunctions.GetCurrentQuest();
|
||||
if (currentQuestId == 0)
|
||||
{
|
||||
@ -185,7 +207,8 @@ internal sealed class QuestController
|
||||
}
|
||||
|
||||
var step = sequence.Steps[CurrentQuest.Step];
|
||||
DebugState = step.Comment ?? sequence.Comment ?? q.Data.Comment;
|
||||
DebugState = null;
|
||||
Comment = step.Comment ?? sequence.Comment ?? q.Data.Comment;
|
||||
}
|
||||
|
||||
public (QuestSequence? Sequence, QuestStep? Step) GetNextStep()
|
||||
@ -216,8 +239,7 @@ internal sealed class QuestController
|
||||
CurrentQuest = CurrentQuest with
|
||||
{
|
||||
Step = CurrentQuest.Step + 1,
|
||||
AetheryteShortcutUsed = false,
|
||||
AethernetShortcutUsed = false
|
||||
StepProgress = new()
|
||||
};
|
||||
}
|
||||
else
|
||||
@ -225,30 +247,29 @@ internal sealed class QuestController
|
||||
CurrentQuest = CurrentQuest with
|
||||
{
|
||||
Step = 255,
|
||||
AetheryteShortcutUsed = false,
|
||||
AethernetShortcutUsed = false
|
||||
StepProgress = new()
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public void ExecuteNextStep()
|
||||
public unsafe void ExecuteNextStep()
|
||||
{
|
||||
(QuestSequence? seq, QuestStep? step) = GetNextStep();
|
||||
if (seq == null || step == null)
|
||||
return;
|
||||
|
||||
Debug.Assert(CurrentQuest != null, nameof(CurrentQuest) + " != null");
|
||||
if (!CurrentQuest.AetheryteShortcutUsed && step.AetheryteShortcut != null)
|
||||
if (!CurrentQuest.StepProgress.AetheryteShortcutUsed && step.AetheryteShortcut != null)
|
||||
{
|
||||
bool skipTeleport = false;
|
||||
ushort territoryType = _clientState.TerritoryType;
|
||||
if (step.TerritoryId == territoryType)
|
||||
{
|
||||
Vector3 playerPosition = _clientState.LocalPlayer!.Position;
|
||||
if (_aetheryteData.CalculateDistance(playerPosition, territoryType, step.AetheryteShortcut.Value) < 11 ||
|
||||
Vector3 pos = _clientState.LocalPlayer!.Position;
|
||||
if (_aetheryteData.CalculateDistance(pos, territoryType, step.AetheryteShortcut.Value) < 11 ||
|
||||
(step.AethernetShortcut != null &&
|
||||
(_aetheryteData.CalculateDistance(playerPosition, territoryType, step.AethernetShortcut.From) < 11 ||
|
||||
_aetheryteData.CalculateDistance(playerPosition, territoryType, step.AethernetShortcut.To) < 11)))
|
||||
(_aetheryteData.CalculateDistance(pos, territoryType, step.AethernetShortcut.From) < 20 ||
|
||||
_aetheryteData.CalculateDistance(pos, territoryType, step.AethernetShortcut.To) < 20)))
|
||||
{
|
||||
skipTeleport = true;
|
||||
}
|
||||
@ -256,7 +277,10 @@ internal sealed class QuestController
|
||||
|
||||
if (skipTeleport)
|
||||
{
|
||||
CurrentQuest = CurrentQuest with { AetheryteShortcutUsed = true };
|
||||
CurrentQuest = CurrentQuest with
|
||||
{
|
||||
StepProgress = CurrentQuest.StepProgress with { AetheryteShortcutUsed = true }
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -265,7 +289,10 @@ internal sealed class QuestController
|
||||
if (!_gameFunctions.IsAetheryteUnlocked(step.AetheryteShortcut.Value))
|
||||
_chatGui.Print($"[Questionable] Aetheryte {step.AetheryteShortcut.Value} is not unlocked.");
|
||||
else if (_gameFunctions.TeleportAetheryte(step.AetheryteShortcut.Value))
|
||||
CurrentQuest = CurrentQuest with { AetheryteShortcutUsed = true };
|
||||
CurrentQuest = CurrentQuest with
|
||||
{
|
||||
StepProgress = CurrentQuest.StepProgress with { AetheryteShortcutUsed = true }
|
||||
};
|
||||
else
|
||||
_chatGui.Print("[Questionable] Unable to teleport to aetheryte.");
|
||||
}
|
||||
@ -276,7 +303,7 @@ internal sealed class QuestController
|
||||
}
|
||||
}
|
||||
|
||||
if (!CurrentQuest.AethernetShortcutUsed)
|
||||
if (!CurrentQuest.StepProgress.AethernetShortcutUsed)
|
||||
{
|
||||
if (step.AethernetShortcut != null)
|
||||
{
|
||||
@ -291,10 +318,11 @@ internal sealed class QuestController
|
||||
{
|
||||
if (_aetheryteData.CalculateDistance(playerPosition, territoryType, from) < 11)
|
||||
{
|
||||
// unsure if this works across languages
|
||||
_commandManager.ProcessCommand(
|
||||
$"/li {_aetheryteData.AethernetNames[step.AethernetShortcut.To].Replace("The ", "", StringComparison.Ordinal)}");
|
||||
CurrentQuest = CurrentQuest with { AethernetShortcutUsed = true };
|
||||
_lifestreamIpc.Teleport(to);
|
||||
CurrentQuest = CurrentQuest with
|
||||
{
|
||||
StepProgress = CurrentQuest.StepProgress with { AethernetShortcutUsed = true }
|
||||
};
|
||||
}
|
||||
else
|
||||
_movementController.NavigateTo(EMovementType.Quest, _aetheryteData.Locations[from], false,
|
||||
@ -315,30 +343,57 @@ internal sealed class QuestController
|
||||
|
||||
var position = _clientState.LocalPlayer?.Position ?? new Vector3();
|
||||
float actualDistance = (position - step.Position.Value).Length();
|
||||
if (actualDistance > 30f && !_condition[ConditionFlag.Mounted] &&
|
||||
_territoryData.CanUseMount(_clientState.TerritoryType))
|
||||
|
||||
if (step.Mount == true && !_gameFunctions.HasStatusPreventingSprintOrMount())
|
||||
{
|
||||
unsafe
|
||||
if (!_condition[ConditionFlag.Mounted] && _territoryData.CanUseMount(_clientState.TerritoryType))
|
||||
{
|
||||
ActionManager.Instance()->UseAction(ActionType.Mount, 71);
|
||||
if (ActionManager.Instance()->GetActionStatus(ActionType.Mount, 71) == 0)
|
||||
ActionManager.Instance()->UseAction(ActionType.Mount, 71);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (step.Mount == false)
|
||||
{
|
||||
if (_condition[ConditionFlag.Mounted])
|
||||
{
|
||||
_gameFunctions.Unmount();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!step.DisableNavmesh)
|
||||
{
|
||||
if (step.Mount != false && actualDistance > 30f && !_condition[ConditionFlag.Mounted] &&
|
||||
_territoryData.CanUseMount(_clientState.TerritoryType))
|
||||
{
|
||||
if (ActionManager.Instance()->GetActionStatus(ActionType.Mount, 71) == 0)
|
||||
ActionManager.Instance()->UseAction(ActionType.Mount, 71);
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
if (actualDistance > distance)
|
||||
{
|
||||
_movementController.NavigateTo(EMovementType.Quest, step.Position.Value,
|
||||
_gameFunctions.IsFlyingUnlocked(_clientState.TerritoryType), distance);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (actualDistance > distance)
|
||||
else
|
||||
{
|
||||
_movementController.NavigateTo(EMovementType.Quest, step.Position.Value,
|
||||
_gameFunctions.IsFlyingUnlocked(_clientState.TerritoryType), distance);
|
||||
return;
|
||||
if (actualDistance > distance)
|
||||
{
|
||||
_movementController.NavigateTo(EMovementType.Quest, [step.Position.Value],
|
||||
_gameFunctions.IsFlyingUnlocked(_clientState.TerritoryType), distance);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (step.InteractionType)
|
||||
{
|
||||
case EInteractionType.Interact:
|
||||
case EInteractionType.AttuneAetheryte:
|
||||
case EInteractionType.AttuneAethernetShard:
|
||||
case EInteractionType.AttuneAetherCurrent:
|
||||
if (step.DataId != null)
|
||||
{
|
||||
_gameFunctions.InteractWith(step.DataId.Value);
|
||||
@ -347,10 +402,81 @@ internal sealed class QuestController
|
||||
|
||||
break;
|
||||
|
||||
case EInteractionType.AttuneAetheryte:
|
||||
if (step.DataId != null)
|
||||
{
|
||||
if (!_gameFunctions.IsAetheryteUnlocked((EAetheryteLocation)step.DataId.Value))
|
||||
_gameFunctions.InteractWith(step.DataId.Value);
|
||||
|
||||
IncreaseStepCount();
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case EInteractionType.AttuneAetherCurrent:
|
||||
if (step.DataId != null)
|
||||
{
|
||||
_pluginLog.Information(
|
||||
$"{step.AetherCurrentId} → {_gameFunctions.IsAetherCurrentUnlocked(step.AetherCurrentId.GetValueOrDefault())}");
|
||||
if (step.AetherCurrentId == null ||
|
||||
!_gameFunctions.IsAetherCurrentUnlocked(step.AetherCurrentId.Value))
|
||||
_gameFunctions.InteractWith(step.DataId.Value);
|
||||
|
||||
IncreaseStepCount();
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case EInteractionType.WalkTo:
|
||||
IncreaseStepCount();
|
||||
break;
|
||||
|
||||
case EInteractionType.UseItem:
|
||||
if (step is { DataId: not null, ItemId: not null })
|
||||
{
|
||||
if (_gameFunctions.Unmount())
|
||||
return;
|
||||
|
||||
_gameFunctions.UseItem(step.DataId.Value, step.ItemId.Value);
|
||||
IncreaseStepCount();
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case EInteractionType.Combat:
|
||||
if (step.EnemySpawnType != null)
|
||||
{
|
||||
if (_gameFunctions.Unmount())
|
||||
return;
|
||||
|
||||
if (step.DataId != null && step.EnemySpawnType == EEnemySpawnType.AfterInteraction)
|
||||
_gameFunctions.InteractWith(step.DataId.Value);
|
||||
|
||||
// next sequence should trigger automatically
|
||||
IncreaseStepCount();
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case EInteractionType.Emote:
|
||||
if (step is { DataId: not null, Emote: not null })
|
||||
{
|
||||
_gameFunctions.UseEmote(step.DataId.Value, step.Emote.Value);
|
||||
IncreaseStepCount();
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case EInteractionType.WaitForObjectAtPosition:
|
||||
if (step is { DataId: not null, Position: not null } &&
|
||||
!_gameFunctions.IsObbjectAtPosition(step.DataId.Value, step.Position.Value))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
IncreaseStepCount();
|
||||
break;
|
||||
|
||||
default:
|
||||
_pluginLog.Warning($"Action '{step.InteractionType}' is not implemented");
|
||||
break;
|
||||
@ -361,6 +487,15 @@ internal sealed class QuestController
|
||||
Quest Quest,
|
||||
byte Sequence,
|
||||
int Step,
|
||||
StepProgress StepProgress)
|
||||
{
|
||||
public QuestProgress(Quest quest, byte sequence, int step)
|
||||
: this(quest, sequence, step, new StepProgress())
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public sealed record StepProgress(
|
||||
bool AetheryteShortcutUsed = false,
|
||||
bool AethernetShortcutUsed = false);
|
||||
}
|
||||
|
@ -40,7 +40,51 @@ internal sealed class AetheryteData
|
||||
{ EAetheryteLocation.LimsaMarauder, new(-5.1728516f, 44.63257f, -218.06671f) },
|
||||
{ EAetheryteLocation.LimsaHawkersAlley, new(-213.61108f, 16.739136f, 51.80432f) },
|
||||
|
||||
// ... missing a few
|
||||
{ EAetheryteLocation.Ishgard, new(-63.98114f, 11.154297f, 43.9917f) },
|
||||
{ EAetheryteLocation.IshgardForgottenKnight, new(45.792236f, 24.551636f, 0.99176025f) },
|
||||
{ EAetheryteLocation.IshgardSkysteelManufactory, new(-111.436646f, 16.128723f, -27.054321f) },
|
||||
{ EAetheryteLocation.IshgardBrume, new(49.42395f, -11.154419f, 66.69714f) },
|
||||
{ EAetheryteLocation.IshgardAthenaeumAstrologicum, new(133.37903f, -8.86554f, -64.77466f) },
|
||||
{ EAetheryteLocation.IshgardJeweledCrozier, new(-134.6914f, -11.795227f, -15.396423f) },
|
||||
{ EAetheryteLocation.IshgardSaintReymanaudsCathedral, new(-77.958374f, 10.60498f, -126.54315f) },
|
||||
{ EAetheryteLocation.IshgardTribunal, new(78.01941f, 11.001709f, -126.51257f) },
|
||||
{ EAetheryteLocation.IshgardLastVigil, new(0.015197754f, 16.525452f, -32.51703f) },
|
||||
|
||||
{ EAetheryteLocation.Idyllshire, new(71.94617f, 211.26111f, -18.905945f) },
|
||||
{ EAetheryteLocation.IdyllshireWest, new(-75.48645f, 210.22351f, -21.347473f) },
|
||||
|
||||
{ EAetheryteLocation.RhalgrsReach, new(78.23291f, 1.9683228f, 97.45935f) },
|
||||
{ EAetheryteLocation.RhalgrsReachWest, new(-84.275635f, 0.503479f, 9.323181f) },
|
||||
{ EAetheryteLocation.RhalgrsReachNorthEast, new(101.24353f, 3.463745f, -115.46509f) },
|
||||
|
||||
{ EAetheryteLocation.Kugane, new(47.501343f, 8.438171f, -37.30841f) },
|
||||
{ EAetheryteLocation.KuganeShiokazeHostelry, new(-73.16705f, -6.088379f, -77.77527f) },
|
||||
{ EAetheryteLocation.KuganePier1, new(-113.57294f, -3.8911133f, 155.41309f) },
|
||||
{ EAetheryteLocation.KuganeThavnairianConsulate, new(27.17627f, 9.048584f, 141.58838f) },
|
||||
{ EAetheryteLocation.KuganeMarkets, new(26.687988f, 4.92865f, 73.3501f) },
|
||||
{ EAetheryteLocation.KuganeBokairoInn, new(-76.00525f, 19.058472f, -161.18109f) },
|
||||
{ EAetheryteLocation.KuganeRubyBazaar, new(132.40247f, 12.954895f, 83.02429f) },
|
||||
{ EAetheryteLocation.KuganeSekiseigumiBarracks, new(119.09656f, 13.01593f, -92.881714f) },
|
||||
{ EAetheryteLocation.KuganeRakuzaDistrict, new(24.64331f, 7.003784f, -152.97174f) },
|
||||
|
||||
{ EAetheryteLocation.FringesCastrumOriens, new(-629.11426f, 132.89075f, -509.14783f) },
|
||||
{ EAetheryteLocation.FringesPeeringStones, new(415.3047f, 117.357056f, 246.75354f) },
|
||||
{ EAetheryteLocation.PeaksAlaGannha, new(114.579956f, 120.10376f, -747.06647f) },
|
||||
{ EAetheryteLocation.PeaksAlaGhiri, new(-271.3817f, 259.87634f, 748.86694f) },
|
||||
{ EAetheryteLocation.LochsPortaPraetoria, new(-652.0333f, 53.391357f, -16.006714f) },
|
||||
{ EAetheryteLocation.LochsAlaMhiganQuarter, new(612.4512f, 84.45862f, 656.82446f) },
|
||||
{ EAetheryteLocation.RubySeaTamamizu, new(358.72437f, -118.05908f, -263.4165f) },
|
||||
{ EAetheryteLocation.RubySeaOnokoro, new(88.181885f, 4.135132f, -583.3677f) },
|
||||
{ EAetheryteLocation.YanxiaNamai, new(432.66956f, 73.07532f, -90.74542f) },
|
||||
{ EAetheryteLocation.YanxiaHouseOfTheFierce, new(246.02112f, 9.079041f, -401.3581f) },
|
||||
{ EAetheryteLocation.AzimSteppeReunion, new(556.1454f, -16.800232f, 340.10828f) },
|
||||
{ EAetheryteLocation.AzimSteppeDawnThrone, new(78.26355f, 119.37134f, 36.301147f) },
|
||||
{ EAetheryteLocation.AzimSteppeDhoroIloh, new(-754.63495f, 131.2428f, 116.5636f) },
|
||||
|
||||
{ EAetheryteLocation.DomanEnclave, new(42.648926f, 1.4190674f, -14.8776245f) },
|
||||
{ EAetheryteLocation.DomanEnclaveNorthern, new(8.987488f, 0.8086548f, -105.85187f) },
|
||||
{ EAetheryteLocation.DomanEnclaveSouthern, new(-61.57019f, 0.77819824f, 90.684326f) },
|
||||
{ EAetheryteLocation.DomanEnclaveDocks, new(96.269165f, -3.4332886f, 81.01013f) },
|
||||
|
||||
{ EAetheryteLocation.Crystarium, new(-65.0188f, 4.5318604f, 0.015197754f) },
|
||||
{ EAetheryteLocation.CrystariumMarkets, new(-6.149414f, -7.736328f, 148.72961f) },
|
||||
@ -57,7 +101,21 @@ internal sealed class AetheryteData
|
||||
{ EAetheryteLocation.EulmoreGloryGate, new(6.9122925f, 6.240906f, -56.351562f) },
|
||||
{ EAetheryteLocation.EulmoreSoutheastDerelict, new(71.82422f, -10.391418f, 65.32385f) },
|
||||
|
||||
// ... missing a few
|
||||
{ EAetheryteLocation.LakelandFortJobb, new(753.7803f, 24.338135f, -28.82434f) },
|
||||
{ EAetheryteLocation.LakelandOstallImperative, new(-735.01184f, 53.391357f, -230.02979f) },
|
||||
{ EAetheryteLocation.KholusiaStilltide, new(668.32983f, 29.465088f, 289.17358f) },
|
||||
{ EAetheryteLocation.KholusiaWright, new(-244.00702f, 20.736938f, 385.45813f) },
|
||||
{ EAetheryteLocation.KholusiaTomra, new(-426.38287f, 419.27222f, -623.5294f) },
|
||||
{ EAetheryteLocation.AmhAraengMordSouq, new(246.38745f, 12.985352f, -220.29456f) },
|
||||
{ EAetheryteLocation.AmhAraengInnAtJourneysHead, new(399.0996f, -24.521301f, 307.97278f) },
|
||||
{ EAetheryteLocation.AmhAraengTwine, new(-511.3451f, 47.989624f, -212.604f) },
|
||||
{ EAetheryteLocation.RaktikaSlitherbough, new(-103.4104f, -19.333252f, 297.23047f) },
|
||||
{ EAetheryteLocation.RaktikaFanow, new(382.77246f, 21.042175f, -194.11005f) },
|
||||
{ EAetheryteLocation.IlMhegLydhaLran, new(-344.71655f, 48.722046f, 512.2606f) },
|
||||
{ EAetheryteLocation.IlMhegPiaEnni, new(-72.55664f, 103.95972f, -857.35864f) },
|
||||
{ EAetheryteLocation.IlMhegWolekdorf, new(380.51416f, 87.20532f, -687.2511f) },
|
||||
{ EAetheryteLocation.TempestOndoCups, new(561.76074f, 352.62073f, -199.17603f) },
|
||||
{ EAetheryteLocation.TempestMacarensesAngle, new(-141.74109f, -280.5371f, 218.00562f) },
|
||||
|
||||
{ EAetheryteLocation.OldSharlayan, new(0.07623291f, 4.8065186f, -0.10687256f) },
|
||||
{ EAetheryteLocation.OldSharlayanStudium, new(-291.1574f, 20.004517f, -74.143616f) },
|
||||
|
26
Questionable/External/LifestreamIpc.cs
vendored
Normal file
26
Questionable/External/LifestreamIpc.cs
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
using Dalamud.Plugin;
|
||||
using Dalamud.Plugin.Ipc;
|
||||
using Questionable.Data;
|
||||
using Questionable.Model.V1;
|
||||
|
||||
namespace Questionable.External;
|
||||
|
||||
internal sealed class LifestreamIpc
|
||||
{
|
||||
private readonly AetheryteData _aetheryteData;
|
||||
private readonly ICallGateSubscriber<string, bool> _aethernetTeleport;
|
||||
|
||||
public LifestreamIpc(DalamudPluginInterface pluginInterface, AetheryteData aetheryteData)
|
||||
{
|
||||
_aetheryteData = aetheryteData;
|
||||
_aethernetTeleport = pluginInterface.GetIpcSubscriber<string, bool>("Lifestream.AethernetTeleport");
|
||||
}
|
||||
|
||||
public bool Teleport(EAetheryteLocation aetheryteLocation)
|
||||
{
|
||||
if (!_aetheryteData.AethernetNames.TryGetValue(aetheryteLocation, out string? name))
|
||||
return false;
|
||||
|
||||
return _aethernetTeleport.InvokeFunc(name);
|
||||
}
|
||||
}
|
@ -7,10 +7,13 @@ using System.Numerics;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using Dalamud.Game;
|
||||
using Dalamud.Game.ClientState.Conditions;
|
||||
using Dalamud.Game.ClientState.Objects;
|
||||
using Dalamud.Game.ClientState.Objects.Types;
|
||||
using Dalamud.Plugin.Services;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.Control;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.Object;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.UI;
|
||||
using FFXIVClientStructs.FFXIV.Client.System.Framework;
|
||||
using FFXIVClientStructs.FFXIV.Client.System.Memory;
|
||||
@ -18,6 +21,8 @@ using FFXIVClientStructs.FFXIV.Client.System.String;
|
||||
using FFXIVClientStructs.FFXIV.Client.UI.Agent;
|
||||
using Lumina.Excel.GeneratedSheets;
|
||||
using Questionable.Model.V1;
|
||||
using BattleChara = FFXIVClientStructs.FFXIV.Client.Game.Character.BattleChara;
|
||||
using GameObject = Dalamud.Game.ClientState.Objects.Types.GameObject;
|
||||
|
||||
namespace Questionable;
|
||||
|
||||
@ -34,15 +39,19 @@ internal sealed unsafe class GameFunctions
|
||||
private readonly ProcessChatBoxDelegate _processChatBox;
|
||||
private readonly delegate* unmanaged<Utf8String*, int, IntPtr, void> _sanitiseString;
|
||||
private readonly ReadOnlyDictionary<ushort, byte> _territoryToAetherCurrentCompFlgSet;
|
||||
private readonly ReadOnlyDictionary<EEmote, string> _emoteCommands;
|
||||
|
||||
private readonly IObjectTable _objectTable;
|
||||
private readonly ITargetManager _targetManager;
|
||||
private readonly ICondition _condition;
|
||||
private readonly IPluginLog _pluginLog;
|
||||
|
||||
public GameFunctions(IDataManager dataManager, IObjectTable objectTable, ISigScanner sigScanner, ITargetManager targetManager, IPluginLog pluginLog)
|
||||
public GameFunctions(IDataManager dataManager, IObjectTable objectTable, ISigScanner sigScanner,
|
||||
ITargetManager targetManager, ICondition condition, IPluginLog pluginLog)
|
||||
{
|
||||
_objectTable = objectTable;
|
||||
_targetManager = targetManager;
|
||||
_condition = condition;
|
||||
_pluginLog = pluginLog;
|
||||
_processChatBox =
|
||||
Marshal.GetDelegateForFunctionPointer<ProcessChatBoxDelegate>(sigScanner.ScanText(Signatures.SendChat));
|
||||
@ -54,6 +63,13 @@ internal sealed unsafe class GameFunctions
|
||||
.Where(x => x.Unknown32 > 0)
|
||||
.ToDictionary(x => (ushort)x.RowId, x => x.Unknown32)
|
||||
.AsReadOnly();
|
||||
_emoteCommands = dataManager.GetExcelSheet<Emote>()!
|
||||
.Where(x => x.RowId > 0)
|
||||
.Where(x => x.TextCommand != null && x.TextCommand.Value != null)
|
||||
.Select(x => (x.RowId, Command: x.TextCommand.Value!.Command?.ToString()))
|
||||
.Where(x => x.Command != null && x.Command.StartsWith('/'))
|
||||
.ToDictionary(x => (EEmote)x.RowId, x => x.Command!)
|
||||
.AsReadOnly();
|
||||
}
|
||||
|
||||
public (ushort CurrentQuest, byte Sequence) GetCurrentQuest()
|
||||
@ -92,7 +108,7 @@ internal sealed unsafe class GameFunctions
|
||||
return false;
|
||||
}
|
||||
|
||||
for (ulong i = 0; i < telepo->TeleportList.Size(); ++ i)
|
||||
for (ulong i = 0; i < telepo->TeleportList.Size(); ++i)
|
||||
{
|
||||
var data = telepo->TeleportList.Get(i);
|
||||
if (data.AetheryteId == aetheryteId)
|
||||
@ -134,6 +150,13 @@ internal sealed unsafe class GameFunctions
|
||||
playerState->IsAetherCurrentZoneComplete(aetherCurrentCompFlgSet);
|
||||
}
|
||||
|
||||
public bool IsAetherCurrentUnlocked(uint aetherCurrentId)
|
||||
{
|
||||
var playerState = PlayerState.Instance();
|
||||
return playerState != null &&
|
||||
playerState->IsAetherCurrentUnlocked(aetherCurrentId);
|
||||
}
|
||||
|
||||
public void ExecuteCommand(string command)
|
||||
{
|
||||
if (!command.StartsWith('/'))
|
||||
@ -262,19 +285,81 @@ internal sealed unsafe class GameFunctions
|
||||
|
||||
#endregion
|
||||
|
||||
public void InteractWith(uint dataId)
|
||||
private GameObject? FindObjectByDataId(uint dataId)
|
||||
{
|
||||
foreach (var gameObject in _objectTable)
|
||||
{
|
||||
if (gameObject.DataId == dataId)
|
||||
{
|
||||
_targetManager.Target = null;
|
||||
_targetManager.Target = gameObject;
|
||||
|
||||
TargetSystem.Instance()->InteractWithObject(
|
||||
(FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)gameObject.Address, false);
|
||||
return;
|
||||
return gameObject;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void InteractWith(uint dataId)
|
||||
{
|
||||
GameObject? gameObject = FindObjectByDataId(dataId);
|
||||
if (gameObject != null)
|
||||
{
|
||||
_targetManager.Target = null;
|
||||
_targetManager.Target = gameObject;
|
||||
|
||||
TargetSystem.Instance()->InteractWithObject(
|
||||
(FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)gameObject.Address, false);
|
||||
}
|
||||
}
|
||||
|
||||
public void UseItem(uint dataId, uint itemId)
|
||||
{
|
||||
GameObject? gameObject = FindObjectByDataId(dataId);
|
||||
if (gameObject != null)
|
||||
{
|
||||
_targetManager.Target = gameObject;
|
||||
AgentInventoryContext.Instance()->UseItem(itemId);
|
||||
}
|
||||
}
|
||||
|
||||
public void UseEmote(uint dataId, EEmote emote)
|
||||
{
|
||||
GameObject? gameObject = FindObjectByDataId(dataId);
|
||||
if (gameObject != null)
|
||||
{
|
||||
_targetManager.Target = gameObject;
|
||||
ExecuteCommand($"{_emoteCommands[emote]} motion");
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsObbjectAtPosition(uint dataId, Vector3 position)
|
||||
{
|
||||
GameObject? gameObject = FindObjectByDataId(dataId);
|
||||
return gameObject != null && (gameObject.Position - position).Length() < 0.05f;
|
||||
}
|
||||
|
||||
public bool HasStatusPreventingSprintOrMount()
|
||||
{
|
||||
var gameObject = GameObjectManager.GetGameObjectByIndex(0);
|
||||
if (gameObject != null && gameObject->ObjectKind == 1)
|
||||
{
|
||||
var battleChara = (BattleChara*)gameObject;
|
||||
StatusManager* statusManager = battleChara->GetStatusManager;
|
||||
return statusManager->HasStatus(565);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool Unmount()
|
||||
{
|
||||
if (_condition[ConditionFlag.Mounted])
|
||||
{
|
||||
if (ActionManager.Instance()->GetActionStatus(ActionType.GeneralAction, 23) == 0)
|
||||
ActionManager.Instance()->UseAction(ActionType.GeneralAction, 23);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ public sealed class AethernetShortcutConverter : JsonConverter<AethernetShortcut
|
||||
{ EAetheryteLocation.LimsaAirship, "[Limsa Lominsa] Airship Landing" },
|
||||
{ EAetheryteLocation.Gridania, "[Gridania] Aetheryte Plaza" },
|
||||
{ EAetheryteLocation.GridaniaArcher, "[Gridania] Archer's Guild" },
|
||||
{ EAetheryteLocation.GridaniaLeatherworker, "[Gridania] Leatherworker's Guld & Shaded Bower" },
|
||||
{ EAetheryteLocation.GridaniaLeatherworker, "[Gridania] Leatherworker's Guild & Shaded Bower" },
|
||||
{ EAetheryteLocation.GridaniaLancer, "[Gridania] Lancer's Guild" },
|
||||
{ EAetheryteLocation.GridaniaConjurer, "[Gridania] Conjurer's Guild" },
|
||||
{ EAetheryteLocation.GridaniaBotanist, "[Gridania] Botanist's Guild" },
|
||||
|
@ -6,7 +6,7 @@ using System.Text.Json.Serialization;
|
||||
|
||||
namespace Questionable.Model.V1.Converter;
|
||||
|
||||
public class AetheryteConverter : JsonConverter<EAetheryteLocation>
|
||||
public sealed class AetheryteConverter : JsonConverter<EAetheryteLocation>
|
||||
{
|
||||
private static readonly Dictionary<EAetheryteLocation, string> EnumToString = new()
|
||||
{
|
||||
@ -14,6 +14,7 @@ public class AetheryteConverter : JsonConverter<EAetheryteLocation>
|
||||
{ EAetheryteLocation.Gridania, "Gridania" },
|
||||
{ EAetheryteLocation.Uldah, "Ul'dah" },
|
||||
{ EAetheryteLocation.Ishgard, "Ishgard" },
|
||||
{ EAetheryteLocation.Idyllshire, "Idyllshire" },
|
||||
|
||||
{ EAetheryteLocation.RhalgrsReach, "Rhalgr's Reach" },
|
||||
{ EAetheryteLocation.FringesCastrumOriens, "Fringes - Castrum Oriens" },
|
||||
@ -31,8 +32,6 @@ public class AetheryteConverter : JsonConverter<EAetheryteLocation>
|
||||
{ EAetheryteLocation.AzimSteppeDawnThrone, "Azim Steppe - Dawn Throne" },
|
||||
{ EAetheryteLocation.AzimSteppeDhoroIloh, "Azim Steppe - Dhoro Iloh" },
|
||||
{ EAetheryteLocation.DomanEnclave, "Doman Enclave" },
|
||||
{ EAetheryteLocation.DomamEnclaveNorthern, "Doman Enclave - Northern Enclave" },
|
||||
{ EAetheryteLocation.DomamEnclaveSouthern, "Doman Enclave - Southern Enclave" },
|
||||
|
||||
{ EAetheryteLocation.Crystarium, "Crystarium" },
|
||||
{ EAetheryteLocation.Eulmore, "Eulmore" },
|
||||
|
40
Questionable/Model/V1/Converter/EmoteConverter.cs
Normal file
40
Questionable/Model/V1/Converter/EmoteConverter.cs
Normal file
@ -0,0 +1,40 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Questionable.Model.V1.Converter;
|
||||
|
||||
public class EmoteConverter : JsonConverter<EEmote>
|
||||
{
|
||||
private static readonly Dictionary<EEmote, string> EnumToString = new()
|
||||
{
|
||||
{ EEmote.Stretch, "stretch" },
|
||||
{ EEmote.Wave, "wave" },
|
||||
{ EEmote.Rally, "rally" },
|
||||
{ EEmote.Deny, "deny" },
|
||||
};
|
||||
|
||||
private static readonly Dictionary<string, EEmote> StringToEnum =
|
||||
EnumToString.ToDictionary(x => x.Value, x => x.Key);
|
||||
|
||||
public override EEmote Read(ref Utf8JsonReader reader, Type typeToConvert,
|
||||
JsonSerializerOptions options)
|
||||
{
|
||||
if (reader.TokenType != JsonTokenType.String)
|
||||
throw new JsonException();
|
||||
|
||||
string? str = reader.GetString();
|
||||
if (str == null)
|
||||
throw new JsonException();
|
||||
|
||||
return StringToEnum.TryGetValue(str, out EEmote value) ? value : throw new JsonException();
|
||||
}
|
||||
|
||||
public override void Write(Utf8JsonWriter writer, EEmote value, JsonSerializerOptions options)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(writer);
|
||||
writer.WriteStringValue(EnumToString[value]);
|
||||
}
|
||||
}
|
38
Questionable/Model/V1/Converter/EnemySpawnTypeConverter.cs
Normal file
38
Questionable/Model/V1/Converter/EnemySpawnTypeConverter.cs
Normal file
@ -0,0 +1,38 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Questionable.Model.V1.Converter;
|
||||
|
||||
public class EnemySpawnTypeConverter : JsonConverter<EEnemySpawnType>
|
||||
{
|
||||
private static readonly Dictionary<EEnemySpawnType, string> EnumToString = new()
|
||||
{
|
||||
{ EEnemySpawnType.AfterInteraction, "AfterInteraction" },
|
||||
{ EEnemySpawnType.AutoOnEnterArea, "AutoOnEnterArea" },
|
||||
};
|
||||
|
||||
private static readonly Dictionary<string, EEnemySpawnType> StringToEnum =
|
||||
EnumToString.ToDictionary(x => x.Value, x => x.Key);
|
||||
|
||||
public override EEnemySpawnType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
if (reader.TokenType != JsonTokenType.String)
|
||||
throw new JsonException();
|
||||
|
||||
string? str = reader.GetString();
|
||||
if (str == null)
|
||||
throw new JsonException();
|
||||
|
||||
return StringToEnum.TryGetValue(str, out EEnemySpawnType value) ? value : throw new JsonException();
|
||||
}
|
||||
|
||||
public override void Write(Utf8JsonWriter writer, EEnemySpawnType value, JsonSerializerOptions options)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(writer);
|
||||
writer.WriteStringValue(EnumToString[value]);
|
||||
}
|
||||
|
||||
}
|
@ -12,12 +12,13 @@ public sealed class InteractionTypeConverter : JsonConverter<EInteractionType>
|
||||
{
|
||||
{ EInteractionType.Interact, "Interact" },
|
||||
{ EInteractionType.WalkTo, "WalkTo" },
|
||||
{ EInteractionType.AttuneAethernetShard, "AttuneAethenetShard" },
|
||||
{ EInteractionType.AttuneAethernetShard, "AttuneAethernetShard" },
|
||||
{ EInteractionType.AttuneAetheryte, "AttuneAetheryte" },
|
||||
{ EInteractionType.AttuneAetherCurrent, "AttuneAetherCurrent" },
|
||||
{ EInteractionType.Combat, "Combat" },
|
||||
{ EInteractionType.UseItem, "UseItem" },
|
||||
{ EInteractionType.Emote, "Emote" },
|
||||
{ EInteractionType.WaitForObjectAtPosition, "WaitForNpcAtPosition" },
|
||||
{ EInteractionType.ManualAction, "ManualAction" }
|
||||
};
|
||||
|
||||
|
@ -45,7 +45,7 @@ public enum EAetheryteLocation
|
||||
IshgardLastVigil = 87,
|
||||
|
||||
Idyllshire = 75,
|
||||
IdyllshireWest = 76,
|
||||
IdyllshireWest = 90,
|
||||
|
||||
RhalgrsReach = 104,
|
||||
RhalgrsReachWest = 121,
|
||||
@ -77,8 +77,9 @@ public enum EAetheryteLocation
|
||||
AzimSteppeDhoroIloh = 128,
|
||||
|
||||
DomanEnclave = 127,
|
||||
DomamEnclaveNorthern = 129,
|
||||
DomamEnclaveSouthern = 130,
|
||||
DomanEnclaveNorthern = 129,
|
||||
DomanEnclaveSouthern = 130,
|
||||
DomanEnclaveDocks = 162,
|
||||
|
||||
Crystarium = 133,
|
||||
CrystariumMarkets = 149,
|
||||
@ -101,15 +102,15 @@ public enum EAetheryteLocation
|
||||
KholusiaWright = 138,
|
||||
KholusiaTomra = 139,
|
||||
AmhAraengMordSouq = 140,
|
||||
AmhAraengInnAtJourneysHead = 141,
|
||||
AmhAraengTwine = 142,
|
||||
RaktikaSlitherbough = 143,
|
||||
RaktikaFanow = 144,
|
||||
IlMhegLydhaLran = 145,
|
||||
IlMhegPiaEnni = 146,
|
||||
IlMhegWolekdorf = 147,
|
||||
TempestOndoCups = 148,
|
||||
TempestMacarensesAngle = 156,
|
||||
AmhAraengInnAtJourneysHead = 161,
|
||||
AmhAraengTwine = 141,
|
||||
RaktikaSlitherbough = 142,
|
||||
RaktikaFanow = 143,
|
||||
IlMhegLydhaLran = 144,
|
||||
IlMhegPiaEnni = 145,
|
||||
IlMhegWolekdorf = 146,
|
||||
TempestOndoCups = 147,
|
||||
TempestMacarensesAngle = 148,
|
||||
|
||||
OldSharlayan = 182,
|
||||
OldSharlayanStudium = 184,
|
||||
|
11
Questionable/Model/V1/EEmote.cs
Normal file
11
Questionable/Model/V1/EEmote.cs
Normal file
@ -0,0 +1,11 @@
|
||||
namespace Questionable.Model.V1;
|
||||
|
||||
public enum EEmote
|
||||
{
|
||||
None = 0,
|
||||
|
||||
Stretch = 37,
|
||||
Wave = 16,
|
||||
Rally = 34,
|
||||
Deny = 25,
|
||||
}
|
8
Questionable/Model/V1/EEnemySpawnType.cs
Normal file
8
Questionable/Model/V1/EEnemySpawnType.cs
Normal file
@ -0,0 +1,8 @@
|
||||
namespace Questionable.Model.V1;
|
||||
|
||||
public enum EEnemySpawnType
|
||||
{
|
||||
None = 0,
|
||||
AfterInteraction,
|
||||
AutoOnEnterArea,
|
||||
}
|
@ -10,5 +10,6 @@ public enum EInteractionType
|
||||
Combat,
|
||||
UseItem,
|
||||
Emote,
|
||||
WaitForObjectAtPosition,
|
||||
ManualAction
|
||||
}
|
||||
|
@ -18,6 +18,8 @@ public class QuestStep
|
||||
public float? StopDistance { get; set; }
|
||||
public ushort TerritoryId { get; set; }
|
||||
public bool Disabled { get; set; }
|
||||
public bool DisableNavmesh { get; set; }
|
||||
public bool? Mount { get; set; }
|
||||
public string? Comment { get; set; }
|
||||
|
||||
[JsonConverter(typeof(AetheryteConverter))]
|
||||
@ -25,4 +27,15 @@ public class QuestStep
|
||||
|
||||
[JsonConverter(typeof(AethernetShortcutConverter))]
|
||||
public AethernetShortcut? AethernetShortcut { get; set; }
|
||||
public uint? AetherCurrentId { get; set; }
|
||||
|
||||
public uint? ItemId { get; set; }
|
||||
|
||||
[JsonConverter(typeof(EmoteConverter))]
|
||||
public EEmote? Emote { get; set; }
|
||||
|
||||
[JsonConverter(typeof(EnemySpawnTypeConverter))]
|
||||
public EEnemySpawnType? EnemySpawnType { get; set; }
|
||||
|
||||
public IList<uint>? KillEnemyDataIds { get; set; }
|
||||
}
|
||||
|
@ -58,7 +58,7 @@
|
||||
"Z": 127.753
|
||||
},
|
||||
"TerritoryId": 962,
|
||||
"InteractionType": "AttuneAethenetShard"
|
||||
"InteractionType": "AttuneAethernetShard"
|
||||
},
|
||||
{
|
||||
"DataId": 1038578,
|
||||
@ -76,6 +76,15 @@
|
||||
{
|
||||
"Sequence": 4,
|
||||
"Steps": [
|
||||
{
|
||||
"Position": {
|
||||
"X": -8.38828,
|
||||
"Y": 3.2249968,
|
||||
"Z": 9.224017
|
||||
},
|
||||
"TerritoryId": 962,
|
||||
"InteractionType": "WalkTo"
|
||||
},
|
||||
{
|
||||
"DataId": 1038578,
|
||||
"Position": {
|
||||
@ -127,6 +136,15 @@
|
||||
"TerritoryId": 962,
|
||||
"InteractionType": "WalkTo"
|
||||
},
|
||||
{
|
||||
"Position": {
|
||||
"X": 96.67595,
|
||||
"Y": 15.025446,
|
||||
"Z": -134.08261
|
||||
},
|
||||
"TerritoryId": 962,
|
||||
"InteractionType": "WalkTo"
|
||||
},
|
||||
{
|
||||
"DataId": 1038578,
|
||||
"Position": {
|
||||
@ -150,9 +168,8 @@
|
||||
"Y": 41.367188,
|
||||
"Z": -156.6034
|
||||
},
|
||||
"StopDistance": 0.25,
|
||||
"TerritoryId": 962,
|
||||
"InteractionType": "AttuneAethenetShard"
|
||||
"InteractionType": "AttuneAethernetShard"
|
||||
},
|
||||
{
|
||||
"DataId": 1038578,
|
||||
@ -161,6 +178,7 @@
|
||||
"Y": 18.800978,
|
||||
"Z": -142.65858
|
||||
},
|
||||
"StopDistance": 0.25,
|
||||
"TerritoryId": 962,
|
||||
"InteractionType": "Interact"
|
||||
}
|
||||
@ -177,7 +195,7 @@
|
||||
"Z": -118.73047
|
||||
},
|
||||
"TerritoryId": 962,
|
||||
"InteractionType": "AttuneAethenetShard"
|
||||
"InteractionType": "AttuneAethernetShard"
|
||||
},
|
||||
{
|
||||
"DataId": 188,
|
||||
@ -187,7 +205,7 @@
|
||||
"Z": 13.77887
|
||||
},
|
||||
"TerritoryId": 962,
|
||||
"InteractionType": "AttuneAethenetShard"
|
||||
"InteractionType": "AttuneAethernetShard"
|
||||
},
|
||||
{
|
||||
"DataId": 1038578,
|
||||
|
@ -38,7 +38,7 @@
|
||||
"Z": 29.709229
|
||||
},
|
||||
"TerritoryId": 962,
|
||||
"InteractionType": "AttuneAethenetShard"
|
||||
"InteractionType": "AttuneAethernetShard"
|
||||
},
|
||||
{
|
||||
"DataId": 184,
|
||||
@ -48,7 +48,7 @@
|
||||
"Z": -74.143616
|
||||
},
|
||||
"TerritoryId": 962,
|
||||
"InteractionType": "AttuneAethenetShard"
|
||||
"InteractionType": "AttuneAethernetShard"
|
||||
},
|
||||
{
|
||||
"DataId": 1038675,
|
||||
@ -167,6 +167,7 @@
|
||||
"Y": 19.003881,
|
||||
"Z": 13.321045
|
||||
},
|
||||
"StopDistance": 5,
|
||||
"TerritoryId": 962,
|
||||
"InteractionType": "Interact"
|
||||
}
|
||||
|
@ -12,6 +12,7 @@
|
||||
"Y": 19.003874,
|
||||
"Z": 18.966919
|
||||
},
|
||||
"StopDistance": 5,
|
||||
"TerritoryId": 962,
|
||||
"InteractionType": "Interact"
|
||||
}
|
||||
|
@ -42,6 +42,7 @@
|
||||
"Y": 186.03699,
|
||||
"Z": -740.9324
|
||||
},
|
||||
"StopDistance": 1,
|
||||
"TerritoryId": 956,
|
||||
"InteractionType": "Combat",
|
||||
"EnemySpawnType": "AutoOnEnterArea",
|
||||
@ -77,6 +78,7 @@
|
||||
"Z": -595.69696
|
||||
},
|
||||
"TerritoryId": 956,
|
||||
"StopDistance": 1,
|
||||
"InteractionType": "Combat",
|
||||
"EnemySpawnType": "AutoOnEnterArea",
|
||||
"KillEnemyDataIds": [
|
||||
@ -97,13 +99,23 @@
|
||||
"Z": -595.69696
|
||||
},
|
||||
"TerritoryId": 956,
|
||||
"InteractionType": "UseItem"
|
||||
"InteractionType": "UseItem",
|
||||
"ItemId": 2003129
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Sequence": 6,
|
||||
"Steps": [
|
||||
{
|
||||
"Position": {
|
||||
"X": 222.61905,
|
||||
"Y": 182.78828,
|
||||
"Z": -704.0299
|
||||
},
|
||||
"TerritoryId": 956,
|
||||
"InteractionType": "WalkTo"
|
||||
},
|
||||
{
|
||||
"DataId": 2011980,
|
||||
"Position": {
|
||||
@ -112,7 +124,8 @@
|
||||
"Z": -767.7577
|
||||
},
|
||||
"TerritoryId": 956,
|
||||
"InteractionType": "AttuneAetherCurrent"
|
||||
"InteractionType": "AttuneAetherCurrent",
|
||||
"AetherCurrentId": 2818314
|
||||
},
|
||||
{
|
||||
"DataId": 1038701,
|
||||
@ -122,7 +135,8 @@
|
||||
"Z": -823.3921
|
||||
},
|
||||
"TerritoryId": 956,
|
||||
"InteractionType": "UseItem"
|
||||
"InteractionType": "UseItem",
|
||||
"ItemId": 2003129
|
||||
}
|
||||
]
|
||||
},
|
||||
@ -144,6 +158,15 @@
|
||||
{
|
||||
"Sequence": 255,
|
||||
"Steps": [
|
||||
{
|
||||
"Position": {
|
||||
"X": 254.80028,
|
||||
"Y": 163.44171,
|
||||
"Z": -626.4951
|
||||
},
|
||||
"TerritoryId": 956,
|
||||
"InteractionType": "WalkTo"
|
||||
},
|
||||
{
|
||||
"DataId": 1038702,
|
||||
"Position": {
|
||||
|
@ -28,7 +28,17 @@
|
||||
"Z": 66.75818
|
||||
},
|
||||
"TerritoryId": 956,
|
||||
"InteractionType": "AttuneAetherCurrent"
|
||||
"InteractionType": "AttuneAetherCurrent",
|
||||
"AetherCurrentId": 2818315
|
||||
},
|
||||
{
|
||||
"Position": {
|
||||
"X": 760.1999,
|
||||
"Y": 145.74788,
|
||||
"Z": -52.025288
|
||||
},
|
||||
"TerritoryId": 956,
|
||||
"InteractionType": "WalkTo"
|
||||
},
|
||||
{
|
||||
"DataId": 2011840,
|
||||
@ -83,6 +93,16 @@
|
||||
{
|
||||
"Sequence": 4,
|
||||
"Steps": [
|
||||
{
|
||||
"Position": {
|
||||
"X": 483.16574,
|
||||
"Y": 83.132675,
|
||||
"Z": 74.693695
|
||||
},
|
||||
"TerritoryId": 956,
|
||||
"InteractionType": "WalkTo",
|
||||
"Comment": "Avoids aggroing some enemies on the hill"
|
||||
},
|
||||
{
|
||||
"DataId": 2011842,
|
||||
"Position": {
|
||||
@ -141,7 +161,8 @@
|
||||
"Z": -267.23126
|
||||
},
|
||||
"TerritoryId": 956,
|
||||
"InteractionType": "AttuneAetherCurrent"
|
||||
"InteractionType": "AttuneAetherCurrent",
|
||||
"AetherCurrentId": 2818320
|
||||
},
|
||||
{
|
||||
"DataId": 2011843,
|
||||
|
@ -20,6 +20,17 @@
|
||||
{
|
||||
"Sequence": 1,
|
||||
"Steps": [
|
||||
{
|
||||
"Position": {
|
||||
"X": 304.306,
|
||||
"Y": 84.01365,
|
||||
"Z": -292.01114
|
||||
},
|
||||
"TerritoryId": 956,
|
||||
"InteractionType": "WalkTo",
|
||||
"DisableNavmesh": true,
|
||||
"Mount": true
|
||||
},
|
||||
{
|
||||
"DataId": 1038736,
|
||||
"Position": {
|
||||
|
@ -46,16 +46,19 @@
|
||||
"Z": -395.31555
|
||||
},
|
||||
"TerritoryId": 956,
|
||||
"InteractionType": "AttuneAetherCurrent"
|
||||
"InteractionType": "AttuneAetherCurrent",
|
||||
"AetherCurrentId": 2818318
|
||||
},
|
||||
{
|
||||
"Position": {
|
||||
"X": -327.6718,
|
||||
"Y": 79.535736,
|
||||
"Z": -400.00397
|
||||
"X": -300.80545,
|
||||
"Y": 59.384476,
|
||||
"Z": -409.0928
|
||||
},
|
||||
"TerritoryId": 956,
|
||||
"InteractionType": "WalkTo"
|
||||
"InteractionType": "WalkTo",
|
||||
"DisableNavmesh": true,
|
||||
"Mount": true
|
||||
},
|
||||
{
|
||||
"DataId": 2011983,
|
||||
@ -65,7 +68,8 @@
|
||||
"Z": -286.27454
|
||||
},
|
||||
"TerritoryId": 956,
|
||||
"InteractionType": "AttuneAetherCurrent"
|
||||
"InteractionType": "AttuneAetherCurrent",
|
||||
"AetherCurrentId": 2818319
|
||||
},
|
||||
{
|
||||
"DataId": 1038736,
|
||||
@ -114,6 +118,7 @@
|
||||
"Y": 41.37599,
|
||||
"Z": -141.16125
|
||||
},
|
||||
"StopDistance": 5,
|
||||
"TerritoryId": 962,
|
||||
"InteractionType": "Interact"
|
||||
}
|
||||
|
@ -12,6 +12,7 @@
|
||||
"Y": 41.37599,
|
||||
"Z": -142.1684
|
||||
},
|
||||
"StopDistance": 5,
|
||||
"TerritoryId": 962,
|
||||
"InteractionType": "Interact"
|
||||
}
|
||||
@ -27,6 +28,7 @@
|
||||
"Y": 41.37599,
|
||||
"Z": -141.00867
|
||||
},
|
||||
"StopDistance": 5,
|
||||
"TerritoryId": 962,
|
||||
"InteractionType": "Interact"
|
||||
}
|
||||
@ -42,6 +44,7 @@
|
||||
"Y": 41.37599,
|
||||
"Z": -142.1684
|
||||
},
|
||||
"StopDistance": 5,
|
||||
"TerritoryId": 962,
|
||||
"InteractionType": "Interact"
|
||||
}
|
||||
@ -92,7 +95,11 @@
|
||||
"Z": 4.5318604
|
||||
},
|
||||
"TerritoryId": 962,
|
||||
"InteractionType": "Interact"
|
||||
"InteractionType": "Interact",
|
||||
"AethernetShortcut": [
|
||||
"[Old Sharlayan] The Leveilleur Estate",
|
||||
"[Old Sharlayan] The Baldesion Annex"
|
||||
]
|
||||
},
|
||||
{
|
||||
"DataId": 1040291,
|
||||
|
@ -83,7 +83,8 @@
|
||||
"Z": 633.93604
|
||||
},
|
||||
"TerritoryId": 957,
|
||||
"InteractionType": "Interact"
|
||||
"InteractionType": "Interact",
|
||||
"DisableNavmesh": true
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -83,6 +83,16 @@
|
||||
{
|
||||
"Sequence": 5,
|
||||
"Steps": [
|
||||
{
|
||||
"Position": {
|
||||
"X": 232.93636,
|
||||
"Y": 15.136732,
|
||||
"Z": 526.6279
|
||||
},
|
||||
"TerritoryId": 957,
|
||||
"InteractionType": "WalkTo",
|
||||
"Mount": true
|
||||
},
|
||||
{
|
||||
"DataId": 2011992,
|
||||
"Position": {
|
||||
@ -91,7 +101,9 @@
|
||||
"Z": 473.65527
|
||||
},
|
||||
"TerritoryId": 957,
|
||||
"InteractionType": "AttuneAetherCurrent"
|
||||
"InteractionType": "AttuneAetherCurrent",
|
||||
"AetherCurrentId": 2818333,
|
||||
"DisableNavmesh": true
|
||||
},
|
||||
{
|
||||
"Position": {
|
||||
@ -102,6 +114,16 @@
|
||||
"TerritoryId": 957,
|
||||
"InteractionType": "WalkTo"
|
||||
},
|
||||
{
|
||||
"Position": {
|
||||
"X": 199.50157,
|
||||
"Y": 1.769943,
|
||||
"Z": 738.831
|
||||
},
|
||||
"StopDistance": 0.25,
|
||||
"TerritoryId": 957,
|
||||
"InteractionType": "WalkTo"
|
||||
},
|
||||
{
|
||||
"DataId": 1038608,
|
||||
"Position": {
|
||||
@ -109,9 +131,9 @@
|
||||
"Y": 1.769943,
|
||||
"Z": 738.9843
|
||||
},
|
||||
"StopDistance": 0.25,
|
||||
"TerritoryId": 957,
|
||||
"InteractionType": "Interact"
|
||||
"InteractionType": "Interact",
|
||||
"Mount": false
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -12,6 +12,7 @@
|
||||
"Y": 5.880045,
|
||||
"Z": 612.02405
|
||||
},
|
||||
"StopDistance": 5,
|
||||
"TerritoryId": 957,
|
||||
"InteractionType": "Interact"
|
||||
}
|
||||
@ -92,7 +93,8 @@
|
||||
"Z": 537.8346
|
||||
},
|
||||
"TerritoryId": 957,
|
||||
"InteractionType": "AttuneAetherCurrent"
|
||||
"InteractionType": "AttuneAetherCurrent",
|
||||
"AetherCurrentId": 2818329
|
||||
},
|
||||
{
|
||||
"DataId": 1038616,
|
||||
|
@ -1,6 +1,7 @@
|
||||
{
|
||||
"Version": 1,
|
||||
"Author": "liza",
|
||||
"Comment": "This is possibly the least polished quest so far, as the follow steps are awkward (need to move >10 units away to trigger the follow-up)",
|
||||
"QuestSequence": [
|
||||
{
|
||||
"Sequence": 0,
|
||||
@ -83,23 +84,184 @@
|
||||
"Y": 49.103825,
|
||||
"Z": 152.91064
|
||||
},
|
||||
"StopDistance": 5,
|
||||
"TerritoryId": 957,
|
||||
"InteractionType": "ManualAction",
|
||||
"Comment": "Follow the Lantern"
|
||||
"InteractionType": "Interact"
|
||||
},
|
||||
{
|
||||
"DataId": 1038636,
|
||||
"Position": {
|
||||
"X": -425.414,
|
||||
"Y": 38.415024,
|
||||
"Z": 160.1206
|
||||
},
|
||||
"StopDistance": 4,
|
||||
"TerritoryId": 957,
|
||||
"InteractionType": "WaitForNpcAtPosition"
|
||||
},
|
||||
{
|
||||
"Position": {
|
||||
"X": -425.43683,
|
||||
"Y": 38.413155,
|
||||
"Z": 160.11292
|
||||
},
|
||||
"TerritoryId": 957,
|
||||
"InteractionType": "WalkTo"
|
||||
},
|
||||
{
|
||||
"DataId": 1038636,
|
||||
"Position": {
|
||||
"X": -425.414,
|
||||
"Y": 38.415024,
|
||||
"Z": 160.1206
|
||||
},
|
||||
"StopDistance": 4,
|
||||
"TerritoryId": 957,
|
||||
"InteractionType": "WalkTo"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Sequence": 5,
|
||||
"Comment": "Follow the Lantern"
|
||||
"Steps": [
|
||||
{
|
||||
"DataId": 1041219,
|
||||
"Position": {
|
||||
"X": -425.43683,
|
||||
"Y": 38.413155,
|
||||
"Z": 160.11292
|
||||
},
|
||||
"StopDistance": 5,
|
||||
"TerritoryId": 957,
|
||||
"InteractionType": "Interact"
|
||||
},
|
||||
{
|
||||
"DataId": 1041219,
|
||||
"Position": {
|
||||
"X": -419.6078,
|
||||
"Y": 43.950115,
|
||||
"Z": 87.3025
|
||||
},
|
||||
"StopDistance": 4,
|
||||
"TerritoryId": 957,
|
||||
"InteractionType": "WaitForNpcAtPosition"
|
||||
},
|
||||
{
|
||||
"Position": {
|
||||
"X": -430.35034,
|
||||
"Y": 46.160213,
|
||||
"Z": 93.2392
|
||||
},
|
||||
"TerritoryId": 957,
|
||||
"InteractionType": "WalkTo"
|
||||
},
|
||||
{
|
||||
"DataId": 1041220,
|
||||
"Position": {
|
||||
"X": -419.60785,
|
||||
"Y": 43.9499,
|
||||
"Z": 87.296875
|
||||
},
|
||||
"StopDistance": 4,
|
||||
"TerritoryId": 957,
|
||||
"InteractionType": "WalkTo"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Sequence": 6,
|
||||
"Comment": "Follow the Lantern"
|
||||
"Steps": [
|
||||
{
|
||||
"DataId": 1041220,
|
||||
"Position": {
|
||||
"X": -419.60785,
|
||||
"Y": 43.9499,
|
||||
"Z": 87.296875
|
||||
},
|
||||
"StopDistance": 5,
|
||||
"TerritoryId": 957,
|
||||
"InteractionType": "Interact"
|
||||
},
|
||||
{
|
||||
"DataId": 1041220,
|
||||
"Position": {
|
||||
"X": -444.7032,
|
||||
"Y": 49.551,
|
||||
"Z": 97.1969
|
||||
},
|
||||
"StopDistance": 4,
|
||||
"TerritoryId": 957,
|
||||
"InteractionType": "WaitForNpcAtPosition"
|
||||
},
|
||||
{
|
||||
"Position": {
|
||||
"X": -433.19608,
|
||||
"Y": 46.94587,
|
||||
"Z": 93.295135
|
||||
},
|
||||
"StopDistance": 0.35,
|
||||
"TerritoryId": 957,
|
||||
"InteractionType": "WalkTo"
|
||||
},
|
||||
{
|
||||
"DataId": 1041221,
|
||||
"Position": {
|
||||
"X": -444.72424,
|
||||
"Y": 49.55681,
|
||||
"Z": 97.18469
|
||||
},
|
||||
"StopDistance": 4,
|
||||
"TerritoryId": 957,
|
||||
"InteractionType": "WalkTo"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Sequence": 7,
|
||||
"Comment": "Follow the Lantern"
|
||||
"Steps": [
|
||||
{
|
||||
"DataId": 1041221,
|
||||
"Position": {
|
||||
"X": -444.72424,
|
||||
"Y": 49.55681,
|
||||
"Z": 97.18469
|
||||
},
|
||||
"StopDistance": 5,
|
||||
"TerritoryId": 957,
|
||||
"InteractionType": "Interact"
|
||||
},
|
||||
{
|
||||
"DataId": 1041221,
|
||||
"Position": {
|
||||
"X": -484.5909,
|
||||
"Y": 54.18516,
|
||||
"Z": 128.3601
|
||||
},
|
||||
"StopDistance": 4,
|
||||
"TerritoryId": 957,
|
||||
"InteractionType": "WaitForNpcAtPosition"
|
||||
},
|
||||
{
|
||||
"Position": {
|
||||
"X": -472.65085,
|
||||
"Y": 53.779083,
|
||||
"Z": 124.34451
|
||||
},
|
||||
"TerritoryId": 957,
|
||||
"InteractionType": "WalkTo"
|
||||
},
|
||||
{
|
||||
"DataId": 1038637,
|
||||
"Position": {
|
||||
"X": -484.61133,
|
||||
"Y": 54.187614,
|
||||
"Z": 128.34363
|
||||
},
|
||||
"StopDistance": 4,
|
||||
"TerritoryId": 957,
|
||||
"InteractionType": "WalkTo"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Sequence": 8,
|
||||
@ -111,6 +273,7 @@
|
||||
"Y": 54.187614,
|
||||
"Z": 128.34363
|
||||
},
|
||||
"StopDistance": 5,
|
||||
"TerritoryId": 957,
|
||||
"InteractionType": "Interact"
|
||||
}
|
||||
|
@ -107,7 +107,8 @@
|
||||
"Z": 117.69275
|
||||
},
|
||||
"TerritoryId": 957,
|
||||
"InteractionType": "Interact"
|
||||
"InteractionType": "Interact",
|
||||
"AetheryteShortcut": "Thavnair - Great Work"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -22,18 +22,18 @@
|
||||
"Steps": [
|
||||
{
|
||||
"Position": {
|
||||
"X": -80.636894,
|
||||
"Y": 99.974266,
|
||||
"Z": -708.7214
|
||||
"X": -82.02301,
|
||||
"Y": 95.24942,
|
||||
"Z": -697.3925
|
||||
},
|
||||
"TerritoryId": 957,
|
||||
"InteractionType": "WalkTo"
|
||||
},
|
||||
{
|
||||
"Position": {
|
||||
"X": -67.775665,
|
||||
"Y": 97.140656,
|
||||
"Z": -710.1025
|
||||
"X": -78.47051,
|
||||
"Y": 99.96379,
|
||||
"Z": -711.17303
|
||||
},
|
||||
"TerritoryId": 957,
|
||||
"InteractionType": "WalkTo"
|
||||
@ -46,7 +46,9 @@
|
||||
"Z": -710.7805
|
||||
},
|
||||
"TerritoryId": 957,
|
||||
"InteractionType": "AttuneAetherCurrent"
|
||||
"InteractionType": "AttuneAetherCurrent",
|
||||
"AetherCurrentId": 2818330,
|
||||
"DisableNavmesh": true
|
||||
},
|
||||
{
|
||||
"DataId": 1038631,
|
||||
@ -56,7 +58,8 @@
|
||||
"Z": 117.69275
|
||||
},
|
||||
"TerritoryId": 957,
|
||||
"InteractionType": "Interact"
|
||||
"InteractionType": "Interact",
|
||||
"AetheryteShortcut": "Thavnair - Great Work"
|
||||
}
|
||||
]
|
||||
},
|
||||
@ -71,7 +74,28 @@
|
||||
"Z": -561.82196
|
||||
},
|
||||
"TerritoryId": 957,
|
||||
"InteractionType": "Interact"
|
||||
"InteractionType": "AttuneAetherCurrent",
|
||||
"AetherCurrentId": 2818334
|
||||
},
|
||||
{
|
||||
"Position": {
|
||||
"X": -489.27457,
|
||||
"Y": 72.74904,
|
||||
"Z": -546.8438
|
||||
},
|
||||
"TerritoryId": 957,
|
||||
"InteractionType": "WalkTo",
|
||||
"Mount": true
|
||||
},
|
||||
{
|
||||
"Position": {
|
||||
"X": -523.7225,
|
||||
"Y": 9.401685,
|
||||
"Z": -554.4276
|
||||
},
|
||||
"TerritoryId": 957,
|
||||
"InteractionType": "WalkTo",
|
||||
"DisableNavmesh": true
|
||||
},
|
||||
{
|
||||
"DataId": 1038651,
|
||||
@ -95,6 +119,7 @@
|
||||
"Y": -0.090369135,
|
||||
"Z": -562.4323
|
||||
},
|
||||
"StopDistance": 6,
|
||||
"TerritoryId": 957,
|
||||
"InteractionType": "Interact"
|
||||
}
|
||||
@ -111,7 +136,8 @@
|
||||
"Z": 17.532532
|
||||
},
|
||||
"TerritoryId": 957,
|
||||
"InteractionType": "Interact"
|
||||
"InteractionType": "Interact",
|
||||
"AetheryteShortcut": "Thavnair - Great Work"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -20,6 +20,15 @@
|
||||
{
|
||||
"Sequence": 1,
|
||||
"Steps": [
|
||||
{
|
||||
"Position": {
|
||||
"X": -130.78743,
|
||||
"Y": 86.83725,
|
||||
"Z": -252.08578
|
||||
},
|
||||
"TerritoryId": 957,
|
||||
"InteractionType": "WalkTo"
|
||||
},
|
||||
{
|
||||
"DataId": 2011994,
|
||||
"Position": {
|
||||
@ -28,7 +37,28 @@
|
||||
"Z": -288.3192
|
||||
},
|
||||
"TerritoryId": 957,
|
||||
"InteractionType": "AttuneAetherCurrent"
|
||||
"InteractionType": "AttuneAetherCurrent",
|
||||
"AetherCurrentId": 2818335,
|
||||
"DisableNavmesh": true
|
||||
},
|
||||
{
|
||||
"Position": {
|
||||
"X": -156.25183,
|
||||
"Y": 90.34184,
|
||||
"Z": -399.8714
|
||||
},
|
||||
"TerritoryId": 957,
|
||||
"InteractionType": "WalkTo"
|
||||
},
|
||||
{
|
||||
"Position": {
|
||||
"X": -126.149765,
|
||||
"Y": 73.745605,
|
||||
"Z": -427.64508
|
||||
},
|
||||
"TerritoryId": 957,
|
||||
"InteractionType": "WalkTo",
|
||||
"DisableNavmesh": true
|
||||
},
|
||||
{
|
||||
"DataId": 1038656,
|
||||
|
@ -12,6 +12,7 @@
|
||||
"Y": 1.9073486E-06,
|
||||
"Z": 1.5715942
|
||||
},
|
||||
"StopDistance": 5,
|
||||
"TerritoryId": 987,
|
||||
"InteractionType": "Interact"
|
||||
}
|
||||
|
@ -42,6 +42,7 @@
|
||||
"Y": -27.000013,
|
||||
"Z": 177.5387
|
||||
},
|
||||
"StopDistance": 5,
|
||||
"TerritoryId": 963,
|
||||
"InteractionType": "Interact"
|
||||
}
|
||||
@ -58,7 +59,7 @@
|
||||
"Z": 110.55151
|
||||
},
|
||||
"TerritoryId": 963,
|
||||
"InteractionType": "AttuneAethenetShard"
|
||||
"InteractionType": "AttuneAethernetShard"
|
||||
},
|
||||
{
|
||||
"DataId": 1040256,
|
||||
@ -113,7 +114,7 @@
|
||||
"Z": 202.2583
|
||||
},
|
||||
"TerritoryId": 963,
|
||||
"InteractionType": "AttuneAethenetShard"
|
||||
"InteractionType": "AttuneAethernetShard"
|
||||
},
|
||||
{
|
||||
"DataId": 191,
|
||||
@ -123,7 +124,7 @@
|
||||
"Z": -31.815125
|
||||
},
|
||||
"TerritoryId": 963,
|
||||
"InteractionType": "AttuneAethenetShard"
|
||||
"InteractionType": "AttuneAethernetShard"
|
||||
},
|
||||
{
|
||||
"DataId": 1040259,
|
||||
|
@ -43,7 +43,7 @@
|
||||
"Z": 27.725586
|
||||
},
|
||||
"TerritoryId": 963,
|
||||
"InteractionType": "AttuneAethenetShard"
|
||||
"InteractionType": "AttuneAethernetShard"
|
||||
},
|
||||
{
|
||||
"DataId": 1040264,
|
||||
@ -98,7 +98,12 @@
|
||||
"Z": 1.3884888
|
||||
},
|
||||
"TerritoryId": 962,
|
||||
"InteractionType": "Interact"
|
||||
"InteractionType": "Interact",
|
||||
"AetheryteShortcut": "Old Sharlayan",
|
||||
"AethernetShortcut": [
|
||||
"[Old Sharlayan] Aetheryte Plaza",
|
||||
"[Old Sharlayan] The Baldesion Annex"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
@ -112,6 +117,7 @@
|
||||
"Y": 4.357494,
|
||||
"Z": 0.7476196
|
||||
},
|
||||
"StopDistance": 6,
|
||||
"TerritoryId": 962,
|
||||
"InteractionType": "Interact"
|
||||
}
|
||||
|
@ -72,7 +72,7 @@
|
||||
"InteractionType": "Interact"
|
||||
},
|
||||
{
|
||||
"ItemId": -1,
|
||||
"ItemId": null,
|
||||
"TerritoryId": 959,
|
||||
"InteractionType": "UseItem"
|
||||
}
|
||||
|
@ -111,7 +111,7 @@
|
||||
"Z": -197.61963
|
||||
},
|
||||
"TerritoryId": 963,
|
||||
"InteractionType": "AttuneAethenetShard"
|
||||
"InteractionType": "AttuneAethernetShard"
|
||||
},
|
||||
{
|
||||
"DataId": 1039001,
|
||||
|
@ -57,7 +57,7 @@
|
||||
"Z": 13.473633
|
||||
},
|
||||
"TerritoryId": 963,
|
||||
"InteractionType": "AttuneAethenetShard"
|
||||
"InteractionType": "AttuneAethernetShard"
|
||||
},
|
||||
{
|
||||
"DataId": 1039540,
|
||||
|
@ -53,7 +53,7 @@
|
||||
"Z": -98.43509
|
||||
},
|
||||
"TerritoryId": 963,
|
||||
"InteractionType": "AttuneAethenetShard"
|
||||
"InteractionType": "AttuneAethernetShard"
|
||||
},
|
||||
{
|
||||
"DataId": 1040374,
|
||||
|
@ -28,7 +28,7 @@
|
||||
"Z": -210.6151
|
||||
},
|
||||
"TerritoryId": 963,
|
||||
"InteractionType": "AttuneAethenetShard",
|
||||
"InteractionType": "AttuneAethernetShard",
|
||||
"Comment": "This is pretty late here, maybe move it to some other quest"
|
||||
},
|
||||
{
|
||||
|
@ -47,10 +47,12 @@
|
||||
"properties": {
|
||||
"DataId": {
|
||||
"type": "integer",
|
||||
"description": "The data id of the NPC/Object/Aetheryte/Aether Current",
|
||||
"exclusiveMinimum": 0
|
||||
},
|
||||
"Position": {
|
||||
"type": "object",
|
||||
"description": "Position to (typically) walk to",
|
||||
"properties": {
|
||||
"X": {
|
||||
"type": "number"
|
||||
@ -69,38 +71,53 @@
|
||||
]
|
||||
},
|
||||
"StopDistance": {
|
||||
"type": "number",
|
||||
"type": ["number", "null"],
|
||||
"description": "Set if pathfinding should stop closer or further away from the default stop distance",
|
||||
"exclusiveMinimum": 0
|
||||
},
|
||||
"TerritoryId": {
|
||||
"type": "integer",
|
||||
"description": "The territory id associated with the location",
|
||||
"exclusiveMinimum": 0
|
||||
},
|
||||
"InteractionType": {
|
||||
"type": "string",
|
||||
"description": "What to do at the position",
|
||||
"enum": [
|
||||
"Interact",
|
||||
"WalkTo",
|
||||
"AttuneAethenetShard",
|
||||
"AttuneAethernetShard",
|
||||
"AttuneAetheryte",
|
||||
"AttuneAetherCurrent",
|
||||
"Combat",
|
||||
"UseItem",
|
||||
"Emote",
|
||||
"WaitForNpcAtPosition",
|
||||
"ManualAction"
|
||||
]
|
||||
},
|
||||
"Disabled": {
|
||||
"description": "Unused (TODO)",
|
||||
"type": "boolean"
|
||||
},
|
||||
"DisableNavmesh": {
|
||||
"description": "If true, will go to the position in a straight line instead of using pathfinding",
|
||||
"type": "boolean"
|
||||
},
|
||||
"Mount": {
|
||||
"type": ["boolean", "null"],
|
||||
"description": "If true, will mount regardless of distance to position. If false, will unmount."
|
||||
},
|
||||
"AetheryteShortcut": {
|
||||
"type": "string",
|
||||
"description": "The Aetheryte to teleport to (before moving)",
|
||||
"$comment": "TODO add remaining aetherytes for 2.x/3.x",
|
||||
"enum": [
|
||||
"Limsa Lominsa",
|
||||
"Gridania",
|
||||
"Ul'dah",
|
||||
"Ishgard",
|
||||
"Idyllshire",
|
||||
|
||||
"Rhalgr's Reach",
|
||||
"Fringes - Castrum Oriens",
|
||||
@ -118,8 +135,6 @@
|
||||
"Azim Steppe - Dawn Throne",
|
||||
"Azim Steppe - Dhoro Iloh",
|
||||
"Doman Enclave",
|
||||
"Doman Enclave - Northern Enclave",
|
||||
"Doman Enclave - Southern Enclave",
|
||||
|
||||
"Crystarium",
|
||||
"Eulmore",
|
||||
@ -155,12 +170,13 @@
|
||||
"Elpis - Twelve Wonders",
|
||||
"Elpis - Poieten Oikos",
|
||||
"Ultima Thule - Reah Tahra",
|
||||
"Ultima Thula - Abode of the Ea",
|
||||
"Ultima Thule - Abode of the Ea",
|
||||
"Ultima Thule - Base Omicron"
|
||||
]
|
||||
},
|
||||
"AethernetShortcut": {
|
||||
"type": "array",
|
||||
"description": "A pair of aethernet locations (from + to) to use as a shortcut",
|
||||
"minItems": 2,
|
||||
"maxItems": 2,
|
||||
"items": {
|
||||
@ -176,7 +192,7 @@
|
||||
"[Limsa Lominsa] Airship Landing",
|
||||
"[Gridania] Aetheryte Plaza",
|
||||
"[Gridania] Archer's Guild",
|
||||
"[Gridania] Leatherworker's Guld & Shaded Bower",
|
||||
"[Gridania] Leatherworker's Guild & Shaded Bower",
|
||||
"[Gridania] Lancer's Guild",
|
||||
"[Gridania] Conjurer's Guild",
|
||||
"[Gridania] Botanist's Guild",
|
||||
@ -249,14 +265,20 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
"AetherCurrentId": {
|
||||
"type": "number",
|
||||
"description": "The aether current id, used to check if a given aetheryte is unlocked"
|
||||
},
|
||||
"EnemySpawnType": {
|
||||
"type": "string",
|
||||
"description": "Determines how enemy spawning is handled in combat locations",
|
||||
"enum": [
|
||||
"AutoOnEnterArea",
|
||||
"AfterInteraction"
|
||||
]
|
||||
},
|
||||
"KillEnemyDataIds": {
|
||||
"description": "The enemy data ids which are supposed to be killed",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "integer"
|
||||
@ -264,6 +286,7 @@
|
||||
},
|
||||
"Emote": {
|
||||
"type": "string",
|
||||
"description": "The emote to use",
|
||||
"enum": [
|
||||
"stretch",
|
||||
"wave",
|
||||
@ -271,8 +294,14 @@
|
||||
"deny"
|
||||
]
|
||||
},
|
||||
"ItemId": {
|
||||
"type": ["number", "null"],
|
||||
"description": "The Item to use",
|
||||
"exclusiveMinimum": 0
|
||||
},
|
||||
"SkipIf": {
|
||||
"type": "array",
|
||||
"description": "TODO Not implemented",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
|
@ -7,12 +7,13 @@ using Dalamud.Plugin;
|
||||
using Dalamud.Plugin.Services;
|
||||
using FFXIVClientStructs.FFXIV.Client.UI;
|
||||
using Questionable.Controller;
|
||||
using Questionable.Data;
|
||||
using Questionable.External;
|
||||
using Questionable.Windows;
|
||||
|
||||
namespace Questionable;
|
||||
|
||||
public sealed class Questionable : IDalamudPlugin
|
||||
public sealed class QuestionablePlugin : IDalamudPlugin
|
||||
{
|
||||
private readonly WindowSystem _windowSystem = new(nameof(Questionable));
|
||||
|
||||
@ -25,9 +26,10 @@ public sealed class Questionable : IDalamudPlugin
|
||||
|
||||
private readonly MovementController _movementController;
|
||||
|
||||
public Questionable(DalamudPluginInterface pluginInterface, IClientState clientState, ITargetManager targetManager,
|
||||
IFramework framework, IGameGui gameGui, IDataManager dataManager, ISigScanner sigScanner,
|
||||
IObjectTable objectTable, IPluginLog pluginLog, ICondition condition, IChatGui chatGui, ICommandManager commandManager)
|
||||
public QuestionablePlugin(DalamudPluginInterface pluginInterface, IClientState clientState,
|
||||
ITargetManager targetManager, IFramework framework, IGameGui gameGui, IDataManager dataManager,
|
||||
ISigScanner sigScanner, IObjectTable objectTable, IPluginLog pluginLog, ICondition condition, IChatGui chatGui,
|
||||
ICommandManager commandManager)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(pluginInterface);
|
||||
ArgumentNullException.ThrowIfNull(sigScanner);
|
||||
@ -38,13 +40,15 @@ public sealed class Questionable : IDalamudPlugin
|
||||
_clientState = clientState;
|
||||
_framework = framework;
|
||||
_gameGui = gameGui;
|
||||
_gameFunctions = new GameFunctions(dataManager, objectTable, sigScanner, targetManager, pluginLog);
|
||||
_gameFunctions = new GameFunctions(dataManager, objectTable, sigScanner, targetManager, condition, pluginLog);
|
||||
|
||||
AetheryteData aetheryteData = new AetheryteData(dataManager);
|
||||
NavmeshIpc navmeshIpc = new NavmeshIpc(pluginInterface);
|
||||
LifestreamIpc lifestreamIpc = new LifestreamIpc(pluginInterface, aetheryteData);
|
||||
_movementController =
|
||||
new MovementController(navmeshIpc, clientState, _gameFunctions, pluginLog);
|
||||
new MovementController(navmeshIpc, clientState, _gameFunctions, condition, pluginLog);
|
||||
_questController = new QuestController(pluginInterface, dataManager, _clientState, _gameFunctions,
|
||||
_movementController, pluginLog, condition, chatGui, commandManager);
|
||||
_movementController, pluginLog, condition, chatGui, aetheryteData, lifestreamIpc);
|
||||
_windowSystem.AddWindow(new DebugWindow(_movementController, _questController, _gameFunctions, clientState,
|
||||
targetManager));
|
||||
|
@ -35,7 +35,7 @@ internal sealed class DebugWindow : Window
|
||||
IsOpen = true;
|
||||
SizeConstraints = new WindowSizeConstraints
|
||||
{
|
||||
MinimumSize = new Vector2(100, 0),
|
||||
MinimumSize = new Vector2(200, 30),
|
||||
MaximumSize = default
|
||||
};
|
||||
}
|
||||
@ -43,16 +43,22 @@ internal sealed class DebugWindow : Window
|
||||
public override unsafe void Draw()
|
||||
{
|
||||
if (!_clientState.IsLoggedIn || _clientState.LocalPlayer == null)
|
||||
{
|
||||
ImGui.Text("Not logged in.");
|
||||
return;
|
||||
}
|
||||
|
||||
var currentQuest = _questController.CurrentQuest;
|
||||
if (currentQuest != null)
|
||||
{
|
||||
ImGui.TextUnformatted($"Quest: {currentQuest.Quest.Name} / {currentQuest.Sequence} / {currentQuest.Step}");
|
||||
ImGui.TextUnformatted(_questController.DebugState ?? "--");
|
||||
ImGui.TextUnformatted(_questController.Comment ?? "--");
|
||||
|
||||
ImGui.BeginDisabled(_questController.GetNextStep().Step == null);
|
||||
ImGui.Text($"{_questController.GetNextStep().Step?.Position}");
|
||||
var nextStep = _questController.GetNextStep();
|
||||
ImGui.BeginDisabled(nextStep.Step == null);
|
||||
ImGui.Text(string.Create(CultureInfo.InvariantCulture,
|
||||
$"{nextStep.Step?.InteractionType} @ {nextStep.Step?.Position}"));
|
||||
if (ImGuiComponents.IconButton(FontAwesomeIcon.Play))
|
||||
{
|
||||
_questController.ExecuteNextStep();
|
||||
@ -163,5 +169,8 @@ internal sealed class DebugWindow : Window
|
||||
if (ImGui.Button("Stop Nav"))
|
||||
_movementController.Stop();
|
||||
ImGui.EndDisabled();
|
||||
|
||||
if (ImGui.Button("Reload Data"))
|
||||
_questController.Reload();
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user