From 2003906bb2e61372a327ac8062411b6314d47039 Mon Sep 17 00:00:00 2001 From: Liza Carvelli Date: Wed, 19 Jun 2024 00:17:51 +0200 Subject: [PATCH] Improve logic for detecting side-quests based off of the quest/to-do list --- .../4410_The Blasphemy Unmasked.json | 19 ++++++++++ .../4415_Warm Hearts, Rekindled Hopes.json | 3 +- Questionable/GameFunctions.cs | 36 +++++++++++++++---- Questionable/Windows/QuestWindow.cs | 13 ++++--- 4 files changed, 58 insertions(+), 13 deletions(-) diff --git a/QuestPaths/Endwalker/MSQ/D-Thavnair2/4410_The Blasphemy Unmasked.json b/QuestPaths/Endwalker/MSQ/D-Thavnair2/4410_The Blasphemy Unmasked.json index a23d73f8..6d23d997 100644 --- a/QuestPaths/Endwalker/MSQ/D-Thavnair2/4410_The Blasphemy Unmasked.json +++ b/QuestPaths/Endwalker/MSQ/D-Thavnair2/4410_The Blasphemy Unmasked.json @@ -51,6 +51,25 @@ { "Sequence": 3, "Steps": [ + { + "Position": { + "X": 81.33277, + "Y": 1.8631814, + "Z": -96.56102 + }, + "TerritoryId": 963, + "InteractionType": "WalkTo", + "DisableNavmesh": true, + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + -128 + ], + "Sprint": true + }, { "DataId": 1037314, "Position": { 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 1b19646c..08e581a0 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,8 +99,7 @@ "TerritoryId": 957, "InteractionType": "WalkTo", "DisableNavmesh": true, - "Mount": true, - "Comment": "FIXME Returning to the surface means navmesh won't move anymore, but the path is still 'running'" + "Mount": true }, { "Position": { diff --git a/Questionable/GameFunctions.cs b/Questionable/GameFunctions.cs index c3118697..cd1588c2 100644 --- a/Questionable/GameFunctions.cs +++ b/Questionable/GameFunctions.cs @@ -148,29 +148,47 @@ internal sealed unsafe class GameFunctions public (ushort CurrentQuest, byte Sequence) GetCurrentQuestInternal() { - 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) { - foreach (var tracked in questManager->TrackedQuestsSpan) + // always prioritize accepting MSQ quests, to make sure we don't turn in one MSQ quest and then go off to do + // side quests until the end of time. + var msqQuest = GetMainStoryQuest(questManager); + if (msqQuest.CurrentQuest != 0 && !questManager->IsQuestAccepted(msqQuest.CurrentQuest)) + return msqQuest; + + // Use the quests in the same order as they're shown in the to-do list, e.g. if the MSQ is the first item, + // do the MSQ; if a side quest is the first item do that side quest. + // + // If no quests are marked as 'priority', accepting a new quest adds it to the top of the list. + for (int i = questManager->TrackedQuestsSpan.Length - 1; i >= 0; --i) { - switch (tracked.QuestType) + ushort currentQuest; + var trackedQuest = questManager->TrackedQuestsSpan[i]; + switch (trackedQuest.QuestType) { default: continue; case 1: // normal quest - currentQuest = questManager->NormalQuestsSpan[tracked.Index].QuestId; + currentQuest = questManager->NormalQuestsSpan[trackedQuest.Index].QuestId; break; } if (_questRegistry.IsKnownQuest(currentQuest)) return (currentQuest, QuestManager.GetQuestSequence(currentQuest)); } + + // if we know no quest of those currently in the to-do list, just do MSQ + return msqQuest; } + return default; + } + + // TODO This doesn't work with unaccepted quests in NG+, only accepted quests + private (ushort CurrentQuest, byte Sequence) GetMainStoryQuest(QuestManager* questManager) + { var scenarioTree = AgentScenarioTree.Instance(); if (scenarioTree == null) return default; @@ -178,10 +196,14 @@ internal sealed unsafe class GameFunctions if (scenarioTree->Data == null) return default; - currentQuest = scenarioTree->Data->CurrentScenarioQuest; + ushort currentQuest = scenarioTree->Data->CurrentScenarioQuest; if (currentQuest == 0) return default; + // if the MSQ is hidden, we generally ignore it + if (questManager->IsQuestAccepted(currentQuest) && questManager->GetQuestById(currentQuest)->IsHidden) + return default; + return (currentQuest, QuestManager.GetQuestSequence(currentQuest)); } diff --git a/Questionable/Windows/QuestWindow.cs b/Questionable/Windows/QuestWindow.cs index 11672649..eb65373b 100644 --- a/Questionable/Windows/QuestWindow.cs +++ b/Questionable/Windows/QuestWindow.cs @@ -36,6 +36,7 @@ internal sealed class QuestWindow : LWindow, IPersistableWindowConfig private readonly GameUiController _gameUiController; private readonly Configuration _configuration; private readonly NavmeshIpc _navmeshIpc; + private readonly QuestRegistry _questRegistry; private readonly ILogger _logger; public QuestWindow(DalamudPluginInterface pluginInterface, @@ -48,6 +49,7 @@ internal sealed class QuestWindow : LWindow, IPersistableWindowConfig GameUiController gameUiController, Configuration configuration, NavmeshIpc navmeshIpc, + QuestRegistry questRegistry, ILogger logger) : base("Questionable###Questionable", ImGuiWindowFlags.AlwaysAutoResize) { @@ -61,6 +63,7 @@ internal sealed class QuestWindow : LWindow, IPersistableWindowConfig _gameUiController = gameUiController; _configuration = configuration; _navmeshIpc = navmeshIpc; + _questRegistry = questRegistry; _logger = logger; #if DEBUG @@ -206,11 +209,11 @@ internal sealed class QuestWindow : LWindow, IPersistableWindowConfig var q = _gameFunctions.GetCurrentQuest(); ImGui.Text($"Current Quest: {q.CurrentQuest} → {q.Sequence}"); +#if false var questManager = QuestManager.Instance(); if (questManager != null) { - // unsure how these are sorted - for (int i = 0; i < 1 /*questManager->TrackedQuestsSpan.Length*/; ++i) + for (int i = questManager->TrackedQuestsSpan.Length - 1; i >= 0; --i) { var trackedQuest = questManager->TrackedQuestsSpan[i]; switch (trackedQuest.QuestType) @@ -220,13 +223,15 @@ internal sealed class QuestWindow : LWindow, IPersistableWindowConfig break; case 1: + _questRegistry.TryGetQuest(questManager->NormalQuestsSpan[trackedQuest.Index].QuestId, + out var quest); ImGui.Text( - $"Tracked quest: {questManager->NormalQuestsSpan[trackedQuest.Index].QuestId}, {trackedQuest.Index}"); + $"Tracked quest: {questManager->NormalQuestsSpan[trackedQuest.Index].QuestId}, {trackedQuest.Index}: {quest?.Name}"); break; } } } - +#endif if (_targetManager.Target != null) {