From a45cfda2e649c1c585f2fc2df6ed8405a9e9c222 Mon Sep 17 00:00:00 2001 From: Liza Carvelli Date: Mon, 3 Jun 2024 23:17:35 +0200 Subject: [PATCH] Handle configured dialogue prompts; hide UI in blacklisted territories; path updates Automatically handles: - SelectString - CutSceneSelectString - SelectYesno - Credit - Closing Unending Codex during 'Newfound Adventure' --- .../Thavnair/4203_Alchemist or Dancer.json | 36 ++- .../4370_A Fishermans Friend.json | 24 +- .../MSQ/J-6.3/4674_King of the Mountain.json | 3 + .../MSQ/J-6.3/4677_Desires Untold.json | 3 + .../Endwalker/MSQ/K-6.4/4736_Going Haam.json | 9 +- .../MSQ/K-6.4/4737_Like Fear to Flame.json | 13 +- .../MSQ/K-6.4/4738_The Fallen Empire.json | 4 +- .../MSQ/K-6.4/4739_Bonds of Trust.json | 1 + .../MSQ/K-6.4/4740_Lunar Rendezvous.json | 28 +- .../K-6.4/4741_The Red Side of the Moon.json | 3 +- .../MSQ/K-6.4/4742_Abyssal Dark.json | 3 + .../MSQ/K-6.4/4743_The Dark Throne.json | 25 +- .../MSQ/L-6.5/4744_Seeking the Light.json | 2 +- .../MSQ/L-6.5/4748_Down in the Dark.json | 13 +- .../MSQ/L-6.5/4749_Reunited at Last.json | 5 +- .../MSQ/L-6.5/4750_Growing Light.json | 36 ++- .../MSQ/M-6.55/4751_When One Door Closes.json | 11 +- .../MSQ/M-6.55/4752_The Game Is Afoot.json | 5 + .../MSQ/M-6.55/4753_The Coming Dawn.json | 49 +++- .../MSQ/F-Tempest/3654_Shadowbringers.json | 4 + .../MSQ/G-5.1/3673_Shaken Resolve.json | 12 +- .../MSQ/G-5.1/3674_A Grand Adventure.json | 1 + QuestPaths/TODO Quest YesNo.txt | 13 + QuestPaths/quest-v1.json | 61 ++++- Questionable/Controller/GameUiController.cs | 240 ++++++++++++++++++ Questionable/Controller/QuestController.cs | 75 +++--- Questionable/GameFunctions.cs | 16 +- .../Converter/DialogueChoiceTypeConverter.cs | 12 + .../V1/Converter/InteractionTypeConverter.cs | 1 - Questionable/Model/V1/DialogueChoice.cs | 13 +- Questionable/Model/V1/EDialogChoiceType.cs | 8 + Questionable/Model/V1/EInteractionType.cs | 1 - Questionable/Model/V1/QuestSequence.cs | 8 + Questionable/Questionable.csproj | 2 +- Questionable/QuestionablePlugin.cs | 8 +- Questionable/Windows/DebugWindow.cs | 12 +- 36 files changed, 652 insertions(+), 108 deletions(-) create mode 100644 QuestPaths/TODO Quest YesNo.txt create mode 100644 Questionable/Controller/GameUiController.cs create mode 100644 Questionable/Model/V1/Converter/DialogueChoiceTypeConverter.cs create mode 100644 Questionable/Model/V1/EDialogChoiceType.cs diff --git a/QuestPaths/Endwalker/AetherCurrents/Thavnair/4203_Alchemist or Dancer.json b/QuestPaths/Endwalker/AetherCurrents/Thavnair/4203_Alchemist or Dancer.json index 8615adf1..17fc0350 100644 --- a/QuestPaths/Endwalker/AetherCurrents/Thavnair/4203_Alchemist or Dancer.json +++ b/QuestPaths/Endwalker/AetherCurrents/Thavnair/4203_Alchemist or Dancer.json @@ -44,6 +44,14 @@ }, "TerritoryId": 957, "InteractionType": "Interact", + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 128 + ], "$": "QuestVariables after: 16 1 0 0 0 128" }, { @@ -53,12 +61,28 @@ "Z": -159.90234 }, "TerritoryId": 957, - "InteractionType": "WalkTo" + "InteractionType": "WalkTo", + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 32 + ] }, { "DataId": 2011914, "TerritoryId": 957, "InteractionType": "Interact", + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 32 + ], "$": "QuestVariables after: 32 17 0 0 0 160" }, { @@ -69,7 +93,15 @@ "Z": -157.09167 }, "TerritoryId": 957, - "InteractionType": "Interact" + "InteractionType": "Interact", + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 64 + ] } ] }, diff --git a/QuestPaths/Endwalker/MSQ/A-Thavnair1-Labyrinthos1/4370_A Fishermans Friend.json b/QuestPaths/Endwalker/MSQ/A-Thavnair1-Labyrinthos1/4370_A Fishermans Friend.json index 357f41b7..4f29e2b6 100644 --- a/QuestPaths/Endwalker/MSQ/A-Thavnair1-Labyrinthos1/4370_A Fishermans Friend.json +++ b/QuestPaths/Endwalker/MSQ/A-Thavnair1-Labyrinthos1/4370_A Fishermans Friend.json @@ -43,15 +43,21 @@ "Z": 799.2217 }, "TerritoryId": 957, - "InteractionType": "CutsceneSelectString", + "InteractionType": "Interact", "DialogueChoices": [ { + "Type": "List", + "Prompt": "TEXT_AKTKMA114_04370_Q2_000_086", "Answer": "TEXT_AKTKMA114_04370_A2_000_088" }, { + "Type": "List", + "Prompt": "TEXT_AKTKMA114_04370_Q3_000_096", "Answer": "TEXT_AKTKMA114_04370_A3_000_098" }, { + "Type": "List", + "Prompt": "TEXT_AKTKMA114_04370_Q5_000_106", "Answer": "TEXT_AKTKMA114_04370_A5_000_107" } ] @@ -69,15 +75,21 @@ "Z": 681.7273 }, "TerritoryId": 957, - "InteractionType": "CutsceneSelectString", + "InteractionType": "Interact", "DialogueChoices": [ { + "Type": "List", + "Prompt": "TEXT_AKTKMA114_04370_Q6_000_147", "Answer": "TEXT_AKTKMA114_04370_A6_000_149" }, { + "Type": "List", + "Prompt": "TEXT_AKTKMA114_04370_Q7_000_157", "Answer": "TEXT_AKTKMA114_04370_A7_000_158" }, { + "Type": "List", + "Prompt": "TEXT_AKTKMA114_04370_Q8_000_162", "Answer": "TEXT_AKTKMA114_04370_A8_000_164" } ] @@ -95,15 +107,21 @@ "Z": 517.72327 }, "TerritoryId": 957, - "InteractionType": "CutsceneSelectString", + "InteractionType": "Interact", "DialogueChoices": [ { + "Type": "List", + "Prompt": "TEXT_AKTKMA114_04370_Q9_000_198", "Answer": "TEXT_AKTKMA114_04370_A9_000_200" }, { + "Type": "List", + "Prompt": "TEXT_AKTKMA114_04370_Q10_000_207", "Answer": "TEXT_AKTKMA114_04370_A10_000_209" }, { + "Type": "List", + "Prompt": "TEXT_AKTKMA114_04370_Q11_000_216", "Answer": "TEXT_AKTKMA114_04370_A11_000_218" } ] diff --git a/QuestPaths/Endwalker/MSQ/J-6.3/4674_King of the Mountain.json b/QuestPaths/Endwalker/MSQ/J-6.3/4674_King of the Mountain.json index 6f0cf2d8..dee5098f 100644 --- a/QuestPaths/Endwalker/MSQ/J-6.3/4674_King of the Mountain.json +++ b/QuestPaths/Endwalker/MSQ/J-6.3/4674_King of the Mountain.json @@ -1,6 +1,9 @@ { "$schema": "https://carvel.li/questionable/quest-1.0", "Author": "liza", + "TerritoryBlacklist": [ + 1097 + ], "QuestSequence": [ { "Sequence": 0, diff --git a/QuestPaths/Endwalker/MSQ/J-6.3/4677_Desires Untold.json b/QuestPaths/Endwalker/MSQ/J-6.3/4677_Desires Untold.json index 4d7218e3..ce4256b1 100644 --- a/QuestPaths/Endwalker/MSQ/J-6.3/4677_Desires Untold.json +++ b/QuestPaths/Endwalker/MSQ/J-6.3/4677_Desires Untold.json @@ -1,6 +1,9 @@ { "$schema": "https://carvel.li/questionable/quest-1.0", "Author": "liza", + "TerritoryBlacklist": [ + 1095 + ], "QuestSequence": [ { "Sequence": 0, diff --git a/QuestPaths/Endwalker/MSQ/K-6.4/4736_Going Haam.json b/QuestPaths/Endwalker/MSQ/K-6.4/4736_Going Haam.json index a4a44a7e..d2815fbf 100644 --- a/QuestPaths/Endwalker/MSQ/K-6.4/4736_Going Haam.json +++ b/QuestPaths/Endwalker/MSQ/K-6.4/4736_Going Haam.json @@ -82,7 +82,14 @@ }, "StopDistance": 5, "TerritoryId": 962, - "InteractionType": "Interact" + "InteractionType": "Interact", + "DialogueChoices": [ + { + "Type": "YesNo", + "Prompt": "TEXT_AKTKMK102_04736_Q2_000_094", + "Yes": true + } + ] } ] }, diff --git a/QuestPaths/Endwalker/MSQ/K-6.4/4737_Like Fear to Flame.json b/QuestPaths/Endwalker/MSQ/K-6.4/4737_Like Fear to Flame.json index 0360fbc7..b4972cf5 100644 --- a/QuestPaths/Endwalker/MSQ/K-6.4/4737_Like Fear to Flame.json +++ b/QuestPaths/Endwalker/MSQ/K-6.4/4737_Like Fear to Flame.json @@ -135,7 +135,6 @@ }, "TerritoryId": 958, "InteractionType": "Interact", - "Comment": "TODO Check flags", "CompletionQuestVariablesFlags": [ null, null, @@ -150,6 +149,18 @@ { "Sequence": 255, "Steps": [ + { + "Position": { + "X": 534.8861, + "Y": -36.65, + "Z": -245.12135 + }, + "TerritoryId": 958, + "InteractionType": "WalkTo", + "SkipIf": [ + "FlyingLocked" + ] + }, { "DataId": 1045430, "Position": { diff --git a/QuestPaths/Endwalker/MSQ/K-6.4/4738_The Fallen Empire.json b/QuestPaths/Endwalker/MSQ/K-6.4/4738_The Fallen Empire.json index 81e38a8a..79fc769b 100644 --- a/QuestPaths/Endwalker/MSQ/K-6.4/4738_The Fallen Empire.json +++ b/QuestPaths/Endwalker/MSQ/K-6.4/4738_The Fallen Empire.json @@ -30,7 +30,8 @@ }, "TerritoryId": 958, "InteractionType": "Interact", - "Fly": true + "Fly": true, + "TargetTerritoryId": 1160 } ] }, @@ -61,7 +62,6 @@ }, "TerritoryId": 1160, "InteractionType": "Interact", - "Comment": "TODO Check Flags", "CompletionQuestVariablesFlags": [ null, null, diff --git a/QuestPaths/Endwalker/MSQ/K-6.4/4739_Bonds of Trust.json b/QuestPaths/Endwalker/MSQ/K-6.4/4739_Bonds of Trust.json index bb8fb52f..c6d94c9b 100644 --- a/QuestPaths/Endwalker/MSQ/K-6.4/4739_Bonds of Trust.json +++ b/QuestPaths/Endwalker/MSQ/K-6.4/4739_Bonds of Trust.json @@ -64,6 +64,7 @@ "Y": 10.8, "Z": -231.61676 }, + "StopDistance": 5, "TerritoryId": 958, "InteractionType": "Interact" } diff --git a/QuestPaths/Endwalker/MSQ/K-6.4/4740_Lunar Rendezvous.json b/QuestPaths/Endwalker/MSQ/K-6.4/4740_Lunar Rendezvous.json index 35d89bc3..347b99f3 100644 --- a/QuestPaths/Endwalker/MSQ/K-6.4/4740_Lunar Rendezvous.json +++ b/QuestPaths/Endwalker/MSQ/K-6.4/4740_Lunar Rendezvous.json @@ -64,8 +64,23 @@ "TerritoryId": 959, "InteractionType": "Interact", "AetheryteShortcut": "Mare Lamentorum - Bestways Burrow", - "SkipIf": ["FlyingUnlocked"], - "Comment": "Check if the flying unlocked check is good enough" + "SkipIf": [ + "FlyingUnlocked" + ] + }, + { + "Position": { + "X": -19.779482, + "Y": -56.63768, + "Z": -464.9354 + }, + "StopDistance": 1, + "TerritoryId": 959, + "InteractionType": "WalkTo", + "SkipIf": [ + "FlyingLocked" + ], + "Fly": true }, { "DataId": 1039686, @@ -91,7 +106,8 @@ "Z": -620.3861 }, "TerritoryId": 959, - "InteractionType": "Interact" + "InteractionType": "Interact", + "Fly": true } ] }, @@ -156,8 +172,7 @@ null, null, 32 - ], - "Comment": "TODO Check Flags" + ] }, { "DataId": 1045473, @@ -179,7 +194,8 @@ 16 ] } - ] + ], + "Comment": "TODO Check Flags (32)" }, { "Sequence": 255, diff --git a/QuestPaths/Endwalker/MSQ/K-6.4/4741_The Red Side of the Moon.json b/QuestPaths/Endwalker/MSQ/K-6.4/4741_The Red Side of the Moon.json index f9feb9c3..d1d08aa6 100644 --- a/QuestPaths/Endwalker/MSQ/K-6.4/4741_The Red Side of the Moon.json +++ b/QuestPaths/Endwalker/MSQ/K-6.4/4741_The Red Side of the Moon.json @@ -53,8 +53,7 @@ null, null, 128 - ], - "Comment": "TODO Check Flags" + ] }, { "DataId": 2013355, diff --git a/QuestPaths/Endwalker/MSQ/K-6.4/4742_Abyssal Dark.json b/QuestPaths/Endwalker/MSQ/K-6.4/4742_Abyssal Dark.json index 524a09c2..5076d2ef 100644 --- a/QuestPaths/Endwalker/MSQ/K-6.4/4742_Abyssal Dark.json +++ b/QuestPaths/Endwalker/MSQ/K-6.4/4742_Abyssal Dark.json @@ -1,6 +1,9 @@ { "$schema": "https://carvel.li/questionable/quest-1.0", "Author": "liza", + "TerritoryBlacklist": [ + 1140 + ], "QuestSequence": [ { "Sequence": 0, diff --git a/QuestPaths/Endwalker/MSQ/K-6.4/4743_The Dark Throne.json b/QuestPaths/Endwalker/MSQ/K-6.4/4743_The Dark Throne.json index 4817a889..ae894378 100644 --- a/QuestPaths/Endwalker/MSQ/K-6.4/4743_The Dark Throne.json +++ b/QuestPaths/Endwalker/MSQ/K-6.4/4743_The Dark Throne.json @@ -31,7 +31,23 @@ "TerritoryId": 959, "InteractionType": "Interact", "AetheryteShortcut": "Mare Lamentorum - Bestways Burrow", - "SkipIf": ["FlyingUnlocked"] + "SkipIf": [ + "FlyingUnlocked" + ] + }, + { + "Position": { + "X": -19.779482, + "Y": -56.63768, + "Z": -464.9354 + }, + "StopDistance": 1, + "TerritoryId": 959, + "InteractionType": "WalkTo", + "SkipIf": [ + "FlyingLocked" + ], + "Fly": true }, { "DataId": 1045466, @@ -62,6 +78,13 @@ "AethernetShortcut": [ "[Radz-at-Han] Aetheryte Plaza", "[Radz-at-Han] Meghaduta" + ], + "DialogueChoices": [ + { + "Type": "YesNo", + "Prompt": "TEXT_AKTKMK109_04743_Q1_000_000", + "Yes": true + } ] } ] diff --git a/QuestPaths/Endwalker/MSQ/L-6.5/4744_Seeking the Light.json b/QuestPaths/Endwalker/MSQ/L-6.5/4744_Seeking the Light.json index 87f9eda5..6403e2cd 100644 --- a/QuestPaths/Endwalker/MSQ/L-6.5/4744_Seeking the Light.json +++ b/QuestPaths/Endwalker/MSQ/L-6.5/4744_Seeking the Light.json @@ -27,7 +27,7 @@ "Y": 55, "Z": -68.61987 }, - "StopDistance": 5, + "StopDistance": 7, "TerritoryId": 963, "InteractionType": "Interact" } diff --git a/QuestPaths/Endwalker/MSQ/L-6.5/4748_Down in the Dark.json b/QuestPaths/Endwalker/MSQ/L-6.5/4748_Down in the Dark.json index 206d1297..1684a79d 100644 --- a/QuestPaths/Endwalker/MSQ/L-6.5/4748_Down in the Dark.json +++ b/QuestPaths/Endwalker/MSQ/L-6.5/4748_Down in the Dark.json @@ -1,6 +1,10 @@ { "$schema": "https://carvel.li/questionable/quest-1.0", "Author": "liza", + "TerritoryBlacklist": [ + 1164, + 1168 + ], "QuestSequence": [ { "Sequence": 0, @@ -39,7 +43,14 @@ "Z": -440.63483 }, "TerritoryId": 1184, - "InteractionType": "Interact" + "InteractionType": "Interact", + "DialogueChoices": [ + { + "Type": "YesNo", + "Prompt": "TEXT_AKTKML105_04748_SYSTEM_000_406", + "Yes": true + } + ] } ] }, diff --git a/QuestPaths/Endwalker/MSQ/L-6.5/4749_Reunited at Last.json b/QuestPaths/Endwalker/MSQ/L-6.5/4749_Reunited at Last.json index 2e891614..82c54ad7 100644 --- a/QuestPaths/Endwalker/MSQ/L-6.5/4749_Reunited at Last.json +++ b/QuestPaths/Endwalker/MSQ/L-6.5/4749_Reunited at Last.json @@ -12,6 +12,7 @@ "Y": 56.66061, "Z": 467.39905 }, + "StopDistance": 15, "TerritoryId": 1162, "InteractionType": "Interact" } @@ -43,7 +44,8 @@ "Z": -191.51605 }, "TerritoryId": 958, - "InteractionType": "Interact" + "InteractionType": "Interact", + "AetheryteShortcut": "Garlemald - Tertium" } ] }, @@ -59,6 +61,7 @@ }, "TerritoryId": 962, "InteractionType": "Interact", + "AetheryteShortcut": "Old Sharlayan", "AethernetShortcut": [ "[Old Sharlayan] Aetheryte Plaza", "[Old Sharlayan] The Rostra" diff --git a/QuestPaths/Endwalker/MSQ/L-6.5/4750_Growing Light.json b/QuestPaths/Endwalker/MSQ/L-6.5/4750_Growing Light.json index 2ca6af02..d68a56d1 100644 --- a/QuestPaths/Endwalker/MSQ/L-6.5/4750_Growing Light.json +++ b/QuestPaths/Endwalker/MSQ/L-6.5/4750_Growing Light.json @@ -12,6 +12,7 @@ "Y": 41.530136, "Z": -165.27051 }, + "StopDistance": 7, "TerritoryId": 962, "InteractionType": "Interact" } @@ -29,9 +30,17 @@ }, "TerritoryId": 819, "InteractionType": "Interact", + "AetheryteShortcut": "Crystarium", "AethernetShortcut": [ "[Crystarium] Aetheryte Plaza", "[Crystarium] The Dossal Gate" + ], + "DialogueChoices": [ + { + "Type": "YesNo", + "Prompt": "TEXT_AKTKML107_04750_SYSTEM_000_101", + "Yes": true + } ] } ] @@ -51,6 +60,22 @@ } ] }, + { + "Sequence": 3, + "Steps": [ + { + "DataId": 1045684, + "Position": { + "X": -0.96136475, + "Y": 0, + "Z": -3.3417358 + }, + "StopDistance": 5, + "TerritoryId": 844, + "InteractionType": "Interact" + } + ] + }, { "Sequence": 4, "Steps": [ @@ -63,6 +88,7 @@ }, "TerritoryId": 963, "InteractionType": "Interact", + "AetheryteShortcut": "Radz-at-Han", "AethernetShortcut": [ "[Radz-at-Han] Aetheryte Plaza", "[Radz-at-Han] Meghaduta" @@ -89,17 +115,17 @@ "Sequence": 255, "Steps": [ { - "DataId": 196, + "DataId": 1039645, "Position": { - "X": -42.61847, - "Y": -0.015319824, - "Z": -197.61963 + "X": -338.33832, + "Y": 55, + "Z": -68.40625 }, "TerritoryId": 963, "InteractionType": "Interact", "AethernetShortcut": [ "[Radz-at-Han] Mehryde's Meyhane", - "[Radz-at-Han] Aetheryte Plaza" + "[Radz-at-Han] Meghaduta" ] } ] diff --git a/QuestPaths/Endwalker/MSQ/M-6.55/4751_When One Door Closes.json b/QuestPaths/Endwalker/MSQ/M-6.55/4751_When One Door Closes.json index 93d122de..8a666924 100644 --- a/QuestPaths/Endwalker/MSQ/M-6.55/4751_When One Door Closes.json +++ b/QuestPaths/Endwalker/MSQ/M-6.55/4751_When One Door Closes.json @@ -13,7 +13,14 @@ "Z": -68.40625 }, "TerritoryId": 963, - "InteractionType": "Interact" + "InteractionType": "Interact", + "DialogueChoices": [ + { + "Type": "List", + "Prompt": "TEXT_AKTKMM103_04753_Q1_000_000", + "Answer": "TEXT_AKTKMM103_04753_A1_000_001" + } + ] } ] }, @@ -27,8 +34,10 @@ "Y": 4.357494, "Z": 0.7476196 }, + "StopDistance": 7, "TerritoryId": 962, "InteractionType": "Interact", + "AetheryteShortcut": "Old Sharlayan", "AethernetShortcut": [ "[Old Sharlayan] Aetheryte Plaza", "[Old Sharlayan] The Baldesion Annex" diff --git a/QuestPaths/Endwalker/MSQ/M-6.55/4752_The Game Is Afoot.json b/QuestPaths/Endwalker/MSQ/M-6.55/4752_The Game Is Afoot.json index 0e40c9db..3268c428 100644 --- a/QuestPaths/Endwalker/MSQ/M-6.55/4752_The Game Is Afoot.json +++ b/QuestPaths/Endwalker/MSQ/M-6.55/4752_The Game Is Afoot.json @@ -1,6 +1,9 @@ { "$schema": "https://carvel.li/questionable/quest-1.0", "Author": "liza", + "TerritoryBlacklist": [ + 1177 + ], "QuestSequence": [ { "Sequence": 0, @@ -62,6 +65,7 @@ "Y": -14.169313, "Z": 105.30249 }, + "StopDistance": 7, "TerritoryId": 962, "InteractionType": "Interact" } @@ -77,6 +81,7 @@ "Y": -15.127002, "Z": 139.42163 }, + "StopDistance": 5, "TerritoryId": 962, "InteractionType": "Interact" } diff --git a/QuestPaths/Endwalker/MSQ/M-6.55/4753_The Coming Dawn.json b/QuestPaths/Endwalker/MSQ/M-6.55/4753_The Coming Dawn.json index 3747b3b3..5d1dec8b 100644 --- a/QuestPaths/Endwalker/MSQ/M-6.55/4753_The Coming Dawn.json +++ b/QuestPaths/Endwalker/MSQ/M-6.55/4753_The Coming Dawn.json @@ -12,6 +12,7 @@ "Y": -15.127001, "Z": 139.45215 }, + "StopDistance": 5, "TerritoryId": 962, "InteractionType": "Interact" } @@ -32,6 +33,14 @@ "AethernetShortcut": [ "[Old Sharlayan] Scholar's Harbor", "[Old Sharlayan] The Studium" + ], + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 16 ] }, { @@ -42,7 +51,15 @@ "Z": 103.28821 }, "TerritoryId": 962, - "InteractionType": "Interact" + "InteractionType": "Interact", + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 32 + ] }, { "DataId": 2013417, @@ -52,7 +69,15 @@ "Z": 59.00659 }, "TerritoryId": 962, - "InteractionType": "Interact" + "InteractionType": "Interact", + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 64 + ] }, { "DataId": 2013416, @@ -62,7 +87,15 @@ "Z": 20.523315 }, "TerritoryId": 962, - "InteractionType": "Interact" + "InteractionType": "Interact", + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 128 + ] } ] }, @@ -111,7 +144,14 @@ "Z": 0.7476196 }, "TerritoryId": 962, - "InteractionType": "Interact" + "InteractionType": "Interact", + "DialogueChoices": [ + { + "Type": "YesNo", + "Prompt": "TEXT_AKTKMM103_04753_SYSTEM_000_302", + "Yes": true + } + ] } ] }, @@ -151,6 +191,7 @@ "Y": 4.357494, "Z": 0.7476196 }, + "StopDistance": 5, "TerritoryId": 962, "InteractionType": "Interact" } diff --git a/QuestPaths/Shadowbringers/MSQ/F-Tempest/3654_Shadowbringers.json b/QuestPaths/Shadowbringers/MSQ/F-Tempest/3654_Shadowbringers.json index 23b3f745..2d5d4197 100644 --- a/QuestPaths/Shadowbringers/MSQ/F-Tempest/3654_Shadowbringers.json +++ b/QuestPaths/Shadowbringers/MSQ/F-Tempest/3654_Shadowbringers.json @@ -2,6 +2,10 @@ "$schema": "https://carvel.li/questionable/quest-1.0", "Author": "liza", "Comment": "TODO Missing Quest Start", + "TerritoryBlacklist": [ + 838, + 847 + ], "QuestSequence": [ { "Sequence": 7, diff --git a/QuestPaths/Shadowbringers/MSQ/G-5.1/3673_Shaken Resolve.json b/QuestPaths/Shadowbringers/MSQ/G-5.1/3673_Shaken Resolve.json index de3cd854..4ff0ea54 100644 --- a/QuestPaths/Shadowbringers/MSQ/G-5.1/3673_Shaken Resolve.json +++ b/QuestPaths/Shadowbringers/MSQ/G-5.1/3673_Shaken Resolve.json @@ -13,7 +13,14 @@ "Z": -9.10968 }, "TerritoryId": 351, - "InteractionType": "Interact" + "InteractionType": "Interact", + "DialogueChoices": [ + { + "Type": "List", + "Prompt": "TEXT_LUCKMG101_03673_Q1_000_500", + "Answer": "TEXT_LUCKMG101_03673_A1_000_500" + } + ] } ] }, @@ -38,7 +45,8 @@ "Z": -656.1909 }, "TerritoryId": 156, - "InteractionType": "WalkTo" + "InteractionType": "WalkTo", + "Mount": true }, { "DataId": 1018433, diff --git a/QuestPaths/Shadowbringers/MSQ/G-5.1/3674_A Grand Adventure.json b/QuestPaths/Shadowbringers/MSQ/G-5.1/3674_A Grand Adventure.json index b6a47fc7..ab3cba3e 100644 --- a/QuestPaths/Shadowbringers/MSQ/G-5.1/3674_A Grand Adventure.json +++ b/QuestPaths/Shadowbringers/MSQ/G-5.1/3674_A Grand Adventure.json @@ -26,6 +26,7 @@ "Y": -0.67464465, "Z": 653.1527 }, + "StopDistance": 0.5, "TerritoryId": 813, "InteractionType": "WalkTo", "AetheryteShortcut": "Lakeland - Fort Jobb", diff --git a/QuestPaths/TODO Quest YesNo.txt b/QuestPaths/TODO Quest YesNo.txt new file mode 100644 index 00000000..64c5478d --- /dev/null +++ b/QuestPaths/TODO Quest YesNo.txt @@ -0,0 +1,13 @@ +Currying Flavor: + "DialogueChoices": [ + { + "Type": "List", + "Prompt": "TEXT_AKTKMK101_04735_Q1_000_000", + "Answer": "TEXT_AKTKMK101_04735_A1_000_003" + }, + { + "Type": "YesNo", + "Prompt": "TEXT_AKTKMK101_04735_Q2_000_182", + "Yes": true + } + ] diff --git a/QuestPaths/quest-v1.json b/QuestPaths/quest-v1.json index 6162ef64..ff33740a 100644 --- a/QuestPaths/quest-v1.json +++ b/QuestPaths/quest-v1.json @@ -100,7 +100,6 @@ "Duty", "SinglePlayerDuty", "Jump", - "CutsceneSelectString", "ShouldBeAJump", "Instruction" ] @@ -648,7 +647,7 @@ "if": { "properties": { "InteractionType": { - "const": "CutsceneSelectString" + "const": "Interact" } } }, @@ -659,22 +658,68 @@ "items": { "type": "object", "properties": { + "Type": { + "type": "string", + "enum": [ + "YesNo", + "List" + ] + }, "ExcelSheet": { "type": "string" }, - "Answer": { + "Prompt": { "type": "string" } }, "required": [ - "Answer" + "Type", + "Prompt" + ], + "allOf": [ + { + "if": { + "properties": { + "Type": { + "const": "YesNo" + } + } + }, + "then": { + "properties": { + "Yes": { + "type": "boolean", + "default": true + } + }, + "required": [ + "Yes" + ] + } + }, + { + "if": { + "properties": { + "Type": { + "const": "List" + } + } + }, + "then": { + "properties": { + "Answer": { + "type": "string" + } + }, + "required": [ + "Answer" + ] + } + } ] } } - }, - "required": [ - "DialogueChoices" - ] + } } }, { diff --git a/Questionable/Controller/GameUiController.cs b/Questionable/Controller/GameUiController.cs new file mode 100644 index 00000000..63884ed3 --- /dev/null +++ b/Questionable/Controller/GameUiController.cs @@ -0,0 +1,240 @@ +using System; +using System.Linq; +using Dalamud.Game.Addon.Lifecycle; +using Dalamud.Game.Addon.Lifecycle.AddonArgTypes; +using Dalamud.Plugin.Services; +using FFXIVClientStructs.FFXIV.Client.UI; +using FFXIVClientStructs.FFXIV.Component.GUI; +using LLib.GameUI; +using Lumina.Excel.GeneratedSheets; +using Questionable.Model.V1; +using Quest = Questionable.Model.Quest; + +namespace Questionable.Controller; + +internal sealed class GameUiController : IDisposable +{ + private readonly IClientState _clientState; + private readonly IAddonLifecycle _addonLifecycle; + private readonly IDataManager _dataManager; + private readonly GameFunctions _gameFunctions; + private readonly QuestController _questController; + private readonly IPluginLog _pluginLog; + + public GameUiController(IClientState clientState, IAddonLifecycle addonLifecycle, IDataManager dataManager, + GameFunctions gameFunctions, QuestController questController, IPluginLog pluginLog) + { + _clientState = clientState; + _addonLifecycle = addonLifecycle; + _dataManager = dataManager; + _gameFunctions = gameFunctions; + _questController = questController; + _pluginLog = pluginLog; + + _addonLifecycle.RegisterListener(AddonEvent.PostSetup, "SelectString", SelectStringPostSetup); + _addonLifecycle.RegisterListener(AddonEvent.PostSetup, "CutSceneSelectString", CutsceneSelectStringPostSetup); + _addonLifecycle.RegisterListener(AddonEvent.PostSetup, "SelectYesno", SelectYesnoPostSetup); + _addonLifecycle.RegisterListener(AddonEvent.PostSetup, "Credit", CreditPostSetup); + _addonLifecycle.RegisterListener(AddonEvent.PostSetup, "AkatsukiNote", UnendingCodexPostSetup); + } + + private unsafe void SelectStringPostSetup(AddonEvent type, AddonArgs args) + { + AddonSelectString* addonSelectString = (AddonSelectString*)args.Addon; + string? actualPrompt = addonSelectString->AtkUnitBase.AtkValues[2].ReadAtkString(); + if (actualPrompt == null) + return; + + var currentQuest = _questController.CurrentQuest; + if (currentQuest == null) + return; + + var quest = currentQuest.Quest; + var step = quest.FindSequence(currentQuest.Sequence)?.FindStep(currentQuest.Step); + if (step == null) + return; + + foreach (var dialogueChoice in step.DialogueChoices) + { + if (dialogueChoice.Answer == null) + continue; + + string? excelPrompt = + _gameFunctions.GetExcelString(quest, dialogueChoice.ExcelSheet, dialogueChoice.Prompt); + string? excelAnswer = + _gameFunctions.GetExcelString(quest, dialogueChoice.ExcelSheet, dialogueChoice.Answer); + if (excelPrompt == null || actualPrompt != excelPrompt) + continue; + + for (ushort i = 7; i <= addonSelectString->AtkUnitBase.AtkValuesCount; ++i) + { + string? actualAnswer = addonSelectString->AtkUnitBase.AtkValues[i].ReadAtkString(); + if (actualAnswer == null || actualAnswer != excelAnswer) + continue; + + _questController.IncreaseDialogueChoicesSelected(); + addonSelectString->AtkUnitBase.FireCallbackInt(i - 7); + return; + } + } + } + + private unsafe void CutsceneSelectStringPostSetup(AddonEvent type, AddonArgs args) + { + AddonCutSceneSelectString* addonCutSceneSelectString = (AddonCutSceneSelectString*)args.Addon; + string? actualPrompt = addonCutSceneSelectString->AtkUnitBase.AtkValues[2].ReadAtkString(); + if (actualPrompt == null) + return; + + var currentQuest = _questController.CurrentQuest; + if (currentQuest == null) + return; + + var quest = currentQuest.Quest; + var step = quest.FindSequence(currentQuest.Sequence)?.FindStep(currentQuest.Step); + if (step == null) + return; + + foreach (DialogueChoice dialogueChoice in step.DialogueChoices) + { + if (dialogueChoice.Answer == null) + continue; + + string? excelPrompt = + _gameFunctions.GetExcelString(quest, dialogueChoice.ExcelSheet, dialogueChoice.Prompt); + string? excelAnswer = + _gameFunctions.GetExcelString(quest, dialogueChoice.ExcelSheet, dialogueChoice.Answer); + if (excelPrompt == null || actualPrompt != excelPrompt) + continue; + + for (int i = 5; i < addonCutSceneSelectString->AtkUnitBase.AtkValuesCount; ++i) + { + string? actualAnswer = addonCutSceneSelectString->AtkUnitBase.AtkValues[i].ReadAtkString(); + if (actualAnswer == null || actualAnswer != excelAnswer) + continue; + + _questController.IncreaseDialogueChoicesSelected(); + addonCutSceneSelectString->AtkUnitBase.FireCallbackInt(i - 5); + return; + } + } + } + + private unsafe void SelectYesnoPostSetup(AddonEvent type, AddonArgs args) + { + AddonSelectYesno* addonSelectYesno = (AddonSelectYesno*)args.Addon; + string? actualPrompt = addonSelectYesno->AtkUnitBase.AtkValues[0].ReadAtkString(); + if (actualPrompt == null) + return; + + _pluginLog.Verbose($"Prompt: '{actualPrompt}'"); + + var currentQuest = _questController.CurrentQuest; + if (currentQuest == null) + return; + + var quest = currentQuest.Quest; + var step = quest.FindSequence(currentQuest.Sequence)?.FindStep(currentQuest.Step); + if (step != null && HandleDefaultYesNo(addonSelectYesno, quest, step, actualPrompt)) + return; + + HandleTravelYesNo(addonSelectYesno, currentQuest, actualPrompt); + } + + private unsafe bool HandleDefaultYesNo(AddonSelectYesno* addonSelectYesno, Quest quest, QuestStep step, + string actualPrompt) + { + _pluginLog.Verbose($"DefaultYesNo: Choice count: {step.DialogueChoices.Count}"); + foreach (var dialogueChoice in step.DialogueChoices) + { + string? excelPrompt = + _gameFunctions.GetExcelString(quest, dialogueChoice.ExcelSheet, dialogueChoice.Prompt); + if (excelPrompt == null || actualPrompt != excelPrompt) + continue; + + addonSelectYesno->AtkUnitBase.FireCallbackInt(dialogueChoice.Yes ? 0 : 1); + _questController.IncreaseDialogueChoicesSelected(); + return true; + } + + return false; + } + + private unsafe bool HandleTravelYesNo(AddonSelectYesno* addonSelectYesno, + QuestController.QuestProgress currentQuest, string actualPrompt) + { + // this can be triggered either manually (in which case we should increase the step counter), or automatically + // (in which case it is ~1 frame later, and the step counter has already been increased) + var sequence = currentQuest.Quest.FindSequence(currentQuest.Sequence); + if (sequence == null) + return false; + + bool increaseStepCount = true; + QuestStep? step = sequence.FindStep(currentQuest.Step); + if (step != null) + _pluginLog.Verbose($"Current step: {step.TerritoryId}, {step.TargetTerritoryId}"); + + if (step == null || step.TargetTerritoryId == null || step.TerritoryId != _clientState.TerritoryType) + { + _pluginLog.Verbose("TravelYesNo: Checking previous step..."); + step = sequence.FindStep(currentQuest.Step == 255 ? (sequence.Steps.Count - 1) : (currentQuest.Step - 1)); + increaseStepCount = false; + + if (step != null) + _pluginLog.Verbose($"Previous step: {step.TerritoryId}, {step.TargetTerritoryId}"); + } + + if (step == null || step.TargetTerritoryId == null || step.TerritoryId != _clientState.TerritoryType) + { + _pluginLog.Verbose("TravelYesNo: Not found"); + return false; + } + + var warps = _dataManager.GetExcelSheet()! + .Where(x => x.RowId > 0 && x.TerritoryType.Row == step.TargetTerritoryId) + .Where(x => x.ConfirmEvent.Row == 0); // unsure if this is needed + foreach (var entry in warps) + { + string? excelPrompt = entry.Question?.ToString(); + if (excelPrompt == null || excelPrompt != actualPrompt) + { + _pluginLog.Information($"Ignoring prompt '{excelPrompt}'"); + continue; + } + + _pluginLog.Information($"Using warp {entry.RowId}, {excelPrompt}"); + addonSelectYesno->AtkUnitBase.FireCallbackInt(0); + if (increaseStepCount) + _questController.IncreaseStepCount(); + return true; + } + + return false; + } + + private unsafe void CreditPostSetup(AddonEvent type, AddonArgs args) + { + _pluginLog.Information("Closing Credits sequence"); + AtkUnitBase* addon = (AtkUnitBase*)args.Addon; + addon->FireCallbackInt(-2); + } + + private unsafe void UnendingCodexPostSetup(AddonEvent type, AddonArgs args) + { + if (_questController.CurrentQuest?.Quest.QuestId == 4526) + { + _pluginLog.Information("Closing Unending Codex"); + AtkUnitBase* addon = (AtkUnitBase*)args.Addon; + addon->FireCallbackInt(-2); + } + } + + public void Dispose() + { + _addonLifecycle.UnregisterListener(AddonEvent.PostSetup, "AkatsukiNote", UnendingCodexPostSetup); + _addonLifecycle.UnregisterListener(AddonEvent.PostSetup, "Credit", CreditPostSetup); + _addonLifecycle.UnregisterListener(AddonEvent.PostSetup, "SelectYesno", SelectYesnoPostSetup); + _addonLifecycle.UnregisterListener(AddonEvent.PostSetup, "CutSceneSelectString", CutsceneSelectStringPostSetup); + _addonLifecycle.UnregisterListener(AddonEvent.PostSetup, "SelectString", SelectStringPostSetup); + } +} diff --git a/Questionable/Controller/QuestController.cs b/Questionable/Controller/QuestController.cs index ad9d91ec..03425ba1 100644 --- a/Questionable/Controller/QuestController.cs +++ b/Questionable/Controller/QuestController.cs @@ -10,14 +10,11 @@ using Dalamud.Plugin; using Dalamud.Plugin.Services; using FFXIVClientStructs.FFXIV.Application.Network.WorkDefinitions; using FFXIVClientStructs.FFXIV.Client.Game; -using FFXIVClientStructs.FFXIV.Client.UI; -using LLib.GameUI; using Questionable.Data; using Questionable.External; using Questionable.Model; using Questionable.Model.V1; using Questionable.Model.V1.Converter; -using ValueType = FFXIVClientStructs.FFXIV.Component.GUI.ValueType; namespace Questionable.Controller; @@ -272,6 +269,27 @@ internal sealed class QuestController } } + public void IncreaseDialogueChoicesSelected() + { + (QuestSequence? seq, QuestStep? step) = GetNextStep(); + if (CurrentQuest == null || seq == null || step == null) + { + _pluginLog.Warning("Unable to retrieve next quest step, not increasing dialogue choice count"); + return; + } + + CurrentQuest = CurrentQuest with + { + StepProgress = CurrentQuest.StepProgress with + { + DialogueChoicesSelected = CurrentQuest.StepProgress.DialogueChoicesSelected + 1 + } + }; + + if (CurrentQuest.StepProgress.DialogueChoicesSelected >= step.DialogueChoices.Count) + IncreaseStepCount(); + } + public unsafe void ExecuteNextStep() { (QuestSequence? seq, QuestStep? step) = GetNextStep(); @@ -422,7 +440,8 @@ internal sealed class QuestController } } else - _pluginLog.Warning($"Aethernet shortcut not unlocked (from: {step.AethernetShortcut.From}, to: {step.AethernetShortcut.To}), walking manually"); + _pluginLog.Warning( + $"Aethernet shortcut not unlocked (from: {step.AethernetShortcut.From}, to: {step.AethernetShortcut.To}), walking manually"); } if (step.TargetTerritoryId == _clientState.TerritoryType && !step.SkipIf.Contains(ESkipCondition.Never)) @@ -439,11 +458,6 @@ internal sealed class QuestController { _pluginLog.Information("We're at the jump destination, skipping movement"); } - else if (step.InteractionType == EInteractionType.CutsceneSelectString && - _condition[ConditionFlag.OccupiedInCutSceneEvent]) - { - _pluginLog.Information("In cutscene selection, skipping movement"); - } else if (step.Position != null) { float distance; @@ -543,7 +557,10 @@ internal sealed class QuestController } _gameFunctions.InteractWith(step.DataId.Value); - IncreaseStepCount(); + + // if we have any dialogue, that is handled in GameUiController + if (step.DialogueChoices.Count == 0) + IncreaseStepCount(); } else _pluginLog.Warning("Not interacting on current step, DataId is null"); @@ -712,41 +729,6 @@ internal sealed class QuestController // Need to manually forward break; - case EInteractionType.CutsceneSelectString: - // to do this automatically, should likely be in Addon's post setup - if (_gameGui.TryGetAddonByName("CutSceneSelectString", out var addon) && - LAddon.IsAddonReady(&addon->AtkUnitBase)) - { - foreach (DialogueChoice dialogueChoice in step.DialogueChoices) - { - string? excelString = _gameFunctions.GetExcelString(CurrentQuest.Quest, - dialogueChoice.ExcelSheet, dialogueChoice.Answer); - if (excelString == null) - return; - - _pluginLog.Verbose($"Looking for option '{excelString}'"); - for (int i = 5; i < addon->AtkUnitBase.AtkValuesCount; ++i) - { - var atkValue = addon->AtkUnitBase.AtkValues[i]; - if (atkValue.Type != ValueType.String) - continue; - - string? atkString = atkValue.ReadAtkString(); - _pluginLog.Verbose($"Option {i}: {atkString}"); - if (excelString == atkString) - { - _pluginLog.Information($"Selecting option {i - 5}: {atkString}"); - addon->AtkUnitBase.FireCallbackInt(i - 5); - return; - } - } - } - } - else if (step.DataId != null && !_condition[ConditionFlag.OccupiedInCutSceneEvent]) - _gameFunctions.InteractWith(step.DataId.Value); - - break; - default: _pluginLog.Warning($"Action '{step.InteractionType}' is not implemented"); break; @@ -767,5 +749,6 @@ internal sealed class QuestController public sealed record StepProgress( bool AetheryteShortcutUsed = false, - bool AethernetShortcutUsed = false); + bool AethernetShortcutUsed = false, + int DialogueChoicesSelected = 0); } diff --git a/Questionable/GameFunctions.cs b/Questionable/GameFunctions.cs index 79d728cd..6a276159 100644 --- a/Questionable/GameFunctions.cs +++ b/Questionable/GameFunctions.cs @@ -474,22 +474,18 @@ internal sealed unsafe class GameFunctions _pluginLog.Error($"Could not find content for content finder condition (cf: {contentFinderConditionId})"); } - public string? GetExcelString(Quest currentQuestQuest, string? excelSheetName, string key) + public string? GetExcelString(Quest currentQuest, string? excelSheetName, string key) { if (excelSheetName == null) { - string questPrefix = $"quest/{(currentQuestQuest.QuestId / 100):000}/"; - string questSuffix = $"_{currentQuestQuest.QuestId:00000}"; - excelSheetName = _dataManager.Excel - .GetSheetNames() - .SingleOrDefault(x => - x.StartsWith(questPrefix, StringComparison.Ordinal) && - x.EndsWith(questSuffix, StringComparison.Ordinal)); - if (excelSheetName == null) + var questRow = _dataManager.GetExcelSheet()!.GetRow((uint)currentQuest.QuestId + 0x10000); + if (questRow == null) { - _pluginLog.Error($"Could not find sheet matching '{questPrefix}*{questSuffix}"); + _pluginLog.Error($"Could not find quest row for {currentQuest.QuestId}"); return null; } + + excelSheetName = $"quest/{(currentQuest.QuestId / 100):000}/{questRow.Id}"; } var excelSheet = _dataManager.Excel.GetSheet(excelSheetName); diff --git a/Questionable/Model/V1/Converter/DialogueChoiceTypeConverter.cs b/Questionable/Model/V1/Converter/DialogueChoiceTypeConverter.cs new file mode 100644 index 00000000..ea832cac --- /dev/null +++ b/Questionable/Model/V1/Converter/DialogueChoiceTypeConverter.cs @@ -0,0 +1,12 @@ +using System.Collections.Generic; + +namespace Questionable.Model.V1.Converter; + +public sealed class DialogueChoiceTypeConverter() : EnumConverter(Values) +{ + private static readonly Dictionary Values = new() + { + { EDialogChoiceType.YesNo, "YesNo" }, + { EDialogChoiceType.List, "List" }, + }; +} diff --git a/Questionable/Model/V1/Converter/InteractionTypeConverter.cs b/Questionable/Model/V1/Converter/InteractionTypeConverter.cs index 09a4dfaf..fcd2228b 100644 --- a/Questionable/Model/V1/Converter/InteractionTypeConverter.cs +++ b/Questionable/Model/V1/Converter/InteractionTypeConverter.cs @@ -20,7 +20,6 @@ public sealed class InteractionTypeConverter() : EnumConverter { EInteractionType.Duty, "Duty" }, { EInteractionType.SinglePlayerDuty, "SinglePlayerDuty" }, { EInteractionType.Jump, "Jump" }, - { EInteractionType.CutsceneSelectString, "CutsceneSelectString" }, { EInteractionType.ShouldBeAJump, "ShouldBeAJump" }, { EInteractionType.Instruction, "Instruction" }, }; diff --git a/Questionable/Model/V1/DialogueChoice.cs b/Questionable/Model/V1/DialogueChoice.cs index d4c607e7..1f85c63e 100644 --- a/Questionable/Model/V1/DialogueChoice.cs +++ b/Questionable/Model/V1/DialogueChoice.cs @@ -1,7 +1,14 @@ -namespace Questionable.Model.V1; +using System.Text.Json.Serialization; +using Questionable.Model.V1.Converter; -public sealed class DialogueChoice +namespace Questionable.Model.V1; + +public class DialogueChoice { + [JsonConverter(typeof(DialogueChoiceTypeConverter))] + public EDialogChoiceType Type { get; set; } public string? ExcelSheet { get; set; } - public string Answer { get; set; } = null!; + public string Prompt { get; set; } = null!; + public bool Yes { get; set; } = true; + public string? Answer { get; set; } } diff --git a/Questionable/Model/V1/EDialogChoiceType.cs b/Questionable/Model/V1/EDialogChoiceType.cs new file mode 100644 index 00000000..008418f4 --- /dev/null +++ b/Questionable/Model/V1/EDialogChoiceType.cs @@ -0,0 +1,8 @@ +namespace Questionable.Model.V1; + +public enum EDialogChoiceType +{ + None, + YesNo, + List +} diff --git a/Questionable/Model/V1/EInteractionType.cs b/Questionable/Model/V1/EInteractionType.cs index ae0267f0..f0ca8a32 100644 --- a/Questionable/Model/V1/EInteractionType.cs +++ b/Questionable/Model/V1/EInteractionType.cs @@ -20,7 +20,6 @@ public enum EInteractionType Duty, SinglePlayerDuty, Jump, - CutsceneSelectString, /// /// Needs to be adjusted for coords etc. in the quest data. diff --git a/Questionable/Model/V1/QuestSequence.cs b/Questionable/Model/V1/QuestSequence.cs index cd691b13..4ea058ed 100644 --- a/Questionable/Model/V1/QuestSequence.cs +++ b/Questionable/Model/V1/QuestSequence.cs @@ -7,4 +7,12 @@ public class QuestSequence public required int Sequence { get; set; } public string? Comment { get; set; } public List Steps { get; set; } = new(); + + public QuestStep? FindStep(int step) + { + if (step < 0 || step >= Steps.Count) + return null; + + return Steps[step]; + } } diff --git a/Questionable/Questionable.csproj b/Questionable/Questionable.csproj index ac0f229b..1bc72708 100644 --- a/Questionable/Questionable.csproj +++ b/Questionable/Questionable.csproj @@ -1,7 +1,7 @@  net8.0-windows - 0.2 + 0.3 12 enable true diff --git a/Questionable/QuestionablePlugin.cs b/Questionable/QuestionablePlugin.cs index 4d04fec2..5e810040 100644 --- a/Questionable/QuestionablePlugin.cs +++ b/Questionable/QuestionablePlugin.cs @@ -27,13 +27,13 @@ public sealed class QuestionablePlugin : IDalamudPlugin private readonly ICommandManager _commandManager; private readonly GameFunctions _gameFunctions; private readonly QuestController _questController; - private readonly MovementController _movementController; + private readonly GameUiController _gameUiController; public QuestionablePlugin(DalamudPluginInterface pluginInterface, IClientState clientState, ITargetManager targetManager, IFramework framework, IGameGui gameGui, IDataManager dataManager, ISigScanner sigScanner, IObjectTable objectTable, IPluginLog pluginLog, ICondition condition, IChatGui chatGui, - ICommandManager commandManager) + ICommandManager commandManager, IAddonLifecycle addonLifecycle) { ArgumentNullException.ThrowIfNull(pluginInterface); ArgumentNullException.ThrowIfNull(sigScanner); @@ -55,6 +55,9 @@ public sealed class QuestionablePlugin : IDalamudPlugin new MovementController(navmeshIpc, clientState, _gameFunctions, condition, pluginLog); _questController = new QuestController(pluginInterface, dataManager, _clientState, _gameFunctions, _movementController, pluginLog, condition, chatGui, framework, gameGui, aetheryteData, lifestreamIpc); + _gameUiController = + new GameUiController(clientState, addonLifecycle, dataManager, _gameFunctions, _questController, pluginLog); + _windowSystem.AddWindow(new DebugWindow(_movementController, _questController, _gameFunctions, clientState, targetManager)); @@ -100,6 +103,7 @@ public sealed class QuestionablePlugin : IDalamudPlugin _framework.Update -= FrameworkUpdate; _pluginInterface.UiBuilder.Draw -= _windowSystem.Draw; + _gameUiController.Dispose(); _movementController.Dispose(); } } diff --git a/Questionable/Windows/DebugWindow.cs b/Questionable/Windows/DebugWindow.cs index 845fd530..b3c68450 100644 --- a/Questionable/Windows/DebugWindow.cs +++ b/Questionable/Windows/DebugWindow.cs @@ -1,12 +1,9 @@ using System.Globalization; -using System.Linq; using System.Numerics; -using System.Runtime.InteropServices; using Dalamud.Game.ClientState.Objects; using Dalamud.Interface; using Dalamud.Interface.Components; using Dalamud.Interface.Windowing; -using Dalamud.Memory; using Dalamud.Plugin.Services; using FFXIVClientStructs.FFXIV.Client.Game; using FFXIVClientStructs.FFXIV.Client.Game.Control; @@ -45,6 +42,15 @@ internal sealed class DebugWindow : Window }; } + public override bool DrawConditions() + { + if (!_clientState.IsLoggedIn || _clientState.LocalPlayer == null) + return false; + + var currentQuest = _questController.CurrentQuest; + return currentQuest == null || !currentQuest.Quest.Data.TerritoryBlacklist.Contains(_clientState.TerritoryType); + } + public override unsafe void Draw() { if (!_clientState.IsLoggedIn || _clientState.LocalPlayer == null)