From 77168a9ee636505e5876dbf56730862b4a3bb511 Mon Sep 17 00:00:00 2001 From: Liza Carvelli Date: Fri, 12 Jul 2024 02:42:37 +0200 Subject: [PATCH] Improve quest chain handling (auto-accepting next quest, dialogue choices) --- .../Healer/4829_An Antidote for Anarchy.json | 98 +++++++++ .../MagicalRanged/4845_Floundering Fame.json | 189 ++++++++++++++++++ .../MagicalRanged/4846_Behind the Helm.json | 138 +++++++++++++ .../4847_Heroes and Pretenders.json | 95 +++++++++ .../Urqopacha/5054_Springing the Trap.json | 2 +- .../Arkasodara/4567_Vanaspati's Blessing.json | 97 +++++++++ ...Hells Hath No Fury as a Hippo Scorned.json | 70 +++++++ .../Tribal/Arkasodara/4569_Tusk Trouble.json | 74 +++++++ .../Hunts/4176_The Hunt for Specimens.json | 41 ++++ ...4177_That Specimen Came from the Moon.json | 41 ++++ .../Hunts/4178_A Hunt for the Ages.json | 41 ++++ .../Unlocks/Hunts/4179_Perfect Specimens.json | 41 ++++ .../MSQ/H-5.2/3768_A Whale's Tale.json | 1 - .../MSQ/I-5.3/3772_Heroic Dreams.json | 1 - .../MSQ/I-5.3/3774_Food for the Soul.json | 3 +- .../MSQ/I-5.3/3775_Faded Memories.json | 23 ++- QuestPaths/quest-v1.json | 3 +- .../V1/Converter/SkipConditionConverter.cs | 1 + Questionable.Model/V1/ESkipCondition.cs | 1 + Questionable/Controller/GameUiController.cs | 14 +- Questionable/Controller/QuestController.cs | 37 +++- .../Steps/BaseFactory/SkipCondition.cs | 24 ++- Questionable/Data/QuestData.cs | 5 +- Questionable/Model/QuestInfo.cs | 7 +- Questionable/Windows/DebugOverlay.cs | 2 +- Questionable/Windows/QuestWindow.cs | 39 +++- 26 files changed, 1063 insertions(+), 25 deletions(-) create mode 100644 QuestPaths/Dawntrail/RoleQuests/MagicalRanged/4846_Behind the Helm.json create mode 100644 QuestPaths/Dawntrail/RoleQuests/MagicalRanged/4847_Heroes and Pretenders.json create mode 100644 QuestPaths/Endwalker/Tribal/Arkasodara/4567_Vanaspati's Blessing.json create mode 100644 QuestPaths/Endwalker/Tribal/Arkasodara/4568_Hells Hath No Fury as a Hippo Scorned.json create mode 100644 QuestPaths/Endwalker/Tribal/Arkasodara/4569_Tusk Trouble.json create mode 100644 QuestPaths/Endwalker/Unlocks/Hunts/4176_The Hunt for Specimens.json create mode 100644 QuestPaths/Endwalker/Unlocks/Hunts/4177_That Specimen Came from the Moon.json create mode 100644 QuestPaths/Endwalker/Unlocks/Hunts/4178_A Hunt for the Ages.json create mode 100644 QuestPaths/Endwalker/Unlocks/Hunts/4179_Perfect Specimens.json diff --git a/QuestPaths/Dawntrail/RoleQuests/Healer/4829_An Antidote for Anarchy.json b/QuestPaths/Dawntrail/RoleQuests/Healer/4829_An Antidote for Anarchy.json index a994b992..d8ee7007 100644 --- a/QuestPaths/Dawntrail/RoleQuests/Healer/4829_An Antidote for Anarchy.json +++ b/QuestPaths/Dawntrail/RoleQuests/Healer/4829_An Antidote for Anarchy.json @@ -20,6 +20,104 @@ ] } ] + }, + { + "Sequence": 1, + "Steps": [ + { + "DataId": 1046319, + "Position": { + "X": -335.3476, + "Y": 69.418495, + "Z": 155.87085 + }, + "TerritoryId": 137, + "InteractionType": "Interact", + "AetheryteShortcut": "Eastern La Noscea - Wineport" + } + ] + }, + { + "Sequence": 2, + "Steps": [ + { + "DataId": 1046319, + "Position": { + "X": -335.3476, + "Y": 69.418495, + "Z": 155.87085 + }, + "TerritoryId": 137, + "InteractionType": "SinglePlayerDuty" + } + ] + }, + { + "Sequence": 3, + "Steps": [ + { + "Position": { + "X": 0, + "Y": 0, + "Z": 0 + }, + "TerritoryId": 1, + "InteractionType": "WalkTo", + "Comment": "Filler" + } + ] + }, + { + "Sequence": 4, + "Steps": [ + { + "DataId": 1046319, + "Position": { + "X": -335.3476, + "Y": 69.418495, + "Z": 155.87085 + }, + "StopDistance": 5, + "TerritoryId": 137, + "InteractionType": "Interact" + } + ] + }, + { + "Sequence": 5, + "Steps": [ + { + "DataId": 1046320, + "Position": { + "X": 267.01758, + "Y": -25, + "Z": 264.88135 + }, + "TerritoryId": 138, + "InteractionType": "Interact", + "AetheryteShortcut": "Western La Noscea - Aleport" + } + ] + }, + { + "Sequence": 255, + "Steps": [ + { + "DataId": 1046289, + "Position": { + "X": -64.62195, + "Y": -17.95485, + "Z": 201.28174 + }, + "TerritoryId": 1185, + "InteractionType": "CompleteQuest", + "AetheryteShortcut": "Tuliyollal", + "AethernetShortcut": [ + "[Tuliyollal] Aetheryte Plaza", + "[Tuliyollal] Bayside Bevy Marketplace" + ] + } + ] } ] } diff --git a/QuestPaths/Dawntrail/RoleQuests/MagicalRanged/4845_Floundering Fame.json b/QuestPaths/Dawntrail/RoleQuests/MagicalRanged/4845_Floundering Fame.json index 121237bc..b6ab46ab 100644 --- a/QuestPaths/Dawntrail/RoleQuests/MagicalRanged/4845_Floundering Fame.json +++ b/QuestPaths/Dawntrail/RoleQuests/MagicalRanged/4845_Floundering Fame.json @@ -152,6 +152,195 @@ "InteractionType": "Interact" } ] + }, + { + "Sequence": 6, + "Steps": [ + { + "DataId": 2013713, + "Position": { + "X": 362.35596, + "Y": 3.616333, + "Z": -241.77924 + }, + "StopDistance": 0.25, + "TerritoryId": 957, + "InteractionType": "Interact", + "Fly": true, + "SkipIf": [ + "NotTargetable" + ], + "DialogueChoices": [ + { + "Type": "YesNo", + "Prompt": "TEXT_KINGBA531_04845_Q1_000_054", + "Yes": true + } + ], + "Comment": "retry point" + }, + { + "DataId": 1048364, + "Position": { + "X": 387.43045, + "Y": 5.8062716, + "Z": -203.20459 + }, + "TerritoryId": 957, + "InteractionType": "WaitForNpcAtPosition", + "StopDistance": 50, + "Mount": false, + "Sprint": false + }, + { + "Position": { + "X": 386.85394, + "Y": 3.0972311, + "Z": -220.57103 + }, + "TerritoryId": 957, + "InteractionType": "WalkTo", + "Mount": false, + "Sprint": false + }, + { + "DataId": 1048364, + "Position": { + "X": 398.46808, + "Y": 12.103142, + "Z": -174.068 + }, + "TerritoryId": 957, + "InteractionType": "WaitForNpcAtPosition", + "StopDistance": 50, + "Mount": false, + "Sprint": false + }, + { + "Position": { + "X": 395.88028, + "Y": 10.267179, + "Z": -192.21916 + }, + "TerritoryId": 957, + "InteractionType": "WalkTo", + "Mount": false, + "Sprint": false + }, + { + "DataId": 1048364, + "Position": { + "X": 395.6862, + "Y": 11.099065, + "Z": -169.7558 + }, + "TerritoryId": 957, + "InteractionType": "WaitForNpcAtPosition", + "StopDistance": 50, + "Mount": false, + "Sprint": false + }, + { + "Position": { + "X": 398.42825, + "Y": 12.946791, + "Z": -180.08061 + }, + "TerritoryId": 957, + "InteractionType": "WalkTo", + "Mount": false, + "Sprint": false + }, + { + "Position": { + "X": 368.02908, + "Y": 5.7749786, + "Z": -135.06207 + }, + "TerritoryId": 957, + "InteractionType": "WalkTo", + "Mount": false, + "Sprint": false + }, + { + "Position": { + "X": 300.81885, + "Y": 18.925224, + "Z": -43.56831 + }, + "TerritoryId": 957, + "InteractionType": "WalkTo", + "Mount": false, + "Sprint": false + }, + { + "DataId": 1048364, + "Position": { + "X": 274.41418, + "Y": 17.838093, + "Z": -2.1020741 + }, + "TerritoryId": 957, + "InteractionType": "WaitForNpcAtPosition", + "StopDistance": 50, + "Mount": false, + "Sprint": false + }, + { + "Position": { + "X": 256.60135, + "Y": 19.312042, + "Z": -1.2628903 + }, + "TerritoryId": 957, + "InteractionType": "WalkTo", + "Mount": false, + "Sprint": false + }, + { + "Position": { + "X": 244.453, + "Y": 16.725914, + "Z": 14.936783 + }, + "TerritoryId": 957, + "InteractionType": "WalkTo", + "Mount": false, + "Sprint": false + } + ] + }, + { + "Sequence": 7, + "Steps": [ + { + "DataId": 1048368, + "Position": { + "X": 239.33765, + "Y": 11.061386, + "Z": 69.99304 + }, + "TerritoryId": 957, + "InteractionType": "Interact" + } + ] + }, + { + "Sequence": 255, + "Steps": [ + { + "DataId": 1048331, + "Position": { + "X": 214.03821, + "Y": 5.2600574, + "Z": 628.3817 + }, + "TerritoryId": 957, + "InteractionType": "CompleteQuest", + "AetheryteShortcut": "Thavnair - Yedlihmad", + "NextQuestId": 4846 + } + ] } ] } diff --git a/QuestPaths/Dawntrail/RoleQuests/MagicalRanged/4846_Behind the Helm.json b/QuestPaths/Dawntrail/RoleQuests/MagicalRanged/4846_Behind the Helm.json new file mode 100644 index 00000000..5fb53413 --- /dev/null +++ b/QuestPaths/Dawntrail/RoleQuests/MagicalRanged/4846_Behind the Helm.json @@ -0,0 +1,138 @@ +{ + "$schema": "https://carvel.li/questionable/quest-1.0", + "Author": "liza", + "QuestSequence": [ + { + "Sequence": 0, + "Steps": [ + { + "DataId": 1048331, + "Position": { + "X": 214.03821, + "Y": 5.2600574, + "Z": 628.3817 + }, + "TerritoryId": 957, + "InteractionType": "AcceptQuest" + } + ] + }, + { + "Sequence": 1, + "Steps": [ + { + "DataId": 1048330, + "Position": { + "X": -28.732727, + "Y": -17.972864, + "Z": 194.72034 + }, + "TerritoryId": 1185, + "InteractionType": "Interact", + "AetheryteShortcut": "Tuliyollal", + "AethernetShortcut": [ + "[Tuliyollal] Aetheryte Plaza", + "[Tuliyollal] Bayside Bevy Marketplace" + ] + } + ] + }, + { + "Sequence": 2, + "Steps": [ + { + "Position": { + "X": 327.87598, + "Y": -15.862221, + "Z": -236.6933 + }, + "TerritoryId": 1190, + "InteractionType": "WalkTo", + "AetheryteShortcut": "Shaaloani - Mehwahhetsoan", + "SkipIf": [ + "FlyingUnlocked" + ] + }, + { + "Position": { + "X": 442.79218, + "Y": -16.660347, + "Z": -111.04725 + }, + "TerritoryId": 1190, + "InteractionType": "Combat", + "EnemySpawnType": "AutoOnEnterArea", + "KillEnemyDataIds": [ + 17627 + ], + "Fly": true + } + ] + }, + { + "Sequence": 3, + "Steps": [ + { + "DataId": 1048369, + "Position": { + "X": 441.5503, + "Y": -16.619904, + "Z": -109.14783 + }, + "StopDistance": 7, + "TerritoryId": 1190, + "InteractionType": "Interact" + } + ] + }, + { + "Sequence": 4, + "Steps": [ + { + "DataId": 1048333, + "Position": { + "X": 52.506226, + "Y": -5.20688E-07, + "Z": -54.154297 + }, + "TerritoryId": 963, + "InteractionType": "Interact", + "AetheryteShortcut": "Radz-at-Han" + } + ] + }, + { + "Sequence": 5, + "Steps": [ + { + "DataId": 1048372, + "Position": { + "X": -53.177734, + "Y": -1.9999962, + "Z": 147.60046 + }, + "StopDistance": 7, + "TerritoryId": 963, + "InteractionType": "Interact" + } + ] + }, + { + "Sequence": 255, + "Steps": [ + { + "DataId": 1048331, + "Position": { + "X": 214.03821, + "Y": 5.2600574, + "Z": 628.3817 + }, + "TerritoryId": 957, + "InteractionType": "CompleteQuest", + "AetheryteShortcut": "Thavnair - Yedlihmad", + "NextQuestId": 4847 + } + ] + } + ] +} diff --git a/QuestPaths/Dawntrail/RoleQuests/MagicalRanged/4847_Heroes and Pretenders.json b/QuestPaths/Dawntrail/RoleQuests/MagicalRanged/4847_Heroes and Pretenders.json new file mode 100644 index 00000000..d3023ced --- /dev/null +++ b/QuestPaths/Dawntrail/RoleQuests/MagicalRanged/4847_Heroes and Pretenders.json @@ -0,0 +1,95 @@ +{ + "$schema": "https://carvel.li/questionable/quest-1.0", + "Author": "liza", + "TerritoryBlacklist": [ + 1218 + ], + "QuestSequence": [ + { + "Sequence": 0, + "Steps": [ + { + "DataId": 1048331, + "Position": { + "X": 214.03821, + "Y": 5.2600574, + "Z": 628.3817 + }, + "TerritoryId": 957, + "InteractionType": "AcceptQuest" + } + ] + }, + { + "Sequence": 1, + "Steps": [ + { + "DataId": 1048374, + "Position": { + "X": -77.04285, + "Y": 99.946754, + "Z": -711.0552 + }, + "TerritoryId": 957, + "InteractionType": "SinglePlayerDuty", + "AetheryteShortcut": "Radz-at-Han", + "AethernetShortcut": [ + "[Radz-at-Han] Aetheryte Plaza", + "[Radz-at-Han] The Gate of First Sight (Thavnair)" + ], + "Fly": true + } + ] + }, + { + "Sequence": 2, + "Steps": [ + { + "Position": { + "X": 0, + "Y": 0, + "Z": 0 + }, + "TerritoryId": 1, + "InteractionType": "WalkTo", + "Comment": "Filler" + } + ] + }, + { + "Sequence": 3, + "Steps": [ + { + "DataId": 1048374, + "Position": { + "X": -77.04285, + "Y": 99.946754, + "Z": -711.0552 + }, + "TerritoryId": 957, + "InteractionType": "Interact" + } + ] + }, + { + "Sequence": 255, + "Steps": [ + { + "DataId": 1048330, + "Position": { + "X": -28.732727, + "Y": -17.972864, + "Z": 194.72034 + }, + "TerritoryId": 1185, + "InteractionType": "CompleteQuest", + "AetheryteShortcut": "Tuliyollal", + "AethernetShortcut": [ + "[Tuliyollal] Aetheryte Plaza", + "[Tuliyollal] Bayside Bevy Marketplace" + ] + } + ] + } + ] +} diff --git a/QuestPaths/Dawntrail/SideQuests/Urqopacha/5054_Springing the Trap.json b/QuestPaths/Dawntrail/SideQuests/Urqopacha/5054_Springing the Trap.json index d336dec7..27040e8a 100644 --- a/QuestPaths/Dawntrail/SideQuests/Urqopacha/5054_Springing the Trap.json +++ b/QuestPaths/Dawntrail/SideQuests/Urqopacha/5054_Springing the Trap.json @@ -45,7 +45,7 @@ }, "TerritoryId": 1187, "InteractionType": "Interact", - "Fly": true, + "DisableNavmesh": true, "DialogueChoices": [ { "Type": "YesNo", diff --git a/QuestPaths/Endwalker/Tribal/Arkasodara/4567_Vanaspati's Blessing.json b/QuestPaths/Endwalker/Tribal/Arkasodara/4567_Vanaspati's Blessing.json new file mode 100644 index 00000000..18b9b83d --- /dev/null +++ b/QuestPaths/Endwalker/Tribal/Arkasodara/4567_Vanaspati's Blessing.json @@ -0,0 +1,97 @@ +{ + "$schema": "https://carvel.li/questionable/quest-1.0", + "Author": "liza", + "QuestSequence": [ + { + "Sequence": 0, + "Steps": [ + { + "DataId": 1042301, + "Position": { + "X": -66.02582, + "Y": 39.994705, + "Z": 321.06494 + }, + "TerritoryId": 957, + "InteractionType": "Interact" + } + ] + }, + { + "Sequence": 1, + "Steps": [ + { + "DataId": 2012858, + "Position": { + "X": 280.78125, + "Y": 0.045776367, + "Z": 556.7252 + }, + "TerritoryId": 957, + "InteractionType": "Interact", + "Fly": true, + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 32 + ] + }, + { + "DataId": 2012857, + "Position": { + "X": 303.36462, + "Y": 0.015197754, + "Z": 530.44934 + }, + "TerritoryId": 957, + "InteractionType": "Interact", + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 64 + ] + }, + { + "DataId": 2012856, + "Position": { + "X": 281.94092, + "Y": 0.015197754, + "Z": 510.64307 + }, + "TerritoryId": 957, + "InteractionType": "Interact", + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 128 + ] + } + ] + }, + { + "Sequence": 255, + "Steps": [ + { + "DataId": 1042301, + "Position": { + "X": -66.02582, + "Y": 39.994705, + "Z": 321.06494 + }, + "TerritoryId": 957, + "InteractionType": "CompleteQuest", + "Fly": true + } + ] + } + ] +} diff --git a/QuestPaths/Endwalker/Tribal/Arkasodara/4568_Hells Hath No Fury as a Hippo Scorned.json b/QuestPaths/Endwalker/Tribal/Arkasodara/4568_Hells Hath No Fury as a Hippo Scorned.json new file mode 100644 index 00000000..0a0aaa80 --- /dev/null +++ b/QuestPaths/Endwalker/Tribal/Arkasodara/4568_Hells Hath No Fury as a Hippo Scorned.json @@ -0,0 +1,70 @@ +{ + "$schema": "https://carvel.li/questionable/quest-1.0", + "Author": "liza", + "QuestSequence": [ + { + "Sequence": 0, + "Steps": [ + { + "DataId": 1042301, + "Position": { + "X": -66.02582, + "Y": 39.994705, + "Z": 321.06494 + }, + "TerritoryId": 957, + "InteractionType": "Interact" + } + ] + }, + { + "Sequence": 1, + "Steps": [ + { + "DataId": 2012892, + "Position": { + "X": -120.19531, + "Y": 41.000854, + "Z": 340.41345 + }, + "TerritoryId": 957, + "InteractionType": "Interact" + } + ] + }, + { + "Sequence": 2, + "Steps": [ + { + "DataId": 1042458, + "Position": { + "X": 416.5254, + "Y": 8.834262, + "Z": -344.38086 + }, + "TerritoryId": 957, + "InteractionType": "Interact", + "AetheryteShortcut": "Thavnair - Palaka's Stand", + "Fly": true + } + ] + }, + { + "Sequence": 255, + "Steps": [ + { + "DataId": 1042301, + "Position": { + "X": -66.02582, + "Y": 39.994705, + "Z": 321.06494 + }, + "TerritoryId": 957, + "InteractionType": "CompleteQuest", + "AetheryteShortcut": "Thavnair - Yedlihmad", + "Fly": true + } + ] + } + ] +} diff --git a/QuestPaths/Endwalker/Tribal/Arkasodara/4569_Tusk Trouble.json b/QuestPaths/Endwalker/Tribal/Arkasodara/4569_Tusk Trouble.json new file mode 100644 index 00000000..0d01f386 --- /dev/null +++ b/QuestPaths/Endwalker/Tribal/Arkasodara/4569_Tusk Trouble.json @@ -0,0 +1,74 @@ +{ + "$schema": "https://carvel.li/questionable/quest-1.0", + "Author": "liza", + "QuestSequence": [ + { + "Sequence": 0, + "Steps": [ + { + "DataId": 1042301, + "Position": { + "X": -66.02582, + "Y": 39.994705, + "Z": 321.06494 + }, + "TerritoryId": 957, + "InteractionType": "Interact" + } + ] + }, + { + "Sequence": 1, + "Steps": [ + { + "DataId": 2012893, + "Position": { + "X": 267.32275, + "Y": 7.156433, + "Z": -476.34088 + }, + "TerritoryId": 957, + "InteractionType": "UseItem", + "ItemId": 2003403, + "AetheryteShortcut": "Thavnair - Palaka's Stand" + } + ] + }, + { + "Sequence": 2, + "Steps": [ + { + "DataId": 2012894, + "Position": { + "X": 257.09924, + "Y": 6.6071167, + "Z": -468.0705 + }, + "TerritoryId": 957, + "InteractionType": "Combat", + "EnemySpawnType": "AfterInteraction", + "KillEnemyDataIds": [ + 14678 + ] + } + ] + }, + { + "Sequence": 255, + "Steps": [ + { + "DataId": 1042301, + "Position": { + "X": -66.02582, + "Y": 39.994705, + "Z": 321.06494 + }, + "TerritoryId": 957, + "InteractionType": "CompleteQuest", + "AetheryteShortcut": "Thavnair - Yedlihmad", + "Fly": true + } + ] + } + ] +} diff --git a/QuestPaths/Endwalker/Unlocks/Hunts/4176_The Hunt for Specimens.json b/QuestPaths/Endwalker/Unlocks/Hunts/4176_The Hunt for Specimens.json new file mode 100644 index 00000000..62310683 --- /dev/null +++ b/QuestPaths/Endwalker/Unlocks/Hunts/4176_The Hunt for Specimens.json @@ -0,0 +1,41 @@ +{ + "$schema": "https://carvel.li/questionable/quest-1.0", + "Author": "liza", + "QuestSequence": [ + { + "Sequence": 0, + "Steps": [ + { + "DataId": 1041960, + "Position": { + "X": -1.9379272, + "Y": -7.758, + "Z": 42.282715 + }, + "TerritoryId": 962, + "InteractionType": "AcceptQuest", + "AetheryteShortcut": "Old Sharlayan", + "SkipIf": [ + "AetheryteShortcutIfInSameTerritory" + ] + } + ] + }, + { + "Sequence": 255, + "Steps": [ + { + "DataId": 1037060, + "Position": { + "X": 25.894531, + "Y": -15.646991, + "Z": 99.68713 + }, + "TerritoryId": 962, + "InteractionType": "CompleteQuest", + "NextQuestId": 4177 + } + ] + } + ] +} diff --git a/QuestPaths/Endwalker/Unlocks/Hunts/4177_That Specimen Came from the Moon.json b/QuestPaths/Endwalker/Unlocks/Hunts/4177_That Specimen Came from the Moon.json new file mode 100644 index 00000000..05ef5bf0 --- /dev/null +++ b/QuestPaths/Endwalker/Unlocks/Hunts/4177_That Specimen Came from the Moon.json @@ -0,0 +1,41 @@ +{ + "$schema": "https://carvel.li/questionable/quest-1.0", + "Author": "liza", + "QuestSequence": [ + { + "Sequence": 0, + "Steps": [ + { + "DataId": 1037060, + "Position": { + "X": 25.894531, + "Y": -15.646991, + "Z": 99.68713 + }, + "TerritoryId": 962, + "InteractionType": "AcceptQuest", + "AetheryteShortcut": "Old Sharlayan", + "SkipIf": [ + "AetheryteShortcutIfInSameTerritory" + ] + } + ] + }, + { + "Sequence": 255, + "Steps": [ + { + "DataId": 1037059, + "Position": { + "X": 35.202515, + "Y": -15.646992, + "Z": 102.4032 + }, + "TerritoryId": 962, + "InteractionType": "CompleteQuest", + "NextQuestId": 4178 + } + ] + } + ] +} diff --git a/QuestPaths/Endwalker/Unlocks/Hunts/4178_A Hunt for the Ages.json b/QuestPaths/Endwalker/Unlocks/Hunts/4178_A Hunt for the Ages.json new file mode 100644 index 00000000..f518bf0f --- /dev/null +++ b/QuestPaths/Endwalker/Unlocks/Hunts/4178_A Hunt for the Ages.json @@ -0,0 +1,41 @@ +{ + "$schema": "https://carvel.li/questionable/quest-1.0", + "Author": "liza", + "QuestSequence": [ + { + "Sequence": 0, + "Steps": [ + { + "DataId": 1037060, + "Position": { + "X": 25.894531, + "Y": -15.646991, + "Z": 99.68713 + }, + "TerritoryId": 962, + "InteractionType": "AcceptQuest", + "AetheryteShortcut": "Old Sharlayan", + "SkipIf": [ + "AetheryteShortcutIfInSameTerritory" + ] + } + ] + }, + { + "Sequence": 255, + "Steps": [ + { + "DataId": 1037059, + "Position": { + "X": 35.202515, + "Y": -15.646992, + "Z": 102.4032 + }, + "TerritoryId": 962, + "InteractionType": "CompleteQuest", + "NextQuestId": 4179 + } + ] + } + ] +} diff --git a/QuestPaths/Endwalker/Unlocks/Hunts/4179_Perfect Specimens.json b/QuestPaths/Endwalker/Unlocks/Hunts/4179_Perfect Specimens.json new file mode 100644 index 00000000..8f89f853 --- /dev/null +++ b/QuestPaths/Endwalker/Unlocks/Hunts/4179_Perfect Specimens.json @@ -0,0 +1,41 @@ +{ + "$schema": "https://carvel.li/questionable/quest-1.0", + "Author": "liza", + "QuestSequence": [ + { + "Sequence": 0, + "Steps": [ + { + "DataId": 1037060, + "Position": { + "X": 25.894531, + "Y": -15.646991, + "Z": 99.68713 + }, + "TerritoryId": 962, + "InteractionType": "AcceptQuest", + "AetheryteShortcut": "Old Sharlayan", + "SkipIf": [ + "AetheryteShortcutIfInSameTerritory" + ] + } + ] + }, + { + "Sequence": 255, + "Steps": [ + { + "DataId": 1037059, + "Position": { + "X": 35.202515, + "Y": -15.646992, + "Z": 102.4032 + }, + "TerritoryId": 962, + "InteractionType": "CompleteQuest", + "NextQuestId": 5009 + } + ] + } + ] +} diff --git a/QuestPaths/Shadowbringers/MSQ/H-5.2/3768_A Whale's Tale.json b/QuestPaths/Shadowbringers/MSQ/H-5.2/3768_A Whale's Tale.json index 6fee81f6..48e0e15e 100644 --- a/QuestPaths/Shadowbringers/MSQ/H-5.2/3768_A Whale's Tale.json +++ b/QuestPaths/Shadowbringers/MSQ/H-5.2/3768_A Whale's Tale.json @@ -133,7 +133,6 @@ }, "TerritoryId": 813, "InteractionType": "Interact", - "DisableNavmesh": true, "CompletionQuestVariablesFlags": [ null, null, diff --git a/QuestPaths/Shadowbringers/MSQ/I-5.3/3772_Heroic Dreams.json b/QuestPaths/Shadowbringers/MSQ/I-5.3/3772_Heroic Dreams.json index ef9d5062..17a19db8 100644 --- a/QuestPaths/Shadowbringers/MSQ/I-5.3/3772_Heroic Dreams.json +++ b/QuestPaths/Shadowbringers/MSQ/I-5.3/3772_Heroic Dreams.json @@ -106,7 +106,6 @@ "KillEnemyDataIds": [ 12168 ], - "Comment": "TODO Missing enemy ids", "Fly": true, "$.2": "QuestVariables if done after [1, 2]: irrelevant because it automatically progresses to the next step" } diff --git a/QuestPaths/Shadowbringers/MSQ/I-5.3/3774_Food for the Soul.json b/QuestPaths/Shadowbringers/MSQ/I-5.3/3774_Food for the Soul.json index ce3d658b..b9c6b4b8 100644 --- a/QuestPaths/Shadowbringers/MSQ/I-5.3/3774_Food for the Soul.json +++ b/QuestPaths/Shadowbringers/MSQ/I-5.3/3774_Food for the Soul.json @@ -38,7 +38,8 @@ "Z": -653.85443 }, "TerritoryId": 156, - "InteractionType": "WalkTo" + "InteractionType": "WalkTo", + "Mount": true }, { "Position": { diff --git a/QuestPaths/Shadowbringers/MSQ/I-5.3/3775_Faded Memories.json b/QuestPaths/Shadowbringers/MSQ/I-5.3/3775_Faded Memories.json index 9955355d..c053f22e 100644 --- a/QuestPaths/Shadowbringers/MSQ/I-5.3/3775_Faded Memories.json +++ b/QuestPaths/Shadowbringers/MSQ/I-5.3/3775_Faded Memories.json @@ -15,6 +15,7 @@ "Y": -2.0168546E-08, "Z": 1.9378662 }, + "StopDistance": 5, "TerritoryId": 819, "InteractionType": "AcceptQuest" } @@ -80,7 +81,27 @@ }, "TerritoryId": 918, "InteractionType": "SinglePlayerDuty", - "Comment": "Fight NPCs, then Elidibus" + "Comment": "Fight NPCs, then Elidibus", + "DialogueChoices": [ + { + "Type": "List", + "ExcelSheet": "ContentTalk", + "Prompt": 209, + "Answer": 211 + }, + { + "Type": "List", + "ExcelSheet": "ContentTalk", + "Prompt": 209, + "Answer": 216 + }, + { + "Type": "List", + "ExcelSheet": "ContentTalk", + "Prompt": 241, + "Answer": 222 + } + ] } ] }, diff --git a/QuestPaths/quest-v1.json b/QuestPaths/quest-v1.json index 32f9de52..dbf3465a 100644 --- a/QuestPaths/quest-v1.json +++ b/QuestPaths/quest-v1.json @@ -394,7 +394,8 @@ "FlyingUnlocked", "DifferentTerritory", "ChocoboUnlocked", - "AetheryteShortcutIfInSameTerritory" + "AetheryteShortcutIfInSameTerritory", + "NotTargetable" ] } }, diff --git a/Questionable.Model/V1/Converter/SkipConditionConverter.cs b/Questionable.Model/V1/Converter/SkipConditionConverter.cs index 3ae25769..adf008ba 100644 --- a/Questionable.Model/V1/Converter/SkipConditionConverter.cs +++ b/Questionable.Model/V1/Converter/SkipConditionConverter.cs @@ -11,5 +11,6 @@ public sealed class SkipConditionConverter() : EnumConverter(Val { ESkipCondition.FlyingUnlocked, "FlyingUnlocked" }, { ESkipCondition.ChocoboUnlocked, "ChocoboUnlocked" }, { ESkipCondition.AetheryteShortcutIfInSameTerritory, "AetheryteShortcutIfInSameTerritory" }, + { ESkipCondition.NotTargetable, "NotTargetable" }, }; } diff --git a/Questionable.Model/V1/ESkipCondition.cs b/Questionable.Model/V1/ESkipCondition.cs index fd8ee6a3..3ece172b 100644 --- a/Questionable.Model/V1/ESkipCondition.cs +++ b/Questionable.Model/V1/ESkipCondition.cs @@ -12,4 +12,5 @@ public enum ESkipCondition FlyingUnlocked, ChocoboUnlocked, AetheryteShortcutIfInSameTerritory, + NotTargetable, } diff --git a/Questionable/Controller/GameUiController.cs b/Questionable/Controller/GameUiController.cs index 29071202..fdbf7d1c 100644 --- a/Questionable/Controller/GameUiController.cs +++ b/Questionable/Controller/GameUiController.cs @@ -162,7 +162,7 @@ internal sealed class GameUiController : IDisposable return; } - var currentQuest = _questController.CurrentQuest; + var currentQuest = _questController.StartedQuest; if (currentQuest != null && actualPrompt == null) { // it is possible for this to be a quest selection @@ -177,7 +177,7 @@ internal sealed class GameUiController : IDisposable private int? HandleListChoice(string? actualPrompt, List answers, bool checkAllSteps) { List dialogueChoices = []; - var currentQuest = _questController.CurrentQuest; + var currentQuest = _questController.StartedQuest; if (currentQuest != null) { var quest = currentQuest.Quest; @@ -305,7 +305,7 @@ internal sealed class GameUiController : IDisposable _logger.LogTrace("Prompt: '{Prompt}'", actualPrompt); - var currentQuest = _questController.CurrentQuest; + var currentQuest = _questController.StartedQuest; if (currentQuest == null) return; @@ -421,7 +421,7 @@ internal sealed class GameUiController : IDisposable private unsafe void PointMenuPostSetup(AtkUnitBase* addonPointMenu) { - var currentQuest = _questController.CurrentQuest; + var currentQuest = _questController.StartedQuest; if (currentQuest == null) { _logger.LogInformation("Ignoring point menu, no active quest"); @@ -471,7 +471,7 @@ internal sealed class GameUiController : IDisposable private unsafe void UnendingCodexPostSetup(AddonEvent type, AddonArgs args) { - if (_questController.CurrentQuest?.Quest.QuestId == 4526) + if (_questController.StartedQuest?.Quest.QuestId == 4526) { _logger.LogInformation("Closing Unending Codex"); AtkUnitBase* addon = (AtkUnitBase*)args.Addon; @@ -481,7 +481,7 @@ internal sealed class GameUiController : IDisposable private unsafe void ContentsTutorialPostSetup(AddonEvent type, AddonArgs args) { - if (_questController.CurrentQuest?.Quest.QuestId == 245) + if (_questController.StartedQuest?.Quest.QuestId == 245) { _logger.LogInformation("Closing ContentsTutorial"); AtkUnitBase* addon = (AtkUnitBase*)args.Addon; @@ -491,7 +491,7 @@ internal sealed class GameUiController : IDisposable private unsafe void MultipleHelpWindowPostSetup(AddonEvent type, AddonArgs args) { - if (_questController.CurrentQuest?.Quest.QuestId == 245) + if (_questController.StartedQuest?.Quest.QuestId == 245) { _logger.LogInformation("Closing MultipleHelpWindow"); AtkUnitBase* addon = (AtkUnitBase*)args.Addon; diff --git a/Questionable/Controller/QuestController.cs b/Questionable/Controller/QuestController.cs index 221bb224..e00ab5d3 100644 --- a/Questionable/Controller/QuestController.cs +++ b/Questionable/Controller/QuestController.cs @@ -5,6 +5,7 @@ using Dalamud.Game.ClientState.Keys; using Dalamud.Plugin.Services; using Microsoft.Extensions.Logging; using Questionable.Controller.Steps; +using Questionable.Controller.Steps.BaseFactory; using Questionable.External; using Questionable.Model; using Questionable.Model.V1; @@ -55,19 +56,24 @@ internal sealed class QuestController _taskFactories = taskFactories.ToList().AsReadOnly(); } - public QuestProgress? CurrentQuest + public (QuestProgress Progress, CurrentQuestType Type)? CurrentQuestDetails { get { if (_simulatedQuest != null) - return _simulatedQuest; + return (_simulatedQuest, CurrentQuestType.Simulated); else if (_nextQuest != null && _gameFunctions.IsReadyToAcceptQuest(_nextQuest.Quest.QuestId)) - return _nextQuest; + return (_nextQuest, CurrentQuestType.Next); + else if (_startedQuest != null) + return (_startedQuest, CurrentQuestType.Normal); else - return _startedQuest; + return null; } } + public QuestProgress? CurrentQuest => CurrentQuestDetails?.Progress; + + public QuestProgress? StartedQuest => _startedQuest; public QuestProgress? SimulatedQuest => _simulatedQuest; public QuestProgress? NextQuest => _nextQuest; @@ -106,7 +112,6 @@ internal sealed class QuestController if (CurrentQuest != null && CurrentQuest.Quest.Root.TerritoryBlacklist.Contains(_clientState.TerritoryType)) return; - // not verified to work if (_automatic && _currentTask == null && _taskQueue.Count == 0 && CurrentQuest is { Sequence: 0, Step: 0 } or { Sequence: 0, Step: 255 } && DateTime.Now >= CurrentQuest.StepProgress.StartedAt.AddSeconds(15)) @@ -140,12 +145,16 @@ internal sealed class QuestController // if the quest is accepted, we no longer track it if (_gameFunctions.IsQuestAcceptedOrComplete(_nextQuest.Quest.QuestId)) { + _logger.LogInformation("Next quest {QuestId} accepted or completed", _nextQuest.Quest.QuestId); + _nextQuest = null; currentSequence = 0; } else { currentSequence = _nextQuest.Sequence; // by definition, this should always be 0 + if (_nextQuest.Step == 0 && _currentTask == null && _taskQueue.Count == 0 && _automatic) + ExecuteNextStep(true); } } @@ -325,6 +334,8 @@ internal sealed class QuestController { if (CurrentQuest?.Step is >= 0 and < 255) ExecuteNextStep(true); + else + _logger.LogInformation("Couldn't execute next step during Stop() call"); } else if (_automatic) { @@ -422,6 +433,10 @@ internal sealed class QuestController case ETaskResult.TaskComplete: _logger.LogInformation("{Task} → {Result}, remaining tasks: {RemainingTaskCount}", _currentTask, result, _taskQueue.Count); + + if (_currentTask is WaitAtEnd.WaitQuestCompleted) + _simulatedQuest = null; + _currentTask = null; // handled in next update @@ -566,7 +581,19 @@ internal sealed class QuestController } } + public void SkipSimulatedTask() + { + _currentTask = null; + } + public sealed record StepProgress( DateTime StartedAt, int PointMenuCounter = 0); + + public enum CurrentQuestType + { + Normal, + Next, + Simulated, + } } diff --git a/Questionable/Controller/Steps/BaseFactory/SkipCondition.cs b/Questionable/Controller/Steps/BaseFactory/SkipCondition.cs index 6757aa20..d31f46e6 100644 --- a/Questionable/Controller/Steps/BaseFactory/SkipCondition.cs +++ b/Questionable/Controller/Steps/BaseFactory/SkipCondition.cs @@ -1,6 +1,8 @@ using System; using System.Collections.Generic; using System.Linq; +using Dalamud.Game.ClientState.Objects.Types; +using Dalamud.Plugin.Services; using FFXIVClientStructs.FFXIV.Application.Network.WorkDefinitions; using FFXIVClientStructs.FFXIV.Client.Game.UI; using FFXIVClientStructs.FFXIV.Client.System.Framework; @@ -32,7 +34,8 @@ internal static class SkipCondition internal sealed class CheckTask( ILogger logger, - GameFunctions gameFunctions) : ITask + GameFunctions gameFunctions, + IClientState clientState) : ITask { public QuestStep Step { get; set; } = null!; public List SkipConditions { get; set; } = null!; @@ -71,6 +74,25 @@ internal static class SkipCondition return true; } + if (SkipConditions.Contains(ESkipCondition.NotTargetable) && + Step is { DataId: not null }) + { + IGameObject? gameObject = gameFunctions.FindObjectByDataId(Step.DataId.Value); + if (gameObject == null) + { + if ((Step.Position.GetValueOrDefault() - clientState.LocalPlayer!.Position).Length() < 100) + { + logger.LogInformation("Skipping step, object is not nearby (but we are)"); + return true; + } + } + else if (!gameObject.IsTargetable) + { + logger.LogInformation("Skipping step, object is not targetable"); + return true; + } + } + if (Step is { DataId: not null, diff --git a/Questionable/Data/QuestData.cs b/Questionable/Data/QuestData.cs index 3a2c5682..1d309750 100644 --- a/Questionable/Data/QuestData.cs +++ b/Questionable/Data/QuestData.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using Dalamud.Game.ClientState.Objects; +using Dalamud.Game.Text; using Dalamud.Plugin.Services; using Questionable.Model; using Quest = Lumina.Excel.GeneratedSheets.Quest; @@ -40,6 +41,8 @@ internal sealed class QuestData .ToList(); } + public bool IsIssuerOfAnyQuest(uint targetId) => _quests.Values.Any(x => x.IssuerDataId == targetId); + public void ShowQuestsIssuedByTarget() { var targetId = _targetManager.Target?.DataId; @@ -53,6 +56,6 @@ internal sealed class QuestData _chatGui.Print($"{quests.Count} quest(s) issued by target {_targetManager.Target?.Name}:"); foreach (QuestInfo quest in quests) - _chatGui.Print($" {quest.QuestId}: {quest.Name}"); + _chatGui.Print($" {quest.QuestId}_{quest.SimplifiedName}"); } } diff --git a/Questionable/Model/QuestInfo.cs b/Questionable/Model/QuestInfo.cs index 67301801..f0902fd1 100644 --- a/Questionable/Model/QuestInfo.cs +++ b/Questionable/Model/QuestInfo.cs @@ -1,4 +1,6 @@ -using ExcelQuest = Lumina.Excel.GeneratedSheets.Quest; +using System; +using Dalamud.Game.Text; +using ExcelQuest = Lumina.Excel.GeneratedSheets.Quest; namespace Questionable.Model; @@ -16,4 +18,7 @@ internal sealed class QuestInfo public string Name { get; } public ushort Level { get; } public uint IssuerDataId { get; } + + public string SimplifiedName => Name + .TrimStart(SeIconChar.QuestSync.ToIconChar(), SeIconChar.QuestRepeatable.ToIconChar(), ' '); } diff --git a/Questionable/Windows/DebugOverlay.cs b/Questionable/Windows/DebugOverlay.cs index bbbc4302..902d247a 100644 --- a/Questionable/Windows/DebugOverlay.cs +++ b/Questionable/Windows/DebugOverlay.cs @@ -100,6 +100,6 @@ internal sealed class DebugOverlay : Window ImGui.GetWindowDrawList().AddCircleFilled(screenPos, 3f, color); ImGui.GetWindowDrawList().AddText(screenPos + new Vector2(10, -8), color, - $"{counter}: {step.InteractionType}\n{step.Position.Value.ToString("G", CultureInfo.InvariantCulture)}\n{step.Comment}"); + $"{counter}: {step.InteractionType}\n{step.Position.Value.ToString("G", CultureInfo.InvariantCulture)} [{(step.Position.Value - _clientState.LocalPlayer!.Position).Length():N2}]\n{step.Comment}"); } } diff --git a/Questionable/Windows/QuestWindow.cs b/Questionable/Windows/QuestWindow.cs index 2a47215a..0a6b8102 100644 --- a/Questionable/Windows/QuestWindow.cs +++ b/Questionable/Windows/QuestWindow.cs @@ -119,10 +119,37 @@ internal sealed class QuestWindow : LWindow, IPersistableWindowConfig private void DrawQuest() { - var currentQuest = _questController.CurrentQuest; + var currentQuestDetails = _questController.CurrentQuestDetails; + QuestController.QuestProgress? currentQuest = currentQuestDetails?.Progress; + QuestController.CurrentQuestType? currentQuestType = currentQuestDetails?.Type; if (currentQuest != null) { - ImGui.TextUnformatted($"Quest: {currentQuest.Quest.Info.Name} / {currentQuest.Sequence} / {currentQuest.Step}"); + if (currentQuestType == QuestController.CurrentQuestType.Simulated) + { + var simulatedQuest = _questController.SimulatedQuest ?? currentQuest; + using var _ = ImRaii.PushColor(ImGuiCol.Text, 0xFF0000FF); + ImGui.TextUnformatted( + $"Simulated Quest: {simulatedQuest.Quest.Info.Name} / {simulatedQuest.Sequence} / {simulatedQuest.Step}"); + } + else if (currentQuestType == QuestController.CurrentQuestType.Next) + { + var startedQuest = _questController.StartedQuest; + if (startedQuest != null) + { + ImGui.TextUnformatted( + $"Quest: {startedQuest.Quest.Info.Name} / {startedQuest.Sequence} / {startedQuest.Step}"); + } + + using var _ = ImRaii.PushColor(ImGuiCol.Text, 0xFF00FFFF); + ImGui.TextUnformatted( + $"Next Quest: {currentQuest.Quest.Info.Name} / {currentQuest.Sequence} / {currentQuest.Step}"); + } + else + { + ImGui.TextUnformatted( + $"Quest: {currentQuest.Quest.Info.Name} / {currentQuest.Sequence} / {currentQuest.Step}"); + } + ImGui.BeginDisabled(); var questWork = _gameFunctions.GetQuestEx(currentQuest.Quest.QuestId); @@ -295,6 +322,12 @@ internal sealed class QuestWindow : LWindow, IPersistableWindowConfig ImGui.EndDisabled(); + if (ImGui.Button("Skip current task")) + { + _questController.SkipSimulatedTask(); + } + + ImGui.SameLine(); if (ImGui.Button("Clear sim")) { _questController.SimulateQuest(null); @@ -378,7 +411,7 @@ internal sealed class QuestWindow : LWindow, IPersistableWindowConfig ImGui.EndDisabled(); ImGui.SameLine(); - ImGui.BeginDisabled(gameObject->NamePlateIconId == 0); + ImGui.BeginDisabled(!_questData.IsIssuerOfAnyQuest(_targetManager.Target.DataId)); if (ImGuiComponents.IconButton(FontAwesomeIcon.Bars)) _questData.ShowQuestsIssuedByTarget(); ImGui.EndDisabled();