diff --git a/QuestPaths/Endwalker/MSQ/D-Thavnair2/4415_Warm Hearts, Rekindled Hopes.json b/QuestPaths/Endwalker/MSQ/D-Thavnair2/4415_Warm Hearts, Rekindled Hopes.json index 08e581a0..1b19646c 100644 --- a/QuestPaths/Endwalker/MSQ/D-Thavnair2/4415_Warm Hearts, Rekindled Hopes.json +++ b/QuestPaths/Endwalker/MSQ/D-Thavnair2/4415_Warm Hearts, Rekindled Hopes.json @@ -99,7 +99,8 @@ "TerritoryId": 957, "InteractionType": "WalkTo", "DisableNavmesh": true, - "Mount": true + "Mount": true, + "Comment": "FIXME Returning to the surface means navmesh won't move anymore, but the path is still 'running'" }, { "Position": { diff --git a/QuestPaths/Endwalker/MSQ/E-Elpis/4420_Hope Upon a Flower.json b/QuestPaths/Endwalker/MSQ/E-Elpis/4420_Hope Upon a Flower.json index 41e2d48e..ca793492 100644 --- a/QuestPaths/Endwalker/MSQ/E-Elpis/4420_Hope Upon a Flower.json +++ b/QuestPaths/Endwalker/MSQ/E-Elpis/4420_Hope Upon a Flower.json @@ -34,7 +34,6 @@ "[Crystarium] The Cabinet of Curiosity", "[Crystarium] The Dossal Gate" ], - "Comment": "TODO Check target territory id", "TargetTerritoryId": 844 } ] @@ -63,7 +62,7 @@ null, null, null, - 16 + -16 ] }, { diff --git a/Questionable/Controller/MovementController.cs b/Questionable/Controller/MovementController.cs index a3d97865..999ecc9a 100644 --- a/Questionable/Controller/MovementController.cs +++ b/Questionable/Controller/MovementController.cs @@ -173,7 +173,10 @@ internal sealed class MovementController : IDisposable ResetPathfinding(); if (InputManager.IsAutoRunning()) + { + _logger.LogInformation("Turning off auto-move"); _gameFunctions.ExecuteCommand("/automove off"); + } Destination = new DestinationData(dataId, to, stopDistance ?? (DefaultStopDistance - 0.2f), fly, sprint); MovementStartedAt = DateTime.MaxValue; @@ -227,7 +230,10 @@ internal sealed class MovementController : IDisposable ResetPathfinding(); if (InputManager.IsAutoRunning()) + { + _logger.LogInformation("Turning off auto-move [stop]"); _gameFunctions.ExecuteCommand("/automove off"); + } } public void Dispose() diff --git a/Questionable/Controller/Steps/BaseFactory/AethernetShortcut.cs b/Questionable/Controller/Steps/BaseFactory/AethernetShortcut.cs index a1d1fafa..988d5cd4 100644 --- a/Questionable/Controller/Steps/BaseFactory/AethernetShortcut.cs +++ b/Questionable/Controller/Steps/BaseFactory/AethernetShortcut.cs @@ -108,9 +108,19 @@ internal static class AethernetShortcut return ETaskResult.StillRunning; } - if (aetheryteData.CalculateDistance(clientState.LocalPlayer?.Position ?? Vector3.Zero, - clientState.TerritoryType, To) > 11) - return ETaskResult.StillRunning; + if (aetheryteData.IsCityAetheryte(To)) + { + if (aetheryteData.CalculateDistance(clientState.LocalPlayer?.Position ?? Vector3.Zero, + clientState.TerritoryType, To) > 11) + return ETaskResult.StillRunning; + } + else + { + // some overworld location (e.g. 'Tesselation (Lakeland)' would end up here + if (clientState.TerritoryType != aetheryteData.TerritoryIds[To]) + return ETaskResult.StillRunning; + } + return ETaskResult.TaskComplete; } diff --git a/Questionable/Controller/Steps/BaseFactory/AetheryteShortcut.cs b/Questionable/Controller/Steps/BaseFactory/AetheryteShortcut.cs index 5220876d..58ecb128 100644 --- a/Questionable/Controller/Steps/BaseFactory/AetheryteShortcut.cs +++ b/Questionable/Controller/Steps/BaseFactory/AetheryteShortcut.cs @@ -13,7 +13,10 @@ namespace Questionable.Controller.Steps.BaseFactory; internal static class AetheryteShortcut { - internal sealed class Factory(IServiceProvider serviceProvider, GameFunctions gameFunctions) : ITaskFactory + internal sealed class Factory( + IServiceProvider serviceProvider, + GameFunctions gameFunctions, + AetheryteData aetheryteData) : ITaskFactory { public IEnumerable CreateAllTasks(Quest quest, QuestSequence sequence, QuestStep step) { @@ -21,7 +24,7 @@ internal static class AetheryteShortcut return []; var task = serviceProvider.GetRequiredService() - .With(step, step.AetheryteShortcut.Value); + .With(step, step.AetheryteShortcut.Value, aetheryteData.TerritoryIds[step.AetheryteShortcut.Value]); return [new WaitConditionTask(gameFunctions.CanTeleport, "CanTeleport"), task]; } @@ -41,10 +44,17 @@ internal static class AetheryteShortcut public QuestStep Step { get; set; } = null!; public EAetheryteLocation TargetAetheryte { get; set; } - public ITask With(QuestStep step, EAetheryteLocation targetAetheryte) + /// + /// If using an aethernet shortcut after, the aetheryte's territory-id and the step's territory-id can differ, + /// we always use the aetheryte's territory-id. + /// + public ushort ExpectedTerritoryId { get; set; } + + public ITask With(QuestStep step, EAetheryteLocation targetAetheryte, ushort expectedTerritoryId) { Step = step; TargetAetheryte = targetAetheryte; + ExpectedTerritoryId = expectedTerritoryId; return this; } @@ -52,7 +62,7 @@ internal static class AetheryteShortcut { _continueAt = DateTime.Now.AddSeconds(8); ushort territoryType = clientState.TerritoryType; - if (Step.TerritoryId == territoryType) + if (ExpectedTerritoryId == territoryType) { Vector3 pos = clientState.LocalPlayer!.Position; if (aetheryteData.CalculateDistance(pos, territoryType, TargetAetheryte) < 11 || @@ -84,8 +94,7 @@ internal static class AetheryteShortcut public ETaskResult Update() { - - if (DateTime.Now >= _continueAt && clientState.TerritoryType == Step.TerritoryId) + if (DateTime.Now >= _continueAt && clientState.TerritoryType == ExpectedTerritoryId) return ETaskResult.TaskComplete; return ETaskResult.StillRunning; diff --git a/Questionable/Controller/Steps/BaseFactory/Move.cs b/Questionable/Controller/Steps/BaseFactory/Move.cs index a3d6e1e0..61f7957a 100644 --- a/Questionable/Controller/Steps/BaseFactory/Move.cs +++ b/Questionable/Controller/Steps/BaseFactory/Move.cs @@ -60,8 +60,10 @@ internal static class Move yield break; } - yield return new WaitConditionTask(() => clientState.TerritoryType == Step.TerritoryId, $"Wait(territory: {Step.TerritoryId}"); - yield return new WaitConditionTask(() => movementController.IsNavmeshReady, "Wait(navmesh ready)"); + yield return new WaitConditionTask(() => clientState.TerritoryType == Step.TerritoryId, + $"Wait(territory: {Step.TerritoryId})"); + yield return new WaitConditionTask(() => movementController.IsNavmeshReady, + "Wait(navmesh ready)"); float distance; if (Step.InteractionType == EInteractionType.WalkTo) diff --git a/Questionable/Controller/Steps/InteractionFactory/Say.cs b/Questionable/Controller/Steps/InteractionFactory/Say.cs index 9ec51c37..7f82e9e1 100644 --- a/Questionable/Controller/Steps/InteractionFactory/Say.cs +++ b/Questionable/Controller/Steps/InteractionFactory/Say.cs @@ -13,7 +13,7 @@ internal static class Say { public IEnumerable CreateAllTasks(Quest quest, QuestSequence sequence, QuestStep step) { - if (step.InteractionType != EInteractionType.Emote) + if (step.InteractionType != EInteractionType.Say) return []; diff --git a/Questionable/Data/AetheryteData.cs b/Questionable/Data/AetheryteData.cs index bd66ac67..377fb0ce 100644 --- a/Questionable/Data/AetheryteData.cs +++ b/Questionable/Data/AetheryteData.cs @@ -10,6 +10,29 @@ namespace Questionable.Data; internal sealed class AetheryteData { + public AetheryteData(IDataManager dataManager) + { + Dictionary aethernetNames = new(); + Dictionary territoryIds = new(); + foreach (var aetheryte in dataManager.GetExcelSheet()!.Where(x => x.RowId > 0)) + { + string? aethernetName = aetheryte.AethernetName?.Value?.Name.ToString(); + if (!string.IsNullOrEmpty(aethernetName)) + aethernetNames[(EAetheryteLocation)aetheryte.RowId] = aethernetName; + + if (aetheryte.Territory != null && aetheryte.Territory.Row > 0) + territoryIds[(EAetheryteLocation)aetheryte.RowId] = (ushort)aetheryte.Territory.Row; + } + + AethernetNames = aethernetNames.AsReadOnly(); + TerritoryIds = territoryIds.AsReadOnly(); + + TownTerritoryIds = dataManager.GetExcelSheet()! + .Where(x => x.RowId > 0 && !string.IsNullOrEmpty(x.Name) && x.TerritoryIntendedUse == 0) + .Select(x => (ushort)x.RowId) + .ToList(); + } + public ReadOnlyDictionary Locations { get; } = new Dictionary { @@ -196,24 +219,7 @@ internal sealed class AetheryteData public ReadOnlyDictionary AethernetNames { get; } public ReadOnlyDictionary TerritoryIds { get; } - - public AetheryteData(IDataManager dataManager) - { - Dictionary aethernetNames = new(); - Dictionary territoryIds = new(); - foreach (var aetheryte in dataManager.GetExcelSheet()!.Where(x => x.RowId > 0)) - { - string? aethernetName = aetheryte.AethernetName?.Value?.Name.ToString(); - if (!string.IsNullOrEmpty(aethernetName)) - aethernetNames[(EAetheryteLocation)aetheryte.RowId] = aethernetName; - - if (aetheryte.Territory != null && aetheryte.Territory.Row > 0) - territoryIds[(EAetheryteLocation)aetheryte.RowId] = (ushort)aetheryte.Territory.Row; - } - - AethernetNames = aethernetNames.AsReadOnly(); - TerritoryIds = territoryIds.AsReadOnly(); - } + public IReadOnlyList TownTerritoryIds { get; set; } public float CalculateDistance(Vector3 fromPosition, ushort fromTerritoryType, EAetheryteLocation to) { @@ -225,4 +231,10 @@ internal sealed class AetheryteData return (fromPosition - toPosition).Length(); } + + public bool IsCityAetheryte(EAetheryteLocation aetheryte) + { + var territoryId = TerritoryIds[aetheryte]; + return TownTerritoryIds.Contains(territoryId); + } } diff --git a/Questionable/GameFunctions.cs b/Questionable/GameFunctions.cs index 3ca4c08d..c868f286 100644 --- a/Questionable/GameFunctions.cs +++ b/Questionable/GameFunctions.cs @@ -441,16 +441,26 @@ internal sealed unsafe class GameFunctions { if (ActionManager.Instance()->GetActionStatus(ActionType.Mount, 71) == 0) { - _logger.LogInformation("Using SDS Fenrir as mount"); - return ActionManager.Instance()->UseAction(ActionType.Mount, 71); + if (ActionManager.Instance()->UseAction(ActionType.Mount, 71)) + { + _logger.LogInformation("Using SDS Fenrir as mount"); + return true; + } + + return false; } } else { if (ActionManager.Instance()->GetActionStatus(ActionType.GeneralAction, 9) == 0) { - _logger.LogInformation("Using mount roulette"); - return ActionManager.Instance()->UseAction(ActionType.GeneralAction, 9); + if (ActionManager.Instance()->UseAction(ActionType.GeneralAction, 9)) + { + _logger.LogInformation("Using mount roulette"); + return true; + } + + return false; } } @@ -485,14 +495,17 @@ internal sealed unsafe class GameFunctions contentFinderConditionId, contentId); } else - _logger.LogError("Could not find content for content finder condition (cf: {ContentFinderId})", contentFinderConditionId); + _logger.LogError("Could not find content for content finder condition (cf: {ContentFinderId})", + contentFinderConditionId); } public string? GetDialogueText(Quest currentQuest, string? excelSheetName, string key) { if (excelSheetName == null) { - var questRow = _dataManager.GetExcelSheet()!.GetRow((uint)currentQuest.QuestId + 0x10000); + var questRow = + _dataManager.GetExcelSheet()!.GetRow((uint)currentQuest.QuestId + + 0x10000); if (questRow == null) { _logger.LogError("Could not find quest row for {QuestId}", currentQuest.QuestId); @@ -526,10 +539,10 @@ internal sealed unsafe class GameFunctions return true; return _condition[ConditionFlag.Occupied] || _condition[ConditionFlag.Occupied30] || - _condition[ConditionFlag.Occupied33] || _condition[ConditionFlag.Occupied38] || - _condition[ConditionFlag.Occupied39] || _condition[ConditionFlag.OccupiedInEvent] || - _condition[ConditionFlag.OccupiedInQuestEvent] || _condition[ConditionFlag.OccupiedInCutSceneEvent] || - _condition[ConditionFlag.Casting] || _condition[ConditionFlag.Unknown57] || - _condition[ConditionFlag.BetweenAreas] || _condition[ConditionFlag.BetweenAreas51]; + _condition[ConditionFlag.Occupied33] || _condition[ConditionFlag.Occupied38] || + _condition[ConditionFlag.Occupied39] || _condition[ConditionFlag.OccupiedInEvent] || + _condition[ConditionFlag.OccupiedInQuestEvent] || _condition[ConditionFlag.OccupiedInCutSceneEvent] || + _condition[ConditionFlag.Casting] || _condition[ConditionFlag.Unknown57] || + _condition[ConditionFlag.BetweenAreas] || _condition[ConditionFlag.BetweenAreas51]; } } diff --git a/Questionable/Questionable.csproj b/Questionable/Questionable.csproj index c7874da7..b24b3ae3 100644 --- a/Questionable/Questionable.csproj +++ b/Questionable/Questionable.csproj @@ -1,7 +1,7 @@  net8.0-windows - 0.6 + 0.7 12 enable true diff --git a/Questionable/QuestionablePlugin.cs b/Questionable/QuestionablePlugin.cs index ca86fa00..b3575820 100644 --- a/Questionable/QuestionablePlugin.cs +++ b/Questionable/QuestionablePlugin.cs @@ -92,9 +92,6 @@ public sealed class QuestionablePlugin : IDalamudPlugin serviceCollection.AddTaskWithFactory(); serviceCollection.AddTaskWithFactory(); - // TODO sort this in properly - serviceCollection.AddTaskWithFactory(); - serviceCollection .AddTaskWithFactory