Add Arcadion quests

This commit is contained in:
Liza 2024-07-16 14:43:31 +02:00
parent fb9e31cd80
commit 3a742ea2ad
Signed by: liza
GPG Key ID: 7199F8D727D55F67
16 changed files with 485 additions and 24 deletions

View File

@ -0,0 +1,60 @@
{
"$schema": "https://carvel.li/questionable/quest-1.0",
"Author": "liza",
"QuestSequence": [
{
"Sequence": 0,
"Steps": [
{
"DataId": 1049786,
"Position": {
"X": 340.13867,
"Y": 50.75,
"Z": 231.37244
},
"TerritoryId": 1186,
"InteractionType": "AcceptQuest"
}
]
},
{
"Sequence": 1,
"Steps": [
{
"DataId": 1049787,
"Position": {
"X": 364.3396,
"Y": 60.125,
"Z": 357.1068
},
"TerritoryId": 1186,
"InteractionType": "Interact",
"DialogueChoices": [
{
"Type": "YesNo",
"Prompt": "TEXT_KINGRA101_04960_SYSTEM_100_030",
"Yes": true
}
]
}
]
},
{
"Sequence": 255,
"Steps": [
{
"DataId": 1049788,
"Position": {
"X": 1.6021729,
"Y": 0,
"Z": -6.088379
},
"StopDistance": 5,
"TerritoryId": 1224,
"InteractionType": "CompleteQuest",
"NextQuestId": 4961
}
]
}
]
}

View File

@ -0,0 +1,52 @@
{
"$schema": "https://carvel.li/questionable/quest-1.0",
"Author": "liza",
"TerritoryBlacklist": [
1225
],
"QuestSequence": [
{
"Sequence": 0,
"Steps": [
{
"DataId": 1049788,
"Position": {
"X": 1.6021729,
"Y": 0,
"Z": -6.088379
},
"StopDistance": 5,
"TerritoryId": 1224,
"InteractionType": "AcceptQuest"
}
]
},
{
"Sequence": 1,
"Steps": [
{
"TerritoryId": 1224,
"InteractionType": "Duty",
"ContentFinderConditionId": 985
}
]
},
{
"Sequence": 255,
"Steps": [
{
"DataId": 1050476,
"Position": {
"X": 0.1373291,
"Y": -3.3667622E-13,
"Z": -9.658997
},
"StopDistance": 7,
"TerritoryId": 1224,
"InteractionType": "CompleteQuest",
"NextQuestId": 4962
}
]
}
]
}

View File

@ -0,0 +1,68 @@
{
"$schema": "https://carvel.li/questionable/quest-1.0",
"Author": "liza",
"TerritoryBlacklist": [
1227
],
"QuestSequence": [
{
"Sequence": 0,
"Steps": [
{
"DataId": 1050476,
"Position": {
"X": 0.1373291,
"Y": -3.3667622E-13,
"Z": -9.658997
},
"StopDistance": 7,
"TerritoryId": 1224,
"InteractionType": "AcceptQuest"
}
]
},
{
"Sequence": 1,
"Steps": [
{
"TerritoryId": 1224,
"InteractionType": "Duty",
"ContentFinderConditionId": 987
}
]
},
{
"Sequence": 2,
"Steps": [
{
"DataId": 1050476,
"Position": {
"X": 0.1373291,
"Y": -3.3667622E-13,
"Z": -9.658997
},
"StopDistance": 7,
"TerritoryId": 1224,
"InteractionType": "Interact"
}
]
},
{
"Sequence": 255,
"Steps": [
{
"DataId": 1050477,
"Position": {
"X": 1.663208,
"Y": -1.9688797E-12,
"Z": -10.727112
},
"StopDistance": 7,
"TerritoryId": 1224,
"InteractionType": "CompleteQuest",
"NextQuestId": 4963
}
]
}
]
}

View File

@ -0,0 +1,55 @@
{
"$schema": "https://carvel.li/questionable/quest-1.0",
"Author": "liza",
"QuestSequence": [
{
"Sequence": 0,
"Steps": [
{
"DataId": 1050477,
"Position": {
"X": 1.663208,
"Y": -1.9688797E-12,
"Z": -10.727112
},
"StopDistance": 7,
"TerritoryId": 1224,
"InteractionType": "AcceptQuest"
}
]
},
{
"Sequence": 1,
"Steps": [
{
"DataId": 1049790,
"Position": {
"X": 494.7433,
"Y": 59.55,
"Z": 125.10864
},
"StopDistance": 5,
"TerritoryId": 1186,
"InteractionType": "Interact"
}
]
},
{
"Sequence": 255,
"Steps": [
{
"DataId": 1049789,
"Position": {
"X": 2.3651123,
"Y": -4.334177E-12,
"Z": -14.206177
},
"StopDistance": 7,
"TerritoryId": 1224,
"InteractionType": "CompleteQuest",
"NextQuestId": 4964
}
]
}
]
}

View File

@ -0,0 +1,68 @@
{
"$schema": "https://carvel.li/questionable/quest-1.0",
"Author": "liza",
"TerritoryBlacklist": [
1229
],
"QuestSequence": [
{
"Sequence": 0,
"Steps": [
{
"DataId": 1049789,
"Position": {
"X": 2.3651123,
"Y": -4.334177E-12,
"Z": -14.206177
},
"StopDistance": 7,
"TerritoryId": 1224,
"InteractionType": "AcceptQuest"
}
]
},
{
"Sequence": 1,
"Steps": [
{
"TerritoryId": 1224,
"InteractionType": "Duty",
"ContentFinderConditionId": 989
}
]
},
{
"Sequence": 2,
"Steps": [
{
"DataId": 1050477,
"Position": {
"X": 1.663208,
"Y": -1.9688797E-12,
"Z": -10.727112
},
"StopDistance": 7,
"TerritoryId": 1224,
"InteractionType": "Interact"
}
]
},
{
"Sequence": 255,
"Steps": [
{
"DataId": 1050477,
"Position": {
"X": 1.663208,
"Y": -1.9688797E-12,
"Z": -10.727112
},
"StopDistance": 7,
"TerritoryId": 1224,
"InteractionType": "CompleteQuest",
"NextQuestId": 4965
}
]
}
]
}

View File

@ -0,0 +1,96 @@
{
"$schema": "https://carvel.li/questionable/quest-1.0",
"Author": "liza",
"TerritoryBlacklist": [
1231
],
"QuestSequence": [
{
"Sequence": 0,
"Steps": [
{
"DataId": 1049792,
"Position": {
"X": 1.663208,
"Y": -1.9688797E-12,
"Z": -10.727112
},
"StopDistance": 7,
"TerritoryId": 1224,
"InteractionType": "AcceptQuest"
}
]
},
{
"Sequence": 1,
"Steps": [
{
"TerritoryId": 1224,
"InteractionType": "Duty",
"ContentFinderConditionId": 991
}
]
},
{
"Sequence": 2,
"Steps": [
{
"DataId": 1050477,
"Position": {
"X": 1.663208,
"Y": -1.9688797E-12,
"Z": -10.727112
},
"StopDistance": 7,
"TerritoryId": 1224,
"InteractionType": "Interact"
}
]
},
{
"Sequence": 3,
"Steps": [
{
"DataId": 2013722,
"Position": {
"X": -0.07635498,
"Y": 1.0527954,
"Z": 8.102478
},
"TerritoryId": 1224,
"InteractionType": "Interact",
"TargetTerritoryId": 1186
},
{
"DataId": 1049790,
"Position": {
"X": 494.7433,
"Y": 59.55,
"Z": 125.10864
},
"TerritoryId": 1186,
"InteractionType": "Interact",
"AethernetShortcut": [
"[Solution Nine] The Arcadion",
"[Solution Nine] True Vue"
]
}
]
},
{
"Sequence": 255,
"Steps": [
{
"DataId": 1049790,
"Position": {
"X": 494.7433,
"Y": 59.55,
"Z": 125.10864
},
"TerritoryId": 1186,
"InteractionType": "CompleteQuest"
}
]
}
]
}

View File

@ -36,6 +36,7 @@ internal sealed class QuestRegistry
public IEnumerable<Quest> AllQuests => _quests.Values; public IEnumerable<Quest> AllQuests => _quests.Values;
public int Count => _quests.Count; public int Count => _quests.Count;
public int ValidationIssueCount => _questValidator.IssueCount; public int ValidationIssueCount => _questValidator.IssueCount;
public int ValidationErrorCount => _questValidator.ErrorCount;
public void Reload() public void Reload()
{ {

View File

@ -1,4 +1,5 @@
using System.Linq; using System.Collections.Generic;
using System.Linq;
using Questionable.Model.V1; using Questionable.Model.V1;
namespace Questionable.Model; namespace Questionable.Model;
@ -12,4 +13,18 @@ internal sealed class Quest
public QuestSequence? FindSequence(byte currentSequence) public QuestSequence? FindSequence(byte currentSequence)
=> Root.QuestSequence.SingleOrDefault(seq => seq.Sequence == currentSequence); => Root.QuestSequence.SingleOrDefault(seq => seq.Sequence == currentSequence);
public IEnumerable<QuestSequence> AllSequences() => Root.QuestSequence;
public IEnumerable<(QuestSequence Sequence, int StepId, QuestStep Step)> AllSteps()
{
foreach (var sequence in Root.QuestSequence)
{
for (int i = 0; i < sequence.Steps.Count; ++i)
{
var step = sequence.Steps[i];
yield return (sequence, i, step);
}
}
}
} }

View File

@ -136,6 +136,7 @@ public sealed class QuestionablePlugin : IDalamudPlugin
serviceCollection.AddSingleton<IQuestValidator, QuestDisabledValidator>(); serviceCollection.AddSingleton<IQuestValidator, QuestDisabledValidator>();
serviceCollection.AddSingleton<IQuestValidator, BasicSequenceValidator>(); serviceCollection.AddSingleton<IQuestValidator, BasicSequenceValidator>();
serviceCollection.AddSingleton<IQuestValidator, UniqueStartStopValidator>(); serviceCollection.AddSingleton<IQuestValidator, UniqueStartStopValidator>();
serviceCollection.AddSingleton<IQuestValidator, NextQuestValidator>();
serviceCollection.AddSingleton<IQuestValidator, CompletionFlagsValidator>(); serviceCollection.AddSingleton<IQuestValidator, CompletionFlagsValidator>();
serviceCollection.AddSingleton<CommandHandler>(); serviceCollection.AddSingleton<CommandHandler>();

View File

@ -24,6 +24,7 @@ internal sealed class QuestValidator
public IReadOnlyList<ValidationIssue> Issues => _validationIssues; public IReadOnlyList<ValidationIssue> Issues => _validationIssues;
public int IssueCount => _validationIssues.Count; public int IssueCount => _validationIssues.Count;
public int ErrorCount => _validationIssues.Count(x => x.Severity == EIssueSeverity.Error);
public void ClearIssues() => _validationIssues.Clear(); public void ClearIssues() => _validationIssues.Clear();

View File

@ -10,7 +10,7 @@ internal sealed class CompletionFlagsValidator : IQuestValidator
{ {
public IEnumerable<ValidationIssue> Validate(Quest quest) public IEnumerable<ValidationIssue> Validate(Quest quest)
{ {
foreach (var sequence in quest.Root.QuestSequence) foreach (var sequence in quest.AllSequences())
{ {
var mappedCompletionFlags = sequence.Steps var mappedCompletionFlags = sequence.Steps
.Select(x => .Select(x =>

View File

@ -0,0 +1,23 @@
using System.Collections.Generic;
using System.Linq;
using Questionable.Model;
namespace Questionable.Validation.Validators;
internal sealed class NextQuestValidator : IQuestValidator
{
public IEnumerable<ValidationIssue> Validate(Quest quest)
{
foreach (var invalidNextQuest in quest.AllSteps().Where(x => x.Step.NextQuestId == quest.QuestId))
{
yield return new ValidationIssue
{
QuestId = quest.QuestId,
Sequence = (byte)invalidNextQuest.Sequence.Sequence,
Step = invalidNextQuest.StepId,
Severity = EIssueSeverity.Error,
Description = "Next quest should not reference itself",
};
}
}
}

View File

@ -14,12 +14,12 @@ internal sealed class UniqueStartStopValidator : IQuestValidator
.ToList(); .ToList();
foreach (var accept in questAccepts) foreach (var accept in questAccepts)
{ {
if (accept.SequenceId != 0 || accept.StepId != quest.FindSequence(0)!.Steps.Count - 1) if (accept.Sequence.Sequence != 0 || accept.StepId != quest.FindSequence(0)!.Steps.Count - 1)
{ {
yield return new ValidationIssue yield return new ValidationIssue
{ {
QuestId = quest.QuestId, QuestId = quest.QuestId,
Sequence = (byte)accept.SequenceId, Sequence = (byte)accept.Sequence.Sequence,
Step = accept.StepId, Step = accept.StepId,
Severity = EIssueSeverity.Error, Severity = EIssueSeverity.Error,
Description = "Unexpected AcceptQuest step", Description = "Unexpected AcceptQuest step",
@ -44,12 +44,12 @@ internal sealed class UniqueStartStopValidator : IQuestValidator
.ToList(); .ToList();
foreach (var complete in questCompletes) foreach (var complete in questCompletes)
{ {
if (complete.SequenceId != 255 || complete.StepId != quest.FindSequence(255)!.Steps.Count - 1) if (complete.Sequence.Sequence != 255 || complete.StepId != quest.FindSequence(255)!.Steps.Count - 1)
{ {
yield return new ValidationIssue yield return new ValidationIssue
{ {
QuestId = quest.QuestId, QuestId = quest.QuestId,
Sequence = (byte)complete.SequenceId, Sequence = (byte)complete.Sequence.Sequence,
Step = complete.StepId, Step = complete.StepId,
Severity = EIssueSeverity.Error, Severity = EIssueSeverity.Error,
Description = "Unexpected CompleteQuest step", Description = "Unexpected CompleteQuest step",
@ -70,16 +70,7 @@ internal sealed class UniqueStartStopValidator : IQuestValidator
} }
} }
private static IEnumerable<(int SequenceId, int StepId, QuestStep Step)> FindQuestStepsWithInteractionType(Quest quest, EInteractionType interactionType) private static IEnumerable<(QuestSequence Sequence, int StepId, QuestStep Step)> FindQuestStepsWithInteractionType(
{ Quest quest, EInteractionType interactionType)
foreach (var sequence in quest.Root.QuestSequence) => quest.AllSteps().Where(x => x.Step.InteractionType == interactionType);
{
for (int i = 0; i < sequence.Steps.Count; ++i)
{
var step = sequence.Steps[i];
if (step.InteractionType == interactionType)
yield return (sequence.Sequence, i, step);
}
}
}
} }

View File

@ -2,6 +2,7 @@
using System.Globalization; using System.Globalization;
using System.Linq; using System.Linq;
using System.Numerics; using System.Numerics;
using Dalamud.Game.ClientState.Conditions;
using Dalamud.Interface.Utility; using Dalamud.Interface.Utility;
using Dalamud.Interface.Windowing; using Dalamud.Interface.Windowing;
using Dalamud.Plugin.Services; using Dalamud.Plugin.Services;
@ -18,10 +19,11 @@ internal sealed class DebugOverlay : Window
private readonly QuestRegistry _questRegistry; private readonly QuestRegistry _questRegistry;
private readonly IGameGui _gameGui; private readonly IGameGui _gameGui;
private readonly IClientState _clientState; private readonly IClientState _clientState;
private readonly ICondition _condition;
private readonly Configuration _configuration; private readonly Configuration _configuration;
public DebugOverlay(QuestController questController, QuestRegistry questRegistry, IGameGui gameGui, public DebugOverlay(QuestController questController, QuestRegistry questRegistry, IGameGui gameGui,
IClientState clientState, Configuration configuration) IClientState clientState, ICondition condition, Configuration configuration)
: base("Questionable Debug Overlay###QuestionableDebugOverlay", : base("Questionable Debug Overlay###QuestionableDebugOverlay",
ImGuiWindowFlags.NoTitleBar | ImGuiWindowFlags.NoScrollbar | ImGuiWindowFlags.NoBackground | ImGuiWindowFlags.NoTitleBar | ImGuiWindowFlags.NoScrollbar | ImGuiWindowFlags.NoBackground |
ImGuiWindowFlags.NoInputs | ImGuiWindowFlags.NoSavedSettings, true) ImGuiWindowFlags.NoInputs | ImGuiWindowFlags.NoSavedSettings, true)
@ -30,6 +32,7 @@ internal sealed class DebugOverlay : Window
_questRegistry = questRegistry; _questRegistry = questRegistry;
_gameGui = gameGui; _gameGui = gameGui;
_clientState = clientState; _clientState = clientState;
_condition = condition;
_configuration = configuration; _configuration = configuration;
Position = Vector2.Zero; Position = Vector2.Zero;
@ -44,7 +47,8 @@ internal sealed class DebugOverlay : Window
public override bool DrawConditions() public override bool DrawConditions()
{ {
return _configuration.Advanced.DebugOverlay && _clientState is return _configuration.Advanced.DebugOverlay && _clientState is
{ IsLoggedIn: true, LocalPlayer: not null, IsPvPExcludingDen: false }; { IsLoggedIn: true, LocalPlayer: not null, IsPvPExcludingDen: false } &&
!_condition[ConditionFlag.OccupiedInCutSceneEvent];
} }
public override void PreDraw() public override void PreDraw()

View File

@ -3,6 +3,7 @@ using Dalamud.Interface;
using Dalamud.Interface.Colors; using Dalamud.Interface.Colors;
using Dalamud.Interface.Components; using Dalamud.Interface.Components;
using Dalamud.Interface.Utility.Raii; using Dalamud.Interface.Utility.Raii;
using Dalamud.Plugin;
using FFXIVClientStructs.FFXIV.Common.Math; using FFXIVClientStructs.FFXIV.Common.Math;
using ImGuiNET; using ImGuiNET;
using LLib.ImGui; using LLib.ImGui;
@ -16,11 +17,13 @@ internal sealed class QuestValidationWindow : LWindow
{ {
private readonly QuestValidator _questValidator; private readonly QuestValidator _questValidator;
private readonly QuestData _questData; private readonly QuestData _questData;
private readonly IDalamudPluginInterface _pluginInterface;
public QuestValidationWindow(QuestValidator questValidator, QuestData questData) : base("Quest Validation###QuestionableValidator") public QuestValidationWindow(QuestValidator questValidator, QuestData questData, IDalamudPluginInterface pluginInterface) : base("Quest Validation###QuestionableValidator")
{ {
_questValidator = questValidator; _questValidator = questValidator;
_questData = questData; _questData = questData;
_pluginInterface = pluginInterface;
Size = new Vector2(600, 200); Size = new Vector2(600, 200);
SizeCondition = ImGuiCond.Once; SizeCondition = ImGuiCond.Once;
@ -41,8 +44,8 @@ internal sealed class QuestValidationWindow : LWindow
ImGui.TableSetupColumn("Quest", ImGuiTableColumnFlags.WidthFixed, 50); ImGui.TableSetupColumn("Quest", ImGuiTableColumnFlags.WidthFixed, 50);
ImGui.TableSetupColumn("", ImGuiTableColumnFlags.WidthFixed, 200); ImGui.TableSetupColumn("", ImGuiTableColumnFlags.WidthFixed, 200);
ImGui.TableSetupColumn("Sq", ImGuiTableColumnFlags.WidthFixed, 30); ImGui.TableSetupColumn("Seq", ImGuiTableColumnFlags.WidthFixed, 30);
ImGui.TableSetupColumn("Sp", ImGuiTableColumnFlags.WidthFixed, 30); ImGui.TableSetupColumn("Step", ImGuiTableColumnFlags.WidthFixed, 30);
ImGui.TableSetupColumn("Issue", ImGuiTableColumnFlags.None, 200); ImGui.TableSetupColumn("Issue", ImGuiTableColumnFlags.None, 200);
ImGui.TableHeadersRow(); ImGui.TableHeadersRow();
@ -63,7 +66,24 @@ internal sealed class QuestValidationWindow : LWindow
ImGui.TextUnformatted(validationIssue.Step?.ToString(CultureInfo.InvariantCulture) ?? string.Empty); ImGui.TextUnformatted(validationIssue.Step?.ToString(CultureInfo.InvariantCulture) ?? string.Empty);
if (ImGui.TableNextColumn()) if (ImGui.TableNextColumn())
{
// ReSharper disable once UnusedVariable
using (var font = _pluginInterface.UiBuilder.IconFontFixedWidthHandle.Push())
{
if (validationIssue.Severity == EIssueSeverity.Error)
{
using var color = ImRaii.PushColor(ImGuiCol.Text, ImGuiColors.DalamudRed);
ImGui.TextUnformatted(FontAwesomeIcon.TimesCircle.ToIconString());
}
else
{
using var color = ImRaii.PushColor(ImGuiCol.Text, ImGuiColors.ParsedBlue);
ImGui.TextUnformatted(FontAwesomeIcon.InfoCircle.ToIconString());
}
}
ImGui.SameLine();
ImGui.TextUnformatted(validationIssue.Description); ImGui.TextUnformatted(validationIssue.Description);
} }
} }
} }
}

View File

@ -581,10 +581,16 @@ internal sealed class QuestWindow : LWindow, IPersistableWindowConfig
{ {
ImGui.SameLine(); ImGui.SameLine();
using var textColor = ImRaii.PushColor(ImGuiCol.Text, ImGuiColors.DalamudRed); bool colored = _questRegistry.ValidationErrorCount > 0;
if (colored)
ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudRed);
if (ImGuiComponents.IconButtonWithText(FontAwesomeIcon.Flag, if (ImGuiComponents.IconButtonWithText(FontAwesomeIcon.Flag,
$"{_questRegistry.ValidationIssueCount}")) $"{_questRegistry.ValidationIssueCount}"))
_questValidationWindow.IsOpen = true; _questValidationWindow.IsOpen = true;
if (colored)
ImGui.PopStyleColor();
} }
} }