private void AddPreviousQuest(QuestId questToUpdate, QuestId requiredQuestId)
{
QuestInfo quest = (QuestInfo)_quests[questToUpdate];
- quest.AddPreviousQuest(new QuestInfo.PreviousQuestInfo(requiredQuestId));
+ quest.AddPreviousQuest(new PreviousQuestInfo(requiredQuestId));
}
private void AddGcFollowUpQuests()
foreach (QuestId questId in questIds)
{
QuestInfo quest = (QuestInfo)_quests[questId];
- quest.AddQuestLocks(QuestInfo.QuestJoin.AtLeastOne, questIds.Where(x => x != questId).ToArray());
+ quest.AddQuestLocks(EQuestJoin.AtLeastOne, questIds.Where(x => x != questId).ToArray());
}
}
return IsQuestLocked(questId, extraCompletedQuest);
else if (elementId is LeveId leveId)
return IsQuestLocked(leveId);
- else if (elementId is SatisfactionSupplyNpcId)
- return false;
+ else if (elementId is SatisfactionSupplyNpcId satisfactionSupplyNpcId)
+ return IsQuestLocked(satisfactionSupplyNpcId);
else
throw new ArgumentOutOfRangeException(nameof(elementId));
}
- public bool IsQuestLocked(QuestId questId, ElementId? extraCompletedQuest = null)
+ private bool IsQuestLocked(QuestId questId, ElementId? extraCompletedQuest = null)
{
if (IsQuestUnobtainable(questId, extraCompletedQuest))
return true;
return !HasCompletedPreviousQuests(questInfo, extraCompletedQuest) || !HasCompletedPreviousInstances(questInfo);
}
- public bool IsQuestLocked(LeveId leveId)
+ private bool IsQuestLocked(LeveId leveId)
{
if (IsQuestUnobtainable(leveId))
return true;
return !IsQuestAccepted(leveId) && QuestManager.Instance()->NumLeveAllowances == 0;
}
+ private bool IsQuestLocked(SatisfactionSupplyNpcId satisfactionSupplyNpcId)
+ {
+ SatisfactionSupplyInfo questInfo = (SatisfactionSupplyInfo)_questData.GetQuestInfo(satisfactionSupplyNpcId);
+ return !HasCompletedPreviousQuests(questInfo, null);
+ }
+
public bool IsQuestUnobtainable(ElementId elementId, ElementId? extraCompletedQuest = null)
{
if (elementId is QuestId questId)
if (questInfo.QuestLocks.Count > 0)
{
var completedQuests = questInfo.QuestLocks.Count(x => IsQuestComplete(x) || x.Equals(extraCompletedQuest));
- if (questInfo.QuestLockJoin == QuestInfo.QuestJoin.All && questInfo.QuestLocks.Count == completedQuests)
+ if (questInfo.QuestLockJoin == EQuestJoin.All && questInfo.QuestLocks.Count == completedQuests)
return true;
- else if (questInfo.QuestLockJoin == QuestInfo.QuestJoin.AtLeastOne && completedQuests > 0)
+ else if (questInfo.QuestLockJoin == EQuestJoin.AtLeastOne && completedQuests > 0)
return true;
}
return false;
}
- private bool HasCompletedPreviousQuests(QuestInfo questInfo, ElementId? extraCompletedQuest)
+ private bool HasCompletedPreviousQuests(IQuestInfo questInfo, ElementId? extraCompletedQuest)
{
if (questInfo.PreviousQuests.Count == 0)
return true;
var completedQuests = questInfo.PreviousQuests.Count(x =>
HasEnoughProgressOnPreviousQuest(x) || x.QuestId.Equals(extraCompletedQuest));
- if (questInfo.PreviousQuestJoin == QuestInfo.QuestJoin.All &&
+ if (questInfo.PreviousQuestJoin == EQuestJoin.All &&
questInfo.PreviousQuests.Count == completedQuests)
return true;
- else if (questInfo.PreviousQuestJoin == QuestInfo.QuestJoin.AtLeastOne && completedQuests > 0)
+ else if (questInfo.PreviousQuestJoin == EQuestJoin.AtLeastOne && completedQuests > 0)
return true;
else
return false;
}
- private bool HasEnoughProgressOnPreviousQuest(QuestInfo.PreviousQuestInfo previousQuestInfo)
+ private bool HasEnoughProgressOnPreviousQuest(PreviousQuestInfo previousQuestInfo)
{
if (IsQuestComplete(previousQuestInfo.QuestId))
return true;
return true;
var completedInstances = questInfo.PreviousInstanceContent.Count(x => UIState.IsInstanceContentCompleted(x));
- if (questInfo.PreviousInstanceContentJoin == QuestInfo.QuestJoin.All &&
+ if (questInfo.PreviousInstanceContentJoin == EQuestJoin.All &&
questInfo.PreviousInstanceContent.Count == completedInstances)
return true;
- else if (questInfo.PreviousInstanceContentJoin == QuestInfo.QuestJoin.AtLeastOne && completedInstances > 0)
+ else if (questInfo.PreviousInstanceContentJoin == EQuestJoin.AtLeastOne && completedInstances > 0)
return true;
else
return false;
--- /dev/null
+using System.Diagnostics.CodeAnalysis;
+using JetBrains.Annotations;
+
+namespace Questionable.Model;
+
+[SuppressMessage("Design", "CA1028", Justification = "Game type")]
+[UsedImplicitly(ImplicitUseKindFlags.Assign, ImplicitUseTargetFlags.Members)]
+internal enum EQuestJoin : byte
+{
+ None = 0,
+ All = 1,
+ AtLeastOne = 2,
+}
using System;
using System.Collections.Generic;
+using System.Collections.Immutable;
using Dalamud.Game.Text;
using LLib.GameData;
using Questionable.Model.Questing;
namespace Questionable.Model;
-public interface IQuestInfo
+internal interface IQuestInfo
{
public ElementId QuestId { get; }
public string Name { get; }
public uint IssuerDataId { get; }
public bool IsRepeatable { get; }
+ public ImmutableList<PreviousQuestInfo> PreviousQuests { get; }
+ public EQuestJoin PreviousQuestJoin { get; }
public ushort Level { get; }
public EAlliedSociety AlliedSociety { get; }
public uint? JournalGenre { get; }
using System.Collections.Generic;
+using System.Collections.Immutable;
using LLib.GameData;
using Lumina.Excel.GeneratedSheets2;
using Questionable.Model.Questing;
public ElementId QuestId { get; }
public string Name { get; }
public uint IssuerDataId { get; }
+ public ImmutableList<PreviousQuestInfo> PreviousQuests { get; } = [];
+ public EQuestJoin PreviousQuestJoin => EQuestJoin.All;
public bool IsRepeatable => true;
public ushort Level { get; }
public EAlliedSociety AlliedSociety => EAlliedSociety.None;
--- /dev/null
+using Questionable.Model.Questing;
+
+namespace Questionable.Model;
+
+internal sealed record PreviousQuestInfo(QuestId QuestId, byte Sequence = 0);
}
.Where(x => x.QuestId.Value != 0)
.ToImmutableList();
- PreviousQuestJoin = (QuestJoin)quest.PreviousQuestJoin;
+ PreviousQuestJoin = (EQuestJoin)quest.PreviousQuestJoin;
QuestLocks = quest.QuestLock
.Select(x => new QuestId((ushort)(x.Row & 0xFFFFF)))
.Where(x => x.Value != 0)
.ToImmutableList();
- QuestLockJoin = (QuestJoin)quest.QuestLockJoin;
+ QuestLockJoin = (EQuestJoin)quest.QuestLockJoin;
JournalGenre = quest.JournalGenre?.Row;
SortKey = quest.SortKey;
IsMainScenarioQuest = quest.JournalGenre?.Value?.JournalCategory?.Value?.JournalSection?.Row is 0 or 1;
CompletesInstantly = quest.TodoParams[0].ToDoCompleteSeq == 0;
PreviousInstanceContent = quest.InstanceContent.Select(x => (ushort)x.Row).Where(x => x != 0).ToList();
- PreviousInstanceContentJoin = (QuestJoin)quest.InstanceContentJoin;
+ PreviousInstanceContentJoin = (EQuestJoin)quest.InstanceContentJoin;
GrandCompany = (GrandCompany)quest.GrandCompany.Row;
AlliedSociety = (EAlliedSociety)quest.BeastTribe.Row;
ClassJobs = QuestInfoUtils.AsList(quest.ClassJobCategory0.Value!);
public uint IssuerDataId { get; }
public bool IsRepeatable { get; }
public ImmutableList<PreviousQuestInfo> PreviousQuests { get; private set; }
- public QuestJoin PreviousQuestJoin { get; }
+ public EQuestJoin PreviousQuestJoin { get; }
public ImmutableList<QuestId> QuestLocks { get; private set; }
- public QuestJoin QuestLockJoin { get; private set; }
+ public EQuestJoin QuestLockJoin { get; private set; }
public List<ushort> PreviousInstanceContent { get; }
- public QuestJoin PreviousInstanceContentJoin { get; }
+ public EQuestJoin PreviousInstanceContentJoin { get; }
public uint? JournalGenre { get; }
public ushort SortKey { get; }
public bool IsMainScenarioQuest { get; }
public byte StartingCity { get; set; }
public EExpansionVersion Expansion { get; }
- [UsedImplicitly(ImplicitUseKindFlags.Assign, ImplicitUseTargetFlags.Members)]
- public enum QuestJoin : byte
- {
- None = 0,
- All = 1,
- AtLeastOne = 2,
- }
-
public void AddPreviousQuest(PreviousQuestInfo questId)
{
PreviousQuests = [..PreviousQuests, questId];
}
- public void AddQuestLocks(QuestJoin questJoin, params QuestId[] questId)
+ public void AddQuestLocks(EQuestJoin questJoin, params QuestId[] questId)
{
if (QuestLocks.Count > 0 && QuestLockJoin != questJoin)
throw new InvalidOperationException();
QuestLockJoin = questJoin;
QuestLocks = [..QuestLocks, ..questId];
}
-
- public sealed record PreviousQuestInfo(QuestId QuestId, byte Sequence = 0);
}
using System.Collections.Generic;
+using System.Collections.Immutable;
using LLib.GameData;
using Lumina.Excel.GeneratedSheets;
using Questionable.Model.Questing;
Level = npc.LevelUnlock;
SortKey = QuestId.Value;
Expansion = (EExpansionVersion)npc.QuestRequired.Value!.Expansion.Row;
+ PreviousQuests = [new PreviousQuestInfo(new QuestId((ushort)(npc.QuestRequired.Row & 0xFFFF)))];
}
public ElementId QuestId { get; }
public string Name { get; }
public uint IssuerDataId { get; }
public bool IsRepeatable => true;
+ public ImmutableList<PreviousQuestInfo> PreviousQuests { get; }
+ public EQuestJoin PreviousQuestJoin => EQuestJoin.All;
public ushort Level { get; }
public EAlliedSociety AlliedSociety => EAlliedSociety.None;
public uint? JournalGenre => null;
using Questionable.Data;
using Questionable.Functions;
using Questionable.Model;
-using Questionable.Model.Questing;
namespace Questionable.Windows.QuestComponents;
_configuration = configuration;
}
- public void Draw(IQuestInfo quest)
- {
- if (quest is QuestInfo questInfo)
- Draw(questInfo);
- }
-
- public void Draw(QuestInfo quest)
+ public void Draw(IQuestInfo questInfo)
{
using var tooltip = ImRaii.Tooltip();
if (tooltip)
{
- ImGui.Text($"{SeIconChar.LevelEn.ToIconString()}{quest.Level}");
+ ImGui.Text($"{SeIconChar.LevelEn.ToIconString()}{questInfo.Level}");
ImGui.SameLine();
- var (color, _, tooltipText) = _uiUtils.GetQuestStyle(quest.QuestId);
+ var (color, _, tooltipText) = _uiUtils.GetQuestStyle(questInfo.QuestId);
ImGui.TextColored(color, tooltipText);
- if (quest.IsRepeatable)
+ if (questInfo.IsRepeatable)
{
ImGui.SameLine();
ImGui.TextUnformatted("Repeatable");
}
- if (quest.CompletesInstantly)
+ if (questInfo is QuestInfo { CompletesInstantly: true })
{
ImGui.SameLine();
ImGui.TextUnformatted("Instant");
}
- if (_questRegistry.TryGetQuest(quest.QuestId, out Quest? knownQuest))
+ if (_questRegistry.TryGetQuest(questInfo.QuestId, out Quest? quest))
{
- if (knownQuest.Root.Author.Count == 1)
- ImGui.Text($"Author: {knownQuest.Root.Author[0]}");
+ if (quest.Root.Author.Count == 1)
+ ImGui.Text($"Author: {quest.Root.Author[0]}");
else
- ImGui.Text($"Authors: {string.Join(", ", knownQuest.Root.Author)}");
+ ImGui.Text($"Authors: {string.Join(", ", quest.Root.Author)}");
}
else
{
ImGui.TextUnformatted("NoQuestPath");
}
- DrawQuestUnlocks(quest, 0);
+ DrawQuestUnlocks(questInfo, 0);
}
}
- private void DrawQuestUnlocks(QuestInfo quest, int counter)
+ private void DrawQuestUnlocks(IQuestInfo questInfo, int counter)
{
if (counter >= 10)
return;
- if (counter != 0 && quest.IsMainScenarioQuest)
+ if (counter != 0 && questInfo.IsMainScenarioQuest)
return;
if (counter > 0)
ImGui.Indent();
- if (quest.PreviousQuests.Count > 0)
+ if (questInfo.PreviousQuests.Count > 0)
{
if (counter == 0)
ImGui.Separator();
- if (quest.PreviousQuests.Count > 1)
+ if (questInfo.PreviousQuests.Count > 1)
{
- if (quest.PreviousQuestJoin == QuestInfo.QuestJoin.All)
+ if (questInfo.PreviousQuestJoin == EQuestJoin.All)
ImGui.Text("Requires all:");
- else if (quest.PreviousQuestJoin == QuestInfo.QuestJoin.AtLeastOne)
+ else if (questInfo.PreviousQuestJoin == EQuestJoin.AtLeastOne)
ImGui.Text("Requires one:");
}
- foreach (var q in quest.PreviousQuests)
+ foreach (var q in questInfo.PreviousQuests)
{
if (_questData.TryGetQuestInfo(q.QuestId, out var qInfo))
{
if (!_questRegistry.IsKnownQuest(qInfo.QuestId))
iconColor = ImGuiColors.DalamudGrey;
- _uiUtils.ChecklistItem(FormatQuestUnlockName(qInfo, _questFunctions.IsQuestComplete(q.QuestId) ? byte.MinValue : q.Sequence), 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);
}
}
- if (counter == 0 && quest.QuestLocks.Count > 0)
+ if (questInfo is QuestInfo actualQuestInfo)
{
- ImGui.Separator();
- if (quest.QuestLocks.Count > 1)
+ if (counter == 0 && actualQuestInfo.QuestLocks.Count > 0)
{
- if (quest.QuestLockJoin == QuestInfo.QuestJoin.All)
- ImGui.Text("Blocked by (if all completed):");
- else if (quest.QuestLockJoin == QuestInfo.QuestJoin.AtLeastOne)
- ImGui.Text("Blocked by (if at least completed):");
- }
- else
- ImGui.Text("Blocked by (if completed):");
+ ImGui.Separator();
+ if (actualQuestInfo.QuestLocks.Count > 1)
+ {
+ if (actualQuestInfo.QuestLockJoin == EQuestJoin.All)
+ ImGui.Text("Blocked by (if all completed):");
+ else if (actualQuestInfo.QuestLockJoin == EQuestJoin.AtLeastOne)
+ ImGui.Text("Blocked by (if at least completed):");
+ }
+ else
+ ImGui.Text("Blocked by (if completed):");
- foreach (var q in quest.QuestLocks)
- {
- var qInfo = _questData.GetQuestInfo(q);
- var (iconColor, icon, _) = _uiUtils.GetQuestStyle(q);
- if (!_questRegistry.IsKnownQuest(qInfo.QuestId))
- iconColor = ImGuiColors.DalamudGrey;
+ foreach (var q in actualQuestInfo.QuestLocks)
+ {
+ var qInfo = _questData.GetQuestInfo(q);
+ var (iconColor, icon, _) = _uiUtils.GetQuestStyle(q);
+ if (!_questRegistry.IsKnownQuest(qInfo.QuestId))
+ iconColor = ImGuiColors.DalamudGrey;
- _uiUtils.ChecklistItem(FormatQuestUnlockName(qInfo), iconColor, icon);
+ _uiUtils.ChecklistItem(FormatQuestUnlockName(qInfo), iconColor, icon);
+ }
}
- }
- if (counter == 0 && quest.PreviousInstanceContent.Count > 0)
- {
- ImGui.Separator();
- if (quest.PreviousInstanceContent.Count > 1)
+ if (counter == 0 && actualQuestInfo.PreviousInstanceContent.Count > 0)
{
- if (quest.PreviousQuestJoin == QuestInfo.QuestJoin.All)
- ImGui.Text("Requires all:");
- else if (quest.PreviousQuestJoin == QuestInfo.QuestJoin.AtLeastOne)
- ImGui.Text("Requires one:");
- }
- else
- ImGui.Text("Requires:");
+ ImGui.Separator();
+ if (actualQuestInfo.PreviousInstanceContent.Count > 1)
+ {
+ if (questInfo.PreviousQuestJoin == EQuestJoin.All)
+ ImGui.Text("Requires all:");
+ else if (questInfo.PreviousQuestJoin == EQuestJoin.AtLeastOne)
+ ImGui.Text("Requires one:");
+ }
+ else
+ ImGui.Text("Requires:");
- foreach (var instanceId in quest.PreviousInstanceContent)
- {
- string instanceName = _territoryData.GetInstanceName(instanceId) ?? "?";
- var (iconColor, icon) = UiUtils.GetInstanceStyle(instanceId);
- _uiUtils.ChecklistItem(instanceName, iconColor, icon);
+ foreach (var instanceId in actualQuestInfo.PreviousInstanceContent)
+ {
+ string instanceName = _territoryData.GetInstanceName(instanceId) ?? "?";
+ var (iconColor, icon) = UiUtils.GetInstanceStyle(instanceId);
+ _uiUtils.ChecklistItem(instanceName, iconColor, icon);
+ }
}
- }
- if (counter == 0 && quest.GrandCompany != GrandCompany.None)
- {
- ImGui.Separator();
- string gcName = quest.GrandCompany switch
+ if (counter == 0 && actualQuestInfo.GrandCompany != GrandCompany.None)
{
- GrandCompany.Maelstrom => "Maelstrom",
- GrandCompany.TwinAdder => "Twin Adder",
- GrandCompany.ImmortalFlames => "Immortal Flames",
- _ => "None",
- };
-
- GrandCompany currentGrandCompany = ~_questFunctions.GetGrandCompany();
- _uiUtils.ChecklistItem($"Grand Company: {gcName}", quest.GrandCompany == currentGrandCompany);
+ ImGui.Separator();
+ string gcName = actualQuestInfo.GrandCompany switch
+ {
+ GrandCompany.Maelstrom => "Maelstrom",
+ GrandCompany.TwinAdder => "Twin Adder",
+ GrandCompany.ImmortalFlames => "Immortal Flames",
+ _ => "None",
+ };
+
+ GrandCompany currentGrandCompany = ~_questFunctions.GetGrandCompany();
+ _uiUtils.ChecklistItem($"Grand Company: {gcName}", actualQuestInfo.GrandCompany == currentGrandCompany);
+ }
}
if (counter > 0)