public void Execute(GeneratorExecutionContext context)
{
- List<(ushort, QuestData)> quests = [];
+ List<(ushort, QuestRoot)> quests = [];
// Find schema definition
AdditionalText jsonSchemaFile =
context.ReportDiagnostic(error);
}
- var quest = questNode.Deserialize<QuestData>()!;
+ var quest = questNode.Deserialize<QuestRoot>()!;
quests.Add((id, quest));
}
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[]
{
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))
))))
})),
.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())));
},
"StopDistance": 7,
"TerritoryId": 962,
- "InteractionType": "AcceptQuest"
+ "InteractionType": "AcceptQuest",
+ "AetheryteShortcut": "Old Sharlayan",
+ "SkipIf": [
+ "AetheryteShortcutIfInSameTerritory"
+ ]
}
]
},
"Z": 201.28174
},
"TerritoryId": 1185,
- "InteractionType": "AcceptQuest"
+ "InteractionType": "AcceptQuest",
+ "AetheryteShortcut": "Tuliyollal",
+ "SkipIf": [
+ "AetheryteShortcutIfInSameTerritory"
+ ]
}
]
},
"Z": 111.436646
},
"TerritoryId": 129,
- "InteractionType": "CompleteQuest"
+ "InteractionType": "CompleteQuest",
+ "NextQuestId": 4825
}
]
}
"Z": 111.436646
},
"TerritoryId": 129,
- "InteractionType": "AcceptQuest"
+ "InteractionType": "AcceptQuest",
+ "AetheryteShortcut": "Limsa Lominsa",
+ "SkipIf": [
+ "AetheryteShortcutIfInSameTerritory"
+ ]
}
]
},
},
"TerritoryId": 129,
"InteractionType": "CompleteQuest",
- "AetheryteShortcut": "Limsa Lominsa"
+ "AetheryteShortcut": "Limsa Lominsa",
+ "NextQuestId": 4826
}
]
}
"Z": 111.436646
},
"TerritoryId": 129,
- "InteractionType": "AcceptQuest"
+ "InteractionType": "AcceptQuest",
+ "AetheryteShortcut": "Limsa Lominsa",
+ "SkipIf": [
+ "AetheryteShortcutIfInSameTerritory"
+ ]
}
]
},
},
"TerritoryId": 129,
"InteractionType": "CompleteQuest",
- "AetheryteShortcut": "Limsa Lominsa"
+ "AetheryteShortcut": "Limsa Lominsa",
+ "NextQuestId": 4827
}
]
}
"Z": 111.436646
},
"TerritoryId": 129,
- "InteractionType": "AcceptQuest"
+ "InteractionType": "AcceptQuest",
+ "AetheryteShortcut": "Limsa Lominsa",
+ "SkipIf": [
+ "AetheryteShortcutIfInSameTerritory"
+ ]
}
]
},
"Z": 111.436646
},
"TerritoryId": 129,
- "InteractionType": "CompleteQuest"
+ "InteractionType": "CompleteQuest",
+ "AetheryteShortcut": "Limsa Lominsa",
+ "NextQuestId": 4828
}
]
}
--- /dev/null
+{
+ "$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
+ }
+ ]
+ }
+ ]
+}
--- /dev/null
+{
+ "$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"
+ ]
+ }
+ ]
+ }
+ ]
+}
"Z": 628.3817
},
"TerritoryId": 957,
- "InteractionType": "CompleteQuest"
+ "InteractionType": "CompleteQuest",
+ "NextQuestId": 4843
}
]
}
"Z": 628.3817
},
"TerritoryId": 957,
- "InteractionType": "CompleteQuest"
+ "InteractionType": "CompleteQuest",
+ "NextQuestId": 4844
}
]
}
"Z": 628.3817
},
"TerritoryId": 957,
- "InteractionType": "CompleteQuest"
+ "InteractionType": "CompleteQuest",
+ "NextQuestId": 4845
}
]
}
"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
}
]
}
--- /dev/null
+{
+ "$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"
+ ]
+ }
+ ]
+ }
+ ]
+}
"Z": -48.05072
},
"TerritoryId": 418,
- "InteractionType": "CompleteQuest"
+ "InteractionType": "CompleteQuest",
+ "NextQuestId": 4819
}
]
}
"Z": -48.05072
},
"TerritoryId": 418,
- "InteractionType": "CompleteQuest"
+ "InteractionType": "CompleteQuest",
+ "NextQuestId": 4820
}
]
}
"AethernetShortcut": [
"[Ishgard] Aetheryte Plaza",
"[Ishgard] The Forgotten Knight"
- ]
+ ],
+ "NextQuestId": 4821
}
]
}
},
"StopDistance": 5,
"TerritoryId": 418,
- "InteractionType": "CompleteQuest"
+ "InteractionType": "CompleteQuest",
+ "NextQuestId": 4822
}
]
}
"Prompt": "TEXT_KINGBA141_04822_Q3_000_000",
"Answer": "TEXT_KINGBA141_04822_A3_000_002"
}
- ]
+ ],
+ "NextQuestId": 4823
}
]
}
--- /dev/null
+{
+ "$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"
+ ]
+ }
+ ]
+ }
+ ]
+}
--- /dev/null
+{
+ "$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"
+ }
+ ]
+ }
+ ]
+}
--- /dev/null
+{
+ "$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"
+ ]
+ }
+ ]
+ }
+ ]
+}
--- /dev/null
+{
+ "$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"
+ ]
+ }
+ ]
+ }
+ ]
+}
--- /dev/null
+{
+ "$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"
+ }
+ ]
+ }
+ ]
+}
--- /dev/null
+{
+ "$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"
+ ]
+ }
+ ]
+ }
+ ]
+}
--- /dev/null
+{
+ "$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"
+ }
+ ]
+ }
+ ]
+}
--- /dev/null
+{
+ "$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"
+ }
+ ]
+ }
+ ]
+}
--- /dev/null
+{
+ "$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"
+ }
+ ]
+ }
+ ]
+}
--- /dev/null
+{
+ "$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"
+ }
+ ]
+ }
+ ]
+}
--- /dev/null
+{
+ "$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"
+ ]
+ }
+ ]
+ }
+ ]
+}
--- /dev/null
+{
+ "$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"
+ }
+ ]
+ }
+ ]
+}
--- /dev/null
+{
+ "$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"
+ }
+ ]
+ }
+ ]
+}
--- /dev/null
+{
+ "$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"
+ }
+ ]
+ }
+ ]
+}
--- /dev/null
+{
+ "$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"
+ }
+ ]
+ }
+ ]
+}
--- /dev/null
+{
+ "$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"
+ ]
+ }
+ ]
+ }
+ ]
+}
--- /dev/null
+{
+ "$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"
+ }
+ ]
+ }
+ ]
+}
--- /dev/null
+{
+ "$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"
+ ]
+ }
+ ]
+ }
+ ]
+}
--- /dev/null
+{
+ "$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"
+ ]
+ }
+ ]
+ }
+ ]
+}
--- /dev/null
+{
+ "$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"
+ ]
+ }
+ ]
+ }
+ ]
+}
--- /dev/null
+{
+ "$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"
+ ]
+ }
+ ]
+ }
+ ]
+}
--- /dev/null
+{
+ "$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"
+ ]
+ }
+ ]
+ }
+ ]
+}
--- /dev/null
+{
+ "$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
+ }
+ ]
+ }
+ ]
+}
--- /dev/null
+{
+ "$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
+ }
+ ]
+ }
+ ]
+ }
+ ]
+}
--- /dev/null
+{
+ "$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"
+ }
+ ]
+ }
+ ]
+}
"cheer",
"happy",
"poke",
- "flex"
+ "flex",
+ "soothe"
]
}
}
},
"then": {
"properties": {
- "QuestId": {
+ "PickUpQuestId": {
"type": [
"null",
"number"
}
}
}
+ },
+ {
+ "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."
+ }
+ }
+ }
}
]
}
{ EEmote.Happy, "happy" },
{ EEmote.Poke, "poke" },
{ EEmote.Flex, "flex" },
+ { EEmote.Soothe, "soothe" },
};
}
Happy = 48,
Poke = 28,
Flex = 139,
+ Soothe = 35,
}
+++ /dev/null
-using System.Collections.Generic;
-
-namespace Questionable.Model.V1;
-
-public sealed class QuestData
-{
- public string Author { get; set; } = null!;
- public List<string> Contributors { get; set; } = new();
- public string? Comment { get; set; }
- public List<ushort> TerritoryBlacklist { get; set; } = new();
- public List<QuestSequence> QuestSequence { get; set; } = new();
-}
--- /dev/null
+using System.Collections.Generic;
+
+namespace Questionable.Model.V1;
+
+public sealed class QuestRoot
+{
+ public string Author { get; set; } = null!;
+ public List<string> Contributors { get; set; } = new();
+ public string? Comment { get; set; }
+ public List<ushort> TerritoryBlacklist { get; set; } = new();
+ public List<QuestSequence> QuestSequence { get; set; } = new();
+}
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()
--- /dev/null
+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");
+ }
+}
using System;
using System.Collections.Generic;
-using System.Globalization;
using System.Linq;
using System.Text.RegularExpressions;
using Dalamud.Game.Addon.Lifecycle;
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;
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;
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);
private int? HandleListChoice(string? actualPrompt, List<string?> answers, bool checkAllSteps)
{
+ List<DialogueChoiceInfo> dialogueChoices = [];
var currentQuest = _questController.CurrentQuest;
- if (currentQuest == null)
- {
- _logger.LogInformation("Ignoring list choice, no active quest");
- return null;
- }
-
- var quest = currentQuest.Quest;
- IList<DialogueChoice> dialogueChoices;
- if (checkAllSteps)
+ if (currentQuest != null)
{
- 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
+ _logger.LogInformation("Ignoring current quest dialogue choices, no active quest");
+
+ // add all quests that start with the targeted npc
+ var target = _targetManager.Target;
+ if (target != null)
{
- var step = quest.FindSequence(currentQuest.Sequence)?.FindStep(currentQuest.Step);
- if (step == null)
+ foreach (var questInfo in _questData.GetAllByIssuerDataId(target.DataId))
{
- _logger.LogInformation("Ignoring list choice, no active step");
- return null;
+ 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)));
+ }
+ }
}
-
- dialogueChoices = step.DialogueChoices;
}
- foreach (var dialogueChoice in dialogueChoices)
+ if (dialogueChoices.Count == 0)
+ return null;
+
+ foreach (var (quest, dialogueChoice) in dialogueChoices)
{
if (dialogueChoice.Type != EDialogChoiceType.List)
continue;
};
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)
_addonLifecycle.UnregisterListener(AddonEvent.PostSetup, "CutSceneSelectString", CutsceneSelectStringPostSetup);
_addonLifecycle.UnregisterListener(AddonEvent.PostSetup, "SelectString", SelectStringPostSetup);
}
+
+ private sealed record DialogueChoiceInfo(Quest Quest, DialogueChoice DialogueChoice);
}
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;
_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; }
{
lock (_lock)
{
- CurrentQuest = null;
+ _startedQuest = null;
+ _nextQuest = null;
+ _simulatedQuest = null;
+
DebugState = null;
_questRegistry.Reload();
}
}
- 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
lock (_lock)
{
_logger.LogWarning("Quest accept apparently didn't work out, resetting progress");
- CurrentQuest = CurrentQuest with
- {
- Step = 0
- };
+ CurrentQuest.SetStep(0);
}
ExecuteNextStep(true);
{
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))
+ {
+ _nextQuest = null;
+ currentSequence = 0;
+ }
+ else
{
- _logger.LogInformation("No current quest, resetting data");
- CurrentQuest = null;
- Stop("Resetting current quest");
+ 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);
+ if (_startedQuest != null)
+ {
+ _logger.LogInformation("No current quest, resetting data");
+ _startedQuest = null;
+ Stop("Resetting current quest");
+ }
+ }
+ else if (_startedQuest == null || _startedQuest.Quest.QuestId != currentQuestId)
+ {
+ if (_questRegistry.TryGetQuest(currentQuestId, out var quest))
+ {
+ _logger.LogInformation("New quest: {QuestName}", quest.Info.Name);
+ _startedQuest = new QuestProgress(quest, currentSequence);
- bool continueAutomatically = _configuration.General.AutoAcceptNextQuest;
+ bool continueAutomatically = _configuration.General.AutoAcceptNextQuest;
- if (_clientState.LocalPlayer?.Level < quest.Level)
- continueAutomatically = false;
+ if (_clientState.LocalPlayer?.Level < quest.Info.Level)
+ continueAutomatically = false;
- Stop("Different Quest", continueAutomatically);
- }
- else if (CurrentQuest != null)
- {
- _logger.LogInformation("No active quest anymore? Not sure what happened...");
- CurrentQuest = null;
- Stop("No active Quest");
- }
+ 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;
+ return;
+ }
}
- if (CurrentQuest == null)
+ var questToRun = CurrentQuest;
+ if (questToRun == null)
{
DebugState = "No quest active";
Comment = null;
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";
return;
}
- if (CurrentQuest.Step == 255)
+ if (questToRun.Step == 255)
{
DebugState = "Step completed";
Comment = null;
return;
}
- if (CurrentQuest.Step >= sequence.Steps.Count)
+ if (questToRun.Step >= sequence.Steps.Count)
{
DebugState = "Step not found";
Comment = null;
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;
}
}
_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)
_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 QuestProgress(quest);
+ else
+ _simulatedQuest = null;
+ }
+
+ public void SetNextQuest(Quest? quest)
+ {
+ _logger.LogInformation("NextQuest: {QuestId}", quest?.QuestId);
if (quest != null)
- SimulatedQuest = new SimulationProgress(quest, 0);
+ _nextQuest = new QuestProgress(quest);
else
- SimulatedQuest = null;
+ _nextQuest = null;
}
private void UpdateCurrentTask()
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 sealed record SimulationProgress(Quest Quest, byte 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 void Skip(ushort questQuestId, byte currentQuestSequence)
{
using Dalamud.Plugin;
using Dalamud.Plugin.Services;
using Microsoft.Extensions.Logging;
+using Questionable.Data;
using Questionable.Model;
using Questionable.Model.V1;
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;
}
_quests[questId] = quest;
}
#else
- DirectoryInfo? solutionDirectory = _pluginInterface.AssemblyLocation?.Directory?.Parent?.Parent;
+ DirectoryInfo? solutionDirectory = _pluginInterface.AssemblyLocation.Directory?.Parent?.Parent;
if (solutionDirectory != null)
{
DirectoryInfo pathProjectDirectory =
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);
}
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;
}
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);
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>()
];
--- /dev/null
+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;
+ }
+}
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;
{
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);
_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));
}
}
}
- 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;
--- /dev/null
+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}");
+ }
+}
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));
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;
public bool IsOccupied()
{
+ if (!_clientState.IsLoggedIn || _clientState.LocalPlayer == null)
+ return true;
+
if (IsLoadingScreenVisible())
return true;
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);
}
--- /dev/null
+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; }
+}
serviceCollection.AddSingleton<ChatFunctions>();
serviceCollection.AddSingleton<AetherCurrentData>();
serviceCollection.AddSingleton<AetheryteData>();
+ serviceCollection.AddSingleton<QuestData>();
serviceCollection.AddSingleton<TerritoryData>();
serviceCollection.AddSingleton<NavmeshIpc>();
serviceCollection.AddSingleton<LifestreamIpc>();
WaitAtEnd.WaitObjectAtPosition>();
serviceCollection.AddTransient<WaitAtEnd.WaitQuestAccepted>();
serviceCollection.AddTransient<WaitAtEnd.WaitQuestCompleted>();
+ serviceCollection.AddTaskWithFactory<NextQuest.Factory, NextQuest.SetQuest>();
serviceCollection.AddSingleton<MovementController>();
serviceCollection.AddSingleton<QuestRegistry>();
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>();
}
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)
{
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;
Configuration configuration,
NavmeshIpc navmeshIpc,
QuestRegistry questRegistry,
+ QuestData questData,
TerritoryData territoryData,
ILogger<QuestWindow> logger)
: base("Questionable###Questionable", ImGuiWindowFlags.AlwaysAutoResize)
_configuration = configuration;
_navmeshIpc = navmeshIpc;
_questRegistry = questRegistry;
+ _questData = questData;
_territoryData = territoryData;
_logger = logger;
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()
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);
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();
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);
}
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();
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);
ImGui.SameLine();
- ImGui.Button("Copy");
+ ImGuiComponents.IconButton(FontAwesomeIcon.Copy);
if (ImGui.IsItemClicked(ImGuiMouseButton.Left))
{
string interactionType = gameObject->NamePlateIconId switch
}
else
{
- ImGui.Button($"Copy");
+ ImGuiComponents.IconButton(FontAwesomeIcon.Copy);
if (ImGui.IsItemClicked(ImGuiMouseButton.Left))
{
ImGui.SetClipboardText($$"""