From d310c9ff1bb259dcabad2f7ff2c1aa8ae3e3d560 Mon Sep 17 00:00:00 2001 From: Liza Carvelli Date: Sun, 25 Aug 2024 14:45:08 +0200 Subject: [PATCH] Handle quests that are unlocked when a previous quest isn't complete yet --- Questionable/Data/QuestData.cs | 5 ++-- Questionable/Functions/QuestFunctions.cs | 17 +++++++++++- Questionable/Model/LeveInfo.cs | 4 +-- Questionable/Model/QuestInfo.cs | 27 ++++++++++++------- Questionable/Model/QuestInfoUtils.cs | 6 ++--- .../QuestComponents/QuestTooltipComponent.cs | 23 +++++++++++----- 6 files changed, 57 insertions(+), 25 deletions(-) diff --git a/Questionable/Data/QuestData.cs b/Questionable/Data/QuestData.cs index 3a5f64acc..c2a8aba39 100644 --- a/Questionable/Data/QuestData.cs +++ b/Questionable/Data/QuestData.cs @@ -8,7 +8,8 @@ using LLib.GameData; using Lumina.Excel.GeneratedSheets; using Questionable.Model; using Questionable.Model.Questing; -using Quest = Lumina.Excel.GeneratedSheets.Quest; +using Leve = Lumina.Excel.GeneratedSheets2.Leve; +using Quest = Lumina.Excel.GeneratedSheets2.Quest; namespace Questionable.Data; @@ -62,7 +63,7 @@ internal sealed class QuestData // workaround because the game doesn't require completion of the CT questline through normal means QuestInfo aTimeToEveryPurpose = (QuestInfo)_quests[new QuestId(425)]; - aTimeToEveryPurpose.AddPreviousQuest(new QuestId(495)); + aTimeToEveryPurpose.AddPreviousQuest(new QuestInfo.PreviousQuestInfo(new QuestId(495))); } public IQuestInfo GetQuestInfo(ElementId elementId) diff --git a/Questionable/Functions/QuestFunctions.cs b/Questionable/Functions/QuestFunctions.cs index 7e360cd69..15a2dec1c 100644 --- a/Questionable/Functions/QuestFunctions.cs +++ b/Questionable/Functions/QuestFunctions.cs @@ -494,7 +494,8 @@ internal sealed unsafe class QuestFunctions if (questInfo.PreviousQuests.Count == 0) return true; - var completedQuests = questInfo.PreviousQuests.Count(x => IsQuestComplete(x) || x.Equals(extraCompletedQuest)); + var completedQuests = questInfo.PreviousQuests.Count(x => + HasEnoughProgressOnPreviousQuest(x) || x.QuestId.Equals(extraCompletedQuest)); if (questInfo.PreviousQuestJoin == QuestInfo.QuestJoin.All && questInfo.PreviousQuests.Count == completedQuests) return true; @@ -504,6 +505,20 @@ internal sealed unsafe class QuestFunctions return false; } + private bool HasEnoughProgressOnPreviousQuest(QuestInfo.PreviousQuestInfo previousQuestInfo) + { + if (IsQuestComplete(previousQuestInfo.QuestId)) + return true; + + if (previousQuestInfo.Sequence != 0 && IsQuestAccepted(previousQuestInfo.QuestId)) + { + var progress = GetQuestProgressInfo(previousQuestInfo.QuestId); + return progress != null && progress.Sequence >= previousQuestInfo.Sequence; + } + + return false; + } + private static bool HasCompletedPreviousInstances(QuestInfo questInfo) { if (questInfo.PreviousInstanceContent.Count == 0) diff --git a/Questionable/Model/LeveInfo.cs b/Questionable/Model/LeveInfo.cs index b446da9a7..d50ac82e4 100644 --- a/Questionable/Model/LeveInfo.cs +++ b/Questionable/Model/LeveInfo.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; using LLib.GameData; -using Lumina.Excel.GeneratedSheets; +using Lumina.Excel.GeneratedSheets2; using Questionable.Model.Questing; namespace Questionable.Model; @@ -14,7 +14,7 @@ internal sealed class LeveInfo : IQuestInfo Level = leve.ClassJobLevel; JournalGenre = leve.JournalGenre.Row; SortKey = QuestId.Value; - IssuerDataId = leve.LevelLevemete.Value!.Object; + IssuerDataId = leve.LevelLevemete.Value!.Object.Row; ClassJobs = QuestInfoUtils.AsList(leve.ClassJobCategory.Value!); Expansion = (EExpansionVersion)leve.LevelLevemete.Value.Territory.Value!.ExVersion.Row; } diff --git a/Questionable/Model/QuestInfo.cs b/Questionable/Model/QuestInfo.cs index 2c9c29517..d78838fc9 100644 --- a/Questionable/Model/QuestInfo.cs +++ b/Questionable/Model/QuestInfo.cs @@ -5,7 +5,7 @@ using FFXIVClientStructs.FFXIV.Client.UI.Agent; using JetBrains.Annotations; using LLib.GameData; using Questionable.Model.Questing; -using ExcelQuest = Lumina.Excel.GeneratedSheets.Quest; +using ExcelQuest = Lumina.Excel.GeneratedSheets2.Quest; namespace Questionable.Model; @@ -31,13 +31,18 @@ internal sealed class QuestInfo : IQuestInfo }; Name = $"{quest.Name}{suffix}"; - Level = quest.ClassJobLevel0; - IssuerDataId = quest.IssuerStart; + Level = quest.ClassJobLevel[0]; + IssuerDataId = quest.IssuerStart.Row; IsRepeatable = quest.IsRepeatable; - PreviousQuests = quest.PreviousQuest - .Select(x => new QuestId((ushort)(x.Row & 0xFFFF))) - .Where(x => x.Value != 0) - .ToImmutableList(); + PreviousQuests = + new List + { + new(new QuestId((ushort)(quest.PreviousQuest[0].Row & 0xFFFF)), quest.Unknown7), + new(new QuestId((ushort)(quest.PreviousQuest[1].Row & 0xFFFF))), + new(new QuestId((ushort)(quest.PreviousQuest[1].Row & 0xFFFF))) + } + .Where(x => x.QuestId.Value != 0) + .ToImmutableList(); PreviousQuestJoin = (QuestJoin)quest.PreviousQuestJoin; QuestLocks = quest.QuestLock .Select(x => new QuestId((ushort)(x.Row & 0xFFFFF))) @@ -47,7 +52,7 @@ internal sealed class QuestInfo : IQuestInfo JournalGenre = quest.JournalGenre?.Row; SortKey = quest.SortKey; IsMainScenarioQuest = quest.JournalGenre?.Value?.JournalCategory?.Value?.JournalSection?.Row is 0 or 1; - CompletesInstantly = quest.ToDoCompleteSeq[0] == 0; + CompletesInstantly = quest.TodoParams[0].ToDoCompleteSeq == 0; PreviousInstanceContent = quest.InstanceContent.Select(x => (ushort)x.Row).Where(x => x != 0).ToList(); PreviousInstanceContentJoin = (QuestJoin)quest.InstanceContentJoin; GrandCompany = (GrandCompany)quest.GrandCompany.Row; @@ -64,7 +69,7 @@ internal sealed class QuestInfo : IQuestInfo public ushort Level { get; } public uint IssuerDataId { get; } public bool IsRepeatable { get; } - public ImmutableList PreviousQuests { get; set; } + public ImmutableList PreviousQuests { get; set; } public QuestJoin PreviousQuestJoin { get; } public ImmutableList QuestLocks { get; } public QuestJoin QuestLockJoin { get; } @@ -89,8 +94,10 @@ internal sealed class QuestInfo : IQuestInfo AtLeastOne = 2, } - public void AddPreviousQuest(QuestId questId) + public void AddPreviousQuest(PreviousQuestInfo questId) { PreviousQuests = [..PreviousQuests, questId]; } + + public sealed record PreviousQuestInfo(QuestId QuestId, byte Sequence = 0); } diff --git a/Questionable/Model/QuestInfoUtils.cs b/Questionable/Model/QuestInfoUtils.cs index 688458840..4f44fd4aa 100644 --- a/Questionable/Model/QuestInfoUtils.cs +++ b/Questionable/Model/QuestInfoUtils.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using System.Linq; using LLib.GameData; -using Lumina.Excel.GeneratedSheets; +using Lumina.Excel.GeneratedSheets2; namespace Questionable.Model; @@ -57,8 +57,8 @@ internal static class QuestInfoUtils { EClassJob.Dancer, classJobCategory.DNC }, { EClassJob.Reaper, classJobCategory.RPR }, { EClassJob.Sage, classJobCategory.SGE }, - { EClassJob.Viper, classJobCategory.VPR }, - { EClassJob.Pictomancer, classJobCategory.PCT } + { EClassJob.Viper, classJobCategory.Unknown1 }, + { EClassJob.Pictomancer, classJobCategory.Unknown2 } } .Where(y => y.Value) .Select(y => y.Key) diff --git a/Questionable/Windows/QuestComponents/QuestTooltipComponent.cs b/Questionable/Windows/QuestComponents/QuestTooltipComponent.cs index d181d45a8..cda7636c2 100644 --- a/Questionable/Windows/QuestComponents/QuestTooltipComponent.cs +++ b/Questionable/Windows/QuestComponents/QuestTooltipComponent.cs @@ -19,19 +19,22 @@ internal sealed class QuestTooltipComponent private readonly TerritoryData _territoryData; private readonly QuestFunctions _questFunctions; private readonly UiUtils _uiUtils; + private readonly Configuration _configuration; public QuestTooltipComponent( QuestRegistry questRegistry, QuestData questData, TerritoryData territoryData, QuestFunctions questFunctions, - UiUtils uiUtils) + UiUtils uiUtils, + Configuration configuration) { _questRegistry = questRegistry; _questData = questData; _territoryData = territoryData; _questFunctions = questFunctions; _uiUtils = uiUtils; + _configuration = configuration; } public void Draw(IQuestInfo quest) @@ -105,13 +108,13 @@ internal sealed class QuestTooltipComponent foreach (var q in quest.PreviousQuests) { - if (_questData.TryGetQuestInfo(q, out var qInfo)) + if (_questData.TryGetQuestInfo(q.QuestId, out var qInfo)) { - var (iconColor, icon, _) = _uiUtils.GetQuestStyle(q); + var (iconColor, icon, _) = _uiUtils.GetQuestStyle(q.QuestId); if (!_questRegistry.IsKnownQuest(qInfo.QuestId)) iconColor = ImGuiColors.DalamudGrey; - _uiUtils.ChecklistItem(FormatQuestUnlockName(qInfo), iconColor, icon); + _uiUtils.ChecklistItem(FormatQuestUnlockName(qInfo, _questFunctions.IsQuestComplete(q.QuestId) ? byte.MinValue : q.Sequence), iconColor, icon); if (qInfo is QuestInfo qstInfo && (counter <= 2 || icon != FontAwesomeIcon.Check)) DrawQuestUnlocks(qstInfo, counter + 1); @@ -188,11 +191,17 @@ internal sealed class QuestTooltipComponent ImGui.Unindent(); } - private static string FormatQuestUnlockName(IQuestInfo questInfo) + private string FormatQuestUnlockName(IQuestInfo questInfo, byte sequence = 0) { + string name = questInfo.Name; + if (_configuration.Advanced.AdditionalStatusInformation && sequence != 0) + name += $" {SeIconChar.ItemLevel.ToIconString()}"; + if (questInfo.IsMainScenarioQuest) - return $"{questInfo.Name} ({questInfo.QuestId}, MSQ)"; + name += $" ({questInfo.QuestId}, MSQ)"; else - return $"{questInfo.Name} ({questInfo.QuestId})"; + name += $" {questInfo.Name} ({questInfo.QuestId})"; + + return name; } }