using System.Threading;
using System.Threading.Tasks;
using Dalamud.Game.ClientState.Conditions;
+using Dalamud.Game.ClientState.Objects.Types;
using Dalamud.Plugin.Services;
using FFXIVClientStructs.FFXIV.Client.Game;
using Questionable.External;
public bool IsNavmeshReady => _navmeshIpc.IsReady;
public bool IsPathRunning => _navmeshIpc.IsPathRunning;
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 DestinationData? Destination { get; private set; }
public void Update()
{
- if (_pathfindTask != null)
+ if (_pathfindTask != null && Destination != null)
{
if (_pathfindTask.IsCompletedSuccessfully)
{
var navPoints = _pathfindTask.Result.Skip(1).ToList();
Vector3 start = _clientState.LocalPlayer?.Position ?? navPoints[0];
- if (IsFlying && !_condition[ConditionFlag.InFlight] && _condition[ConditionFlag.Mounted])
+ if (Destination.IsFlying && !_condition[ConditionFlag.InFlight] && _condition[ConditionFlag.Mounted])
{
if (IsOnFlightPath(start) || navPoints.Any(IsOnFlightPath))
{
}
}
}
- else if (!IsFlying && !_condition[ConditionFlag.Mounted] && navPoints.Count > 0 &&
+ else if (!Destination.IsFlying && !_condition[ConditionFlag.Mounted] && navPoints.Count > 0 &&
!_gameFunctions.HasStatusPreventingSprintOrMount())
{
float actualDistance = 0;
if (IsPathRunning && Destination != null)
{
Vector3 localPlayerPosition = _clientState.LocalPlayer?.Position ?? Vector3.Zero;
- if ((localPlayerPosition - Destination.Value).Length() < StopDistance &&
- Math.Abs(localPlayerPosition.Y - Destination.Value.Y) < 1.95f) // target is too far below you
- Stop();
+ if ((localPlayerPosition - Destination.Position).Length() < Destination.StopDistance)
+ {
+ if (Destination.DataId != null)
+ {
+ GameObject? gameObject = _gameFunctions.FindObjectByDataId(Destination.DataId.Value);
+ if (gameObject != null && gameObject is Character)
+ {
+ if (Math.Abs(localPlayerPosition.Y - gameObject.Position.Y) < 1.95f)
+ Stop();
+ }
+ else
+ Stop();
+ }
+ else
+ Stop();
+ }
}
}
return pointOnFloor != null && Math.Abs(pointOnFloor.Value.Y - p.Y) > 0.5f;
}
- private void PrepareNavigation(EMovementType type, Vector3 to, bool fly, float? stopDistance)
+ private void PrepareNavigation(EMovementType type, uint? dataId, Vector3 to, bool fly, float? stopDistance)
{
ResetPathfinding();
_gameFunctions.ExecuteCommand("/automove off");
- Destination = to;
- StopDistance = stopDistance ?? (DefaultStopDistance - 0.2f);
- IsFlying = fly;
+ Destination = new DestinationData(dataId, to, stopDistance ?? (DefaultStopDistance - 0.2f), fly);
}
- public void NavigateTo(EMovementType type, Vector3 to, bool fly, float? stopDistance = null)
+ public void NavigateTo(EMovementType type, uint? dataId, Vector3 to, bool fly, float? stopDistance = null)
{
- PrepareNavigation(type, to, fly, stopDistance);
+ PrepareNavigation(type, dataId, 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)
+ public void NavigateTo(EMovementType type, uint? dataId, List<Vector3> to, bool fly, float? stopDistance)
{
- PrepareNavigation(type, to.Last(), fly, stopDistance);
+ PrepareNavigation(type, dataId, to.Last(), fly, stopDistance);
_navmeshIpc.MoveTo(to);
}
{
Stop();
}
+
+ public sealed record DestinationData(uint? DataId, Vector3 Position, float StopDistance, bool IsFlying);
}
using System.Numerics;
using System.Text.Json;
using Dalamud.Game.ClientState.Conditions;
+using Dalamud.Game.ClientState.Objects.Types;
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;
_territoryData = new TerritoryData(dataManager);
Reload();
+ _gameFunctions.QuestController = this;
}
}
#endif
+ public bool IsKnownQuest(ushort questId) => _quests.ContainsKey(questId);
+
private void LoadFromDirectory(DirectoryInfo configDirectory)
{
foreach (FileInfo fileInfo in configDirectory.GetFiles("*.json"))
if (!CurrentQuest.StepProgress.AethernetShortcutUsed)
{
- if (step.AethernetShortcut != null)
+ if (step.AethernetShortcut != null &&
+ _gameFunctions.IsAetheryteUnlocked(step.AethernetShortcut.From) &&
+ _gameFunctions.IsAetheryteUnlocked(step.AethernetShortcut.To))
{
EAetheryteLocation from = step.AethernetShortcut.From;
EAetheryteLocation to = step.AethernetShortcut.To;
};
}
else
- _movementController.NavigateTo(EMovementType.Quest, _aetheryteData.Locations[from], false,
+ _movementController.NavigateTo(EMovementType.Quest, null, _aetheryteData.Locations[from], false,
6.9f);
return;
}
}
- if (step.Position != null)
+ if (step.TargetTerritoryId == _clientState.TerritoryType)
+ {
+ // no more movement
+ }
+ else if (step.Position != null)
{
float distance;
if (step.InteractionType == EInteractionType.WalkTo)
if (actualDistance > distance)
{
- _movementController.NavigateTo(EMovementType.Quest, step.Position.Value,
+ _movementController.NavigateTo(EMovementType.Quest, step.DataId, step.Position.Value,
step.Fly && _gameFunctions.IsFlyingUnlocked(_clientState.TerritoryType), distance);
return;
}
{
if (actualDistance > distance)
{
- _movementController.NavigateTo(EMovementType.Quest, [step.Position.Value],
+ _movementController.NavigateTo(EMovementType.Quest, step.DataId, [step.Position.Value],
step.Fly && _gameFunctions.IsFlyingUnlocked(_clientState.TerritoryType), distance);
return;
}
}
}
+ else if (step.DataId != null && step.StopDistance != null)
+ {
+ GameObject? gameObject = _gameFunctions.FindObjectByDataId(step.DataId.Value);
+ if (gameObject == null ||
+ (gameObject.Position - _clientState.LocalPlayer!.Position).Length() > step.StopDistance)
+ {
+ return;
+ }
+ }
switch (step.InteractionType)
{
case EInteractionType.Interact:
- case EInteractionType.AttuneAethernetShard:
if (step.DataId != null)
{
+ GameObject? gameObject = _gameFunctions.FindObjectByDataId(step.DataId.Value);
+ if (gameObject == null)
+ return;
+
+ if (!gameObject.IsTargetable && _condition[ConditionFlag.Mounted])
+ {
+ _gameFunctions.Unmount();
+ return;
+ }
+
_gameFunctions.InteractWith(step.DataId.Value);
IncreaseStepCount();
}
break;
+ case EInteractionType.AttuneAethernetShard:
+ if (step.DataId != null)
+ {
+ if (!_gameFunctions.IsAetheryteUnlocked((EAetheryteLocation)step.DataId.Value))
+ _gameFunctions.InteractWith(step.DataId.Value);
+
+ IncreaseStepCount();
+ }
+
+ break;
+
case EInteractionType.AttuneAetheryte:
if (step.DataId != null)
{
break;
case EInteractionType.UseItem:
+ if (_gameFunctions.Unmount())
+ return;
+
if (step is { DataId: not null, ItemId: not null })
{
- if (_gameFunctions.Unmount())
- return;
-
_gameFunctions.UseItem(step.DataId.Value, step.ItemId.Value);
IncreaseStepCount();
}
+ else if (step.ItemId != null)
+ {
+ _gameFunctions.UseItem(step.ItemId.Value);
+ IncreaseStepCount();
+ }
break;
case EInteractionType.Combat:
+ if (_gameFunctions.Unmount())
+ return;
+
if (step.EnemySpawnType != null)
{
- if (_gameFunctions.Unmount())
- return;
-
if (step.DataId != null && step.EnemySpawnType == EEnemySpawnType.AfterInteraction)
_gameFunctions.InteractWith(step.DataId.Value);
case EInteractionType.WaitForObjectAtPosition:
if (step is { DataId: not null, Position: not null } &&
- !_gameFunctions.IsObbjectAtPosition(step.DataId.Value, step.Position.Value))
+ !_gameFunctions.IsObjectAtPosition(step.DataId.Value, step.Position.Value))
{
return;
}
using Dalamud.Game.ClientState.Objects;
using Dalamud.Game.ClientState.Objects.Types;
using Dalamud.Plugin.Services;
+using FFXIVClientStructs.FFXIV.Application.Network.WorkDefinitions;
using FFXIVClientStructs.FFXIV.Client.Game;
using FFXIVClientStructs.FFXIV.Client.Game.Control;
using FFXIVClientStructs.FFXIV.Client.Game.Object;
using FFXIVClientStructs.FFXIV.Client.System.String;
using FFXIVClientStructs.FFXIV.Client.UI.Agent;
using Lumina.Excel.GeneratedSheets;
+using Questionable.Controller;
using Questionable.Model.V1;
using BattleChara = FFXIVClientStructs.FFXIV.Client.Game.Character.BattleChara;
using GameObject = Dalamud.Game.ClientState.Objects.Types.GameObject;
.AsReadOnly();
}
+ public QuestController QuestController { private get; set; }
+
public (ushort CurrentQuest, byte Sequence) GetCurrentQuest()
{
- var scenarioTree = AgentScenarioTree.Instance();
- if (scenarioTree == null)
+ ushort currentQuest;
+
+ // if any quest that is currently tracked (i.e. in the to-do list) exists as mapped quest, we use that
+ var questManager = QuestManager.Instance();
+ if (questManager != null)
{
- //ImGui.Text("Scenario tree is null.");
- return (0, 0);
+ foreach (var tracked in questManager->TrackedQuestsSpan)
+ {
+ switch (tracked.QuestType)
+ {
+ default:
+ continue;
+
+ case 1: // normal quest
+ currentQuest = questManager->NormalQuestsSpan[tracked.Index].QuestId;
+ break;
+ }
+
+ if (QuestController.IsKnownQuest(currentQuest))
+ return (currentQuest, QuestManager.GetQuestSequence(currentQuest));
+ }
}
+ var scenarioTree = AgentScenarioTree.Instance();
+ if (scenarioTree == null)
+ return default;
+
if (scenarioTree->Data == null)
- {
- //ImGui.Text("Scenario tree data is null.");
- return (0, 0);
- }
+ return default;
- uint currentQuest = scenarioTree->Data->CurrentScenarioQuest;
+ currentQuest = scenarioTree->Data->CurrentScenarioQuest;
if (currentQuest == 0)
- {
- //ImGui.Text("Current quest is 0.");
- return (0, 0);
- }
+ return default;
+
+ return (currentQuest, QuestManager.GetQuestSequence(currentQuest));
+ }
+
+ public QuestWork? GetQuestEx(ushort questId)
+ {
+ QuestWork* questWork = QuestManager.Instance()->GetQuestById(questId);
+ return questWork != null ? *questWork : null;
- //ImGui.Text($"Current Quest: {currentQuest}");
- //ImGui.Text($"Progress: {QuestManager.GetQuestSequence(currentQuest)}");
- return ((ushort)currentQuest, QuestManager.GetQuestSequence(currentQuest));
}
public bool IsAetheryteUnlocked(uint aetheryteId, out byte subIndex)
{
+ subIndex = 0;
+
+ var uiState = UIState.Instance();
+ return uiState != null && uiState->IsAetheryteUnlocked(aetheryteId);
+ /*
var telepo = Telepo.Instance();
if (telepo == null || telepo->UpdateAetheryteList() == null)
{
subIndex = 0;
return false;
+ */
}
public bool IsAetheryteUnlocked(EAetheryteLocation aetheryteLocation)
#endregion
- private GameObject? FindObjectByDataId(uint dataId)
+ public GameObject? FindObjectByDataId(uint dataId)
{
foreach (var gameObject in _objectTable)
{
}
}
+ public void UseItem(uint itemId)
+ {
+ AgentInventoryContext.Instance()->UseItem(itemId);
+ }
+
public void UseItem(uint dataId, uint itemId)
{
GameObject? gameObject = FindObjectByDataId(dataId);
}
}
- public bool IsObbjectAtPosition(uint dataId, Vector3 position)
+ public bool IsObjectAtPosition(uint dataId, Vector3 position)
{
GameObject? gameObject = FindObjectByDataId(dataId);
return gameObject != null && (gameObject.Position - position).Length() < 0.05f;
public float? StopDistance { get; set; }
public ushort TerritoryId { get; set; }
+ public ushort? TargetTerritoryId { get; set; }
+
public bool Disabled { get; set; }
public bool DisableNavmesh { get; set; }
public bool? Mount { get; set; }
"Z": 67.826294
},
"TerritoryId": 958,
- "InteractionType": "AttuneAetherCurrent"
+ "InteractionType": "AttuneAetherCurrent",
+ "AetherCurrentId": 2818348
},
{
"DataId": 1039942,
"Z": -325.85645
},
"TerritoryId": 958,
- "InteractionType": "AttuneAetherCurrent"
+ "InteractionType": "AttuneAetherCurrent",
+ "AetherCurrentId": 2818350
},
{
"DataId": 1039946,
{
"Version": 1,
"Author": "liza",
- "Comment": "TODO This should have an aetheryte?",
"QuestSequence": [
{
"Sequence": 0,
{
"Sequence": 3,
"Steps": [
+ {
+ "DataId": 174,
+ "Position": {
+ "X": -566.2438,
+ "Y": 134.6656,
+ "Z": 650.6459
+ },
+ "StopDistance": 10,
+ "TerritoryId": 959,
+ "InteractionType": "AttuneAetheryte",
+ "DisableNavmesh": true
+ },
{
"DataId": 1039977,
"Position": {
},
"TerritoryId": 959,
"InteractionType": "Interact",
+ "EnemySpawnType": "AfterInteraction",
"KillEnemyDataIds": [
14077
- ],
- "Comment": "TODO what happened to seq: 2"
+ ]
}
]
},
"Z": 514.4884
},
"TerritoryId": 959,
- "InteractionType": "Interact"
+ "InteractionType": "Interact",
+ "DisableNavmesh": true
}
]
},
"Y": 76.14732,
"Z": 480.91858
},
+ "StopDistance": 5,
"TerritoryId": 959,
"InteractionType": "Interact"
}
"Y": 76.14732,
"Z": 480.91858
},
+ "StopDistance": 5,
"TerritoryId": 959,
"InteractionType": "Interact"
}
"Y": 172.25903,
"Z": 548.94324
},
+ "StopDistance": 5,
"TerritoryId": 959,
"InteractionType": "Interact"
}
"Y": 163.31726,
"Z": 593.0419
},
+ "StopDistance": 5,
"TerritoryId": 959,
"InteractionType": "Interact"
}
"Y": 156.8169,
"Z": 594.23206
},
+ "StopDistance": 5,
"TerritoryId": 959,
"InteractionType": "Interact"
}
"Y": 147.4784,
"Z": 566.1554
},
+ "StopDistance": 5,
"TerritoryId": 959,
"InteractionType": "Interact"
}
"Y": 169.00394,
"Z": 549.6758
},
+ "StopDistance": 5,
"TerritoryId": 959,
"InteractionType": "Interact"
}
{
"Sequence": 1,
"Steps": [
+ {
+ "Position": {
+ "X": -326.42538,
+ "Y": 98.98749,
+ "Z": 526.5519
+ },
+ "TerritoryId": 959,
+ "InteractionType": "WalkTo",
+ "DisableNavmesh": true
+ },
+ {
+ "Position": {
+ "X": -50.482517,
+ "Y": 42.360725,
+ "Z": 466.64243
+ },
+ "TerritoryId": 959,
+ "InteractionType": "WalkTo"
+ },
+ {
+ "Position": {
+ "X": 113.70272,
+ "Y": 45.552776,
+ "Z": 460.49585
+ },
+ "TerritoryId": 959,
+ "InteractionType": "WalkTo"
+ },
+ {
+ "Position": {
+ "X": 129.9883,
+ "Y": 54.543076,
+ "Z": 468.93378
+ },
+ "TerritoryId": 959,
+ "InteractionType": "WalkTo"
+ },
+ {
+ "Position": {
+ "X": 126.817184,
+ "Y": 55.823048,
+ "Z": 476.34058
+ },
+ "TerritoryId": 959,
+ "InteractionType": "WalkTo"
+ },
{
"DataId": 1038884,
"Position": {
"Y": 59.911327,
"Z": 411.42883
},
+ "StopDistance": 5,
"TerritoryId": 959,
"InteractionType": "Interact"
}
"Sequence": 1,
"Steps": [
{
- "DataId": 2012019,
"Position": {
- "X": 21.7081,
- "Y": -133.5001,
- "Z": -385.7313
+ "X": 1.131261,
+ "Y": -114.92335,
+ "Z": -418.2727
},
"TerritoryId": 959,
- "InteractionType": "AttuneAetherCurrent"
+ "InteractionType": "WalkTo",
+ "DisableNavmesh": true
},
{
"DataId": 1038897,
"Y": -128.8109,
"Z": -512.0165
},
+ "StopDistance": 10,
"TerritoryId": 959,
"InteractionType": "AttuneAetheryte"
},
+ {
+ "Position": {
+ "X": 36.500526,
+ "Y": -129.20917,
+ "Z": -521.85284
+ },
+ "TerritoryId": 959,
+ "InteractionType": "WalkTo"
+ },
{
"DataId": 1038901,
"Position": {
"Z": -555.0164
},
"TerritoryId": 959,
- "InteractionType": "Interact"
+ "InteractionType": "Interact",
+ "DisableNavmesh": true
}
]
},
{
"Sequence": 255,
"Steps": [
+ {
+ "Position": {
+ "X": -72.39724,
+ "Y": -49.589592,
+ "Z": -336.63968
+ },
+ "TerritoryId": 959,
+ "InteractionType": "WalkTo"
+ },
+ {
+ "Position": {
+ "X": -105.34293,
+ "Y": -49.589592,
+ "Z": -367.6591
+ },
+ "TerritoryId": 959,
+ "InteractionType": "WalkTo",
+ "DisableNavmesh": true
+ },
{
"DataId": 1038903,
"Position": {
{
"Sequence": 1,
"Steps": [
+ {
+ "DataId": 2012013,
+ "Position": {
+ "X": 29.1046,
+ "Y": -47.739,
+ "Z": -550.4077
+ },
+ "TerritoryId": 959,
+ "InteractionType": "AttuneAetherCurrent",
+ "AetherCurrentId": 2818362
+ },
+ {
+ "Position": {
+ "X": 62.71022,
+ "Y": -46.99965,
+ "Z": -433.81802
+ },
+ "TerritoryId": 959,
+ "InteractionType": "WalkTo"
+ },
+ {
+ "Position": {
+ "X": 47.394165,
+ "Y": -133.50012,
+ "Z": -397.90225
+ },
+ "TerritoryId": 959,
+ "InteractionType": "WalkTo",
+ "DisableNavmesh": true
+ },
+ {
+ "DataId": 2012019,
+ "Position": {
+ "X": 21.7081,
+ "Y": -133.5001,
+ "Z": -385.7313
+ },
+ "TerritoryId": 959,
+ "InteractionType": "AttuneAetherCurrent",
+ "AetherCurrentId": 2818368,
+ "DisableNavmesh": true
+ },
{
"DataId": 1038908,
"Position": {
"Z": -618.7686
},
"TerritoryId": 959,
- "InteractionType": "Interact"
+ "InteractionType": "Interact",
+ "AetheryteShortcut": "Mare Lamentorum - Bestways Burrow"
}
]
},
"Steps": [
{
"DataId": 2012178,
- "Position": {
- "X": -486.59497,
- "Y": -154.37555,
- "Z": -689.26526
- },
"TerritoryId": 959,
- "InteractionType": "ManualAction",
+ "InteractionType": "Interact",
"Comment": "Navmesh can't jump"
}
]
"Z": -595.72754
},
"TerritoryId": 959,
- "InteractionType": "AttuneAetherCurrent"
+ "InteractionType": "AttuneAetherCurrent",
+ "AetherCurrentId": 2818360
},
{
"DataId": 1038912,
+ "StopDistance": 5,
+ "TerritoryId": 959,
+ "InteractionType": "Interact",
+ "Comment": "Navmesh can't jump"
+ }
+ ]
+ },
+ {
+ "Sequence": 4,
+ "Steps": [
+ {
"Position": {
"X": -455.40552,
"Y": -168,
"Z": -620.05035
},
"TerritoryId": 959,
- "InteractionType": "Interact"
- },
- {
- "ItemId": null,
- "TerritoryId": 959,
- "InteractionType": "UseItem"
+ "InteractionType": "UseItem",
+ "ItemId": 2003236
}
]
},
"Z": -253.94832
},
"TerritoryId": 959,
- "InteractionType": "ManualAction",
- "Comment": "Navmesh can't jump"
+ "InteractionType": "WalkTo"
},
{
"DataId": 1038923,
- "Position": {
- "X": -376.27222,
- "Y": -151.67168,
- "Z": -267.90265
- },
+ "StopDistance": 5,
"TerritoryId": 959,
- "InteractionType": "Interact"
+ "InteractionType": "Interact",
+ "Comment": "Navmesh can't jump"
}
]
},
"Z": -361.57114
},
"TerritoryId": 959,
- "InteractionType": "ManualAction",
- "Comment": "Navmesh can't jump"
+ "InteractionType": "WalkTo"
},
{
"DataId": 1038924,
- "Position": {
- "X": -329.97632,
- "Y": -151.67169,
- "Z": -333.76062
- },
+ "StopDistance": 5,
"TerritoryId": 959,
- "InteractionType": "Interact"
+ "InteractionType": "Interact",
+ "Comment": "Navmesh can't jump"
}
]
},
{
"Sequence": 1,
"Steps": [
+ {
+ "Position": {
+ "X": 68.93551,
+ "Y": -48.912445,
+ "Z": -683.716
+ },
+ "TerritoryId": 959,
+ "InteractionType": "WalkTo",
+ "DisableNavmesh": true,
+ "Mount": true
+ },
+ {
+ "Position": {
+ "X": 86.32549,
+ "Y": -137.4167,
+ "Z": -619.77936
+ },
+ "TerritoryId": 959,
+ "InteractionType": "WalkTo",
+ "DisableNavmesh": true
+ },
{
"DataId": 1038928,
"Position": {
"Z": -405.08124
},
"TerritoryId": 959,
- "InteractionType": "AttuneAetherCurrent"
+ "InteractionType": "AttuneAetherCurrent",
+ "AetherCurrentId": 2818366
},
{
"DataId": 1038929,
"Position": {
- "X": 596.2294,
+ "X": 595.4731,
"Y": -167.50227,
- "Z": -510.33884
+ "Z": -511.4072
},
+ "StopDistance": 0.25,
"TerritoryId": 959,
"InteractionType": "Interact"
}
{
"DataId": 1038929,
"Position": {
- "X": 547.2717,
+ "X": 547.8397,
"Y": -167.50174,
- "Z": -525.274
+ "Z": -526.3702
},
+ "StopDistance": 0.25,
"TerritoryId": 959,
"InteractionType": "Interact"
}
{
"DataId": 1038929,
"Position": {
- "X": 572.0069,
+ "X": 572.45984,
"Y": -167.50163,
- "Z": -574.98785
+ "Z": -577.03906
},
+ "StopDistance": 0.25,
"TerritoryId": 959,
"InteractionType": "Interact"
}
{
"DataId": 1038929,
"Position": {
- "X": 616.97437,
+ "X": 617.89886,
"Y": -167.50163,
- "Z": -593.1553
+ "Z": -594.92847
},
+ "StopDistance": 0.25,
"TerritoryId": 959,
"InteractionType": "Interact"
}
{
"DataId": 1038929,
"Position": {
- "X": 623.16296,
+ "X": 622.8754,
"Y": -167.50217,
- "Z": -657.5506
+ "Z": -659.45184
},
+ "StopDistance": 0.25,
"TerritoryId": 959,
"InteractionType": "Interact"
}
"Y": -168.00002,
"Z": -656.58044
},
+ "StopDistance": 7,
"TerritoryId": 959,
"InteractionType": "Interact"
}
{
"Version": 1,
"Author": "liza",
- "Comment": "Sequence 3 is the end of the chase marker",
"QuestSequence": [
{
"Sequence": 0,
"Z": -512.2606
},
"TerritoryId": 959,
- "InteractionType": "Interact"
+ "InteractionType": "Interact",
+ "AetheryteShortcut": "Mare Lamentorum - Bestways Burrow"
}
]
},
}
]
},
+ {
+ "Sequence": 3,
+ "Steps": [
+ {
+ "DataId": 2012185,
+ "Position": {
+ "X": -5.416992,
+ "Y": -49.05786,
+ "Z": -269.24548
+ },
+ "TerritoryId": 959,
+ "InteractionType": "ManualAction",
+ "Comment": "Duty - Follow Urianger (but you failed the first time)"
+ }
+ ]
+ },
{
"Sequence": 255,
"Steps": [
{
"Sequence": 1,
"Steps": [
+ {
+ "Position": {
+ "X": -126.76068,
+ "Y": 61.04055,
+ "Z": -76.382324
+ },
+ "TerritoryId": 959,
+ "InteractionType": "WalkTo"
+ },
+ {
+ "DataId": 2012014,
+ "Position": {
+ "X": -128.008,
+ "Y": 66.33093,
+ "Z": -68.2536
+ },
+ "StopDistance": 5,
+ "TerritoryId": 959,
+ "InteractionType": "AttuneAetherCurrent",
+ "AetherCurrentId": 2818363
+ },
+ {
+ "Position": {
+ "X": -116.83438,
+ "Y": 63.151585,
+ "Z": -71.81973
+ },
+ "TerritoryId": 959,
+ "InteractionType": "WalkTo"
+ },
+ {
+ "DataId": 2012010,
+ "Position": {
+ "X": 42.58789,
+ "Y": 124.01001,
+ "Z": -167.04059
+ },
+ "TerritoryId": 959,
+ "InteractionType": "AttuneAetherCurrent",
+ "AetherCurrentId": 2818359
+ },
{
"DataId": 1038936,
"Position": {
},
"TerritoryId": 959,
"InteractionType": "Combat",
+ "EnemySpawnType": "AfterInteraction",
"KillEnemyDataIds": [
13998,
14093,
},
"TerritoryId": 959,
"InteractionType": "ManualAction",
+ "AetheryteShortcut": "Mare Lamentorum - Bestways Burrow",
"Comment": "Navmesh can't jump"
},
{
"Y": -154.98596,
"Z": -595.5444
},
+ "StopDistance": 3,
+ "TerritoryId": 959,
+ "InteractionType": "AttuneAetherCurrent",
+ "AetherCurrentId": 2818361
+ },
+ {
+ "Position": {
+ "X": 351.1467,
+ "Y": -167.87698,
+ "Z": -605.0467
+ },
"TerritoryId": 959,
- "InteractionType": "AttuneAetherCurrent"
+ "InteractionType": "WalkTo"
},
{
"DataId": 1038937,
"InteractionType": "Interact",
"Comment": "Teleporter"
},
+ {
+ "Position": {
+ "X": 65.32143,
+ "Y": -49.589592,
+ "Z": -690.11676
+ },
+ "TerritoryId": 959,
+ "InteractionType": "WalkTo"
+ },
{
"DataId": 1038947,
"Position": {
},
"TerritoryId": 959,
"InteractionType": "Combat",
+ "EnemySpawnType": "AutoOnEnterArea",
"KillEnemyDataIds": [
13996,
13997,
{
"Sequence": 3,
"Steps": [
+ {
+ "Position": {
+ "X": 18.495846,
+ "Y": -49.589592,
+ "Z": -301.7225
+ },
+ "TerritoryId": 959,
+ "InteractionType": "WalkTo"
+ },
{
"DataId": 1038950,
"Position": {
"Y": 128.67769,
"Z": 572.0454
},
+ "StopDistance": 5,
"TerritoryId": 959,
- "InteractionType": "Interact",
- "Comment": "Unsure if this is the correct data id"
+ "InteractionType": "Interact"
}
]
}
"Y": 128.6778,
"Z": 566.8573
},
+ "StopDistance": 5,
"TerritoryId": 959,
"InteractionType": "Interact"
}
{
"Sequence": 1,
"Steps": [
+ {
+ "Position": {
+ "X": -614.86835,
+ "Y": 128.67761,
+ "Z": 677.33923
+ },
+ "TerritoryId": 959,
+ "InteractionType": "WalkTo",
+ "Comment": "Avoids Combat"
+ },
{
"DataId": 2012531,
"Position": {
"Z": 407.79736
},
"TerritoryId": 958,
- "InteractionType": "Interact"
+ "InteractionType": "Interact",
+ "AetheryteShortcut": "Garlemald - Camp Broken Glass"
}
]
},
},
"TerritoryId": 962,
"InteractionType": "Interact",
+ "AetheryteShortcut": "Old Sharlayan",
"AethernetShortcut": [
"[Old Sharlayan] Aetheryte Plaza",
"[Old Sharlayan] The Baldesion Annex"
"Y": 3.8989394,
"Z": 7.003784
},
+ "StopDistance": 5,
"TerritoryId": 962,
"InteractionType": "Interact"
}
"Sequence": 2,
"Steps": [
{
- "DataId": 1038978,
- "Position": {
- "X": 202.34985,
- "Y": 1.7699993,
- "Z": 757.71716
- },
"TerritoryId": 957,
- "InteractionType": "Interact",
- "Comment": "Does this get completed automatically on teleport? Using the coords from the next step"
+ "AetheryteShortcut": "Thavnair - Yedlihmad",
+ "InteractionType": "WalkTo",
+ "Comment": "Quest automatically progresses once teleported to Yedlihmad"
}
]
},
{
"DataId": 1038997,
"Position": {
- "X": -37.70625,
- "Y": -9.957219E-05,
- "Z": -134.90237
+ "X": -37.667046,
+ "Y": -0.00014948845,
+ "Z": -136.80333
},
+ "StopDistance": 0.25,
"TerritoryId": 963,
"InteractionType": "Interact"
}
{
"DataId": 1039002,
"Position": {
- "X": 56.012253,
+ "X": 57.04193,
"Y": 26.99999,
- "Z": 44.92237
+ "Z": 46.383568
},
+ "StopDistance": 0.25,
"TerritoryId": 963,
"InteractionType": "Interact",
"AethernetShortcut": [
"Y": 51.57471,
"Z": -597.1924
},
+ "StopDistance": 5,
"TerritoryId": 957,
"InteractionType": "Interact"
}
},
"TerritoryId": 957,
"InteractionType": "Combat",
+ "EnemySpawnType": "AfterInteraction",
"KillEnemyDataIds": [
13994
]
},
"TerritoryId": 957,
"InteractionType": "Combat",
+ "EnemySpawnType": "AfterInteraction",
"KillEnemyDataIds": [
13992,
13993
"Y": 5.2643433,
"Z": -244.4953
},
+ "StopDistance": 10,
"TerritoryId": 957,
"InteractionType": "AttuneAetheryte"
},
"Z": -272.84656
},
"TerritoryId": 957,
- "InteractionType": "Interact"
+ "InteractionType": "Interact",
+ "DisableNavmesh": true
}
]
},
"Z": -343.89258
},
"TerritoryId": 957,
- "InteractionType": "AttuneAetherCurrent"
+ "InteractionType": "AttuneAetherCurrent",
+ "AetherCurrentId": 2818331
},
{
"DataId": 2011997,
"Z": -447.8676
},
"TerritoryId": 957,
- "InteractionType": "AttuneAetherCurrent"
+ "InteractionType": "AttuneAetherCurrent",
+ "AetherCurrentId": 2818336
},
{
"DataId": 1039023,
},
"TerritoryId": 957,
"InteractionType": "Combat",
+ "EnemySpawnType": "AutoOnEnterArea",
"KillEnemyDataIds": [
13991,
13990
},
"TerritoryId": 957,
"InteractionType": "Combat",
+ "EnemySpawnType": "AfterInteraction",
"KillEnemyDataIds": [
13989
]
{
"Sequence": 3,
"Steps": [
+ {
+ "Position": {
+ "X": 543.0377,
+ "Y": 15.147404,
+ "Z": -147.8739
+ },
+ "TerritoryId": 957,
+ "InteractionType": "WalkTo"
+ },
{
"DataId": 2011996,
"Position": {
"Z": -159.1059
},
"TerritoryId": 957,
- "InteractionType": "AttuneAetherCurrent"
+ "InteractionType": "AttuneAetherCurrent",
+ "AetherCurrentId": 2818332,
+ "DisableNavmesh": true
+ },
+ {
+ "Position": {
+ "X": 536.3203,
+ "Y": 12.722106,
+ "Z": -95.65565
+ },
+ "TerritoryId": 957,
+ "InteractionType": "WalkTo"
},
{
"Position": {
},
"TerritoryId": 957,
"InteractionType": "Combat",
+ "EnemySpawnType": "AutoOnEnterArea",
"KillEnemyDataIds": [
13988
]
},
"TerritoryId": 957,
"InteractionType": "Combat",
+ "EnemySpawnType": "AutoOnEnterArea",
"KillEnemyDataIds": [
13987
- ]
+ ],
+ "$": "QuestVariables after: 16 1 0 0 0 128"
},
{
"Position": {
},
"TerritoryId": 957,
"InteractionType": "Combat",
+ "EnemySpawnType": "AutoOnEnterArea",
"KillEnemyDataIds": [
13986
- ]
+ ],
+ "$": "QuestVariables after: 33 1 0 0 0 192"
},
{
"Position": {
},
"TerritoryId": 957,
"InteractionType": "Combat",
+ "EnemySpawnType": "AutoOnEnterArea",
"KillEnemyDataIds": [
13985,
13984
"Z": 425.10107
},
"TerritoryId": 957,
- "InteractionType": "AttuneAetherCurrent"
+ "InteractionType": "AttuneAetherCurrent",
+ "AetherCurrentId": 2818337
},
{
"DataId": 2012207,
"Z": 141.25269
},
"TerritoryId": 957,
- "InteractionType": "ManualAction",
- "Comment": "Navmesh can't swim"
+ "InteractionType": "Interact",
+ "DisableNavmesh": true
}
]
},
"Y": -60.471558,
"Z": 133.25696
},
+ "StopDistance": 0.5,
"TerritoryId": 957,
- "InteractionType": "ManualAction",
- "Comment": "Navmesh can't swim"
+ "InteractionType": "Interact",
+ "DisableNavmesh": true
}
]
},
{
"Sequence": 4,
"Steps": [
+ {
+ "Position": {
+ "X": 235.94444,
+ "Y": -0.6,
+ "Z": 145.83025
+ },
+ "TerritoryId": 957,
+ "InteractionType": "WalkTo",
+ "DisableNavmesh": true,
+ "Mount": true
+ },
+ {
+ "Position": {
+ "X": 252.0308,
+ "Y": 0.57823455,
+ "Z": 150.66217
+ },
+ "TerritoryId": 957,
+ "InteractionType": "WalkTo",
+ "DisableNavmesh": true
+ },
+ {
+ "DataId": 2011999,
+ "Position": {
+ "X": 53.177612,
+ "Y": 11.36792,
+ "Z": 187.396
+ },
+ "TerritoryId": 957,
+ "InteractionType": "AttuneAetherCurrent",
+ "AetherCurrentId": 2818338
+ },
{
"DataId": 1039052,
"Position": {
"Z": 217.85303
},
"TerritoryId": 957,
- "InteractionType": "ManualAction",
- "Comment": "Navmesh can't swim; should *probably* collect the aether current before interacting here"
+ "InteractionType": "Interact"
}
]
},
"Y": 25.65825,
"Z": -319.87494
},
+ "StopDistance": 5,
"TerritoryId": 957,
"InteractionType": "Interact"
}
"Y": 3.1168795,
"Z": -262.0432
},
+ "StopDistance": 15,
"TerritoryId": 957,
- "InteractionType": "Interact"
+ "InteractionType": "Interact",
+ "AetheryteShortcut": "Thavnair - Palaka's Stand"
}
]
},
"Y": 3.1168792,
"Z": -262.62305
},
+ "StopDistance": 7,
"TerritoryId": 957,
"InteractionType": "Interact"
}
{
"Sequence": 255,
"Steps": [
+ {
+ "Position": {
+ "X": 425.544,
+ "Y": 3.1257756,
+ "Z": -218.32741
+ },
+ "TerritoryId": 957,
+ "InteractionType": "WalkTo",
+ "DisableNavmesh": true
+ },
{
"DataId": 1039064,
"Position": {
"Y": 3.1168795,
"Z": -262.62305
},
+ "StopDistance": 5,
"TerritoryId": 957,
"InteractionType": "Interact"
}
"Z": -683.829
},
"TerritoryId": 957,
- "InteractionType": "Interact",
- "Comment": "Travel to Radz-at-Han"
+ "InteractionType": "WalkTo",
+ "Comment": "Travel to Radz-at-Han",
+ "TargetTerritoryId": 963
},
{
"DataId": 1040354,
"Y": 36,
"Z": 71.70203
},
+ "StopDistance": 5,
"TerritoryId": 963,
"InteractionType": "Interact"
}
"Z": -27.023743
},
"TerritoryId": 963,
- "InteractionType": "AttuneAetheryte"
+ "InteractionType": "AttuneAetheryte",
+ "StopDistance": 10,
+ "DisableNavmesh": true
},
{
"DataId": 195,
"Y": -1.9999962,
"Z": 88.12085
},
+ "StopDistance": 5,
"TerritoryId": 963,
"InteractionType": "Interact"
}
"description": "The territory id associated with the location",
"exclusiveMinimum": 0
},
+ "TargetTerritoryId": {
+ "type": "integer",
+ "description": "If set, this step is complete (movement-wise) if this territory id is reached",
+ "exclusiveMinimum": 0
+ },
"InteractionType": {
"type": "string",
"description": "What to do at the position",
using System;
+using System.Linq;
using System.Numerics;
using Dalamud.Game;
using Dalamud.Game.ClientState.Objects;
+using Dalamud.Game.Command;
using Dalamud.Interface.Windowing;
using Dalamud.Plugin;
using Dalamud.Plugin.Services;
private readonly IClientState _clientState;
private readonly IFramework _framework;
private readonly IGameGui _gameGui;
+ private readonly ICommandManager _commandManager;
private readonly GameFunctions _gameFunctions;
private readonly QuestController _questController;
_clientState = clientState;
_framework = framework;
_gameGui = gameGui;
+ _commandManager = commandManager;
_gameFunctions = new GameFunctions(dataManager, objectTable, sigScanner, targetManager, condition, pluginLog);
AetheryteData aetheryteData = new AetheryteData(dataManager);
_pluginInterface.UiBuilder.Draw += _windowSystem.Draw;
_framework.Update += FrameworkUpdate;
+ _commandManager.AddHandler("/qst", new CommandInfo(ProcessCommand));
+
}
private void FrameworkUpdate(IFramework framework)
_movementController.Update();
}
+ private void ProcessCommand(string command, string arguments)
+ {
+ _windowSystem.Windows.Single(x => x is DebugWindow).Toggle();
+ }
+
private unsafe void HandleNavigationShortcut()
{
var inputData = UIInputData.Instance();
_gameGui.ScreenToWorld(new Vector2(inputData->CursorXPosition, inputData->CursorYPosition),
out Vector3 worldPos))
{
- _movementController.NavigateTo(EMovementType.Shortcut, worldPos,
+ _movementController.NavigateTo(EMovementType.Shortcut, null, worldPos,
_gameFunctions.IsFlyingUnlocked(_clientState.TerritoryType));
}
}
public void Dispose()
{
+ _commandManager.RemoveHandler("/qst");
_framework.Update -= FrameworkUpdate;
_pluginInterface.UiBuilder.Draw -= _windowSystem.Draw;
using System.Globalization;
+using System.Linq;
using System.Numerics;
using Dalamud.Game.ClientState.Objects;
using Dalamud.Interface;
using Dalamud.Interface.Components;
using Dalamud.Interface.Windowing;
using Dalamud.Plugin.Services;
+using FFXIVClientStructs.FFXIV.Client.Game;
using FFXIVClientStructs.FFXIV.Client.Game.Control;
using FFXIVClientStructs.FFXIV.Client.UI.Agent;
using ImGuiNET;
if (currentQuest != null)
{
ImGui.TextUnformatted($"Quest: {currentQuest.Quest.Name} / {currentQuest.Sequence} / {currentQuest.Step}");
+
+ var questWork = _gameFunctions.GetQuestEx(currentQuest.Quest.QuestId);
+ if (questWork != null)
+ {
+ var qw = questWork.Value;
+ string vars = "";
+ for (int i = 0; i < 6; ++i)
+ vars += qw.Variables[i] + " ";
+
+ // For combat quests, a sequence to kill 3 enemies works a bit like this:
+ // Trigger enemies → 0
+ // Kill first enemy → 1
+ // Kill second enemy → 2
+ // Last enemy → increase sequence, reset variable to 0
+ // The order in which enemies are killed doesn't seem to matter.
+ // If multiple waves spawn, this continues to count up (e.g. 1 enemy from wave 1, 2 enemies from wave 2, 1 from wave 3) would count to 3 then 0
+ ImGui.Text($"QW: {vars.Trim()} / {qw.Flags}");
+ }
+ else
+ ImGui.TextUnformatted("(Not accepted)");
+
ImGui.TextUnformatted(_questController.DebugState ?? "--");
ImGui.TextUnformatted(_questController.Comment ?? "--");
{
if (ImGui.Button("Move to Target"))
{
- _movementController.NavigateTo(EMovementType.DebugWindow, _targetManager.Target.Position,
- _gameFunctions.IsFlyingUnlocked(_clientState.TerritoryType));
+ _movementController.NavigateTo(EMovementType.DebugWindow, _targetManager.Target.DataId,
+ _targetManager.Target.Position, _gameFunctions.IsFlyingUnlocked(_clientState.TerritoryType));
}
}
else