Handle quests that are unlocked when a previous quest isn't complete yet

master
Liza 2024-08-25 14:45:08 +02:00
parent abee323d2b
commit d310c9ff1b
Signed by: liza
GPG Key ID: 7199F8D727D55F67
6 changed files with 57 additions and 25 deletions

View File

@ -8,7 +8,8 @@ using LLib.GameData;
using Lumina.Excel.GeneratedSheets; using Lumina.Excel.GeneratedSheets;
using Questionable.Model; using Questionable.Model;
using Questionable.Model.Questing; 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; 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 // workaround because the game doesn't require completion of the CT questline through normal means
QuestInfo aTimeToEveryPurpose = (QuestInfo)_quests[new QuestId(425)]; 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) public IQuestInfo GetQuestInfo(ElementId elementId)

View File

@ -494,7 +494,8 @@ internal sealed unsafe class QuestFunctions
if (questInfo.PreviousQuests.Count == 0) if (questInfo.PreviousQuests.Count == 0)
return true; 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 && if (questInfo.PreviousQuestJoin == QuestInfo.QuestJoin.All &&
questInfo.PreviousQuests.Count == completedQuests) questInfo.PreviousQuests.Count == completedQuests)
return true; return true;
@ -504,6 +505,20 @@ internal sealed unsafe class QuestFunctions
return false; 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) private static bool HasCompletedPreviousInstances(QuestInfo questInfo)
{ {
if (questInfo.PreviousInstanceContent.Count == 0) if (questInfo.PreviousInstanceContent.Count == 0)

View File

@ -1,6 +1,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using LLib.GameData; using LLib.GameData;
using Lumina.Excel.GeneratedSheets; using Lumina.Excel.GeneratedSheets2;
using Questionable.Model.Questing; using Questionable.Model.Questing;
namespace Questionable.Model; namespace Questionable.Model;
@ -14,7 +14,7 @@ internal sealed class LeveInfo : IQuestInfo
Level = leve.ClassJobLevel; Level = leve.ClassJobLevel;
JournalGenre = leve.JournalGenre.Row; JournalGenre = leve.JournalGenre.Row;
SortKey = QuestId.Value; SortKey = QuestId.Value;
IssuerDataId = leve.LevelLevemete.Value!.Object; IssuerDataId = leve.LevelLevemete.Value!.Object.Row;
ClassJobs = QuestInfoUtils.AsList(leve.ClassJobCategory.Value!); ClassJobs = QuestInfoUtils.AsList(leve.ClassJobCategory.Value!);
Expansion = (EExpansionVersion)leve.LevelLevemete.Value.Territory.Value!.ExVersion.Row; Expansion = (EExpansionVersion)leve.LevelLevemete.Value.Territory.Value!.ExVersion.Row;
} }

View File

@ -5,7 +5,7 @@ using FFXIVClientStructs.FFXIV.Client.UI.Agent;
using JetBrains.Annotations; using JetBrains.Annotations;
using LLib.GameData; using LLib.GameData;
using Questionable.Model.Questing; using Questionable.Model.Questing;
using ExcelQuest = Lumina.Excel.GeneratedSheets.Quest; using ExcelQuest = Lumina.Excel.GeneratedSheets2.Quest;
namespace Questionable.Model; namespace Questionable.Model;
@ -31,12 +31,17 @@ internal sealed class QuestInfo : IQuestInfo
}; };
Name = $"{quest.Name}{suffix}"; Name = $"{quest.Name}{suffix}";
Level = quest.ClassJobLevel0; Level = quest.ClassJobLevel[0];
IssuerDataId = quest.IssuerStart; IssuerDataId = quest.IssuerStart.Row;
IsRepeatable = quest.IsRepeatable; IsRepeatable = quest.IsRepeatable;
PreviousQuests = quest.PreviousQuest PreviousQuests =
.Select(x => new QuestId((ushort)(x.Row & 0xFFFF))) new List<PreviousQuestInfo>
.Where(x => x.Value != 0) {
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(); .ToImmutableList();
PreviousQuestJoin = (QuestJoin)quest.PreviousQuestJoin; PreviousQuestJoin = (QuestJoin)quest.PreviousQuestJoin;
QuestLocks = quest.QuestLock QuestLocks = quest.QuestLock
@ -47,7 +52,7 @@ internal sealed class QuestInfo : IQuestInfo
JournalGenre = quest.JournalGenre?.Row; JournalGenre = quest.JournalGenre?.Row;
SortKey = quest.SortKey; SortKey = quest.SortKey;
IsMainScenarioQuest = quest.JournalGenre?.Value?.JournalCategory?.Value?.JournalSection?.Row is 0 or 1; 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(); PreviousInstanceContent = quest.InstanceContent.Select(x => (ushort)x.Row).Where(x => x != 0).ToList();
PreviousInstanceContentJoin = (QuestJoin)quest.InstanceContentJoin; PreviousInstanceContentJoin = (QuestJoin)quest.InstanceContentJoin;
GrandCompany = (GrandCompany)quest.GrandCompany.Row; GrandCompany = (GrandCompany)quest.GrandCompany.Row;
@ -64,7 +69,7 @@ internal sealed class QuestInfo : IQuestInfo
public ushort Level { get; } public ushort Level { get; }
public uint IssuerDataId { get; } public uint IssuerDataId { get; }
public bool IsRepeatable { get; } public bool IsRepeatable { get; }
public ImmutableList<QuestId> PreviousQuests { get; set; } public ImmutableList<PreviousQuestInfo> PreviousQuests { get; set; }
public QuestJoin PreviousQuestJoin { get; } public QuestJoin PreviousQuestJoin { get; }
public ImmutableList<QuestId> QuestLocks { get; } public ImmutableList<QuestId> QuestLocks { get; }
public QuestJoin QuestLockJoin { get; } public QuestJoin QuestLockJoin { get; }
@ -89,8 +94,10 @@ internal sealed class QuestInfo : IQuestInfo
AtLeastOne = 2, AtLeastOne = 2,
} }
public void AddPreviousQuest(QuestId questId) public void AddPreviousQuest(PreviousQuestInfo questId)
{ {
PreviousQuests = [..PreviousQuests, questId]; PreviousQuests = [..PreviousQuests, questId];
} }
public sealed record PreviousQuestInfo(QuestId QuestId, byte Sequence = 0);
} }

View File

@ -1,7 +1,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using LLib.GameData; using LLib.GameData;
using Lumina.Excel.GeneratedSheets; using Lumina.Excel.GeneratedSheets2;
namespace Questionable.Model; namespace Questionable.Model;
@ -57,8 +57,8 @@ internal static class QuestInfoUtils
{ EClassJob.Dancer, classJobCategory.DNC }, { EClassJob.Dancer, classJobCategory.DNC },
{ EClassJob.Reaper, classJobCategory.RPR }, { EClassJob.Reaper, classJobCategory.RPR },
{ EClassJob.Sage, classJobCategory.SGE }, { EClassJob.Sage, classJobCategory.SGE },
{ EClassJob.Viper, classJobCategory.VPR }, { EClassJob.Viper, classJobCategory.Unknown1 },
{ EClassJob.Pictomancer, classJobCategory.PCT } { EClassJob.Pictomancer, classJobCategory.Unknown2 }
} }
.Where(y => y.Value) .Where(y => y.Value)
.Select(y => y.Key) .Select(y => y.Key)

View File

@ -19,19 +19,22 @@ internal sealed class QuestTooltipComponent
private readonly TerritoryData _territoryData; private readonly TerritoryData _territoryData;
private readonly QuestFunctions _questFunctions; private readonly QuestFunctions _questFunctions;
private readonly UiUtils _uiUtils; private readonly UiUtils _uiUtils;
private readonly Configuration _configuration;
public QuestTooltipComponent( public QuestTooltipComponent(
QuestRegistry questRegistry, QuestRegistry questRegistry,
QuestData questData, QuestData questData,
TerritoryData territoryData, TerritoryData territoryData,
QuestFunctions questFunctions, QuestFunctions questFunctions,
UiUtils uiUtils) UiUtils uiUtils,
Configuration configuration)
{ {
_questRegistry = questRegistry; _questRegistry = questRegistry;
_questData = questData; _questData = questData;
_territoryData = territoryData; _territoryData = territoryData;
_questFunctions = questFunctions; _questFunctions = questFunctions;
_uiUtils = uiUtils; _uiUtils = uiUtils;
_configuration = configuration;
} }
public void Draw(IQuestInfo quest) public void Draw(IQuestInfo quest)
@ -105,13 +108,13 @@ internal sealed class QuestTooltipComponent
foreach (var q in quest.PreviousQuests) 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)) if (!_questRegistry.IsKnownQuest(qInfo.QuestId))
iconColor = ImGuiColors.DalamudGrey; 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)) if (qInfo is QuestInfo qstInfo && (counter <= 2 || icon != FontAwesomeIcon.Check))
DrawQuestUnlocks(qstInfo, counter + 1); DrawQuestUnlocks(qstInfo, counter + 1);
@ -188,11 +191,17 @@ internal sealed class QuestTooltipComponent
ImGui.Unindent(); 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) if (questInfo.IsMainScenarioQuest)
return $"{questInfo.Name} ({questInfo.QuestId}, MSQ)"; name += $" ({questInfo.QuestId}, MSQ)";
else else
return $"{questInfo.Name} ({questInfo.QuestId})"; name += $" {questInfo.Name} ({questInfo.QuestId})";
return name;
} }
} }