Rework logic for next/simulated quests., handle dialogue choices when starting quests, tuliyollal/solution nine side quests

This commit is contained in:
Liza 2024-07-11 02:56:42 +02:00
parent 48f4045e77
commit 7072df6fcf
Signed by: liza
GPG Key ID: 7199F8D727D55F67
62 changed files with 3252 additions and 283 deletions

View File

@ -38,7 +38,7 @@ public class QuestSourceGenerator : ISourceGenerator
public void Execute(GeneratorExecutionContext context)
{
List<(ushort, QuestData)> quests = [];
List<(ushort, QuestRoot)> quests = [];
// Find schema definition
AdditionalText jsonSchemaFile =
@ -75,7 +75,7 @@ public class QuestSourceGenerator : ISourceGenerator
context.ReportDiagnostic(error);
}
var quest = questNode.Deserialize<QuestData>()!;
var quest = questNode.Deserialize<QuestRoot>()!;
quests.Add((id, quest));
}
@ -196,7 +196,7 @@ public class QuestSourceGenerator : ISourceGenerator
context.AddSource("AssemblyQuestLoader.g.cs", code.ToFullString());
}
private static IEnumerable<SyntaxNodeOrToken> CreateQuestInitializer(ushort questId, QuestData quest)
private static IEnumerable<SyntaxNodeOrToken> CreateQuestInitializer(ushort questId, QuestRoot quest)
{
return new SyntaxNodeOrToken[]
{
@ -210,23 +210,23 @@ public class QuestSourceGenerator : ISourceGenerator
Literal(questId)),
Token(SyntaxKind.CommaToken),
ObjectCreationExpression(
IdentifierName(nameof(QuestData)))
IdentifierName(nameof(QuestRoot)))
.WithInitializer(
InitializerExpression(
SyntaxKind.ObjectInitializerExpression,
SeparatedList<ExpressionSyntax>(
SyntaxNodeList(
Assignment(nameof(QuestData.Author), quest.Author, null)
Assignment(nameof(QuestRoot.Author), quest.Author, null)
.AsSyntaxNodeOrToken(),
AssignmentList(nameof(QuestData.Contributors), quest.Contributors)
AssignmentList(nameof(QuestRoot.Contributors), quest.Contributors)
.AsSyntaxNodeOrToken(),
Assignment(nameof(QuestData.Comment), quest.Comment, null)
Assignment(nameof(QuestRoot.Comment), quest.Comment, null)
.AsSyntaxNodeOrToken(),
AssignmentList(nameof(QuestData.TerritoryBlacklist),
AssignmentList(nameof(QuestRoot.TerritoryBlacklist),
quest.TerritoryBlacklist).AsSyntaxNodeOrToken(),
AssignmentExpression(
SyntaxKind.SimpleAssignmentExpression,
IdentifierName(nameof(QuestData.QuestSequence)),
IdentifierName(nameof(QuestRoot.QuestSequence)),
CreateQuestSequence(quest.QuestSequence))
))))
})),
@ -354,7 +354,11 @@ public class QuestSourceGenerator : ISourceGenerator
.AsSyntaxNodeOrToken(),
AssignmentList(nameof(QuestStep.PointMenuChoices), step.PointMenuChoices)
.AsSyntaxNodeOrToken(),
Assignment(nameof(QuestStep.QuestId), step.QuestId, emptyStep.QuestId)
Assignment(nameof(QuestStep.PickupQuestId), step.PickupQuestId, emptyStep.PickupQuestId)
.AsSyntaxNodeOrToken(),
Assignment(nameof(QuestStep.TurnInQuestId), step.TurnInQuestId, emptyStep.TurnInQuestId)
.AsSyntaxNodeOrToken(),
Assignment(nameof(QuestStep.NextQuestId), step.NextQuestId, emptyStep.NextQuestId)
.AsSyntaxNodeOrToken()))))),
Token(SyntaxKind.CommaToken),
}.ToArray())));

View File

@ -14,7 +14,11 @@
},
"StopDistance": 7,
"TerritoryId": 962,
"InteractionType": "AcceptQuest"
"InteractionType": "AcceptQuest",
"AetheryteShortcut": "Old Sharlayan",
"SkipIf": [
"AetheryteShortcutIfInSameTerritory"
]
}
]
},

View File

@ -13,7 +13,11 @@
"Z": 201.28174
},
"TerritoryId": 1185,
"InteractionType": "AcceptQuest"
"InteractionType": "AcceptQuest",
"AetheryteShortcut": "Tuliyollal",
"SkipIf": [
"AetheryteShortcutIfInSameTerritory"
]
}
]
},
@ -187,7 +191,8 @@
"Z": 111.436646
},
"TerritoryId": 129,
"InteractionType": "CompleteQuest"
"InteractionType": "CompleteQuest",
"NextQuestId": 4825
}
]
}

View File

@ -13,7 +13,11 @@
"Z": 111.436646
},
"TerritoryId": 129,
"InteractionType": "AcceptQuest"
"InteractionType": "AcceptQuest",
"AetheryteShortcut": "Limsa Lominsa",
"SkipIf": [
"AetheryteShortcutIfInSameTerritory"
]
}
]
},
@ -115,7 +119,8 @@
},
"TerritoryId": 129,
"InteractionType": "CompleteQuest",
"AetheryteShortcut": "Limsa Lominsa"
"AetheryteShortcut": "Limsa Lominsa",
"NextQuestId": 4826
}
]
}

View File

@ -13,7 +13,11 @@
"Z": 111.436646
},
"TerritoryId": 129,
"InteractionType": "AcceptQuest"
"InteractionType": "AcceptQuest",
"AetheryteShortcut": "Limsa Lominsa",
"SkipIf": [
"AetheryteShortcutIfInSameTerritory"
]
}
]
},
@ -99,7 +103,8 @@
},
"TerritoryId": 129,
"InteractionType": "CompleteQuest",
"AetheryteShortcut": "Limsa Lominsa"
"AetheryteShortcut": "Limsa Lominsa",
"NextQuestId": 4827
}
]
}

View File

@ -13,7 +13,11 @@
"Z": 111.436646
},
"TerritoryId": 129,
"InteractionType": "AcceptQuest"
"InteractionType": "AcceptQuest",
"AetheryteShortcut": "Limsa Lominsa",
"SkipIf": [
"AetheryteShortcutIfInSameTerritory"
]
}
]
},
@ -137,7 +141,9 @@
"Z": 111.436646
},
"TerritoryId": 129,
"InteractionType": "CompleteQuest"
"InteractionType": "CompleteQuest",
"AetheryteShortcut": "Limsa Lominsa",
"NextQuestId": 4828
}
]
}

View File

@ -0,0 +1,151 @@
{
"$schema": "https://carvel.li/questionable/quest-1.0",
"Author": "liza",
"QuestSequence": [
{
"Sequence": 0,
"Steps": [
{
"DataId": 1046290,
"Position": {
"X": -114.091736,
"Y": 20,
"Z": 111.436646
},
"TerritoryId": 129,
"InteractionType": "AcceptQuest",
"AetheryteShortcut": "Limsa Lominsa",
"SkipIf": [
"AetheryteShortcutIfInSameTerritory"
]
}
]
},
{
"Sequence": 1,
"Steps": [
{
"DataId": 1046317,
"Position": {
"X": 570.18384,
"Y": 20.721313,
"Z": 451.34656
},
"TerritoryId": 137,
"InteractionType": "Interact",
"AetheryteShortcut": "Eastern La Noscea - Costa Del Sol",
"DialogueChoices": [
{
"Type": "List",
"Prompt": "TEXT_KINGBA241_04828_Q1_000_013",
"Answer": "TEXT_KINGBA241_04828_A1_000_001"
}
]
}
]
},
{
"Sequence": 2,
"Steps": [
{
"DataId": 1046317,
"Position": {
"X": 570.18384,
"Y": 20.721313,
"Z": 451.34656
},
"TerritoryId": 137,
"InteractionType": "Interact"
}
]
},
{
"Sequence": 3,
"Steps": [
{
"DataId": 2013561,
"Position": {
"X": -220.44714,
"Y": 35.78235,
"Z": 268.05518
},
"StopDistance": 0.25,
"TerritoryId": 137,
"InteractionType": "Combat",
"EnemySpawnType": "AfterInteraction",
"KillEnemyDataIds": [
17614,
17615,
17616
],
"AetheryteShortcut": "Eastern La Noscea - Wineport",
"Fly": true,
"Comment": "two waves of enemies"
}
]
},
{
"Sequence": 4,
"Steps": [
{
"DataId": 1046318,
"Position": {
"X": -98.95477,
"Y": 34.20764,
"Z": 220.44702
},
"TerritoryId": 137,
"InteractionType": "Interact"
}
]
},
{
"Sequence": 5,
"Steps": [
{
"DataId": 1046318,
"Position": {
"X": -98.95477,
"Y": 34.20764,
"Z": 220.44702
},
"TerritoryId": 137,
"InteractionType": "Interact"
}
]
},
{
"Sequence": 6,
"Steps": [
{
"DataId": 1046317,
"Position": {
"X": 570.18384,
"Y": 20.721313,
"Z": 451.34656
},
"TerritoryId": 137,
"InteractionType": "Interact",
"AetheryteShortcut": "Eastern La Noscea - Costa Del Sol"
}
]
},
{
"Sequence": 255,
"Steps": [
{
"DataId": 1046290,
"Position": {
"X": -114.091736,
"Y": 20,
"Z": 111.436646
},
"TerritoryId": 129,
"InteractionType": "CompleteQuest",
"AetheryteShortcut": "Limsa Lominsa",
"NextQuestId": 4829
}
]
}
]
}

View File

@ -0,0 +1,25 @@
{
"$schema": "https://carvel.li/questionable/quest-1.0",
"Author": "liza",
"QuestSequence": [
{
"Sequence": 0,
"Steps": [
{
"DataId": 1046290,
"Position": {
"X": -114.091736,
"Y": 20,
"Z": 111.436646
},
"TerritoryId": 129,
"InteractionType": "AcceptQuest",
"AetheryteShortcut": "Limsa Lominsa",
"SkipIf": [
"AetheryteShortcutIfInSameTerritory"
]
}
]
}
]
}

View File

@ -75,7 +75,8 @@
"Z": 628.3817
},
"TerritoryId": 957,
"InteractionType": "CompleteQuest"
"InteractionType": "CompleteQuest",
"NextQuestId": 4843
}
]
}

View File

@ -133,7 +133,8 @@
"Z": 628.3817
},
"TerritoryId": 957,
"InteractionType": "CompleteQuest"
"InteractionType": "CompleteQuest",
"NextQuestId": 4844
}
]
}

View File

@ -155,7 +155,8 @@
"Z": 628.3817
},
"TerritoryId": 957,
"InteractionType": "CompleteQuest"
"InteractionType": "CompleteQuest",
"NextQuestId": 4845
}
]
}

View File

@ -13,7 +13,105 @@
"Z": 203.38745
},
"TerritoryId": 1185,
"InteractionType": "AcceptQuest"
"InteractionType": "AcceptQuest",
"AetheryteShortcut": "Tuliyollal",
"SkipIf": [
"AetheryteShortcutIfInSameTerritory"
]
}
]
},
{
"Sequence": 1,
"Steps": [
{
"DataId": 1020193,
"Position": {
"X": 26.108154,
"Y": 0,
"Z": 25.253662
},
"TerritoryId": 635,
"InteractionType": "Interact",
"AetheryteShortcut": "Rhalgr's Reach",
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
64
]
},
{
"DataId": 1019483,
"Position": {
"X": -37.521973,
"Y": 1.2530026,
"Z": 36.301147
},
"TerritoryId": 635,
"InteractionType": "Interact",
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
128
]
},
{
"DataId": 1019484,
"Position": {
"X": -66.5141,
"Y": -5.9571908E-15,
"Z": -22.964844
},
"TerritoryId": 635,
"InteractionType": "Interact",
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
32
]
}
]
},
{
"Sequence": 2,
"Steps": [
{
"DataId": 1048311,
"Position": {
"X": 460.86804,
"Y": 41.92747,
"Z": 335.10327
},
"TerritoryId": 612,
"InteractionType": "Interact",
"AetheryteShortcut": "Fringes - Peering Stones",
"Fly": true
}
]
},
{
"Sequence": 255,
"Steps": [
{
"DataId": 1048309,
"Position": {
"X": 19.638367,
"Y": -0.11837298,
"Z": 47.226562
},
"TerritoryId": 635,
"InteractionType": "CompleteQuest",
"AetheryteShortcut": "Rhalgr's Reach",
"NextQuestId": 4837
}
]
}

View File

@ -0,0 +1,25 @@
{
"$schema": "https://carvel.li/questionable/quest-1.0",
"Author": "liza",
"QuestSequence": [
{
"Sequence": 0,
"Steps": [
{
"DataId": 1048309,
"Position": {
"X": 19.638367,
"Y": -0.11837298,
"Z": 47.226562
},
"TerritoryId": 635,
"InteractionType": "AcceptQuest",
"AetheryteShortcut": "Rhalgr's Reach",
"SkipIf": [
"AetheryteShortcutIfInSameTerritory"
]
}
]
}
]
}

View File

@ -96,7 +96,8 @@
"Z": -48.05072
},
"TerritoryId": 418,
"InteractionType": "CompleteQuest"
"InteractionType": "CompleteQuest",
"NextQuestId": 4819
}
]
}

View File

@ -113,7 +113,8 @@
"Z": -48.05072
},
"TerritoryId": 418,
"InteractionType": "CompleteQuest"
"InteractionType": "CompleteQuest",
"NextQuestId": 4820
}
]
}

View File

@ -143,7 +143,8 @@
"AethernetShortcut": [
"[Ishgard] Aetheryte Plaza",
"[Ishgard] The Forgotten Knight"
]
],
"NextQuestId": 4821
}
]
}

View File

@ -115,7 +115,8 @@
},
"StopDistance": 5,
"TerritoryId": 418,
"InteractionType": "CompleteQuest"
"InteractionType": "CompleteQuest",
"NextQuestId": 4822
}
]
}

View File

@ -137,7 +137,8 @@
"Prompt": "TEXT_KINGBA141_04822_Q3_000_000",
"Answer": "TEXT_KINGBA141_04822_A3_000_002"
}
]
],
"NextQuestId": 4823
}
]
}

View File

@ -0,0 +1,88 @@
{
"$schema": "https://carvel.li/questionable/quest-1.0",
"Author": "liza",
"QuestSequence": [
{
"Sequence": 0,
"Steps": [
{
"DataId": 1051388,
"Position": {
"X": -185.47345,
"Y": 0.66,
"Z": -42.648987
},
"TerritoryId": 1186,
"InteractionType": "AcceptQuest"
}
]
},
{
"Sequence": 1,
"Steps": [
{
"Position": {
"X": -445.9273,
"Y": 13.999773,
"Z": 192.44756
},
"TerritoryId": 1186,
"InteractionType": "WalkTo",
"AethernetShortcut": [
"[Solution Nine] Nexus Arcade",
"[Solution Nine] Residential Sector"
]
},
{
"DataId": 1050492,
"Position": {
"X": -446.25012,
"Y": 13.999722,
"Z": 195.23914
},
"TerritoryId": 1186,
"InteractionType": "Interact"
}
]
},
{
"Sequence": 255,
"Steps": [
{
"Position": {
"X": -445.1605,
"Y": 13.999999,
"Z": 162.65598
},
"TerritoryId": 1186,
"InteractionType": "WalkTo"
},
{
"Position": {
"X": -440.51483,
"Y": 13.999909,
"Z": 154.73817
},
"TerritoryId": 1186,
"InteractionType": "WalkTo",
"DisableNavmesh": true,
"Comment": "For some reason navmesh wanders off through the whole area"
},
{
"DataId": 1051388,
"Position": {
"X": -185.47345,
"Y": 0.66,
"Z": -42.648987
},
"TerritoryId": 1186,
"InteractionType": "CompleteQuest",
"AethernetShortcut": [
"[Solution Nine] Residential Sector",
"[Solution Nine] Nexus Arcade"
]
}
]
}
]
}

View File

@ -0,0 +1,133 @@
{
"$schema": "https://carvel.li/questionable/quest-1.0",
"Author": "liza",
"QuestSequence": [
{
"Sequence": 0,
"Steps": [
{
"DataId": 1051389,
"Position": {
"X": 501.12158,
"Y": 59.999813,
"Z": 163.83606
},
"TerritoryId": 1186,
"InteractionType": "AcceptQuest",
"DialogueChoices": [
{
"Type": "List",
"Prompt": "TEXT_KINGZG002_05165_Q1_000_000",
"Answer": "TEXT_KINGZG002_05165_A1_000_002"
}
]
}
]
},
{
"Sequence": 1,
"Steps": [
{
"DataId": 2014339,
"Position": {
"X": 483.08533,
"Y": 61.386963,
"Z": 196.09363
},
"TerritoryId": 1186,
"InteractionType": "Interact",
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
64
]
},
{
"DataId": 2014340,
"Position": {
"X": 444.3275,
"Y": 61.356445,
"Z": 242.38953
},
"TerritoryId": 1186,
"InteractionType": "Interact",
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
32
]
},
{
"DataId": 2014338,
"Position": {
"X": 456.2904,
"Y": 61.41748,
"Z": 68.89441
},
"TerritoryId": 1186,
"InteractionType": "Interact",
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
128
]
}
]
},
{
"Sequence": 2,
"Steps": [
{
"DataId": 1051390,
"Position": {
"X": 500.08386,
"Y": 59.999813,
"Z": 161.4862
},
"TerritoryId": 1186,
"InteractionType": "Interact"
}
]
},
{
"Sequence": 3,
"Steps": [
{
"DataId": 1051391,
"Position": {
"X": 497.94763,
"Y": 59.99981,
"Z": 160.84534
},
"TerritoryId": 1186,
"InteractionType": "Emote",
"Emote": "doubt"
}
]
},
{
"Sequence": 255,
"Steps": [
{
"DataId": 1051390,
"Position": {
"X": 500.08386,
"Y": 59.999813,
"Z": 161.4862
},
"TerritoryId": 1186,
"InteractionType": "CompleteQuest"
}
]
}
]
}

View File

@ -0,0 +1,94 @@
{
"$schema": "https://carvel.li/questionable/quest-1.0",
"Author": "liza",
"QuestSequence": [
{
"Sequence": 0,
"Steps": [
{
"DataId": 1051393,
"Position": {
"X": -315.4193,
"Y": 14,
"Z": 155.7793
},
"TerritoryId": 1186,
"InteractionType": "AcceptQuest"
}
]
},
{
"Sequence": 1,
"Steps": [
{
"DataId": 1051393,
"Position": {
"X": -315.4193,
"Y": 14,
"Z": 155.7793
},
"TerritoryId": 1186,
"InteractionType": "Interact"
}
]
},
{
"Sequence": 2,
"Steps": [
{
"DataId": 1051393,
"Position": {
"X": -206.10861,
"Y": 2.1999774,
"Z": 213.03752
},
"StopDistance": 0.25,
"TerritoryId": 1186,
"InteractionType": "Interact",
"DialogueChoices": [
{
"Type": "List",
"Prompt": "TEXT_KINGZG003_05166_Q2_000_000",
"Answer": "TEXT_KINGZG003_05166_A2_000_001"
}
]
}
]
},
{
"Sequence": 3,
"Steps": [
{
"DataId": 1051393,
"Position": {
"X": -23.899967,
"Y": -5.8484287,
"Z": 230.24123
},
"StopDistance": 0.25,
"TerritoryId": 1186,
"InteractionType": "Interact"
}
]
},
{
"Sequence": 255,
"Steps": [
{
"DataId": 1051395,
"Position": {
"X": -3.55542,
"Y": 0.0005434508,
"Z": -85.89307
},
"TerritoryId": 1186,
"InteractionType": "CompleteQuest",
"AethernetShortcut": [
"[Solution Nine] Information Center",
"[Solution Nine] Aetheryte Plaza"
]
}
]
}
]
}

View File

@ -0,0 +1,92 @@
{
"$schema": "https://carvel.li/questionable/quest-1.0",
"Author": "liza",
"QuestSequence": [
{
"Sequence": 0,
"Steps": [
{
"DataId": 1051396,
"Position": {
"X": -346.7918,
"Y": 9.519508,
"Z": 18.20398
},
"TerritoryId": 1186,
"InteractionType": "AcceptQuest"
}
]
},
{
"Sequence": 1,
"Steps": [
{
"Position": {
"X": -306.07123,
"Y": 10.014936,
"Z": 1.7894125
},
"TerritoryId": 1186,
"InteractionType": "WalkTo"
},
{
"DataId": 1049242,
"Position": {
"X": -303.7309,
"Y": 10.014902,
"Z": 1.7241821
},
"TerritoryId": 1186,
"InteractionType": "Interact"
}
]
},
{
"Sequence": 2,
"Steps": [
{
"Position": {
"X": 292.01248,
"Y": 51.401478,
"Z": 200.04631
},
"TerritoryId": 1186,
"InteractionType": "WalkTo",
"AethernetShortcut": [
"[Solution Nine] Residential Sector",
"[Solution Nine] Neon Stein"
]
},
{
"DataId": 1048081,
"Position": {
"X": 292.16443,
"Y": 51.401485,
"Z": 202.65503
},
"TerritoryId": 1186,
"InteractionType": "Interact"
}
]
},
{
"Sequence": 255,
"Steps": [
{
"DataId": 1051396,
"Position": {
"X": -346.7918,
"Y": 9.519508,
"Z": 18.20398
},
"TerritoryId": 1186,
"InteractionType": "CompleteQuest",
"AethernetShortcut": [
"[Solution Nine] Neon Stein",
"[Solution Nine] Residential Sector"
]
}
]
}
]
}

View File

@ -0,0 +1,95 @@
{
"$schema": "https://carvel.li/questionable/quest-1.0",
"Author": "liza",
"QuestSequence": [
{
"Sequence": 0,
"Steps": [
{
"DataId": 1051397,
"Position": {
"X": -40.024475,
"Y": 38.80659,
"Z": -459.49493
},
"TerritoryId": 1186,
"InteractionType": "AcceptQuest"
}
]
},
{
"Sequence": 1,
"Steps": [
{
"DataId": 1051400,
"Position": {
"X": -56.351562,
"Y": 38.0566,
"Z": -347.1275
},
"TerritoryId": 1186,
"InteractionType": "Interact",
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
32
]
},
{
"DataId": 1051399,
"Position": {
"X": -26.230347,
"Y": 38.056416,
"Z": -310.81104
},
"TerritoryId": 1186,
"InteractionType": "Interact",
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
64
]
},
{
"DataId": 1051398,
"Position": {
"X": 38.254395,
"Y": 38.0566,
"Z": -357.99194
},
"TerritoryId": 1186,
"InteractionType": "Interact",
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
128
]
}
]
},
{
"Sequence": 255,
"Steps": [
{
"DataId": 1051397,
"Position": {
"X": -40.024475,
"Y": 38.80659,
"Z": -459.49493
},
"TerritoryId": 1186,
"InteractionType": "CompleteQuest"
}
]
}
]
}

View File

@ -0,0 +1,87 @@
{
"$schema": "https://carvel.li/questionable/quest-1.0",
"Author": "liza",
"QuestSequence": [
{
"Sequence": 0,
"Steps": [
{
"DataId": 1051401,
"Position": {
"X": 383.90173,
"Y": 60,
"Z": 56.839844
},
"TerritoryId": 1186,
"InteractionType": "AcceptQuest"
}
]
},
{
"Sequence": 1,
"Steps": [
{
"Position": {
"X": 292.01248,
"Y": 51.401478,
"Z": 200.04631
},
"TerritoryId": 1186,
"InteractionType": "WalkTo",
"AethernetShortcut": [
"[Solution Nine] True Vue",
"[Solution Nine] Neon Stein"
]
},
{
"DataId": 1048081,
"Position": {
"X": 292.16443,
"Y": 51.401485,
"Z": 202.65503
},
"TerritoryId": 1186,
"InteractionType": "Interact"
}
]
},
{
"Sequence": 2,
"Steps": [
{
"DataId": 1051402,
"Position": {
"X": -205.58484,
"Y": 1.9200057,
"Z": 7.583679
},
"TerritoryId": 1186,
"InteractionType": "Interact",
"AethernetShortcut": [
"[Solution Nine] Neon Stein",
"[Solution Nine] Nexus Arcade"
]
}
]
},
{
"Sequence": 255,
"Steps": [
{
"DataId": 1051403,
"Position": {
"X": 13.992493,
"Y": -5.845003,
"Z": 269.91675
},
"TerritoryId": 1186,
"InteractionType": "CompleteQuest",
"AethernetShortcut": [
"[Solution Nine] Nexus Arcade",
"[Solution Nine] Information Center"
]
}
]
}
]
}

View File

@ -0,0 +1,100 @@
{
"$schema": "https://carvel.li/questionable/quest-1.0",
"Author": "liza",
"QuestSequence": [
{
"Sequence": 0,
"Steps": [
{
"DataId": 1051404,
"Position": {
"X": -157.33582,
"Y": 2.1999714,
"Z": 229.69409
},
"TerritoryId": 1186,
"InteractionType": "AcceptQuest"
}
]
},
{
"Sequence": 1,
"Steps": [
{
"Position": {
"X": 322.70325,
"Y": 52.41666,
"Z": 211.24818
},
"TerritoryId": 1186,
"InteractionType": "WalkTo",
"AethernetShortcut": [
"[Solution Nine] Information Center",
"[Solution Nine] True Vue"
]
},
{
"DataId": 1049154,
"Position": {
"X": 320.27148,
"Y": 52.41666,
"Z": 211.32214
},
"TerritoryId": 1186,
"InteractionType": "Interact"
}
]
},
{
"Sequence": 2,
"Steps": [
{
"DataId": 1051405,
"Position": {
"X": -156.2677,
"Y": 2.199971,
"Z": 231.79968
},
"TerritoryId": 1186,
"InteractionType": "Interact",
"AethernetShortcut": [
"[Solution Nine] True Vue",
"[Solution Nine] Information Center"
]
}
]
},
{
"Sequence": 3,
"Steps": [
{
"DataId": 1051409,
"Position": {
"X": -157.24426,
"Y": 2.1999712,
"Z": 231.21985
},
"StopDistance": 4,
"TerritoryId": 1186,
"InteractionType": "Emote",
"Emote": "psych"
}
]
},
{
"Sequence": 255,
"Steps": [
{
"DataId": 1051405,
"Position": {
"X": -156.2677,
"Y": 2.199971,
"Z": 231.79968
},
"TerritoryId": 1186,
"InteractionType": "CompleteQuest"
}
]
}
]
}

View File

@ -0,0 +1,51 @@
{
"$schema": "https://carvel.li/questionable/quest-1.0",
"Author": "liza",
"QuestSequence": [
{
"Sequence": 0,
"Steps": [
{
"DataId": 1051407,
"Position": {
"X": -182.29956,
"Y": 1.1335879E-05,
"Z": 45.059814
},
"TerritoryId": 1186,
"InteractionType": "AcceptQuest"
}
]
},
{
"Sequence": 1,
"Steps": [
{
"DataId": 2014345,
"Position": {
"X": -206.92761,
"Y": 0.25933838,
"Z": -106.58429
},
"TerritoryId": 1186,
"InteractionType": "Interact"
}
]
},
{
"Sequence": 255,
"Steps": [
{
"DataId": 1051407,
"Position": {
"X": -182.29956,
"Y": 1.1335879E-05,
"Z": 45.059814
},
"TerritoryId": 1186,
"InteractionType": "CompleteQuest"
}
]
}
]
}

View File

@ -0,0 +1,73 @@
{
"$schema": "https://carvel.li/questionable/quest-1.0",
"Author": "liza",
"QuestSequence": [
{
"Sequence": 0,
"Steps": [
{
"DataId": 1051069,
"Position": {
"X": -313.43555,
"Y": 4.6900077,
"Z": -36.57599
},
"TerritoryId": 1186,
"InteractionType": "AcceptQuest",
"DialogueChoices": [
{
"Type": "List",
"Prompt": "TEXT_KINGZG009_05172_Q1_000_000",
"Answer": "TEXT_KINGZG009_05172_A1_000_003"
}
]
}
]
},
{
"Sequence": 1,
"Steps": [
{
"DataId": 2014292,
"Position": {
"X": -375.93652,
"Y": 13.992493,
"Z": 144.06042
},
"TerritoryId": 1186,
"InteractionType": "Interact"
}
]
},
{
"Sequence": 2,
"Steps": [
{
"Position": {
"X": -375.93652,
"Y": 13.992493,
"Z": 144.06042
},
"TerritoryId": 1186,
"InteractionType": "Instruction",
"Comment": "Catch the cat. Good luck!"
}
]
},
{
"Sequence": 255,
"Steps": [
{
"DataId": 1051069,
"Position": {
"X": -313.43555,
"Y": 4.6900077,
"Z": -36.57599
},
"TerritoryId": 1186,
"InteractionType": "CompleteQuest"
}
]
}
]
}

View File

@ -0,0 +1,51 @@
{
"$schema": "https://carvel.li/questionable/quest-1.0",
"Author": "liza",
"QuestSequence": [
{
"Sequence": 0,
"Steps": [
{
"DataId": 1050728,
"Position": {
"X": 50.125854,
"Y": 47,
"Z": -330.40363
},
"TerritoryId": 1185,
"InteractionType": "AcceptQuest"
}
]
},
{
"Sequence": 1,
"Steps": [
{
"DataId": 1050729,
"Position": {
"X": 187.51807,
"Y": 42.40001,
"Z": -350.36243
},
"TerritoryId": 1185,
"InteractionType": "Interact"
}
]
},
{
"Sequence": 255,
"Steps": [
{
"DataId": 1050728,
"Position": {
"X": 50.125854,
"Y": 47,
"Z": -330.40363
},
"TerritoryId": 1185,
"InteractionType": "CompleteQuest"
}
]
}
]
}

View File

@ -0,0 +1,81 @@
{
"$schema": "https://carvel.li/questionable/quest-1.0",
"Author": "liza",
"QuestSequence": [
{
"Sequence": 0,
"Steps": [
{
"DataId": 1048459,
"Position": {
"X": -394.43048,
"Y": 11,
"Z": 3.5552979
},
"TerritoryId": 1185,
"InteractionType": "AcceptQuest"
}
]
},
{
"Sequence": 1,
"Steps": [
{
"DataId": 1050733,
"Position": {
"X": -16.83075,
"Y": -10.000011,
"Z": 93.12573
},
"TerritoryId": 1185,
"InteractionType": "Interact",
"AethernetShortcut": [
"[Tuliyollal] Dirigible Landing",
"[Tuliyollal] Bayside Bevy Marketplace"
]
}
]
},
{
"Sequence": 2,
"Steps": [
{
"DataId": 1050734,
"Position": {
"X": 79.301025,
"Y": -17.964588,
"Z": 199.57275
},
"TerritoryId": 1185,
"InteractionType": "Interact",
"DialogueChoices": [
{
"Type": "List",
"Prompt": "TEXT_KINGZA002_05018_Q1_000_000",
"Answer": "TEXT_KINGZA002_05018_A1_000_003"
}
]
}
]
},
{
"Sequence": 255,
"Steps": [
{
"DataId": 1048459,
"Position": {
"X": -394.43048,
"Y": 11,
"Z": 3.5552979
},
"TerritoryId": 1185,
"InteractionType": "CompleteQuest",
"AethernetShortcut": [
"[Tuliyollal] Bayside Bevy Marketplace",
"[Tuliyollal] Dirigible Landing"
]
}
]
}
]
}

View File

@ -0,0 +1,82 @@
{
"$schema": "https://carvel.li/questionable/quest-1.0",
"Author": "liza",
"QuestSequence": [
{
"Sequence": 0,
"Steps": [
{
"DataId": 1050735,
"Position": {
"X": 121.11084,
"Y": -17.972874,
"Z": 74.021484
},
"TerritoryId": 1185,
"InteractionType": "AcceptQuest"
}
]
},
{
"Sequence": 1,
"Steps": [
{
"DataId": 1050736,
"Position": {
"X": 31.47937,
"Y": -17.9643,
"Z": 167.46765
},
"StopDistance": 2,
"TerritoryId": 1185,
"InteractionType": "Interact"
}
]
},
{
"Sequence": 2,
"Steps": [
{
"DataId": 2014232,
"Position": {
"X": 33.310425,
"Y": -16.678162,
"Z": 167.98657
},
"TerritoryId": 1185,
"InteractionType": "Interact"
}
]
},
{
"Sequence": 3,
"Steps": [
{
"DataId": 1050737,
"Position": {
"X": 87.57141,
"Y": -14,
"Z": 52.384155
},
"TerritoryId": 1185,
"InteractionType": "Interact"
}
]
},
{
"Sequence": 255,
"Steps": [
{
"DataId": 1050737,
"Position": {
"X": 87.57141,
"Y": -14,
"Z": 52.384155
},
"TerritoryId": 1185,
"InteractionType": "CompleteQuest"
}
]
}
]
}

View File

@ -0,0 +1,126 @@
{
"$schema": "https://carvel.li/questionable/quest-1.0",
"Author": "liza",
"QuestSequence": [
{
"Sequence": 0,
"Steps": [
{
"DataId": 1051038,
"Position": {
"X": 153.94824,
"Y": -17.9645,
"Z": 95.384155
},
"TerritoryId": 1185,
"InteractionType": "AcceptQuest"
}
]
},
{
"Sequence": 1,
"Steps": [
{
"DataId": 1051025,
"Position": {
"X": 153.94824,
"Y": -17.9645,
"Z": 95.384155
},
"TerritoryId": 1185,
"InteractionType": "Interact"
}
]
},
{
"Sequence": 2,
"Steps": [
{
"DataId": 1051026,
"Position": {
"X": 109.910645,
"Y": -14,
"Z": 39.505493
},
"TerritoryId": 1185,
"InteractionType": "Interact",
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
128
]
},
{
"DataId": 1051027,
"Position": {
"X": 12.527649,
"Y": -10.00001,
"Z": 35.599243
},
"TerritoryId": 1185,
"InteractionType": "Interact",
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
64
]
},
{
"DataId": 1051028,
"Position": {
"X": -69.77954,
"Y": -10.00001,
"Z": 119.79846
},
"TerritoryId": 1185,
"InteractionType": "Interact",
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
32
]
}
]
},
{
"Sequence": 3,
"Steps": [
{
"DataId": 1051025,
"Position": {
"X": -124.85585,
"Y": -5.0000095,
"Z": 130.06908
},
"StopDistance": 0.25,
"TerritoryId": 1185,
"InteractionType": "Interact"
}
]
},
{
"Sequence": 255,
"Steps": [
{
"DataId": 1051029,
"Position": {
"X": -249.77496,
"Y": -9.2517585E-06,
"Z": 138.01782
},
"TerritoryId": 1185,
"InteractionType": "CompleteQuest"
}
]
}
]
}

View File

@ -0,0 +1,51 @@
{
"$schema": "https://carvel.li/questionable/quest-1.0",
"Author": "liza",
"QuestSequence": [
{
"Sequence": 0,
"Steps": [
{
"DataId": 1051030,
"Position": {
"X": -227.64941,
"Y": 40.075134,
"Z": -25.436829
},
"TerritoryId": 1185,
"InteractionType": "AcceptQuest"
}
]
},
{
"Sequence": 1,
"Steps": [
{
"DataId": 1051030,
"Position": {
"X": -227.64941,
"Y": 40.075134,
"Z": -25.436829
},
"TerritoryId": 1185,
"InteractionType": "Interact"
}
]
},
{
"Sequence": 255,
"Steps": [
{
"DataId": 1051031,
"Position": {
"X": -56.6568,
"Y": 52.057556,
"Z": 20.767456
},
"TerritoryId": 1185,
"InteractionType": "CompleteQuest"
}
]
}
]
}

View File

@ -0,0 +1,91 @@
{
"$schema": "https://carvel.li/questionable/quest-1.0",
"Author": "liza",
"QuestSequence": [
{
"Sequence": 0,
"Steps": [
{
"DataId": 1051032,
"Position": {
"X": -259.05243,
"Y": 2.127327E-05,
"Z": 116.13635
},
"TerritoryId": 1185,
"InteractionType": "AcceptQuest"
}
]
},
{
"Sequence": 1,
"Steps": [
{
"DataId": 1051033,
"Position": {
"X": -282.49036,
"Y": 14.508167,
"Z": 178.72888
},
"TerritoryId": 1185,
"InteractionType": "Interact"
}
]
},
{
"Sequence": 2,
"Steps": [
{
"Position": {
"X": -290.98425,
"Y": -9.417534E-06,
"Z": 179.37634
},
"TerritoryId": 1185,
"InteractionType": "WalkTo",
"DisableNavmesh": true
},
{
"DataId": 2014234,
"Position": {
"X": -272.84656,
"Y": -0.015319824,
"Z": 191.39392
},
"TerritoryId": 1185,
"InteractionType": "Interact"
}
]
},
{
"Sequence": 3,
"Steps": [
{
"DataId": 1051033,
"Position": {
"X": -282.49036,
"Y": 14.508167,
"Z": 178.72888
},
"TerritoryId": 1185,
"InteractionType": "Interact"
}
]
},
{
"Sequence": 255,
"Steps": [
{
"DataId": 1051032,
"Position": {
"X": -259.05243,
"Y": 2.127327E-05,
"Z": 116.13635
},
"TerritoryId": 1185,
"InteractionType": "CompleteQuest"
}
]
}
]
}

View File

@ -0,0 +1,85 @@
{
"$schema": "https://carvel.li/questionable/quest-1.0",
"Author": "liza",
"QuestSequence": [
{
"Sequence": 0,
"Steps": [
{
"DataId": 1051034,
"Position": {
"X": 15.457336,
"Y": -10.00001,
"Z": 64.43884
},
"TerritoryId": 1185,
"InteractionType": "AcceptQuest"
}
]
},
{
"Sequence": 1,
"Steps": [
{
"DataId": 1051036,
"Position": {
"X": -134.72198,
"Y": 45.35523,
"Z": 52.20105
},
"TerritoryId": 1185,
"InteractionType": "Interact",
"AethernetShortcut": [
"[Tuliyollal] Aetheryte Plaza",
"[Tuliyollal] The Resplendent Quarter"
],
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
64
]
},
{
"DataId": 1051035,
"Position": {
"X": -104.38696,
"Y": 54.09999,
"Z": 19.33313
},
"TerritoryId": 1185,
"InteractionType": "Interact",
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
128
]
}
]
},
{
"Sequence": 255,
"Steps": [
{
"DataId": 1051034,
"Position": {
"X": 15.457336,
"Y": -10.00001,
"Z": 64.43884
},
"TerritoryId": 1185,
"InteractionType": "CompleteQuest",
"AethernetShortcut": [
"[Tuliyollal] The Resplendent Quarter",
"[Tuliyollal] Aetheryte Plaza"
]
}
]
}
]
}

View File

@ -0,0 +1,78 @@
{
"$schema": "https://carvel.li/questionable/quest-1.0",
"Author": "liza",
"QuestSequence": [
{
"Sequence": 0,
"Steps": [
{
"DataId": 1048509,
"Position": {
"X": 181.44495,
"Y": 40.99999,
"Z": -66.63617
},
"TerritoryId": 1185,
"InteractionType": "AcceptQuest"
}
]
},
{
"Sequence": 1,
"Steps": [
{
"DataId": 1048431,
"Position": {
"X": 88.48706,
"Y": -14,
"Z": 56.687256
},
"StopDistance": 4,
"TerritoryId": 1185,
"InteractionType": "Interact",
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
64
]
},
{
"DataId": 1051037,
"Position": {
"X": -35.29419,
"Y": -17.97287,
"Z": 169.02417
},
"TerritoryId": 1185,
"InteractionType": "Interact",
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
128
]
}
]
},
{
"Sequence": 255,
"Steps": [
{
"DataId": 1048509,
"Position": {
"X": 181.44495,
"Y": 40.99999,
"Z": -66.63617
},
"TerritoryId": 1185,
"InteractionType": "CompleteQuest"
}
]
}
]
}

View File

@ -0,0 +1,66 @@
{
"$schema": "https://carvel.li/questionable/quest-1.0",
"Author": "liza",
"QuestSequence": [
{
"Sequence": 0,
"Steps": [
{
"DataId": 1051039,
"Position": {
"X": 17.593567,
"Y": -17.942173,
"Z": 153.06323
},
"TerritoryId": 1185,
"InteractionType": "AcceptQuest",
"DialogueChoices": [
{
"Type": "List",
"Prompt": "TEXT_KINGZA009_05025_Q1_000_000",
"Answer": "TEXT_KINGZA009_05025_A1_000_001"
}
]
}
]
},
{
"Sequence": 1,
"Steps": [
{
"DataId": 1051040,
"Position": {
"X": -169.93976,
"Y": 59.999985,
"Z": -54.703613
},
"TerritoryId": 1185,
"InteractionType": "Interact",
"AethernetShortcut": [
"[Tuliyollal] Bayside Bevy Marketplace",
"[Tuliyollal] The Resplendent Quarter"
]
}
]
},
{
"Sequence": 255,
"Steps": [
{
"DataId": 1051039,
"Position": {
"X": 17.593567,
"Y": -17.942173,
"Z": 153.06323
},
"TerritoryId": 1185,
"InteractionType": "CompleteQuest",
"AethernetShortcut": [
"[Tuliyollal] The Resplendent Quarter",
"[Tuliyollal] Bayside Bevy Marketplace"
]
}
]
}
]
}

View File

@ -0,0 +1,94 @@
{
"$schema": "https://carvel.li/questionable/quest-1.0",
"Author": "liza",
"QuestSequence": [
{
"Sequence": 0,
"Steps": [
{
"DataId": 1051042,
"Position": {
"X": 100.38904,
"Y": 47,
"Z": -230.27393
},
"TerritoryId": 1185,
"InteractionType": "AcceptQuest"
}
]
},
{
"Sequence": 1,
"Steps": [
{
"DataId": 2014235,
"Position": {
"X": -80.094604,
"Y": -19.333252,
"Z": 179.49182
},
"TerritoryId": 1185,
"InteractionType": "Interact",
"AethernetShortcut": [
"[Tuliyollal] Brightploom Post",
"[Tuliyollal] The For'ard Cabins"
]
}
]
},
{
"Sequence": 2,
"Steps": [
{
"DataId": 2014236,
"Position": {
"X": -154.34503,
"Y": -14.084106,
"Z": 548.24133
},
"TerritoryId": 1185,
"InteractionType": "Interact"
}
]
},
{
"Sequence": 3,
"Steps": [
{
"DataId": 2014237,
"Position": {
"X": -124.77307,
"Y": -5.0202637,
"Z": 113.11511
},
"TerritoryId": 1185,
"InteractionType": "Interact",
"AetheryteShortcut": "Tuliyollal",
"AethernetShortcut": [
"[Tuliyollal] Aetheryte Plaza",
"[Tuliyollal] The For'ard Cabins"
]
}
]
},
{
"Sequence": 255,
"Steps": [
{
"DataId": 1051042,
"Position": {
"X": 100.38904,
"Y": 47,
"Z": -230.27393
},
"TerritoryId": 1185,
"InteractionType": "CompleteQuest",
"AethernetShortcut": [
"[Tuliyollal] The For'ard Cabins",
"[Tuliyollal] Brightploom Post"
]
}
]
}
]
}

View File

@ -0,0 +1,87 @@
{
"$schema": "https://carvel.li/questionable/quest-1.0",
"Author": "liza",
"QuestSequence": [
{
"Sequence": 0,
"Steps": [
{
"DataId": 1051043,
"Position": {
"X": -276.99707,
"Y": 1.9748375E-05,
"Z": 71.97681
},
"TerritoryId": 1185,
"InteractionType": "AcceptQuest"
}
]
},
{
"Sequence": 1,
"Steps": [
{
"DataId": 1051044,
"Position": {
"X": -307.6372,
"Y": 3,
"Z": -50.8584
},
"TerritoryId": 1185,
"InteractionType": "Emote",
"Emote": "soothe",
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
128
]
},
{
"DataId": 1051045,
"Position": {
"X": -49.42401,
"Y": -2.7939677E-09,
"Z": 16.647583
},
"TerritoryId": 1185,
"InteractionType": "Emote",
"Emote": "soothe",
"AethernetShortcut": [
"[Tuliyollal] Dirigible Landing",
"[Tuliyollal] Aetheryte Plaza"
],
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
64
]
}
]
},
{
"Sequence": 255,
"Steps": [
{
"DataId": 1051043,
"Position": {
"X": -276.99707,
"Y": 1.9748375E-05,
"Z": 71.97681
},
"TerritoryId": 1185,
"InteractionType": "CompleteQuest",
"AethernetShortcut": [
"[Tuliyollal] Aetheryte Plaza",
"[Tuliyollal] The Resplendent Quarter"
]
}
]
}
]
}

View File

@ -0,0 +1,140 @@
{
"$schema": "https://carvel.li/questionable/quest-1.0",
"Author": "liza",
"QuestSequence": [
{
"Sequence": 0,
"Steps": [
{
"DataId": 1051046,
"Position": {
"X": 69.38269,
"Y": -14,
"Z": 91.081055
},
"TerritoryId": 1185,
"InteractionType": "AcceptQuest"
}
]
},
{
"Sequence": 1,
"Steps": [
{
"DataId": 2014238,
"Position": {
"X": 75.12012,
"Y": -17.990417,
"Z": 154.52808
},
"TerritoryId": 1185,
"InteractionType": "Interact",
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
128
]
},
{
"DataId": 2014239,
"Position": {
"X": 64.530396,
"Y": -17.990417,
"Z": 189.56274
},
"TerritoryId": 1185,
"InteractionType": "Interact",
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
64
]
},
{
"DataId": 2014240,
"Position": {
"X": 131.91418,
"Y": -17.990417,
"Z": 112.2301
},
"TerritoryId": 1185,
"InteractionType": "Interact",
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
32
]
}
]
},
{
"Sequence": 2,
"Steps": [
{
"DataId": 1051046,
"Position": {
"X": 69.38269,
"Y": -14,
"Z": 91.081055
},
"TerritoryId": 1185,
"InteractionType": "Interact"
}
]
},
{
"Sequence": 3,
"Steps": [
{
"DataId": 1051048,
"Position": {
"X": -227.95453,
"Y": 40.04104,
"Z": -42.648987
},
"TerritoryId": 1185,
"InteractionType": "Interact",
"AethernetShortcut": [
"[Tuliyollal] Aetheryte Plaza",
"[Tuliyollal] The Resplendent Quarter"
],
"DialogueChoices": [
{
"Type": "List",
"Prompt": "TEXT_KINGZA012_05028_Q1_000_000",
"Answer": "TEXT_KINGZA012_05028_A1_000_002"
}
]
}
]
},
{
"Sequence": 255,
"Steps": [
{
"DataId": 1051046,
"Position": {
"X": 69.38269,
"Y": -14,
"Z": 91.081055
},
"TerritoryId": 1185,
"InteractionType": "CompleteQuest",
"AethernetShortcut": [
"[Tuliyollal] The Resplendent Quarter",
"[Tuliyollal] Aetheryte Plaza"
]
}
]
}
]
}

View File

@ -0,0 +1,119 @@
{
"$schema": "https://carvel.li/questionable/quest-1.0",
"Author": "liza",
"QuestSequence": [
{
"Sequence": 0,
"Steps": [
{
"DataId": 1048537,
"Position": {
"X": -61.753296,
"Y": 99.99999,
"Z": -188.98297
},
"TerritoryId": 1185,
"InteractionType": "AcceptQuest"
}
]
},
{
"Sequence": 1,
"Steps": [
{
"DataId": 1046521,
"Position": {
"X": -46.616333,
"Y": -17.97287,
"Z": 180.3158
},
"StopDistance": 5,
"TerritoryId": 1185,
"InteractionType": "Interact",
"AethernetShortcut": [
"[Tuliyollal] Vollok Shoonsa",
"[Tuliyollal] Bayside Bevy Marketplace"
]
}
]
},
{
"Sequence": 2,
"Steps": [
{
"DataId": 1048547,
"Position": {
"X": -39.35309,
"Y": -17.972866,
"Z": 198.38245
},
"TerritoryId": 1185,
"InteractionType": "Interact",
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
32
]
},
{
"DataId": 1048418,
"Position": {
"X": -54.154297,
"Y": -17.972868,
"Z": 198.44348
},
"TerritoryId": 1185,
"InteractionType": "Interact",
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
64
]
},
{
"DataId": 1048546,
"Position": {
"X": -60.83777,
"Y": -17.972868,
"Z": 197.07019
},
"TerritoryId": 1185,
"InteractionType": "Interact",
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
128
]
}
]
},
{
"Sequence": 255,
"Steps": [
{
"DataId": 1048537,
"Position": {
"X": -61.753296,
"Y": 99.99999,
"Z": -188.98297
},
"TerritoryId": 1185,
"InteractionType": "CompleteQuest",
"AethernetShortcut": [
"[Tuliyollal] Bayside Bevy Marketplace",
"[Tuliyollal] Vollok Shoonsa"
]
}
]
}
]
}

View File

@ -0,0 +1,86 @@
{
"$schema": "https://carvel.li/questionable/quest-1.0",
"Author": "liza",
"QuestSequence": [
{
"Sequence": 0,
"Steps": [
{
"DataId": 1051195,
"Position": {
"X": 383.29138,
"Y": -154.50243,
"Z": -420.49292
},
"TerritoryId": 1187,
"InteractionType": "AcceptQuest"
}
]
},
{
"Sequence": 1,
"Steps": [
{
"DataId": 1051199,
"Position": {
"X": 442.95398,
"Y": -116.815155,
"Z": -178.63745
},
"TerritoryId": 1187,
"InteractionType": "Interact",
"Fly": true
}
]
},
{
"Sequence": 2,
"Steps": [
{
"DataId": 1051200,
"Position": {
"X": 563.83606,
"Y": -49.515564,
"Z": 49.54602
},
"TerritoryId": 1187,
"InteractionType": "Interact",
"Fly": true
}
]
},
{
"Sequence": 3,
"Steps": [
{
"DataId": 1048773,
"Position": {
"X": 576.2875,
"Y": -49.16388,
"Z": 37.00305
},
"TerritoryId": 1187,
"InteractionType": "Interact"
}
]
},
{
"Sequence": 255,
"Steps": [
{
"DataId": 1051195,
"Position": {
"X": 383.29138,
"Y": -154.50243,
"Z": -420.49292
},
"TerritoryId": 1187,
"InteractionType": "CompleteQuest",
"AetheryteShortcut": "Urqopacha - Wachunpelo",
"Fly": true,
"NextQuestId": 5053
}
]
}
]
}

View File

@ -0,0 +1,132 @@
{
"$schema": "https://carvel.li/questionable/quest-1.0",
"Author": "liza",
"QuestSequence": [
{
"Sequence": 0,
"Steps": [
{
"DataId": 1051195,
"Position": {
"X": 383.29138,
"Y": -154.50243,
"Z": -420.49292
},
"TerritoryId": 1187,
"InteractionType": "AcceptQuest",
"DialogueChoices": [
{
"Type": "List",
"Prompt": "TEXT_KINGZB203_05053_Q1_000_000",
"Answer": "TEXT_KINGZB203_05053_A1_000_003"
}
]
}
]
},
{
"Sequence": 1,
"Steps": [
{
"DataId": 1048629,
"Position": {
"X": 353.35315,
"Y": -158.06824,
"Z": -423.72784
},
"TerritoryId": 1187,
"InteractionType": "Interact",
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
32
]
},
{
"DataId": 1051202,
"Position": {
"X": 338.55188,
"Y": -160.20284,
"Z": -450.9804
},
"TerritoryId": 1187,
"InteractionType": "Interact",
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
128
],
"Fly": true
},
{
"DataId": 1051203,
"Position": {
"X": 283.22266,
"Y": -168.30641,
"Z": -452.26215
},
"TerritoryId": 1187,
"InteractionType": "Interact",
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
64
],
"Fly": true
},
{
"DataId": 1048660,
"Position": {
"X": 246.3263,
"Y": -168.27,
"Z": -487.20532
},
"TerritoryId": 1187,
"InteractionType": "Interact",
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
16
],
"Fly": true
}
]
},
{
"Sequence": 255,
"Steps": [
{
"DataId": 1051195,
"Position": {
"X": 383.29138,
"Y": -154.50243,
"Z": -420.49292
},
"TerritoryId": 1187,
"InteractionType": "CompleteQuest",
"Fly": true,
"NextQuestId": 5054,
"DialogueChoices": [
{
"Type": "YesNo",
"Prompt": "TEXT_KINGZB203_05053_Q2_000_000",
"Yes": true
}
]
}
]
}
]
}

View File

@ -0,0 +1,92 @@
{
"$schema": "https://carvel.li/questionable/quest-1.0",
"Author": "liza",
"QuestSequence": [
{
"Sequence": 0,
"Steps": [
{
"DataId": 1051195,
"Position": {
"X": 383.29138,
"Y": -154.50243,
"Z": -420.49292
},
"TerritoryId": 1187,
"InteractionType": "AcceptQuest"
}
]
},
{
"Sequence": 1,
"Steps": [
{
"DataId": 1051200,
"Position": {
"X": 563.83606,
"Y": -49.515564,
"Z": 49.54602
},
"TerritoryId": 1187,
"InteractionType": "Interact",
"Fly": true
}
]
},
{
"Sequence": 2,
"Steps": [
{
"DataId": 2014271,
"Position": {
"X": 560.9064,
"Y": -54.459473,
"Z": 22.781677
},
"TerritoryId": 1187,
"InteractionType": "Interact",
"Fly": true,
"DialogueChoices": [
{
"Type": "YesNo",
"Prompt": "TEXT_KINGZB204_05054_Q1_000_000",
"Yes": true
}
]
}
]
},
{
"Sequence": 3,
"Steps": [
{
"DataId": 1051204,
"Position": {
"X": 562.7374,
"Y": -54.457336,
"Z": 21.530457
},
"StopDistance": 5,
"TerritoryId": 1187,
"InteractionType": "Interact"
}
]
},
{
"Sequence": 255,
"Steps": [
{
"DataId": 1051195,
"Position": {
"X": 383.29138,
"Y": -154.50243,
"Z": -420.49292
},
"TerritoryId": 1187,
"InteractionType": "CompleteQuest",
"AetheryteShortcut": "Urqopacha - Wachunpelo"
}
]
}
]
}

View File

@ -651,7 +651,8 @@
"cheer",
"happy",
"poke",
"flex"
"flex",
"soothe"
]
}
}
@ -948,7 +949,7 @@
},
"then": {
"properties": {
"QuestId": {
"PickUpQuestId": {
"type": [
"null",
"number"
@ -957,6 +958,33 @@
}
}
}
},
{
"if": {
"properties": {
"InteractionType": {
"const": "CompleteQuest"
}
}
},
"then": {
"properties": {
"TurnInQuestId": {
"type": [
"null",
"number"
],
"description": "Determines the quest which should be turned in. If empty/null, turns in the quest corresponding to the file name."
},
"NextQuestId": {
"type": [
"null",
"number"
],
"description": "For quest chains (e.g. DT healer role quests) Which quest to do next, given that you meet the required level."
}
}
}
}
]
}

View File

@ -18,5 +18,6 @@ public sealed class EmoteConverter() : EnumConverter<EEmote>(Values)
{ EEmote.Happy, "happy" },
{ EEmote.Poke, "poke" },
{ EEmote.Flex, "flex" },
{ EEmote.Soothe, "soothe" },
};
}

View File

@ -20,4 +20,5 @@ public enum EEmote
Happy = 48,
Poke = 28,
Flex = 139,
Soothe = 35,
}

View File

@ -2,7 +2,7 @@
namespace Questionable.Model.V1;
public sealed class QuestData
public sealed class QuestRoot
{
public string Author { get; set; } = null!;
public List<string> Contributors { get; set; } = new();

View File

@ -53,7 +53,12 @@ public sealed class QuestStep
public IList<short?> CompletionQuestVariablesFlags { get; set; } = new List<short?>();
public IList<DialogueChoice> DialogueChoices { get; set; } = new List<DialogueChoice>();
public IList<uint> PointMenuChoices { get; set; } = new List<uint>();
public ushort? QuestId { get; set; }
// TODO: Not implemented
public ushort? PickupQuestId { get; set; }
public ushort? TurnInQuestId { get; set; }
public ushort? NextQuestId { get; set; }
[JsonConstructor]
public QuestStep()

View File

@ -0,0 +1,155 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Dalamud.Game.ClientState.Objects;
using Dalamud.Game.Command;
using Dalamud.Plugin.Services;
using Questionable.Data;
using Questionable.Model;
using Questionable.Windows;
namespace Questionable.Controller;
internal sealed class CommandHandler : IDisposable
{
private readonly ICommandManager _commandManager;
private readonly IChatGui _chatGui;
private readonly QuestController _questController;
private readonly MovementController _movementController;
private readonly QuestRegistry _questRegistry;
private readonly QuestData _questData;
private readonly ConfigWindow _configWindow;
private readonly DebugOverlay _debugOverlay;
private readonly QuestWindow _questWindow;
public CommandHandler(ICommandManager commandManager, IChatGui chatGui, QuestController questController,
MovementController movementController, QuestRegistry questRegistry, QuestData questData,
ConfigWindow configWindow, DebugOverlay debugOverlay, QuestWindow questWindow)
{
_commandManager = commandManager;
_chatGui = chatGui;
_questController = questController;
_movementController = movementController;
_questRegistry = questRegistry;
_questData = questData;
_configWindow = configWindow;
_debugOverlay = debugOverlay;
_questWindow = questWindow;
_commandManager.AddHandler("/qst", new CommandInfo(ProcessCommand)
{
HelpMessage = "Opens the Questing window"
});
}
private void ProcessCommand(string command, string arguments)
{
string[] parts = arguments.Split(' ');
switch (parts[0])
{
case "c":
case "config":
_configWindow.Toggle();
break;
case "start":
_questController.ExecuteNextStep(true);
break;
case "stop":
_movementController.Stop();
_questController.Stop("Stop command");
break;
case "do":
ConfigureDebugOverlay(parts.Skip(1).ToArray());
break;
case "next":
SetNextQuest(parts.Skip(1).ToArray());
break;
case "sim":
SetSimulatedQuest(parts.Skip(1).ToArray());
break;
case "which":
_questData.ShowQuestsIssuedByTarget();
break;
default:
_questWindow.Toggle();
break;
}
}
private void ConfigureDebugOverlay(string[] arguments)
{
if (!_debugOverlay.DrawConditions())
{
_chatGui.PrintError("[Questionable] You don't have the debug overlay enabled.");
return;
}
if (arguments.Length >= 1 && ushort.TryParse(arguments[0], out ushort questId))
{
if (_questRegistry.IsKnownQuest(questId))
{
_debugOverlay.HighlightedQuest = questId;
_chatGui.Print($"[Questionable] Set highlighted quest to {questId}.");
}
else
_chatGui.PrintError($"[Questionable] Unknown quest {questId}.");
}
else
{
_debugOverlay.HighlightedQuest = null;
_chatGui.Print("[Questionable] Cleared highlighted quest.");
}
}
private void SetNextQuest(string[] arguments)
{
if (arguments.Length >= 1 && ushort.TryParse(arguments[0], out ushort questId))
{
if (_questRegistry.TryGetQuest(questId, out Quest? quest))
{
_questController.SetNextQuest(quest);
_chatGui.Print($"[Questionable] Set next quest to {questId}.");
}
else
{
_chatGui.PrintError($"[Questionable] Unknown quest {questId}.");
}
}
else
{
_questController.SetNextQuest(null);
_chatGui.Print("[Questionable] Cleared next quest.");
}
}
private void SetSimulatedQuest(string[] arguments)
{
if (arguments.Length >= 1 && ushort.TryParse(arguments[0], out ushort questId))
{
if (_questRegistry.TryGetQuest(questId, out Quest? quest))
{
_questController.SimulateQuest(quest);
_chatGui.Print($"[Questionable] Simulating quest {questId}.");
}
else
_chatGui.PrintError($"[Questionable] Unknown quest {questId}.");
}
else
{
_questController.SimulateQuest(null);
_chatGui.Print("[Questionable] Cleared simulated quest.");
}
}
public void Dispose()
{
_commandManager.RemoveHandler("/qst");
}
}

View File

@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text.RegularExpressions;
using Dalamud.Game.Addon.Lifecycle;
@ -13,6 +12,7 @@ using LLib;
using LLib.GameUI;
using Lumina.Excel.GeneratedSheets;
using Microsoft.Extensions.Logging;
using Questionable.Data;
using Questionable.Model.V1;
using Quest = Questionable.Model.Quest;
using ValueType = FFXIVClientStructs.FFXIV.Component.GUI.ValueType;
@ -25,19 +25,23 @@ internal sealed class GameUiController : IDisposable
private readonly IDataManager _dataManager;
private readonly GameFunctions _gameFunctions;
private readonly QuestController _questController;
private readonly QuestRegistry _questRegistry;
private readonly QuestData _questData;
private readonly IGameGui _gameGui;
private readonly ITargetManager _targetManager;
private readonly ILogger<GameUiController> _logger;
private readonly Regex _returnRegex;
public GameUiController(IAddonLifecycle addonLifecycle, IDataManager dataManager, GameFunctions gameFunctions,
QuestController questController, IGameGui gameGui, ITargetManager targetManager, IPluginLog pluginLog,
ILogger<GameUiController> logger)
QuestController questController, QuestRegistry questRegistry, QuestData questData, IGameGui gameGui,
ITargetManager targetManager, IPluginLog pluginLog, ILogger<GameUiController> logger)
{
_addonLifecycle = addonLifecycle;
_dataManager = dataManager;
_gameFunctions = gameFunctions;
_questController = questController;
_questRegistry = questRegistry;
_questData = questData;
_gameGui = gameGui;
_targetManager = targetManager;
_logger = logger;
@ -162,7 +166,7 @@ internal sealed class GameUiController : IDisposable
if (currentQuest != null && actualPrompt == null)
{
// it is possible for this to be a quest selection
string questName = currentQuest.Quest.Name;
string questName = currentQuest.Quest.Info.Name;
int questSelection = answers.FindIndex(x => GameStringEquals(questName, x));
if (questSelection >= 0)
addonSelectIconString->AtkUnitBase.FireCallbackInt(questSelection);
@ -172,33 +176,55 @@ internal sealed class GameUiController : IDisposable
private int? HandleListChoice(string? actualPrompt, List<string?> answers, bool checkAllSteps)
{
List<DialogueChoiceInfo> dialogueChoices = [];
var currentQuest = _questController.CurrentQuest;
if (currentQuest == null)
if (currentQuest != null)
{
_logger.LogInformation("Ignoring list choice, no active quest");
return null;
}
var quest = currentQuest.Quest;
IList<DialogueChoice> dialogueChoices;
if (checkAllSteps)
{
var sequence = quest.FindSequence(currentQuest.Sequence);
dialogueChoices = sequence?.Steps.SelectMany(x => x.DialogueChoices).ToList() ?? new List<DialogueChoice>();
var quest = currentQuest.Quest;
if (checkAllSteps)
{
var sequence = quest.FindSequence(currentQuest.Sequence);
var choices = sequence?.Steps.SelectMany(x => x.DialogueChoices);
if (choices != null)
dialogueChoices.AddRange(choices.Select(x => new DialogueChoiceInfo(quest, x)));
}
else
{
var step = quest.FindSequence(currentQuest.Sequence)?.FindStep(currentQuest.Step);
if (step == null)
_logger.LogInformation("Ignoring current quest dialogue choices, no active step");
else
dialogueChoices.AddRange(step.DialogueChoices.Select(x => new DialogueChoiceInfo(quest, x)));
}
}
else
{
var step = quest.FindSequence(currentQuest.Sequence)?.FindStep(currentQuest.Step);
if (step == null)
{
_logger.LogInformation("Ignoring list choice, no active step");
return null;
}
_logger.LogInformation("Ignoring current quest dialogue choices, no active quest");
dialogueChoices = step.DialogueChoices;
// add all quests that start with the targeted npc
var target = _targetManager.Target;
if (target != null)
{
foreach (var questInfo in _questData.GetAllByIssuerDataId(target.DataId))
{
if (_gameFunctions.IsReadyToAcceptQuest(questInfo.QuestId) &&
_questRegistry.TryGetQuest(questInfo.QuestId, out Quest? knownQuest))
{
var questChoices = knownQuest.FindSequence(0)?.Steps
.SelectMany(x => x.DialogueChoices)
.ToList();
if (questChoices != null && questChoices.Count > 0)
{
_logger.LogInformation("Adding {Count} dialogue choices from not accepted quest {QuestName}", questChoices.Count, questInfo.Name);
dialogueChoices.AddRange(questChoices.Select(x => new DialogueChoiceInfo(knownQuest, x)));
}
}
}
}
foreach (var dialogueChoice in dialogueChoices)
if (dialogueChoices.Count == 0)
return null;
foreach (var (quest, dialogueChoice) in dialogueChoices)
{
if (dialogueChoice.Type != EDialogChoiceType.List)
continue;
@ -433,13 +459,7 @@ internal sealed class GameUiController : IDisposable
};
addonPointMenu->FireCallback(2, selectChoice);
_questController.CurrentQuest = currentQuest with
{
StepProgress = currentQuest.StepProgress with
{
PointMenuCounter = counter + 1,
}
};
currentQuest.IncreasePointMenuCounter();
}
private unsafe void CreditPostSetup(AddonEvent type, AddonArgs args)
@ -519,4 +539,6 @@ internal sealed class GameUiController : IDisposable
_addonLifecycle.UnregisterListener(AddonEvent.PostSetup, "CutSceneSelectString", CutsceneSelectStringPostSetup);
_addonLifecycle.UnregisterListener(AddonEvent.PostSetup, "SelectString", SelectStringPostSetup);
}
private sealed record DialogueChoiceInfo(Quest Quest, DialogueChoice DialogueChoice);
}

View File

@ -25,6 +25,10 @@ internal sealed class QuestController
private readonly object _lock = new();
private QuestProgress? _startedQuest;
private QuestProgress? _nextQuest;
private QuestProgress? _simulatedQuest;
private readonly Queue<ITask> _taskQueue = new();
private ITask? _currentTask;
private bool _automatic;
@ -51,9 +55,22 @@ internal sealed class QuestController
_taskFactories = taskFactories.ToList().AsReadOnly();
}
public QuestProgress? CurrentQuest
{
get
{
if (_simulatedQuest != null)
return _simulatedQuest;
else if (_nextQuest != null && _gameFunctions.IsReadyToAcceptQuest(_nextQuest.Quest.QuestId))
return _nextQuest;
else
return _startedQuest;
}
}
public QuestProgress? SimulatedQuest => _simulatedQuest;
public QuestProgress? NextQuest => _nextQuest;
public QuestProgress? CurrentQuest { get; set; }
public SimulationProgress? SimulatedQuest { get; set; }
public string? DebugState { get; private set; }
public string? Comment { get; private set; }
@ -61,7 +78,10 @@ internal sealed class QuestController
{
lock (_lock)
{
CurrentQuest = null;
_startedQuest = null;
_nextQuest = null;
_simulatedQuest = null;
DebugState = null;
_questRegistry.Reload();
@ -81,7 +101,7 @@ internal sealed class QuestController
}
}
if (CurrentQuest != null && CurrentQuest.Quest.Data.TerritoryBlacklist.Contains(_clientState.TerritoryType))
if (CurrentQuest != null && CurrentQuest.Quest.Root.TerritoryBlacklist.Contains(_clientState.TerritoryType))
return;
// not verified to work
@ -92,10 +112,7 @@ internal sealed class QuestController
lock (_lock)
{
_logger.LogWarning("Quest accept apparently didn't work out, resetting progress");
CurrentQuest = CurrentQuest with
{
Step = 0
};
CurrentQuest.SetStep(0);
}
ExecuteNextStep(true);
@ -111,50 +128,64 @@ internal sealed class QuestController
{
DebugState = null;
ushort currentQuestId;
byte currentSequence;
if (SimulatedQuest != null)
byte currentSequence = 0;
if (_simulatedQuest != null)
{
currentQuestId = SimulatedQuest.Quest.QuestId;
currentSequence = SimulatedQuest.Sequence;
currentSequence = _simulatedQuest.Sequence;
}
else
(currentQuestId, currentSequence) = _gameFunctions.GetCurrentQuest();
if (currentQuestId == 0)
else if (_nextQuest != null)
{
if (CurrentQuest != null)
// if the quest is accepted, we no longer track it
if (_gameFunctions.IsQuestAcceptedOrComplete(_nextQuest.Quest.QuestId))
{
_logger.LogInformation("No current quest, resetting data");
CurrentQuest = null;
Stop("Resetting current quest");
_nextQuest = null;
currentSequence = 0;
}
else
{
currentSequence = _nextQuest.Sequence; // by definition, this should always be 0
}
}
else if (CurrentQuest == null || CurrentQuest.Quest.QuestId != currentQuestId)
if (_simulatedQuest == null && _nextQuest == null)
{
if (_questRegistry.TryGetQuest(currentQuestId, out var quest))
(ushort currentQuestId, currentSequence) = _gameFunctions.GetCurrentQuest();
if (currentQuestId == 0)
{
_logger.LogInformation("New quest: {QuestName}", quest.Name);
CurrentQuest = new QuestProgress(quest, currentSequence, 0);
bool continueAutomatically = _configuration.General.AutoAcceptNextQuest;
if (_clientState.LocalPlayer?.Level < quest.Level)
continueAutomatically = false;
Stop("Different Quest", continueAutomatically);
if (_startedQuest != null)
{
_logger.LogInformation("No current quest, resetting data");
_startedQuest = null;
Stop("Resetting current quest");
}
}
else if (CurrentQuest != null)
else if (_startedQuest == null || _startedQuest.Quest.QuestId != currentQuestId)
{
_logger.LogInformation("No active quest anymore? Not sure what happened...");
CurrentQuest = null;
Stop("No active Quest");
}
if (_questRegistry.TryGetQuest(currentQuestId, out var quest))
{
_logger.LogInformation("New quest: {QuestName}", quest.Info.Name);
_startedQuest = new QuestProgress(quest, currentSequence);
return;
bool continueAutomatically = _configuration.General.AutoAcceptNextQuest;
if (_clientState.LocalPlayer?.Level < quest.Info.Level)
continueAutomatically = false;
Stop("Different Quest", continueAutomatically);
}
else if (_startedQuest != null)
{
_logger.LogInformation("No active quest anymore? Not sure what happened...");
_startedQuest = null;
Stop("No active Quest");
}
return;
}
}
if (CurrentQuest == null)
var questToRun = CurrentQuest;
if (questToRun == null)
{
DebugState = "No quest active";
Comment = null;
@ -179,14 +210,14 @@ internal sealed class QuestController
return;
}
if (CurrentQuest.Sequence != currentSequence)
if (questToRun.Sequence != currentSequence)
{
CurrentQuest = CurrentQuest with { Sequence = currentSequence, Step = 0 };
questToRun.SetSequence(currentSequence);
Stop("New sequence", continueIfAutomatic: true);
}
var q = CurrentQuest.Quest;
var sequence = q.FindSequence(CurrentQuest.Sequence);
var q = questToRun.Quest;
var sequence = q.FindSequence(questToRun.Sequence);
if (sequence == null)
{
DebugState = "Sequence not found";
@ -195,7 +226,7 @@ internal sealed class QuestController
return;
}
if (CurrentQuest.Step == 255)
if (questToRun.Step == 255)
{
DebugState = "Step completed";
Comment = null;
@ -204,7 +235,7 @@ internal sealed class QuestController
return;
}
if (CurrentQuest.Step >= sequence.Steps.Count)
if (questToRun.Step >= sequence.Steps.Count)
{
DebugState = "Step not found";
Comment = null;
@ -212,9 +243,9 @@ internal sealed class QuestController
return;
}
var step = sequence.Steps[CurrentQuest.Step];
var step = sequence.Steps[questToRun.Step];
DebugState = null;
Comment = step.Comment ?? sequence.Comment ?? q.Data.Comment;
Comment = step.Comment ?? sequence.Comment ?? q.Root.Comment;
}
}
@ -262,21 +293,9 @@ internal sealed class QuestController
_logger.LogInformation("Increasing step count from {CurrentValue}", CurrentQuest.Step);
if (CurrentQuest.Step + 1 < seq.Steps.Count)
{
CurrentQuest = CurrentQuest with
{
Step = CurrentQuest.Step + 1,
StepProgress = new(DateTime.Now),
};
}
CurrentQuest.SetStep(CurrentQuest.Step + 1);
else
{
CurrentQuest = CurrentQuest with
{
Step = 255,
StepProgress = new(DateTime.Now),
};
}
CurrentQuest.SetStep(255);
}
if (shouldContinue && _automatic)
@ -310,14 +329,26 @@ internal sealed class QuestController
_logger.LogInformation("Stopping automatic questing");
_automatic = false;
}
_nextQuest = null;
}
public void SimulateQuest(Quest? quest)
{
_logger.LogInformation("SimulateQuest: {QuestId}", quest?.QuestId);
if (quest != null)
SimulatedQuest = new SimulationProgress(quest, 0);
_simulatedQuest = new QuestProgress(quest);
else
SimulatedQuest = null;
_simulatedQuest = null;
}
public void SetNextQuest(Quest? quest)
{
_logger.LogInformation("NextQuest: {QuestId}", quest?.QuestId);
if (quest != null)
_nextQuest = new QuestProgress(quest);
else
_nextQuest = null;
}
private void UpdateCurrentTask()
@ -470,20 +501,40 @@ internal sealed class QuestController
public bool IsRunning => _currentTask != null || _taskQueue.Count > 0;
public sealed record QuestProgress(
Quest Quest,
byte Sequence,
int Step,
StepProgress StepProgress)
public sealed class QuestProgress
{
public QuestProgress(Quest quest, byte sequence, int step)
: this(quest, sequence, step, new StepProgress(DateTime.Now))
public Quest Quest { get; }
public byte Sequence { get; private set; }
public int Step { get; private set; }
public StepProgress StepProgress { get; private set; } = new(DateTime.Now);
public QuestProgress(Quest quest, byte sequence = 0)
{
Quest = quest;
SetSequence(sequence);
}
public void SetSequence(byte sequence)
{
Sequence = sequence;
SetStep(0);
}
public void SetStep(int step)
{
Step = step;
StepProgress = new StepProgress(DateTime.Now);
}
public void IncreasePointMenuCounter()
{
StepProgress = StepProgress with
{
PointMenuCounter = StepProgress.PointMenuCounter + 1,
};
}
}
public sealed record SimulationProgress(Quest Quest, byte Sequence);
public void Skip(ushort questQuestId, byte currentQuestSequence)
{
lock (_lock)

View File

@ -8,6 +8,7 @@ using System.Text.Json;
using Dalamud.Plugin;
using Dalamud.Plugin.Services;
using Microsoft.Extensions.Logging;
using Questionable.Data;
using Questionable.Model;
using Questionable.Model.V1;
@ -16,16 +17,16 @@ namespace Questionable.Controller;
internal sealed class QuestRegistry
{
private readonly IDalamudPluginInterface _pluginInterface;
private readonly IDataManager _dataManager;
private readonly QuestData _questData;
private readonly ILogger<QuestRegistry> _logger;
private readonly Dictionary<ushort, Quest> _quests = new();
public QuestRegistry(IDalamudPluginInterface pluginInterface, IDataManager dataManager,
public QuestRegistry(IDalamudPluginInterface pluginInterface, QuestData questData,
ILogger<QuestRegistry> logger)
{
_pluginInterface = pluginInterface;
_dataManager = dataManager;
_questData = questData;
_logger = logger;
}
@ -47,7 +48,7 @@ internal sealed class QuestRegistry
_quests[questId] = quest;
}
#else
DirectoryInfo? solutionDirectory = _pluginInterface.AssemblyLocation?.Directory?.Parent?.Parent;
DirectoryInfo? solutionDirectory = _pluginInterface.AssemblyLocation.Directory?.Parent?.Parent;
if (solutionDirectory != null)
{
DirectoryInfo pathProjectDirectory =
@ -64,22 +65,14 @@ internal sealed class QuestRegistry
LoadFromDirectory(new DirectoryInfo(Path.Combine(_pluginInterface.ConfigDirectory.FullName, "Quests")));
foreach (var (questId, quest) in _quests)
{
var questData =
_dataManager.GetExcelSheet<Lumina.Excel.GeneratedSheets.Quest>()!.GetRow((uint)questId + 0x10000);
if (questData == null)
continue;
quest.Name = questData.Name.ToString();
quest.Level = questData.ClassJobLevel0;
#if !RELEASE
int missingSteps = quest.Data.QuestSequence.Where(x => x.Sequence < 255).Max(x => x.Sequence) - quest.Data.QuestSequence.Count(x => x.Sequence < 255) + 1;
foreach (var quest in _quests.Values)
{
int missingSteps = quest.Root.QuestSequence.Where(x => x.Sequence < 255).Max(x => x.Sequence) - quest.Root.QuestSequence.Count(x => x.Sequence < 255) + 1;
if (missingSteps != 0)
_logger.LogWarning("Quest has missing steps: {QuestId} / {QuestName} → {Count}", quest.QuestId, quest.Name, missingSteps);
#endif
_logger.LogWarning("Quest has missing steps: {QuestId} / {QuestName} → {Count}", quest.QuestId, quest.Info.Name, missingSteps);
}
#endif
_logger.LogInformation("Loaded {Count} quests", _quests.Count);
}
@ -88,12 +81,12 @@ internal sealed class QuestRegistry
private void LoadQuestFromStream(string fileName, Stream stream)
{
_logger.LogTrace("Loading quest from '{FileName}'", fileName);
var (questId, name) = ExtractQuestDataFromName(fileName);
var questId = ExtractQuestIdFromName(fileName);
Quest quest = new Quest
{
QuestId = questId,
Name = name,
Data = JsonSerializer.Deserialize<QuestData>(stream)!,
Root = JsonSerializer.Deserialize<QuestRoot>(stream)!,
Info = _questData.GetQuestInfo(questId),
};
_quests[questId] = quest;
}
@ -124,13 +117,13 @@ internal sealed class QuestRegistry
LoadFromDirectory(childDirectory);
}
private static (ushort QuestId, string Name) ExtractQuestDataFromName(string resourceName)
private static ushort ExtractQuestIdFromName(string resourceName)
{
string name = resourceName.Substring(0, resourceName.Length - ".json".Length);
name = name.Substring(name.LastIndexOf('.') + 1);
string[] parts = name.Split('_', 2);
return (ushort.Parse(parts[0], CultureInfo.InvariantCulture), parts[1]);
return ushort.Parse(parts[0], CultureInfo.InvariantCulture);
}
public bool IsKnownQuest(ushort questId) => _quests.ContainsKey(questId);

View File

@ -107,14 +107,14 @@ internal static class WaitAtEnd
case EInteractionType.AcceptQuest:
return
[
serviceProvider.GetRequiredService<WaitQuestAccepted>().With(step.QuestId ?? quest.QuestId),
serviceProvider.GetRequiredService<WaitQuestAccepted>().With(step.PickupQuestId ?? quest.QuestId),
serviceProvider.GetRequiredService<WaitDelay>()
];
case EInteractionType.CompleteQuest:
return
[
serviceProvider.GetRequiredService<WaitQuestCompleted>().With(step.QuestId ?? quest.QuestId),
serviceProvider.GetRequiredService<WaitQuestCompleted>().With(step.TurnInQuestId ?? quest.QuestId),
serviceProvider.GetRequiredService<WaitDelay>()
];

View File

@ -0,0 +1,54 @@
using System;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Questionable.Model;
using Questionable.Model.V1;
namespace Questionable.Controller.Steps.BaseTasks;
internal static class NextQuest
{
internal sealed class Factory(IServiceProvider serviceProvider) : ITaskFactory
{
public ITask? CreateTask(Quest quest, QuestSequence sequence, QuestStep step)
{
if (step.InteractionType != EInteractionType.CompleteQuest)
return null;
if (step.NextQuestId == null)
return null;
return serviceProvider.GetRequiredService<SetQuest>()
.With(step.NextQuestId.Value);
}
}
internal sealed class SetQuest(QuestRegistry questRegistry, QuestController questController, ILogger<SetQuest> logger) : ITask
{
public ushort NextQuestId { get; set; }
public ITask With(ushort nextQuestId)
{
NextQuestId = nextQuestId;
return this;
}
public bool Start()
{
if (questRegistry.TryGetQuest(NextQuestId, out Quest? quest))
{
logger.LogInformation("Setting next quest to {QuestId}: '{QuestName}'", NextQuestId, quest.Info.Name);
questController.SetNextQuest(quest);
}
else
{
logger.LogInformation("Next quest with id {QuestId} not found", NextQuestId);
questController.SetNextQuest(null);
}
return true;
}
public ETaskResult Update() => ETaskResult.TaskComplete;
}
}

View File

@ -1,12 +1,8 @@
using System;
using Dalamud.Game.Command;
using Dalamud.Interface.Windowing;
using Dalamud.Plugin;
using Dalamud.Plugin.Services;
using Microsoft.Extensions.Logging;
using Questionable.Controller;
using Questionable.Data;
using Questionable.Model;
using Questionable.Windows;
namespace Questionable;
@ -15,35 +11,33 @@ internal sealed class DalamudInitializer : IDisposable
{
private readonly IDalamudPluginInterface _pluginInterface;
private readonly IFramework _framework;
private readonly ICommandManager _commandManager;
private readonly QuestController _questController;
private readonly MovementController _movementController;
private readonly NavigationShortcutController _navigationShortcutController;
private readonly IChatGui _chatGui;
private readonly WindowSystem _windowSystem;
private readonly QuestWindow _questWindow;
private readonly DebugOverlay _debugOverlay;
private readonly ConfigWindow _configWindow;
private readonly QuestRegistry _questRegistry;
public DalamudInitializer(IDalamudPluginInterface pluginInterface, IFramework framework,
ICommandManager commandManager, QuestController questController, MovementController movementController,
GameUiController gameUiController, NavigationShortcutController navigationShortcutController, IChatGui chatGui,
WindowSystem windowSystem, QuestWindow questWindow, DebugOverlay debugOverlay, ConfigWindow configWindow,
QuestRegistry questRegistry)
public DalamudInitializer(
IDalamudPluginInterface pluginInterface,
IFramework framework,
QuestController questController,
MovementController movementController,
GameUiController gameUiController,
NavigationShortcutController navigationShortcutController,
WindowSystem windowSystem,
QuestWindow questWindow,
DebugOverlay debugOverlay,
ConfigWindow configWindow)
{
_pluginInterface = pluginInterface;
_framework = framework;
_commandManager = commandManager;
_questController = questController;
_movementController = movementController;
_navigationShortcutController = navigationShortcutController;
_chatGui = chatGui;
_windowSystem = windowSystem;
_questWindow = questWindow;
_debugOverlay = debugOverlay;
_configWindow = configWindow;
_questRegistry = questRegistry;
_windowSystem.AddWindow(questWindow);
_windowSystem.AddWindow(configWindow);
@ -53,11 +47,6 @@ internal sealed class DalamudInitializer : IDisposable
_pluginInterface.UiBuilder.OpenMainUi += _questWindow.Toggle;
_pluginInterface.UiBuilder.OpenConfigUi += _configWindow.Toggle;
_framework.Update += FrameworkUpdate;
_commandManager.AddHandler("/qst", new CommandInfo(ProcessCommand)
{
HelpMessage = "Opens the Questing window"
});
_framework.RunOnTick(gameUiController.HandleCurrentDialogueChoices, TimeSpan.FromMilliseconds(200));
}
@ -76,68 +65,10 @@ internal sealed class DalamudInitializer : IDisposable
}
}
private void ProcessCommand(string command, string arguments)
{
if (arguments is "c" or "config")
_configWindow.Toggle();
if (arguments is "start")
_questController.ExecuteNextStep(true);
else if (arguments is "stop")
{
_movementController.Stop();
_questController.Stop("Stop command");
}
else if (arguments.StartsWith("do", StringComparison.Ordinal))
{
if (!_debugOverlay.DrawConditions())
{
_chatGui.PrintError("[Questionable] You don't have the debug overlay enabled.");
return;
}
if (arguments.Length >= 4 && ushort.TryParse(arguments.AsSpan(3), out ushort questId))
{
if (_questRegistry.IsKnownQuest(questId))
{
_debugOverlay.HighlightedQuest = questId;
_chatGui.Print($"[Questionable] Set highlighted quest to {questId}.");
}
else
_chatGui.PrintError($"[Questionable] Unknown quest {questId}.");
}
else
{
_debugOverlay.HighlightedQuest = null;
_chatGui.Print("[Questionable] Cleared highlighted quest.");
}
}
else if (arguments.StartsWith("sim", StringComparison.InvariantCulture))
{
string[] parts = arguments.Split(' ');
if (parts.Length == 2 && ushort.TryParse(parts[1], out ushort questId))
{
if (_questRegistry.TryGetQuest(questId, out Quest? quest))
{
_questController.SimulateQuest(quest);
_chatGui.Print($"[Questionable] Simulating quest {questId}.");
}
else
_chatGui.PrintError($"[Questionable] Unknown quest {questId}.");
}
else
{
_questController.SimulateQuest(null);
_chatGui.Print("[Questionable] Cleared simulated quest.");
}
}
else if (string.IsNullOrEmpty(arguments))
_questWindow.Toggle();
}
public void Dispose()
{
_commandManager.RemoveHandler("/qst");
_framework.Update -= FrameworkUpdate;
_pluginInterface.UiBuilder.OpenConfigUi -= _configWindow.Toggle;
_pluginInterface.UiBuilder.OpenMainUi -= _questWindow.Toggle;
_pluginInterface.UiBuilder.Draw -= _windowSystem.Draw;

View File

@ -0,0 +1,58 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using Dalamud.Game.ClientState.Objects;
using Dalamud.Plugin.Services;
using Questionable.Model;
using Quest = Lumina.Excel.GeneratedSheets.Quest;
namespace Questionable.Data;
internal sealed class QuestData
{
private readonly ITargetManager _targetManager;
private readonly IChatGui _chatGui;
private readonly ImmutableDictionary<ushort, QuestInfo> _quests;
public QuestData(IDataManager dataManager, ITargetManager targetManager, IChatGui chatGui)
{
_targetManager = targetManager;
_chatGui = chatGui;
_quests = dataManager.GetExcelSheet<Quest>()!
.Where(x => x.RowId > 0)
.Where(x => x.IssuerLocation.Row > 0)
.Select(x => new QuestInfo(x))
.ToImmutableDictionary(x => x.QuestId, x => x);
}
public QuestInfo GetQuestInfo(ushort questId)
{
return _quests[questId] ?? throw new ArgumentOutOfRangeException(nameof(questId));
}
public List<QuestInfo> GetAllByIssuerDataId(uint targetId)
{
return _quests.Values
.Where(x => x.IssuerDataId == targetId)
.ToList();
}
public void ShowQuestsIssuedByTarget()
{
var targetId = _targetManager.Target?.DataId;
if (targetId == null)
{
_chatGui.PrintError("[Questionable] No target selected.");
return;
}
List<QuestInfo> quests = GetAllByIssuerDataId(targetId.Value);
_chatGui.Print($"{quests.Count} quest(s) issued by target {_targetManager.Target?.Name}:");
foreach (QuestInfo quest in quests)
_chatGui.Print($" {quest.QuestId}: {quest.Name}");
}
}

View File

@ -206,7 +206,10 @@ internal sealed unsafe class GameFunctions
return default;
// if we're not at a high enough level to continue, we also ignore it
if (_questRegistry.TryGetQuest(currentQuest, out Quest? quest) && quest.Level > (_clientState.LocalPlayer?.Level ?? 0))
var currentLevel = _clientState.LocalPlayer?.Level ?? 0;
if (currentLevel != 0 &&
_questRegistry.TryGetQuest(currentQuest, out Quest? quest)
&& quest.Info.Level > currentLevel)
return default;
return (currentQuest, QuestManager.GetQuestSequence(currentQuest));
@ -218,6 +221,30 @@ internal sealed unsafe class GameFunctions
return questWork != null ? *questWork : null;
}
public bool IsReadyToAcceptQuest(ushort questId)
{
if (IsQuestAcceptedOrComplete(questId))
return false;
// if we're not at a high enough level to continue, we also ignore it
var currentLevel = _clientState.LocalPlayer?.Level ?? 0;
if (currentLevel != 0 &&
_questRegistry.TryGetQuest(questId, out Quest? quest) &&
quest.Info.Level > currentLevel)
return false;
return true;
}
public bool IsQuestAcceptedOrComplete(ushort questId)
{
if (QuestManager.IsQuestComplete(questId))
return true;
QuestManager* questManager = QuestManager.Instance();
return questManager->IsQuestAccepted(questId);
}
public bool IsAetheryteUnlocked(uint aetheryteId, out byte subIndex)
{
subIndex = 0;
@ -548,6 +575,9 @@ internal sealed unsafe class GameFunctions
public bool IsOccupied()
{
if (!_clientState.IsLoggedIn || _clientState.LocalPlayer == null)
return true;
if (IsLoadingScreenVisible())
return true;

View File

@ -6,10 +6,9 @@ namespace Questionable.Model;
internal sealed class Quest
{
public required ushort QuestId { get; init; }
public required string Name { get; set; }
public ushort Level { get; set; }
public required QuestData Data { get; init; }
public required QuestRoot Root { get; init; }
public required QuestInfo Info { get; init; }
public QuestSequence? FindSequence(byte currentSequence)
=> Data.QuestSequence.SingleOrDefault(seq => seq.Sequence == currentSequence);
=> Root.QuestSequence.SingleOrDefault(seq => seq.Sequence == currentSequence);
}

View File

@ -0,0 +1,19 @@
using ExcelQuest = Lumina.Excel.GeneratedSheets.Quest;
namespace Questionable.Model;
internal sealed class QuestInfo
{
public QuestInfo(ExcelQuest quest)
{
QuestId = (ushort)(quest.RowId & 0xFFFF);
Name = quest.Name.ToString();
Level = quest.ClassJobLevel0;
IssuerDataId = quest.IssuerStart;
}
public ushort QuestId { get; }
public string Name { get; }
public ushort Level { get; }
public uint IssuerDataId { get; }
}

View File

@ -68,6 +68,7 @@ public sealed class QuestionablePlugin : IDalamudPlugin
serviceCollection.AddSingleton<ChatFunctions>();
serviceCollection.AddSingleton<AetherCurrentData>();
serviceCollection.AddSingleton<AetheryteData>();
serviceCollection.AddSingleton<QuestData>();
serviceCollection.AddSingleton<TerritoryData>();
serviceCollection.AddSingleton<NavmeshIpc>();
serviceCollection.AddSingleton<LifestreamIpc>();
@ -110,6 +111,7 @@ public sealed class QuestionablePlugin : IDalamudPlugin
WaitAtEnd.WaitObjectAtPosition>();
serviceCollection.AddTransient<WaitAtEnd.WaitQuestAccepted>();
serviceCollection.AddTransient<WaitAtEnd.WaitQuestCompleted>();
serviceCollection.AddTaskWithFactory<NextQuest.Factory, NextQuest.SetQuest>();
serviceCollection.AddSingleton<MovementController>();
serviceCollection.AddSingleton<QuestRegistry>();
@ -120,11 +122,12 @@ public sealed class QuestionablePlugin : IDalamudPlugin
serviceCollection.AddSingleton<QuestWindow>();
serviceCollection.AddSingleton<ConfigWindow>();
serviceCollection.AddSingleton<DebugOverlay>();
serviceCollection.AddSingleton<CommandHandler>();
serviceCollection.AddSingleton<DalamudInitializer>();
_serviceProvider = serviceCollection.BuildServiceProvider();
_serviceProvider.GetRequiredService<QuestRegistry>().Reload();
_serviceProvider.GetRequiredService<QuestWindow>();
_serviceProvider.GetRequiredService<CommandHandler>();
_serviceProvider.GetRequiredService<DalamudInitializer>();
}

View File

@ -76,7 +76,7 @@ internal sealed class DebugOverlay : Window
if (HighlightedQuest == null || !_questRegistry.TryGetQuest(HighlightedQuest.Value, out var quest))
return;
foreach (var sequence in quest.Data.QuestSequence)
foreach (var sequence in quest.Root.QuestSequence)
{
for (int i = 0; i < sequence.Steps.Count; ++i)
{

View File

@ -41,6 +41,7 @@ internal sealed class QuestWindow : LWindow, IPersistableWindowConfig
private readonly Configuration _configuration;
private readonly NavmeshIpc _navmeshIpc;
private readonly QuestRegistry _questRegistry;
private readonly QuestData _questData;
private readonly TerritoryData _territoryData;
private readonly ILogger<QuestWindow> _logger;
@ -56,6 +57,7 @@ internal sealed class QuestWindow : LWindow, IPersistableWindowConfig
Configuration configuration,
NavmeshIpc navmeshIpc,
QuestRegistry questRegistry,
QuestData questData,
TerritoryData territoryData,
ILogger<QuestWindow> logger)
: base("Questionable###Questionable", ImGuiWindowFlags.AlwaysAutoResize)
@ -72,6 +74,7 @@ internal sealed class QuestWindow : LWindow, IPersistableWindowConfig
_configuration = configuration;
_navmeshIpc = navmeshIpc;
_questRegistry = questRegistry;
_questData = questData;
_territoryData = territoryData;
_logger = logger;
@ -99,7 +102,7 @@ internal sealed class QuestWindow : LWindow, IPersistableWindowConfig
return false;
var currentQuest = _questController.CurrentQuest;
return currentQuest == null || !currentQuest.Quest.Data.TerritoryBlacklist.Contains(_clientState.TerritoryType);
return currentQuest == null || !currentQuest.Quest.Root.TerritoryBlacklist.Contains(_clientState.TerritoryType);
}
public override void Draw()
@ -114,12 +117,12 @@ internal sealed class QuestWindow : LWindow, IPersistableWindowConfig
DrawRemainingTasks();
}
private unsafe void DrawQuest()
private void DrawQuest()
{
var currentQuest = _questController.CurrentQuest;
if (currentQuest != null)
{
ImGui.TextUnformatted($"Quest: {currentQuest.Quest.Name} / {currentQuest.Sequence} / {currentQuest.Step}");
ImGui.TextUnformatted($"Quest: {currentQuest.Quest.Info.Name} / {currentQuest.Sequence} / {currentQuest.Step}");
ImGui.BeginDisabled();
var questWork = _gameFunctions.GetQuestEx(currentQuest.Quest.QuestId);
@ -144,7 +147,12 @@ internal sealed class QuestWindow : LWindow, IPersistableWindowConfig
ImGui.Text($"QW: {vars.Trim()}");
}
else
ImGui.TextUnformatted("(Not accepted)");
{
if (currentQuest.Quest.QuestId == _questController.NextQuest?.Quest.QuestId)
ImGui.TextUnformatted("(Next quest in story line not accepted)");
else
ImGui.TextUnformatted("(Not accepted)");
}
ImGui.TextUnformatted(_questController.DebugState ?? "--");
ImGui.EndDisabled();
@ -158,6 +166,10 @@ internal sealed class QuestWindow : LWindow, IPersistableWindowConfig
ImGui.BeginDisabled(_questController.IsRunning);
if (ImGuiComponents.IconButton(FontAwesomeIcon.Play))
{
// if we haven't accepted this quest, mark it as next quest so that we can optionally use aetherytes to travel
if (questWork == null)
_questController.SetNextQuest(currentQuest.Quest);
_questController.ExecuteNextStep(true);
}
@ -210,84 +222,75 @@ internal sealed class QuestWindow : LWindow, IPersistableWindowConfig
if (_questController.SimulatedQuest != null)
{
var simulatedQuest = _questController.SimulatedQuest;
ImGui.Separator();
ImGui.TextColored(ImGuiColors.DalamudRed, "Quest sim active (experimental)");
ImGui.Text($"Sequence: {_questController.SimulatedQuest.Sequence}");
ImGui.Text($"Sequence: {simulatedQuest.Sequence}");
ImGui.BeginDisabled(_questController.SimulatedQuest.Sequence == 0);
ImGui.BeginDisabled(simulatedQuest.Sequence == 0);
if (ImGuiComponents.IconButton(FontAwesomeIcon.Minus))
{
_movementController.Stop();
_questController.Stop("Sim-");
byte oldSequence = _questController.SimulatedQuest.Sequence;
byte newSequence = _questController.SimulatedQuest.Quest.Data.QuestSequence
byte oldSequence = simulatedQuest.Sequence;
byte newSequence = simulatedQuest.Quest.Root.QuestSequence
.Select(x => (byte)x.Sequence)
.LastOrDefault(x => x < oldSequence, byte.MinValue);
_questController.SimulatedQuest = _questController.SimulatedQuest with
{
Sequence = newSequence,
};
_questController.SimulatedQuest.SetSequence(newSequence);
}
ImGui.EndDisabled();
ImGui.SameLine();
ImGui.BeginDisabled(_questController.SimulatedQuest.Sequence >= 255);
ImGui.BeginDisabled(simulatedQuest.Sequence >= 255);
if (ImGuiComponents.IconButton(FontAwesomeIcon.Plus))
{
_movementController.Stop();
_questController.Stop("Sim+");
byte oldSequence = _questController.SimulatedQuest.Sequence;
byte newSequence = _questController.SimulatedQuest.Quest.Data.QuestSequence
byte oldSequence = simulatedQuest.Sequence;
byte newSequence = simulatedQuest.Quest.Root.QuestSequence
.Select(x => (byte)x.Sequence)
.FirstOrDefault(x => x > oldSequence, byte.MaxValue);
_questController.SimulatedQuest = _questController.SimulatedQuest with
{
Sequence = newSequence,
};
simulatedQuest.SetSequence(newSequence);
}
ImGui.EndDisabled();
var simulatedSequence =
_questController.SimulatedQuest.Quest.FindSequence(_questController.SimulatedQuest.Sequence);
var simulatedSequence = simulatedQuest.Quest.FindSequence(simulatedQuest.Sequence);
if (simulatedSequence != null)
{
using var _ = ImRaii.PushId("SimulatedStep");
ImGui.Text($"Step: {currentQuest.Step} / {simulatedSequence.Steps.Count - 1}");
ImGui.Text($"Step: {simulatedQuest.Step} / {simulatedSequence.Steps.Count - 1}");
ImGui.BeginDisabled(currentQuest.Step == 0);
ImGui.BeginDisabled(simulatedQuest.Step == 0);
if (ImGuiComponents.IconButton(FontAwesomeIcon.Minus))
{
_movementController.Stop();
_questController.Stop("SimStep-");
_questController.CurrentQuest = currentQuest with
{
Step = Math.Min(currentQuest.Step - 1, simulatedSequence.Steps.Count - 1),
};
simulatedQuest.SetStep(Math.Min(simulatedQuest.Step - 1,
simulatedSequence.Steps.Count - 1));
}
ImGui.EndDisabled();
ImGui.SameLine();
ImGui.BeginDisabled(currentQuest.Step >= simulatedSequence.Steps.Count);
ImGui.BeginDisabled(simulatedQuest.Step >= simulatedSequence.Steps.Count);
if (ImGuiComponents.IconButton(FontAwesomeIcon.Plus))
{
_movementController.Stop();
_questController.Stop("SimStep+");
_questController.CurrentQuest = currentQuest with
{
Step = currentQuest.Step == simulatedSequence.Steps.Count - 1
simulatedQuest.SetStep(
simulatedQuest.Step == simulatedSequence.Steps.Count - 1
? 255
: (currentQuest.Step + 1),
};
: (simulatedQuest.Step + 1));
}
ImGui.EndDisabled();
@ -375,7 +378,13 @@ internal sealed class QuestWindow : LWindow, IPersistableWindowConfig
ImGui.EndDisabled();
ImGui.SameLine();
if (ImGui.Button("Interact"))
ImGui.BeginDisabled(gameObject->NamePlateIconId == 0);
if (ImGuiComponents.IconButton(FontAwesomeIcon.Bars))
_questData.ShowQuestsIssuedByTarget();
ImGui.EndDisabled();
ImGui.SameLine();
if (ImGuiComponents.IconButton(FontAwesomeIcon.MousePointer))
{
ulong result = TargetSystem.Instance()->InteractWithObject(
(GameObject*)_targetManager.Target.Address, false);
@ -384,7 +393,7 @@ internal sealed class QuestWindow : LWindow, IPersistableWindowConfig
ImGui.SameLine();
ImGui.Button("Copy");
ImGuiComponents.IconButton(FontAwesomeIcon.Copy);
if (ImGui.IsItemClicked(ImGuiMouseButton.Left))
{
string interactionType = gameObject->NamePlateIconId switch
@ -414,7 +423,7 @@ internal sealed class QuestWindow : LWindow, IPersistableWindowConfig
}
else
{
ImGui.Button($"Copy");
ImGuiComponents.IconButton(FontAwesomeIcon.Copy);
if (ImGui.IsItemClicked(ImGuiMouseButton.Left))
{
ImGui.SetClipboardText($$"""