From f9c7b6c7623589f75458059bf8725871a81e8146 Mon Sep 17 00:00:00 2001 From: Liza Carvelli Date: Thu, 1 Aug 2024 00:40:38 +0200 Subject: [PATCH 01/12] Daily quest update --- .../Pixies/Dailies/3716_The Chaser.json | 30 +++- .../Tribal/Pixies/Dailies/3716_The Chaser.md | 3 + .../Dailies/4578_Steep the Legs.json | 67 ++++++++- .../Story/4548_Defiant Ogul, Deified.json | 134 ++++++++++++++++++ 4 files changed, 231 insertions(+), 3 deletions(-) create mode 100644 QuestPaths/5.x - Shadowbringers/Tribal/Pixies/Dailies/3716_The Chaser.md create mode 100644 QuestPaths/6.x - Endwalker/Tribal/Arkasodara/Story/4548_Defiant Ogul, Deified.json diff --git a/QuestPaths/5.x - Shadowbringers/Tribal/Pixies/Dailies/3716_The Chaser.json b/QuestPaths/5.x - Shadowbringers/Tribal/Pixies/Dailies/3716_The Chaser.json index 06f47e6e..750ac0b7 100644 --- a/QuestPaths/5.x - Shadowbringers/Tribal/Pixies/Dailies/3716_The Chaser.json +++ b/QuestPaths/5.x - Shadowbringers/Tribal/Pixies/Dailies/3716_The Chaser.json @@ -31,7 +31,35 @@ "InteractionType": "UseItem", "ItemId": 2002943, "AetheryteShortcut": "Il Mheg - Pia Enni", - "Fly": true + "Fly": true, + "RequiredQuestVariables": [ + null, + null, + [1], + null, + null, + null + ] + }, + { + "DataId": 1032202, + "Position": { + "X": 10.849121, + "Y": 100.161, + "Z": -886.22876 + }, + "TerritoryId": 816, + "InteractionType": "UseItem", + "ItemId": 2002943, + "Fly": true, + "RequiredQuestVariables": [ + null, + null, + [2], + null, + null, + null + ] } ] }, diff --git a/QuestPaths/5.x - Shadowbringers/Tribal/Pixies/Dailies/3716_The Chaser.md b/QuestPaths/5.x - Shadowbringers/Tribal/Pixies/Dailies/3716_The Chaser.md new file mode 100644 index 00000000..352f3b22 --- /dev/null +++ b/QuestPaths/5.x - Shadowbringers/Tribal/Pixies/Dailies/3716_The Chaser.md @@ -0,0 +1,3 @@ +0 0 ? 0 0 0 + 1 → 1032203 + 2 → 1032202 diff --git a/QuestPaths/6.x - Endwalker/Tribal/Arkasodara/Dailies/4578_Steep the Legs.json b/QuestPaths/6.x - Endwalker/Tribal/Arkasodara/Dailies/4578_Steep the Legs.json index 42a2b0f7..c10304a9 100644 --- a/QuestPaths/6.x - Endwalker/Tribal/Arkasodara/Dailies/4578_Steep the Legs.json +++ b/QuestPaths/6.x - Endwalker/Tribal/Arkasodara/Dailies/4578_Steep the Legs.json @@ -1,7 +1,6 @@ { "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/QuestPaths/quest-v1.json", "Author": "liza", - "Disabled": true, "QuestSequence": [ { "Sequence": 0, @@ -21,7 +20,71 @@ { "Sequence": 1, "Steps": [ - + { + "DataId": 2012915, + "Position": { + "X": -383.505, + "Y": 1.0527954, + "Z": 362.99683 + }, + "TerritoryId": 957, + "InteractionType": "Combat", + "EnemySpawnType": "AfterInteraction", + "KillEnemyDataIds": [ + 14680 + ], + "Fly": true, + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 32 + ] + }, + { + "DataId": 2012914, + "Position": { + "X": -399.83215, + "Y": 1.6326294, + "Z": 291.73718 + }, + "TerritoryId": 957, + "InteractionType": "Interact", + "Fly": true, + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 64 + ] + }, + { + "DataId": 2012913, + "Position": { + "X": -444.0528, + "Y": 0.38146973, + "Z": 249.53076 + }, + "TerritoryId": 957, + "InteractionType": "Combat", + "EnemySpawnType": "AfterInteraction", + "KillEnemyDataIds": [ + 14680 + ], + "Fly": true, + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 128 + ] + } ] }, { diff --git a/QuestPaths/6.x - Endwalker/Tribal/Arkasodara/Story/4548_Defiant Ogul, Deified.json b/QuestPaths/6.x - Endwalker/Tribal/Arkasodara/Story/4548_Defiant Ogul, Deified.json new file mode 100644 index 00000000..69172cff --- /dev/null +++ b/QuestPaths/6.x - Endwalker/Tribal/Arkasodara/Story/4548_Defiant Ogul, Deified.json @@ -0,0 +1,134 @@ +{ + "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/QuestPaths/quest-v1.json", + "Author": "liza", + "QuestSequence": [ + { + "Sequence": 0, + "Steps": [ + { + "DataId": 1042300, + "Position": { + "X": -76.82922, + "Y": 39.977543, + "Z": 309.98706 + }, + "TerritoryId": 957, + "InteractionType": "AcceptQuest" + } + ] + }, + { + "Sequence": 1, + "Steps": [ + { + "DataId": 1042336, + "Position": { + "X": 409.964, + "Y": 18.253498, + "Z": -461.53967 + }, + "TerritoryId": 957, + "InteractionType": "Interact", + "AetheryteShortcut": "Thavnair - Palaka's Stand", + "Fly": true + } + ] + }, + { + "Sequence": 2, + "Steps": [ + { + "DataId": 2012970, + "Position": { + "X": 197.4364, + "Y": 9.323181, + "Z": -438.71216 + }, + "TerritoryId": 957, + "InteractionType": "Interact", + "Fly": true, + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 64 + ] + }, + { + "DataId": 2012924, + "Position": { + "X": 179.33923, + "Y": 7.309021, + "Z": -392.44684 + }, + "TerritoryId": 957, + "InteractionType": "Combat", + "EnemySpawnType": "AfterInteraction", + "KillEnemyDataIds": [ + 14683 + ], + "Fly": true, + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 128 + ] + } + ] + }, + { + "Sequence": 3, + "Steps": [ + { + "DataId": 1042339, + "Position": { + "X": 145.95251, + "Y": 9.608223, + "Z": -234.24127 + }, + "TerritoryId": 957, + "InteractionType": "Interact", + "Fly": true + } + ] + }, + { + "Sequence": 4, + "Steps": [ + { + "DataId": 1042343, + "Position": { + "X": 142.53455, + "Y": 10.132848, + "Z": -232.89844 + }, + "StopDistance": 7, + "TerritoryId": 957, + "InteractionType": "Interact" + } + ] + }, + { + "Sequence": 255, + "Steps": [ + { + "DataId": 1042300, + "Position": { + "X": -76.82922, + "Y": 39.977543, + "Z": 309.98706 + }, + "TerritoryId": 957, + "InteractionType": "CompleteQuest", + "AetheryteShortcut": "Thavnair - Yedlihmad", + "Fly": true + } + ] + } + ] +} From becfac28ad659ea6ecf49afae7f39294261774c7 Mon Sep 17 00:00:00 2001 From: Liza Carvelli Date: Thu, 1 Aug 2024 00:40:52 +0200 Subject: [PATCH 02/12] Add Esuna as action --- QuestPaths/quest-v1.json | 1 + Questionable.Model/V1/Converter/ActionConverter.cs | 1 + Questionable.Model/V1/EAction.cs | 1 + 3 files changed, 3 insertions(+) diff --git a/QuestPaths/quest-v1.json b/QuestPaths/quest-v1.json index 60629b40..8cda540c 100644 --- a/QuestPaths/quest-v1.json +++ b/QuestPaths/quest-v1.json @@ -736,6 +736,7 @@ "type": "string", "description": "The action to use", "enum": [ + "Cure", "Esuna", "Physick", "Buffet", diff --git a/Questionable.Model/V1/Converter/ActionConverter.cs b/Questionable.Model/V1/Converter/ActionConverter.cs index 67a32a8d..eaf5baac 100644 --- a/Questionable.Model/V1/Converter/ActionConverter.cs +++ b/Questionable.Model/V1/Converter/ActionConverter.cs @@ -6,6 +6,7 @@ public sealed class ActionConverter() : EnumConverter(Values) { private static readonly Dictionary Values = new() { + { EAction.Cure, "Cure" }, { EAction.Esuna, "Esuna" }, { EAction.Physick, "Physick" }, { EAction.Buffet, "Buffet" }, diff --git a/Questionable.Model/V1/EAction.cs b/Questionable.Model/V1/EAction.cs index b83e6c86..8aca752f 100644 --- a/Questionable.Model/V1/EAction.cs +++ b/Questionable.Model/V1/EAction.cs @@ -6,6 +6,7 @@ namespace Questionable.Model.V1; [JsonConverter(typeof(ActionConverter))] public enum EAction { + Cure = 120, Esuna = 7568, Physick = 190, Buffet = 4931, From d64cd9d5fc57515756048ebe7435aa420e6c038a Mon Sep 17 00:00:00 2001 From: Liza Carvelli Date: Thu, 1 Aug 2024 03:22:01 +0200 Subject: [PATCH 03/12] Update CompletionQuestVariablesFlags for skip checking --- QuestPathGenerator/RoslynShortcuts.cs | 7 +- .../GLA/253_Way of the Gladiator.json | 178 ++++++++++- .../GLA/256_Kicking the Hornet's Nest.json | 286 ++++++++++++++++++ .../SCH/1098_The Last Remnants.json | 80 +++-- .../SCH/1101_For Your Fellow Man.json | 36 ++- .../WAR/1052_Looking the Part.json | 78 +++-- .../MSQ-1/Gridania/377_Don't Look Down.json | 80 +++-- .../MSQ-1/Limsa/465_Washed Up.json | 20 +- .../MSQ-1/Shared/574_Dressed to Deceive.json | 20 +- .../MSQ-1/Ul'dah/671_Nothing to See Here.json | 20 +- .../738_Sylphish Concerns.json | 80 +++-- .../889_Three for Three.json | 20 +- .../897_The Talk of Coerthas.json | 20 +- .../960_It's Probably Not Pirates.json | 40 ++- .../1001_Drowning Out the Voices.json | 40 ++- .../E3-2.3/1460_Brave New Companions.json | 20 +- .../Raid Quests/1709_Legacy of Allag.json | 160 ++++++---- .../Story/1321_How Low Can You Go.json | 20 +- .../1828_Hide Your Moogles.json | 100 +++--- .../1771_Some Bad News.json | 100 +++--- .../1797_The Hunter Becomes the Kweh.json | 100 +++--- .../1593_Sense of Urgency.json | 40 ++- .../1662_Hour of Departure.json | 40 ++- .../Ananta/Dailies/3064_Thin-skinned.json | 120 +++++--- .../Lakeland/3380_A Jobb Well Done.json | 100 +++--- .../Lakeland/3384_Imperative Repairs.json | 40 ++- .../B-Il Mheg/3305_The Oracle of Light.json | 20 +- .../MSQ/B-Il Mheg/3307_Sul Uin's Request.json | 40 ++- .../MSQ/B-Il Mheg/3315_Spore Sweeper.json | 40 ++- .../MSQ/B-Il Mheg/3316_The Lawless Ones.json | 120 +++++--- .../C-Rak'tika/3335_Look to the Stars.json | 100 +++--- .../MSQ/E-Kholusia 2/3633_The Ladder.json | 40 ++- .../MSQ/F-Tempest/3645_In His Garden.json | 20 +- ...689_Where There's Wool, There's a Way.json | 40 ++- .../4241_Carrots Its Whats for Dinner.json | 280 ++++++++++------- .../Thavnair/4203_Alchemist or Dancer.json | 20 +- .../Thavnair/4259_Radiant Patrol.json | 2 +- .../B-Garlemald/4389_Personae non Gratae.json | 20 +- .../B-Garlemald/4393_Strange Bedfellows.json | 60 ++-- .../4410_The Blasphemy Unmasked.json | 20 +- .../MSQ/E-Elpis/4420_Hope Upon a Flower.json | 20 +- .../4456_Roads Paved of Sacrifice.json | 20 +- .../MSQ/H-6.1/4531_Sharing the Wealth.json | 20 +- .../Thavnair/4491_Ogul Repays Her Favors.json | 60 ++-- .../Thavnair/4495_The Sins We Bear.json | 60 ++-- .../Dailies/4557_Gulal Generosity.json | 60 ++-- .../Dailies/4564_Olfactory Warfare.json | 62 ++-- .../Arkasodara/Dailies/4570_Patching Up.json | 60 ++-- .../Dailies/4573_Gathering Moss.json | 20 +- .../Dailies/4574_Blood from a Stonemason.json | 20 +- .../5047_An Illuminating Ritual.json | 20 +- .../4892_An Echo of Madness.json | 20 +- .../MSQ/C-Yak T'el/4907_Mamook Speaks.json | 40 ++- .../4927_The Land of Levin.json | 20 +- .../4952_A Knight of Alexandria.json | 20 +- .../Heritage Found/5155_History Reforged.json | 40 ++- .../Kozama'uka/5075_Water Colors.json | 20 +- .../5175_The Canals of History.json | 20 +- .../5181_Leaving This Place for Good.json | 40 ++- .../Shaaloani/5121_Taste of the Wilds.json | 40 ++- .../Shaaloani/5132_Death by Popoto.json | 20 +- .../Shaaloani/5142_Back on Stage.json | 48 +-- .../Shaaloani/5148_Dig for Victory.json | 16 +- .../Side Quests/Yak T'el/5097_Sick Day.json | 20 +- .../Yak T'el/5098_To Forge in the Forest.json | 60 ++-- .../Yak T'el/5101_Two Hearts Aflutter.json | 80 +++-- QuestPaths/AssemblyQuestLoader.cs | 1 + QuestPaths/quest-v1.json | 82 +++-- Questionable.Model/V1/ComplexCombatData.cs | 2 +- .../V1/Converter/QuestWorkConfigConverter.cs | 7 +- .../V1/Converter/QuestWorkModeConverter.cs | 12 + .../Converter/StringListOrValueConverter.cs | 2 +- Questionable.Model/V1/EQuestWorkMode.cs | 11 + Questionable.Model/V1/QuestStep.cs | 2 +- Questionable.Model/V1/QuestWorkValue.cs | 20 +- Questionable.Model/V1/SkipStepConditions.cs | 11 +- Questionable/Controller/CombatController.cs | 2 +- .../Controller/Steps/Interactions/Combat.cs | 6 +- .../Controller/Steps/Interactions/UseItem.cs | 12 +- .../Controller/Steps/Shared/SkipCondition.cs | 20 +- .../Controller/Steps/Shared/WaitAtEnd.cs | 8 +- .../Controller/Utils/QuestWorkUtils.cs | 46 +-- .../Validators/CompletionFlagsValidator.cs | 13 +- 83 files changed, 2510 insertions(+), 1340 deletions(-) create mode 100644 QuestPaths/2.x - A Realm Reborn/Class Quests/GLA/256_Kicking the Hornet's Nest.json create mode 100644 Questionable.Model/V1/Converter/QuestWorkModeConverter.cs create mode 100644 Questionable.Model/V1/EQuestWorkMode.cs diff --git a/QuestPathGenerator/RoslynShortcuts.cs b/QuestPathGenerator/RoslynShortcuts.cs index 63ccdcd6..2bacaba4 100644 --- a/QuestPathGenerator/RoslynShortcuts.cs +++ b/QuestPathGenerator/RoslynShortcuts.cs @@ -213,7 +213,9 @@ public static class RoslynShortcuts { Argument(LiteralValue(qwv.High)), Token(SyntaxKind.CommaToken), - Argument(LiteralValue(qwv.Low)) + Argument(LiteralValue(qwv.Low)), + Token(SyntaxKind.CommaToken), + Argument(LiteralValue(qwv.Mode)) }))); } else if (value is List list) @@ -255,6 +257,9 @@ public static class RoslynShortcuts Assignment(nameof(SkipStepConditions.Never), skipStepConditions.Never, emptyStep.Never) .AsSyntaxNodeOrToken(), + AssignmentList(nameof(SkipStepConditions.CompletionQuestVariablesFlags), + skipStepConditions.CompletionQuestVariablesFlags) + .AsSyntaxNodeOrToken(), Assignment(nameof(SkipStepConditions.Flying), skipStepConditions.Flying, emptyStep.Flying) .AsSyntaxNodeOrToken(), diff --git a/QuestPaths/2.x - A Realm Reborn/Class Quests/GLA/253_Way of the Gladiator.json b/QuestPaths/2.x - A Realm Reborn/Class Quests/GLA/253_Way of the Gladiator.json index 790d5671..09113bd9 100644 --- a/QuestPaths/2.x - A Realm Reborn/Class Quests/GLA/253_Way of the Gladiator.json +++ b/QuestPaths/2.x - A Realm Reborn/Class Quests/GLA/253_Way of the Gladiator.json @@ -1,7 +1,6 @@ { "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/QuestPaths/quest-v1.json", "Author": "liza", - "Disabled": true, "QuestSequence": [ { "Sequence": 0, @@ -24,6 +23,183 @@ ] } ] + }, + { + "Sequence": 1, + "Steps": [ + { + "DataId": 1001739, + "Position": { + "X": -94.529724, + "Y": 6.4999976, + "Z": 39.81079 + }, + "TerritoryId": 131, + "InteractionType": "Interact", + "DialogueChoices": [ + { + "Type": "YesNo", + "Prompt": "TEXT_CLSGLA020_00253_Q2_000_1", + "Yes": true + } + ] + } + ] + }, + { + "Sequence": 2, + "Steps": [ + { + "Position": { + "X": 45.13088, + "Y": 3.889354, + "Z": -166.51999 + }, + "TerritoryId": 130, + "InteractionType": "WalkTo", + "AethernetShortcut": [ + "[Ul'dah] Gladiators' Guild", + "[Ul'dah] Adventurers' Guild" + ], + "SkipConditions": { + "StepIf": { + "InTerritory": [ + 141 + ] + } + } + }, + { + "Position": { + "X": -116.10664, + "Y": 10.801613, + "Z": 276.979 + }, + "TerritoryId": 141, + "InteractionType": "Combat", + "EnemySpawnType": "OverworldEnemies", + "ComplexCombatData": [ + { + "DataId": 351, + "MinimumKillCount": 3, + "CompletionQuestVariablesFlags": [ + { + "Low": 3, + "Mode": "Exact" + }, + null, + null, + null, + null, + null + ] + }, + { + "DataId": 141, + "MinimumKillCount": 3, + "CompletionQuestVariablesFlags": [ + null, + { + "High": 3, + "Mode": "Exact" + }, + null, + null, + null, + null + ] + } + ], + "CompletionQuestVariablesFlags": [ + { + "Low": 3, + "Mode": "Exact" + }, + { + "High": 3, + "Mode": "Exact" + }, + null, + null, + null, + null + ] + }, + { + "Position": { + "X": 39.635372, + "Y": 3.2401803, + "Z": 273.41232 + }, + "TerritoryId": 141, + "InteractionType": "Combat", + "EnemySpawnType": "OverworldEnemies", + "ComplexCombatData": [ + { + "DataId": 205, + "MinimumKillCount": 3, + "CompletionQuestVariablesFlags": [ + null, + { + "Low": 3, + "Mode": "Exact" + }, + null, + null, + null, + null + ] + } + ], + "CompletionQuestVariablesFlags": [ + null, + { + "Low": 3, + "Mode": "Exact" + }, + null, + null, + null, + null + ] + } + ] + }, + { + "Sequence": 255, + "Steps": [ + { + "Position": { + "X": -118.17538, + "Y": 18.35357, + "Z": 341.3039 + }, + "TerritoryId": 141, + "InteractionType": "WalkTo", + "SkipConditions": { + "StepIf": { + "NotInTerritory": [ + 141 + ] + } + } + }, + { + "DataId": 1001739, + "Position": { + "X": -94.529724, + "Y": 6.4999976, + "Z": 39.81079 + }, + "TerritoryId": 131, + "InteractionType": "CompleteQuest", + "AethernetShortcut": [ + "[Ul'dah] Adventurers' Guild", + "[Ul'dah] Gladiators' Guild" + ], + "NextQuestId": 256 + } + ] } ] } diff --git a/QuestPaths/2.x - A Realm Reborn/Class Quests/GLA/256_Kicking the Hornet's Nest.json b/QuestPaths/2.x - A Realm Reborn/Class Quests/GLA/256_Kicking the Hornet's Nest.json new file mode 100644 index 00000000..88320c09 --- /dev/null +++ b/QuestPaths/2.x - A Realm Reborn/Class Quests/GLA/256_Kicking the Hornet's Nest.json @@ -0,0 +1,286 @@ +{ + "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/QuestPaths/quest-v1.json", + "Author": "liza", + "QuestSequence": [ + { + "Sequence": 0, + "Steps": [ + { + "DataId": 1001739, + "Position": { + "X": -94.529724, + "Y": 6.4999976, + "Z": 39.81079 + }, + "TerritoryId": 131, + "InteractionType": "AcceptQuest" + } + ] + }, + { + "Sequence": 1, + "Steps": [ + { + "DataId": 1003990, + "Position": { + "X": 77.25635, + "Y": 4.0999947, + "Z": -138.62823 + }, + "TerritoryId": 130, + "InteractionType": "Emote", + "Emote": "me", + "AethernetShortcut": [ + "[Ul'dah] Gladiators' Guild", + "[Ul'dah] Adventurers' Guild" + ], + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 64 + ] + }, + { + "DataId": 1003984, + "Position": { + "X": 45.029297, + "Y": 3.9999998, + "Z": -128.16058 + }, + "TerritoryId": 130, + "InteractionType": "Emote", + "Emote": "me", + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 128 + ] + }, + { + "DataId": 1003992, + "Position": { + "X": 12.191956, + "Y": 4.0999947, + "Z": -155.53528 + }, + "TerritoryId": 130, + "InteractionType": "Emote", + "Emote": "me", + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 32 + ] + }, + { + "DataId": 1003994, + "Position": { + "X": 15.976135, + "Y": 7.9999995, + "Z": -124.071106 + }, + "TerritoryId": 130, + "InteractionType": "Emote", + "Emote": "me", + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 16 + ] + } + ] + }, + { + "Sequence": 2, + "Steps": [ + { + "DataId": 1004222, + "Position": { + "X": 21.927185, + "Y": 7.1999974, + "Z": -97.39838 + }, + "TerritoryId": 130, + "InteractionType": "Emote", + "Emote": "me" + } + ] + }, + { + "Sequence": 3, + "Steps": [ + { + "DataId": 1001353, + "Position": { + "X": 21.072632, + "Y": 7.45, + "Z": -78.78235 + }, + "TerritoryId": 130, + "InteractionType": "Interact" + } + ] + }, + { + "Sequence": 4, + "Steps": [ + { + "DataId": 1001739, + "Position": { + "X": -94.529724, + "Y": 6.4999976, + "Z": 39.81079 + }, + "TerritoryId": 131, + "InteractionType": "Interact", + "AethernetShortcut": [ + "[Ul'dah] Adventurers' Guild", + "[Ul'dah] Gladiators' Guild" + ] + } + ] + }, + { + "Sequence": 5, + "Steps": [ + { + "Position": { + "X": -112.70276, + "Y": 7.7544775, + "Z": 9.123527 + }, + "TerritoryId": 131, + "InteractionType": "WalkTo" + }, + { + "Position": { + "X": -183.00035, + "Y": 13.958975, + "Z": -13.998203 + }, + "TerritoryId": 130, + "InteractionType": "WalkTo" + }, + { + "DataId": 1003985, + "Position": { + "X": 201.52588, + "Y": 52.038116, + "Z": 149.40112 + }, + "TerritoryId": 140, + "InteractionType": "Interact" + } + ] + }, + { + "Sequence": 6, + "Steps": [ + { + "DataId": 2001408, + "Position": { + "X": 154.37549, + "Y": 52.536743, + "Z": 200.91553 + }, + "TerritoryId": 140, + "InteractionType": "Combat", + "EnemySpawnType": "AfterInteraction", + "KillEnemyDataIds": [ + 1246 + ], + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 128 + ] + }, + { + "DataId": 2001409, + "Position": { + "X": 141.83252, + "Y": 52.994507, + "Z": 221.54565 + }, + "TerritoryId": 140, + "InteractionType": "Combat", + "EnemySpawnType": "AfterInteraction", + "KillEnemyDataIds": [ + 1390 + ], + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 64 + ] + } + ] + }, + { + "Sequence": 7, + "Steps": [ + { + "DataId": 1003985, + "Position": { + "X": 201.52588, + "Y": 52.038116, + "Z": 149.40112 + }, + "TerritoryId": 140, + "InteractionType": "Interact" + } + ] + }, + { + "Sequence": 255, + "Steps": [ + { + "Position": { + "X": 473.74796, + "Y": 96.62057, + "Z": 159.993 + }, + "TerritoryId": 140, + "InteractionType": "WalkTo" + }, + { + "Position": { + "X": -117.06801, + "Y": 9.195247, + "Z": 9.181297 + }, + "TerritoryId": 130, + "InteractionType": "WalkTo" + }, + { + "DataId": 1001739, + "Position": { + "X": -94.529724, + "Y": 6.4999976, + "Z": 39.81079 + }, + "TerritoryId": 131, + "InteractionType": "CompleteQuest" + } + ] + } + ] +} diff --git a/QuestPaths/2.x - A Realm Reborn/Class Quests/SCH/1098_The Last Remnants.json b/QuestPaths/2.x - A Realm Reborn/Class Quests/SCH/1098_The Last Remnants.json index 9ba37d45..a7116bac 100644 --- a/QuestPaths/2.x - A Realm Reborn/Class Quests/SCH/1098_The Last Remnants.json +++ b/QuestPaths/2.x - A Realm Reborn/Class Quests/SCH/1098_The Last Remnants.json @@ -37,16 +37,18 @@ "SkipConditions": { "AetheryteShortcutIf": { "NotInSameTerritory": true + }, + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 64 + ] } - }, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -64 - ] + } }, { "DataId": 2002380, @@ -76,14 +78,18 @@ "TerritoryId": 180, "InteractionType": "WalkTo", "Fly": true, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -128 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 128 + ] + } + } }, { "DataId": 2002379, @@ -112,14 +118,18 @@ "TerritoryId": 180, "InteractionType": "WalkTo", "Fly": true, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -16 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 16 + ] + } + } }, { "DataId": 2002382, @@ -148,14 +158,18 @@ "TerritoryId": 180, "InteractionType": "WalkTo", "Fly": true, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -32 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 32 + ] + } + } }, { "DataId": 2002381, diff --git a/QuestPaths/2.x - A Realm Reborn/Class Quests/SCH/1101_For Your Fellow Man.json b/QuestPaths/2.x - A Realm Reborn/Class Quests/SCH/1101_For Your Fellow Man.json index b52d04ba..a2b64690 100644 --- a/QuestPaths/2.x - A Realm Reborn/Class Quests/SCH/1101_For Your Fellow Man.json +++ b/QuestPaths/2.x - A Realm Reborn/Class Quests/SCH/1101_For Your Fellow Man.json @@ -65,14 +65,18 @@ "TerritoryId": 139, "InteractionType": "WalkTo", "Mount": true, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -128 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 128 + ] + } + } }, { "DataId": 1007844, @@ -120,16 +124,16 @@ }, "TerritoryId": 139, "InteractionType": "WalkTo", - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -32 - ], "SkipConditions": { "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 32 + ], "Flying": "Unlocked" } } diff --git a/QuestPaths/2.x - A Realm Reborn/Class Quests/WAR/1052_Looking the Part.json b/QuestPaths/2.x - A Realm Reborn/Class Quests/WAR/1052_Looking the Part.json index 6dcb2e15..5e629673 100644 --- a/QuestPaths/2.x - A Realm Reborn/Class Quests/WAR/1052_Looking the Part.json +++ b/QuestPaths/2.x - A Realm Reborn/Class Quests/WAR/1052_Looking the Part.json @@ -28,18 +28,20 @@ }, "TerritoryId": 155, "InteractionType": "WalkTo", - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -128 - ], "AetheryteShortcut": "Coerthas Central Highlands - Camp Dragonhead", "SkipConditions": { "AetheryteShortcutIf": { "NotInSameTerritory": true + }, + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 128 + ] } }, "Fly": true @@ -56,14 +58,18 @@ "KillEnemyDataIds": [ 1918 ], - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -128 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 128 + ] + } + } }, { "DataId": 2002308, @@ -127,14 +133,18 @@ "InteractionType": "UseItem", "ItemId": 30362, "TargetTerritoryId": 140, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -32 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 32 + ] + } + } }, { "Position": { @@ -148,14 +158,18 @@ "KillEnemyDataIds": [ 1920 ], - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -32 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 32 + ] + } + } }, { "DataId": 2002310, diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-1/Gridania/377_Don't Look Down.json b/QuestPaths/2.x - A Realm Reborn/MSQ-1/Gridania/377_Don't Look Down.json index d4d4a3eb..e3a5ea4f 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-1/Gridania/377_Don't Look Down.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-1/Gridania/377_Don't Look Down.json @@ -65,14 +65,18 @@ }, "TerritoryId": 148, "InteractionType": "WalkTo", - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -128 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 128 + ] + } + } }, { "Position": { @@ -83,14 +87,18 @@ "TerritoryId": 148, "InteractionType": "WalkTo", "DisableNavmesh": true, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -128 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 128 + ] + } + } }, { "DataId": 2000748, @@ -120,14 +128,18 @@ "TerritoryId": 148, "InteractionType": "WalkTo", "DisableNavmesh": true, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -16 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 16 + ] + } + } }, { "Position": { @@ -137,14 +149,18 @@ }, "TerritoryId": 148, "InteractionType": "WalkTo", - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -16 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 16 + ] + } + } }, { "DataId": 2000751, diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-1/Limsa/465_Washed Up.json b/QuestPaths/2.x - A Realm Reborn/MSQ-1/Limsa/465_Washed Up.json index 51da268c..8a9700f8 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-1/Limsa/465_Washed Up.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-1/Limsa/465_Washed Up.json @@ -36,14 +36,18 @@ }, "StopDistance": 3 }, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -8 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 8 + ] + } + } }, { "DataId": 1002639, diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-1/Shared/574_Dressed to Deceive.json b/QuestPaths/2.x - A Realm Reborn/MSQ-1/Shared/574_Dressed to Deceive.json index 982e2df4..75423c9d 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-1/Shared/574_Dressed to Deceive.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-1/Shared/574_Dressed to Deceive.json @@ -64,14 +64,18 @@ }, "StopDistance": 5 }, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -16 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 16 + ] + } + } }, { "DataId": 1004506, diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-1/Ul'dah/671_Nothing to See Here.json b/QuestPaths/2.x - A Realm Reborn/MSQ-1/Ul'dah/671_Nothing to See Here.json index 10b55d22..e9f7f5ad 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-1/Ul'dah/671_Nothing to See Here.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-1/Ul'dah/671_Nothing to See Here.json @@ -65,14 +65,18 @@ "TerritoryId": 141, "InteractionType": "WalkTo", "DisableNavmesh": false, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -128 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 128 + ] + } + } }, { "DataId": 1004599, diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/A3-South Shroud, Buscarron’s Druthers/738_Sylphish Concerns.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/A3-South Shroud, Buscarron’s Druthers/738_Sylphish Concerns.json index d9c68776..e4b2ae37 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/A3-South Shroud, Buscarron’s Druthers/738_Sylphish Concerns.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/A3-South Shroud, Buscarron’s Druthers/738_Sylphish Concerns.json @@ -63,14 +63,18 @@ }, "DelaySeconds": 0.25 }, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -8 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 8 + ] + } + } }, { "DataId": 2001953, @@ -109,14 +113,18 @@ }, "DelaySeconds": 0.25 }, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -32 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 32 + ] + } + } }, { "DataId": 2001951, @@ -146,14 +154,18 @@ "TerritoryId": 153, "InteractionType": "WalkTo", "DisableNavmesh": true, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -16 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 16 + ] + } + } }, { "Position": { @@ -163,14 +175,18 @@ }, "TerritoryId": 153, "InteractionType": "WalkTo", - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -16 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 16 + ] + } + } }, { "DataId": 2001952, diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/B6-Coerthas Central Highlands, Camp Dragonhead/889_Three for Three.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/B6-Coerthas Central Highlands, Camp Dragonhead/889_Three for Three.json index eb2aae1f..3ff98b75 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/B6-Coerthas Central Highlands, Camp Dragonhead/889_Three for Three.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/B6-Coerthas Central Highlands, Camp Dragonhead/889_Three for Three.json @@ -71,14 +71,18 @@ 725, 726 ], - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -128 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 128 + ] + } + } }, { "DataId": 2002261, diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/B7-Coerthas Central Highlands, Camp Dragonhead/897_The Talk of Coerthas.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/B7-Coerthas Central Highlands, Camp Dragonhead/897_The Talk of Coerthas.json index 968fd089..8f5426e3 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/B7-Coerthas Central Highlands, Camp Dragonhead/897_The Talk of Coerthas.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/B7-Coerthas Central Highlands, Camp Dragonhead/897_The Talk of Coerthas.json @@ -64,14 +64,18 @@ "InteractionType": "WalkTo", "$": "NW Skyfire Locks door (inside)", "DisableNavmesh": true, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -64 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 64 + ] + } + } }, { "DataId": 1006396, diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/C2-Western La Noscea, Isles of Umbra/960_It's Probably Not Pirates.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/C2-Western La Noscea, Isles of Umbra/960_It's Probably Not Pirates.json index 6400f289..f2be862b 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/C2-Western La Noscea, Isles of Umbra/960_It's Probably Not Pirates.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/C2-Western La Noscea, Isles of Umbra/960_It's Probably Not Pirates.json @@ -34,14 +34,18 @@ }, "TerritoryId": 138, "InteractionType": "WalkTo", - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -32 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 32 + ] + } + } }, { "Position": { @@ -52,14 +56,18 @@ "TerritoryId": 138, "InteractionType": "WalkTo", "DisableNavmesh": true, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -32 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 32 + ] + } + } }, { "DataId": 1006500, diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/C6-Mor Dhona/1001_Drowning Out the Voices.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/C6-Mor Dhona/1001_Drowning Out the Voices.json index 805400af..c9fc5c3a 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/C6-Mor Dhona/1001_Drowning Out the Voices.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/C6-Mor Dhona/1001_Drowning Out the Voices.json @@ -94,14 +94,18 @@ "TerritoryId": 156, "InteractionType": "WalkTo", "Comment": "Avoids pit", - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -32 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 32 + ] + } + } }, { "Position": { @@ -112,14 +116,18 @@ "TerritoryId": 156, "InteractionType": "WalkTo", "Comment": "Move into LOS", - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -32 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 32 + ] + } + } }, { "DataId": 2002230, diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/E3-2.3/1460_Brave New Companions.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/E3-2.3/1460_Brave New Companions.json index 0da1b858..e318a55b 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/E3-2.3/1460_Brave New Companions.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/E3-2.3/1460_Brave New Companions.json @@ -68,14 +68,18 @@ "TerritoryId": 351, "InteractionType": "Interact", "TargetTerritoryId": 156, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -2 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 2 + ] + } + } }, { "DataId": 1009147, diff --git a/QuestPaths/2.x - A Realm Reborn/Raid Quests/1709_Legacy of Allag.json b/QuestPaths/2.x - A Realm Reborn/Raid Quests/1709_Legacy of Allag.json index f9ed54c6..b0157e38 100644 --- a/QuestPaths/2.x - A Realm Reborn/Raid Quests/1709_Legacy of Allag.json +++ b/QuestPaths/2.x - A Realm Reborn/Raid Quests/1709_Legacy of Allag.json @@ -76,14 +76,18 @@ "InteractionType": "WalkTo", "Fly": true, "AetheryteShortcut": "Upper La Noscea - Camp Bronze Lake", - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -128 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 128 + ] + } + } }, { "Position": { @@ -94,14 +98,18 @@ "TerritoryId": 139, "InteractionType": "WalkTo", "TargetTerritoryId": 180, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -128 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 128 + ] + } + } }, { "Position": { @@ -112,27 +120,35 @@ "TerritoryId": 180, "InteractionType": "WalkTo", "Fly": true, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -128 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 128 + ] + } + } }, { "TerritoryId": 180, "InteractionType": "AttuneAetheryte", "Aetheryte": "Outer La Noscea - Camp Overlook", - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -128 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 128 + ] + } + } }, { "Position": { @@ -143,14 +159,18 @@ "TerritoryId": 180, "InteractionType": "WalkTo", "Fly": true, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -128 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 128 + ] + } + } }, { "Position": { @@ -161,14 +181,18 @@ "TerritoryId": 180, "InteractionType": "WalkTo", "Fly": true, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -128 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 128 + ] + } + } }, { "Position": { @@ -179,14 +203,18 @@ "TerritoryId": 180, "InteractionType": "WalkTo", "Fly": true, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -128 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 128 + ] + } + } }, { "DataId": 2000075, @@ -221,14 +249,18 @@ "InteractionType": "WalkTo", "Fly": true, "AetheryteShortcut": "Western La Noscea - Aleport", - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -64 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 64 + ] + } + } }, { "DataId": 2000076, diff --git a/QuestPaths/2.x - A Realm Reborn/Tribal/Kobolds/Story/1321_How Low Can You Go.json b/QuestPaths/2.x - A Realm Reborn/Tribal/Kobolds/Story/1321_How Low Can You Go.json index 7f119f73..b53e459c 100644 --- a/QuestPaths/2.x - A Realm Reborn/Tribal/Kobolds/Story/1321_How Low Can You Go.json +++ b/QuestPaths/2.x - A Realm Reborn/Tribal/Kobolds/Story/1321_How Low Can You Go.json @@ -28,14 +28,18 @@ }, "TerritoryId": 180, "InteractionType": "WalkTo", - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -32 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 32 + ] + } + } }, { "DataId": 2003715, diff --git a/QuestPaths/3.x - Heavensward/Aether Currents/The Churning Mists/1828_Hide Your Moogles.json b/QuestPaths/3.x - Heavensward/Aether Currents/The Churning Mists/1828_Hide Your Moogles.json index e152eea9..7d7043cf 100644 --- a/QuestPaths/3.x - Heavensward/Aether Currents/The Churning Mists/1828_Hide Your Moogles.json +++ b/QuestPaths/3.x - Heavensward/Aether Currents/The Churning Mists/1828_Hide Your Moogles.json @@ -28,14 +28,18 @@ }, "TerritoryId": 400, "InteractionType": "WalkTo", - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -64 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 64 + ] + } + } }, { "Position": { @@ -46,14 +50,18 @@ "TerritoryId": 400, "InteractionType": "WalkTo", "DisableNavmesh": true, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -64 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 64 + ] + } + } }, { "Position": { @@ -63,14 +71,18 @@ }, "TerritoryId": 400, "InteractionType": "WalkTo", - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -64 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 64 + ] + } + } }, { "DataId": 1013424, @@ -118,14 +130,18 @@ }, "TerritoryId": 400, "InteractionType": "WalkTo", - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -128 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 128 + ] + } + } }, { "Position": { @@ -144,14 +160,18 @@ "Z": 380.9018 } }, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -128 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 128 + ] + } + } }, { "DataId": 1013421, diff --git a/QuestPaths/3.x - Heavensward/Aether Currents/The Dravanian Forelands/1771_Some Bad News.json b/QuestPaths/3.x - Heavensward/Aether Currents/The Dravanian Forelands/1771_Some Bad News.json index 4010255c..c584f07b 100644 --- a/QuestPaths/3.x - Heavensward/Aether Currents/The Dravanian Forelands/1771_Some Bad News.json +++ b/QuestPaths/3.x - Heavensward/Aether Currents/The Dravanian Forelands/1771_Some Bad News.json @@ -28,14 +28,18 @@ }, "TerritoryId": 398, "InteractionType": "WalkTo", - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -32 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 32 + ] + } + } }, { "Position": { @@ -46,14 +50,18 @@ "TerritoryId": 398, "InteractionType": "WalkTo", "DisableNavmesh": true, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -32 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 32 + ] + } + } }, { "Position": { @@ -64,14 +72,18 @@ "TerritoryId": 398, "InteractionType": "WalkTo", "DisableNavmesh": true, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -32 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 32 + ] + } + } }, { "DataId": 1011932, @@ -99,14 +111,18 @@ }, "TerritoryId": 398, "InteractionType": "WalkTo", - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -64 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 64 + ] + } + } }, { "Position": { @@ -117,14 +133,18 @@ "TerritoryId": 398, "InteractionType": "WalkTo", "DisableNavmesh": true, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -64 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 64 + ] + } + } }, { "DataId": 1011924, diff --git a/QuestPaths/3.x - Heavensward/Aether Currents/The Dravanian Forelands/1797_The Hunter Becomes the Kweh.json b/QuestPaths/3.x - Heavensward/Aether Currents/The Dravanian Forelands/1797_The Hunter Becomes the Kweh.json index 1b6676ba..11df6fd8 100644 --- a/QuestPaths/3.x - Heavensward/Aether Currents/The Dravanian Forelands/1797_The Hunter Becomes the Kweh.json +++ b/QuestPaths/3.x - Heavensward/Aether Currents/The Dravanian Forelands/1797_The Hunter Becomes the Kweh.json @@ -34,14 +34,18 @@ }, "TerritoryId": 398, "InteractionType": "WalkTo", - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -32 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 32 + ] + } + } }, { "Position": { @@ -52,14 +56,18 @@ "TerritoryId": 398, "InteractionType": "WalkTo", "DisableNavmesh": true, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -32 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 32 + ] + } + } }, { "Position": { @@ -70,14 +78,18 @@ "TerritoryId": 398, "InteractionType": "WalkTo", "DisableNavmesh": true, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -32 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 32 + ] + } + } }, { "DataId": 1011932, @@ -106,14 +118,18 @@ }, "TerritoryId": 398, "InteractionType": "WalkTo", - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -64 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 64 + ] + } + } }, { "Position": { @@ -124,14 +140,18 @@ "TerritoryId": 398, "InteractionType": "WalkTo", "DisableNavmesh": true, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -64 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 64 + ] + } + } }, { "DataId": 1011924, diff --git a/QuestPaths/3.x - Heavensward/MSQ/A1-Coerthas Western Highlands 1, Sea of Clouds 1/1593_Sense of Urgency.json b/QuestPaths/3.x - Heavensward/MSQ/A1-Coerthas Western Highlands 1, Sea of Clouds 1/1593_Sense of Urgency.json index 499045db..4a8d50ac 100644 --- a/QuestPaths/3.x - Heavensward/MSQ/A1-Coerthas Western Highlands 1, Sea of Clouds 1/1593_Sense of Urgency.json +++ b/QuestPaths/3.x - Heavensward/MSQ/A1-Coerthas Western Highlands 1, Sea of Clouds 1/1593_Sense of Urgency.json @@ -29,14 +29,18 @@ "TerritoryId": 401, "InteractionType": "WalkTo", "Mount": true, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -128 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 128 + ] + } + } }, { "Position": { @@ -47,14 +51,18 @@ "TerritoryId": 401, "InteractionType": "WalkTo", "DisableNavmesh": true, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -128 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 128 + ] + } + } }, { "DataId": 1013498, diff --git a/QuestPaths/3.x - Heavensward/MSQ/A6-The Dravanian Hinterlands/1662_Hour of Departure.json b/QuestPaths/3.x - Heavensward/MSQ/A6-The Dravanian Hinterlands/1662_Hour of Departure.json index b79ad407..ddf0e6ea 100644 --- a/QuestPaths/3.x - Heavensward/MSQ/A6-The Dravanian Hinterlands/1662_Hour of Departure.json +++ b/QuestPaths/3.x - Heavensward/MSQ/A6-The Dravanian Hinterlands/1662_Hour of Departure.json @@ -86,14 +86,18 @@ }, "TerritoryId": 418, "InteractionType": "WalkTo", - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -32 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 32 + ] + } + } }, { "Position": { @@ -104,14 +108,18 @@ "TerritoryId": 418, "InteractionType": "WalkTo", "DisableNavmesh": true, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -32 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 32 + ] + } + } }, { "DataId": 1012251, diff --git a/QuestPaths/4.x - Stormblood/Tribal/Ananta/Dailies/3064_Thin-skinned.json b/QuestPaths/4.x - Stormblood/Tribal/Ananta/Dailies/3064_Thin-skinned.json index 59c56180..2e3c84b6 100644 --- a/QuestPaths/4.x - Stormblood/Tribal/Ananta/Dailies/3064_Thin-skinned.json +++ b/QuestPaths/4.x - Stormblood/Tribal/Ananta/Dailies/3064_Thin-skinned.json @@ -64,14 +64,18 @@ null, null ], - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -32 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 32 + ] + } + } }, { "DataId": 2009361, @@ -160,14 +164,18 @@ null, null ], - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -64 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 64 + ] + } + } }, { "DataId": 2009360, @@ -253,14 +261,18 @@ null, null ], - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -128 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 128 + ] + } + } }, { "DataId": 2009359, @@ -346,14 +358,18 @@ null, null ], - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -4 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 4 + ] + } + } }, { "DataId": 2009364, @@ -436,14 +452,18 @@ null, null ], - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -8 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 8 + ] + } + } }, { "DataId": 2009363, @@ -529,14 +549,18 @@ null, null ], - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -16 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 16 + ] + } + } }, { "DataId": 2009362, diff --git a/QuestPaths/5.x - Shadowbringers/Aether Currents/Lakeland/3380_A Jobb Well Done.json b/QuestPaths/5.x - Shadowbringers/Aether Currents/Lakeland/3380_A Jobb Well Done.json index 19c4d695..bb74f278 100644 --- a/QuestPaths/5.x - Shadowbringers/Aether Currents/Lakeland/3380_A Jobb Well Done.json +++ b/QuestPaths/5.x - Shadowbringers/Aether Currents/Lakeland/3380_A Jobb Well Done.json @@ -63,14 +63,18 @@ "TerritoryId": 813, "InteractionType": "WalkTo", "Mount": true, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -64 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 64 + ] + } + } }, { "Position": { @@ -81,14 +85,18 @@ "TerritoryId": 813, "InteractionType": "WalkTo", "DisableNavmesh": true, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -64 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 64 + ] + } + } }, { "DataId": 1027339, @@ -116,14 +124,18 @@ }, "TerritoryId": 813, "InteractionType": "WalkTo", - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -32 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 32 + ] + } + } }, { "Position": { @@ -133,14 +145,18 @@ }, "TerritoryId": 813, "InteractionType": "WalkTo", - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -32 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 32 + ] + } + } }, { "Position": { @@ -150,14 +166,18 @@ }, "TerritoryId": 813, "InteractionType": "WalkTo", - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -32 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 32 + ] + } + } }, { "DataId": 1027420, diff --git a/QuestPaths/5.x - Shadowbringers/Aether Currents/Lakeland/3384_Imperative Repairs.json b/QuestPaths/5.x - Shadowbringers/Aether Currents/Lakeland/3384_Imperative Repairs.json index b54bc132..4f8715aa 100644 --- a/QuestPaths/5.x - Shadowbringers/Aether Currents/Lakeland/3384_Imperative Repairs.json +++ b/QuestPaths/5.x - Shadowbringers/Aether Currents/Lakeland/3384_Imperative Repairs.json @@ -29,14 +29,18 @@ "TerritoryId": 813, "InteractionType": "WalkTo", "Comment": "Tower Bottom", - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -64 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 64 + ] + } + } }, { "Position": { @@ -48,14 +52,18 @@ "InteractionType": "WalkTo", "DisableNavmesh": true, "Comment": "Tower Bottom Platform 1", - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -64 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 64 + ] + } + } }, { "DataId": 2010618, diff --git a/QuestPaths/5.x - Shadowbringers/MSQ/B-Il Mheg/3305_The Oracle of Light.json b/QuestPaths/5.x - Shadowbringers/MSQ/B-Il Mheg/3305_The Oracle of Light.json index 8c3baec4..5aeffbc0 100644 --- a/QuestPaths/5.x - Shadowbringers/MSQ/B-Il Mheg/3305_The Oracle of Light.json +++ b/QuestPaths/5.x - Shadowbringers/MSQ/B-Il Mheg/3305_The Oracle of Light.json @@ -74,14 +74,18 @@ }, "TerritoryId": 813, "InteractionType": "WalkTo", - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -64 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 64 + ] + } + } }, { "DataId": 1028952, diff --git a/QuestPaths/5.x - Shadowbringers/MSQ/B-Il Mheg/3307_Sul Uin's Request.json b/QuestPaths/5.x - Shadowbringers/MSQ/B-Il Mheg/3307_Sul Uin's Request.json index b578fa65..b4801eed 100644 --- a/QuestPaths/5.x - Shadowbringers/MSQ/B-Il Mheg/3307_Sul Uin's Request.json +++ b/QuestPaths/5.x - Shadowbringers/MSQ/B-Il Mheg/3307_Sul Uin's Request.json @@ -28,14 +28,18 @@ }, "TerritoryId": 816, "InteractionType": "WalkTo", - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -64 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 64 + ] + } + } }, { "DataId": 2009820, @@ -66,14 +70,18 @@ "TerritoryId": 816, "InteractionType": "WalkTo", "DisableNavmesh": true, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -128 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 128 + ] + } + } }, { "DataId": 2009819, diff --git a/QuestPaths/5.x - Shadowbringers/MSQ/B-Il Mheg/3315_Spore Sweeper.json b/QuestPaths/5.x - Shadowbringers/MSQ/B-Il Mheg/3315_Spore Sweeper.json index 93eeea77..99929255 100644 --- a/QuestPaths/5.x - Shadowbringers/MSQ/B-Il Mheg/3315_Spore Sweeper.json +++ b/QuestPaths/5.x - Shadowbringers/MSQ/B-Il Mheg/3315_Spore Sweeper.json @@ -46,14 +46,18 @@ }, "TerritoryId": 816, "InteractionType": "WalkTo", - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -64 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 64 + ] + } + } }, { "Position": { @@ -64,14 +68,18 @@ "TerritoryId": 816, "InteractionType": "WalkTo", "DisableNavmesh": true, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -64 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 64 + ] + } + } }, { "DataId": 2009831, diff --git a/QuestPaths/5.x - Shadowbringers/MSQ/B-Il Mheg/3316_The Lawless Ones.json b/QuestPaths/5.x - Shadowbringers/MSQ/B-Il Mheg/3316_The Lawless Ones.json index 9acc6b95..07967866 100644 --- a/QuestPaths/5.x - Shadowbringers/MSQ/B-Il Mheg/3316_The Lawless Ones.json +++ b/QuestPaths/5.x - Shadowbringers/MSQ/B-Il Mheg/3316_The Lawless Ones.json @@ -150,14 +150,18 @@ }, "TerritoryId": 816, "InteractionType": "WalkTo", - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -32 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 32 + ] + } + } }, { "Position": { @@ -168,14 +172,18 @@ "TerritoryId": 816, "InteractionType": "WalkTo", "DisableNavmesh": true, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -32 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 32 + ] + } + } }, { "DataId": 2009836, @@ -214,14 +222,18 @@ }, "DelaySeconds": 0.2 }, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -64 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 64 + ] + } + } }, { "Position": { @@ -241,14 +253,18 @@ }, "DelaySeconds": 0.1 }, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -64 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 64 + ] + } + } }, { "Position": { @@ -268,14 +284,18 @@ }, "DelaySeconds": 0.1 }, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -64 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 64 + ] + } + } }, { "Position": { @@ -295,14 +315,18 @@ }, "DelaySeconds": 0.2 }, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -64 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 64 + ] + } + } }, { "DataId": 2009835, diff --git a/QuestPaths/5.x - Shadowbringers/MSQ/C-Rak'tika/3335_Look to the Stars.json b/QuestPaths/5.x - Shadowbringers/MSQ/C-Rak'tika/3335_Look to the Stars.json index a005447b..668c8fee 100644 --- a/QuestPaths/5.x - Shadowbringers/MSQ/C-Rak'tika/3335_Look to the Stars.json +++ b/QuestPaths/5.x - Shadowbringers/MSQ/C-Rak'tika/3335_Look to the Stars.json @@ -79,14 +79,18 @@ "StopDistance": 2, "Type": "RepeatedJumps" }, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -16 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 16 + ] + } + } }, { "DataId": 2009890, @@ -128,14 +132,18 @@ "StopDistance": 2, "Type": "RepeatedJumps" }, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -128 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 128 + ] + } + } }, { "DataId": 2009887, @@ -166,14 +174,18 @@ "InteractionType": "WalkTo", "DisableNavmesh": true, "Mount": true, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -64 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 64 + ] + } + } }, { "Position": { @@ -196,14 +208,18 @@ "StopDistance": 2, "Type": "RepeatedJumps" }, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -64 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 64 + ] + } + } }, { "DataId": 2009888, @@ -245,14 +261,18 @@ "StopDistance": 2, "Type": "RepeatedJumps" }, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -32 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 32 + ] + } + } }, { "DataId": 2009889, diff --git a/QuestPaths/5.x - Shadowbringers/MSQ/E-Kholusia 2/3633_The Ladder.json b/QuestPaths/5.x - Shadowbringers/MSQ/E-Kholusia 2/3633_The Ladder.json index a7c9fd25..0c46f86d 100644 --- a/QuestPaths/5.x - Shadowbringers/MSQ/E-Kholusia 2/3633_The Ladder.json +++ b/QuestPaths/5.x - Shadowbringers/MSQ/E-Kholusia 2/3633_The Ladder.json @@ -60,14 +60,18 @@ }, "TerritoryId": 814, "InteractionType": "WalkTo", - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -64 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 64 + ] + } + } }, { "DataId": 2010088, @@ -114,14 +118,18 @@ }, "TerritoryId": 814, "InteractionType": "WalkTo", - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -32 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 32 + ] + } + } }, { "DataId": 2010089, diff --git a/QuestPaths/5.x - Shadowbringers/MSQ/F-Tempest/3645_In His Garden.json b/QuestPaths/5.x - Shadowbringers/MSQ/F-Tempest/3645_In His Garden.json index 8972210d..a2485ea1 100644 --- a/QuestPaths/5.x - Shadowbringers/MSQ/F-Tempest/3645_In His Garden.json +++ b/QuestPaths/5.x - Shadowbringers/MSQ/F-Tempest/3645_In His Garden.json @@ -48,14 +48,18 @@ "TerritoryId": 819, "InteractionType": "WalkTo", "DisableNavmesh": true, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -128 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 128 + ] + } + } }, { "DataId": 1027246, diff --git a/QuestPaths/5.x - Shadowbringers/Tribal/Pixies/Dailies/3689_Where There's Wool, There's a Way.json b/QuestPaths/5.x - Shadowbringers/Tribal/Pixies/Dailies/3689_Where There's Wool, There's a Way.json index 51110d72..6a4cbf23 100644 --- a/QuestPaths/5.x - Shadowbringers/Tribal/Pixies/Dailies/3689_Where There's Wool, There's a Way.json +++ b/QuestPaths/5.x - Shadowbringers/Tribal/Pixies/Dailies/3689_Where There's Wool, There's a Way.json @@ -29,14 +29,18 @@ "TerritoryId": 816, "InteractionType": "WalkTo", "Fly": true, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -128 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 128 + ] + } + } }, { "DataId": 2010856, @@ -83,14 +87,18 @@ }, "TerritoryId": 816, "InteractionType": "WalkTo", - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -64 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 64 + ] + } + } }, { "DataId": 2010857, diff --git a/QuestPaths/6.x - Endwalker/Aether Currents/Mare Lamentorum/4241_Carrots Its Whats for Dinner.json b/QuestPaths/6.x - Endwalker/Aether Currents/Mare Lamentorum/4241_Carrots Its Whats for Dinner.json index 720ba8e8..0d7637ca 100644 --- a/QuestPaths/6.x - Endwalker/Aether Currents/Mare Lamentorum/4241_Carrots Its Whats for Dinner.json +++ b/QuestPaths/6.x - Endwalker/Aether Currents/Mare Lamentorum/4241_Carrots Its Whats for Dinner.json @@ -29,14 +29,18 @@ "StopDistance": 1, "TerritoryId": 959, "InteractionType": "WalkTo", - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -128 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 128 + ] + } + } }, { "Position": { @@ -56,14 +60,18 @@ }, "Mount": false, "Comment": "Platform 1", - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -128 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 128 + ] + } + } }, { "Position": { @@ -82,14 +90,18 @@ "DelaySeconds": 0.25 }, "Comment": "Platform 2", - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -128 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 128 + ] + } + } }, { "Position": { @@ -108,14 +120,18 @@ "DelaySeconds": 0.25 }, "Comment": "Platform 3", - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -128 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 128 + ] + } + } }, { "Position": { @@ -134,14 +150,18 @@ "DelaySeconds": 0.25 }, "Comment": "Platform 4", - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -128 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 128 + ] + } + } }, { "Position": { @@ -160,14 +180,18 @@ "DelaySeconds": 0.25 }, "Comment": "Platform 5", - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -128 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 128 + ] + } + } }, { "Position": { @@ -186,14 +210,18 @@ "DelaySeconds": 0.25 }, "Comment": "Platform 6", - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -128 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 128 + ] + } + } }, { "Position": { @@ -204,14 +232,18 @@ "TerritoryId": 959, "InteractionType": "WalkTo", "DisableNavmesh": true, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -128 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 128 + ] + } + } }, { "DataId": 1041789, @@ -287,14 +319,18 @@ }, "Mount": false, "Comment": "Platform 1", - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -32 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 32 + ] + } + } }, { "Position": { @@ -314,14 +350,18 @@ "DelaySeconds": 0.25 }, "Comment": "Platform 2", - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -32 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 32 + ] + } + } }, { "Position": { @@ -341,14 +381,18 @@ "DelaySeconds": 0.25 }, "Comment": "Platform 3", - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -32 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 32 + ] + } + } }, { "Position": { @@ -368,14 +412,18 @@ "DelaySeconds": 0.25 }, "Comment": "Platform 4", - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -32 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 32 + ] + } + } }, { "Position": { @@ -395,14 +443,18 @@ "DelaySeconds": 0.25 }, "Comment": "Platform 5", - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -32 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 32 + ] + } + } }, { "Position": { @@ -422,14 +474,18 @@ "DelaySeconds": 0.25 }, "Comment": "Platform 6", - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -32 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 32 + ] + } + } }, { "DataId": 1041791, diff --git a/QuestPaths/6.x - Endwalker/Aether Currents/Thavnair/4203_Alchemist or Dancer.json b/QuestPaths/6.x - Endwalker/Aether Currents/Thavnair/4203_Alchemist or Dancer.json index 6e01fb6f..3b15ae0b 100644 --- a/QuestPaths/6.x - Endwalker/Aether Currents/Thavnair/4203_Alchemist or Dancer.json +++ b/QuestPaths/6.x - Endwalker/Aether Currents/Thavnair/4203_Alchemist or Dancer.json @@ -61,14 +61,18 @@ }, "TerritoryId": 957, "InteractionType": "WalkTo", - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -32 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 32 + ] + } + } }, { "DataId": 2011914, diff --git a/QuestPaths/6.x - Endwalker/Aether Currents/Thavnair/4259_Radiant Patrol.json b/QuestPaths/6.x - Endwalker/Aether Currents/Thavnair/4259_Radiant Patrol.json index ca5a8652..43425dbe 100644 --- a/QuestPaths/6.x - Endwalker/Aether Currents/Thavnair/4259_Radiant Patrol.json +++ b/QuestPaths/6.x - Endwalker/Aether Currents/Thavnair/4259_Radiant Patrol.json @@ -74,7 +74,7 @@ null, null, null, - -64 + 64 ], "$": "QuestVariables after killing enemy: 17 1 0 0 0 64" }, diff --git a/QuestPaths/6.x - Endwalker/MSQ/B-Garlemald/4389_Personae non Gratae.json b/QuestPaths/6.x - Endwalker/MSQ/B-Garlemald/4389_Personae non Gratae.json index d76baf9d..9bee400f 100644 --- a/QuestPaths/6.x - Endwalker/MSQ/B-Garlemald/4389_Personae non Gratae.json +++ b/QuestPaths/6.x - Endwalker/MSQ/B-Garlemald/4389_Personae non Gratae.json @@ -66,14 +66,18 @@ }, "TerritoryId": 958, "InteractionType": "WalkTo", - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -128 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 128 + ] + } + } }, { "DataId": 1037715, diff --git a/QuestPaths/6.x - Endwalker/MSQ/B-Garlemald/4393_Strange Bedfellows.json b/QuestPaths/6.x - Endwalker/MSQ/B-Garlemald/4393_Strange Bedfellows.json index 8dfb9b50..04342d49 100644 --- a/QuestPaths/6.x - Endwalker/MSQ/B-Garlemald/4393_Strange Bedfellows.json +++ b/QuestPaths/6.x - Endwalker/MSQ/B-Garlemald/4393_Strange Bedfellows.json @@ -112,14 +112,18 @@ "InteractionType": "WalkTo", "Mount": true, "DisableNavmesh": true, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -64 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 64 + ] + } + } }, { "DataId": 2012111, @@ -180,14 +184,18 @@ }, "TerritoryId": 958, "InteractionType": "WalkTo", - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -128 - ], + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 128 + ] + } + }, "Comment": "Avoids combat" }, { @@ -219,14 +227,18 @@ "TerritoryId": 958, "InteractionType": "WalkTo", "Comment": "Avoids combat", - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -16 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 16 + ] + } + } }, { "DataId": 2012110, diff --git a/QuestPaths/6.x - Endwalker/MSQ/D-Thavnair2/4410_The Blasphemy Unmasked.json b/QuestPaths/6.x - Endwalker/MSQ/D-Thavnair2/4410_The Blasphemy Unmasked.json index 436856e5..92f13d83 100644 --- a/QuestPaths/6.x - Endwalker/MSQ/D-Thavnair2/4410_The Blasphemy Unmasked.json +++ b/QuestPaths/6.x - Endwalker/MSQ/D-Thavnair2/4410_The Blasphemy Unmasked.json @@ -60,14 +60,18 @@ "TerritoryId": 963, "InteractionType": "WalkTo", "DisableNavmesh": true, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -128 - ], + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 128 + ] + } + }, "Sprint": true }, { diff --git a/QuestPaths/6.x - Endwalker/MSQ/E-Elpis/4420_Hope Upon a Flower.json b/QuestPaths/6.x - Endwalker/MSQ/E-Elpis/4420_Hope Upon a Flower.json index 90507512..82b13f6e 100644 --- a/QuestPaths/6.x - Endwalker/MSQ/E-Elpis/4420_Hope Upon a Flower.json +++ b/QuestPaths/6.x - Endwalker/MSQ/E-Elpis/4420_Hope Upon a Flower.json @@ -71,14 +71,18 @@ "Z": -1.1141448 } }, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -16 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 16 + ] + } + } }, { "DataId": 2012128, diff --git a/QuestPaths/6.x - Endwalker/MSQ/G-UltimaThule/4456_Roads Paved of Sacrifice.json b/QuestPaths/6.x - Endwalker/MSQ/G-UltimaThule/4456_Roads Paved of Sacrifice.json index 4289281a..deaef791 100644 --- a/QuestPaths/6.x - Endwalker/MSQ/G-UltimaThule/4456_Roads Paved of Sacrifice.json +++ b/QuestPaths/6.x - Endwalker/MSQ/G-UltimaThule/4456_Roads Paved of Sacrifice.json @@ -109,14 +109,18 @@ }, "TerritoryId": 960, "InteractionType": "WalkTo", - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -128 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 128 + ] + } + } }, { "DataId": 2012354, diff --git a/QuestPaths/6.x - Endwalker/MSQ/H-6.1/4531_Sharing the Wealth.json b/QuestPaths/6.x - Endwalker/MSQ/H-6.1/4531_Sharing the Wealth.json index 476a8659..59686b6f 100644 --- a/QuestPaths/6.x - Endwalker/MSQ/H-6.1/4531_Sharing the Wealth.json +++ b/QuestPaths/6.x - Endwalker/MSQ/H-6.1/4531_Sharing the Wealth.json @@ -51,14 +51,18 @@ "TerritoryId": 957, "InteractionType": "WalkTo", "AetheryteShortcut": "Thavnair - Yedlihmad", - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -128 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 128 + ] + } + } }, { "DataId": 1037631, diff --git a/QuestPaths/6.x - Endwalker/Side Quests/Thavnair/4491_Ogul Repays Her Favors.json b/QuestPaths/6.x - Endwalker/Side Quests/Thavnair/4491_Ogul Repays Her Favors.json index 4d77d3b3..f5f66dc4 100644 --- a/QuestPaths/6.x - Endwalker/Side Quests/Thavnair/4491_Ogul Repays Her Favors.json +++ b/QuestPaths/6.x - Endwalker/Side Quests/Thavnair/4491_Ogul Repays Her Favors.json @@ -97,14 +97,18 @@ "TerritoryId": 957, "InteractionType": "WalkTo", "Fly": true, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -128 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 128 + ] + } + } }, { "DataId": 1037655, @@ -151,14 +155,18 @@ }, "TerritoryId": 957, "InteractionType": "WalkTo", - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -32 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 32 + ] + } + } }, { "DataId": 1037708, @@ -169,14 +177,18 @@ }, "TerritoryId": 957, "InteractionType": "Interact", - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -32 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 32 + ] + } + } } ] }, diff --git a/QuestPaths/6.x - Endwalker/Side Quests/Thavnair/4495_The Sins We Bear.json b/QuestPaths/6.x - Endwalker/Side Quests/Thavnair/4495_The Sins We Bear.json index 952be85e..60491984 100644 --- a/QuestPaths/6.x - Endwalker/Side Quests/Thavnair/4495_The Sins We Bear.json +++ b/QuestPaths/6.x - Endwalker/Side Quests/Thavnair/4495_The Sins We Bear.json @@ -68,14 +68,18 @@ "TerritoryId": 957, "InteractionType": "WalkTo", "Fly": true, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -128 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 128 + ] + } + } }, { "DataId": 2012455, @@ -105,14 +109,18 @@ "TerritoryId": 957, "InteractionType": "WalkTo", "Fly": true, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -32 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 32 + ] + } + } }, { "DataId": 2012457, @@ -141,14 +149,18 @@ "TerritoryId": 957, "InteractionType": "WalkTo", "Fly": true, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -64 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 64 + ] + } + } }, { "DataId": 2012456, diff --git a/QuestPaths/6.x - Endwalker/Tribal/Arkasodara/Dailies/4557_Gulal Generosity.json b/QuestPaths/6.x - Endwalker/Tribal/Arkasodara/Dailies/4557_Gulal Generosity.json index 2250fc99..2f59883e 100644 --- a/QuestPaths/6.x - Endwalker/Tribal/Arkasodara/Dailies/4557_Gulal Generosity.json +++ b/QuestPaths/6.x - Endwalker/Tribal/Arkasodara/Dailies/4557_Gulal Generosity.json @@ -45,14 +45,18 @@ "InteractionType": "WalkTo", "Fly": true, "Land": true, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -32 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 32 + ] + } + } }, { "DataId": 1042372, @@ -84,14 +88,18 @@ "InteractionType": "WalkTo", "Fly": true, "Land": true, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -64 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 64 + ] + } + } }, { "DataId": 1042371, @@ -123,14 +131,18 @@ "InteractionType": "WalkTo", "Fly": true, "Land": true, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -128 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 128 + ] + } + } }, { "DataId": 1042373, diff --git a/QuestPaths/6.x - Endwalker/Tribal/Arkasodara/Dailies/4564_Olfactory Warfare.json b/QuestPaths/6.x - Endwalker/Tribal/Arkasodara/Dailies/4564_Olfactory Warfare.json index b9fda16a..b7219f5d 100644 --- a/QuestPaths/6.x - Endwalker/Tribal/Arkasodara/Dailies/4564_Olfactory Warfare.json +++ b/QuestPaths/6.x - Endwalker/Tribal/Arkasodara/Dailies/4564_Olfactory Warfare.json @@ -45,14 +45,18 @@ "InteractionType": "WalkTo", "Fly": true, "Land": true, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -128 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 128 + ] + } + } }, { "DataId": 2012887, @@ -84,14 +88,18 @@ "InteractionType": "WalkTo", "Fly": true, "Land": true, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -64 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 64 + ] + } + } }, { "DataId": 2012888, @@ -123,14 +131,18 @@ "InteractionType": "WalkTo", "Fly": true, "Land": true, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -32 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 32 + ] + } + } }, { "DataId": 2012889, @@ -149,7 +161,7 @@ null, null, null, - -32 + 32 ] } ] diff --git a/QuestPaths/6.x - Endwalker/Tribal/Arkasodara/Dailies/4570_Patching Up.json b/QuestPaths/6.x - Endwalker/Tribal/Arkasodara/Dailies/4570_Patching Up.json index 34493e0e..90e6b009 100644 --- a/QuestPaths/6.x - Endwalker/Tribal/Arkasodara/Dailies/4570_Patching Up.json +++ b/QuestPaths/6.x - Endwalker/Tribal/Arkasodara/Dailies/4570_Patching Up.json @@ -29,14 +29,18 @@ "TerritoryId": 957, "InteractionType": "WalkTo", "Fly": true, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -32 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 32 + ] + } + } }, { "DataId": 2012902, @@ -66,14 +70,18 @@ "TerritoryId": 957, "InteractionType": "WalkTo", "Fly": true, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -64 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 64 + ] + } + } }, { "DataId": 2012901, @@ -103,14 +111,18 @@ "TerritoryId": 957, "InteractionType": "WalkTo", "Fly": true, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -128 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 128 + ] + } + } }, { "DataId": 2012900, diff --git a/QuestPaths/6.x - Endwalker/Tribal/Arkasodara/Dailies/4573_Gathering Moss.json b/QuestPaths/6.x - Endwalker/Tribal/Arkasodara/Dailies/4573_Gathering Moss.json index 57905110..9685dbf8 100644 --- a/QuestPaths/6.x - Endwalker/Tribal/Arkasodara/Dailies/4573_Gathering Moss.json +++ b/QuestPaths/6.x - Endwalker/Tribal/Arkasodara/Dailies/4573_Gathering Moss.json @@ -30,14 +30,18 @@ "TerritoryId": 957, "InteractionType": "WalkTo", "Fly": true, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -32 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 32 + ] + } + } }, { "DataId": 2012907, diff --git a/QuestPaths/6.x - Endwalker/Tribal/Arkasodara/Dailies/4574_Blood from a Stonemason.json b/QuestPaths/6.x - Endwalker/Tribal/Arkasodara/Dailies/4574_Blood from a Stonemason.json index f79b047c..c84aa4ac 100644 --- a/QuestPaths/6.x - Endwalker/Tribal/Arkasodara/Dailies/4574_Blood from a Stonemason.json +++ b/QuestPaths/6.x - Endwalker/Tribal/Arkasodara/Dailies/4574_Blood from a Stonemason.json @@ -34,14 +34,18 @@ "[Radz-at-Han] The Gate of First Sight (Thavnair)" ], "Fly": true, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -32 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 32 + ] + } + } }, { "DataId": 1042462, diff --git a/QuestPaths/7.x - Dawntrail/Aether Currents/Urqopacha/5047_An Illuminating Ritual.json b/QuestPaths/7.x - Dawntrail/Aether Currents/Urqopacha/5047_An Illuminating Ritual.json index 119513fb..f3436491 100644 --- a/QuestPaths/7.x - Dawntrail/Aether Currents/Urqopacha/5047_An Illuminating Ritual.json +++ b/QuestPaths/7.x - Dawntrail/Aether Currents/Urqopacha/5047_An Illuminating Ritual.json @@ -111,14 +111,18 @@ }, "DelaySeconds": 0.25 }, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -64 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 64 + ] + } + } }, { "DataId": 2014134, diff --git a/QuestPaths/7.x - Dawntrail/MSQ/B-Kozama'uka2-Urqopacha2/4892_An Echo of Madness.json b/QuestPaths/7.x - Dawntrail/MSQ/B-Kozama'uka2-Urqopacha2/4892_An Echo of Madness.json index 355a6b30..f35bf22e 100644 --- a/QuestPaths/7.x - Dawntrail/MSQ/B-Kozama'uka2-Urqopacha2/4892_An Echo of Madness.json +++ b/QuestPaths/7.x - Dawntrail/MSQ/B-Kozama'uka2-Urqopacha2/4892_An Echo of Madness.json @@ -47,14 +47,18 @@ }, "TerritoryId": 1187, "InteractionType": "WalkTo", - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -32 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 32 + ] + } + } }, { "DataId": 1046874, diff --git a/QuestPaths/7.x - Dawntrail/MSQ/C-Yak T'el/4907_Mamook Speaks.json b/QuestPaths/7.x - Dawntrail/MSQ/C-Yak T'el/4907_Mamook Speaks.json index bdfb619a..95739833 100644 --- a/QuestPaths/7.x - Dawntrail/MSQ/C-Yak T'el/4907_Mamook Speaks.json +++ b/QuestPaths/7.x - Dawntrail/MSQ/C-Yak T'el/4907_Mamook Speaks.json @@ -142,14 +142,18 @@ "InteractionType": "WalkTo", "DisableNavmesh": true, "Mount": true, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -128 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 128 + ] + } + } }, { "DataId": 2013653, @@ -177,14 +181,18 @@ }, "TerritoryId": 1189, "InteractionType": "WalkTo", - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -32 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 32 + ] + } + } }, { "DataId": 2013655, diff --git a/QuestPaths/7.x - Dawntrail/MSQ/D-Shaaloani-HeritageFound1/4927_The Land of Levin.json b/QuestPaths/7.x - Dawntrail/MSQ/D-Shaaloani-HeritageFound1/4927_The Land of Levin.json index 092ada30..c846a700 100644 --- a/QuestPaths/7.x - Dawntrail/MSQ/D-Shaaloani-HeritageFound1/4927_The Land of Levin.json +++ b/QuestPaths/7.x - Dawntrail/MSQ/D-Shaaloani-HeritageFound1/4927_The Land of Levin.json @@ -113,14 +113,18 @@ }, "TerritoryId": 1191, "InteractionType": "WalkTo", - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -32 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 32 + ] + } + } }, { "DataId": 2013819, diff --git a/QuestPaths/7.x - Dawntrail/MSQ/F-Living Memory/4952_A Knight of Alexandria.json b/QuestPaths/7.x - Dawntrail/MSQ/F-Living Memory/4952_A Knight of Alexandria.json index 2791cb5a..9fce9170 100644 --- a/QuestPaths/7.x - Dawntrail/MSQ/F-Living Memory/4952_A Knight of Alexandria.json +++ b/QuestPaths/7.x - Dawntrail/MSQ/F-Living Memory/4952_A Knight of Alexandria.json @@ -131,14 +131,18 @@ }, "TerritoryId": 1192, "InteractionType": "WalkTo", - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -16 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 16 + ] + } + } }, { "DataId": 1047904, diff --git a/QuestPaths/7.x - Dawntrail/Side Quests/Heritage Found/5155_History Reforged.json b/QuestPaths/7.x - Dawntrail/Side Quests/Heritage Found/5155_History Reforged.json index 7218094c..6d3f5179 100644 --- a/QuestPaths/7.x - Dawntrail/Side Quests/Heritage Found/5155_History Reforged.json +++ b/QuestPaths/7.x - Dawntrail/Side Quests/Heritage Found/5155_History Reforged.json @@ -29,14 +29,18 @@ "TerritoryId": 1191, "InteractionType": "WalkTo", "Fly": true, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -128 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 128 + ] + } + } }, { "DataId": 2014091, @@ -85,14 +89,18 @@ "TerritoryId": 1191, "InteractionType": "WalkTo", "Fly": true, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -32 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 32 + ] + } + } }, { "DataId": 2014093, diff --git a/QuestPaths/7.x - Dawntrail/Side Quests/Kozama'uka/5075_Water Colors.json b/QuestPaths/7.x - Dawntrail/Side Quests/Kozama'uka/5075_Water Colors.json index 4d81d887..002e4fad 100644 --- a/QuestPaths/7.x - Dawntrail/Side Quests/Kozama'uka/5075_Water Colors.json +++ b/QuestPaths/7.x - Dawntrail/Side Quests/Kozama'uka/5075_Water Colors.json @@ -31,17 +31,17 @@ "Fly": true, "SkipConditions": { "StepIf": { - "Flying": "Locked" + "Flying": "Locked", + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 32 + ] } - }, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -32 - ] + } }, { "DataId": 2014184, diff --git a/QuestPaths/7.x - Dawntrail/Side Quests/Living Memory/5175_The Canals of History.json b/QuestPaths/7.x - Dawntrail/Side Quests/Living Memory/5175_The Canals of History.json index 92ac2270..2a09e97d 100644 --- a/QuestPaths/7.x - Dawntrail/Side Quests/Living Memory/5175_The Canals of History.json +++ b/QuestPaths/7.x - Dawntrail/Side Quests/Living Memory/5175_The Canals of History.json @@ -31,17 +31,17 @@ "Fly": true, "SkipConditions": { "StepIf": { - "Flying": "Locked" + "Flying": "Locked", + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 128 + ] } - }, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -128 - ] + } }, { "DataId": 2013901, diff --git a/QuestPaths/7.x - Dawntrail/Side Quests/Living Memory/5181_Leaving This Place for Good.json b/QuestPaths/7.x - Dawntrail/Side Quests/Living Memory/5181_Leaving This Place for Good.json index 8062590b..a77798f7 100644 --- a/QuestPaths/7.x - Dawntrail/Side Quests/Living Memory/5181_Leaving This Place for Good.json +++ b/QuestPaths/7.x - Dawntrail/Side Quests/Living Memory/5181_Leaving This Place for Good.json @@ -49,14 +49,18 @@ "TerritoryId": 1192, "InteractionType": "WalkTo", "Fly": true, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -32 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 32 + ] + } + } }, { "DataId": 2013916, @@ -86,14 +90,18 @@ "TerritoryId": 1192, "InteractionType": "WalkTo", "Fly": true, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -128 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 128 + ] + } + } }, { "DataId": 2013917, diff --git a/QuestPaths/7.x - Dawntrail/Side Quests/Shaaloani/5121_Taste of the Wilds.json b/QuestPaths/7.x - Dawntrail/Side Quests/Shaaloani/5121_Taste of the Wilds.json index 77ee6e04..f1414639 100644 --- a/QuestPaths/7.x - Dawntrail/Side Quests/Shaaloani/5121_Taste of the Wilds.json +++ b/QuestPaths/7.x - Dawntrail/Side Quests/Shaaloani/5121_Taste of the Wilds.json @@ -29,14 +29,18 @@ "TerritoryId": 1190, "InteractionType": "WalkTo", "Fly": true, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -128 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 128 + ] + } + } }, { "DataId": 1049284, @@ -64,14 +68,18 @@ }, "TerritoryId": 1190, "InteractionType": "WalkTo", - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -64 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 64 + ] + } + } }, { "DataId": 1049275, diff --git a/QuestPaths/7.x - Dawntrail/Side Quests/Shaaloani/5132_Death by Popoto.json b/QuestPaths/7.x - Dawntrail/Side Quests/Shaaloani/5132_Death by Popoto.json index c16f3f0d..0c7e9530 100644 --- a/QuestPaths/7.x - Dawntrail/Side Quests/Shaaloani/5132_Death by Popoto.json +++ b/QuestPaths/7.x - Dawntrail/Side Quests/Shaaloani/5132_Death by Popoto.json @@ -31,17 +31,17 @@ "Fly": true, "SkipConditions": { "StepIf": { - "Flying": "Locked" + "Flying": "Locked", + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 128 + ] } - }, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -128 - ] + } }, { "DataId": 2014051, diff --git a/QuestPaths/7.x - Dawntrail/Side Quests/Shaaloani/5142_Back on Stage.json b/QuestPaths/7.x - Dawntrail/Side Quests/Shaaloani/5142_Back on Stage.json index 92cf0fac..8a873f7a 100644 --- a/QuestPaths/7.x - Dawntrail/Side Quests/Shaaloani/5142_Back on Stage.json +++ b/QuestPaths/7.x - Dawntrail/Side Quests/Shaaloani/5142_Back on Stage.json @@ -46,16 +46,16 @@ "TerritoryId": 1190, "InteractionType": "WalkTo", "Fly": true, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -64 - ], "SkipConditions": { "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 64 + ], "Flying": "Locked" } } @@ -89,16 +89,16 @@ "TerritoryId": 1190, "InteractionType": "WalkTo", "Fly": true, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -128 - ], "SkipConditions": { "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 128 + ], "Flying": "Locked" } }, @@ -131,16 +131,16 @@ }, "TerritoryId": 1190, "InteractionType": "WalkTo", - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -32 - ], "SkipConditions": { "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 32 + ], "Flying": "Locked" } }, diff --git a/QuestPaths/7.x - Dawntrail/Side Quests/Shaaloani/5148_Dig for Victory.json b/QuestPaths/7.x - Dawntrail/Side Quests/Shaaloani/5148_Dig for Victory.json index d764508d..836fb20f 100644 --- a/QuestPaths/7.x - Dawntrail/Side Quests/Shaaloani/5148_Dig for Victory.json +++ b/QuestPaths/7.x - Dawntrail/Side Quests/Shaaloani/5148_Dig for Victory.json @@ -126,16 +126,16 @@ "InteractionType": "WalkTo", "AetheryteShortcut": "Shaaloani - Hhusatahwi", "Fly": true, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -128 - ], "SkipConditions": { "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 128 + ], "Flying": "Locked" } }, diff --git a/QuestPaths/7.x - Dawntrail/Side Quests/Yak T'el/5097_Sick Day.json b/QuestPaths/7.x - Dawntrail/Side Quests/Yak T'el/5097_Sick Day.json index f7afd7b5..5ec0cff1 100644 --- a/QuestPaths/7.x - Dawntrail/Side Quests/Yak T'el/5097_Sick Day.json +++ b/QuestPaths/7.x - Dawntrail/Side Quests/Yak T'el/5097_Sick Day.json @@ -49,14 +49,18 @@ "TerritoryId": 1189, "InteractionType": "WalkTo", "Fly": true, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -128 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 128 + ] + } + } }, { "DataId": 1048995, diff --git a/QuestPaths/7.x - Dawntrail/Side Quests/Yak T'el/5098_To Forge in the Forest.json b/QuestPaths/7.x - Dawntrail/Side Quests/Yak T'el/5098_To Forge in the Forest.json index 1995c178..007b8687 100644 --- a/QuestPaths/7.x - Dawntrail/Side Quests/Yak T'el/5098_To Forge in the Forest.json +++ b/QuestPaths/7.x - Dawntrail/Side Quests/Yak T'el/5098_To Forge in the Forest.json @@ -45,14 +45,18 @@ "TerritoryId": 1189, "InteractionType": "WalkTo", "Fly": true, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -128 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 128 + ] + } + } }, { "DataId": 2014313, @@ -82,14 +86,18 @@ "TerritoryId": 1189, "InteractionType": "WalkTo", "Fly": true, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -64 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 64 + ] + } + } }, { "DataId": 2014314, @@ -119,14 +127,18 @@ "TerritoryId": 1189, "InteractionType": "WalkTo", "Fly": true, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -32 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 32 + ] + } + } }, { "DataId": 2014315, diff --git a/QuestPaths/7.x - Dawntrail/Side Quests/Yak T'el/5101_Two Hearts Aflutter.json b/QuestPaths/7.x - Dawntrail/Side Quests/Yak T'el/5101_Two Hearts Aflutter.json index ee0174ba..bfd9d8fb 100644 --- a/QuestPaths/7.x - Dawntrail/Side Quests/Yak T'el/5101_Two Hearts Aflutter.json +++ b/QuestPaths/7.x - Dawntrail/Side Quests/Yak T'el/5101_Two Hearts Aflutter.json @@ -29,14 +29,18 @@ "TerritoryId": 1189, "InteractionType": "WalkTo", "Fly": true, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -128 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 128 + ] + } + } }, { "DataId": 1051049, @@ -48,14 +52,18 @@ "StopDistance": 4, "TerritoryId": 1189, "InteractionType": "Interact", - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -128 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 128 + ] + } + } }, { "Position": { @@ -66,14 +74,18 @@ "TerritoryId": 1189, "InteractionType": "WalkTo", "Fly": true, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -32 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 32 + ] + } + } }, { "DataId": 1051051, @@ -102,14 +114,18 @@ "TerritoryId": 1189, "InteractionType": "WalkTo", "Fly": true, - "CompletionQuestVariablesFlags": [ - null, - null, - null, - null, - null, - -64 - ] + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 64 + ] + } + } }, { "DataId": 1051050, diff --git a/QuestPaths/AssemblyQuestLoader.cs b/QuestPaths/AssemblyQuestLoader.cs index afc7ea83..90ba89a1 100644 --- a/QuestPaths/AssemblyQuestLoader.cs +++ b/QuestPaths/AssemblyQuestLoader.cs @@ -28,5 +28,6 @@ public static partial class AssemblyQuestLoader public static Stream QuestSchema => typeof(AssemblyQuestLoader).Assembly.GetManifestResourceStream("Questionable.QuestPaths.QuestSchema")!; + [SuppressMessage("ReSharper", "UnusedMember.Local")] private static void AddQuest(ushort questId, QuestRoot root) => _quests![questId] = root; } diff --git a/QuestPaths/quest-v1.json b/QuestPaths/quest-v1.json index 8cda540c..751e4730 100644 --- a/QuestPaths/quest-v1.json +++ b/QuestPaths/quest-v1.json @@ -182,6 +182,9 @@ "Never": { "type": "boolean" }, + "CompletionQuestVariablesFlags": { + "$ref": "#/$defs/CompletionFlags" + }, "Flying": { "type": "string", "enum": [ @@ -237,7 +240,8 @@ "WakingSandsMainArea" ] } - } + }, + "additionalProperties": false }, "AetheryteShortcutIf": { "type": "object", @@ -248,7 +252,8 @@ "InSameTerritory": { "type": "boolean" } - } + }, + "additionalProperties": false }, "AethernetShortcutIf": { "type": "object", @@ -259,7 +264,8 @@ "InSameTerritory": { "type": "boolean" } - } + }, + "additionalProperties": false } }, "additionalProperties": false @@ -1309,28 +1315,54 @@ "type": "array", "description": "Quest Variables that dictate whether or not this step is skipped: null is don't check, positive values need to be set, negative values need to be unset", "items": { - "type": [ - "integer", - "null" - ], - "enum": [ - null, - 1, - 2, - 4, - 8, - 16, - 32, - 64, - 128, - -1, - -2, - -4, - -8, - -16, - -32, - -64, - -128 + "oneOf": [ + { + "type": "object", + "properties": { + "High": { + "type": [ + "number", + "null" + ], + "minimum": 0, + "maximum": 15 + }, + "Low": { + "type": [ + "number", + "null" + ], + "minimum": 0, + "maximum": 15 + }, + "Negative": { + "type": "boolean" + }, + "Mode": { + "type": "string", + "enum": [ + "Bitwise", + "Exact" + ] + } + } + }, + { + "type": "number", + "enum": [ + 1, + 2, + 4, + 8, + 16, + 32, + 64, + 128 + ] + }, + { + "type": "null" + } ] }, "minItems": 6, diff --git a/Questionable.Model/V1/ComplexCombatData.cs b/Questionable.Model/V1/ComplexCombatData.cs index a408a29f..d31de7e2 100644 --- a/Questionable.Model/V1/ComplexCombatData.cs +++ b/Questionable.Model/V1/ComplexCombatData.cs @@ -14,6 +14,6 @@ public sealed class ComplexCombatData /// public uint? RewardItemId { get; set; } public int? RewardItemCount { get; set; } - public IList CompletionQuestVariablesFlags { get; set; } = new List(); + public IList CompletionQuestVariablesFlags { get; set; } = new List(); public bool IgnoreQuestMarker { get; set; } } diff --git a/Questionable.Model/V1/Converter/QuestWorkConfigConverter.cs b/Questionable.Model/V1/Converter/QuestWorkConfigConverter.cs index 9f6b0e7e..2b376937 100644 --- a/Questionable.Model/V1/Converter/QuestWorkConfigConverter.cs +++ b/Questionable.Model/V1/Converter/QuestWorkConfigConverter.cs @@ -15,6 +15,7 @@ public sealed class QuestWorkConfigConverter : JsonConverter throw new JsonException(); byte? high = null, low = null; + EQuestWorkMode mode = EQuestWorkMode.Bitwise; while (reader.Read()) { switch (reader.TokenType) @@ -34,6 +35,10 @@ public sealed class QuestWorkConfigConverter : JsonConverter low = reader.GetByte(); break; + case nameof(QuestWorkValue.Mode): + mode = new QuestWorkModeConverter().Read(ref reader, typeof(EQuestWorkMode), options); + break; + default: throw new JsonException(); } @@ -41,7 +46,7 @@ public sealed class QuestWorkConfigConverter : JsonConverter break; case JsonTokenType.EndObject: - return new QuestWorkValue(high, low); + return new QuestWorkValue(high, low, mode); default: throw new JsonException(); diff --git a/Questionable.Model/V1/Converter/QuestWorkModeConverter.cs b/Questionable.Model/V1/Converter/QuestWorkModeConverter.cs new file mode 100644 index 00000000..a3697d66 --- /dev/null +++ b/Questionable.Model/V1/Converter/QuestWorkModeConverter.cs @@ -0,0 +1,12 @@ +using System.Collections.Generic; + +namespace Questionable.Model.V1.Converter; + +public sealed class QuestWorkModeConverter() : EnumConverter(Values) +{ + private static readonly Dictionary Values = new() + { + { EQuestWorkMode.Bitwise, "Bitwise" }, + { EQuestWorkMode.Exact, "Exact" }, + }; +} diff --git a/Questionable.Model/V1/Converter/StringListOrValueConverter.cs b/Questionable.Model/V1/Converter/StringListOrValueConverter.cs index d3e6ea6f..b6da81a2 100644 --- a/Questionable.Model/V1/Converter/StringListOrValueConverter.cs +++ b/Questionable.Model/V1/Converter/StringListOrValueConverter.cs @@ -7,7 +7,7 @@ namespace Questionable.Model.V1.Converter; public sealed class StringListOrValueConverter : JsonConverter> { - public override List? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override List Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.String) return [reader.GetString()!]; diff --git a/Questionable.Model/V1/EQuestWorkMode.cs b/Questionable.Model/V1/EQuestWorkMode.cs new file mode 100644 index 00000000..ef225b23 --- /dev/null +++ b/Questionable.Model/V1/EQuestWorkMode.cs @@ -0,0 +1,11 @@ +using System.Text.Json.Serialization; +using Questionable.Model.V1.Converter; + +namespace Questionable.Model.V1; + +[JsonConverter(typeof(QuestWorkModeConverter))] +public enum EQuestWorkMode +{ + Bitwise, + Exact, +} diff --git a/Questionable.Model/V1/QuestStep.cs b/Questionable.Model/V1/QuestStep.cs index 37d4a0d8..accd6623 100644 --- a/Questionable.Model/V1/QuestStep.cs +++ b/Questionable.Model/V1/QuestStep.cs @@ -64,7 +64,7 @@ public sealed class QuestStep public SkipConditions? SkipConditions { get; set; } public List?> RequiredQuestVariables { get; set; } = new(); - public IList CompletionQuestVariablesFlags { get; set; } = new List(); + public IList CompletionQuestVariablesFlags { get; set; } = new List(); public IList DialogueChoices { get; set; } = new List(); public IList PointMenuChoices { get; set; } = new List(); diff --git a/Questionable.Model/V1/QuestWorkValue.cs b/Questionable.Model/V1/QuestWorkValue.cs index 7321b2be..75c68511 100644 --- a/Questionable.Model/V1/QuestWorkValue.cs +++ b/Questionable.Model/V1/QuestWorkValue.cs @@ -1,16 +1,30 @@ -using System.Text.Json.Serialization; +using System; +using System.Text.Json.Serialization; using Questionable.Model.V1.Converter; namespace Questionable.Model.V1; [JsonConverter(typeof(QuestWorkConfigConverter))] -public sealed class QuestWorkValue(byte? high, byte? low) +public sealed class QuestWorkValue(byte? high, byte? low, EQuestWorkMode mode) { public QuestWorkValue(byte value) - : this((byte)(value >> 4), (byte)(value & 0xF)) + : this((byte)(value >> 4), (byte)(value & 0xF), EQuestWorkMode.Bitwise) { } public byte? High { get; set; } = high; public byte? Low { get; set; } = low; + public EQuestWorkMode Mode { get; set; } = mode; + + public override string ToString() + { + if (High != null && Low != null) + return ((byte)(High << 4) + Low).ToString(); + else if (High != null) + return High + "H"; + else if (Low != null) + return Low + "L"; + else + return "-"; + } } diff --git a/Questionable.Model/V1/SkipStepConditions.cs b/Questionable.Model/V1/SkipStepConditions.cs index 316b1cc1..9186515d 100644 --- a/Questionable.Model/V1/SkipStepConditions.cs +++ b/Questionable.Model/V1/SkipStepConditions.cs @@ -1,10 +1,12 @@ using System.Collections.Generic; +using System.Linq; namespace Questionable.Model.V1; public sealed class SkipStepConditions { public bool Never { get; set; } + public IList CompletionQuestVariablesFlags { get; set; } = new List(); public ELockedSkipCondition? Flying { get; set; } public ELockedSkipCondition? Chocobo { get; set; } public bool NotTargetable { get; set; } @@ -19,7 +21,8 @@ public sealed class SkipStepConditions { if (Never) return false; - return Flying != null || + return (CompletionQuestVariablesFlags.Count > 6 && CompletionQuestVariablesFlags.Any(x => x != null)) || + Flying != null || Chocobo != null || InTerritory.Count > 0 || NotInTerritory.Count > 0 || @@ -27,4 +30,10 @@ public sealed class SkipStepConditions QuestsAccepted.Count > 0 || QuestsCompleted.Count > 0; } + + public override string ToString() + { + return + $"{nameof(Never)}: {Never}, {nameof(CompletionQuestVariablesFlags)}: {CompletionQuestVariablesFlags}, {nameof(Flying)}: {Flying}, {nameof(Chocobo)}: {Chocobo}, {nameof(NotTargetable)}: {NotTargetable}, {nameof(InTerritory)}: {string.Join(" ", InTerritory)}, {nameof(NotInTerritory)}: {string.Join(" ", NotInTerritory)}, {nameof(Item)}: {Item}, {nameof(QuestsAccepted)}: {string.Join(" ", QuestsAccepted)}, {nameof(QuestsCompleted)}: {string.Join(" ", QuestsCompleted)}, {nameof(ExtraCondition)}: {ExtraCondition}"; + } } diff --git a/Questionable/Controller/CombatController.cs b/Questionable/Controller/CombatController.cs index d02def76..f747966e 100644 --- a/Questionable/Controller/CombatController.cs +++ b/Questionable/Controller/CombatController.cs @@ -172,7 +172,7 @@ internal sealed class CombatController : IDisposable { var questWork = _gameFunctions.GetQuestEx(_currentFight.Data.QuestId); if (questWork != null && QuestWorkUtils.MatchesQuestWork(condition.CompletionQuestVariablesFlags, - questWork.Value, false)) + questWork.Value)) { _logger.LogInformation("Complex combat condition fulfilled: QuestWork matches"); _currentFight.Data.CompletedComplexDatas.Add(i); diff --git a/Questionable/Controller/Steps/Interactions/Combat.cs b/Questionable/Controller/Steps/Interactions/Combat.cs index 11f5777d..97201b46 100644 --- a/Questionable/Controller/Steps/Interactions/Combat.cs +++ b/Questionable/Controller/Steps/Interactions/Combat.cs @@ -82,10 +82,10 @@ internal static class Combat { private bool _isLastStep; private CombatController.CombatData _combatData = null!; - private IList _completionQuestVariableFlags = null!; + private IList _completionQuestVariableFlags = null!; public ITask With(ushort questId, bool isLastStep, EEnemySpawnType enemySpawnType, IList killEnemyDataIds, - IList completionQuestVariablesFlags, IList complexCombatData) + IList completionQuestVariablesFlags, IList complexCombatData) { _isLastStep = isLastStep; _combatData = new CombatController.CombatData @@ -113,7 +113,7 @@ internal static class Combat if (questWork == null) return ETaskResult.StillRunning; - if (QuestWorkUtils.MatchesQuestWork(_completionQuestVariableFlags, questWork.Value, false)) + if (QuestWorkUtils.MatchesQuestWork(_completionQuestVariableFlags, questWork.Value)) return ETaskResult.TaskComplete; else return ETaskResult.StillRunning; diff --git a/Questionable/Controller/Steps/Interactions/UseItem.cs b/Questionable/Controller/Steps/Interactions/UseItem.cs index bef6fade..3e1212f8 100644 --- a/Questionable/Controller/Steps/Interactions/UseItem.cs +++ b/Questionable/Controller/Steps/Interactions/UseItem.cs @@ -119,7 +119,7 @@ internal static class UseItem public ushort? QuestId { get; set; } public uint ItemId { get; set; } - public IList CompletionQuestVariablesFlags { get; set; } = new List(); + public IList CompletionQuestVariablesFlags { get; set; } = new List(); public bool StartingCombat { get; set; } protected abstract bool UseItem(); @@ -145,7 +145,7 @@ internal static class UseItem { QuestWork? questWork = gameFunctions.GetQuestEx(QuestId.Value); if (questWork != null && - QuestWorkUtils.MatchesQuestWork(CompletionQuestVariablesFlags, questWork.Value, false)) + QuestWorkUtils.MatchesQuestWork(CompletionQuestVariablesFlags, questWork.Value)) return ETaskResult.TaskComplete; } @@ -202,7 +202,7 @@ internal static class UseItem public uint DataId { get; set; } - public ITask With(ushort? questId, uint dataId, uint itemId, IList completionQuestVariablesFlags) + public ITask With(ushort? questId, uint dataId, uint itemId, IList completionQuestVariablesFlags) { QuestId = questId; DataId = dataId; @@ -226,7 +226,7 @@ internal static class UseItem public Vector3 Position { get; set; } - public ITask With(ushort? questId, Vector3 position, uint itemId, IList completionQuestVariablesFlags) + public ITask With(ushort? questId, Vector3 position, uint itemId, IList completionQuestVariablesFlags) { QuestId = questId; Position = position; @@ -248,7 +248,7 @@ internal static class UseItem public uint DataId { get; set; } - public ITask With(ushort? questId, uint dataId, uint itemId, IList completionQuestVariablesFlags, + public ITask With(ushort? questId, uint dataId, uint itemId, IList completionQuestVariablesFlags, bool startingCombat = false) { QuestId = questId; @@ -269,7 +269,7 @@ internal static class UseItem { private readonly GameFunctions _gameFunctions = gameFunctions; - public ITask With(ushort? questId, uint itemId, IList completionQuestVariablesFlags) + public ITask With(ushort? questId, uint itemId, IList completionQuestVariablesFlags) { QuestId = questId; ItemId = itemId; diff --git a/Questionable/Controller/Steps/Shared/SkipCondition.cs b/Questionable/Controller/Steps/Shared/SkipCondition.cs index 6710071c..2f768ecd 100644 --- a/Questionable/Controller/Steps/Shared/SkipCondition.cs +++ b/Questionable/Controller/Steps/Shared/SkipCondition.cs @@ -156,15 +156,27 @@ internal static class SkipCondition } QuestWork? questWork = gameFunctions.GetQuestEx(QuestId); - if (questWork != null) + if (QuestWorkUtils.HasCompletionFlags(Step.CompletionQuestVariablesFlags) && questWork != null) { - if (QuestWorkUtils.MatchesQuestWork(Step.CompletionQuestVariablesFlags, questWork.Value, true)) + if (QuestWorkUtils.MatchesQuestWork(Step.CompletionQuestVariablesFlags, questWork.Value)) { - logger.LogInformation("Skipping step, as quest variables match"); + logger.LogInformation("Skipping step, as quest variables match (step is complete)"); return true; } + } - if (!QuestWorkUtils.MatchesRequiredQuestWorkConfig(Step.RequiredQuestVariables, questWork.Value, + if (Step is { SkipConditions.StepIf: { } conditions } && questWork != null) + { + if (QuestWorkUtils.MatchesQuestWork(conditions.CompletionQuestVariablesFlags, questWork.Value)) + { + logger.LogInformation("Skipping step, as quest variables match (step can be skipped)"); + return true; + } + } + + if (Step is { RequiredQuestVariables: { } requiredQuestVariables } && questWork != null) + { + if (!QuestWorkUtils.MatchesRequiredQuestWorkConfig(requiredQuestVariables, questWork.Value, logger)) { logger.LogInformation("Skipping step, as required variables do not match"); diff --git a/Questionable/Controller/Steps/Shared/WaitAtEnd.cs b/Questionable/Controller/Steps/Shared/WaitAtEnd.cs index 16a5589b..0d44663c 100644 --- a/Questionable/Controller/Steps/Shared/WaitAtEnd.cs +++ b/Questionable/Controller/Steps/Shared/WaitAtEnd.cs @@ -27,7 +27,7 @@ internal static class WaitAtEnd { public IEnumerable CreateAllTasks(Quest quest, QuestSequence sequence, QuestStep step) { - if (step.CompletionQuestVariablesFlags.Count == 6 && step.CompletionQuestVariablesFlags.Any(x => x is > 0)) + if (step.CompletionQuestVariablesFlags.Count == 6 && QuestWorkUtils.HasCompletionFlags(step.CompletionQuestVariablesFlags)) { var task = serviceProvider.GetRequiredService() .With(quest, step); @@ -164,7 +164,7 @@ internal static class WaitAtEnd { public Quest Quest { get; set; } = null!; public QuestStep Step { get; set; } = null!; - public IList Flags { get; set; } = null!; + public IList Flags { get; set; } = null!; public ITask With(Quest quest, QuestStep step) { @@ -180,13 +180,13 @@ internal static class WaitAtEnd { QuestWork? questWork = gameFunctions.GetQuestEx(Quest.QuestId); return questWork != null && - QuestWorkUtils.MatchesQuestWork(Step.CompletionQuestVariablesFlags, questWork.Value, false) + QuestWorkUtils.MatchesQuestWork(Step.CompletionQuestVariablesFlags, questWork.Value) ? ETaskResult.TaskComplete : ETaskResult.StillRunning; } public override string ToString() => - $"Wait(QW: {string.Join(", ", Flags.Select(x => x?.ToString(CultureInfo.InvariantCulture) ?? "-"))})"; + $"Wait(QW: {string.Join(", ", Flags.Select(x => x?.ToString() ?? "-"))})"; } internal sealed class WaitObjectAtPosition(GameFunctions gameFunctions) : ITask diff --git a/Questionable/Controller/Utils/QuestWorkUtils.cs b/Questionable/Controller/Utils/QuestWorkUtils.cs index 33edd498..6bb77180 100644 --- a/Questionable/Controller/Utils/QuestWorkUtils.cs +++ b/Questionable/Controller/Utils/QuestWorkUtils.cs @@ -10,40 +10,50 @@ namespace Questionable.Controller.Utils; internal static class QuestWorkUtils { - public static bool HasCompletionFlags(IList completionQuestVariablesFlags) + public static bool HasCompletionFlags(IList completionQuestVariablesFlags) { - return completionQuestVariablesFlags.Count == 6 && completionQuestVariablesFlags.Any(x => x != null); + return completionQuestVariablesFlags.Count == 6 && completionQuestVariablesFlags.Any(x => x != null && (x.High != 0 || x.Low != 0)); } - /// - /// Positive values: Must be set to this value; will wait for the step to have these set. - /// Negative values: Will skip if set to this value, won't wait for this to be set. - /// - public static bool MatchesQuestWork(IList completionQuestVariablesFlags, QuestWork questWork, bool forSkip) + public static bool MatchesQuestWork(IList completionQuestVariablesFlags, QuestWork questWork) { if (!HasCompletionFlags(completionQuestVariablesFlags)) return false; for (int i = 0; i < 6; ++i) { - short? check = completionQuestVariablesFlags[i]; + QuestWorkValue? check = completionQuestVariablesFlags[i]; if (check == null) continue; - byte actualValue = questWork.Variables[i]; - byte checkByte = check > 0 ? (byte)check : (byte)-check; - if (forSkip) + EQuestWorkMode mode = check.Mode; + + byte actualHigh = (byte)(questWork.Variables[i] >> 4); + byte actualLow = (byte)(questWork.Variables[i] & 0xF); + + byte? checkHigh = check.High; + byte? checkLow = check.Low; + + byte expectedHigh = checkHigh.GetValueOrDefault(); + byte expectedLow = checkLow.GetValueOrDefault(); + if (mode == EQuestWorkMode.Exact) { - byte expectedValue = (byte)Math.Abs(check.Value); - if ((actualValue & checkByte) != expectedValue) + if (checkHigh != null && actualHigh != expectedHigh) + return false; + + if (checkLow != null && actualLow != expectedLow) return false; } - else if (!forSkip && check > 0) + else if (mode == EQuestWorkMode.Bitwise) { - byte expectedValue = check > 0 ? (byte)check : (byte)0; - if ((actualValue & checkByte) != expectedValue) + if (checkHigh != null && (actualHigh & checkHigh) != expectedHigh) + return false; + + if (checkLow != null && (actualLow & checkLow) != expectedLow) return false; } + else + throw new InvalidOperationException($"Unknown qw mode {mode}"); } return true; @@ -54,7 +64,7 @@ internal static class QuestWorkUtils { if (requiredQuestVariables.Count != 6 || requiredQuestVariables.All(x => x == null || x.Count == 0)) { - logger.LogInformation("No RQW defined"); + logger.LogDebug("No RQW defined"); return true; } @@ -71,7 +81,7 @@ internal static class QuestWorkUtils foreach (QuestWorkValue expectedValue in requiredQuestVariables[i]!) { - logger.LogInformation("H: {ExpectedHigh} - {ActualHigh}, L: {ExpectedLow} - {ActualLow}", + logger.LogDebug("H: {ExpectedHigh} - {ActualHigh}, L: {ExpectedLow} - {ActualLow}", expectedValue.High, high, expectedValue.Low, low); if (expectedValue.High != null && expectedValue.High != high) continue; diff --git a/Questionable/Validation/Validators/CompletionFlagsValidator.cs b/Questionable/Validation/Validators/CompletionFlagsValidator.cs index 462e9289..1d36c8c4 100644 --- a/Questionable/Validation/Validators/CompletionFlagsValidator.cs +++ b/Questionable/Validation/Validators/CompletionFlagsValidator.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Numerics; using Questionable.Controller.Utils; using Questionable.Model; +using Questionable.Model.V1; namespace Questionable.Validation.Validators; @@ -19,10 +20,13 @@ internal sealed class CompletionFlagsValidator : IQuestValidator { return Enumerable.Range(0, 6).Select(y => { - short? value = x.CompletionQuestVariablesFlags[y]; - if (value == null || value.Value < 0) + QuestWorkValue? value = x.CompletionQuestVariablesFlags[y]; + if (value == null) return 0; - return (long)BitOperations.RotateLeft((ulong)value.Value, 8 * y); + + // this isn't perfect, as it assumes {High: 1, Low: null} == {High: 1, Low: 0} + return (long)BitOperations.RotateLeft( + (ulong)(value.High.GetValueOrDefault() * 16 + value.Low.GetValueOrDefault()), 8 * y); }) .Sum(); } @@ -46,7 +50,8 @@ internal sealed class CompletionFlagsValidator : IQuestValidator Step = i, Type = EIssueType.DuplicateCompletionFlags, Severity = EIssueSeverity.Error, - Description = $"Duplicate completion flags: {string.Join(", ", sequence.Steps[i].CompletionQuestVariablesFlags)}", + Description = + $"Duplicate completion flags: {string.Join(", ", sequence.Steps[i].CompletionQuestVariablesFlags)}", }; } } From 252424c802f36ceb43c2bae0c9b959368d36bc4c Mon Sep 17 00:00:00 2001 From: Liza Carvelli Date: Thu, 1 Aug 2024 03:23:09 +0200 Subject: [PATCH 04/12] Replace NotInSameTerritory --- .../Class Quests/SCH/1098_The Last Remnants.json | 2 +- .../Class Quests/WAR/1050_Embracing the Beast.json | 2 +- .../Class Quests/WAR/1052_Looking the Part.json | 4 ++-- .../Class Quests/WAR/1053_Proof Is the Pudding.json | 2 +- .../MSQ-1/Shared/685_For Coin and Country.json | 2 +- .../A0-Gridania to East Shroud/3856_We Come in Peace.json | 2 +- .../A0-Gridania to East Shroud/709_Sylphic Studies.json | 2 +- .../A0-Gridania to East Shroud/710_First Impressions.json | 2 +- .../MSQ-2/A1-East Shroud/3857_Dance Dance Diplomacy.json | 2 +- .../MSQ-2/A1-East Shroud/3858_Forest Friend.json | 2 +- .../MSQ-2/A1-East Shroud/715_First Contact.json | 2 +- .../MSQ-2/A1-East Shroud/719_Presence of the Enemy.json | 2 +- .../A2-East Shroud to South Shroud/724_Brotherly Love.json | 2 +- .../A2-East Shroud to South Shroud/725_Spirited Away.json | 2 +- .../3862_Nouveau Riche.json | 2 +- .../514_Into the Beast's Maw.json | 2 +- .../738_Sylphish Concerns.json | 2 +- .../MSQ-2/A4-Back from the Woods/743_A Simple Gift.json | 2 +- .../A4-Back from the Woods/744_Believe in Your Sylph.json | 2 +- .../A4-Back from the Woods/746_Back from the Wood.json | 2 +- .../MSQ-2/A4-Back from the Woods/748_Highbridge Times.json | 2 +- .../756_Where There Is Smoke.json | 2 +- .../757_On to Little Ala Mhigo.json | 2 +- .../761_Tea for Three.json | 2 +- .../762_Foot in the Door.json | 2 +- .../A6-South Shroud, Quarrymill/765_Killing Him Softly.json | 2 +- .../774_Helping Horn.json | 2 +- .../775_He Ain't Heavy.json | 2 +- .../776_Come Highly Recommended.json | 2 +- .../777_The Bear and the Young'uns' Cares.json | 2 +- .../778_Wilred Wants You.json | 2 +- .../782_Big Trouble in Little Ala Mhigo.json | 2 +- .../783_Back to Square One.json | 2 +- .../786_Seeing Eye to Winged Eye.json | 2 +- .../787_Rock of Rancor.json | 2 +- .../MSQ-2/A9-Haukke Manor/799_Power of Deduction.json | 2 +- .../MSQ-2/A9-Haukke Manor/800_Secret of the White Lily.json | 2 +- .../MSQ-2/B0-Company of Heroes/3865_Trial by Turtle.json | 2 +- .../MSQ-2/B0-Company of Heroes/812_Nix That.json | 2 +- .../MSQ-2/B0-Company of Heroes/814_A Modest Proposal.json | 2 +- .../MSQ-2/B1-Forgotten Springs/821_The Perfect Prey.json | 2 +- .../MSQ-2/B1-Forgotten Springs/822_When the Worm Turns.json | 2 +- .../B1-Forgotten Springs/831_There and Back Again.json | 2 +- .../3866_What Do You Mean You Forgot the Wine.json | 2 +- .../832_The Things We Do for Cheese.json | 2 +- .../840_An Offer You Can Refuse.json | 2 +- .../843_It Won't Work.json | 2 +- .../B3-Eastern La Noscea, Wine/845_Give a Man a Drink.json | 2 +- .../MSQ-2/B3-Eastern La Noscea, Wine/846_That Weight.json | 2 +- .../MSQ-2/B3-Eastern La Noscea, Wine/848_Battle Scars.json | 2 +- .../850_It Was a Very Good Year.json | 2 +- .../855_In the Company of Heroes.json | 2 +- .../MSQ-2/B3-Eastern La Noscea, Wine/856_As You Wish.json | 2 +- .../MSQ-2/B4-Titan/857_Lord of Crags.json | 2 +- .../3867_You Can't Take It with You.json | 2 +- .../MSQ-2/B5-Western Thanalan/517_All Good Things.json | 2 +- .../MSQ-2/B5-Western Thanalan/518_Eyes on Me.json | 2 +- .../B5-Western Thanalan/876_Bringing out the Dead.json | 2 +- .../878_Bury Me Not on the Lone Prairie.json | 2 +- .../883_He Who Waited Behind.json | 2 +- .../884_Cold Reception.json | 2 +- .../897_The Talk of Coerthas.json | 2 +- .../910_Road to Redemption.json | 2 +- .../911_Following the Evidence.json | 2 +- .../912_In the Eyes of Gods and Men.json | 2 +- .../3868_The Final Flight of the Enterprise.json | 2 +- .../3869_The Best Inventions.json | 2 +- .../924_Ye of Little Faith.json | 2 +- .../927_Factual Folklore.json | 2 +- .../938_Influencing Inquisitors.json | 2 +- .../939_By the Lights of Ishgard.json | 2 +- .../940_Blood for Blood.json | 2 +- .../941_The Heretic among Us.json | 2 +- .../952_In Pursuit of the Past.json | 2 +- .../955_Sealed With Science.json | 2 +- .../956_With the Utmost Care.json | 2 +- .../959_A Promising Prospect.json | 2 +- .../960_It's Probably Not Pirates.json | 2 +- .../961_Representing the Representative.json | 2 +- .../962_The Reluctant Researcher.json | 2 +- .../MSQ-2/C3-Garuda/3870_The Curious Case of Giggity.json | 2 +- .../MSQ-2/C6-Mor Dhona/1004_Fool Me Twice.json | 2 +- .../MSQ-2/C9-Ultimate Weapon/3872_Hearts on Fire.json | 2 +- .../MSQ-2/C9-Ultimate Weapon/3873_Rock the Castrum.json | 2 +- .../MSQ-2/C9-Ultimate Weapon/4522_The Ultimate Weapon.json | 2 +- .../MSQ-2/E1-2.1/1189_Hail to the King, Kupo.json | 2 +- .../MSQ-2/E1-2.1/1191_On the Properties of Primals.json | 2 +- .../MSQ-2/E1-2.1/3875_All Things in Time.json | 2 +- .../MSQ-2/E1-2.1/3877_It's Possibly a Primal.json | 2 +- .../MSQ-2/E2-2.2/1346_A Final Temptation.json | 2 +- .../MSQ-2/E2-2.2/1347_The Mother of Exiles.json | 2 +- .../MSQ-2/E2-2.2/1352_Why We Adventure.json | 2 +- .../MSQ-2/E2-2.2/1361_Lord of the Whorl.json | 2 +- .../MSQ-2/E2-2.2/1362_When Yugiri Met the Fraternity.json | 2 +- .../MSQ-2/E2-2.2/1363_Through the Maelstrom.json | 2 +- .../MSQ-2/E2-2.2/3881_Yugiri's Game.json | 2 +- .../MSQ-2/E2-2.2/3882_All Due Respect.json | 2 +- .../MSQ-2/E3-2.3/1443_Desperate Times.json | 2 +- .../2.x - A Realm Reborn/MSQ-2/E3-2.3/1446_Revolution.json | 2 +- .../MSQ-2/E3-2.3/1447_Stories We Tell.json | 2 +- .../MSQ-2/E3-2.3/1453_What Little Gods Are Made Of.json | 4 ++-- .../MSQ-2/E3-2.3/1459_When the Cold Sets In.json | 2 +- .../MSQ-2/E3-2.3/1460_Brave New Companions.json | 4 ++-- .../MSQ-2/E3-2.3/3883_Shock and Awe.json | 2 +- .../MSQ-2/E3-2.3/3884_Reap the Whirlwind.json | 2 +- .../MSQ-2/E3-2.3/3885_Levin an Impression.json | 2 +- .../2.x - A Realm Reborn/MSQ-2/E4-2.4/3886_Chasing Ivy.json | 2 +- .../MSQ-2/E4-2.4/3887_In Flagrante Delicto.json | 2 +- .../MSQ-2/E4-2.4/53_Back and Fourth.json | 2 +- .../MSQ-2/E4-2.4/57_The Intercession of Saints.json | 2 +- .../MSQ-2/E4-2.4/62_Strength in Unity.json | 2 +- .../MSQ-2/E4-2.4/87_Eyes Unclouded.json | 2 +- .../MSQ-2/E4-2.4/89_Let Us Cling Together.json | 2 +- .../MSQ-2/E5-2.5/364_Bait and Switch.json | 2 +- .../MSQ-2/E5-2.5/369_An Uninvited Ascian.json | 2 +- .../MSQ-2/E6-2.55/418_An Allied Perspective.json | 2 +- .../MSQ-2/E6-2.55/424_The Least among Us.json | 2 +- .../MSQ-2/E6-2.55/428_Before the Dawn.json | 2 +- .../Raid Quests/1200_Sanding It Down.json | 2 +- .../Raid Quests/1201_A Performance for the Ages.json | 2 +- .../Raid Quests/1202_Labyrinth of the Ancients.json | 2 +- .../Raid Quests/1203_For Prosperity.json | 2 +- .../2.x - A Realm Reborn/Raid Quests/1474_Syrcus Tower.json | 2 +- .../Raid Quests/1709_Legacy of Allag.json | 2 +- .../Raid Quests/494_The World of Darkness.json | 2 +- .../Raid Quests/495_The Light of Hope.json | 2 +- .../1797_The Hunter Becomes the Kweh.json | 2 +- .../The Dravanian Forelands/1802_A Lesson in Humility.json | 2 +- .../1582_The Better Half.json | 2 +- .../1584_Work in Progress.json | 2 +- .../1587_Reconnaissance Lost.json | 2 +- .../1591_An Indispensable Ally.json | 2 +- .../1596_A Reward Long in Coming.json | 2 +- .../Unlocks/Hunts/2119_Let the Clan Hunt Begin.json | 2 +- .../3.x - Heavensward/Unlocks/Hunts/2121_Top Marks.json | 2 +- .../Unlocks/Hunts/2122_Elite and Dangerous.json | 2 +- .../Unlocks/Misc/2107_Sights of the North.json | 2 +- .../Unlocks/Misc/2118_A Striking Opportunity.json | 2 +- .../Unlocks/Hunts/2936_One-star Veteran Clan Hunt.json | 2 +- .../Unlocks/Hunts/2937_Two-star Veteran Clan Hunt.json | 2 +- .../Unlocks/Hunts/2938_Three-star Veteran Clan Hunt.json | 2 +- .../Unlocks/Hunts/2939_Elite Veteran Clan Hunt.json | 2 +- .../Unlocks/Misc/2940_Another Striking Opportunity.json | 2 +- .../MSQ/C-Rak'tika/3323_A Little Faith.json | 2 +- .../MSQ/C-Rak'tika/3326_A Helping Hand.json | 2 +- .../Unlocks/Hunts/3598_Two Nuts Too Nutty.json | 2 +- .../Unlocks/Hunts/3599_How Do You Like Three Nuts.json | 2 +- .../Unlocks/Hunts/3600_Too Many Nutters.json | 2 +- .../Unlocks/Misc/3601_Yet Another Striking Opportunity.json | 2 +- .../Tribal/Allied/4788_A Dream Worth Chasing.json | 2 +- .../Unlocks/Hunts/4176_The Hunt for Specimens.json | 2 +- .../Hunts/4177_That Specimen Came from the Moon.json | 2 +- .../Unlocks/Hunts/4178_A Hunt for the Ages.json | 2 +- .../Unlocks/Hunts/4179_Perfect Specimens.json | 2 +- .../6.x - Endwalker/Unlocks/Misc/4173_A Place to Train.json | 2 +- .../VPR/4850_Viper in the Vidraal's Shadow.json | 2 +- .../Class Quests/VPR/4851_Vipers on the Hunt.json | 6 +++--- .../4860_A New World to Explore.json | 2 +- .../Role Quests/Healer/4824_In the Sting of Things.json | 2 +- .../Healer/4825_Causing Problems on Purpose.json | 2 +- .../Role Quests/Healer/4826_Living among the Deadly.json | 2 +- .../Role Quests/Healer/4827_Taste of a Toxin Paradise.json | 2 +- .../Role Quests/Healer/4828_Downed by the River.json | 2 +- .../Role Quests/Healer/4829_An Antidote for Anarchy.json | 2 +- .../Role Quests/Melee/4830_The Hunter and the Hunted.json | 4 ++-- .../Role Quests/Melee/4831_A Sea of Blood.json | 2 +- .../7.x - Dawntrail/Role Quests/Melee/4832_Who's Who.json | 4 ++-- .../Role Quests/Melee/4833_Cornered Prey.json | 2 +- .../Role Quests/Melee/4834_Impostor Syndrome.json | 4 ++-- .../Role Quests/Melee/4835_A Hunter True.json | 4 ++-- .../Physical Ranged/4836_To Steal a Steelhog.json | 2 +- .../Role Quests/Physical Ranged/4837_Bandits Abound.json | 2 +- .../Urqopacha/5040_Too Much of a Good Thing.json | 2 +- .../Unlocks/Dungeons/5013_It Belongs in a Museum.json | 2 +- .../7.x - Dawntrail/Unlocks/Misc/5005_Trial by Spire.json | 2 +- 175 files changed, 184 insertions(+), 184 deletions(-) diff --git a/QuestPaths/2.x - A Realm Reborn/Class Quests/SCH/1098_The Last Remnants.json b/QuestPaths/2.x - A Realm Reborn/Class Quests/SCH/1098_The Last Remnants.json index a7116bac..66e6af53 100644 --- a/QuestPaths/2.x - A Realm Reborn/Class Quests/SCH/1098_The Last Remnants.json +++ b/QuestPaths/2.x - A Realm Reborn/Class Quests/SCH/1098_The Last Remnants.json @@ -36,7 +36,7 @@ "AetheryteShortcut": "Outer La Noscea - Camp Overlook", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true }, "StepIf": { "CompletionQuestVariablesFlags": [ diff --git a/QuestPaths/2.x - A Realm Reborn/Class Quests/WAR/1050_Embracing the Beast.json b/QuestPaths/2.x - A Realm Reborn/Class Quests/WAR/1050_Embracing the Beast.json index 0a93deb3..1ec8610d 100644 --- a/QuestPaths/2.x - A Realm Reborn/Class Quests/WAR/1050_Embracing the Beast.json +++ b/QuestPaths/2.x - A Realm Reborn/Class Quests/WAR/1050_Embracing the Beast.json @@ -37,7 +37,7 @@ "AetheryteShortcut": "Southern Thanalan - Forgotten Springs", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } }, "CompletionQuestVariablesFlags": [ diff --git a/QuestPaths/2.x - A Realm Reborn/Class Quests/WAR/1052_Looking the Part.json b/QuestPaths/2.x - A Realm Reborn/Class Quests/WAR/1052_Looking the Part.json index 5e629673..c87c93ab 100644 --- a/QuestPaths/2.x - A Realm Reborn/Class Quests/WAR/1052_Looking the Part.json +++ b/QuestPaths/2.x - A Realm Reborn/Class Quests/WAR/1052_Looking the Part.json @@ -31,7 +31,7 @@ "AetheryteShortcut": "Coerthas Central Highlands - Camp Dragonhead", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true }, "StepIf": { "CompletionQuestVariablesFlags": [ @@ -105,7 +105,7 @@ "Fly": true, "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } }, "Comment": "TODO Verify enemy id" diff --git a/QuestPaths/2.x - A Realm Reborn/Class Quests/WAR/1053_Proof Is the Pudding.json b/QuestPaths/2.x - A Realm Reborn/Class Quests/WAR/1053_Proof Is the Pudding.json index 44bf6fae..ff849d9e 100644 --- a/QuestPaths/2.x - A Realm Reborn/Class Quests/WAR/1053_Proof Is the Pudding.json +++ b/QuestPaths/2.x - A Realm Reborn/Class Quests/WAR/1053_Proof Is the Pudding.json @@ -45,7 +45,7 @@ "AetheryteShortcut": "Coerthas Central Highlands - Camp Dragonhead", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } }, diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-1/Shared/685_For Coin and Country.json b/QuestPaths/2.x - A Realm Reborn/MSQ-1/Shared/685_For Coin and Country.json index 7a9e8dad..62d293c2 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-1/Shared/685_For Coin and Country.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-1/Shared/685_For Coin and Country.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Ul'dah", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/A0-Gridania to East Shroud/3856_We Come in Peace.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/A0-Gridania to East Shroud/3856_We Come in Peace.json index 0d97069e..cc54a28b 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/A0-Gridania to East Shroud/3856_We Come in Peace.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/A0-Gridania to East Shroud/3856_We Come in Peace.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Gridania", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/A0-Gridania to East Shroud/709_Sylphic Studies.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/A0-Gridania to East Shroud/709_Sylphic Studies.json index 30354318..aa75e6a4 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/A0-Gridania to East Shroud/709_Sylphic Studies.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/A0-Gridania to East Shroud/709_Sylphic Studies.json @@ -18,7 +18,7 @@ "AetheryteShortcut": "East Shroud - Hawthorne Hut", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/A0-Gridania to East Shroud/710_First Impressions.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/A0-Gridania to East Shroud/710_First Impressions.json index 1eec0b6a..3fe97692 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/A0-Gridania to East Shroud/710_First Impressions.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/A0-Gridania to East Shroud/710_First Impressions.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "East Shroud - Hawthorne Hut", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/A1-East Shroud/3857_Dance Dance Diplomacy.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/A1-East Shroud/3857_Dance Dance Diplomacy.json index 742a9070..d41eeb81 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/A1-East Shroud/3857_Dance Dance Diplomacy.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/A1-East Shroud/3857_Dance Dance Diplomacy.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "East Shroud - Hawthorne Hut", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/A1-East Shroud/3858_Forest Friend.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/A1-East Shroud/3858_Forest Friend.json index 3d130a3c..fe5f07a6 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/A1-East Shroud/3858_Forest Friend.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/A1-East Shroud/3858_Forest Friend.json @@ -18,7 +18,7 @@ "AetheryteShortcut": "East Shroud - Hawthorne Hut", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/A1-East Shroud/715_First Contact.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/A1-East Shroud/715_First Contact.json index c9a4a7cc..f2ffc0c1 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/A1-East Shroud/715_First Contact.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/A1-East Shroud/715_First Contact.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "East Shroud - Hawthorne Hut", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/A1-East Shroud/719_Presence of the Enemy.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/A1-East Shroud/719_Presence of the Enemy.json index a9d3be61..d72c7c6c 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/A1-East Shroud/719_Presence of the Enemy.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/A1-East Shroud/719_Presence of the Enemy.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "East Shroud - Hawthorne Hut", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/A2-East Shroud to South Shroud/724_Brotherly Love.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/A2-East Shroud to South Shroud/724_Brotherly Love.json index fc825bbb..2b4fbd24 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/A2-East Shroud to South Shroud/724_Brotherly Love.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/A2-East Shroud to South Shroud/724_Brotherly Love.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "East Shroud - Hawthorne Hut", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/A2-East Shroud to South Shroud/725_Spirited Away.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/A2-East Shroud to South Shroud/725_Spirited Away.json index 866b4f46..a2dbdcab 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/A2-East Shroud to South Shroud/725_Spirited Away.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/A2-East Shroud to South Shroud/725_Spirited Away.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "East Shroud - Hawthorne Hut", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/A3-South Shroud, Buscarron’s Druthers/3862_Nouveau Riche.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/A3-South Shroud, Buscarron’s Druthers/3862_Nouveau Riche.json index 1cd7a8b3..dfda0e54 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/A3-South Shroud, Buscarron’s Druthers/3862_Nouveau Riche.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/A3-South Shroud, Buscarron’s Druthers/3862_Nouveau Riche.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "South Shroud - Quarrymill", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/A3-South Shroud, Buscarron’s Druthers/514_Into the Beast's Maw.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/A3-South Shroud, Buscarron’s Druthers/514_Into the Beast's Maw.json index 4fea783e..12924d71 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/A3-South Shroud, Buscarron’s Druthers/514_Into the Beast's Maw.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/A3-South Shroud, Buscarron’s Druthers/514_Into the Beast's Maw.json @@ -20,7 +20,7 @@ "AetheryteShortcut": "South Shroud - Quarrymill", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/A3-South Shroud, Buscarron’s Druthers/738_Sylphish Concerns.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/A3-South Shroud, Buscarron’s Druthers/738_Sylphish Concerns.json index e4b2ae37..a7e83e81 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/A3-South Shroud, Buscarron’s Druthers/738_Sylphish Concerns.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/A3-South Shroud, Buscarron’s Druthers/738_Sylphish Concerns.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "South Shroud - Quarrymill", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/A4-Back from the Woods/743_A Simple Gift.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/A4-Back from the Woods/743_A Simple Gift.json index 97962854..87bffb88 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/A4-Back from the Woods/743_A Simple Gift.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/A4-Back from the Woods/743_A Simple Gift.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "South Shroud - Quarrymill", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/A4-Back from the Woods/744_Believe in Your Sylph.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/A4-Back from the Woods/744_Believe in Your Sylph.json index 55481985..71ac7920 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/A4-Back from the Woods/744_Believe in Your Sylph.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/A4-Back from the Woods/744_Believe in Your Sylph.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "East Shroud - Hawthorne Hut", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/A4-Back from the Woods/746_Back from the Wood.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/A4-Back from the Woods/746_Back from the Wood.json index b5746991..41c91c81 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/A4-Back from the Woods/746_Back from the Wood.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/A4-Back from the Woods/746_Back from the Wood.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Gridania", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/A4-Back from the Woods/748_Highbridge Times.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/A4-Back from the Woods/748_Highbridge Times.json index 96feca91..5b11524c 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/A4-Back from the Woods/748_Highbridge Times.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/A4-Back from the Woods/748_Highbridge Times.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Eastern Thanalan - Camp Drybone", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/A5-Southern Thanalan, Little Ala Mhigo/756_Where There Is Smoke.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/A5-Southern Thanalan, Little Ala Mhigo/756_Where There Is Smoke.json index 1ff6f279..d33c0cd3 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/A5-Southern Thanalan, Little Ala Mhigo/756_Where There Is Smoke.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/A5-Southern Thanalan, Little Ala Mhigo/756_Where There Is Smoke.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Eastern Thanalan - Camp Drybone", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/A5-Southern Thanalan, Little Ala Mhigo/757_On to Little Ala Mhigo.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/A5-Southern Thanalan, Little Ala Mhigo/757_On to Little Ala Mhigo.json index dc0aa696..27a25019 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/A5-Southern Thanalan, Little Ala Mhigo/757_On to Little Ala Mhigo.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/A5-Southern Thanalan, Little Ala Mhigo/757_On to Little Ala Mhigo.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Eastern Thanalan - Camp Drybone", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/A5-Southern Thanalan, Little Ala Mhigo/761_Tea for Three.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/A5-Southern Thanalan, Little Ala Mhigo/761_Tea for Three.json index f83be304..215cbf4e 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/A5-Southern Thanalan, Little Ala Mhigo/761_Tea for Three.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/A5-Southern Thanalan, Little Ala Mhigo/761_Tea for Three.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Southern Thanalan - Little Ala Mhigo", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/A5-Southern Thanalan, Little Ala Mhigo/762_Foot in the Door.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/A5-Southern Thanalan, Little Ala Mhigo/762_Foot in the Door.json index 7682f735..176f9fac 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/A5-Southern Thanalan, Little Ala Mhigo/762_Foot in the Door.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/A5-Southern Thanalan, Little Ala Mhigo/762_Foot in the Door.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Southern Thanalan - Little Ala Mhigo", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/A6-South Shroud, Quarrymill/765_Killing Him Softly.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/A6-South Shroud, Quarrymill/765_Killing Him Softly.json index 084745c3..e9684cfc 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/A6-South Shroud, Quarrymill/765_Killing Him Softly.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/A6-South Shroud, Quarrymill/765_Killing Him Softly.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "South Shroud - Quarrymill", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/A7-Southern Thanalan, Big Trouble in Little Ala Mhigo/774_Helping Horn.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/A7-Southern Thanalan, Big Trouble in Little Ala Mhigo/774_Helping Horn.json index c5cd8f3c..6f9cb0af 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/A7-Southern Thanalan, Big Trouble in Little Ala Mhigo/774_Helping Horn.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/A7-Southern Thanalan, Big Trouble in Little Ala Mhigo/774_Helping Horn.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "South Shroud - Quarrymill", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/A7-Southern Thanalan, Big Trouble in Little Ala Mhigo/775_He Ain't Heavy.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/A7-Southern Thanalan, Big Trouble in Little Ala Mhigo/775_He Ain't Heavy.json index f62b4890..de323ed9 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/A7-Southern Thanalan, Big Trouble in Little Ala Mhigo/775_He Ain't Heavy.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/A7-Southern Thanalan, Big Trouble in Little Ala Mhigo/775_He Ain't Heavy.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "South Shroud - Quarrymill", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/A7-Southern Thanalan, Big Trouble in Little Ala Mhigo/776_Come Highly Recommended.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/A7-Southern Thanalan, Big Trouble in Little Ala Mhigo/776_Come Highly Recommended.json index e3c2276f..9ee2f4b6 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/A7-Southern Thanalan, Big Trouble in Little Ala Mhigo/776_Come Highly Recommended.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/A7-Southern Thanalan, Big Trouble in Little Ala Mhigo/776_Come Highly Recommended.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "South Shroud - Quarrymill", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/A7-Southern Thanalan, Big Trouble in Little Ala Mhigo/777_The Bear and the Young'uns' Cares.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/A7-Southern Thanalan, Big Trouble in Little Ala Mhigo/777_The Bear and the Young'uns' Cares.json index 4136df47..e13cab7f 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/A7-Southern Thanalan, Big Trouble in Little Ala Mhigo/777_The Bear and the Young'uns' Cares.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/A7-Southern Thanalan, Big Trouble in Little Ala Mhigo/777_The Bear and the Young'uns' Cares.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Southern Thanalan - Little Ala Mhigo", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/A7-Southern Thanalan, Big Trouble in Little Ala Mhigo/778_Wilred Wants You.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/A7-Southern Thanalan, Big Trouble in Little Ala Mhigo/778_Wilred Wants You.json index 341bb2e3..51abeee8 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/A7-Southern Thanalan, Big Trouble in Little Ala Mhigo/778_Wilred Wants You.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/A7-Southern Thanalan, Big Trouble in Little Ala Mhigo/778_Wilred Wants You.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Southern Thanalan - Little Ala Mhigo", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/A7-Southern Thanalan, Big Trouble in Little Ala Mhigo/782_Big Trouble in Little Ala Mhigo.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/A7-Southern Thanalan, Big Trouble in Little Ala Mhigo/782_Big Trouble in Little Ala Mhigo.json index d42dd2ab..7ea44492 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/A7-Southern Thanalan, Big Trouble in Little Ala Mhigo/782_Big Trouble in Little Ala Mhigo.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/A7-Southern Thanalan, Big Trouble in Little Ala Mhigo/782_Big Trouble in Little Ala Mhigo.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Southern Thanalan - Little Ala Mhigo", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/A7-Southern Thanalan, Big Trouble in Little Ala Mhigo/783_Back to Square One.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/A7-Southern Thanalan, Big Trouble in Little Ala Mhigo/783_Back to Square One.json index 32b3b639..c3b2edbd 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/A7-Southern Thanalan, Big Trouble in Little Ala Mhigo/783_Back to Square One.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/A7-Southern Thanalan, Big Trouble in Little Ala Mhigo/783_Back to Square One.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Southern Thanalan - Little Ala Mhigo", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/A8-North Shroud, Murder investigation/786_Seeing Eye to Winged Eye.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/A8-North Shroud, Murder investigation/786_Seeing Eye to Winged Eye.json index 3fb27a70..0363c24f 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/A8-North Shroud, Murder investigation/786_Seeing Eye to Winged Eye.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/A8-North Shroud, Murder investigation/786_Seeing Eye to Winged Eye.json @@ -18,7 +18,7 @@ "AetheryteShortcut": "North Shroud - Fallgourd Float", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/A8-North Shroud, Murder investigation/787_Rock of Rancor.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/A8-North Shroud, Murder investigation/787_Rock of Rancor.json index 3618c40b..30ec3ce6 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/A8-North Shroud, Murder investigation/787_Rock of Rancor.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/A8-North Shroud, Murder investigation/787_Rock of Rancor.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "North Shroud - Fallgourd Float", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/A9-Haukke Manor/799_Power of Deduction.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/A9-Haukke Manor/799_Power of Deduction.json index be710c5d..81520a82 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/A9-Haukke Manor/799_Power of Deduction.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/A9-Haukke Manor/799_Power of Deduction.json @@ -18,7 +18,7 @@ "AetheryteShortcut": "North Shroud - Fallgourd Float", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/A9-Haukke Manor/800_Secret of the White Lily.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/A9-Haukke Manor/800_Secret of the White Lily.json index 0baa498c..c2a143e4 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/A9-Haukke Manor/800_Secret of the White Lily.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/A9-Haukke Manor/800_Secret of the White Lily.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "North Shroud - Fallgourd Float", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/B0-Company of Heroes/3865_Trial by Turtle.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/B0-Company of Heroes/3865_Trial by Turtle.json index db68c5c5..137ffb4d 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/B0-Company of Heroes/3865_Trial by Turtle.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/B0-Company of Heroes/3865_Trial by Turtle.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "South Shroud - Camp Tranquil", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/B0-Company of Heroes/812_Nix That.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/B0-Company of Heroes/812_Nix That.json index 64234727..eb6938c6 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/B0-Company of Heroes/812_Nix That.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/B0-Company of Heroes/812_Nix That.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Eastern La Noscea - Costa Del Sol", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/B0-Company of Heroes/814_A Modest Proposal.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/B0-Company of Heroes/814_A Modest Proposal.json index e509008e..875ee864 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/B0-Company of Heroes/814_A Modest Proposal.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/B0-Company of Heroes/814_A Modest Proposal.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Eastern La Noscea - Costa Del Sol", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/B1-Forgotten Springs/821_The Perfect Prey.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/B1-Forgotten Springs/821_The Perfect Prey.json index 072c6053..6c6ee328 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/B1-Forgotten Springs/821_The Perfect Prey.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/B1-Forgotten Springs/821_The Perfect Prey.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Southern Thanalan - Forgotten Springs", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/B1-Forgotten Springs/822_When the Worm Turns.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/B1-Forgotten Springs/822_When the Worm Turns.json index 4f955a17..22a884cc 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/B1-Forgotten Springs/822_When the Worm Turns.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/B1-Forgotten Springs/822_When the Worm Turns.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Southern Thanalan - Forgotten Springs", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/B1-Forgotten Springs/831_There and Back Again.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/B1-Forgotten Springs/831_There and Back Again.json index 142efd59..c97e49c0 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/B1-Forgotten Springs/831_There and Back Again.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/B1-Forgotten Springs/831_There and Back Again.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Southern Thanalan - Forgotten Springs", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/B2-Eastern La Noscea, Brayflox, Cheese and Wine/3866_What Do You Mean You Forgot the Wine.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/B2-Eastern La Noscea, Brayflox, Cheese and Wine/3866_What Do You Mean You Forgot the Wine.json index 24bb9044..c9cd2fe8 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/B2-Eastern La Noscea, Brayflox, Cheese and Wine/3866_What Do You Mean You Forgot the Wine.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/B2-Eastern La Noscea, Brayflox, Cheese and Wine/3866_What Do You Mean You Forgot the Wine.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Eastern La Noscea - Costa Del Sol", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/B2-Eastern La Noscea, Brayflox, Cheese and Wine/832_The Things We Do for Cheese.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/B2-Eastern La Noscea, Brayflox, Cheese and Wine/832_The Things We Do for Cheese.json index b853bf20..61cf091c 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/B2-Eastern La Noscea, Brayflox, Cheese and Wine/832_The Things We Do for Cheese.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/B2-Eastern La Noscea, Brayflox, Cheese and Wine/832_The Things We Do for Cheese.json @@ -20,7 +20,7 @@ "AetheryteShortcut": "Eastern La Noscea - Costa Del Sol", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/B2-Eastern La Noscea, Brayflox, Cheese and Wine/840_An Offer You Can Refuse.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/B2-Eastern La Noscea, Brayflox, Cheese and Wine/840_An Offer You Can Refuse.json index 38adbccc..79f7c3d6 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/B2-Eastern La Noscea, Brayflox, Cheese and Wine/840_An Offer You Can Refuse.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/B2-Eastern La Noscea, Brayflox, Cheese and Wine/840_An Offer You Can Refuse.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Eastern La Noscea - Wineport", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/B2-Eastern La Noscea, Brayflox, Cheese and Wine/843_It Won't Work.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/B2-Eastern La Noscea, Brayflox, Cheese and Wine/843_It Won't Work.json index 6774dd1b..0020481d 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/B2-Eastern La Noscea, Brayflox, Cheese and Wine/843_It Won't Work.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/B2-Eastern La Noscea, Brayflox, Cheese and Wine/843_It Won't Work.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Eastern La Noscea - Wineport", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/B3-Eastern La Noscea, Wine/845_Give a Man a Drink.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/B3-Eastern La Noscea, Wine/845_Give a Man a Drink.json index 6206721c..ea82e9d7 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/B3-Eastern La Noscea, Wine/845_Give a Man a Drink.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/B3-Eastern La Noscea, Wine/845_Give a Man a Drink.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Eastern La Noscea - Wineport", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/B3-Eastern La Noscea, Wine/846_That Weight.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/B3-Eastern La Noscea, Wine/846_That Weight.json index b869ffb4..fa1c3034 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/B3-Eastern La Noscea, Wine/846_That Weight.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/B3-Eastern La Noscea, Wine/846_That Weight.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Eastern La Noscea - Wineport", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/B3-Eastern La Noscea, Wine/848_Battle Scars.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/B3-Eastern La Noscea, Wine/848_Battle Scars.json index f34cc000..52f4024e 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/B3-Eastern La Noscea, Wine/848_Battle Scars.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/B3-Eastern La Noscea, Wine/848_Battle Scars.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Eastern La Noscea - Wineport", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/B3-Eastern La Noscea, Wine/850_It Was a Very Good Year.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/B3-Eastern La Noscea, Wine/850_It Was a Very Good Year.json index ee6e02b3..bc2237d6 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/B3-Eastern La Noscea, Wine/850_It Was a Very Good Year.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/B3-Eastern La Noscea, Wine/850_It Was a Very Good Year.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Eastern La Noscea - Wineport", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/B3-Eastern La Noscea, Wine/855_In the Company of Heroes.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/B3-Eastern La Noscea, Wine/855_In the Company of Heroes.json index e1ca14af..2aab59ad 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/B3-Eastern La Noscea, Wine/855_In the Company of Heroes.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/B3-Eastern La Noscea, Wine/855_In the Company of Heroes.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Eastern La Noscea - Costa Del Sol", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/B3-Eastern La Noscea, Wine/856_As You Wish.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/B3-Eastern La Noscea, Wine/856_As You Wish.json index 8679e756..93aa32ba 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/B3-Eastern La Noscea, Wine/856_As You Wish.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/B3-Eastern La Noscea, Wine/856_As You Wish.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Eastern La Noscea - Costa Del Sol", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/B4-Titan/857_Lord of Crags.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/B4-Titan/857_Lord of Crags.json index 18022a06..28997d99 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/B4-Titan/857_Lord of Crags.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/B4-Titan/857_Lord of Crags.json @@ -21,7 +21,7 @@ "AetheryteShortcut": "Upper La Noscea - Camp Bronze Lake", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/B5-Western Thanalan/3867_You Can't Take It with You.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/B5-Western Thanalan/3867_You Can't Take It with You.json index 822d1001..fe845a0e 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/B5-Western Thanalan/3867_You Can't Take It with You.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/B5-Western Thanalan/3867_You Can't Take It with You.json @@ -18,7 +18,7 @@ "AetheryteShortcut": "Eastern Thanalan - Camp Drybone", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/B5-Western Thanalan/517_All Good Things.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/B5-Western Thanalan/517_All Good Things.json index 7e119c9f..661eaeed 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/B5-Western Thanalan/517_All Good Things.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/B5-Western Thanalan/517_All Good Things.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Upper La Noscea - Camp Bronze Lake", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/B5-Western Thanalan/518_Eyes on Me.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/B5-Western Thanalan/518_Eyes on Me.json index 63af9a69..7becad13 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/B5-Western Thanalan/518_Eyes on Me.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/B5-Western Thanalan/518_Eyes on Me.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Eastern Thanalan - Camp Drybone", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/B5-Western Thanalan/876_Bringing out the Dead.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/B5-Western Thanalan/876_Bringing out the Dead.json index 41be92dc..e5d5e206 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/B5-Western Thanalan/876_Bringing out the Dead.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/B5-Western Thanalan/876_Bringing out the Dead.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Eastern Thanalan - Camp Drybone", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/B5-Western Thanalan/878_Bury Me Not on the Lone Prairie.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/B5-Western Thanalan/878_Bury Me Not on the Lone Prairie.json index 1a33adf2..711fa7df 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/B5-Western Thanalan/878_Bury Me Not on the Lone Prairie.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/B5-Western Thanalan/878_Bury Me Not on the Lone Prairie.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Eastern Thanalan - Camp Drybone", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/B6-Coerthas Central Highlands, Camp Dragonhead/883_He Who Waited Behind.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/B6-Coerthas Central Highlands, Camp Dragonhead/883_He Who Waited Behind.json index dca9160f..39db6472 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/B6-Coerthas Central Highlands, Camp Dragonhead/883_He Who Waited Behind.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/B6-Coerthas Central Highlands, Camp Dragonhead/883_He Who Waited Behind.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Eastern Thanalan - Camp Drybone", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/B6-Coerthas Central Highlands, Camp Dragonhead/884_Cold Reception.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/B6-Coerthas Central Highlands, Camp Dragonhead/884_Cold Reception.json index 6275beff..a93e1434 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/B6-Coerthas Central Highlands, Camp Dragonhead/884_Cold Reception.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/B6-Coerthas Central Highlands, Camp Dragonhead/884_Cold Reception.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "North Shroud - Fallgourd Float", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/B7-Coerthas Central Highlands, Camp Dragonhead/897_The Talk of Coerthas.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/B7-Coerthas Central Highlands, Camp Dragonhead/897_The Talk of Coerthas.json index 8f5426e3..fc0042f5 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/B7-Coerthas Central Highlands, Camp Dragonhead/897_The Talk of Coerthas.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/B7-Coerthas Central Highlands, Camp Dragonhead/897_The Talk of Coerthas.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Coerthas Central Highlands - Camp Dragonhead", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/B8-Coerthas Central Highlands, Inquistor/910_Road to Redemption.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/B8-Coerthas Central Highlands, Inquistor/910_Road to Redemption.json index 571b2121..6332b8a8 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/B8-Coerthas Central Highlands, Inquistor/910_Road to Redemption.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/B8-Coerthas Central Highlands, Inquistor/910_Road to Redemption.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Coerthas Central Highlands - Camp Dragonhead", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/B8-Coerthas Central Highlands, Inquistor/911_Following the Evidence.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/B8-Coerthas Central Highlands, Inquistor/911_Following the Evidence.json index a6d48faf..22038940 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/B8-Coerthas Central Highlands, Inquistor/911_Following the Evidence.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/B8-Coerthas Central Highlands, Inquistor/911_Following the Evidence.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Coerthas Central Highlands - Camp Dragonhead", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/B8-Coerthas Central Highlands, Inquistor/912_In the Eyes of Gods and Men.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/B8-Coerthas Central Highlands, Inquistor/912_In the Eyes of Gods and Men.json index 2b7960fd..1f5cede7 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/B8-Coerthas Central Highlands, Inquistor/912_In the Eyes of Gods and Men.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/B8-Coerthas Central Highlands, Inquistor/912_In the Eyes of Gods and Men.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Coerthas Central Highlands - Camp Dragonhead", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/B9-Coerthas Central Highlands, Whitebrim Front/3868_The Final Flight of the Enterprise.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/B9-Coerthas Central Highlands, Whitebrim Front/3868_The Final Flight of the Enterprise.json index 2aadfe23..09a8c181 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/B9-Coerthas Central Highlands, Whitebrim Front/3868_The Final Flight of the Enterprise.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/B9-Coerthas Central Highlands, Whitebrim Front/3868_The Final Flight of the Enterprise.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Coerthas Central Highlands - Camp Dragonhead", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/B9-Coerthas Central Highlands, Whitebrim Front/3869_The Best Inventions.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/B9-Coerthas Central Highlands, Whitebrim Front/3869_The Best Inventions.json index f737defb..327a2005 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/B9-Coerthas Central Highlands, Whitebrim Front/3869_The Best Inventions.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/B9-Coerthas Central Highlands, Whitebrim Front/3869_The Best Inventions.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Coerthas Central Highlands - Camp Dragonhead", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/B9-Coerthas Central Highlands, Whitebrim Front/924_Ye of Little Faith.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/B9-Coerthas Central Highlands, Whitebrim Front/924_Ye of Little Faith.json index e3562429..a645698b 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/B9-Coerthas Central Highlands, Whitebrim Front/924_Ye of Little Faith.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/B9-Coerthas Central Highlands, Whitebrim Front/924_Ye of Little Faith.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Coerthas Central Highlands - Camp Dragonhead", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/B9-Coerthas Central Highlands, Whitebrim Front/927_Factual Folklore.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/B9-Coerthas Central Highlands, Whitebrim Front/927_Factual Folklore.json index dd1cf6b6..8a35a23e 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/B9-Coerthas Central Highlands, Whitebrim Front/927_Factual Folklore.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/B9-Coerthas Central Highlands, Whitebrim Front/927_Factual Folklore.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Coerthas Central Highlands - Camp Dragonhead", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } }, "Mount": true diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/C0-Coerthas Central Highlands, Whitebrim Front/938_Influencing Inquisitors.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/C0-Coerthas Central Highlands, Whitebrim Front/938_Influencing Inquisitors.json index 48df2cb6..f759632d 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/C0-Coerthas Central Highlands, Whitebrim Front/938_Influencing Inquisitors.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/C0-Coerthas Central Highlands, Whitebrim Front/938_Influencing Inquisitors.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Coerthas Central Highlands - Camp Dragonhead", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/C0-Coerthas Central Highlands, Whitebrim Front/939_By the Lights of Ishgard.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/C0-Coerthas Central Highlands, Whitebrim Front/939_By the Lights of Ishgard.json index 45eed950..4afc19e7 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/C0-Coerthas Central Highlands, Whitebrim Front/939_By the Lights of Ishgard.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/C0-Coerthas Central Highlands, Whitebrim Front/939_By the Lights of Ishgard.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Coerthas Central Highlands - Camp Dragonhead", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/C0-Coerthas Central Highlands, Whitebrim Front/940_Blood for Blood.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/C0-Coerthas Central Highlands, Whitebrim Front/940_Blood for Blood.json index a30e13ea..295a78e7 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/C0-Coerthas Central Highlands, Whitebrim Front/940_Blood for Blood.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/C0-Coerthas Central Highlands, Whitebrim Front/940_Blood for Blood.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Coerthas Central Highlands - Camp Dragonhead", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/C0-Coerthas Central Highlands, Whitebrim Front/941_The Heretic among Us.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/C0-Coerthas Central Highlands, Whitebrim Front/941_The Heretic among Us.json index f5f8e31e..88f8e889 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/C0-Coerthas Central Highlands, Whitebrim Front/941_The Heretic among Us.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/C0-Coerthas Central Highlands, Whitebrim Front/941_The Heretic among Us.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Coerthas Central Highlands - Camp Dragonhead", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/C1-Coerthas Central Highlands, The Enterprise/952_In Pursuit of the Past.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/C1-Coerthas Central Highlands, The Enterprise/952_In Pursuit of the Past.json index 9589c738..ce945842 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/C1-Coerthas Central Highlands, The Enterprise/952_In Pursuit of the Past.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/C1-Coerthas Central Highlands, The Enterprise/952_In Pursuit of the Past.json @@ -20,7 +20,7 @@ "AetheryteShortcut": "Coerthas Central Highlands - Camp Dragonhead", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/C1-Coerthas Central Highlands, The Enterprise/955_Sealed With Science.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/C1-Coerthas Central Highlands, The Enterprise/955_Sealed With Science.json index b72760c1..5b686bc9 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/C1-Coerthas Central Highlands, The Enterprise/955_Sealed With Science.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/C1-Coerthas Central Highlands, The Enterprise/955_Sealed With Science.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Eastern Thanalan - Camp Drybone", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/C1-Coerthas Central Highlands, The Enterprise/956_With the Utmost Care.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/C1-Coerthas Central Highlands, The Enterprise/956_With the Utmost Care.json index 265821b5..f34692fb 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/C1-Coerthas Central Highlands, The Enterprise/956_With the Utmost Care.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/C1-Coerthas Central Highlands, The Enterprise/956_With the Utmost Care.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Eastern Thanalan - Camp Drybone", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/C1-Coerthas Central Highlands, The Enterprise/959_A Promising Prospect.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/C1-Coerthas Central Highlands, The Enterprise/959_A Promising Prospect.json index e0157f22..278430ac 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/C1-Coerthas Central Highlands, The Enterprise/959_A Promising Prospect.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/C1-Coerthas Central Highlands, The Enterprise/959_A Promising Prospect.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Eastern Thanalan - Camp Drybone", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/C2-Western La Noscea, Isles of Umbra/960_It's Probably Not Pirates.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/C2-Western La Noscea, Isles of Umbra/960_It's Probably Not Pirates.json index f2be862b..0887b40b 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/C2-Western La Noscea, Isles of Umbra/960_It's Probably Not Pirates.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/C2-Western La Noscea, Isles of Umbra/960_It's Probably Not Pirates.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Western La Noscea - Aleport", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/C2-Western La Noscea, Isles of Umbra/961_Representing the Representative.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/C2-Western La Noscea, Isles of Umbra/961_Representing the Representative.json index 2e634b1d..6d2279b9 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/C2-Western La Noscea, Isles of Umbra/961_Representing the Representative.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/C2-Western La Noscea, Isles of Umbra/961_Representing the Representative.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Western La Noscea - Aleport", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/C2-Western La Noscea, Isles of Umbra/962_The Reluctant Researcher.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/C2-Western La Noscea, Isles of Umbra/962_The Reluctant Researcher.json index 13880bc6..8266ce99 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/C2-Western La Noscea, Isles of Umbra/962_The Reluctant Researcher.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/C2-Western La Noscea, Isles of Umbra/962_The Reluctant Researcher.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Western La Noscea - Aleport", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/C3-Garuda/3870_The Curious Case of Giggity.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/C3-Garuda/3870_The Curious Case of Giggity.json index bc367381..6cdd67c4 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/C3-Garuda/3870_The Curious Case of Giggity.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/C3-Garuda/3870_The Curious Case of Giggity.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Western La Noscea - Aleport", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/C6-Mor Dhona/1004_Fool Me Twice.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/C6-Mor Dhona/1004_Fool Me Twice.json index e5e5810d..daaad896 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/C6-Mor Dhona/1004_Fool Me Twice.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/C6-Mor Dhona/1004_Fool Me Twice.json @@ -18,7 +18,7 @@ "AetheryteShortcut": "Mor Dhona", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/C9-Ultimate Weapon/3872_Hearts on Fire.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/C9-Ultimate Weapon/3872_Hearts on Fire.json index 7b3415f8..541a34e1 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/C9-Ultimate Weapon/3872_Hearts on Fire.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/C9-Ultimate Weapon/3872_Hearts on Fire.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Northern Thanalan - Camp Bluefog", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/C9-Ultimate Weapon/3873_Rock the Castrum.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/C9-Ultimate Weapon/3873_Rock the Castrum.json index 41ac9338..b45a155b 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/C9-Ultimate Weapon/3873_Rock the Castrum.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/C9-Ultimate Weapon/3873_Rock the Castrum.json @@ -21,7 +21,7 @@ "AetheryteShortcut": "Northern Thanalan - Ceruleum Processing Plant", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/C9-Ultimate Weapon/4522_The Ultimate Weapon.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/C9-Ultimate Weapon/4522_The Ultimate Weapon.json index 2af98830..d2255ab9 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/C9-Ultimate Weapon/4522_The Ultimate Weapon.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/C9-Ultimate Weapon/4522_The Ultimate Weapon.json @@ -22,7 +22,7 @@ "AetheryteShortcut": "Northern Thanalan - Ceruleum Processing Plant", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/E1-2.1/1189_Hail to the King, Kupo.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/E1-2.1/1189_Hail to the King, Kupo.json index 4a165af4..d07a0a37 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/E1-2.1/1189_Hail to the King, Kupo.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/E1-2.1/1189_Hail to the King, Kupo.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Gridania", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/E1-2.1/1191_On the Properties of Primals.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/E1-2.1/1191_On the Properties of Primals.json index 763aae81..0fba00d8 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/E1-2.1/1191_On the Properties of Primals.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/E1-2.1/1191_On the Properties of Primals.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "South Shroud - Camp Tranquil", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/E1-2.1/3875_All Things in Time.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/E1-2.1/3875_All Things in Time.json index b2097e5e..1e9a8eb9 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/E1-2.1/3875_All Things in Time.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/E1-2.1/3875_All Things in Time.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Eastern La Noscea - Wineport", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/E1-2.1/3877_It's Possibly a Primal.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/E1-2.1/3877_It's Possibly a Primal.json index 863baafa..b5e6d04c 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/E1-2.1/3877_It's Possibly a Primal.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/E1-2.1/3877_It's Possibly a Primal.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Mor Dhona", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/E2-2.2/1346_A Final Temptation.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/E2-2.2/1346_A Final Temptation.json index da6e4d87..fbcc95f5 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/E2-2.2/1346_A Final Temptation.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/E2-2.2/1346_A Final Temptation.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Western Thanalan - Horizon", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/E2-2.2/1347_The Mother of Exiles.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/E2-2.2/1347_The Mother of Exiles.json index 5cff9b71..79177573 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/E2-2.2/1347_The Mother of Exiles.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/E2-2.2/1347_The Mother of Exiles.json @@ -18,7 +18,7 @@ "AetheryteShortcut": "Western Thanalan - Horizon", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/E2-2.2/1352_Why We Adventure.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/E2-2.2/1352_Why We Adventure.json index 34734b2b..e056cf5f 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/E2-2.2/1352_Why We Adventure.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/E2-2.2/1352_Why We Adventure.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Western Thanalan - Horizon", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/E2-2.2/1361_Lord of the Whorl.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/E2-2.2/1361_Lord of the Whorl.json index c7120ca2..1dfcc672 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/E2-2.2/1361_Lord of the Whorl.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/E2-2.2/1361_Lord of the Whorl.json @@ -20,7 +20,7 @@ "AetheryteShortcut": "Lower La Noscea - Moraby Drydocks", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/E2-2.2/1362_When Yugiri Met the Fraternity.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/E2-2.2/1362_When Yugiri Met the Fraternity.json index 684fc8ad..05537641 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/E2-2.2/1362_When Yugiri Met the Fraternity.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/E2-2.2/1362_When Yugiri Met the Fraternity.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Limsa Lominsa", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/E2-2.2/1363_Through the Maelstrom.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/E2-2.2/1363_Through the Maelstrom.json index ce66f368..e7e2bedb 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/E2-2.2/1363_Through the Maelstrom.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/E2-2.2/1363_Through the Maelstrom.json @@ -18,7 +18,7 @@ "AetheryteShortcut": "Limsa Lominsa", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/E2-2.2/3881_Yugiri's Game.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/E2-2.2/3881_Yugiri's Game.json index 4afa2bae..699fc027 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/E2-2.2/3881_Yugiri's Game.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/E2-2.2/3881_Yugiri's Game.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Ul'dah", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/E2-2.2/3882_All Due Respect.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/E2-2.2/3882_All Due Respect.json index df001f74..9e025fef 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/E2-2.2/3882_All Due Respect.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/E2-2.2/3882_All Due Respect.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Ul'dah", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/E3-2.3/1443_Desperate Times.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/E3-2.3/1443_Desperate Times.json index 37cf5d03..e0216614 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/E3-2.3/1443_Desperate Times.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/E3-2.3/1443_Desperate Times.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Ul'dah", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/E3-2.3/1446_Revolution.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/E3-2.3/1446_Revolution.json index db5d3e5a..82c8d555 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/E3-2.3/1446_Revolution.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/E3-2.3/1446_Revolution.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Ul'dah", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/E3-2.3/1447_Stories We Tell.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/E3-2.3/1447_Stories We Tell.json index 14c82892..614107b0 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/E3-2.3/1447_Stories We Tell.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/E3-2.3/1447_Stories We Tell.json @@ -33,7 +33,7 @@ "AetheryteShortcut": "Mor Dhona", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } }, diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/E3-2.3/1453_What Little Gods Are Made Of.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/E3-2.3/1453_What Little Gods Are Made Of.json index feff4595..8605bbf5 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/E3-2.3/1453_What Little Gods Are Made Of.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/E3-2.3/1453_What Little Gods Are Made Of.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "East Shroud - Hawthorne Hut", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } @@ -85,7 +85,7 @@ "AetheryteShortcut": "Mor Dhona", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } }, diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/E3-2.3/1459_When the Cold Sets In.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/E3-2.3/1459_When the Cold Sets In.json index 7fbb0afe..2d54435f 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/E3-2.3/1459_When the Cold Sets In.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/E3-2.3/1459_When the Cold Sets In.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Coerthas Central Highlands - Camp Dragonhead", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/E3-2.3/1460_Brave New Companions.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/E3-2.3/1460_Brave New Companions.json index e318a55b..d2020977 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/E3-2.3/1460_Brave New Companions.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/E3-2.3/1460_Brave New Companions.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Mor Dhona", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } @@ -39,7 +39,7 @@ "AetheryteShortcut": "Mor Dhona", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } }, diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/E3-2.3/3883_Shock and Awe.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/E3-2.3/3883_Shock and Awe.json index 36012513..8b387e4f 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/E3-2.3/3883_Shock and Awe.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/E3-2.3/3883_Shock and Awe.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Central Thanalan - Black Brush Station", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/E3-2.3/3884_Reap the Whirlwind.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/E3-2.3/3884_Reap the Whirlwind.json index 4defd117..5f3c8fcd 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/E3-2.3/3884_Reap the Whirlwind.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/E3-2.3/3884_Reap the Whirlwind.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Central Thanalan - Black Brush Station", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/E3-2.3/3885_Levin an Impression.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/E3-2.3/3885_Levin an Impression.json index 8a968e5a..488ad1ea 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/E3-2.3/3885_Levin an Impression.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/E3-2.3/3885_Levin an Impression.json @@ -20,7 +20,7 @@ "AetheryteShortcut": "East Shroud - Hawthorne Hut", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/E4-2.4/3886_Chasing Ivy.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/E4-2.4/3886_Chasing Ivy.json index 599ecf10..01c93424 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/E4-2.4/3886_Chasing Ivy.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/E4-2.4/3886_Chasing Ivy.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Gridania", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/E4-2.4/3887_In Flagrante Delicto.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/E4-2.4/3887_In Flagrante Delicto.json index f05c5bb7..89400492 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/E4-2.4/3887_In Flagrante Delicto.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/E4-2.4/3887_In Flagrante Delicto.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Gridania", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/E4-2.4/53_Back and Fourth.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/E4-2.4/53_Back and Fourth.json index d0222380..f5f146a3 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/E4-2.4/53_Back and Fourth.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/E4-2.4/53_Back and Fourth.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Ul'dah", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/E4-2.4/57_The Intercession of Saints.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/E4-2.4/57_The Intercession of Saints.json index 59de3217..d5448e5e 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/E4-2.4/57_The Intercession of Saints.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/E4-2.4/57_The Intercession of Saints.json @@ -18,7 +18,7 @@ "AetheryteShortcut": "Coerthas Central Highlands - Camp Dragonhead", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/E4-2.4/62_Strength in Unity.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/E4-2.4/62_Strength in Unity.json index c72b22d6..99374bdd 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/E4-2.4/62_Strength in Unity.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/E4-2.4/62_Strength in Unity.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Coerthas Central Highlands - Camp Dragonhead", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/E4-2.4/87_Eyes Unclouded.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/E4-2.4/87_Eyes Unclouded.json index 688cf0fb..90901de3 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/E4-2.4/87_Eyes Unclouded.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/E4-2.4/87_Eyes Unclouded.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Coerthas Central Highlands - Camp Dragonhead", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/E4-2.4/89_Let Us Cling Together.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/E4-2.4/89_Let Us Cling Together.json index a991be42..92de12da 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/E4-2.4/89_Let Us Cling Together.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/E4-2.4/89_Let Us Cling Together.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Northern Thanalan - Ceruleum Processing Plant", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/E5-2.5/364_Bait and Switch.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/E5-2.5/364_Bait and Switch.json index 9cb55e6b..59fcdf41 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/E5-2.5/364_Bait and Switch.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/E5-2.5/364_Bait and Switch.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Eastern Thanalan - Camp Drybone", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/E5-2.5/369_An Uninvited Ascian.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/E5-2.5/369_An Uninvited Ascian.json index 602aa86b..df1c84c2 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/E5-2.5/369_An Uninvited Ascian.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/E5-2.5/369_An Uninvited Ascian.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Northern Thanalan - Ceruleum Processing Plant", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/E6-2.55/418_An Allied Perspective.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/E6-2.55/418_An Allied Perspective.json index 467d0cf4..cf63b8fe 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/E6-2.55/418_An Allied Perspective.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/E6-2.55/418_An Allied Perspective.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Mor Dhona", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/E6-2.55/424_The Least among Us.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/E6-2.55/424_The Least among Us.json index a44dbc18..f132042a 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/E6-2.55/424_The Least among Us.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/E6-2.55/424_The Least among Us.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "South Shroud - Camp Tranquil", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/E6-2.55/428_Before the Dawn.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/E6-2.55/428_Before the Dawn.json index 00685465..a502544c 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/E6-2.55/428_Before the Dawn.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/E6-2.55/428_Before the Dawn.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Coerthas Central Highlands - Camp Dragonhead", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/Raid Quests/1200_Sanding It Down.json b/QuestPaths/2.x - A Realm Reborn/Raid Quests/1200_Sanding It Down.json index c84e6ff1..fab0e4c0 100644 --- a/QuestPaths/2.x - A Realm Reborn/Raid Quests/1200_Sanding It Down.json +++ b/QuestPaths/2.x - A Realm Reborn/Raid Quests/1200_Sanding It Down.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Mor Dhona", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } }, "$": "0 0 0 0 0 0 -> 0 1 0 0 0 0" diff --git a/QuestPaths/2.x - A Realm Reborn/Raid Quests/1201_A Performance for the Ages.json b/QuestPaths/2.x - A Realm Reborn/Raid Quests/1201_A Performance for the Ages.json index dbd5736a..7095492a 100644 --- a/QuestPaths/2.x - A Realm Reborn/Raid Quests/1201_A Performance for the Ages.json +++ b/QuestPaths/2.x - A Realm Reborn/Raid Quests/1201_A Performance for the Ages.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Mor Dhona", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/Raid Quests/1202_Labyrinth of the Ancients.json b/QuestPaths/2.x - A Realm Reborn/Raid Quests/1202_Labyrinth of the Ancients.json index d10b7488..005d0673 100644 --- a/QuestPaths/2.x - A Realm Reborn/Raid Quests/1202_Labyrinth of the Ancients.json +++ b/QuestPaths/2.x - A Realm Reborn/Raid Quests/1202_Labyrinth of the Ancients.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Mor Dhona", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/Raid Quests/1203_For Prosperity.json b/QuestPaths/2.x - A Realm Reborn/Raid Quests/1203_For Prosperity.json index a6ecd47d..c0c74777 100644 --- a/QuestPaths/2.x - A Realm Reborn/Raid Quests/1203_For Prosperity.json +++ b/QuestPaths/2.x - A Realm Reborn/Raid Quests/1203_For Prosperity.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Mor Dhona", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/Raid Quests/1474_Syrcus Tower.json b/QuestPaths/2.x - A Realm Reborn/Raid Quests/1474_Syrcus Tower.json index 5106db10..3a8bba18 100644 --- a/QuestPaths/2.x - A Realm Reborn/Raid Quests/1474_Syrcus Tower.json +++ b/QuestPaths/2.x - A Realm Reborn/Raid Quests/1474_Syrcus Tower.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Mor Dhona", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/Raid Quests/1709_Legacy of Allag.json b/QuestPaths/2.x - A Realm Reborn/Raid Quests/1709_Legacy of Allag.json index b0157e38..687fc403 100644 --- a/QuestPaths/2.x - A Realm Reborn/Raid Quests/1709_Legacy of Allag.json +++ b/QuestPaths/2.x - A Realm Reborn/Raid Quests/1709_Legacy of Allag.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Mor Dhona", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/Raid Quests/494_The World of Darkness.json b/QuestPaths/2.x - A Realm Reborn/Raid Quests/494_The World of Darkness.json index 915f310d..82facbb5 100644 --- a/QuestPaths/2.x - A Realm Reborn/Raid Quests/494_The World of Darkness.json +++ b/QuestPaths/2.x - A Realm Reborn/Raid Quests/494_The World of Darkness.json @@ -20,7 +20,7 @@ "AetheryteShortcut": "Mor Dhona", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/2.x - A Realm Reborn/Raid Quests/495_The Light of Hope.json b/QuestPaths/2.x - A Realm Reborn/Raid Quests/495_The Light of Hope.json index 7f0fe2a6..74dee6d6 100644 --- a/QuestPaths/2.x - A Realm Reborn/Raid Quests/495_The Light of Hope.json +++ b/QuestPaths/2.x - A Realm Reborn/Raid Quests/495_The Light of Hope.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Mor Dhona", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/3.x - Heavensward/Aether Currents/The Dravanian Forelands/1797_The Hunter Becomes the Kweh.json b/QuestPaths/3.x - Heavensward/Aether Currents/The Dravanian Forelands/1797_The Hunter Becomes the Kweh.json index 11df6fd8..2deff7b9 100644 --- a/QuestPaths/3.x - Heavensward/Aether Currents/The Dravanian Forelands/1797_The Hunter Becomes the Kweh.json +++ b/QuestPaths/3.x - Heavensward/Aether Currents/The Dravanian Forelands/1797_The Hunter Becomes the Kweh.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "The Dravanian Forelands - Tailfeather", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/3.x - Heavensward/Aether Currents/The Dravanian Forelands/1802_A Lesson in Humility.json b/QuestPaths/3.x - Heavensward/Aether Currents/The Dravanian Forelands/1802_A Lesson in Humility.json index a199e174..2c5c6b23 100644 --- a/QuestPaths/3.x - Heavensward/Aether Currents/The Dravanian Forelands/1802_A Lesson in Humility.json +++ b/QuestPaths/3.x - Heavensward/Aether Currents/The Dravanian Forelands/1802_A Lesson in Humility.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "The Dravanian Forelands - Anyx Trine", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/3.x - Heavensward/MSQ/A1-Coerthas Western Highlands 1, Sea of Clouds 1/1582_The Better Half.json b/QuestPaths/3.x - Heavensward/MSQ/A1-Coerthas Western Highlands 1, Sea of Clouds 1/1582_The Better Half.json index 7a2e5f3c..02e39007 100644 --- a/QuestPaths/3.x - Heavensward/MSQ/A1-Coerthas Western Highlands 1, Sea of Clouds 1/1582_The Better Half.json +++ b/QuestPaths/3.x - Heavensward/MSQ/A1-Coerthas Western Highlands 1, Sea of Clouds 1/1582_The Better Half.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Ishgard", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/3.x - Heavensward/MSQ/A1-Coerthas Western Highlands 1, Sea of Clouds 1/1584_Work in Progress.json b/QuestPaths/3.x - Heavensward/MSQ/A1-Coerthas Western Highlands 1, Sea of Clouds 1/1584_Work in Progress.json index 031a6928..5c01cbca 100644 --- a/QuestPaths/3.x - Heavensward/MSQ/A1-Coerthas Western Highlands 1, Sea of Clouds 1/1584_Work in Progress.json +++ b/QuestPaths/3.x - Heavensward/MSQ/A1-Coerthas Western Highlands 1, Sea of Clouds 1/1584_Work in Progress.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Coerthas Western Highlands - Falcon's Nest", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/3.x - Heavensward/MSQ/A1-Coerthas Western Highlands 1, Sea of Clouds 1/1587_Reconnaissance Lost.json b/QuestPaths/3.x - Heavensward/MSQ/A1-Coerthas Western Highlands 1, Sea of Clouds 1/1587_Reconnaissance Lost.json index 0a26c2d5..5d4d02ef 100644 --- a/QuestPaths/3.x - Heavensward/MSQ/A1-Coerthas Western Highlands 1, Sea of Clouds 1/1587_Reconnaissance Lost.json +++ b/QuestPaths/3.x - Heavensward/MSQ/A1-Coerthas Western Highlands 1, Sea of Clouds 1/1587_Reconnaissance Lost.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Coerthas Western Highlands - Falcon's Nest", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/3.x - Heavensward/MSQ/A1-Coerthas Western Highlands 1, Sea of Clouds 1/1591_An Indispensable Ally.json b/QuestPaths/3.x - Heavensward/MSQ/A1-Coerthas Western Highlands 1, Sea of Clouds 1/1591_An Indispensable Ally.json index 95791609..7474320c 100644 --- a/QuestPaths/3.x - Heavensward/MSQ/A1-Coerthas Western Highlands 1, Sea of Clouds 1/1591_An Indispensable Ally.json +++ b/QuestPaths/3.x - Heavensward/MSQ/A1-Coerthas Western Highlands 1, Sea of Clouds 1/1591_An Indispensable Ally.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "The Sea of Clouds - Camp Cloudtop", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/3.x - Heavensward/MSQ/A1-Coerthas Western Highlands 1, Sea of Clouds 1/1596_A Reward Long in Coming.json b/QuestPaths/3.x - Heavensward/MSQ/A1-Coerthas Western Highlands 1, Sea of Clouds 1/1596_A Reward Long in Coming.json index 2a7ee7cd..acc9e8fb 100644 --- a/QuestPaths/3.x - Heavensward/MSQ/A1-Coerthas Western Highlands 1, Sea of Clouds 1/1596_A Reward Long in Coming.json +++ b/QuestPaths/3.x - Heavensward/MSQ/A1-Coerthas Western Highlands 1, Sea of Clouds 1/1596_A Reward Long in Coming.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "The Sea of Clouds - Camp Cloudtop", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/3.x - Heavensward/Unlocks/Hunts/2119_Let the Clan Hunt Begin.json b/QuestPaths/3.x - Heavensward/Unlocks/Hunts/2119_Let the Clan Hunt Begin.json index 72326cfe..d96e292a 100644 --- a/QuestPaths/3.x - Heavensward/Unlocks/Hunts/2119_Let the Clan Hunt Begin.json +++ b/QuestPaths/3.x - Heavensward/Unlocks/Hunts/2119_Let the Clan Hunt Begin.json @@ -21,7 +21,7 @@ ], "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/3.x - Heavensward/Unlocks/Hunts/2121_Top Marks.json b/QuestPaths/3.x - Heavensward/Unlocks/Hunts/2121_Top Marks.json index a86b04ba..0304695c 100644 --- a/QuestPaths/3.x - Heavensward/Unlocks/Hunts/2121_Top Marks.json +++ b/QuestPaths/3.x - Heavensward/Unlocks/Hunts/2121_Top Marks.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Idyllshire", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/3.x - Heavensward/Unlocks/Hunts/2122_Elite and Dangerous.json b/QuestPaths/3.x - Heavensward/Unlocks/Hunts/2122_Elite and Dangerous.json index cab08e7a..712ff6de 100644 --- a/QuestPaths/3.x - Heavensward/Unlocks/Hunts/2122_Elite and Dangerous.json +++ b/QuestPaths/3.x - Heavensward/Unlocks/Hunts/2122_Elite and Dangerous.json @@ -18,7 +18,7 @@ "AetheryteShortcut": "Ishgard", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/3.x - Heavensward/Unlocks/Misc/2107_Sights of the North.json b/QuestPaths/3.x - Heavensward/Unlocks/Misc/2107_Sights of the North.json index 763ef00a..85043ce8 100644 --- a/QuestPaths/3.x - Heavensward/Unlocks/Misc/2107_Sights of the North.json +++ b/QuestPaths/3.x - Heavensward/Unlocks/Misc/2107_Sights of the North.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "The Dravanian Forelands - Tailfeather", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/3.x - Heavensward/Unlocks/Misc/2118_A Striking Opportunity.json b/QuestPaths/3.x - Heavensward/Unlocks/Misc/2118_A Striking Opportunity.json index 92c8a3ed..60b3283d 100644 --- a/QuestPaths/3.x - Heavensward/Unlocks/Misc/2118_A Striking Opportunity.json +++ b/QuestPaths/3.x - Heavensward/Unlocks/Misc/2118_A Striking Opportunity.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Idyllshire", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/4.x - Stormblood/Unlocks/Hunts/2936_One-star Veteran Clan Hunt.json b/QuestPaths/4.x - Stormblood/Unlocks/Hunts/2936_One-star Veteran Clan Hunt.json index 609af62d..ec6350e1 100644 --- a/QuestPaths/4.x - Stormblood/Unlocks/Hunts/2936_One-star Veteran Clan Hunt.json +++ b/QuestPaths/4.x - Stormblood/Unlocks/Hunts/2936_One-star Veteran Clan Hunt.json @@ -18,7 +18,7 @@ "AetheryteShortcut": "Kugane", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/4.x - Stormblood/Unlocks/Hunts/2937_Two-star Veteran Clan Hunt.json b/QuestPaths/4.x - Stormblood/Unlocks/Hunts/2937_Two-star Veteran Clan Hunt.json index c086de81..e0639974 100644 --- a/QuestPaths/4.x - Stormblood/Unlocks/Hunts/2937_Two-star Veteran Clan Hunt.json +++ b/QuestPaths/4.x - Stormblood/Unlocks/Hunts/2937_Two-star Veteran Clan Hunt.json @@ -18,7 +18,7 @@ "AetheryteShortcut": "Kugane", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/4.x - Stormblood/Unlocks/Hunts/2938_Three-star Veteran Clan Hunt.json b/QuestPaths/4.x - Stormblood/Unlocks/Hunts/2938_Three-star Veteran Clan Hunt.json index a83077ff..f223cbcf 100644 --- a/QuestPaths/4.x - Stormblood/Unlocks/Hunts/2938_Three-star Veteran Clan Hunt.json +++ b/QuestPaths/4.x - Stormblood/Unlocks/Hunts/2938_Three-star Veteran Clan Hunt.json @@ -18,7 +18,7 @@ "AetheryteShortcut": "Kugane", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/4.x - Stormblood/Unlocks/Hunts/2939_Elite Veteran Clan Hunt.json b/QuestPaths/4.x - Stormblood/Unlocks/Hunts/2939_Elite Veteran Clan Hunt.json index 7098d7b8..4711f86d 100644 --- a/QuestPaths/4.x - Stormblood/Unlocks/Hunts/2939_Elite Veteran Clan Hunt.json +++ b/QuestPaths/4.x - Stormblood/Unlocks/Hunts/2939_Elite Veteran Clan Hunt.json @@ -18,7 +18,7 @@ "AetheryteShortcut": "Kugane", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/4.x - Stormblood/Unlocks/Misc/2940_Another Striking Opportunity.json b/QuestPaths/4.x - Stormblood/Unlocks/Misc/2940_Another Striking Opportunity.json index 768e7a3b..95bd02b9 100644 --- a/QuestPaths/4.x - Stormblood/Unlocks/Misc/2940_Another Striking Opportunity.json +++ b/QuestPaths/4.x - Stormblood/Unlocks/Misc/2940_Another Striking Opportunity.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Rhalgr's Reach", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/5.x - Shadowbringers/MSQ/C-Rak'tika/3323_A Little Faith.json b/QuestPaths/5.x - Shadowbringers/MSQ/C-Rak'tika/3323_A Little Faith.json index a3b9dc60..c33dfe69 100644 --- a/QuestPaths/5.x - Shadowbringers/MSQ/C-Rak'tika/3323_A Little Faith.json +++ b/QuestPaths/5.x - Shadowbringers/MSQ/C-Rak'tika/3323_A Little Faith.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Lakeland - Fort Jobb", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/5.x - Shadowbringers/MSQ/C-Rak'tika/3326_A Helping Hand.json b/QuestPaths/5.x - Shadowbringers/MSQ/C-Rak'tika/3326_A Helping Hand.json index 607377e1..0983eedd 100644 --- a/QuestPaths/5.x - Shadowbringers/MSQ/C-Rak'tika/3326_A Helping Hand.json +++ b/QuestPaths/5.x - Shadowbringers/MSQ/C-Rak'tika/3326_A Helping Hand.json @@ -18,7 +18,7 @@ "AetheryteShortcut": "Rak'tika - Slitherbough", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/5.x - Shadowbringers/Unlocks/Hunts/3598_Two Nuts Too Nutty.json b/QuestPaths/5.x - Shadowbringers/Unlocks/Hunts/3598_Two Nuts Too Nutty.json index 62b323f1..1a002b88 100644 --- a/QuestPaths/5.x - Shadowbringers/Unlocks/Hunts/3598_Two Nuts Too Nutty.json +++ b/QuestPaths/5.x - Shadowbringers/Unlocks/Hunts/3598_Two Nuts Too Nutty.json @@ -18,7 +18,7 @@ "AetheryteShortcut": "Crystarium", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/5.x - Shadowbringers/Unlocks/Hunts/3599_How Do You Like Three Nuts.json b/QuestPaths/5.x - Shadowbringers/Unlocks/Hunts/3599_How Do You Like Three Nuts.json index be34db4e..1f768594 100644 --- a/QuestPaths/5.x - Shadowbringers/Unlocks/Hunts/3599_How Do You Like Three Nuts.json +++ b/QuestPaths/5.x - Shadowbringers/Unlocks/Hunts/3599_How Do You Like Three Nuts.json @@ -18,7 +18,7 @@ "AetheryteShortcut": "Crystarium", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/5.x - Shadowbringers/Unlocks/Hunts/3600_Too Many Nutters.json b/QuestPaths/5.x - Shadowbringers/Unlocks/Hunts/3600_Too Many Nutters.json index 434f9fd6..b45786c0 100644 --- a/QuestPaths/5.x - Shadowbringers/Unlocks/Hunts/3600_Too Many Nutters.json +++ b/QuestPaths/5.x - Shadowbringers/Unlocks/Hunts/3600_Too Many Nutters.json @@ -18,7 +18,7 @@ "AetheryteShortcut": "Crystarium", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/5.x - Shadowbringers/Unlocks/Misc/3601_Yet Another Striking Opportunity.json b/QuestPaths/5.x - Shadowbringers/Unlocks/Misc/3601_Yet Another Striking Opportunity.json index b54ef989..ad541f10 100644 --- a/QuestPaths/5.x - Shadowbringers/Unlocks/Misc/3601_Yet Another Striking Opportunity.json +++ b/QuestPaths/5.x - Shadowbringers/Unlocks/Misc/3601_Yet Another Striking Opportunity.json @@ -21,7 +21,7 @@ ], "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/6.x - Endwalker/Tribal/Allied/4788_A Dream Worth Chasing.json b/QuestPaths/6.x - Endwalker/Tribal/Allied/4788_A Dream Worth Chasing.json index 79f6c074..db13496d 100644 --- a/QuestPaths/6.x - Endwalker/Tribal/Allied/4788_A Dream Worth Chasing.json +++ b/QuestPaths/6.x - Endwalker/Tribal/Allied/4788_A Dream Worth Chasing.json @@ -18,7 +18,7 @@ "AetheryteShortcut": "Thavnair - Yedlihmad", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/6.x - Endwalker/Unlocks/Hunts/4176_The Hunt for Specimens.json b/QuestPaths/6.x - Endwalker/Unlocks/Hunts/4176_The Hunt for Specimens.json index 162fbb05..0ddd2cd0 100644 --- a/QuestPaths/6.x - Endwalker/Unlocks/Hunts/4176_The Hunt for Specimens.json +++ b/QuestPaths/6.x - Endwalker/Unlocks/Hunts/4176_The Hunt for Specimens.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Old Sharlayan", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/6.x - Endwalker/Unlocks/Hunts/4177_That Specimen Came from the Moon.json b/QuestPaths/6.x - Endwalker/Unlocks/Hunts/4177_That Specimen Came from the Moon.json index e334f412..8a1ae1a2 100644 --- a/QuestPaths/6.x - Endwalker/Unlocks/Hunts/4177_That Specimen Came from the Moon.json +++ b/QuestPaths/6.x - Endwalker/Unlocks/Hunts/4177_That Specimen Came from the Moon.json @@ -18,7 +18,7 @@ "AetheryteShortcut": "Old Sharlayan", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/6.x - Endwalker/Unlocks/Hunts/4178_A Hunt for the Ages.json b/QuestPaths/6.x - Endwalker/Unlocks/Hunts/4178_A Hunt for the Ages.json index bfdc27e6..4eea7ed7 100644 --- a/QuestPaths/6.x - Endwalker/Unlocks/Hunts/4178_A Hunt for the Ages.json +++ b/QuestPaths/6.x - Endwalker/Unlocks/Hunts/4178_A Hunt for the Ages.json @@ -18,7 +18,7 @@ "AetheryteShortcut": "Old Sharlayan", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/6.x - Endwalker/Unlocks/Hunts/4179_Perfect Specimens.json b/QuestPaths/6.x - Endwalker/Unlocks/Hunts/4179_Perfect Specimens.json index 78d9c49b..05a32e8e 100644 --- a/QuestPaths/6.x - Endwalker/Unlocks/Hunts/4179_Perfect Specimens.json +++ b/QuestPaths/6.x - Endwalker/Unlocks/Hunts/4179_Perfect Specimens.json @@ -18,7 +18,7 @@ "AetheryteShortcut": "Old Sharlayan", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/6.x - Endwalker/Unlocks/Misc/4173_A Place to Train.json b/QuestPaths/6.x - Endwalker/Unlocks/Misc/4173_A Place to Train.json index edfdffe8..c314189b 100644 --- a/QuestPaths/6.x - Endwalker/Unlocks/Misc/4173_A Place to Train.json +++ b/QuestPaths/6.x - Endwalker/Unlocks/Misc/4173_A Place to Train.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Radz-at-Han", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/7.x - Dawntrail/Class Quests/VPR/4850_Viper in the Vidraal's Shadow.json b/QuestPaths/7.x - Dawntrail/Class Quests/VPR/4850_Viper in the Vidraal's Shadow.json index 9527ed52..e61fbfcb 100644 --- a/QuestPaths/7.x - Dawntrail/Class Quests/VPR/4850_Viper in the Vidraal's Shadow.json +++ b/QuestPaths/7.x - Dawntrail/Class Quests/VPR/4850_Viper in the Vidraal's Shadow.json @@ -24,7 +24,7 @@ ], "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/7.x - Dawntrail/Class Quests/VPR/4851_Vipers on the Hunt.json b/QuestPaths/7.x - Dawntrail/Class Quests/VPR/4851_Vipers on the Hunt.json index 96851337..9dc0e9e9 100644 --- a/QuestPaths/7.x - Dawntrail/Class Quests/VPR/4851_Vipers on the Hunt.json +++ b/QuestPaths/7.x - Dawntrail/Class Quests/VPR/4851_Vipers on the Hunt.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "South Shroud - Quarrymill", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } @@ -38,7 +38,7 @@ "AetheryteShortcut": "North Shroud - Fallgourd Float", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } @@ -188,7 +188,7 @@ ], "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } }, diff --git a/QuestPaths/7.x - Dawntrail/MSQ/A-Kozama'uka1-Urqopacha1/4860_A New World to Explore.json b/QuestPaths/7.x - Dawntrail/MSQ/A-Kozama'uka1-Urqopacha1/4860_A New World to Explore.json index 476652cb..5db8f68f 100644 --- a/QuestPaths/7.x - Dawntrail/MSQ/A-Kozama'uka1-Urqopacha1/4860_A New World to Explore.json +++ b/QuestPaths/7.x - Dawntrail/MSQ/A-Kozama'uka1-Urqopacha1/4860_A New World to Explore.json @@ -18,7 +18,7 @@ "AetheryteShortcut": "Old Sharlayan", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/7.x - Dawntrail/Role Quests/Healer/4824_In the Sting of Things.json b/QuestPaths/7.x - Dawntrail/Role Quests/Healer/4824_In the Sting of Things.json index 56e2764e..cb863fc3 100644 --- a/QuestPaths/7.x - Dawntrail/Role Quests/Healer/4824_In the Sting of Things.json +++ b/QuestPaths/7.x - Dawntrail/Role Quests/Healer/4824_In the Sting of Things.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Tuliyollal", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/7.x - Dawntrail/Role Quests/Healer/4825_Causing Problems on Purpose.json b/QuestPaths/7.x - Dawntrail/Role Quests/Healer/4825_Causing Problems on Purpose.json index d789b45e..23a1aadf 100644 --- a/QuestPaths/7.x - Dawntrail/Role Quests/Healer/4825_Causing Problems on Purpose.json +++ b/QuestPaths/7.x - Dawntrail/Role Quests/Healer/4825_Causing Problems on Purpose.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Limsa Lominsa", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/7.x - Dawntrail/Role Quests/Healer/4826_Living among the Deadly.json b/QuestPaths/7.x - Dawntrail/Role Quests/Healer/4826_Living among the Deadly.json index 87c09c76..fc676b2b 100644 --- a/QuestPaths/7.x - Dawntrail/Role Quests/Healer/4826_Living among the Deadly.json +++ b/QuestPaths/7.x - Dawntrail/Role Quests/Healer/4826_Living among the Deadly.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Limsa Lominsa", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/7.x - Dawntrail/Role Quests/Healer/4827_Taste of a Toxin Paradise.json b/QuestPaths/7.x - Dawntrail/Role Quests/Healer/4827_Taste of a Toxin Paradise.json index 8d0acb51..c805b340 100644 --- a/QuestPaths/7.x - Dawntrail/Role Quests/Healer/4827_Taste of a Toxin Paradise.json +++ b/QuestPaths/7.x - Dawntrail/Role Quests/Healer/4827_Taste of a Toxin Paradise.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Limsa Lominsa", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/7.x - Dawntrail/Role Quests/Healer/4828_Downed by the River.json b/QuestPaths/7.x - Dawntrail/Role Quests/Healer/4828_Downed by the River.json index 871a4cef..d23e7dd3 100644 --- a/QuestPaths/7.x - Dawntrail/Role Quests/Healer/4828_Downed by the River.json +++ b/QuestPaths/7.x - Dawntrail/Role Quests/Healer/4828_Downed by the River.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Limsa Lominsa", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/7.x - Dawntrail/Role Quests/Healer/4829_An Antidote for Anarchy.json b/QuestPaths/7.x - Dawntrail/Role Quests/Healer/4829_An Antidote for Anarchy.json index 3fe33798..b56436f0 100644 --- a/QuestPaths/7.x - Dawntrail/Role Quests/Healer/4829_An Antidote for Anarchy.json +++ b/QuestPaths/7.x - Dawntrail/Role Quests/Healer/4829_An Antidote for Anarchy.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Limsa Lominsa", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/7.x - Dawntrail/Role Quests/Melee/4830_The Hunter and the Hunted.json b/QuestPaths/7.x - Dawntrail/Role Quests/Melee/4830_The Hunter and the Hunted.json index ee01538e..166f9480 100644 --- a/QuestPaths/7.x - Dawntrail/Role Quests/Melee/4830_The Hunter and the Hunted.json +++ b/QuestPaths/7.x - Dawntrail/Role Quests/Melee/4830_The Hunter and the Hunted.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Tuliyollal", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } @@ -42,7 +42,7 @@ ], "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } }, "CompletionQuestVariablesFlags": [ diff --git a/QuestPaths/7.x - Dawntrail/Role Quests/Melee/4831_A Sea of Blood.json b/QuestPaths/7.x - Dawntrail/Role Quests/Melee/4831_A Sea of Blood.json index 9bb72bcf..ba7713b6 100644 --- a/QuestPaths/7.x - Dawntrail/Role Quests/Melee/4831_A Sea of Blood.json +++ b/QuestPaths/7.x - Dawntrail/Role Quests/Melee/4831_A Sea of Blood.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Kugane", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } }, "DialogueChoices": [ diff --git a/QuestPaths/7.x - Dawntrail/Role Quests/Melee/4832_Who's Who.json b/QuestPaths/7.x - Dawntrail/Role Quests/Melee/4832_Who's Who.json index 529aeb7e..7882d8ac 100644 --- a/QuestPaths/7.x - Dawntrail/Role Quests/Melee/4832_Who's Who.json +++ b/QuestPaths/7.x - Dawntrail/Role Quests/Melee/4832_Who's Who.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Kugane", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } @@ -38,7 +38,7 @@ "AetheryteShortcut": "Yanxia - Namai", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } }, "CompletionQuestVariablesFlags": [ diff --git a/QuestPaths/7.x - Dawntrail/Role Quests/Melee/4833_Cornered Prey.json b/QuestPaths/7.x - Dawntrail/Role Quests/Melee/4833_Cornered Prey.json index b5589cdf..430a5bf4 100644 --- a/QuestPaths/7.x - Dawntrail/Role Quests/Melee/4833_Cornered Prey.json +++ b/QuestPaths/7.x - Dawntrail/Role Quests/Melee/4833_Cornered Prey.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Kugane", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/7.x - Dawntrail/Role Quests/Melee/4834_Impostor Syndrome.json b/QuestPaths/7.x - Dawntrail/Role Quests/Melee/4834_Impostor Syndrome.json index ef0aafb1..61cc3d57 100644 --- a/QuestPaths/7.x - Dawntrail/Role Quests/Melee/4834_Impostor Syndrome.json +++ b/QuestPaths/7.x - Dawntrail/Role Quests/Melee/4834_Impostor Syndrome.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Kugane", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } @@ -122,7 +122,7 @@ ], "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/7.x - Dawntrail/Role Quests/Melee/4835_A Hunter True.json b/QuestPaths/7.x - Dawntrail/Role Quests/Melee/4835_A Hunter True.json index 564cd4b4..043e48ce 100644 --- a/QuestPaths/7.x - Dawntrail/Role Quests/Melee/4835_A Hunter True.json +++ b/QuestPaths/7.x - Dawntrail/Role Quests/Melee/4835_A Hunter True.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Kugane", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } @@ -38,7 +38,7 @@ "AetheryteShortcut": "Azim Steppe - Reunion", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } }, "CompletionQuestVariablesFlags": [ diff --git a/QuestPaths/7.x - Dawntrail/Role Quests/Physical Ranged/4836_To Steal a Steelhog.json b/QuestPaths/7.x - Dawntrail/Role Quests/Physical Ranged/4836_To Steal a Steelhog.json index 6adf040d..a7e71c16 100644 --- a/QuestPaths/7.x - Dawntrail/Role Quests/Physical Ranged/4836_To Steal a Steelhog.json +++ b/QuestPaths/7.x - Dawntrail/Role Quests/Physical Ranged/4836_To Steal a Steelhog.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Tuliyollal", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/7.x - Dawntrail/Role Quests/Physical Ranged/4837_Bandits Abound.json b/QuestPaths/7.x - Dawntrail/Role Quests/Physical Ranged/4837_Bandits Abound.json index 077736fc..18e31a5d 100644 --- a/QuestPaths/7.x - Dawntrail/Role Quests/Physical Ranged/4837_Bandits Abound.json +++ b/QuestPaths/7.x - Dawntrail/Role Quests/Physical Ranged/4837_Bandits Abound.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Rhalgr's Reach", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/7.x - Dawntrail/Side Quests/Urqopacha/5040_Too Much of a Good Thing.json b/QuestPaths/7.x - Dawntrail/Side Quests/Urqopacha/5040_Too Much of a Good Thing.json index 3ab31f3c..5afb621b 100644 --- a/QuestPaths/7.x - Dawntrail/Side Quests/Urqopacha/5040_Too Much of a Good Thing.json +++ b/QuestPaths/7.x - Dawntrail/Side Quests/Urqopacha/5040_Too Much of a Good Thing.json @@ -17,7 +17,7 @@ "AetheryteShortcut": "Urqopacha - Wachunpelo", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/7.x - Dawntrail/Unlocks/Dungeons/5013_It Belongs in a Museum.json b/QuestPaths/7.x - Dawntrail/Unlocks/Dungeons/5013_It Belongs in a Museum.json index 4ae11c8e..1126461b 100644 --- a/QuestPaths/7.x - Dawntrail/Unlocks/Dungeons/5013_It Belongs in a Museum.json +++ b/QuestPaths/7.x - Dawntrail/Unlocks/Dungeons/5013_It Belongs in a Museum.json @@ -59,7 +59,7 @@ "AetheryteShortcut": "Shaaloani - Mehwahhetsoan", "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } diff --git a/QuestPaths/7.x - Dawntrail/Unlocks/Misc/5005_Trial by Spire.json b/QuestPaths/7.x - Dawntrail/Unlocks/Misc/5005_Trial by Spire.json index 04f2fbb1..db7e24e9 100644 --- a/QuestPaths/7.x - Dawntrail/Unlocks/Misc/5005_Trial by Spire.json +++ b/QuestPaths/7.x - Dawntrail/Unlocks/Misc/5005_Trial by Spire.json @@ -21,7 +21,7 @@ ], "SkipConditions": { "AetheryteShortcutIf": { - "NotInSameTerritory": true + "InSameTerritory": true } } } From 035b7383ae14bcc999cafd86b089d5d747f094ff Mon Sep 17 00:00:00 2001 From: Liza Carvelli Date: Thu, 1 Aug 2024 18:02:19 +0200 Subject: [PATCH 05/12] Fix skip.NotTargetable/skipExtraConditions not being considered if no other skips are set --- Questionable.Model/V1/SkipStepConditions.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Questionable.Model/V1/SkipStepConditions.cs b/Questionable.Model/V1/SkipStepConditions.cs index 9186515d..5f15ca98 100644 --- a/Questionable.Model/V1/SkipStepConditions.cs +++ b/Questionable.Model/V1/SkipStepConditions.cs @@ -24,11 +24,13 @@ public sealed class SkipStepConditions return (CompletionQuestVariablesFlags.Count > 6 && CompletionQuestVariablesFlags.Any(x => x != null)) || Flying != null || Chocobo != null || + NotTargetable || InTerritory.Count > 0 || NotInTerritory.Count > 0 || Item != null || QuestsAccepted.Count > 0 || - QuestsCompleted.Count > 0; + QuestsCompleted.Count > 0 || + ExtraCondition != null; } public override string ToString() From 3ff529b99a62b7f903612d3c991d7e257980472d Mon Sep 17 00:00:00 2001 From: Liza Carvelli Date: Thu, 1 Aug 2024 18:47:13 +0200 Subject: [PATCH 06/12] Add an option to disable ESC --- Questionable/Configuration.cs | 1 + Questionable/Controller/QuestController.cs | 2 +- Questionable/Windows/ConfigWindow.cs | 7 +++++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/Questionable/Configuration.cs b/Questionable/Configuration.cs index 4b276961..4424db23 100644 --- a/Questionable/Configuration.cs +++ b/Questionable/Configuration.cs @@ -18,6 +18,7 @@ internal sealed class Configuration : IPluginConfiguration public uint MountId { get; set; } = 71; public GrandCompany GrandCompany { get; set; } = GrandCompany.None; public bool HideInAllInstances { get; set; } = true; + public bool UseEscToCancelQuesting { get; set; } = true; } internal sealed class AdvancedConfiguration diff --git a/Questionable/Controller/QuestController.cs b/Questionable/Controller/QuestController.cs index 4838353a..c92fee2b 100644 --- a/Questionable/Controller/QuestController.cs +++ b/Questionable/Controller/QuestController.cs @@ -140,7 +140,7 @@ internal sealed class QuestController _combatController.Stop("HP = 0"); } } - else if (_keyState[VirtualKey.ESCAPE]) + else if (_configuration.General.UseEscToCancelQuesting && _keyState[VirtualKey.ESCAPE]) { if (_currentTask != null || _taskQueue.Count > 0) { diff --git a/Questionable/Windows/ConfigWindow.cs b/Questionable/Windows/ConfigWindow.cs index 11693300..0fa60d69 100644 --- a/Questionable/Windows/ConfigWindow.cs +++ b/Questionable/Windows/ConfigWindow.cs @@ -76,6 +76,13 @@ internal sealed class ConfigWindow : LWindow, IPersistableWindowConfig Save(); } + bool useEscToCancelQuesting = _configuration.General.UseEscToCancelQuesting; + if (ImGui.Checkbox("Use ESC to cancel questing/movement", ref useEscToCancelQuesting)) + { + _configuration.General.UseEscToCancelQuesting = useEscToCancelQuesting; + Save(); + } + ImGui.EndTabItem(); } From dd7152024a1491e2e47248ce2644951569615d4e Mon Sep 17 00:00:00 2001 From: Liza Carvelli Date: Fri, 2 Aug 2024 09:55:55 +0200 Subject: [PATCH 07/12] Misc skip adjustments --- .../3861_Microbrewing.json | 1 + .../738_Sylphish Concerns.json | 21 ++++++ .../747_Shadow of Darkness.json | 14 +++- .../761_Tea for Three.json | 43 ++++++++++++ .../778_Wilred Wants You.json | 2 + .../Studium Deliveries/4473_The Faculty.json | 36 ++++++++++ .../MIN, BTN/4153_Cultured Pursuits.json | 67 +++++++++++++++++++ .../MIN, BTN/4154_Cooking Up a Culture.json | 37 ++++++++++ .../4966_Wrought in Wachumeqimeqi.json | 36 ++++++++++ .../MIN, BTN/4989_Hands for Hire.json | 36 ++++++++++ .../MIN, BTN/4990_Test of Talents.json | 36 ++++++++++ QuestPaths/QuestPaths.csproj | 4 ++ QuestPaths/Reusable Paths.md | 15 +++++ Questionable.Model/V1/SkipStepConditions.cs | 2 +- 14 files changed, 347 insertions(+), 3 deletions(-) create mode 100644 QuestPaths/6.x - Endwalker/Studium Deliveries/4473_The Faculty.json create mode 100644 QuestPaths/6.x - Endwalker/Studium Deliveries/MIN, BTN/4153_Cultured Pursuits.json create mode 100644 QuestPaths/6.x - Endwalker/Studium Deliveries/MIN, BTN/4154_Cooking Up a Culture.json create mode 100644 QuestPaths/7.x - Dawntrail/Custom Deliveries/Wachumeqimeqi/4966_Wrought in Wachumeqimeqi.json create mode 100644 QuestPaths/7.x - Dawntrail/Custom Deliveries/Wachumeqimeqi/MIN, BTN/4989_Hands for Hire.json create mode 100644 QuestPaths/7.x - Dawntrail/Custom Deliveries/Wachumeqimeqi/MIN, BTN/4990_Test of Talents.json diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/A3-South Shroud, Buscarron’s Druthers/3861_Microbrewing.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/A3-South Shroud, Buscarron’s Druthers/3861_Microbrewing.json index c71fd8b1..1178aff5 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/A3-South Shroud, Buscarron’s Druthers/3861_Microbrewing.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/A3-South Shroud, Buscarron’s Druthers/3861_Microbrewing.json @@ -29,6 +29,7 @@ "TerritoryId": 139, "InteractionType": "WalkTo", "DisableNavmesh": true, + "Mount": true, "Comment": "Avoids swimming" }, { diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/A3-South Shroud, Buscarron’s Druthers/738_Sylphish Concerns.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/A3-South Shroud, Buscarron’s Druthers/738_Sylphish Concerns.json index a7e83e81..86d44f5d 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/A3-South Shroud, Buscarron’s Druthers/738_Sylphish Concerns.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/A3-South Shroud, Buscarron’s Druthers/738_Sylphish Concerns.json @@ -96,6 +96,27 @@ 8 ] }, + { + "Position": { + "X": -103.87269, + "Y": 5.116502, + "Z": -73.9041 + }, + "TerritoryId": 153, + "InteractionType": "WalkTo", + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 32 + ] + } + } + }, { "Position": { "X": -90.467575, diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/A4-Back from the Woods/747_Shadow of Darkness.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/A4-Back from the Woods/747_Shadow of Darkness.json index 6f3f239d..b5cbedd0 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/A4-Back from the Woods/747_Shadow of Darkness.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/A4-Back from the Woods/747_Shadow of Darkness.json @@ -20,6 +20,17 @@ { "Sequence": 1, "Steps": [ + { + "Position": { + "X": -119.1183, + "Y": 3.7999938, + "Z": -104.33473 + }, + "TerritoryId": 130, + "InteractionType": "WalkTo", + "AetheryteShortcut": "Ul'dah", + "$": "Ul'dah Aetheryte to Immortal Flames" + }, { "DataId": 1004576, "Position": { @@ -28,8 +39,7 @@ "Z": -114.67157 }, "TerritoryId": 130, - "InteractionType": "Interact", - "AetheryteShortcut": "Ul'dah" + "InteractionType": "Interact" } ] }, diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/A5-Southern Thanalan, Little Ala Mhigo/761_Tea for Three.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/A5-Southern Thanalan, Little Ala Mhigo/761_Tea for Three.json index 215cbf4e..eba78647 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/A5-Southern Thanalan, Little Ala Mhigo/761_Tea for Three.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/A5-Southern Thanalan, Little Ala Mhigo/761_Tea for Three.json @@ -26,6 +26,49 @@ { "Sequence": 1, "Steps": [ + { + "Position": { + "X": -179.69392, + "Y": 18.008331, + "Z": -279.60886 + }, + "TerritoryId": 146, + "InteractionType": "WalkTo", + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 128 + ] + } + } + }, + { + "Position": { + "X": -184.29613, + "Y": 3.5985415, + "Z": -246.7013 + }, + "TerritoryId": 146, + "InteractionType": "WalkTo", + "DisableNavmesh": true, + "SkipConditions": { + "StepIf": { + "CompletionQuestVariablesFlags": [ + null, + null, + null, + null, + null, + 128 + ] + } + } + }, { "DataId": 1006702, "Position": { diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-2/A7-Southern Thanalan, Big Trouble in Little Ala Mhigo/778_Wilred Wants You.json b/QuestPaths/2.x - A Realm Reborn/MSQ-2/A7-Southern Thanalan, Big Trouble in Little Ala Mhigo/778_Wilred Wants You.json index 51abeee8..6d840e0f 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-2/A7-Southern Thanalan, Big Trouble in Little Ala Mhigo/778_Wilred Wants You.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-2/A7-Southern Thanalan, Big Trouble in Little Ala Mhigo/778_Wilred Wants You.json @@ -12,6 +12,7 @@ "Y": 26.138475, "Z": -355.0622 }, + "StopDistance": 7, "TerritoryId": 146, "InteractionType": "AcceptQuest", "AetheryteShortcut": "Southern Thanalan - Little Ala Mhigo", @@ -53,6 +54,7 @@ "Y": 19.02249, "Z": -557.8546 }, + "StopDistance": 7, "TerritoryId": 146, "InteractionType": "Interact" } diff --git a/QuestPaths/6.x - Endwalker/Studium Deliveries/4473_The Faculty.json b/QuestPaths/6.x - Endwalker/Studium Deliveries/4473_The Faculty.json new file mode 100644 index 00000000..e960c9f3 --- /dev/null +++ b/QuestPaths/6.x - Endwalker/Studium Deliveries/4473_The Faculty.json @@ -0,0 +1,36 @@ +{ + "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/QuestPaths/quest-v1.json", + "Author": "liza", + "QuestSequence": [ + { + "Sequence": 0, + "Steps": [ + { + "DataId": 1038500, + "Position": { + "X": -357.83936, + "Y": 21.84602, + "Z": -91.32526 + }, + "TerritoryId": 962, + "InteractionType": "AcceptQuest" + } + ] + }, + { + "Sequence": 255, + "Steps": [ + { + "DataId": 1038500, + "Position": { + "X": -357.83936, + "Y": 21.84602, + "Z": -91.32526 + }, + "TerritoryId": 962, + "InteractionType": "CompleteQuest" + } + ] + } + ] +} diff --git a/QuestPaths/6.x - Endwalker/Studium Deliveries/MIN, BTN/4153_Cultured Pursuits.json b/QuestPaths/6.x - Endwalker/Studium Deliveries/MIN, BTN/4153_Cultured Pursuits.json new file mode 100644 index 00000000..9e198c81 --- /dev/null +++ b/QuestPaths/6.x - Endwalker/Studium Deliveries/MIN, BTN/4153_Cultured Pursuits.json @@ -0,0 +1,67 @@ +{ + "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/QuestPaths/quest-v1.json", + "Author": "liza", + "QuestSequence": [ + { + "Sequence": 0, + "Steps": [ + { + "DataId": 1038504, + "Position": { + "X": -357.62573, + "Y": 21.64856, + "Z": -95.99457 + }, + "TerritoryId": 962, + "InteractionType": "AcceptQuest" + } + ] + }, + { + "Sequence": 1, + "Steps": [ + { + "DataId": 1038505, + "Position": { + "X": -376.45538, + "Y": 18.999998, + "Z": 37.00305 + }, + "TerritoryId": 962, + "InteractionType": "Interact" + } + ] + }, + { + "Sequence": 2, + "Steps": [ + { + "DataId": 1038503, + "Position": { + "X": -367.0863, + "Y": 21.84602, + "Z": -101.701416 + }, + "TerritoryId": 962, + "InteractionType": "Interact" + } + ] + }, + { + "Sequence": 255, + "Steps": [ + { + "DataId": 1038501, + "Position": { + "X": -367.3305, + "Y": 21.846018, + "Z": -102.983154 + }, + "StopDistance": 7, + "TerritoryId": 962, + "InteractionType": "CompleteQuest" + } + ] + } + ] +} diff --git a/QuestPaths/6.x - Endwalker/Studium Deliveries/MIN, BTN/4154_Cooking Up a Culture.json b/QuestPaths/6.x - Endwalker/Studium Deliveries/MIN, BTN/4154_Cooking Up a Culture.json new file mode 100644 index 00000000..ea7b708c --- /dev/null +++ b/QuestPaths/6.x - Endwalker/Studium Deliveries/MIN, BTN/4154_Cooking Up a Culture.json @@ -0,0 +1,37 @@ +{ + "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/QuestPaths/quest-v1.json", + "Author": "liza", + "Disabled": true, + "QuestSequence": [ + { + "Sequence": 0, + "Steps": [ + { + "DataId": 1038501, + "Position": { + "X": -367.3305, + "Y": 21.846018, + "Z": -102.983154 + }, + "TerritoryId": 962, + "InteractionType": "AcceptQuest" + } + ] + }, + { + "Sequence": 255, + "Steps": [ + { + "DataId": 1038501, + "Position": { + "X": -367.3305, + "Y": 21.846018, + "Z": -102.983154 + }, + "TerritoryId": 962, + "InteractionType": "CompleteQuest" + } + ] + } + ] +} diff --git a/QuestPaths/7.x - Dawntrail/Custom Deliveries/Wachumeqimeqi/4966_Wrought in Wachumeqimeqi.json b/QuestPaths/7.x - Dawntrail/Custom Deliveries/Wachumeqimeqi/4966_Wrought in Wachumeqimeqi.json new file mode 100644 index 00000000..0120cf2a --- /dev/null +++ b/QuestPaths/7.x - Dawntrail/Custom Deliveries/Wachumeqimeqi/4966_Wrought in Wachumeqimeqi.json @@ -0,0 +1,36 @@ +{ + "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/QuestPaths/quest-v1.json", + "Author": "liza", + "QuestSequence": [ + { + "Sequence": 0, + "Steps": [ + { + "DataId": 1047095, + "Position": { + "X": 139.5437, + "Y": -13.99, + "Z": 10.60498 + }, + "TerritoryId": 1185, + "InteractionType": "AcceptQuest" + } + ] + }, + { + "Sequence": 255, + "Steps": [ + { + "DataId": 1047095, + "Position": { + "X": 139.5437, + "Y": -13.99, + "Z": 10.60498 + }, + "TerritoryId": 1185, + "InteractionType": "CompleteQuest" + } + ] + } + ] +} diff --git a/QuestPaths/7.x - Dawntrail/Custom Deliveries/Wachumeqimeqi/MIN, BTN/4989_Hands for Hire.json b/QuestPaths/7.x - Dawntrail/Custom Deliveries/Wachumeqimeqi/MIN, BTN/4989_Hands for Hire.json new file mode 100644 index 00000000..36eb6d7b --- /dev/null +++ b/QuestPaths/7.x - Dawntrail/Custom Deliveries/Wachumeqimeqi/MIN, BTN/4989_Hands for Hire.json @@ -0,0 +1,36 @@ +{ + "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/QuestPaths/quest-v1.json", + "Author": "liza", + "QuestSequence": [ + { + "Sequence": 0, + "Steps": [ + { + "DataId": 1047151, + "Position": { + "X": 130.2052, + "Y": -14, + "Z": 16.952698 + }, + "TerritoryId": 1185, + "InteractionType": "AcceptQuest" + } + ] + }, + { + "Sequence": 255, + "Steps": [ + { + "DataId": 1047164, + "Position": { + "X": 217.21204, + "Y": -14, + "Z": -8.316223 + }, + "TerritoryId": 1185, + "InteractionType": "CompleteQuest" + } + ] + } + ] +} diff --git a/QuestPaths/7.x - Dawntrail/Custom Deliveries/Wachumeqimeqi/MIN, BTN/4990_Test of Talents.json b/QuestPaths/7.x - Dawntrail/Custom Deliveries/Wachumeqimeqi/MIN, BTN/4990_Test of Talents.json new file mode 100644 index 00000000..5693f6bf --- /dev/null +++ b/QuestPaths/7.x - Dawntrail/Custom Deliveries/Wachumeqimeqi/MIN, BTN/4990_Test of Talents.json @@ -0,0 +1,36 @@ +{ + "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/QuestPaths/quest-v1.json", + "Author": "liza", + "QuestSequence": [ + { + "Sequence": 0, + "Steps": [ + { + "DataId": 1047132, + "Position": { + "X": 217.36475, + "Y": -14.000001, + "Z": -5.6916504 + }, + "TerritoryId": 1185, + "InteractionType": "AcceptQuest" + } + ] + }, + { + "Sequence": 255, + "Steps": [ + { + "DataId": 1047132, + "Position": { + "X": 217.36475, + "Y": -14.000001, + "Z": -5.6916504 + }, + "TerritoryId": 1185, + "InteractionType": "CompleteQuest" + } + ] + } + ] +} diff --git a/QuestPaths/QuestPaths.csproj b/QuestPaths/QuestPaths.csproj index bb2b3663..e914b62d 100644 --- a/QuestPaths/QuestPaths.csproj +++ b/QuestPaths/QuestPaths.csproj @@ -39,4 +39,8 @@ + + + + diff --git a/QuestPaths/Reusable Paths.md b/QuestPaths/Reusable Paths.md index 719a95f5..7bbfa2f5 100644 --- a/QuestPaths/Reusable Paths.md +++ b/QuestPaths/Reusable Paths.md @@ -5,6 +5,21 @@ outside). This vastly improves the pathfinding performance, and avoids attempting to fly e.g. under the map or into the building that can sometimes be found as valid paths. +## Ul'dah + +```json + { + "Position": { + "X": -119.1183, + "Y": 3.7999938, + "Z": -104.33473 + }, + "TerritoryId": 130, + "InteractionType": "WalkTo", + "AetheryteShortcut": "Ul'dah", + "$": "Ul'dah Aetheryte to Immortal Flames" + } +``` ## Mor Dhona ```json diff --git a/Questionable.Model/V1/SkipStepConditions.cs b/Questionable.Model/V1/SkipStepConditions.cs index 5f15ca98..be8df96b 100644 --- a/Questionable.Model/V1/SkipStepConditions.cs +++ b/Questionable.Model/V1/SkipStepConditions.cs @@ -21,7 +21,7 @@ public sealed class SkipStepConditions { if (Never) return false; - return (CompletionQuestVariablesFlags.Count > 6 && CompletionQuestVariablesFlags.Any(x => x != null)) || + return (CompletionQuestVariablesFlags.Count > 0 && CompletionQuestVariablesFlags.Any(x => x != null)) || Flying != null || Chocobo != null || NotTargetable || From ae87b4ccc5772913006b43d4477633119cd96b30 Mon Sep 17 00:00:00 2001 From: Liza Carvelli Date: Fri, 2 Aug 2024 18:30:21 +0200 Subject: [PATCH 08/12] Schema update --- .../GatheringPathRenderer.csproj | 3 + GatheringPathRenderer/RendererPlugin.cs | 11 + GatheringPathRenderer/packages.lock.json | 81 +++++ GatheringPaths/2.x - A Realm Reborn/.gitkeep | 0 GatheringPaths/3.x - Heavensward/.gitkeep | 0 GatheringPaths/4.x - Stormblood/.gitkeep | 0 GatheringPaths/5.x - Shadowbringers/.gitkeep | 0 .../Thavnair/820_Pewter Ore.json | 56 ++++ GatheringPaths/7.x - Dawntrail/.gitkeep | 0 .../AssemblyGatheringLocationLoader.cs | 32 ++ GatheringPaths/GatheringPaths.csproj | 43 +++ GatheringPaths/gatheringlocation-v1.json | 98 ++++++ GatheringPaths/packages.lock.json | 26 ++ .../QuestGeneratorTest.cs | 2 +- .../GatheringSourceGenerator.cs | 163 +++++++++ QuestPathGenerator/QuestSourceGenerator.cs | 93 ++---- QuestPathGenerator/RoslynShortcuts.cs | 30 +- QuestPathGenerator/Utils.cs | 109 ++++++ QuestPaths/AssemblyQuestLoader.cs | 3 +- QuestPaths/QuestPaths.csproj | 1 + QuestPaths/quest-v1.json | 311 +----------------- Questionable.Model/AssemblyModelLoader.cs | 9 + .../Converter/AetheryteConverter.cs | 3 +- .../{V1 => Common}/Converter/EnumConverter.cs | 2 +- .../Converter/StringListOrValueConverter.cs | 2 +- .../Converter/VectorConverter.cs | 2 +- .../{V1 => Common}/EAetheryteLocation.cs | 5 +- .../Gathering/GatheringNodeLocation.cs | 13 + Questionable.Model/Gathering/GatheringRoot.cs | 18 + .../{V1 => Questing}/AethernetShortcut.cs | 5 +- .../{V1 => Questing}/ChatMessage.cs | 2 +- .../{V1 => Questing}/ComplexCombatData.cs | 2 +- .../Converter/ActionConverter.cs | 3 +- .../Converter/AethernetShardConverter.cs | 4 +- .../Converter/AethernetShortcutConverter.cs | 3 +- .../Converter/DialogueChoiceTypeConverter.cs | 3 +- .../Converter/EmoteConverter.cs | 3 +- .../Converter/EnemySpawnTypeConverter.cs | 3 +- .../Converter/ExcelRefConverter.cs | 2 +- .../Converter/InteractionTypeConverter.cs | 3 +- .../Converter/JumpTypeConverter.cs | 3 +- .../Converter/LockedSkipConditionConverter.cs | 3 +- .../Converter/QuestWorkConfigConverter.cs | 2 +- .../Converter/QuestWorkModeConverter.cs | 3 +- .../Converter/SkipConditionConverter.cs | 3 +- .../{V1 => Questing}/DialogueChoice.cs | 4 +- .../{V1 => Questing}/EAction.cs | 4 +- .../{V1 => Questing}/EDialogChoiceType.cs | 2 +- Questionable.Model/{V1 => Questing}/EEmote.cs | 4 +- .../{V1 => Questing}/EEnemySpawnType.cs | 4 +- .../{V1 => Questing}/EExtraSkipCondition.cs | 4 +- .../{V1 => Questing}/EInteractionType.cs | 4 +- .../{V1 => Questing}/EJumpType.cs | 4 +- .../{V1 => Questing}/ELockedSkipCondition.cs | 4 +- .../{V1 => Questing}/EQuestWorkMode.cs | 4 +- .../{V1 => Questing}/ExcelRef.cs | 2 +- .../{V1 => Questing}/JumpDestination.cs | 5 +- .../{V1 => Questing}/QuestRoot.cs | 5 +- .../{V1 => Questing}/QuestSequence.cs | 2 +- .../{V1 => Questing}/QuestStep.cs | 6 +- .../{V1 => Questing}/QuestWorkValue.cs | 4 +- .../SkipAetheryteCondition.cs | 2 +- .../{V1 => Questing}/SkipConditions.cs | 2 +- .../{V1 => Questing}/SkipItemConditions.cs | 2 +- .../{V1 => Questing}/SkipStepConditions.cs | 2 +- Questionable.Model/Questionable.Model.csproj | 8 + Questionable.Model/common-schema.json | 299 +++++++++++++++++ Questionable.sln | 12 + Questionable/ChatFunctions.cs | 2 +- Questionable/Controller/CombatController.cs | 2 +- Questionable/Controller/GameUiController.cs | 2 +- Questionable/Controller/MovementController.cs | 6 +- Questionable/Controller/QuestController.cs | 2 +- Questionable/Controller/QuestRegistry.cs | 2 +- .../Controller/Steps/Common/NextQuest.cs | 2 +- Questionable/Controller/Steps/ITaskFactory.cs | 2 +- .../Controller/Steps/Interactions/Action.cs | 2 +- .../Steps/Interactions/AetherCurrent.cs | 2 +- .../Steps/Interactions/AethernetShard.cs | 4 +- .../Steps/Interactions/Aetheryte.cs | 3 +- .../Controller/Steps/Interactions/Combat.cs | 2 +- .../Controller/Steps/Interactions/Dive.cs | 2 +- .../Controller/Steps/Interactions/Duty.cs | 2 +- .../Controller/Steps/Interactions/Emote.cs | 2 +- .../Steps/Interactions/EquipItem.cs | 2 +- .../Controller/Steps/Interactions/Interact.cs | 2 +- .../Controller/Steps/Interactions/Jump.cs | 2 +- .../Controller/Steps/Interactions/Say.cs | 2 +- .../Steps/Interactions/SinglePlayerDuty.cs | 2 +- .../Controller/Steps/Interactions/UseItem.cs | 3 +- .../Steps/Shared/AethernetShortcut.cs | 6 +- .../Steps/Shared/AetheryteShortcut.cs | 3 +- Questionable/Controller/Steps/Shared/Move.cs | 2 +- .../Controller/Steps/Shared/SkipCondition.cs | 3 +- .../Controller/Steps/Shared/StepDisabled.cs | 2 +- .../Controller/Steps/Shared/WaitAtEnd.cs | 2 +- .../Controller/Steps/Shared/WaitAtStart.cs | 2 +- .../Controller/Utils/QuestWorkUtils.cs | 2 +- Questionable/Data/AetheryteData.cs | 3 +- Questionable/External/LifestreamIpc.cs | 2 +- Questionable/GameFunctions.cs | 3 +- Questionable/Model/Quest.cs | 2 +- .../Validators/AethernetShortcutValidator.cs | 2 +- .../Validators/BasicSequenceValidator.cs | 2 +- .../Validators/CompletionFlagsValidator.cs | 2 +- .../Validators/JsonSchemaValidator.cs | 11 +- .../Validators/UniqueStartStopValidator.cs | 2 +- Questionable/Windows/DebugOverlay.cs | 2 +- .../QuestComponents/ActiveQuestComponent.cs | 2 +- .../QuestComponents/CreationUtilsComponent.cs | 50 ++- Questionable/Windows/QuestSelectionWindow.cs | 2 +- 111 files changed, 1211 insertions(+), 500 deletions(-) create mode 100644 GatheringPathRenderer/GatheringPathRenderer.csproj create mode 100644 GatheringPathRenderer/RendererPlugin.cs create mode 100644 GatheringPathRenderer/packages.lock.json create mode 100644 GatheringPaths/2.x - A Realm Reborn/.gitkeep create mode 100644 GatheringPaths/3.x - Heavensward/.gitkeep create mode 100644 GatheringPaths/4.x - Stormblood/.gitkeep create mode 100644 GatheringPaths/5.x - Shadowbringers/.gitkeep create mode 100644 GatheringPaths/6.x - Endwalker/Thavnair/820_Pewter Ore.json create mode 100644 GatheringPaths/7.x - Dawntrail/.gitkeep create mode 100644 GatheringPaths/AssemblyGatheringLocationLoader.cs create mode 100644 GatheringPaths/GatheringPaths.csproj create mode 100644 GatheringPaths/gatheringlocation-v1.json create mode 100644 GatheringPaths/packages.lock.json create mode 100644 QuestPathGenerator/GatheringSourceGenerator.cs create mode 100644 QuestPathGenerator/Utils.cs create mode 100644 Questionable.Model/AssemblyModelLoader.cs rename Questionable.Model/{V1 => Common}/Converter/AetheryteConverter.cs (98%) rename Questionable.Model/{V1 => Common}/Converter/EnumConverter.cs (96%) rename Questionable.Model/{V1 => Common}/Converter/StringListOrValueConverter.cs (96%) rename Questionable.Model/{V1 => Common}/Converter/VectorConverter.cs (97%) rename Questionable.Model/{V1 => Common}/EAetheryteLocation.cs (98%) create mode 100644 Questionable.Model/Gathering/GatheringNodeLocation.cs create mode 100644 Questionable.Model/Gathering/GatheringRoot.cs rename Questionable.Model/{V1 => Questing}/AethernetShortcut.cs (66%) rename Questionable.Model/{V1 => Questing}/ChatMessage.cs (75%) rename Questionable.Model/{V1 => Questing}/ComplexCombatData.cs (93%) rename Questionable.Model/{V1 => Questing}/Converter/ActionConverter.cs (86%) rename Questionable.Model/{V1 => Questing}/Converter/AethernetShardConverter.cs (98%) rename Questionable.Model/{V1 => Questing}/Converter/AethernetShortcutConverter.cs (95%) rename Questionable.Model/{V1 => Questing}/Converter/DialogueChoiceTypeConverter.cs (77%) rename Questionable.Model/{V1 => Questing}/Converter/EmoteConverter.cs (91%) rename Questionable.Model/{V1 => Questing}/Converter/EnemySpawnTypeConverter.cs (83%) rename Questionable.Model/{V1 => Questing}/Converter/ExcelRefConverter.cs (95%) rename Questionable.Model/{V1 => Questing}/Converter/InteractionTypeConverter.cs (93%) rename Questionable.Model/{V1 => Questing}/Converter/JumpTypeConverter.cs (76%) rename Questionable.Model/{V1 => Questing}/Converter/LockedSkipConditionConverter.cs (78%) rename Questionable.Model/{V1 => Questing}/Converter/QuestWorkConfigConverter.cs (97%) rename Questionable.Model/{V1 => Questing}/Converter/QuestWorkModeConverter.cs (77%) rename Questionable.Model/{V1 => Questing}/Converter/SkipConditionConverter.cs (76%) rename Questionable.Model/{V1 => Questing}/DialogueChoice.cs (87%) rename Questionable.Model/{V1 => Questing}/EAction.cs (88%) rename Questionable.Model/{V1 => Questing}/EDialogChoiceType.cs (61%) rename Questionable.Model/{V1 => Questing}/EEmote.cs (85%) rename Questionable.Model/{V1 => Questing}/EEnemySpawnType.cs (72%) rename Questionable.Model/{V1 => Questing}/EExtraSkipCondition.cs (65%) rename Questionable.Model/{V1 => Questing}/EInteractionType.cs (86%) rename Questionable.Model/{V1 => Questing}/EJumpType.cs (63%) rename Questionable.Model/{V1 => Questing}/ELockedSkipCondition.cs (65%) rename Questionable.Model/{V1 => Questing}/EQuestWorkMode.cs (63%) rename Questionable.Model/{V1 => Questing}/ExcelRef.cs (97%) rename Questionable.Model/{V1 => Questing}/JumpDestination.cs (76%) rename Questionable.Model/{V1 => Questing}/QuestRoot.cs (80%) rename Questionable.Model/{V1 => Questing}/QuestSequence.cs (91%) rename Questionable.Model/{V1 => Questing}/QuestStep.cs (95%) rename Questionable.Model/{V1 => Questing}/QuestWorkValue.cs (90%) rename Questionable.Model/{V1 => Questing}/SkipAetheryteCondition.cs (75%) rename Questionable.Model/{V1 => Questing}/SkipConditions.cs (84%) rename Questionable.Model/{V1 => Questing}/SkipItemConditions.cs (67%) rename Questionable.Model/{V1 => Questing}/SkipStepConditions.cs (97%) create mode 100644 Questionable.Model/common-schema.json diff --git a/GatheringPathRenderer/GatheringPathRenderer.csproj b/GatheringPathRenderer/GatheringPathRenderer.csproj new file mode 100644 index 00000000..5d22cd3f --- /dev/null +++ b/GatheringPathRenderer/GatheringPathRenderer.csproj @@ -0,0 +1,3 @@ + + + diff --git a/GatheringPathRenderer/RendererPlugin.cs b/GatheringPathRenderer/RendererPlugin.cs new file mode 100644 index 00000000..d33eae96 --- /dev/null +++ b/GatheringPathRenderer/RendererPlugin.cs @@ -0,0 +1,11 @@ +using Dalamud.Plugin; + +namespace GatheringPathRenderer; + +public sealed class RendererPlugin : IDalamudPlugin +{ + public void Dispose() + { + + } +} diff --git a/GatheringPathRenderer/packages.lock.json b/GatheringPathRenderer/packages.lock.json new file mode 100644 index 00000000..0c669ebf --- /dev/null +++ b/GatheringPathRenderer/packages.lock.json @@ -0,0 +1,81 @@ +{ + "version": 1, + "dependencies": { + "net8.0-windows7.0": { + "DalamudPackager": { + "type": "Direct", + "requested": "[2.1.13, )", + "resolved": "2.1.13", + "contentHash": "rMN1omGe8536f4xLMvx9NwfvpAc9YFFfeXJ1t4P4PE6Gu8WCIoFliR1sh07hM+bfODmesk/dvMbji7vNI+B/pQ==" + }, + "DotNet.ReproducibleBuilds": { + "type": "Direct", + "requested": "[1.1.1, )", + "resolved": "1.1.1", + "contentHash": "+H2t/t34h6mhEoUvHi8yGXyuZ2GjSovcGYehJrS2MDm2XgmPfZL2Sdxg+uL2lKgZ4M6tTwKHIlxOob2bgh0NRQ==", + "dependencies": { + "Microsoft.SourceLink.AzureRepos.Git": "1.1.1", + "Microsoft.SourceLink.Bitbucket.Git": "1.1.1", + "Microsoft.SourceLink.GitHub": "1.1.1", + "Microsoft.SourceLink.GitLab": "1.1.1" + } + }, + "Microsoft.SourceLink.Gitea": { + "type": "Direct", + "requested": "[8.0.0, )", + "resolved": "8.0.0", + "contentHash": "KOBodmDnlWGIqZt2hT47Q69TIoGhIApDVLCyyj9TT5ct8ju16AbHYcB4XeknoHX562wO1pMS/1DfBIZK+V+sxg==", + "dependencies": { + "Microsoft.Build.Tasks.Git": "8.0.0", + "Microsoft.SourceLink.Common": "8.0.0" + } + }, + "Microsoft.Build.Tasks.Git": { + "type": "Transitive", + "resolved": "8.0.0", + "contentHash": "bZKfSIKJRXLTuSzLudMFte/8CempWjVamNUR5eHJizsy+iuOuO/k2gnh7W0dHJmYY0tBf+gUErfluCv5mySAOQ==" + }, + "Microsoft.SourceLink.AzureRepos.Git": { + "type": "Transitive", + "resolved": "1.1.1", + "contentHash": "qB5urvw9LO2bG3eVAkuL+2ughxz2rR7aYgm2iyrB8Rlk9cp2ndvGRCvehk3rNIhRuNtQaeKwctOl1KvWiklv5w==", + "dependencies": { + "Microsoft.Build.Tasks.Git": "1.1.1", + "Microsoft.SourceLink.Common": "1.1.1" + } + }, + "Microsoft.SourceLink.Bitbucket.Git": { + "type": "Transitive", + "resolved": "1.1.1", + "contentHash": "cDzxXwlyWpLWaH0em4Idj0H3AmVo3L/6xRXKssYemx+7W52iNskj/SQ4FOmfCb8YQt39otTDNMveCZzYtMoucQ==", + "dependencies": { + "Microsoft.Build.Tasks.Git": "1.1.1", + "Microsoft.SourceLink.Common": "1.1.1" + } + }, + "Microsoft.SourceLink.Common": { + "type": "Transitive", + "resolved": "8.0.0", + "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw==" + }, + "Microsoft.SourceLink.GitHub": { + "type": "Transitive", + "resolved": "1.1.1", + "contentHash": "IaJGnOv/M7UQjRJks7B6p7pbPnOwisYGOIzqCz5ilGFTApZ3ktOR+6zJ12ZRPInulBmdAf1SrGdDG2MU8g6XTw==", + "dependencies": { + "Microsoft.Build.Tasks.Git": "1.1.1", + "Microsoft.SourceLink.Common": "1.1.1" + } + }, + "Microsoft.SourceLink.GitLab": { + "type": "Transitive", + "resolved": "1.1.1", + "contentHash": "tvsg47DDLqqedlPeYVE2lmiTpND8F0hkrealQ5hYltSmvruy/Gr5nHAKSsjyw5L3NeM/HLMI5ORv7on/M4qyZw==", + "dependencies": { + "Microsoft.Build.Tasks.Git": "1.1.1", + "Microsoft.SourceLink.Common": "1.1.1" + } + } + } + } +} \ No newline at end of file diff --git a/GatheringPaths/2.x - A Realm Reborn/.gitkeep b/GatheringPaths/2.x - A Realm Reborn/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/GatheringPaths/3.x - Heavensward/.gitkeep b/GatheringPaths/3.x - Heavensward/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/GatheringPaths/4.x - Stormblood/.gitkeep b/GatheringPaths/4.x - Stormblood/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/GatheringPaths/5.x - Shadowbringers/.gitkeep b/GatheringPaths/5.x - Shadowbringers/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/GatheringPaths/6.x - Endwalker/Thavnair/820_Pewter Ore.json b/GatheringPaths/6.x - Endwalker/Thavnair/820_Pewter Ore.json new file mode 100644 index 00000000..425d77eb --- /dev/null +++ b/GatheringPaths/6.x - Endwalker/Thavnair/820_Pewter Ore.json @@ -0,0 +1,56 @@ +{ + "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json", + "Author": "liza", + "TerritoryId": 957, + "AetheryteShortcut": "Thavnair - Great Work", + "Nodes": [ + { + "DataId": 33918, + "Position": { + "X": -582.5132, + "Y": 40.54578, + "Z": -426.0171 + } + }, + { + "DataId": 33919, + "Position": { + "X": -578.2101, + "Y": 41.27147, + "Z": -447.6376 + } + }, + { + "DataId": 33920, + "Position": { + "X": -488.2276, + "Y": 34.71221, + "Z": -359.6945 + } + }, + { + "DataId": 33921, + "Position": { + "X": -498.8687, + "Y": 31.08014, + "Z": -351.9397 + } + }, + { + "DataId": 33922, + "Position": { + "X": -304.0609, + "Y": 68.76999, + "Z": -479.1875 + } + }, + { + "DataId": 33923, + "Position": { + "X": -293.6989, + "Y": 68.77935, + "Z": -484.2256 + } + } + ] +} diff --git a/GatheringPaths/7.x - Dawntrail/.gitkeep b/GatheringPaths/7.x - Dawntrail/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/GatheringPaths/AssemblyGatheringLocationLoader.cs b/GatheringPaths/AssemblyGatheringLocationLoader.cs new file mode 100644 index 00000000..04176410 --- /dev/null +++ b/GatheringPaths/AssemblyGatheringLocationLoader.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.IO; +using Questionable.Model.Gathering; + +namespace Questionable.GatheringPaths; + +[SuppressMessage("ReSharper", "PartialTypeWithSinglePart", Justification = "Required for RELEASE")] +public static partial class AssemblyGatheringLocationLoader +{ + private static Dictionary? _locations; + + public static IReadOnlyDictionary GetLocations() + { + if (_locations == null) + { + _locations = []; +#if RELEASE + LoadLocations(); +#endif + } + + return _locations ?? throw new InvalidOperationException("quest data is not initialized"); + } + + public static Stream QuestSchema => + typeof(AssemblyGatheringLocationLoader).Assembly.GetManifestResourceStream("Questionable.GatheringPaths.GatheringLocationSchema")!; + + [SuppressMessage("ReSharper", "UnusedMember.Local")] + private static void AddLocation(ushort questId, GatheringRoot root) => _locations![questId] = root; +} diff --git a/GatheringPaths/GatheringPaths.csproj b/GatheringPaths/GatheringPaths.csproj new file mode 100644 index 00000000..f9e9725f --- /dev/null +++ b/GatheringPaths/GatheringPaths.csproj @@ -0,0 +1,43 @@ + + + net8.0-windows + 12 + enable + Questionable.GatheringPaths + true + true + none + $(SolutionDir)=X:\ + true + x64 + + + + + + + + + + + Questionable.GatheringPaths.GatheringLocationSchema + + + + + + + + + + + + + + + + + + + + diff --git a/GatheringPaths/gatheringlocation-v1.json b/GatheringPaths/gatheringlocation-v1.json new file mode 100644 index 00000000..53b34f74 --- /dev/null +++ b/GatheringPaths/gatheringlocation-v1.json @@ -0,0 +1,98 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json", + "title": "Gathering Location V1", + "description": "A series of gathering locationsk", + "type": "object", + "properties": { + "$schema": { + "type": "string", + "const": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json" + }, + "Author": { + "description": "Author of the gathering location data", + "type": [ + "string", + "array" + ], + "items": { + "type": "string" + } + }, + "TerritoryId": { + "type": "number" + }, + "AetheryteShortcut": { + "$ref": "https://git.carvel.li/liza/Questionable/raw/branch/master/Questionable.Model/common-schema.json#/$defs/Aetheryte" + }, + "Nodes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "DataId": { + "type": "number", + "minimum": 30000, + "maximum": 50000 + }, + "Position": { + "$ref": "#/$defs/Vector3" + }, + "MinimumAngle": { + "type": "number", + "minimum": -360, + "maximum": 360 + }, + "MaximumAngle": { + "type": "number", + "minimum": -360, + "maximum": 360 + }, + "MinimumDistance": { + "type": "number", + "minimum": 0 + }, + "MaximumDistance": { + "type": "number", + "exclusiveMinimum": 0 + } + }, + "required": [ + "DataId", + "Position" + ], + "additionalProperties": false + } + } + }, + "required": [ + "$schema", + "Author", + "TerritoryId", + "AetheryteShortcut", + "Nodes" + ], + "additionalProperties": false, + "$defs": { + "Vector3": { + "type": "object", + "description": "Position to (typically) walk to", + "properties": { + "X": { + "type": "number" + }, + "Y": { + "type": "number" + }, + "Z": { + "type": "number" + } + }, + "required": [ + "X", + "Y", + "Z" + ] + } + } +} diff --git a/GatheringPaths/packages.lock.json b/GatheringPaths/packages.lock.json new file mode 100644 index 00000000..408e267a --- /dev/null +++ b/GatheringPaths/packages.lock.json @@ -0,0 +1,26 @@ +{ + "version": 1, + "dependencies": { + "net8.0-windows7.0": { + "System.Text.Encodings.Web": { + "type": "Transitive", + "resolved": "8.0.0", + "contentHash": "yev/k9GHAEGx2Rg3/tU6MQh4HGBXJs70y7j1LaM1i/ER9po+6nnQ6RRqTJn1E7Xu0fbIFK80Nh5EoODxrbxwBQ==" + }, + "System.Text.Json": { + "type": "Transitive", + "resolved": "8.0.4", + "contentHash": "bAkhgDJ88XTsqczoxEMliSrpijKZHhbJQldhAmObj/RbrN3sU5dcokuXmWJWsdQAhiMJ9bTayWsL1C9fbbCRhw==", + "dependencies": { + "System.Text.Encodings.Web": "8.0.0" + } + }, + "questionable.model": { + "type": "Project", + "dependencies": { + "System.Text.Json": "[8.0.4, )" + } + } + } + } +} \ No newline at end of file diff --git a/QuestPathGenerator.Tests/QuestGeneratorTest.cs b/QuestPathGenerator.Tests/QuestGeneratorTest.cs index 55d4cd64..f08606c1 100644 --- a/QuestPathGenerator.Tests/QuestGeneratorTest.cs +++ b/QuestPathGenerator.Tests/QuestGeneratorTest.cs @@ -1,4 +1,4 @@ -using Questionable.Model.V1; +using Questionable.Model.Questing; using Questionable.QuestPathGenerator; using Xunit; diff --git a/QuestPathGenerator/GatheringSourceGenerator.cs b/QuestPathGenerator/GatheringSourceGenerator.cs new file mode 100644 index 00000000..a10acd0e --- /dev/null +++ b/QuestPathGenerator/GatheringSourceGenerator.cs @@ -0,0 +1,163 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.IO; +using System.Linq; +using System.Text.Json; +using Json.Schema; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Questionable.Model.Gathering; +using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; +using static Questionable.QuestPathGenerator.RoslynShortcuts; + +namespace Questionable.QuestPathGenerator; + +[Generator] +[SuppressMessage("MicrosoftCodeAnalysisReleaseTracking", "RS2008")] +public class GatheringSourceGenerator : ISourceGenerator +{ + private static readonly DiagnosticDescriptor InvalidJson = new("GPG0001", + "Invalid JSON", + "Invalid gathering file: {0}", + nameof(GatheringSourceGenerator), + DiagnosticSeverity.Error, + true); + + public void Initialize(GeneratorInitializationContext context) + { + // No initialization required for this generator. + } + + public void Execute(GeneratorExecutionContext context) + { + // Find schema definition + AdditionalText? gatheringSchema = + context.AdditionalFiles.SingleOrDefault(x => Path.GetFileName(x.Path) == "gatheringlocation-v1.json"); + if (gatheringSchema != null) + GenerateGatheringSource(context, gatheringSchema); + } + + private void GenerateGatheringSource(GeneratorExecutionContext context, AdditionalText jsonSchemaFile) + { + var gatheringSchema = JsonSchema.FromText(jsonSchemaFile.GetText()!.ToString()); + + List<(ushort, GatheringRoot)> gatheringLocations = []; + foreach (var (id, node) in Utils.GetAdditionalFiles(context, jsonSchemaFile, gatheringSchema, InvalidJson)) + { + var gatheringLocation = node.Deserialize()!; + gatheringLocations.Add((id, gatheringLocation)); + } + + if (gatheringLocations.Count == 0) + return; + + var partitionedLocations = gatheringLocations + .OrderBy(x => x.Item1) + .GroupBy(x => $"LoadLocation{x.Item1 / 100}") + .ToList(); + + var methods = Utils.CreateMethods("LoadLocations", partitionedLocations, CreateInitializer); + + var code = + CompilationUnit() + .WithUsings( + List( + new[] + { + UsingDirective( + IdentifierName("System")), + UsingDirective( + QualifiedName( + IdentifierName("System"), + IdentifierName("Numerics"))), + UsingDirective( + QualifiedName( + IdentifierName("System"), + IdentifierName("IO"))), + UsingDirective( + QualifiedName( + QualifiedName( + IdentifierName("System"), IdentifierName("Collections")), + IdentifierName("Generic"))), + UsingDirective( + QualifiedName( + QualifiedName( + IdentifierName("Questionable"), + IdentifierName("Model")), + IdentifierName("Gathering"))), + UsingDirective( + QualifiedName( + QualifiedName( + IdentifierName("Questionable"), + IdentifierName("Model")), + IdentifierName("Common"))) + })) + .WithMembers( + SingletonList( + FileScopedNamespaceDeclaration( + QualifiedName( + IdentifierName("Questionable"), + IdentifierName("GatheringPaths"))) + .WithMembers( + SingletonList( + ClassDeclaration("AssemblyGatheringLocationLoader") + .WithModifiers( + TokenList(Token(SyntaxKind.PartialKeyword))) + .WithMembers(List(methods)))))) + .NormalizeWhitespace(); + + // Add the source code to the compilation. + context.AddSource("AssemblyGatheringLocationLoader.g.cs", code.ToFullString()); + } + + private static StatementSyntax[] CreateInitializer(List<(ushort QuestId, GatheringRoot Root)> quests) + { + List statements = []; + + foreach (var quest in quests) + { + statements.Add( + ExpressionStatement( + InvocationExpression( + IdentifierName("AddLocation")) + .WithArgumentList( + ArgumentList( + SeparatedList( + new SyntaxNodeOrToken[] + { + Argument( + LiteralExpression(SyntaxKind.NumericLiteralExpression, + Literal(quest.QuestId))), + Token(SyntaxKind.CommaToken), + Argument(CreateGatheringRootExpression(quest.QuestId, quest.Root)) + }))))); + } + + return statements.ToArray(); + } + + private static ObjectCreationExpressionSyntax CreateGatheringRootExpression(ushort locationId, GatheringRoot root) + { + try + { + return ObjectCreationExpression( + IdentifierName(nameof(GatheringRoot))) + .WithInitializer( + InitializerExpression( + SyntaxKind.ObjectInitializerExpression, + SeparatedList( + SyntaxNodeList( + AssignmentList(nameof(GatheringRoot.Author), root.Author).AsSyntaxNodeOrToken(), + Assignment(nameof(GatheringRoot.TerritoryId), root.TerritoryId, default) + .AsSyntaxNodeOrToken(), + Assignment(nameof(GatheringRoot.AetheryteShortcut), root.AetheryteShortcut, null), + AssignmentList(nameof(GatheringRoot.Nodes), root.Nodes).AsSyntaxNodeOrToken())))); + } + catch (Exception e) + { + throw new Exception($"GatheringGen[{locationId}]: {e.Message}", e); + } + } +} diff --git a/QuestPathGenerator/QuestSourceGenerator.cs b/QuestPathGenerator/QuestSourceGenerator.cs index 47d311f2..b6cccbab 100644 --- a/QuestPathGenerator/QuestSourceGenerator.cs +++ b/QuestPathGenerator/QuestSourceGenerator.cs @@ -1,16 +1,14 @@ using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; -using System.Globalization; using System.IO; using System.Linq; using System.Text.Json; -using System.Text.Json.Nodes; using Json.Schema; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Questionable.Model.V1; +using Questionable.Model.Questing; using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; using static Questionable.QuestPathGenerator.RoslynShortcuts; @@ -38,47 +36,21 @@ public class QuestSourceGenerator : ISourceGenerator public void Execute(GeneratorExecutionContext context) { - List<(ushort, QuestRoot)> quests = []; - // Find schema definition - AdditionalText jsonSchemaFile = - context.AdditionalFiles.Single(x => Path.GetFileName(x.Path) == "quest-v1.json"); + AdditionalText? questSchema = + context.AdditionalFiles.SingleOrDefault(x => Path.GetFileName(x.Path) == "quest-v1.json"); + if (questSchema != null) + GenerateQuestSource(context, questSchema); + } + + private void GenerateQuestSource(GeneratorExecutionContext context, AdditionalText jsonSchemaFile) + { var questSchema = JsonSchema.FromText(jsonSchemaFile.GetText()!.ToString()); - // Go through all files marked as an Additional File in file properties. - foreach (var additionalFile in context.AdditionalFiles) + List<(ushort, QuestRoot)> quests = []; + foreach (var (id, node) in Utils.GetAdditionalFiles(context, jsonSchemaFile, questSchema, InvalidJson)) { - if (additionalFile == null || additionalFile == jsonSchemaFile) - continue; - - if (Path.GetExtension(additionalFile.Path) != ".json") - continue; - - string name = Path.GetFileName(additionalFile.Path); - if (!name.Contains('_')) - continue; - - ushort id = ushort.Parse(name.Substring(0, name.IndexOf('_'))); - - var text = additionalFile.GetText(); - if (text == null) - continue; - - var questNode = JsonNode.Parse(text.ToString()); - var evaluationResult = questSchema.Evaluate(questNode, new EvaluationOptions - { - Culture = CultureInfo.InvariantCulture, - OutputFormat = OutputFormat.List - }); - if (!evaluationResult.IsValid) - { - var error = Diagnostic.Create(InvalidJson, - null, - Path.GetFileName(additionalFile.Path)); - context.ReportDiagnostic(error); - } - - var quest = questNode.Deserialize()!; + var quest = node.Deserialize()!; if (quest.Disabled) { quest.Author = []; @@ -97,38 +69,7 @@ public class QuestSourceGenerator : ISourceGenerator .GroupBy(x => $"LoadQuests{x.Item1 / 50}") .ToList(); - List methods = - [ - MethodDeclaration( - PredefinedType( - Token(SyntaxKind.VoidKeyword)), - Identifier("LoadQuests")) - .WithModifiers( - TokenList( - Token(SyntaxKind.PrivateKeyword), - Token(SyntaxKind.StaticKeyword))) - .WithBody( - Block( - partitionedQuests - .Select(x => - ExpressionStatement( - InvocationExpression( - IdentifierName(x.Key)))))) - ]; - - foreach (var partition in partitionedQuests) - { - methods.Add(MethodDeclaration( - PredefinedType( - Token(SyntaxKind.VoidKeyword)), - Identifier(partition.Key)) - .WithModifiers( - TokenList( - Token(SyntaxKind.PrivateKeyword), - Token(SyntaxKind.StaticKeyword))) - .WithBody( - Block(CreateInitializer(partition.ToList())))); - } + var methods = Utils.CreateMethods("LoadQuests", partitionedQuests, CreateInitializer); var code = CompilationUnit() @@ -156,7 +97,13 @@ public class QuestSourceGenerator : ISourceGenerator QualifiedName( IdentifierName("Questionable"), IdentifierName("Model")), - IdentifierName("V1"))) + IdentifierName("Questing"))), + UsingDirective( + QualifiedName( + QualifiedName( + IdentifierName("Questionable"), + IdentifierName("Model")), + IdentifierName("Common"))) })) .WithMembers( SingletonList( diff --git a/QuestPathGenerator/RoslynShortcuts.cs b/QuestPathGenerator/RoslynShortcuts.cs index 2bacaba4..4f5a8fb0 100644 --- a/QuestPathGenerator/RoslynShortcuts.cs +++ b/QuestPathGenerator/RoslynShortcuts.cs @@ -6,7 +6,9 @@ using System.Numerics; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Questionable.Model.V1; +using Questionable.Model.Common; +using Questionable.Model.Gathering; +using Questionable.Model.Questing; using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; namespace Questionable.QuestPathGenerator; @@ -312,6 +314,32 @@ public static class RoslynShortcuts Assignment(nameof(SkipAetheryteCondition.InSameTerritory), skipAetheryteCondition.InSameTerritory, emptyAetheryte.InSameTerritory))))); } + else if (value is GatheringNodeLocation nodeLocation) + { + var emptyLocation = new GatheringNodeLocation(); + return ObjectCreationExpression( + IdentifierName(nameof(GatheringNodeLocation))) + .WithInitializer( + InitializerExpression( + SyntaxKind.ObjectInitializerExpression, + SeparatedList( + SyntaxNodeList( + Assignment(nameof(GatheringNodeLocation.DataId), nodeLocation.DataId, + emptyLocation.DataId) + .AsSyntaxNodeOrToken(), + Assignment(nameof(GatheringNodeLocation.Position), nodeLocation.Position, + emptyLocation.Position).AsSyntaxNodeOrToken(), + Assignment(nameof(GatheringNodeLocation.MinimumAngle), nodeLocation.MinimumAngle, + emptyLocation.MinimumAngle).AsSyntaxNodeOrToken(), + Assignment(nameof(GatheringNodeLocation.MaximumAngle), nodeLocation.MaximumAngle, + emptyLocation.MaximumAngle).AsSyntaxNodeOrToken(), + Assignment(nameof(GatheringNodeLocation.MinimumDistance), + nodeLocation.MinimumDistance, emptyLocation.MinimumDistance) + .AsSyntaxNodeOrToken(), + Assignment(nameof(GatheringNodeLocation.MaximumDistance), + nodeLocation.MaximumDistance, emptyLocation.MaximumDistance) + .AsSyntaxNodeOrToken())))); + } else if (value is null) return LiteralExpression(SyntaxKind.NullLiteralExpression); } diff --git a/QuestPathGenerator/Utils.cs b/QuestPathGenerator/Utils.cs new file mode 100644 index 00000000..12873a71 --- /dev/null +++ b/QuestPathGenerator/Utils.cs @@ -0,0 +1,109 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Text.Json.Nodes; +using Json.Schema; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; + +namespace Questionable.QuestPathGenerator; + +public static class Utils +{ + public static IEnumerable<(ushort, JsonNode)> GetAdditionalFiles(GeneratorExecutionContext context, + AdditionalText jsonSchemaFile, JsonSchema jsonSchema, DiagnosticDescriptor invalidJson) + { + var commonSchemaFile = context.AdditionalFiles.Single(x => Path.GetFileName(x.Path) == "common-schema.json"); + List jsonSchemaFiles = [jsonSchemaFile, commonSchemaFile]; + + SchemaRegistry.Global.Register( + new Uri("https://git.carvel.li/liza/Questionable/raw/branch/master/Questionable.Model/common-schema.json"), + JsonSchema.FromText(commonSchemaFile.GetText()!.ToString())); + + foreach (var additionalFile in context.AdditionalFiles) + { + if (additionalFile == null || jsonSchemaFiles.Contains(additionalFile)) + continue; + + if (Path.GetExtension(additionalFile.Path) != ".json") + continue; + + string name = Path.GetFileName(additionalFile.Path); + if (!name.Contains("_")) + continue; + + ushort id = ushort.Parse(name.Substring(0, name.IndexOf('_'))); + + var text = additionalFile.GetText(); + if (text == null) + continue; + + var node = JsonNode.Parse(text.ToString()); + if (node == null) + continue; + + string? schemaLocation = node["$schema"]?.GetValue(); + if (schemaLocation == null || new Uri(schemaLocation) != jsonSchema.GetId()) + continue; + + var evaluationResult = jsonSchema.Evaluate(node, new EvaluationOptions + { + Culture = CultureInfo.InvariantCulture, + OutputFormat = OutputFormat.List, + }); + if (!evaluationResult.IsValid) + { + var error = Diagnostic.Create(invalidJson, + null, + Path.GetFileName(additionalFile.Path)); + context.ReportDiagnostic(error); + } + + yield return (id, node); + } + } + + public static List CreateMethods(string prefix, + List> partitions, + Func, StatementSyntax[]> toInitializers) + { + List methods = + [ + MethodDeclaration( + PredefinedType( + Token(SyntaxKind.VoidKeyword)), + Identifier(prefix)) + .WithModifiers( + TokenList( + Token(SyntaxKind.PrivateKeyword), + Token(SyntaxKind.StaticKeyword))) + .WithBody( + Block( + partitions + .Select(x => + ExpressionStatement( + InvocationExpression( + IdentifierName(x.Key)))))) + ]; + + foreach (var partition in partitions) + { + methods.Add(MethodDeclaration( + PredefinedType( + Token(SyntaxKind.VoidKeyword)), + Identifier(partition.Key)) + .WithModifiers( + TokenList( + Token(SyntaxKind.PrivateKeyword), + Token(SyntaxKind.StaticKeyword))) + .WithBody( + Block(toInitializers(partition.ToList())))); + } + + return methods; + } +} diff --git a/QuestPaths/AssemblyQuestLoader.cs b/QuestPaths/AssemblyQuestLoader.cs index 90ba89a1..3ef7df15 100644 --- a/QuestPaths/AssemblyQuestLoader.cs +++ b/QuestPaths/AssemblyQuestLoader.cs @@ -2,8 +2,7 @@ using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.IO; -using System.Reflection; -using Questionable.Model.V1; +using Questionable.Model.Questing; namespace Questionable.QuestPaths; diff --git a/QuestPaths/QuestPaths.csproj b/QuestPaths/QuestPaths.csproj index e914b62d..5d91a016 100644 --- a/QuestPaths/QuestPaths.csproj +++ b/QuestPaths/QuestPaths.csproj @@ -23,6 +23,7 @@ Questionable.QuestPaths.QuestSchema + diff --git a/QuestPaths/quest-v1.json b/QuestPaths/quest-v1.json index 751e4730..a11a610c 100644 --- a/QuestPaths/quest-v1.json +++ b/QuestPaths/quest-v1.json @@ -154,7 +154,7 @@ }, "AetheryteShortcut": { "description": "The Aetheryte to teleport to (before moving)", - "$ref": "#/$defs/Aetheryte" + "$ref": "https://git.carvel.li/liza/Questionable/raw/branch/master/Questionable.Model/common-schema.json#/$defs/Aetheryte" }, "AethernetShortcut": { "type": "array", @@ -162,7 +162,7 @@ "minItems": 2, "maxItems": 2, "items": { - "$ref": "#/$defs/AethernetShard" + "$ref": "https://git.carvel.li/liza/Questionable/raw/branch/master/Questionable.Model/common-schema.json#/$defs/AethernetShard" } }, "ItemId": { @@ -183,7 +183,7 @@ "type": "boolean" }, "CompletionQuestVariablesFlags": { - "$ref": "#/$defs/CompletionFlags" + "$ref": "https://git.carvel.li/liza/Questionable/raw/branch/master/Questionable.Model/common-schema.json#/$defs/CompletionFlags" }, "Flying": { "type": "string", @@ -271,7 +271,7 @@ "additionalProperties": false }, "CompletionQuestVariablesFlags": { - "$ref": "#/$defs/CompletionFlags" + "$ref": "https://git.carvel.li/liza/Questionable/raw/branch/master/Questionable.Model/common-schema.json#/$defs/CompletionFlags" }, "RequiredQuestVariables": { "type": "array", @@ -383,7 +383,7 @@ "then": { "properties": { "Aetheryte": { - "$ref": "#/$defs/Aetheryte" + "$ref": "https://git.carvel.li/liza/Questionable/raw/branch/master/Questionable.Model/common-schema.json#/$defs/Aetheryte" }, "DataId": { "type": "null" @@ -415,7 +415,7 @@ "then": { "properties": { "AethernetShard": { - "$ref": "#/$defs/AethernetShard" + "$ref": "https://git.carvel.li/liza/Questionable/raw/branch/master/Questionable.Model/common-schema.json#/$defs/AethernetShard" }, "DataId": { "type": "null" @@ -507,7 +507,7 @@ "type": "integer" }, "CompletionQuestVariablesFlags": { - "$ref": "#/$defs/CompletionFlags" + "$ref": "https://git.carvel.li/liza/Questionable/raw/branch/master/Questionable.Model/common-schema.json#/$defs/CompletionFlags" }, "IgnoreQuestMarker": { "type": "boolean" @@ -1073,300 +1073,5 @@ "QuestSequence", "Author" ], - "additionalProperties": false, - "$defs": { - "Aetheryte": { - "type": "string", - "enum": [ - "Gridania", - "Central Shroud - Bentbranch Meadows", - "East Shroud - Hawthorne Hut", - "South Shroud - Quarrymill", - "South Shroud - Camp Tranquil", - "North Shroud - Fallgourd Float", - "Ul'dah", - "Western Thanalan - Horizon", - "Central Thanalan - Black Brush Station", - "Eastern Thanalan - Camp Drybone", - "Southern Thanalan - Little Ala Mhigo", - "Southern Thanalan - Forgotten Springs", - "Northern Thanalan - Camp Bluefog", - "Northern Thanalan - Ceruleum Processing Plant", - "Limsa Lominsa", - "Middle La Noscea - Summerford Farms", - "Lower La Noscea - Moraby Drydocks", - "Eastern La Noscea - Costa Del Sol", - "Eastern La Noscea - Wineport", - "Western La Noscea - Swiftperch", - "Western La Noscea - Aleport", - "Upper La Noscea - Camp Bronze Lake", - "Outer La Noscea - Camp Overlook", - "Coerthas Central Highlands - Camp Dragonhead", - "Mor Dhona", - "Gold Saucer", - "Wolves' Den Pier", - "Ishgard", - "Idyllshire", - "Coerthas Western Highlands - Falcon's Nest", - "The Sea of Clouds - Camp Cloudtop", - "The Sea of Clouds - Ok' Zundu", - "Azys Lla - Helix", - "The Dravanian Forelands - Tailfeather", - "The Dravanian Forelands - Anyx Trine", - "The Churning Mists - Moghome", - "The Churning Mists - Zenith", - "Rhalgr's Reach", - "Fringes - Castrum Oriens", - "Fringes - Peering Stones", - "Peaks - Ala Gannha", - "Peaks - Ala Ghiri", - "Lochs - Porta Praetoria", - "Lochs - Ala Mhigan Quarter", - "Kugane", - "Ruby Sea - Tamamizu", - "Ruby Sea - Onokoro", - "Yanxia - Namai", - "Yanxia - House of the Fierce", - "Azim Steppe - Reunion", - "Azim Steppe - Dawn Throne", - "Azim Steppe - Dhoro Iloh", - "Doman Enclave", - "Crystarium", - "Eulmore", - "Lakeland - Fort Jobb", - "Lakeland - Ostall Imperative", - "Kholusia - Stilltide", - "Kholusia - Wright", - "Kholusia - Tomra", - "Amh Araeng - Mord Souq", - "Amh Araeng - Inn at Journey's Head", - "Amh Araeng - Twine", - "Rak'tika - Slitherbough", - "Rak'tika - Fanow", - "Il Mheg - Lydha Lran", - "Il Mheg - Pia Enni", - "Il Mheg - Wolekdorf", - "Tempest - Ondo Cups", - "Tempest - Macarenses Angle", - "Old Sharlayan", - "Radz-at-Han", - "Labyrinthos - Archeion", - "Labyrinthos - Sharlayan Hamlet", - "Labyrinthos - Aporia", - "Thavnair - Yedlihmad", - "Thavnair - Great Work", - "Thavnair - Palaka's Stand", - "Garlemald - Camp Broken Glass", - "Garlemald - Tertium", - "Mare Lamentorum - Sinus Lacrimarum", - "Mare Lamentorum - Bestways Burrow", - "Elpis - Anagnorisis", - "Elpis - Twelve Wonders", - "Elpis - Poieten Oikos", - "Ultima Thule - Reah Tahra", - "Ultima Thule - Abode of the Ea", - "Ultima Thule - Base Omicron", - "Tuliyollal", - "Solution Nine", - "Urqopacha - Wachunpelo", - "Urqopacha - Worlar's Echo", - "Kozama'uka - Ok'hanu", - "Kozama'uka - Many Fires", - "Kozama'uka - Earthenshire", - "Yak T'el - Iq Br'aax", - "Yak T'el - Mamook", - "Shaaloani - Hhusatahwi", - "Shaaloani - Sheshenewezi Springs", - "Shaaloani - Mehwahhetsoan", - "Heritage Found - Yyasulani Station", - "Heritage Found - The Outskirts", - "Heritage Found - Electrope Strike", - "Living Memory - Leynode Mnemo", - "Living Memory - Leynode Pyro", - "Living Memory - Leynode Aero" - ] - }, - "AethernetShard": { - "type": "string", - "enum": [ - "[Gridania] Aetheryte Plaza", - "[Gridania] Archers' Guild", - "[Gridania] Leatherworkers' Guild & Shaded Bower", - "[Gridania] Lancers' Guild", - "[Gridania] Conjurers' Guild", - "[Gridania] Botanists' Guild", - "[Gridania] Mih Khetto's Amphitheatre", - "[Gridania] Blue Badger Gate (Central Shroud)", - "[Gridania] Yellow Serpent Gate (North Shroud)", - "[Gridania] White Wolf Gate (Central Shroud)", - "[Gridania] Airship Landing", - "[Ul'dah] Aetheryte Plaza", - "[Ul'dah] Adventurers' Guild", - "[Ul'dah] Thaumaturges' Guild", - "[Ul'dah] Gladiators' Guild", - "[Ul'dah] Miners' Guild", - "[Ul'dah] Weavers' Guild", - "[Ul'dah] Goldsmiths' Guild", - "[Ul'dah] Sapphire Avenue Exchange", - "[Ul'dah] Alchemists' Guild", - "[Ul'dah] Gate of the Sultana (Western Thanalan)", - "[Ul'dah] Gate of Nald (Central Thanalan)", - "[Ul'dah] Gate of Thal (Central Thanalan)", - "[Ul'dah] The Chamber of Rule", - "[Ul'dah] Airship Landing", - "[Limsa Lominsa] Aetheryte Plaza", - "[Limsa Lominsa] Arcanists' Guild", - "[Limsa Lominsa] Fishermens' Guild", - "[Limsa Lominsa] Hawkers' Alley", - "[Limsa Lominsa] The Aftcastle", - "[Limsa Lominsa] Culinarians' Guild", - "[Limsa Lominsa] Marauders' Guild", - "[Limsa Lominsa] Zephyr Gate (Middle La Noscea)", - "[Limsa Lominsa] Tempest Gate (Lower La Noscea)", - "[Limsa Lominsa] Airship Landing", - "[Ishgard] Aetheryte Plaza", - "[Ishgard] The Forgotten Knight", - "[Ishgard] Skysteel Manufactory", - "[Ishgard] The Brume", - "[Ishgard] Athenaeum Astrologicum", - "[Ishgard] The Jeweled Crozier", - "[Ishgard] Saint Reymanaud's Cathedral", - "[Ishgard] The Tribunal", - "[Ishgard] The Last Vigil", - "[Ishgard] The Gates of Judgement (Coerthas Central Highlands)", - "[Idyllshire] Aetheryte Plaza", - "[Idyllshire] West Idyllshire", - "[Idyllshire] Prologue Gate (Western Hinterlands)", - "[Idyllshire] Epilogue Gate (Eastern Hinterlands)", - "[Rhalgr's Reach] Aetheryte Plaza", - "[Rhalgr's Reach] Western Rhalgr's Reach", - "[Rhalgr's Reach] Northeastern Rhalgr's Reach", - "[Rhalgr's Reach] Fringes Gate", - "[Rhalgr's Reach] Peaks Gate", - "[Kugane] Aetheryte Plaza", - "[Kugane] Shiokaze Hostelry", - "[Kugane] Pier #1", - "[Kugane] Thavnairian Consulate", - "[Kugane] Kogane Dori Markets", - "[Kugane] Bokairo Inn", - "[Kugane] The Ruby Bazaar", - "[Kugane] Sekiseigumi Barracks", - "[Kugane] Rakuza District", - "[Kugane] The Ruby Price", - "[Kugane] Airship Landing", - "[Crystarium] Aetheryte Plaza", - "[Crystarium] Musica Universalis Markets", - "[Crystarium] Temenos Rookery", - "[Crystarium] The Dossal Gate", - "[Crystarium] The Pendants", - "[Crystarium] The Amaro Launch", - "[Crystarium] The Crystalline Mean", - "[Crystarium] The Cabinet of Curiosity", - "[Crystarium] Tessellation (Lakeland)", - "[Eulmore] Aetheryte Plaza", - "[Eulmore] Southeast Derelicts", - "[Eulmore] Nightsoil Pots", - "[Eulmore] The Glory Gate", - "[Eulmore] The Mainstay", - "[Eulmore] The Path to Glory (Kholusia)", - "[Old Sharlayan] Aetheryte Plaza", - "[Old Sharlayan] The Studium", - "[Old Sharlayan] The Baldesion Annex", - "[Old Sharlayan] The Rostra", - "[Old Sharlayan] The Leveilleur Estate", - "[Old Sharlayan] Journey's End", - "[Old Sharlayan] Scholar's Harbor", - "[Old Sharlayan] The Hall of Artifice (Labyrinthos)", - "[Radz-at-Han] Aetheryte Plaza", - "[Radz-at-Han] Meghaduta", - "[Radz-at-Han] Ruveydah Fibers", - "[Radz-at-Han] Airship Landing", - "[Radz-at-Han] Alzadaal's Peace", - "[Radz-at-Han] Hall of the Radiant Host", - "[Radz-at-Han] Mehryde's Meyhane", - "[Radz-at-Han] Kama", - "[Radz-at-Han] The High Crucible of Al-Kimiya", - "[Radz-at-Han] The Gate of First Sight (Thavnair)", - "[Tuliyollal] Aetheryte Plaza", - "[Tuliyollal] Dirigible Landing", - "[Tuliyollal] The Resplendent Quarter", - "[Tuliyollal] The For'ard Cabins", - "[Tuliyollal] Bayside Bevy Marketplace", - "[Tuliyollal] Vollok Shoonsa", - "[Tuliyollal] Wachumeqimeqi", - "[Tuliyollal] Brightploom Post", - "[Tuliyollal] Arch of the Dawn (Urqopacha)", - "[Tuliyollal] Arch of the Dawn (Kozama'uka)", - "[Tuliyollal] Ihuykatumu (Kozama'uka)", - "[Tuliyollal] Dirigible Landing (Yak T'el)", - "[Tuliyollal] Xak Tural Skygate (Shaaloani)", - "[Solution Nine] Aetheryte Plaza", - "[Solution Nine] Information Center", - "[Solution Nine] True Vue", - "[Solution Nine] Neon Stein", - "[Solution Nine] The Arcadion", - "[Solution Nine] Resolution", - "[Solution Nine] Nexus Arcade", - "[Solution Nine] Residential Sector", - "[Solution Nine] Scanning Port Nine (Heritage Found)" - ] - }, - "CompletionFlags": { - "type": "array", - "description": "Quest Variables that dictate whether or not this step is skipped: null is don't check, positive values need to be set, negative values need to be unset", - "items": { - "oneOf": [ - { - "type": "object", - "properties": { - "High": { - "type": [ - "number", - "null" - ], - "minimum": 0, - "maximum": 15 - }, - "Low": { - "type": [ - "number", - "null" - ], - "minimum": 0, - "maximum": 15 - }, - "Negative": { - "type": "boolean" - }, - "Mode": { - "type": "string", - "enum": [ - "Bitwise", - "Exact" - ] - } - } - }, - { - "type": "number", - "enum": [ - 1, - 2, - 4, - 8, - 16, - 32, - 64, - 128 - ] - }, - { - "type": "null" - } - ] - }, - "minItems": 6, - "maxItems": 6 - } - } + "additionalProperties": false } diff --git a/Questionable.Model/AssemblyModelLoader.cs b/Questionable.Model/AssemblyModelLoader.cs new file mode 100644 index 00000000..d167cb25 --- /dev/null +++ b/Questionable.Model/AssemblyModelLoader.cs @@ -0,0 +1,9 @@ +using System.IO; + +namespace Questionable.Model; + +public static class AssemblyModelLoader +{ + public static Stream CommonSchema => + typeof(AssemblyModelLoader).Assembly.GetManifestResourceStream("Questionable.Model.CommonSchema")!; +} diff --git a/Questionable.Model/V1/Converter/AetheryteConverter.cs b/Questionable.Model/Common/Converter/AetheryteConverter.cs similarity index 98% rename from Questionable.Model/V1/Converter/AetheryteConverter.cs rename to Questionable.Model/Common/Converter/AetheryteConverter.cs index ab0dd549..3887305e 100644 --- a/Questionable.Model/V1/Converter/AetheryteConverter.cs +++ b/Questionable.Model/Common/Converter/AetheryteConverter.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; +using Questionable.Model.Common.Converter; -namespace Questionable.Model.V1.Converter; +namespace Questionable.Model.Common.Converter; public sealed class AetheryteConverter() : EnumConverter(Values) { diff --git a/Questionable.Model/V1/Converter/EnumConverter.cs b/Questionable.Model/Common/Converter/EnumConverter.cs similarity index 96% rename from Questionable.Model/V1/Converter/EnumConverter.cs rename to Questionable.Model/Common/Converter/EnumConverter.cs index 3ed1267b..3708e28c 100644 --- a/Questionable.Model/V1/Converter/EnumConverter.cs +++ b/Questionable.Model/Common/Converter/EnumConverter.cs @@ -5,7 +5,7 @@ using System.Linq; using System.Text.Json; using System.Text.Json.Serialization; -namespace Questionable.Model.V1.Converter; +namespace Questionable.Model.Common.Converter; public abstract class EnumConverter : JsonConverter where T : Enum diff --git a/Questionable.Model/V1/Converter/StringListOrValueConverter.cs b/Questionable.Model/Common/Converter/StringListOrValueConverter.cs similarity index 96% rename from Questionable.Model/V1/Converter/StringListOrValueConverter.cs rename to Questionable.Model/Common/Converter/StringListOrValueConverter.cs index b6da81a2..ebdec1cf 100644 --- a/Questionable.Model/V1/Converter/StringListOrValueConverter.cs +++ b/Questionable.Model/Common/Converter/StringListOrValueConverter.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.Text.Json; using System.Text.Json.Serialization; -namespace Questionable.Model.V1.Converter; +namespace Questionable.Model.Common.Converter; public sealed class StringListOrValueConverter : JsonConverter> { diff --git a/Questionable.Model/V1/Converter/VectorConverter.cs b/Questionable.Model/Common/Converter/VectorConverter.cs similarity index 97% rename from Questionable.Model/V1/Converter/VectorConverter.cs rename to Questionable.Model/Common/Converter/VectorConverter.cs index f75ffe6a..7b4833ef 100644 --- a/Questionable.Model/V1/Converter/VectorConverter.cs +++ b/Questionable.Model/Common/Converter/VectorConverter.cs @@ -3,7 +3,7 @@ using System.Numerics; using System.Text.Json; using System.Text.Json.Serialization; -namespace Questionable.Model.V1.Converter; +namespace Questionable.Model.Common.Converter; public sealed class VectorConverter : JsonConverter { diff --git a/Questionable.Model/V1/EAetheryteLocation.cs b/Questionable.Model/Common/EAetheryteLocation.cs similarity index 98% rename from Questionable.Model/V1/EAetheryteLocation.cs rename to Questionable.Model/Common/EAetheryteLocation.cs index 1ddde305..a00f7b51 100644 --- a/Questionable.Model/V1/EAetheryteLocation.cs +++ b/Questionable.Model/Common/EAetheryteLocation.cs @@ -1,7 +1,8 @@ using System.Text.Json.Serialization; -using Questionable.Model.V1.Converter; +using Questionable.Model.Common.Converter; +using Questionable.Model.Questing.Converter; -namespace Questionable.Model.V1; +namespace Questionable.Model.Common; [JsonConverter(typeof(AetheryteConverter))] public enum EAetheryteLocation diff --git a/Questionable.Model/Gathering/GatheringNodeLocation.cs b/Questionable.Model/Gathering/GatheringNodeLocation.cs new file mode 100644 index 00000000..49a5e640 --- /dev/null +++ b/Questionable.Model/Gathering/GatheringNodeLocation.cs @@ -0,0 +1,13 @@ +using System.Numerics; + +namespace Questionable.Model.Gathering; + +public sealed class GatheringNodeLocation +{ + public uint DataId { get; set; } + public Vector3 Position { get; set; } + public float? MinimumAngle { get; set; } + public float? MaximumAngle { get; set; } + public float? MinimumDistance { get; set; } = 0.5f; + public float? MaximumDistance { get; set; } = 3f; +} diff --git a/Questionable.Model/Gathering/GatheringRoot.cs b/Questionable.Model/Gathering/GatheringRoot.cs new file mode 100644 index 00000000..c572faab --- /dev/null +++ b/Questionable.Model/Gathering/GatheringRoot.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; +using System.Text.Json.Serialization; +using Questionable.Model.Common; +using Questionable.Model.Common.Converter; + +namespace Questionable.Model.Gathering; + +public sealed class GatheringRoot +{ + [JsonConverter(typeof(StringListOrValueConverter))] + public List Author { get; set; } = []; + public ushort TerritoryId { get; set; } + + [JsonConverter(typeof(AetheryteConverter))] + public EAetheryteLocation? AetheryteShortcut { get; set; } + + public List Nodes { get; set; } = []; +} diff --git a/Questionable.Model/V1/AethernetShortcut.cs b/Questionable.Model/Questing/AethernetShortcut.cs similarity index 66% rename from Questionable.Model/V1/AethernetShortcut.cs rename to Questionable.Model/Questing/AethernetShortcut.cs index 40514b58..3d046c44 100644 --- a/Questionable.Model/V1/AethernetShortcut.cs +++ b/Questionable.Model/Questing/AethernetShortcut.cs @@ -1,7 +1,8 @@ using System.Text.Json.Serialization; -using Questionable.Model.V1.Converter; +using Questionable.Model.Common; +using Questionable.Model.Questing.Converter; -namespace Questionable.Model.V1; +namespace Questionable.Model.Questing; [JsonConverter(typeof(AethernetShortcutConverter))] public sealed class AethernetShortcut diff --git a/Questionable.Model/V1/ChatMessage.cs b/Questionable.Model/Questing/ChatMessage.cs similarity index 75% rename from Questionable.Model/V1/ChatMessage.cs rename to Questionable.Model/Questing/ChatMessage.cs index 71721380..b0272135 100644 --- a/Questionable.Model/V1/ChatMessage.cs +++ b/Questionable.Model/Questing/ChatMessage.cs @@ -1,4 +1,4 @@ -namespace Questionable.Model.V1; +namespace Questionable.Model.Questing; public sealed class ChatMessage { diff --git a/Questionable.Model/V1/ComplexCombatData.cs b/Questionable.Model/Questing/ComplexCombatData.cs similarity index 93% rename from Questionable.Model/V1/ComplexCombatData.cs rename to Questionable.Model/Questing/ComplexCombatData.cs index d31de7e2..5f85c243 100644 --- a/Questionable.Model/V1/ComplexCombatData.cs +++ b/Questionable.Model/Questing/ComplexCombatData.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; -namespace Questionable.Model.V1; +namespace Questionable.Model.Questing; public sealed class ComplexCombatData { diff --git a/Questionable.Model/V1/Converter/ActionConverter.cs b/Questionable.Model/Questing/Converter/ActionConverter.cs similarity index 86% rename from Questionable.Model/V1/Converter/ActionConverter.cs rename to Questionable.Model/Questing/Converter/ActionConverter.cs index eaf5baac..7e62c011 100644 --- a/Questionable.Model/V1/Converter/ActionConverter.cs +++ b/Questionable.Model/Questing/Converter/ActionConverter.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; +using Questionable.Model.Common.Converter; -namespace Questionable.Model.V1.Converter; +namespace Questionable.Model.Questing.Converter; public sealed class ActionConverter() : EnumConverter(Values) { diff --git a/Questionable.Model/V1/Converter/AethernetShardConverter.cs b/Questionable.Model/Questing/Converter/AethernetShardConverter.cs similarity index 98% rename from Questionable.Model/V1/Converter/AethernetShardConverter.cs rename to Questionable.Model/Questing/Converter/AethernetShardConverter.cs index bfb259c2..bd07bc39 100644 --- a/Questionable.Model/V1/Converter/AethernetShardConverter.cs +++ b/Questionable.Model/Questing/Converter/AethernetShardConverter.cs @@ -1,6 +1,8 @@ using System.Collections.Generic; +using Questionable.Model.Common; +using Questionable.Model.Common.Converter; -namespace Questionable.Model.V1.Converter; +namespace Questionable.Model.Questing.Converter; public sealed class AethernetShardConverter() : EnumConverter(Values) { diff --git a/Questionable.Model/V1/Converter/AethernetShortcutConverter.cs b/Questionable.Model/Questing/Converter/AethernetShortcutConverter.cs similarity index 95% rename from Questionable.Model/V1/Converter/AethernetShortcutConverter.cs rename to Questionable.Model/Questing/Converter/AethernetShortcutConverter.cs index 8b90769f..d920d882 100644 --- a/Questionable.Model/V1/Converter/AethernetShortcutConverter.cs +++ b/Questionable.Model/Questing/Converter/AethernetShortcutConverter.cs @@ -3,8 +3,9 @@ using System.Collections.Generic; using System.Linq; using System.Text.Json; using System.Text.Json.Serialization; +using Questionable.Model.Common; -namespace Questionable.Model.V1.Converter; +namespace Questionable.Model.Questing.Converter; public sealed class AethernetShortcutConverter : JsonConverter { diff --git a/Questionable.Model/V1/Converter/DialogueChoiceTypeConverter.cs b/Questionable.Model/Questing/Converter/DialogueChoiceTypeConverter.cs similarity index 77% rename from Questionable.Model/V1/Converter/DialogueChoiceTypeConverter.cs rename to Questionable.Model/Questing/Converter/DialogueChoiceTypeConverter.cs index ea832cac..cd66ca9b 100644 --- a/Questionable.Model/V1/Converter/DialogueChoiceTypeConverter.cs +++ b/Questionable.Model/Questing/Converter/DialogueChoiceTypeConverter.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; +using Questionable.Model.Common.Converter; -namespace Questionable.Model.V1.Converter; +namespace Questionable.Model.Questing.Converter; public sealed class DialogueChoiceTypeConverter() : EnumConverter(Values) { diff --git a/Questionable.Model/V1/Converter/EmoteConverter.cs b/Questionable.Model/Questing/Converter/EmoteConverter.cs similarity index 91% rename from Questionable.Model/V1/Converter/EmoteConverter.cs rename to Questionable.Model/Questing/Converter/EmoteConverter.cs index 8a327517..20c97694 100644 --- a/Questionable.Model/V1/Converter/EmoteConverter.cs +++ b/Questionable.Model/Questing/Converter/EmoteConverter.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; +using Questionable.Model.Common.Converter; -namespace Questionable.Model.V1.Converter; +namespace Questionable.Model.Questing.Converter; public sealed class EmoteConverter() : EnumConverter(Values) { diff --git a/Questionable.Model/V1/Converter/EnemySpawnTypeConverter.cs b/Questionable.Model/Questing/Converter/EnemySpawnTypeConverter.cs similarity index 83% rename from Questionable.Model/V1/Converter/EnemySpawnTypeConverter.cs rename to Questionable.Model/Questing/Converter/EnemySpawnTypeConverter.cs index 5c5de532..e97faa4f 100644 --- a/Questionable.Model/V1/Converter/EnemySpawnTypeConverter.cs +++ b/Questionable.Model/Questing/Converter/EnemySpawnTypeConverter.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; +using Questionable.Model.Common.Converter; -namespace Questionable.Model.V1.Converter; +namespace Questionable.Model.Questing.Converter; public sealed class EnemySpawnTypeConverter() : EnumConverter(Values) { diff --git a/Questionable.Model/V1/Converter/ExcelRefConverter.cs b/Questionable.Model/Questing/Converter/ExcelRefConverter.cs similarity index 95% rename from Questionable.Model/V1/Converter/ExcelRefConverter.cs rename to Questionable.Model/Questing/Converter/ExcelRefConverter.cs index 06ba3ff1..03a8168e 100644 --- a/Questionable.Model/V1/Converter/ExcelRefConverter.cs +++ b/Questionable.Model/Questing/Converter/ExcelRefConverter.cs @@ -2,7 +2,7 @@ using System.Text.Json; using System.Text.Json.Serialization; -namespace Questionable.Model.V1.Converter; +namespace Questionable.Model.Questing.Converter; public sealed class ExcelRefConverter : JsonConverter { diff --git a/Questionable.Model/V1/Converter/InteractionTypeConverter.cs b/Questionable.Model/Questing/Converter/InteractionTypeConverter.cs similarity index 93% rename from Questionable.Model/V1/Converter/InteractionTypeConverter.cs rename to Questionable.Model/Questing/Converter/InteractionTypeConverter.cs index 08be6ff6..23f0366e 100644 --- a/Questionable.Model/V1/Converter/InteractionTypeConverter.cs +++ b/Questionable.Model/Questing/Converter/InteractionTypeConverter.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; +using Questionable.Model.Common.Converter; -namespace Questionable.Model.V1.Converter; +namespace Questionable.Model.Questing.Converter; public sealed class InteractionTypeConverter() : EnumConverter(Values) { diff --git a/Questionable.Model/V1/Converter/JumpTypeConverter.cs b/Questionable.Model/Questing/Converter/JumpTypeConverter.cs similarity index 76% rename from Questionable.Model/V1/Converter/JumpTypeConverter.cs rename to Questionable.Model/Questing/Converter/JumpTypeConverter.cs index 94c8ea2b..95bb0846 100644 --- a/Questionable.Model/V1/Converter/JumpTypeConverter.cs +++ b/Questionable.Model/Questing/Converter/JumpTypeConverter.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; +using Questionable.Model.Common.Converter; -namespace Questionable.Model.V1.Converter; +namespace Questionable.Model.Questing.Converter; public sealed class JumpTypeConverter() : EnumConverter(Values) { diff --git a/Questionable.Model/V1/Converter/LockedSkipConditionConverter.cs b/Questionable.Model/Questing/Converter/LockedSkipConditionConverter.cs similarity index 78% rename from Questionable.Model/V1/Converter/LockedSkipConditionConverter.cs rename to Questionable.Model/Questing/Converter/LockedSkipConditionConverter.cs index 5d53058e..72eb9dec 100644 --- a/Questionable.Model/V1/Converter/LockedSkipConditionConverter.cs +++ b/Questionable.Model/Questing/Converter/LockedSkipConditionConverter.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; +using Questionable.Model.Common.Converter; -namespace Questionable.Model.V1.Converter; +namespace Questionable.Model.Questing.Converter; public sealed class LockedSkipConditionConverter() : EnumConverter(Values) { diff --git a/Questionable.Model/V1/Converter/QuestWorkConfigConverter.cs b/Questionable.Model/Questing/Converter/QuestWorkConfigConverter.cs similarity index 97% rename from Questionable.Model/V1/Converter/QuestWorkConfigConverter.cs rename to Questionable.Model/Questing/Converter/QuestWorkConfigConverter.cs index 2b376937..b6cccc46 100644 --- a/Questionable.Model/V1/Converter/QuestWorkConfigConverter.cs +++ b/Questionable.Model/Questing/Converter/QuestWorkConfigConverter.cs @@ -2,7 +2,7 @@ using System.Text.Json; using System.Text.Json.Serialization; -namespace Questionable.Model.V1.Converter; +namespace Questionable.Model.Questing.Converter; public sealed class QuestWorkConfigConverter : JsonConverter { diff --git a/Questionable.Model/V1/Converter/QuestWorkModeConverter.cs b/Questionable.Model/Questing/Converter/QuestWorkModeConverter.cs similarity index 77% rename from Questionable.Model/V1/Converter/QuestWorkModeConverter.cs rename to Questionable.Model/Questing/Converter/QuestWorkModeConverter.cs index a3697d66..322d6a19 100644 --- a/Questionable.Model/V1/Converter/QuestWorkModeConverter.cs +++ b/Questionable.Model/Questing/Converter/QuestWorkModeConverter.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; +using Questionable.Model.Common.Converter; -namespace Questionable.Model.V1.Converter; +namespace Questionable.Model.Questing.Converter; public sealed class QuestWorkModeConverter() : EnumConverter(Values) { diff --git a/Questionable.Model/V1/Converter/SkipConditionConverter.cs b/Questionable.Model/Questing/Converter/SkipConditionConverter.cs similarity index 76% rename from Questionable.Model/V1/Converter/SkipConditionConverter.cs rename to Questionable.Model/Questing/Converter/SkipConditionConverter.cs index f4b4e6fc..eadd84b1 100644 --- a/Questionable.Model/V1/Converter/SkipConditionConverter.cs +++ b/Questionable.Model/Questing/Converter/SkipConditionConverter.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; +using Questionable.Model.Common.Converter; -namespace Questionable.Model.V1.Converter; +namespace Questionable.Model.Questing.Converter; public sealed class SkipConditionConverter() : EnumConverter(Values) { diff --git a/Questionable.Model/V1/DialogueChoice.cs b/Questionable.Model/Questing/DialogueChoice.cs similarity index 87% rename from Questionable.Model/V1/DialogueChoice.cs rename to Questionable.Model/Questing/DialogueChoice.cs index 80b49d05..91370f5d 100644 --- a/Questionable.Model/V1/DialogueChoice.cs +++ b/Questionable.Model/Questing/DialogueChoice.cs @@ -1,7 +1,7 @@ using System.Text.Json.Serialization; -using Questionable.Model.V1.Converter; +using Questionable.Model.Questing.Converter; -namespace Questionable.Model.V1; +namespace Questionable.Model.Questing; public sealed class DialogueChoice { diff --git a/Questionable.Model/V1/EAction.cs b/Questionable.Model/Questing/EAction.cs similarity index 88% rename from Questionable.Model/V1/EAction.cs rename to Questionable.Model/Questing/EAction.cs index 8aca752f..4b24dee1 100644 --- a/Questionable.Model/V1/EAction.cs +++ b/Questionable.Model/Questing/EAction.cs @@ -1,7 +1,7 @@ using System.Text.Json.Serialization; -using Questionable.Model.V1.Converter; +using Questionable.Model.Questing.Converter; -namespace Questionable.Model.V1; +namespace Questionable.Model.Questing; [JsonConverter(typeof(ActionConverter))] public enum EAction diff --git a/Questionable.Model/V1/EDialogChoiceType.cs b/Questionable.Model/Questing/EDialogChoiceType.cs similarity index 61% rename from Questionable.Model/V1/EDialogChoiceType.cs rename to Questionable.Model/Questing/EDialogChoiceType.cs index 066639a3..9b537471 100644 --- a/Questionable.Model/V1/EDialogChoiceType.cs +++ b/Questionable.Model/Questing/EDialogChoiceType.cs @@ -1,4 +1,4 @@ -namespace Questionable.Model.V1; +namespace Questionable.Model.Questing; public enum EDialogChoiceType { diff --git a/Questionable.Model/V1/EEmote.cs b/Questionable.Model/Questing/EEmote.cs similarity index 85% rename from Questionable.Model/V1/EEmote.cs rename to Questionable.Model/Questing/EEmote.cs index 6657a1dd..022930e9 100644 --- a/Questionable.Model/V1/EEmote.cs +++ b/Questionable.Model/Questing/EEmote.cs @@ -1,7 +1,7 @@ using System.Text.Json.Serialization; -using Questionable.Model.V1.Converter; +using Questionable.Model.Questing.Converter; -namespace Questionable.Model.V1; +namespace Questionable.Model.Questing; [JsonConverter(typeof(EmoteConverter))] public enum EEmote diff --git a/Questionable.Model/V1/EEnemySpawnType.cs b/Questionable.Model/Questing/EEnemySpawnType.cs similarity index 72% rename from Questionable.Model/V1/EEnemySpawnType.cs rename to Questionable.Model/Questing/EEnemySpawnType.cs index 8465f011..3c42b9f4 100644 --- a/Questionable.Model/V1/EEnemySpawnType.cs +++ b/Questionable.Model/Questing/EEnemySpawnType.cs @@ -1,7 +1,7 @@ using System.Text.Json.Serialization; -using Questionable.Model.V1.Converter; +using Questionable.Model.Questing.Converter; -namespace Questionable.Model.V1; +namespace Questionable.Model.Questing; [JsonConverter(typeof(EnemySpawnTypeConverter))] public enum EEnemySpawnType diff --git a/Questionable.Model/V1/EExtraSkipCondition.cs b/Questionable.Model/Questing/EExtraSkipCondition.cs similarity index 65% rename from Questionable.Model/V1/EExtraSkipCondition.cs rename to Questionable.Model/Questing/EExtraSkipCondition.cs index 227bf0f2..3f2836a9 100644 --- a/Questionable.Model/V1/EExtraSkipCondition.cs +++ b/Questionable.Model/Questing/EExtraSkipCondition.cs @@ -1,7 +1,7 @@ using System.Text.Json.Serialization; -using Questionable.Model.V1.Converter; +using Questionable.Model.Questing.Converter; -namespace Questionable.Model.V1; +namespace Questionable.Model.Questing; [JsonConverter(typeof(SkipConditionConverter))] public enum EExtraSkipCondition diff --git a/Questionable.Model/V1/EInteractionType.cs b/Questionable.Model/Questing/EInteractionType.cs similarity index 86% rename from Questionable.Model/V1/EInteractionType.cs rename to Questionable.Model/Questing/EInteractionType.cs index 843f600d..5080714a 100644 --- a/Questionable.Model/V1/EInteractionType.cs +++ b/Questionable.Model/Questing/EInteractionType.cs @@ -1,7 +1,7 @@ using System.Text.Json.Serialization; -using Questionable.Model.V1.Converter; +using Questionable.Model.Questing.Converter; -namespace Questionable.Model.V1; +namespace Questionable.Model.Questing; [JsonConverter(typeof(InteractionTypeConverter))] public enum EInteractionType diff --git a/Questionable.Model/V1/EJumpType.cs b/Questionable.Model/Questing/EJumpType.cs similarity index 63% rename from Questionable.Model/V1/EJumpType.cs rename to Questionable.Model/Questing/EJumpType.cs index b06365eb..e89931ac 100644 --- a/Questionable.Model/V1/EJumpType.cs +++ b/Questionable.Model/Questing/EJumpType.cs @@ -1,7 +1,7 @@ using System.Text.Json.Serialization; -using Questionable.Model.V1.Converter; +using Questionable.Model.Questing.Converter; -namespace Questionable.Model.V1; +namespace Questionable.Model.Questing; [JsonConverter(typeof(JumpTypeConverter))] public enum EJumpType diff --git a/Questionable.Model/V1/ELockedSkipCondition.cs b/Questionable.Model/Questing/ELockedSkipCondition.cs similarity index 65% rename from Questionable.Model/V1/ELockedSkipCondition.cs rename to Questionable.Model/Questing/ELockedSkipCondition.cs index 2863c262..7755b129 100644 --- a/Questionable.Model/V1/ELockedSkipCondition.cs +++ b/Questionable.Model/Questing/ELockedSkipCondition.cs @@ -1,7 +1,7 @@ using System.Text.Json.Serialization; -using Questionable.Model.V1.Converter; +using Questionable.Model.Questing.Converter; -namespace Questionable.Model.V1; +namespace Questionable.Model.Questing; [JsonConverter(typeof(LockedSkipConditionConverter))] public enum ELockedSkipCondition diff --git a/Questionable.Model/V1/EQuestWorkMode.cs b/Questionable.Model/Questing/EQuestWorkMode.cs similarity index 63% rename from Questionable.Model/V1/EQuestWorkMode.cs rename to Questionable.Model/Questing/EQuestWorkMode.cs index ef225b23..3d835225 100644 --- a/Questionable.Model/V1/EQuestWorkMode.cs +++ b/Questionable.Model/Questing/EQuestWorkMode.cs @@ -1,7 +1,7 @@ using System.Text.Json.Serialization; -using Questionable.Model.V1.Converter; +using Questionable.Model.Questing.Converter; -namespace Questionable.Model.V1; +namespace Questionable.Model.Questing; [JsonConverter(typeof(QuestWorkModeConverter))] public enum EQuestWorkMode diff --git a/Questionable.Model/V1/ExcelRef.cs b/Questionable.Model/Questing/ExcelRef.cs similarity index 97% rename from Questionable.Model/V1/ExcelRef.cs rename to Questionable.Model/Questing/ExcelRef.cs index 295dd5ba..cdb55014 100644 --- a/Questionable.Model/V1/ExcelRef.cs +++ b/Questionable.Model/Questing/ExcelRef.cs @@ -1,6 +1,6 @@ using System; -namespace Questionable.Model.V1; +namespace Questionable.Model.Questing; public class ExcelRef { diff --git a/Questionable.Model/V1/JumpDestination.cs b/Questionable.Model/Questing/JumpDestination.cs similarity index 76% rename from Questionable.Model/V1/JumpDestination.cs rename to Questionable.Model/Questing/JumpDestination.cs index 2497560a..9682e21e 100644 --- a/Questionable.Model/V1/JumpDestination.cs +++ b/Questionable.Model/Questing/JumpDestination.cs @@ -1,8 +1,9 @@ using System.Numerics; using System.Text.Json.Serialization; -using Questionable.Model.V1.Converter; +using Questionable.Model.Common.Converter; +using Questionable.Model.Questing.Converter; -namespace Questionable.Model.V1; +namespace Questionable.Model.Questing; public sealed class JumpDestination { diff --git a/Questionable.Model/V1/QuestRoot.cs b/Questionable.Model/Questing/QuestRoot.cs similarity index 80% rename from Questionable.Model/V1/QuestRoot.cs rename to Questionable.Model/Questing/QuestRoot.cs index ada2e9fd..e1158fc8 100644 --- a/Questionable.Model/V1/QuestRoot.cs +++ b/Questionable.Model/Questing/QuestRoot.cs @@ -1,8 +1,9 @@ using System.Collections.Generic; using System.Text.Json.Serialization; -using Questionable.Model.V1.Converter; +using Questionable.Model.Common.Converter; +using Questionable.Model.Questing.Converter; -namespace Questionable.Model.V1; +namespace Questionable.Model.Questing; public sealed class QuestRoot { diff --git a/Questionable.Model/V1/QuestSequence.cs b/Questionable.Model/Questing/QuestSequence.cs similarity index 91% rename from Questionable.Model/V1/QuestSequence.cs rename to Questionable.Model/Questing/QuestSequence.cs index 73807e0b..3e42e098 100644 --- a/Questionable.Model/V1/QuestSequence.cs +++ b/Questionable.Model/Questing/QuestSequence.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using System.Linq; -namespace Questionable.Model.V1; +namespace Questionable.Model.Questing; public sealed class QuestSequence { diff --git a/Questionable.Model/V1/QuestStep.cs b/Questionable.Model/Questing/QuestStep.cs similarity index 95% rename from Questionable.Model/V1/QuestStep.cs rename to Questionable.Model/Questing/QuestStep.cs index accd6623..53ed7ced 100644 --- a/Questionable.Model/V1/QuestStep.cs +++ b/Questionable.Model/Questing/QuestStep.cs @@ -1,9 +1,11 @@ using System.Collections.Generic; using System.Numerics; using System.Text.Json.Serialization; -using Questionable.Model.V1.Converter; +using Questionable.Model.Common; +using Questionable.Model.Common.Converter; +using Questionable.Model.Questing.Converter; -namespace Questionable.Model.V1; +namespace Questionable.Model.Questing; public sealed class QuestStep { diff --git a/Questionable.Model/V1/QuestWorkValue.cs b/Questionable.Model/Questing/QuestWorkValue.cs similarity index 90% rename from Questionable.Model/V1/QuestWorkValue.cs rename to Questionable.Model/Questing/QuestWorkValue.cs index 75c68511..d4db77ef 100644 --- a/Questionable.Model/V1/QuestWorkValue.cs +++ b/Questionable.Model/Questing/QuestWorkValue.cs @@ -1,8 +1,8 @@ using System; using System.Text.Json.Serialization; -using Questionable.Model.V1.Converter; +using Questionable.Model.Questing.Converter; -namespace Questionable.Model.V1; +namespace Questionable.Model.Questing; [JsonConverter(typeof(QuestWorkConfigConverter))] public sealed class QuestWorkValue(byte? high, byte? low, EQuestWorkMode mode) diff --git a/Questionable.Model/V1/SkipAetheryteCondition.cs b/Questionable.Model/Questing/SkipAetheryteCondition.cs similarity index 75% rename from Questionable.Model/V1/SkipAetheryteCondition.cs rename to Questionable.Model/Questing/SkipAetheryteCondition.cs index 86d0a1c6..0109e4de 100644 --- a/Questionable.Model/V1/SkipAetheryteCondition.cs +++ b/Questionable.Model/Questing/SkipAetheryteCondition.cs @@ -1,4 +1,4 @@ -namespace Questionable.Model.V1; +namespace Questionable.Model.Questing; public sealed class SkipAetheryteCondition { diff --git a/Questionable.Model/V1/SkipConditions.cs b/Questionable.Model/Questing/SkipConditions.cs similarity index 84% rename from Questionable.Model/V1/SkipConditions.cs rename to Questionable.Model/Questing/SkipConditions.cs index 5f866865..6525ec0f 100644 --- a/Questionable.Model/V1/SkipConditions.cs +++ b/Questionable.Model/Questing/SkipConditions.cs @@ -1,4 +1,4 @@ -namespace Questionable.Model.V1; +namespace Questionable.Model.Questing; public sealed class SkipConditions { diff --git a/Questionable.Model/V1/SkipItemConditions.cs b/Questionable.Model/Questing/SkipItemConditions.cs similarity index 67% rename from Questionable.Model/V1/SkipItemConditions.cs rename to Questionable.Model/Questing/SkipItemConditions.cs index 9154dcd4..04c38f6e 100644 --- a/Questionable.Model/V1/SkipItemConditions.cs +++ b/Questionable.Model/Questing/SkipItemConditions.cs @@ -1,4 +1,4 @@ -namespace Questionable.Model.V1; +namespace Questionable.Model.Questing; public sealed class SkipItemConditions { diff --git a/Questionable.Model/V1/SkipStepConditions.cs b/Questionable.Model/Questing/SkipStepConditions.cs similarity index 97% rename from Questionable.Model/V1/SkipStepConditions.cs rename to Questionable.Model/Questing/SkipStepConditions.cs index be8df96b..ee7e7dcf 100644 --- a/Questionable.Model/V1/SkipStepConditions.cs +++ b/Questionable.Model/Questing/SkipStepConditions.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using System.Linq; -namespace Questionable.Model.V1; +namespace Questionable.Model.Questing; public sealed class SkipStepConditions { diff --git a/Questionable.Model/Questionable.Model.csproj b/Questionable.Model/Questionable.Model.csproj index cb320ec5..54301430 100644 --- a/Questionable.Model/Questionable.Model.csproj +++ b/Questionable.Model/Questionable.Model.csproj @@ -13,4 +13,12 @@ + + + + + + Questionable.Model.CommonSchema + + diff --git a/Questionable.Model/common-schema.json b/Questionable.Model/common-schema.json new file mode 100644 index 00000000..6017ecb7 --- /dev/null +++ b/Questionable.Model/common-schema.json @@ -0,0 +1,299 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://git.carvel.li/liza/Questionable/raw/branch/master/Questionable.Model/common-schema.json", + "$defs": { + "Aetheryte": { + "type": "string", + "enum": [ + "Gridania", + "Central Shroud - Bentbranch Meadows", + "East Shroud - Hawthorne Hut", + "South Shroud - Quarrymill", + "South Shroud - Camp Tranquil", + "North Shroud - Fallgourd Float", + "Ul'dah", + "Western Thanalan - Horizon", + "Central Thanalan - Black Brush Station", + "Eastern Thanalan - Camp Drybone", + "Southern Thanalan - Little Ala Mhigo", + "Southern Thanalan - Forgotten Springs", + "Northern Thanalan - Camp Bluefog", + "Northern Thanalan - Ceruleum Processing Plant", + "Limsa Lominsa", + "Middle La Noscea - Summerford Farms", + "Lower La Noscea - Moraby Drydocks", + "Eastern La Noscea - Costa Del Sol", + "Eastern La Noscea - Wineport", + "Western La Noscea - Swiftperch", + "Western La Noscea - Aleport", + "Upper La Noscea - Camp Bronze Lake", + "Outer La Noscea - Camp Overlook", + "Coerthas Central Highlands - Camp Dragonhead", + "Mor Dhona", + "Gold Saucer", + "Wolves' Den Pier", + "Ishgard", + "Idyllshire", + "Coerthas Western Highlands - Falcon's Nest", + "The Sea of Clouds - Camp Cloudtop", + "The Sea of Clouds - Ok' Zundu", + "Azys Lla - Helix", + "The Dravanian Forelands - Tailfeather", + "The Dravanian Forelands - Anyx Trine", + "The Churning Mists - Moghome", + "The Churning Mists - Zenith", + "Rhalgr's Reach", + "Fringes - Castrum Oriens", + "Fringes - Peering Stones", + "Peaks - Ala Gannha", + "Peaks - Ala Ghiri", + "Lochs - Porta Praetoria", + "Lochs - Ala Mhigan Quarter", + "Kugane", + "Ruby Sea - Tamamizu", + "Ruby Sea - Onokoro", + "Yanxia - Namai", + "Yanxia - House of the Fierce", + "Azim Steppe - Reunion", + "Azim Steppe - Dawn Throne", + "Azim Steppe - Dhoro Iloh", + "Doman Enclave", + "Crystarium", + "Eulmore", + "Lakeland - Fort Jobb", + "Lakeland - Ostall Imperative", + "Kholusia - Stilltide", + "Kholusia - Wright", + "Kholusia - Tomra", + "Amh Araeng - Mord Souq", + "Amh Araeng - Inn at Journey's Head", + "Amh Araeng - Twine", + "Rak'tika - Slitherbough", + "Rak'tika - Fanow", + "Il Mheg - Lydha Lran", + "Il Mheg - Pia Enni", + "Il Mheg - Wolekdorf", + "Tempest - Ondo Cups", + "Tempest - Macarenses Angle", + "Old Sharlayan", + "Radz-at-Han", + "Labyrinthos - Archeion", + "Labyrinthos - Sharlayan Hamlet", + "Labyrinthos - Aporia", + "Thavnair - Yedlihmad", + "Thavnair - Great Work", + "Thavnair - Palaka's Stand", + "Garlemald - Camp Broken Glass", + "Garlemald - Tertium", + "Mare Lamentorum - Sinus Lacrimarum", + "Mare Lamentorum - Bestways Burrow", + "Elpis - Anagnorisis", + "Elpis - Twelve Wonders", + "Elpis - Poieten Oikos", + "Ultima Thule - Reah Tahra", + "Ultima Thule - Abode of the Ea", + "Ultima Thule - Base Omicron", + "Tuliyollal", + "Solution Nine", + "Urqopacha - Wachunpelo", + "Urqopacha - Worlar's Echo", + "Kozama'uka - Ok'hanu", + "Kozama'uka - Many Fires", + "Kozama'uka - Earthenshire", + "Yak T'el - Iq Br'aax", + "Yak T'el - Mamook", + "Shaaloani - Hhusatahwi", + "Shaaloani - Sheshenewezi Springs", + "Shaaloani - Mehwahhetsoan", + "Heritage Found - Yyasulani Station", + "Heritage Found - The Outskirts", + "Heritage Found - Electrope Strike", + "Living Memory - Leynode Mnemo", + "Living Memory - Leynode Pyro", + "Living Memory - Leynode Aero" + ] + }, + "AethernetShard": { + "type": "string", + "enum": [ + "[Gridania] Aetheryte Plaza", + "[Gridania] Archers' Guild", + "[Gridania] Leatherworkers' Guild & Shaded Bower", + "[Gridania] Lancers' Guild", + "[Gridania] Conjurers' Guild", + "[Gridania] Botanists' Guild", + "[Gridania] Mih Khetto's Amphitheatre", + "[Gridania] Blue Badger Gate (Central Shroud)", + "[Gridania] Yellow Serpent Gate (North Shroud)", + "[Gridania] White Wolf Gate (Central Shroud)", + "[Gridania] Airship Landing", + "[Ul'dah] Aetheryte Plaza", + "[Ul'dah] Adventurers' Guild", + "[Ul'dah] Thaumaturges' Guild", + "[Ul'dah] Gladiators' Guild", + "[Ul'dah] Miners' Guild", + "[Ul'dah] Weavers' Guild", + "[Ul'dah] Goldsmiths' Guild", + "[Ul'dah] Sapphire Avenue Exchange", + "[Ul'dah] Alchemists' Guild", + "[Ul'dah] Gate of the Sultana (Western Thanalan)", + "[Ul'dah] Gate of Nald (Central Thanalan)", + "[Ul'dah] Gate of Thal (Central Thanalan)", + "[Ul'dah] The Chamber of Rule", + "[Ul'dah] Airship Landing", + "[Limsa Lominsa] Aetheryte Plaza", + "[Limsa Lominsa] Arcanists' Guild", + "[Limsa Lominsa] Fishermens' Guild", + "[Limsa Lominsa] Hawkers' Alley", + "[Limsa Lominsa] The Aftcastle", + "[Limsa Lominsa] Culinarians' Guild", + "[Limsa Lominsa] Marauders' Guild", + "[Limsa Lominsa] Zephyr Gate (Middle La Noscea)", + "[Limsa Lominsa] Tempest Gate (Lower La Noscea)", + "[Limsa Lominsa] Airship Landing", + "[Ishgard] Aetheryte Plaza", + "[Ishgard] The Forgotten Knight", + "[Ishgard] Skysteel Manufactory", + "[Ishgard] The Brume", + "[Ishgard] Athenaeum Astrologicum", + "[Ishgard] The Jeweled Crozier", + "[Ishgard] Saint Reymanaud's Cathedral", + "[Ishgard] The Tribunal", + "[Ishgard] The Last Vigil", + "[Ishgard] The Gates of Judgement (Coerthas Central Highlands)", + "[Idyllshire] Aetheryte Plaza", + "[Idyllshire] West Idyllshire", + "[Idyllshire] Prologue Gate (Western Hinterlands)", + "[Idyllshire] Epilogue Gate (Eastern Hinterlands)", + "[Rhalgr's Reach] Aetheryte Plaza", + "[Rhalgr's Reach] Western Rhalgr's Reach", + "[Rhalgr's Reach] Northeastern Rhalgr's Reach", + "[Rhalgr's Reach] Fringes Gate", + "[Rhalgr's Reach] Peaks Gate", + "[Kugane] Aetheryte Plaza", + "[Kugane] Shiokaze Hostelry", + "[Kugane] Pier #1", + "[Kugane] Thavnairian Consulate", + "[Kugane] Kogane Dori Markets", + "[Kugane] Bokairo Inn", + "[Kugane] The Ruby Bazaar", + "[Kugane] Sekiseigumi Barracks", + "[Kugane] Rakuza District", + "[Kugane] The Ruby Price", + "[Kugane] Airship Landing", + "[Crystarium] Aetheryte Plaza", + "[Crystarium] Musica Universalis Markets", + "[Crystarium] Temenos Rookery", + "[Crystarium] The Dossal Gate", + "[Crystarium] The Pendants", + "[Crystarium] The Amaro Launch", + "[Crystarium] The Crystalline Mean", + "[Crystarium] The Cabinet of Curiosity", + "[Crystarium] Tessellation (Lakeland)", + "[Eulmore] Aetheryte Plaza", + "[Eulmore] Southeast Derelicts", + "[Eulmore] Nightsoil Pots", + "[Eulmore] The Glory Gate", + "[Eulmore] The Mainstay", + "[Eulmore] The Path to Glory (Kholusia)", + "[Old Sharlayan] Aetheryte Plaza", + "[Old Sharlayan] The Studium", + "[Old Sharlayan] The Baldesion Annex", + "[Old Sharlayan] The Rostra", + "[Old Sharlayan] The Leveilleur Estate", + "[Old Sharlayan] Journey's End", + "[Old Sharlayan] Scholar's Harbor", + "[Old Sharlayan] The Hall of Artifice (Labyrinthos)", + "[Radz-at-Han] Aetheryte Plaza", + "[Radz-at-Han] Meghaduta", + "[Radz-at-Han] Ruveydah Fibers", + "[Radz-at-Han] Airship Landing", + "[Radz-at-Han] Alzadaal's Peace", + "[Radz-at-Han] Hall of the Radiant Host", + "[Radz-at-Han] Mehryde's Meyhane", + "[Radz-at-Han] Kama", + "[Radz-at-Han] The High Crucible of Al-Kimiya", + "[Radz-at-Han] The Gate of First Sight (Thavnair)", + "[Tuliyollal] Aetheryte Plaza", + "[Tuliyollal] Dirigible Landing", + "[Tuliyollal] The Resplendent Quarter", + "[Tuliyollal] The For'ard Cabins", + "[Tuliyollal] Bayside Bevy Marketplace", + "[Tuliyollal] Vollok Shoonsa", + "[Tuliyollal] Wachumeqimeqi", + "[Tuliyollal] Brightploom Post", + "[Tuliyollal] Arch of the Dawn (Urqopacha)", + "[Tuliyollal] Arch of the Dawn (Kozama'uka)", + "[Tuliyollal] Ihuykatumu (Kozama'uka)", + "[Tuliyollal] Dirigible Landing (Yak T'el)", + "[Tuliyollal] Xak Tural Skygate (Shaaloani)", + "[Solution Nine] Aetheryte Plaza", + "[Solution Nine] Information Center", + "[Solution Nine] True Vue", + "[Solution Nine] Neon Stein", + "[Solution Nine] The Arcadion", + "[Solution Nine] Resolution", + "[Solution Nine] Nexus Arcade", + "[Solution Nine] Residential Sector", + "[Solution Nine] Scanning Port Nine (Heritage Found)" + ] + }, + "CompletionFlags": { + "type": "array", + "description": "Quest Variables that dictate whether or not this step is skipped: null is don't check, positive values need to be set, negative values need to be unset", + "items": { + "oneOf": [ + { + "type": "object", + "properties": { + "High": { + "type": [ + "number", + "null" + ], + "minimum": 0, + "maximum": 15 + }, + "Low": { + "type": [ + "number", + "null" + ], + "minimum": 0, + "maximum": 15 + }, + "Negative": { + "type": "boolean" + }, + "Mode": { + "type": "string", + "enum": [ + "Bitwise", + "Exact" + ] + } + } + }, + { + "type": "number", + "enum": [ + 1, + 2, + 4, + 8, + 16, + 32, + 64, + 128 + ] + }, + { + "type": "null" + } + ] + }, + "minItems": 6, + "maxItems": 6 + } + } +} diff --git a/Questionable.sln b/Questionable.sln index a083acfb..b5314287 100644 --- a/Questionable.sln +++ b/Questionable.sln @@ -15,6 +15,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Questionable.Model", "Quest EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "QuestPathGenerator.Tests", "QuestPathGenerator.Tests\QuestPathGenerator.Tests.csproj", "{4FD6F346-8961-4BD5-BDA2-E5F426DE4FC7}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GatheringPaths", "GatheringPaths\GatheringPaths.csproj", "{8BF98BEF-6F00-4197-91ED-75F8F1C35FFB}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GatheringPathRenderer", "GatheringPathRenderer\GatheringPathRenderer.csproj", "{F514DA95-9867-4F3F-8062-ACE0C62E8740}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 @@ -45,6 +49,14 @@ Global {C91EEF13-A1AC-4A40-B695-DD4E378E5989}.Debug|x64.Build.0 = Debug|x64 {C91EEF13-A1AC-4A40-B695-DD4E378E5989}.Release|x64.ActiveCfg = Release|x64 {C91EEF13-A1AC-4A40-B695-DD4E378E5989}.Release|x64.Build.0 = Release|x64 + {8BF98BEF-6F00-4197-91ED-75F8F1C35FFB}.Debug|x64.ActiveCfg = Debug|Any CPU + {8BF98BEF-6F00-4197-91ED-75F8F1C35FFB}.Debug|x64.Build.0 = Debug|Any CPU + {8BF98BEF-6F00-4197-91ED-75F8F1C35FFB}.Release|x64.ActiveCfg = Release|Any CPU + {8BF98BEF-6F00-4197-91ED-75F8F1C35FFB}.Release|x64.Build.0 = Release|Any CPU + {F514DA95-9867-4F3F-8062-ACE0C62E8740}.Debug|x64.ActiveCfg = Debug|Any CPU + {F514DA95-9867-4F3F-8062-ACE0C62E8740}.Debug|x64.Build.0 = Debug|Any CPU + {F514DA95-9867-4F3F-8062-ACE0C62E8740}.Release|x64.ActiveCfg = Release|Any CPU + {F514DA95-9867-4F3F-8062-ACE0C62E8740}.Release|x64.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Questionable/ChatFunctions.cs b/Questionable/ChatFunctions.cs index 26ca9a22..d28946a8 100644 --- a/Questionable/ChatFunctions.cs +++ b/Questionable/ChatFunctions.cs @@ -14,7 +14,7 @@ using FFXIVClientStructs.FFXIV.Client.System.Memory; using FFXIVClientStructs.FFXIV.Client.System.String; using Lumina.Excel.GeneratedSheets; using Microsoft.Extensions.Logging; -using Questionable.Model.V1; +using Questionable.Model.Questing; namespace Questionable; diff --git a/Questionable/Controller/CombatController.cs b/Questionable/Controller/CombatController.cs index f747966e..1f95e9da 100644 --- a/Questionable/Controller/CombatController.cs +++ b/Questionable/Controller/CombatController.cs @@ -14,7 +14,7 @@ using FFXIVClientStructs.FFXIV.Common.Math; using Microsoft.Extensions.Logging; using Questionable.Controller.CombatModules; using Questionable.Controller.Utils; -using Questionable.Model.V1; +using Questionable.Model.Questing; namespace Questionable.Controller; diff --git a/Questionable/Controller/GameUiController.cs b/Questionable/Controller/GameUiController.cs index 0bb4e12b..61d31fbd 100644 --- a/Questionable/Controller/GameUiController.cs +++ b/Questionable/Controller/GameUiController.cs @@ -14,7 +14,7 @@ using LLib.GameUI; using Lumina.Excel.GeneratedSheets; using Microsoft.Extensions.Logging; using Questionable.Data; -using Questionable.Model.V1; +using Questionable.Model.Questing; using Quest = Questionable.Model.Quest; using ValueType = FFXIVClientStructs.FFXIV.Component.GUI.ValueType; diff --git a/Questionable/Controller/MovementController.cs b/Questionable/Controller/MovementController.cs index 1db1d5cf..d7fc74a9 100644 --- a/Questionable/Controller/MovementController.cs +++ b/Questionable/Controller/MovementController.cs @@ -18,8 +18,10 @@ using Microsoft.Extensions.Logging; using Questionable.Controller.NavigationOverrides; using Questionable.External; using Questionable.Model; -using Questionable.Model.V1; -using Questionable.Model.V1.Converter; +using Questionable.Model.Common; +using Questionable.Model.Common.Converter; +using Questionable.Model.Questing; +using Questionable.Model.Questing.Converter; namespace Questionable.Controller; diff --git a/Questionable/Controller/QuestController.cs b/Questionable/Controller/QuestController.cs index c92fee2b..e50891d2 100644 --- a/Questionable/Controller/QuestController.cs +++ b/Questionable/Controller/QuestController.cs @@ -10,7 +10,7 @@ using Questionable.Controller.Steps; using Questionable.Controller.Steps.Shared; using Questionable.External; using Questionable.Model; -using Questionable.Model.V1; +using Questionable.Model.Questing; namespace Questionable.Controller; diff --git a/Questionable/Controller/QuestRegistry.cs b/Questionable/Controller/QuestRegistry.cs index 71750a1c..f472c115 100644 --- a/Questionable/Controller/QuestRegistry.cs +++ b/Questionable/Controller/QuestRegistry.cs @@ -11,7 +11,7 @@ using Dalamud.Plugin; using Microsoft.Extensions.Logging; using Questionable.Data; using Questionable.Model; -using Questionable.Model.V1; +using Questionable.Model.Questing; using Questionable.QuestPaths; using Questionable.Validation; using Questionable.Validation.Validators; diff --git a/Questionable/Controller/Steps/Common/NextQuest.cs b/Questionable/Controller/Steps/Common/NextQuest.cs index 30a705e6..dddc8f9d 100644 --- a/Questionable/Controller/Steps/Common/NextQuest.cs +++ b/Questionable/Controller/Steps/Common/NextQuest.cs @@ -2,7 +2,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Questionable.Model; -using Questionable.Model.V1; +using Questionable.Model.Questing; namespace Questionable.Controller.Steps.Common; diff --git a/Questionable/Controller/Steps/ITaskFactory.cs b/Questionable/Controller/Steps/ITaskFactory.cs index 159d5c12..287f029f 100644 --- a/Questionable/Controller/Steps/ITaskFactory.cs +++ b/Questionable/Controller/Steps/ITaskFactory.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; using Questionable.Model; -using Questionable.Model.V1; +using Questionable.Model.Questing; namespace Questionable.Controller.Steps; diff --git a/Questionable/Controller/Steps/Interactions/Action.cs b/Questionable/Controller/Steps/Interactions/Action.cs index 94125e43..000811ca 100644 --- a/Questionable/Controller/Steps/Interactions/Action.cs +++ b/Questionable/Controller/Steps/Interactions/Action.cs @@ -7,7 +7,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Questionable.Controller.Steps.Common; using Questionable.Model; -using Questionable.Model.V1; +using Questionable.Model.Questing; namespace Questionable.Controller.Steps.Interactions; diff --git a/Questionable/Controller/Steps/Interactions/AetherCurrent.cs b/Questionable/Controller/Steps/Interactions/AetherCurrent.cs index 82b13d27..3ae2c4b3 100644 --- a/Questionable/Controller/Steps/Interactions/AetherCurrent.cs +++ b/Questionable/Controller/Steps/Interactions/AetherCurrent.cs @@ -4,7 +4,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Questionable.Data; using Questionable.Model; -using Questionable.Model.V1; +using Questionable.Model.Questing; namespace Questionable.Controller.Steps.Interactions; diff --git a/Questionable/Controller/Steps/Interactions/AethernetShard.cs b/Questionable/Controller/Steps/Interactions/AethernetShard.cs index 87a4f348..b3219a6e 100644 --- a/Questionable/Controller/Steps/Interactions/AethernetShard.cs +++ b/Questionable/Controller/Steps/Interactions/AethernetShard.cs @@ -1,9 +1,9 @@ using System; -using FFXIVClientStructs.FFXIV.Client.Game.Object; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Questionable.Model; -using Questionable.Model.V1; +using Questionable.Model.Common; +using Questionable.Model.Questing; using ObjectKind = Dalamud.Game.ClientState.Objects.Enums.ObjectKind; namespace Questionable.Controller.Steps.Interactions; diff --git a/Questionable/Controller/Steps/Interactions/Aetheryte.cs b/Questionable/Controller/Steps/Interactions/Aetheryte.cs index a6bccc4c..c2cab7df 100644 --- a/Questionable/Controller/Steps/Interactions/Aetheryte.cs +++ b/Questionable/Controller/Steps/Interactions/Aetheryte.cs @@ -2,7 +2,8 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Questionable.Model; -using Questionable.Model.V1; +using Questionable.Model.Common; +using Questionable.Model.Questing; namespace Questionable.Controller.Steps.Interactions; diff --git a/Questionable/Controller/Steps/Interactions/Combat.cs b/Questionable/Controller/Steps/Interactions/Combat.cs index 97201b46..2d7de402 100644 --- a/Questionable/Controller/Steps/Interactions/Combat.cs +++ b/Questionable/Controller/Steps/Interactions/Combat.cs @@ -6,7 +6,7 @@ using Questionable.Controller.Steps.Common; using Questionable.Controller.Steps.Shared; using Questionable.Controller.Utils; using Questionable.Model; -using Questionable.Model.V1; +using Questionable.Model.Questing; namespace Questionable.Controller.Steps.Interactions; diff --git a/Questionable/Controller/Steps/Interactions/Dive.cs b/Questionable/Controller/Steps/Interactions/Dive.cs index 05e9cf44..3976eb73 100644 --- a/Questionable/Controller/Steps/Interactions/Dive.cs +++ b/Questionable/Controller/Steps/Interactions/Dive.cs @@ -12,7 +12,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Questionable.Controller.Steps.Common; using Questionable.Model; -using Questionable.Model.V1; +using Questionable.Model.Questing; namespace Questionable.Controller.Steps.Interactions; diff --git a/Questionable/Controller/Steps/Interactions/Duty.cs b/Questionable/Controller/Steps/Interactions/Duty.cs index a7de058c..ab2afdcd 100644 --- a/Questionable/Controller/Steps/Interactions/Duty.cs +++ b/Questionable/Controller/Steps/Interactions/Duty.cs @@ -3,7 +3,7 @@ using Dalamud.Game.ClientState.Conditions; using Dalamud.Plugin.Services; using Microsoft.Extensions.DependencyInjection; using Questionable.Model; -using Questionable.Model.V1; +using Questionable.Model.Questing; namespace Questionable.Controller.Steps.Interactions; diff --git a/Questionable/Controller/Steps/Interactions/Emote.cs b/Questionable/Controller/Steps/Interactions/Emote.cs index 44478475..0a5e9064 100644 --- a/Questionable/Controller/Steps/Interactions/Emote.cs +++ b/Questionable/Controller/Steps/Interactions/Emote.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using Microsoft.Extensions.DependencyInjection; using Questionable.Controller.Steps.Common; using Questionable.Model; -using Questionable.Model.V1; +using Questionable.Model.Questing; namespace Questionable.Controller.Steps.Interactions; diff --git a/Questionable/Controller/Steps/Interactions/EquipItem.cs b/Questionable/Controller/Steps/Interactions/EquipItem.cs index 9322563d..95aad266 100644 --- a/Questionable/Controller/Steps/Interactions/EquipItem.cs +++ b/Questionable/Controller/Steps/Interactions/EquipItem.cs @@ -6,7 +6,7 @@ using FFXIVClientStructs.FFXIV.Client.Game; using Lumina.Excel.GeneratedSheets; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; -using Questionable.Model.V1; +using Questionable.Model.Questing; using Quest = Questionable.Model.Quest; namespace Questionable.Controller.Steps.Interactions; diff --git a/Questionable/Controller/Steps/Interactions/Interact.cs b/Questionable/Controller/Steps/Interactions/Interact.cs index f49394de..7dba0d44 100644 --- a/Questionable/Controller/Steps/Interactions/Interact.cs +++ b/Questionable/Controller/Steps/Interactions/Interact.cs @@ -8,7 +8,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Questionable.Controller.Steps.Shared; using Questionable.Model; -using Questionable.Model.V1; +using Questionable.Model.Questing; namespace Questionable.Controller.Steps.Interactions; diff --git a/Questionable/Controller/Steps/Interactions/Jump.cs b/Questionable/Controller/Steps/Interactions/Jump.cs index 5c3d9add..0b0b099d 100644 --- a/Questionable/Controller/Steps/Interactions/Jump.cs +++ b/Questionable/Controller/Steps/Interactions/Jump.cs @@ -5,7 +5,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Questionable.Controller.Steps.Common; using Questionable.Model; -using Questionable.Model.V1; +using Questionable.Model.Questing; namespace Questionable.Controller.Steps.Interactions; diff --git a/Questionable/Controller/Steps/Interactions/Say.cs b/Questionable/Controller/Steps/Interactions/Say.cs index c833badc..20fc7f67 100644 --- a/Questionable/Controller/Steps/Interactions/Say.cs +++ b/Questionable/Controller/Steps/Interactions/Say.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using Microsoft.Extensions.DependencyInjection; using Questionable.Controller.Steps.Common; using Questionable.Model; -using Questionable.Model.V1; +using Questionable.Model.Questing; namespace Questionable.Controller.Steps.Interactions; diff --git a/Questionable/Controller/Steps/Interactions/SinglePlayerDuty.cs b/Questionable/Controller/Steps/Interactions/SinglePlayerDuty.cs index f7d5172a..648627c1 100644 --- a/Questionable/Controller/Steps/Interactions/SinglePlayerDuty.cs +++ b/Questionable/Controller/Steps/Interactions/SinglePlayerDuty.cs @@ -4,7 +4,7 @@ using Dalamud.Plugin.Services; using Microsoft.Extensions.DependencyInjection; using Questionable.External; using Questionable.Model; -using Questionable.Model.V1; +using Questionable.Model.Questing; namespace Questionable.Controller.Steps.Interactions; diff --git a/Questionable/Controller/Steps/Interactions/UseItem.cs b/Questionable/Controller/Steps/Interactions/UseItem.cs index 3e1212f8..e17f005e 100644 --- a/Questionable/Controller/Steps/Interactions/UseItem.cs +++ b/Questionable/Controller/Steps/Interactions/UseItem.cs @@ -13,7 +13,8 @@ using Questionable.Controller.Steps.Shared; using Questionable.Controller.Utils; using Questionable.Data; using Questionable.Model; -using Questionable.Model.V1; +using Questionable.Model.Common; +using Questionable.Model.Questing; using AethernetShortcut = Questionable.Controller.Steps.Shared.AethernetShortcut; namespace Questionable.Controller.Steps.Interactions; diff --git a/Questionable/Controller/Steps/Shared/AethernetShortcut.cs b/Questionable/Controller/Steps/Shared/AethernetShortcut.cs index df7f5788..a66e7c0f 100644 --- a/Questionable/Controller/Steps/Shared/AethernetShortcut.cs +++ b/Questionable/Controller/Steps/Shared/AethernetShortcut.cs @@ -8,8 +8,10 @@ using Microsoft.Extensions.Logging; using Questionable.Data; using Questionable.External; using Questionable.Model; -using Questionable.Model.V1; -using Questionable.Model.V1.Converter; +using Questionable.Model.Common; +using Questionable.Model.Common.Converter; +using Questionable.Model.Questing; +using Questionable.Model.Questing.Converter; namespace Questionable.Controller.Steps.Shared; diff --git a/Questionable/Controller/Steps/Shared/AetheryteShortcut.cs b/Questionable/Controller/Steps/Shared/AetheryteShortcut.cs index 413dd37a..ed8d1c07 100644 --- a/Questionable/Controller/Steps/Shared/AetheryteShortcut.cs +++ b/Questionable/Controller/Steps/Shared/AetheryteShortcut.cs @@ -7,7 +7,8 @@ using Microsoft.Extensions.Logging; using Questionable.Controller.Steps.Common; using Questionable.Data; using Questionable.Model; -using Questionable.Model.V1; +using Questionable.Model.Common; +using Questionable.Model.Questing; namespace Questionable.Controller.Steps.Shared; diff --git a/Questionable/Controller/Steps/Shared/Move.cs b/Questionable/Controller/Steps/Shared/Move.cs index e7474688..24d3e7f8 100644 --- a/Questionable/Controller/Steps/Shared/Move.cs +++ b/Questionable/Controller/Steps/Shared/Move.cs @@ -13,7 +13,7 @@ using Questionable.Controller.NavigationOverrides; using Questionable.Controller.Steps.Common; using Questionable.Data; using Questionable.Model; -using Questionable.Model.V1; +using Questionable.Model.Questing; namespace Questionable.Controller.Steps.Shared; diff --git a/Questionable/Controller/Steps/Shared/SkipCondition.cs b/Questionable/Controller/Steps/Shared/SkipCondition.cs index 2f768ecd..5d50ba18 100644 --- a/Questionable/Controller/Steps/Shared/SkipCondition.cs +++ b/Questionable/Controller/Steps/Shared/SkipCondition.cs @@ -11,7 +11,8 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Questionable.Controller.Utils; using Questionable.Model; -using Questionable.Model.V1; +using Questionable.Model.Common; +using Questionable.Model.Questing; namespace Questionable.Controller.Steps.Shared; diff --git a/Questionable/Controller/Steps/Shared/StepDisabled.cs b/Questionable/Controller/Steps/Shared/StepDisabled.cs index 16bb8365..609f3143 100644 --- a/Questionable/Controller/Steps/Shared/StepDisabled.cs +++ b/Questionable/Controller/Steps/Shared/StepDisabled.cs @@ -2,7 +2,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Questionable.Model; -using Questionable.Model.V1; +using Questionable.Model.Questing; namespace Questionable.Controller.Steps.Shared; diff --git a/Questionable/Controller/Steps/Shared/WaitAtEnd.cs b/Questionable/Controller/Steps/Shared/WaitAtEnd.cs index 0d44663c..6d54623e 100644 --- a/Questionable/Controller/Steps/Shared/WaitAtEnd.cs +++ b/Questionable/Controller/Steps/Shared/WaitAtEnd.cs @@ -12,7 +12,7 @@ using Questionable.Controller.Steps.Common; using Questionable.Controller.Utils; using Questionable.Data; using Questionable.Model; -using Questionable.Model.V1; +using Questionable.Model.Questing; namespace Questionable.Controller.Steps.Shared; diff --git a/Questionable/Controller/Steps/Shared/WaitAtStart.cs b/Questionable/Controller/Steps/Shared/WaitAtStart.cs index 4a1f411e..b39e301d 100644 --- a/Questionable/Controller/Steps/Shared/WaitAtStart.cs +++ b/Questionable/Controller/Steps/Shared/WaitAtStart.cs @@ -2,7 +2,7 @@ using Microsoft.Extensions.DependencyInjection; using Questionable.Controller.Steps.Common; using Questionable.Model; -using Questionable.Model.V1; +using Questionable.Model.Questing; namespace Questionable.Controller.Steps.Shared; diff --git a/Questionable/Controller/Utils/QuestWorkUtils.cs b/Questionable/Controller/Utils/QuestWorkUtils.cs index 6bb77180..59235918 100644 --- a/Questionable/Controller/Utils/QuestWorkUtils.cs +++ b/Questionable/Controller/Utils/QuestWorkUtils.cs @@ -4,7 +4,7 @@ using System.Linq; using FFXIVClientStructs.FFXIV.Application.Network.WorkDefinitions; using Microsoft.Extensions.Logging; using Questionable.Controller.Steps.Shared; -using Questionable.Model.V1; +using Questionable.Model.Questing; namespace Questionable.Controller.Utils; diff --git a/Questionable/Data/AetheryteData.cs b/Questionable/Data/AetheryteData.cs index 9e216cdc..28d8e459 100644 --- a/Questionable/Data/AetheryteData.cs +++ b/Questionable/Data/AetheryteData.cs @@ -4,8 +4,7 @@ using System.Linq; using System.Numerics; using Dalamud.Plugin.Services; using Lumina.Excel.GeneratedSheets; -using Microsoft.Extensions.Logging; -using Questionable.Model.V1; +using Questionable.Model.Common; namespace Questionable.Data; diff --git a/Questionable/External/LifestreamIpc.cs b/Questionable/External/LifestreamIpc.cs index deab3a24..f3267709 100644 --- a/Questionable/External/LifestreamIpc.cs +++ b/Questionable/External/LifestreamIpc.cs @@ -1,7 +1,7 @@ using Dalamud.Plugin; using Dalamud.Plugin.Ipc; using Questionable.Data; -using Questionable.Model.V1; +using Questionable.Model.Common; namespace Questionable.External; diff --git a/Questionable/GameFunctions.cs b/Questionable/GameFunctions.cs index 6487eb98..724f2f11 100644 --- a/Questionable/GameFunctions.cs +++ b/Questionable/GameFunctions.cs @@ -24,7 +24,8 @@ using Microsoft.Extensions.Logging; using Questionable.Controller; using Questionable.Data; using Questionable.Model; -using Questionable.Model.V1; +using Questionable.Model.Common; +using Questionable.Model.Questing; using Action = Lumina.Excel.GeneratedSheets2.Action; using BattleChara = FFXIVClientStructs.FFXIV.Client.Game.Character.BattleChara; using ContentFinderCondition = Lumina.Excel.GeneratedSheets.ContentFinderCondition; diff --git a/Questionable/Model/Quest.cs b/Questionable/Model/Quest.cs index a33bcd18..5124de9d 100644 --- a/Questionable/Model/Quest.cs +++ b/Questionable/Model/Quest.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; using System.Linq; -using Questionable.Model.V1; +using Questionable.Model.Questing; namespace Questionable.Model; diff --git a/Questionable/Validation/Validators/AethernetShortcutValidator.cs b/Questionable/Validation/Validators/AethernetShortcutValidator.cs index 36643c3e..e620d8a5 100644 --- a/Questionable/Validation/Validators/AethernetShortcutValidator.cs +++ b/Questionable/Validation/Validators/AethernetShortcutValidator.cs @@ -2,7 +2,7 @@ using System.Linq; using Questionable.Data; using Questionable.Model; -using Questionable.Model.V1; +using Questionable.Model.Questing; namespace Questionable.Validation.Validators; diff --git a/Questionable/Validation/Validators/BasicSequenceValidator.cs b/Questionable/Validation/Validators/BasicSequenceValidator.cs index 0c10e032..0127bc19 100644 --- a/Questionable/Validation/Validators/BasicSequenceValidator.cs +++ b/Questionable/Validation/Validators/BasicSequenceValidator.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using System.Linq; using Questionable.Model; -using Questionable.Model.V1; +using Questionable.Model.Questing; namespace Questionable.Validation.Validators; diff --git a/Questionable/Validation/Validators/CompletionFlagsValidator.cs b/Questionable/Validation/Validators/CompletionFlagsValidator.cs index 1d36c8c4..2cfc58d7 100644 --- a/Questionable/Validation/Validators/CompletionFlagsValidator.cs +++ b/Questionable/Validation/Validators/CompletionFlagsValidator.cs @@ -3,7 +3,7 @@ using System.Linq; using System.Numerics; using Questionable.Controller.Utils; using Questionable.Model; -using Questionable.Model.V1; +using Questionable.Model.Questing; namespace Questionable.Validation.Validators; diff --git a/Questionable/Validation/Validators/JsonSchemaValidator.cs b/Questionable/Validation/Validators/JsonSchemaValidator.cs index b3ed6f4e..7cacc520 100644 --- a/Questionable/Validation/Validators/JsonSchemaValidator.cs +++ b/Questionable/Validation/Validators/JsonSchemaValidator.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Globalization; using System.Text.Json.Nodes; using Json.Schema; @@ -12,6 +13,13 @@ internal sealed class JsonSchemaValidator : IQuestValidator private readonly Dictionary _questNodes = new(); private JsonSchema? _questSchema; + public JsonSchemaValidator() + { + SchemaRegistry.Global.Register( + new Uri("https://git.carvel.li/liza/Questionable/raw/branch/master/Questionable.Model/common-schema.json"), + JsonSchema.FromStream(AssemblyModelLoader.CommonSchema).AsTask().Result); + } + public IEnumerable Validate(Quest quest) { _questSchema ??= JsonSchema.FromStream(AssemblyQuestLoader.QuestSchema).AsTask().Result; @@ -36,7 +44,6 @@ internal sealed class JsonSchemaValidator : IQuestValidator }; } } - } public void Enqueue(ushort questId, JsonNode questNode) => _questNodes[questId] = questNode; diff --git a/Questionable/Validation/Validators/UniqueStartStopValidator.cs b/Questionable/Validation/Validators/UniqueStartStopValidator.cs index b95522f1..b385306d 100644 --- a/Questionable/Validation/Validators/UniqueStartStopValidator.cs +++ b/Questionable/Validation/Validators/UniqueStartStopValidator.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using System.Linq; using Questionable.Model; -using Questionable.Model.V1; +using Questionable.Model.Questing; namespace Questionable.Validation.Validators; diff --git a/Questionable/Windows/DebugOverlay.cs b/Questionable/Windows/DebugOverlay.cs index 20b572fe..e7cc34e7 100644 --- a/Questionable/Windows/DebugOverlay.cs +++ b/Questionable/Windows/DebugOverlay.cs @@ -11,7 +11,7 @@ using ImGuiNET; using Questionable.Controller; using Questionable.Data; using Questionable.Model; -using Questionable.Model.V1; +using Questionable.Model.Questing; namespace Questionable.Windows; diff --git a/Questionable/Windows/QuestComponents/ActiveQuestComponent.cs b/Questionable/Windows/QuestComponents/ActiveQuestComponent.cs index f819526a..14b628d3 100644 --- a/Questionable/Windows/QuestComponents/ActiveQuestComponent.cs +++ b/Questionable/Windows/QuestComponents/ActiveQuestComponent.cs @@ -13,7 +13,7 @@ using FFXIVClientStructs.FFXIV.Application.Network.WorkDefinitions; using ImGuiNET; using Questionable.Controller; using Questionable.Controller.Steps.Shared; -using Questionable.Model.V1; +using Questionable.Model.Questing; namespace Questionable.Windows.QuestComponents; diff --git a/Questionable/Windows/QuestComponents/CreationUtilsComponent.cs b/Questionable/Windows/QuestComponents/CreationUtilsComponent.cs index a1fac0a4..b824f1af 100644 --- a/Questionable/Windows/QuestComponents/CreationUtilsComponent.cs +++ b/Questionable/Windows/QuestComponents/CreationUtilsComponent.cs @@ -16,7 +16,8 @@ using Microsoft.Extensions.Logging; using Questionable.Controller; using Questionable.Data; using Questionable.Model; -using Questionable.Model.V1; +using Questionable.Model.Common; +using Questionable.Model.Questing; using ObjectKind = Dalamud.Game.ClientState.Objects.Enums.ObjectKind; namespace Questionable.Windows.QuestComponents; @@ -160,23 +161,38 @@ internal sealed class CreationUtilsComponent "Left click: Copy target position as JSON.\nRight click: Copy target position as C# code."); if (copy) { - string interactionType = gameObject->NamePlateIconId switch + var target = _targetManager.Target; + if (target.ObjectKind == ObjectKind.GatheringPoint) { - 71201 or 71211 or 71221 or 71231 or 71341 or 71351 => "AcceptQuest", - 71202 or 71212 or 71222 or 71232 or 71342 or 71352 => "AcceptQuest", // repeatable - 71205 or 71215 or 71225 or 71235 or 71345 or 71355 => "CompleteQuest", - _ => "Interact", - }; - ImGui.SetClipboardText($$""" - "DataId": {{_targetManager.Target.DataId}}, - "Position": { - "X": {{_targetManager.Target.Position.X.ToString(CultureInfo.InvariantCulture)}}, - "Y": {{_targetManager.Target.Position.Y.ToString(CultureInfo.InvariantCulture)}}, - "Z": {{_targetManager.Target.Position.Z.ToString(CultureInfo.InvariantCulture)}} - }, - "TerritoryId": {{_clientState.TerritoryType}}, - "InteractionType": "{{interactionType}}" - """); + ImGui.SetClipboardText($$""" + "DataId": {{target.DataId}}, + "Position": { + "X": {{target.Position.X.ToString(CultureInfo.InvariantCulture)}}, + "Y": {{target.Position.Y.ToString(CultureInfo.InvariantCulture)}}, + "Z": {{target.Position.Z.ToString(CultureInfo.InvariantCulture)}} + } + """); + } + else + { + string interactionType = gameObject->NamePlateIconId switch + { + 71201 or 71211 or 71221 or 71231 or 71341 or 71351 => "AcceptQuest", + 71202 or 71212 or 71222 or 71232 or 71342 or 71352 => "AcceptQuest", // repeatable + 71205 or 71215 or 71225 or 71235 or 71345 or 71355 => "CompleteQuest", + _ => "Interact", + }; + ImGui.SetClipboardText($$""" + "DataId": {{target.DataId}}, + "Position": { + "X": {{target.Position.X.ToString(CultureInfo.InvariantCulture)}}, + "Y": {{target.Position.Y.ToString(CultureInfo.InvariantCulture)}}, + "Z": {{target.Position.Z.ToString(CultureInfo.InvariantCulture)}} + }, + "TerritoryId": {{_clientState.TerritoryType}}, + "InteractionType": "{{interactionType}}" + """); + } } else if (ImGui.IsItemClicked(ImGuiMouseButton.Right)) { diff --git a/Questionable/Windows/QuestSelectionWindow.cs b/Questionable/Windows/QuestSelectionWindow.cs index 6f420786..8da2c2d0 100644 --- a/Questionable/Windows/QuestSelectionWindow.cs +++ b/Questionable/Windows/QuestSelectionWindow.cs @@ -19,7 +19,7 @@ using LLib.ImGui; using Questionable.Controller; using Questionable.Data; using Questionable.Model; -using Questionable.Model.V1; +using Questionable.Model.Questing; using Questionable.Windows.QuestComponents; namespace Questionable.Windows; From 9bfbc99144eca664024f439bd4c6e79569da9548 Mon Sep 17 00:00:00 2001 From: Liza Carvelli Date: Fri, 2 Aug 2024 20:04:45 +0200 Subject: [PATCH 09/12] Schema update --- .gitmodules | 3 + .../GatheringPathRenderer.csproj | 5 + .../GatheringPathRenderer.json | 6 + GatheringPathRenderer/RendererPlugin.cs | 180 +++++++++++++++++- GatheringPathRenderer/packages.lock.json | 28 +++ .../Thavnair/820_Pewter Ore.json | 180 +++++++++++++----- .../AssemblyGatheringLocationLoader.cs | 4 +- GatheringPaths/GatheringPaths.csproj | 2 +- GatheringPaths/gatheringlocation-v1.json | 79 +++++--- .../GatheringSourceGenerator.cs | 2 +- QuestPathGenerator/RoslynShortcuts.cs | 47 +++-- QuestPathGenerator/Utils.cs | 3 +- .../Gathering/GatheringLocation.cs | 21 ++ Questionable.Model/Gathering/GatheringNode.cs | 10 + .../Gathering/GatheringNodeGroup.cs | 8 + .../Gathering/GatheringNodeLocation.cs | 13 -- Questionable.Model/Gathering/GatheringRoot.cs | 2 +- Questionable.sln | 6 + Questionable/Controller/QuestRegistry.cs | 6 +- vendor/ECommons | 1 + 20 files changed, 502 insertions(+), 104 deletions(-) create mode 100644 GatheringPathRenderer/GatheringPathRenderer.json create mode 100644 Questionable.Model/Gathering/GatheringLocation.cs create mode 100644 Questionable.Model/Gathering/GatheringNode.cs create mode 100644 Questionable.Model/Gathering/GatheringNodeGroup.cs delete mode 100644 Questionable.Model/Gathering/GatheringNodeLocation.cs create mode 160000 vendor/ECommons diff --git a/.gitmodules b/.gitmodules index 4ac68e07..0bc08a36 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "LLib"] path = LLib url = https://git.carvel.li/liza/LLib.git +[submodule "vendor/ECommons"] + path = vendor/ECommons + url = https://github.com/NightmareXIV/ECommons.git diff --git a/GatheringPathRenderer/GatheringPathRenderer.csproj b/GatheringPathRenderer/GatheringPathRenderer.csproj index 5d22cd3f..1d3aeae5 100644 --- a/GatheringPathRenderer/GatheringPathRenderer.csproj +++ b/GatheringPathRenderer/GatheringPathRenderer.csproj @@ -1,3 +1,8 @@ + + + + + diff --git a/GatheringPathRenderer/GatheringPathRenderer.json b/GatheringPathRenderer/GatheringPathRenderer.json new file mode 100644 index 00000000..8d68d1d8 --- /dev/null +++ b/GatheringPathRenderer/GatheringPathRenderer.json @@ -0,0 +1,6 @@ +{ + "Name": "GatheringPathRenderer", + "Author": "Liza Carvelli", + "Punchline": "dev only plugin: Renders gathering location.", + "Description": "dev only plugin: Renders gathering location (without ECommons polluting the entire normal project)." +} diff --git a/GatheringPathRenderer/RendererPlugin.cs b/GatheringPathRenderer/RendererPlugin.cs index d33eae96..9c9a50d2 100644 --- a/GatheringPathRenderer/RendererPlugin.cs +++ b/GatheringPathRenderer/RendererPlugin.cs @@ -1,11 +1,189 @@ -using Dalamud.Plugin; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text.Json; +using System.Text.Json.Nodes; +using Dalamud.Plugin; +using Dalamud.Plugin.Services; +using ECommons; +using ECommons.Schedulers; +using ECommons.SplatoonAPI; +using Questionable.Model.Gathering; namespace GatheringPathRenderer; public sealed class RendererPlugin : IDalamudPlugin { + private const long OnTerritoryChange = -2; + private readonly IDalamudPluginInterface _pluginInterface; + private readonly IClientState _clientState; + private readonly IPluginLog _pluginLog; + private readonly List<(ushort Id, GatheringRoot Root)> _gatheringLocations = []; + + public RendererPlugin(IDalamudPluginInterface pluginInterface, IClientState clientState, IPluginLog pluginLog) + { + _pluginInterface = pluginInterface; + _clientState = clientState; + _pluginLog = pluginLog; + + _pluginInterface.GetIpcSubscriber("Questionable.ReloadData") + .Subscribe(Reload); + + ECommonsMain.Init(pluginInterface, this, Module.SplatoonAPI); + LoadGatheringLocationsFromDirectory(); + + _clientState.TerritoryChanged += TerritoryChanged; + if (_clientState.IsLoggedIn) + TerritoryChanged(_clientState.TerritoryType); + } + + private void Reload() + { + LoadGatheringLocationsFromDirectory(); + TerritoryChanged(_clientState.TerritoryType); + } + + private void LoadGatheringLocationsFromDirectory() + { + _gatheringLocations.Clear(); + + DirectoryInfo? solutionDirectory = _pluginInterface.AssemblyLocation.Directory?.Parent?.Parent?.Parent; + if (solutionDirectory != null) + { + DirectoryInfo pathProjectDirectory = + new DirectoryInfo(Path.Combine(solutionDirectory.FullName, "GatheringPaths")); + if (pathProjectDirectory.Exists) + { + try + { + LoadFromDirectory( + new DirectoryInfo(Path.Combine(pathProjectDirectory.FullName, "2.x - A Realm Reborn"))); + LoadFromDirectory( + new DirectoryInfo(Path.Combine(pathProjectDirectory.FullName, "3.x - Heavensward"))); + LoadFromDirectory( + new DirectoryInfo(Path.Combine(pathProjectDirectory.FullName, "4.x - Stormblood"))); + LoadFromDirectory( + new DirectoryInfo(Path.Combine(pathProjectDirectory.FullName, "5.x - Shadowbringers"))); + LoadFromDirectory( + new DirectoryInfo(Path.Combine(pathProjectDirectory.FullName, "6.x - Endwalker"))); + LoadFromDirectory( + new DirectoryInfo(Path.Combine(pathProjectDirectory.FullName, "7.x - Dawntrail"))); + + _pluginLog.Information( + $"Loaded {_gatheringLocations.Count} gathering root locations from project directory"); + } + catch (Exception e) + { + _pluginLog.Error(e, "Failed to load quests from project directory"); + } + } + else + _pluginLog.Warning($"Project directory {pathProjectDirectory} does not exist"); + } + else + _pluginLog.Warning($"Solution directory {solutionDirectory} does not exist"); + } + + private void LoadFromDirectory(DirectoryInfo directory) + { + if (!directory.Exists) + return; + + _pluginLog.Information($"Loading locations from {directory}"); + foreach (FileInfo fileInfo in directory.GetFiles("*.json")) + { + try + { + using FileStream stream = new FileStream(fileInfo.FullName, FileMode.Open, FileAccess.Read); + LoadLocationFromStream(fileInfo.Name, stream); + } + catch (Exception e) + { + throw new InvalidDataException($"Unable to load file {fileInfo.FullName}", e); + } + } + + foreach (DirectoryInfo childDirectory in directory.GetDirectories()) + LoadFromDirectory(childDirectory); + } + + private void LoadLocationFromStream(string fileName, Stream stream) + { + var locationNode = JsonNode.Parse(stream)!; + GatheringRoot root = locationNode.Deserialize()!; + _gatheringLocations.Add((ushort.Parse(fileName.Split('_')[0]), root)); + } + + private void TerritoryChanged(ushort territoryId) + { + Splatoon.RemoveDynamicElements("GatheringPathRenderer"); + + var elements = _gatheringLocations + .Where(x => x.Root.TerritoryId == territoryId) + .SelectMany(v => + v.Root.Groups.SelectMany(group => + group.Nodes.SelectMany(node => node.Locations + .SelectMany(x => + new List + { + new Element(x.IsCone() + ? ElementType.ConeAtFixedCoordinates + : ElementType.CircleAtFixedCoordinates) + { + refX = x.Position.X, + refY = x.Position.Z, + refZ = x.Position.Y, + Filled = true, + radius = x.MinimumDistance, + Donut = x.MaximumDistance - x.MinimumDistance, + color = 0x2020FF80, + Enabled = true, + coneAngleMin = x.IsCone() ? (int)x.MinimumAngle.GetValueOrDefault() : 0, + coneAngleMax = x.IsCone() ? (int)x.MaximumAngle.GetValueOrDefault() : 0 + }, + new Element(ElementType.CircleAtFixedCoordinates) + { + refX = x.Position.X, + refY = x.Position.Z, + refZ = x.Position.Y, + color = 0x00000000, + Enabled = true, + overlayText = $"{v.Id} // {node.DataId} / {node.Locations.IndexOf(x)}" + } + })))) + .ToList(); + + if (elements.Count == 0) + { + _pluginLog.Information("No new elements to render."); + return; + } + + _ = new TickScheduler(delegate + { + try + { + Splatoon.AddDynamicElements("GatheringPathRenderer", + elements.ToArray(), + new[] { OnTerritoryChange }); + _pluginLog.Information($"Created {elements.Count} splatoon elements."); + } + catch (Exception e) + { + _pluginLog.Error(e, "Unable to create splatoon layer"); + } + }); + } + public void Dispose() { + _clientState.TerritoryChanged -= TerritoryChanged; + Splatoon.RemoveDynamicElements("GatheringPathRenderer"); + ECommonsMain.Dispose(); + + _pluginInterface.GetIpcSubscriber("Questionable.ReloadData") + .Unsubscribe(Reload); } } diff --git a/GatheringPathRenderer/packages.lock.json b/GatheringPathRenderer/packages.lock.json index 0c669ebf..c7a267af 100644 --- a/GatheringPathRenderer/packages.lock.json +++ b/GatheringPathRenderer/packages.lock.json @@ -75,6 +75,34 @@ "Microsoft.Build.Tasks.Git": "1.1.1", "Microsoft.SourceLink.Common": "1.1.1" } + }, + "System.Text.Encodings.Web": { + "type": "Transitive", + "resolved": "8.0.0", + "contentHash": "yev/k9GHAEGx2Rg3/tU6MQh4HGBXJs70y7j1LaM1i/ER9po+6nnQ6RRqTJn1E7Xu0fbIFK80Nh5EoODxrbxwBQ==" + }, + "System.Text.Json": { + "type": "Transitive", + "resolved": "8.0.4", + "contentHash": "bAkhgDJ88XTsqczoxEMliSrpijKZHhbJQldhAmObj/RbrN3sU5dcokuXmWJWsdQAhiMJ9bTayWsL1C9fbbCRhw==", + "dependencies": { + "System.Text.Encodings.Web": "8.0.0" + } + }, + "ecommons": { + "type": "Project" + }, + "gatheringpaths": { + "type": "Project", + "dependencies": { + "Questionable.Model": "[1.0.0, )" + } + }, + "questionable.model": { + "type": "Project", + "dependencies": { + "System.Text.Json": "[8.0.4, )" + } } } } diff --git a/GatheringPaths/6.x - Endwalker/Thavnair/820_Pewter Ore.json b/GatheringPaths/6.x - Endwalker/Thavnair/820_Pewter Ore.json index 425d77eb..de175725 100644 --- a/GatheringPaths/6.x - Endwalker/Thavnair/820_Pewter Ore.json +++ b/GatheringPaths/6.x - Endwalker/Thavnair/820_Pewter Ore.json @@ -3,54 +3,148 @@ "Author": "liza", "TerritoryId": 957, "AetheryteShortcut": "Thavnair - Great Work", - "Nodes": [ + "Groups": [ { - "DataId": 33918, - "Position": { - "X": -582.5132, - "Y": 40.54578, - "Z": -426.0171 - } + "Nodes": [ + { + "DataId": 33918, + "Locations": [ + { + "Position": { + "X": -582.5132, + "Y": 40.54578, + "Z": -426.0171 + }, + "MinimumAngle": -50, + "MaximumAngle": 90 + } + ] + }, + { + "DataId": 33919, + "Locations": [ + { + "Position": { + "X": -578.2101, + "Y": 41.27147, + "Z": -447.6376 + }, + "MinimumAngle": 130, + "MaximumAngle": 220 + }, + { + "Position": { + "X": -546.2882, + "Y": 44.52267, + "Z": -435.8184 + }, + "MinimumAngle": 200, + "MaximumAngle": 360 + } + ] + } + ] }, { - "DataId": 33919, - "Position": { - "X": -578.2101, - "Y": 41.27147, - "Z": -447.6376 - } + "Nodes": [ + { + "DataId": 33920, + "Locations": [ + { + "Position": { + "X": -488.2276, + "Y": 34.71221, + "Z": -359.6945 + }, + "MinimumAngle": 20, + "MaximumAngle": 128, + "MinimumDistance": 1.3 + } + ] + }, + { + "DataId": 33921, + "Locations": [ + { + "Position": { + "X": -498.8687, + "Y": 31.08014, + "Z": -351.9397 + }, + "MinimumAngle": 40, + "MaximumAngle": 190 + }, + { + "Position": { + "X": -490.7759, + "Y": 28.70215, + "Z": -344.4114 + }, + "MinimumAngle": -110, + "MaximumAngle": 60 + }, + { + "Position": { + "X": -494.1286, + "Y": 32.89971, + "Z": -355.0208 + }, + "MinimumAngle": 80, + "MaximumAngle": 230 + } + ] + } + ] }, { - "DataId": 33920, - "Position": { - "X": -488.2276, - "Y": 34.71221, - "Z": -359.6945 - } - }, - { - "DataId": 33921, - "Position": { - "X": -498.8687, - "Y": 31.08014, - "Z": -351.9397 - } - }, - { - "DataId": 33922, - "Position": { - "X": -304.0609, - "Y": 68.76999, - "Z": -479.1875 - } - }, - { - "DataId": 33923, - "Position": { - "X": -293.6989, - "Y": 68.77935, - "Z": -484.2256 - } + "Nodes": [ + { + "DataId": 33922, + "Locations": [ + { + "Position": { + "X": -304.0609, + "Y": 68.76999, + "Z": -479.1875 + }, + "MinimumAngle": -110, + "MaximumAngle": 70 + } + ] + }, + { + "DataId": 33923, + "Locations": [ + { + "Position": { + "X": -293.6989, + "Y": 68.77935, + "Z": -484.2256 + }, + "MinimumAngle": -30, + "MaximumAngle": 110 + }, + { + "Position": { + "X": -295.0806, + "Y": 69.12621, + "Z": -498.1898 + }, + "MinimumAngle": 10, + "MaximumAngle": 200 + }, + { + "Position": { + "X": -281.4858, + "Y": 67.64153, + "Z": -477.6673 + }, + "MinimumAngle": -90, + "MaximumAngle": 60 + } + ] + } + ] } ] } diff --git a/GatheringPaths/AssemblyGatheringLocationLoader.cs b/GatheringPaths/AssemblyGatheringLocationLoader.cs index 04176410..e74e59f8 100644 --- a/GatheringPaths/AssemblyGatheringLocationLoader.cs +++ b/GatheringPaths/AssemblyGatheringLocationLoader.cs @@ -16,12 +16,10 @@ public static partial class AssemblyGatheringLocationLoader if (_locations == null) { _locations = []; -#if RELEASE LoadLocations(); -#endif } - return _locations ?? throw new InvalidOperationException("quest data is not initialized"); + return _locations ?? throw new InvalidOperationException("location data is not initialized"); } public static Stream QuestSchema => diff --git a/GatheringPaths/GatheringPaths.csproj b/GatheringPaths/GatheringPaths.csproj index f9e9725f..8a5f3291 100644 --- a/GatheringPaths/GatheringPaths.csproj +++ b/GatheringPaths/GatheringPaths.csproj @@ -26,7 +26,7 @@ - + diff --git a/GatheringPaths/gatheringlocation-v1.json b/GatheringPaths/gatheringlocation-v1.json index 53b34f74..cba558a6 100644 --- a/GatheringPaths/gatheringlocation-v1.json +++ b/GatheringPaths/gatheringlocation-v1.json @@ -25,41 +25,64 @@ "AetheryteShortcut": { "$ref": "https://git.carvel.li/liza/Questionable/raw/branch/master/Questionable.Model/common-schema.json#/$defs/Aetheryte" }, - "Nodes": { + "Groups": { "type": "array", "items": { "type": "object", "properties": { - "DataId": { - "type": "number", - "minimum": 30000, - "maximum": 50000 - }, - "Position": { - "$ref": "#/$defs/Vector3" - }, - "MinimumAngle": { - "type": "number", - "minimum": -360, - "maximum": 360 - }, - "MaximumAngle": { - "type": "number", - "minimum": -360, - "maximum": 360 - }, - "MinimumDistance": { - "type": "number", - "minimum": 0 - }, - "MaximumDistance": { - "type": "number", - "exclusiveMinimum": 0 + "Nodes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "DataId": { + "type": "number", + "minimum": 30000, + "maximum": 50000 + }, + "Locations": { + "type": "array", + "items": { + "type": "object", + "properties": { + "Position": { + "$ref": "#/$defs/Vector3" + }, + "MinimumAngle": { + "type": "number", + "minimum": -360, + "maximum": 360 + }, + "MaximumAngle": { + "type": "number", + "minimum": -360, + "maximum": 360 + }, + "MinimumDistance": { + "type": "number", + "minimum": 0 + }, + "MaximumDistance": { + "type": "number", + "exclusiveMinimum": 0 + } + }, + "required": [ + "Position" + ], + "additionalProperties": false + } + } + }, + "required": [ + "DataId" + ], + "additionalProperties": false + } } }, "required": [ - "DataId", - "Position" + "Nodes" ], "additionalProperties": false } diff --git a/QuestPathGenerator/GatheringSourceGenerator.cs b/QuestPathGenerator/GatheringSourceGenerator.cs index a10acd0e..4995c3e4 100644 --- a/QuestPathGenerator/GatheringSourceGenerator.cs +++ b/QuestPathGenerator/GatheringSourceGenerator.cs @@ -153,7 +153,7 @@ public class GatheringSourceGenerator : ISourceGenerator Assignment(nameof(GatheringRoot.TerritoryId), root.TerritoryId, default) .AsSyntaxNodeOrToken(), Assignment(nameof(GatheringRoot.AetheryteShortcut), root.AetheryteShortcut, null), - AssignmentList(nameof(GatheringRoot.Nodes), root.Nodes).AsSyntaxNodeOrToken())))); + AssignmentList(nameof(GatheringRoot.Groups), root.Groups).AsSyntaxNodeOrToken())))); } catch (Exception e) { diff --git a/QuestPathGenerator/RoslynShortcuts.cs b/QuestPathGenerator/RoslynShortcuts.cs index 4f5a8fb0..07b82912 100644 --- a/QuestPathGenerator/RoslynShortcuts.cs +++ b/QuestPathGenerator/RoslynShortcuts.cs @@ -314,30 +314,55 @@ public static class RoslynShortcuts Assignment(nameof(SkipAetheryteCondition.InSameTerritory), skipAetheryteCondition.InSameTerritory, emptyAetheryte.InSameTerritory))))); } - else if (value is GatheringNodeLocation nodeLocation) + else if (value is GatheringNodeGroup nodeGroup) { - var emptyLocation = new GatheringNodeLocation(); return ObjectCreationExpression( - IdentifierName(nameof(GatheringNodeLocation))) + IdentifierName(nameof(GatheringNodeGroup))) .WithInitializer( InitializerExpression( SyntaxKind.ObjectInitializerExpression, SeparatedList( SyntaxNodeList( - Assignment(nameof(GatheringNodeLocation.DataId), nodeLocation.DataId, + AssignmentList(nameof(GatheringNodeGroup.Nodes), nodeGroup.Nodes) + .AsSyntaxNodeOrToken())))); + } + else if (value is GatheringNode nodeLocation) + { + var emptyLocation = new GatheringNode(); + return ObjectCreationExpression( + IdentifierName(nameof(GatheringNode))) + .WithInitializer( + InitializerExpression( + SyntaxKind.ObjectInitializerExpression, + SeparatedList( + SyntaxNodeList( + Assignment(nameof(GatheringNode.DataId), nodeLocation.DataId, emptyLocation.DataId) .AsSyntaxNodeOrToken(), - Assignment(nameof(GatheringNodeLocation.Position), nodeLocation.Position, + AssignmentList(nameof(GatheringNode.Locations), nodeLocation.Locations) + .AsSyntaxNodeOrToken())))); + } + else if (value is GatheringLocation location) + { + var emptyLocation = new GatheringLocation(); + return ObjectCreationExpression( + IdentifierName(nameof(GatheringLocation))) + .WithInitializer( + InitializerExpression( + SyntaxKind.ObjectInitializerExpression, + SeparatedList( + SyntaxNodeList( + Assignment(nameof(GatheringLocation.Position), location.Position, emptyLocation.Position).AsSyntaxNodeOrToken(), - Assignment(nameof(GatheringNodeLocation.MinimumAngle), nodeLocation.MinimumAngle, + Assignment(nameof(GatheringLocation.MinimumAngle), location.MinimumAngle, emptyLocation.MinimumAngle).AsSyntaxNodeOrToken(), - Assignment(nameof(GatheringNodeLocation.MaximumAngle), nodeLocation.MaximumAngle, + Assignment(nameof(GatheringLocation.MaximumAngle), location.MaximumAngle, emptyLocation.MaximumAngle).AsSyntaxNodeOrToken(), - Assignment(nameof(GatheringNodeLocation.MinimumDistance), - nodeLocation.MinimumDistance, emptyLocation.MinimumDistance) + Assignment(nameof(GatheringLocation.MinimumDistance), + location.MinimumDistance, emptyLocation.MinimumDistance) .AsSyntaxNodeOrToken(), - Assignment(nameof(GatheringNodeLocation.MaximumDistance), - nodeLocation.MaximumDistance, emptyLocation.MaximumDistance) + Assignment(nameof(GatheringLocation.MaximumDistance), + location.MaximumDistance, emptyLocation.MaximumDistance) .AsSyntaxNodeOrToken())))); } else if (value is null) diff --git a/QuestPathGenerator/Utils.cs b/QuestPathGenerator/Utils.cs index 12873a71..5e1baac0 100644 --- a/QuestPathGenerator/Utils.cs +++ b/QuestPathGenerator/Utils.cs @@ -55,12 +55,13 @@ public static class Utils Culture = CultureInfo.InvariantCulture, OutputFormat = OutputFormat.List, }); - if (!evaluationResult.IsValid) + if (evaluationResult.HasErrors) { var error = Diagnostic.Create(invalidJson, null, Path.GetFileName(additionalFile.Path)); context.ReportDiagnostic(error); + continue; } yield return (id, node); diff --git a/Questionable.Model/Gathering/GatheringLocation.cs b/Questionable.Model/Gathering/GatheringLocation.cs new file mode 100644 index 00000000..5d14a55d --- /dev/null +++ b/Questionable.Model/Gathering/GatheringLocation.cs @@ -0,0 +1,21 @@ +using System.Numerics; +using System.Text.Json.Serialization; +using Questionable.Model.Common.Converter; + +namespace Questionable.Model.Gathering; + +public sealed class GatheringLocation +{ + [JsonConverter(typeof(VectorConverter))] + public Vector3 Position { get; set; } + + public float? MinimumAngle { get; set; } + public float? MaximumAngle { get; set; } + public float MinimumDistance { get; set; } = 1f; + public float MaximumDistance { get; set; } = 3f; + + public bool IsCone() + { + return MinimumAngle != null && MaximumAngle != null; + } +} diff --git a/Questionable.Model/Gathering/GatheringNode.cs b/Questionable.Model/Gathering/GatheringNode.cs new file mode 100644 index 00000000..a88f53eb --- /dev/null +++ b/Questionable.Model/Gathering/GatheringNode.cs @@ -0,0 +1,10 @@ +using System.Collections.Generic; + +namespace Questionable.Model.Gathering; + +public sealed class GatheringNode +{ + public uint DataId { get; set; } + + public List Locations { get; set; } = []; +} diff --git a/Questionable.Model/Gathering/GatheringNodeGroup.cs b/Questionable.Model/Gathering/GatheringNodeGroup.cs new file mode 100644 index 00000000..7922d625 --- /dev/null +++ b/Questionable.Model/Gathering/GatheringNodeGroup.cs @@ -0,0 +1,8 @@ +using System.Collections.Generic; + +namespace Questionable.Model.Gathering; + +public sealed class GatheringNodeGroup +{ + public List Nodes { get; set; } = []; +} diff --git a/Questionable.Model/Gathering/GatheringNodeLocation.cs b/Questionable.Model/Gathering/GatheringNodeLocation.cs deleted file mode 100644 index 49a5e640..00000000 --- a/Questionable.Model/Gathering/GatheringNodeLocation.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System.Numerics; - -namespace Questionable.Model.Gathering; - -public sealed class GatheringNodeLocation -{ - public uint DataId { get; set; } - public Vector3 Position { get; set; } - public float? MinimumAngle { get; set; } - public float? MaximumAngle { get; set; } - public float? MinimumDistance { get; set; } = 0.5f; - public float? MaximumDistance { get; set; } = 3f; -} diff --git a/Questionable.Model/Gathering/GatheringRoot.cs b/Questionable.Model/Gathering/GatheringRoot.cs index c572faab..5670482e 100644 --- a/Questionable.Model/Gathering/GatheringRoot.cs +++ b/Questionable.Model/Gathering/GatheringRoot.cs @@ -14,5 +14,5 @@ public sealed class GatheringRoot [JsonConverter(typeof(AetheryteConverter))] public EAetheryteLocation? AetheryteShortcut { get; set; } - public List Nodes { get; set; } = []; + public List Groups { get; set; } = []; } diff --git a/Questionable.sln b/Questionable.sln index b5314287..7ca82fc8 100644 --- a/Questionable.sln +++ b/Questionable.sln @@ -19,6 +19,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GatheringPaths", "Gathering EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GatheringPathRenderer", "GatheringPathRenderer\GatheringPathRenderer.csproj", "{F514DA95-9867-4F3F-8062-ACE0C62E8740}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ECommons", "vendor\ECommons\ECommons\ECommons.csproj", "{A12D7B4B-8E6E-4DCF-A41A-12F62E9FF94B}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 @@ -57,6 +59,10 @@ Global {F514DA95-9867-4F3F-8062-ACE0C62E8740}.Debug|x64.Build.0 = Debug|Any CPU {F514DA95-9867-4F3F-8062-ACE0C62E8740}.Release|x64.ActiveCfg = Release|Any CPU {F514DA95-9867-4F3F-8062-ACE0C62E8740}.Release|x64.Build.0 = Release|Any CPU + {A12D7B4B-8E6E-4DCF-A41A-12F62E9FF94B}.Debug|x64.ActiveCfg = Debug|x64 + {A12D7B4B-8E6E-4DCF-A41A-12F62E9FF94B}.Debug|x64.Build.0 = Debug|x64 + {A12D7B4B-8E6E-4DCF-A41A-12F62E9FF94B}.Release|x64.ActiveCfg = Release|x64 + {A12D7B4B-8E6E-4DCF-A41A-12F62E9FF94B}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Questionable/Controller/QuestRegistry.cs b/Questionable/Controller/QuestRegistry.cs index f472c115..038fe129 100644 --- a/Questionable/Controller/QuestRegistry.cs +++ b/Questionable/Controller/QuestRegistry.cs @@ -8,6 +8,7 @@ using System.Linq; using System.Text.Json; using System.Text.Json.Nodes; using Dalamud.Plugin; +using Dalamud.Plugin.Ipc; using Microsoft.Extensions.Logging; using Questionable.Data; using Questionable.Model; @@ -23,8 +24,9 @@ internal sealed class QuestRegistry private readonly IDalamudPluginInterface _pluginInterface; private readonly QuestData _questData; private readonly QuestValidator _questValidator; - private readonly ILogger _logger; private readonly JsonSchemaValidator _jsonSchemaValidator; + private readonly ILogger _logger; + private readonly ICallGateProvider _reloadDataIpc; private readonly Dictionary _quests = new(); @@ -37,6 +39,7 @@ internal sealed class QuestRegistry _questValidator = questValidator; _jsonSchemaValidator = jsonSchemaValidator; _logger = logger; + _reloadDataIpc = _pluginInterface.GetIpcProvider("Questionable.ReloadData"); } public IEnumerable AllQuests => _quests.Values; @@ -66,6 +69,7 @@ internal sealed class QuestRegistry ValidateQuests(); Reloaded?.Invoke(this, EventArgs.Empty); + _reloadDataIpc.SendMessage(); _logger.LogInformation("Loaded {Count} quests in total", _quests.Count); } diff --git a/vendor/ECommons b/vendor/ECommons new file mode 160000 index 00000000..9e90d003 --- /dev/null +++ b/vendor/ECommons @@ -0,0 +1 @@ +Subproject commit 9e90d0032f0efd4c9e65d9c5a8e8bd0e99557d68 From ff7ee27fde3644f8ad81296328dc426c6a259c03 Mon Sep 17 00:00:00 2001 From: Liza Carvelli Date: Sat, 3 Aug 2024 03:21:11 +0200 Subject: [PATCH 10/12] GE update --- GatheringPathRenderer/EditorCommands.cs | 218 ++++++++++++++++++ GatheringPathRenderer/RendererPlugin.cs | 181 ++++++++++----- GatheringPathRenderer/Windows/EditorWindow.cs | 190 +++++++++++++++ GatheringPaths/7.x - Dawntrail/.gitkeep | 0 .../Urqopacha/974_Mountain Chromite Ore.json | 112 +++++++++ .../Urqopacha/992_Snow Cotton.json | 95 ++++++++ .../Urqopacha/993_Turali Aloe.json | 95 ++++++++ GatheringPaths/gatheringlocation-v1.json | 3 +- .../Common/Converter/VectorConverter.cs | 4 +- Questionable.Model/ExpansionVersion.cs | 16 ++ .../Gathering/GatheringLocation.cs | 17 +- Questionable/Controller/QuestRegistry.cs | 33 ++- 12 files changed, 883 insertions(+), 81 deletions(-) create mode 100644 GatheringPathRenderer/EditorCommands.cs create mode 100644 GatheringPathRenderer/Windows/EditorWindow.cs delete mode 100644 GatheringPaths/7.x - Dawntrail/.gitkeep create mode 100644 GatheringPaths/7.x - Dawntrail/Urqopacha/974_Mountain Chromite Ore.json create mode 100644 GatheringPaths/7.x - Dawntrail/Urqopacha/992_Snow Cotton.json create mode 100644 GatheringPaths/7.x - Dawntrail/Urqopacha/993_Turali Aloe.json create mode 100644 Questionable.Model/ExpansionVersion.cs diff --git a/GatheringPathRenderer/EditorCommands.cs b/GatheringPathRenderer/EditorCommands.cs new file mode 100644 index 00000000..d5008b27 --- /dev/null +++ b/GatheringPathRenderer/EditorCommands.cs @@ -0,0 +1,218 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Numerics; +using System.Text.Json; +using System.Text.Json.Nodes; +using System.Text.Json.Serialization; +using System.Text.Json.Serialization.Metadata; +using Dalamud.Game.ClientState.Objects; +using Dalamud.Game.ClientState.Objects.Enums; +using Dalamud.Game.ClientState.Objects.Types; +using Dalamud.Game.Command; +using Dalamud.Plugin.Services; +using Lumina.Excel.GeneratedSheets; +using Questionable.Model; +using Questionable.Model.Gathering; + +namespace GatheringPathRenderer; + +internal sealed class EditorCommands : IDisposable +{ + private readonly RendererPlugin _plugin; + private readonly IDataManager _dataManager; + private readonly ICommandManager _commandManager; + private readonly ITargetManager _targetManager; + private readonly IClientState _clientState; + private readonly IChatGui _chatGui; + + public EditorCommands(RendererPlugin plugin, IDataManager dataManager, ICommandManager commandManager, + ITargetManager targetManager, IClientState clientState, IChatGui chatGui) + { + _plugin = plugin; + _dataManager = dataManager; + _commandManager = commandManager; + _targetManager = targetManager; + _clientState = clientState; + _chatGui = chatGui; + + _commandManager.AddHandler("/qg", new CommandInfo(ProcessCommand)); + } + + private void ProcessCommand(string command, string argument) + { + string[] parts = argument.Split(' '); + string subCommand = parts[0]; + List arguments = parts.Skip(1).ToList(); + + try + { + switch (subCommand) + { + case "add": + CreateOrAddLocationToGroup(arguments); + break; + } + } + catch (Exception e) + { + _chatGui.PrintError(e.ToString(), "qG"); + } + } + + private void CreateOrAddLocationToGroup(List arguments) + { + var target = _targetManager.Target; + if (target == null || target.ObjectKind != ObjectKind.GatheringPoint) + throw new Exception("No valid target"); + + var gatheringPoint = _dataManager.GetExcelSheet()!.GetRow(target.DataId); + if (gatheringPoint == null) + throw new Exception("Invalid gathering point"); + + FileInfo targetFile; + GatheringRoot root; + var locationsInTerritory = _plugin.GetLocationsInTerritory(_clientState.TerritoryType).ToList(); + var location = locationsInTerritory.SingleOrDefault(x => x.Id == gatheringPoint.GatheringPointBase.Row); + if (location != null) + { + targetFile = location.File; + root = location.Root; + + // if this is an existing node, ignore it + var existingNode = root.Groups.SelectMany(x => x.Nodes.Where(y => y.DataId == target.DataId)) + .Any(x => x.Locations.Any(y => Vector3.Distance(y.Position, target.Position) < 0.1f)); + if (existingNode) + throw new Exception("Node already exists"); + + if (arguments.Contains("group")) + AddToNewGroup(root, target); + else + AddToExistingGroup(root, target); + } + else + { + (targetFile, root) = CreateNewFile(gatheringPoint, target, string.Join(" ", arguments)); + _chatGui.Print($"Creating new file under {targetFile.FullName}", "qG"); + } + + _plugin.Save(targetFile, root); + } + + public void AddToNewGroup(GatheringRoot root, IGameObject target) + { + root.Groups.Add(new GatheringNodeGroup + { + Nodes = + [ + new GatheringNode + { + DataId = target.DataId, + Locations = + [ + new GatheringLocation + { + Position = target.Position, + } + ] + } + ] + }); + _chatGui.Print("Added group.", "qG"); + } + + public void AddToExistingGroup(GatheringRoot root, IGameObject target) + { + // find the same data id + var node = root.Groups.SelectMany(x => x.Nodes) + .SingleOrDefault(x => x.DataId == target.DataId); + if (node != null) + { + node.Locations.Add(new GatheringLocation + { + Position = target.Position, + }); + _chatGui.Print($"Added location to existing node {target.DataId}.", "qG"); + } + else + { + // find the closest group + var closestGroup = root.Groups + .Select(group => new + { + Group = group, + Distance = group.Nodes.Min(x => + x.Locations.Min(y => + Vector3.Distance(_clientState.LocalPlayer!.Position, y.Position))) + }) + .OrderBy(x => x.Distance) + .First(); + + closestGroup.Group.Nodes.Add(new GatheringNode + { + DataId = target.DataId, + Locations = + [ + new GatheringLocation + { + Position = target.Position, + } + ] + }); + _chatGui.Print($"Added new node {target.DataId}.", "qG"); + } + } + + public (FileInfo targetFile, GatheringRoot root) CreateNewFile(GatheringPoint gatheringPoint, IGameObject target, + string fileName) + { + if (string.IsNullOrEmpty(fileName)) + throw new ArgumentException(nameof(fileName)); + + // determine target folder + DirectoryInfo? targetFolder = _plugin.GetLocationsInTerritory(_clientState.TerritoryType).FirstOrDefault() + ?.File.Directory; + if (targetFolder == null) + { + var territoryInfo = _dataManager.GetExcelSheet()!.GetRow(_clientState.TerritoryType)!; + targetFolder = _plugin.PathsDirectory + .CreateSubdirectory(ExpansionData.ExpansionFolders[(byte)territoryInfo.ExVersion.Row]) + .CreateSubdirectory(territoryInfo.PlaceName.Value!.Name.ToString()); + } + + FileInfo targetFile = + new FileInfo( + Path.Combine(targetFolder.FullName, $"{gatheringPoint.GatheringPointBase.Row}_{fileName}.json")); + var root = new GatheringRoot + { + TerritoryId = _clientState.TerritoryType, + Groups = + [ + new GatheringNodeGroup + { + Nodes = + [ + new GatheringNode + { + DataId = target.DataId, + Locations = + [ + new GatheringLocation + { + Position = target.Position + } + ] + } + ] + } + ] + }; + return (targetFile, root); + } + + public void Dispose() + { + _commandManager.RemoveHandler("/qg"); + } +} diff --git a/GatheringPathRenderer/RendererPlugin.cs b/GatheringPathRenderer/RendererPlugin.cs index 9c9a50d2..8e1c864b 100644 --- a/GatheringPathRenderer/RendererPlugin.cs +++ b/GatheringPathRenderer/RendererPlugin.cs @@ -4,11 +4,16 @@ using System.IO; using System.Linq; using System.Text.Json; using System.Text.Json.Nodes; +using System.Text.Json.Serialization; +using Dalamud.Game.ClientState.Objects; +using Dalamud.Interface.Windowing; using Dalamud.Plugin; using Dalamud.Plugin.Services; using ECommons; using ECommons.Schedulers; using ECommons.SplatoonAPI; +using GatheringPathRenderer.Windows; +using Questionable.Model; using Questionable.Model.Gathering; namespace GatheringPathRenderer; @@ -16,73 +21,83 @@ namespace GatheringPathRenderer; public sealed class RendererPlugin : IDalamudPlugin { private const long OnTerritoryChange = -2; + + private readonly WindowSystem _windowSystem = new(nameof(RendererPlugin)); + private readonly List _colors = [0xFFFF2020, 0xFF20FF20, 0xFF2020FF, 0xFFFFFF20, 0xFFFF20FF, 0xFF20FFFF]; + private readonly IDalamudPluginInterface _pluginInterface; private readonly IClientState _clientState; private readonly IPluginLog _pluginLog; - private readonly List<(ushort Id, GatheringRoot Root)> _gatheringLocations = []; - public RendererPlugin(IDalamudPluginInterface pluginInterface, IClientState clientState, IPluginLog pluginLog) + private readonly EditorCommands _editorCommands; + private readonly EditorWindow _editorWindow; + + private readonly List _gatheringLocations = []; + + public RendererPlugin(IDalamudPluginInterface pluginInterface, IClientState clientState, + ICommandManager commandManager, IDataManager dataManager, ITargetManager targetManager, IChatGui chatGui, + IPluginLog pluginLog) { _pluginInterface = pluginInterface; _clientState = clientState; _pluginLog = pluginLog; + _editorCommands = new EditorCommands(this, dataManager, commandManager, targetManager, clientState, chatGui); + _editorWindow = new EditorWindow(this, _editorCommands, dataManager, targetManager, clientState) { IsOpen = true }; + _windowSystem.AddWindow(_editorWindow); + _pluginInterface.GetIpcSubscriber("Questionable.ReloadData") .Subscribe(Reload); ECommonsMain.Init(pluginInterface, this, Module.SplatoonAPI); LoadGatheringLocationsFromDirectory(); + _pluginInterface.UiBuilder.Draw += _windowSystem.Draw; _clientState.TerritoryChanged += TerritoryChanged; if (_clientState.IsLoggedIn) TerritoryChanged(_clientState.TerritoryType); } - private void Reload() + internal DirectoryInfo PathsDirectory + { + get + { + DirectoryInfo? solutionDirectory = _pluginInterface.AssemblyLocation.Directory?.Parent?.Parent?.Parent; + if (solutionDirectory != null) + { + DirectoryInfo pathProjectDirectory = + new DirectoryInfo(Path.Combine(solutionDirectory.FullName, "GatheringPaths")); + if (pathProjectDirectory.Exists) + return pathProjectDirectory; + } + + throw new Exception("Unable to resolve project path"); + } + } + + internal void Reload() { LoadGatheringLocationsFromDirectory(); - TerritoryChanged(_clientState.TerritoryType); + Redraw(); } private void LoadGatheringLocationsFromDirectory() { _gatheringLocations.Clear(); - DirectoryInfo? solutionDirectory = _pluginInterface.AssemblyLocation.Directory?.Parent?.Parent?.Parent; - if (solutionDirectory != null) + try { - DirectoryInfo pathProjectDirectory = - new DirectoryInfo(Path.Combine(solutionDirectory.FullName, "GatheringPaths")); - if (pathProjectDirectory.Exists) - { - try - { - LoadFromDirectory( - new DirectoryInfo(Path.Combine(pathProjectDirectory.FullName, "2.x - A Realm Reborn"))); - LoadFromDirectory( - new DirectoryInfo(Path.Combine(pathProjectDirectory.FullName, "3.x - Heavensward"))); - LoadFromDirectory( - new DirectoryInfo(Path.Combine(pathProjectDirectory.FullName, "4.x - Stormblood"))); - LoadFromDirectory( - new DirectoryInfo(Path.Combine(pathProjectDirectory.FullName, "5.x - Shadowbringers"))); - LoadFromDirectory( - new DirectoryInfo(Path.Combine(pathProjectDirectory.FullName, "6.x - Endwalker"))); - LoadFromDirectory( - new DirectoryInfo(Path.Combine(pathProjectDirectory.FullName, "7.x - Dawntrail"))); + foreach (var expansionFolder in ExpansionData.ExpansionFolders.Values) + LoadFromDirectory( + new DirectoryInfo(Path.Combine(PathsDirectory.FullName, expansionFolder))); - _pluginLog.Information( - $"Loaded {_gatheringLocations.Count} gathering root locations from project directory"); - } - catch (Exception e) - { - _pluginLog.Error(e, "Failed to load quests from project directory"); - } - } - else - _pluginLog.Warning($"Project directory {pathProjectDirectory} does not exist"); + _pluginLog.Information( + $"Loaded {_gatheringLocations.Count} gathering root locations from project directory"); + } + catch (Exception e) + { + _pluginLog.Error(e, "Failed to load paths from project directory"); } - else - _pluginLog.Warning($"Solution directory {solutionDirectory} does not exist"); } private void LoadFromDirectory(DirectoryInfo directory) @@ -96,7 +111,7 @@ public sealed class RendererPlugin : IDalamudPlugin try { using FileStream stream = new FileStream(fileInfo.FullName, FileMode.Open, FileAccess.Read); - LoadLocationFromStream(fileInfo.Name, stream); + LoadLocationFromStream(fileInfo, stream); } catch (Exception e) { @@ -108,26 +123,78 @@ public sealed class RendererPlugin : IDalamudPlugin LoadFromDirectory(childDirectory); } - private void LoadLocationFromStream(string fileName, Stream stream) + private void LoadLocationFromStream(FileInfo fileInfo, Stream stream) { var locationNode = JsonNode.Parse(stream)!; GatheringRoot root = locationNode.Deserialize()!; - _gatheringLocations.Add((ushort.Parse(fileName.Split('_')[0]), root)); + _gatheringLocations.Add(new GatheringLocationContext(fileInfo, ushort.Parse(fileInfo.Name.Split('_')[0]), + root)); } - private void TerritoryChanged(ushort territoryId) + internal IEnumerable GetLocationsInTerritory(ushort territoryId) + => _gatheringLocations.Where(x => x.Root.TerritoryId == territoryId); + + internal void Save(FileInfo targetFile, GatheringRoot root) + { + JsonSerializerOptions options = new() + { + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault, + WriteIndented = true, + }; + using (var stream = File.Create(targetFile.FullName)) + { + var jsonNode = (JsonObject)JsonSerializer.SerializeToNode(root, options)!; + var newNode = new JsonObject(); + newNode.Add("$schema", + "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json"); + foreach (var (key, value) in jsonNode) + newNode.Add(key, value?.DeepClone()); + + using var writer = new Utf8JsonWriter(stream, new JsonWriterOptions + { + Indented = true + }); + newNode.WriteTo(writer, options); + } + + Reload(); + } + + private void TerritoryChanged(ushort territoryId) => Redraw(); + + internal void Redraw() { Splatoon.RemoveDynamicElements("GatheringPathRenderer"); - var elements = _gatheringLocations - .Where(x => x.Root.TerritoryId == territoryId) - .SelectMany(v => - v.Root.Groups.SelectMany(group => + var elements = GetLocationsInTerritory(_clientState.TerritoryType) + .SelectMany(location => + location.Root.Groups.SelectMany(group => group.Nodes.SelectMany(node => node.Locations .SelectMany(x => - new List + { + bool isCone = false; + int minimumAngle = 0; + int maximumAngle = 0; + if (_editorWindow.TryGetOverride(x.InternalId, out LocationOverride? locationOverride) && locationOverride != null) { - new Element(x.IsCone() + if (locationOverride.IsCone()) + { + isCone = true; + minimumAngle = locationOverride.MinimumAngle.GetValueOrDefault(); + maximumAngle = locationOverride.MaximumAngle.GetValueOrDefault(); + } + } + + if (!isCone && x.IsCone()) + { + isCone = true; + minimumAngle = x.MinimumAngle.GetValueOrDefault(); + maximumAngle = x.MaximumAngle.GetValueOrDefault(); + } + + return new List + { + new Element(isCone ? ElementType.ConeAtFixedCoordinates : ElementType.CircleAtFixedCoordinates) { @@ -135,12 +202,13 @@ public sealed class RendererPlugin : IDalamudPlugin refY = x.Position.Z, refZ = x.Position.Y, Filled = true, - radius = x.MinimumDistance, - Donut = x.MaximumDistance - x.MinimumDistance, - color = 0x2020FF80, + radius = x.CalculateMinimumDistance(), + Donut = x.CalculateMaximumDistance() - x.CalculateMinimumDistance(), + color = _colors[location.Root.Groups.IndexOf(group) % _colors.Count], Enabled = true, - coneAngleMin = x.IsCone() ? (int)x.MinimumAngle.GetValueOrDefault() : 0, - coneAngleMax = x.IsCone() ? (int)x.MaximumAngle.GetValueOrDefault() : 0 + coneAngleMin = minimumAngle, + coneAngleMax = maximumAngle, + tether = false, }, new Element(ElementType.CircleAtFixedCoordinates) { @@ -149,9 +217,11 @@ public sealed class RendererPlugin : IDalamudPlugin refZ = x.Position.Y, color = 0x00000000, Enabled = true, - overlayText = $"{v.Id} // {node.DataId} / {node.Locations.IndexOf(x)}" + overlayText = + $"{location.Root.Groups.IndexOf(group)} // {node.DataId} / {node.Locations.IndexOf(x)}", } - })))) + }; + })))) .ToList(); if (elements.Count == 0) @@ -179,11 +249,16 @@ public sealed class RendererPlugin : IDalamudPlugin public void Dispose() { _clientState.TerritoryChanged -= TerritoryChanged; + _pluginInterface.UiBuilder.Draw -= _windowSystem.Draw; Splatoon.RemoveDynamicElements("GatheringPathRenderer"); ECommonsMain.Dispose(); _pluginInterface.GetIpcSubscriber("Questionable.ReloadData") .Unsubscribe(Reload); + + _editorCommands.Dispose(); } + + internal sealed record GatheringLocationContext(FileInfo File, ushort Id, GatheringRoot Root); } diff --git a/GatheringPathRenderer/Windows/EditorWindow.cs b/GatheringPathRenderer/Windows/EditorWindow.cs new file mode 100644 index 00000000..ae8a77d3 --- /dev/null +++ b/GatheringPathRenderer/Windows/EditorWindow.cs @@ -0,0 +1,190 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Numerics; +using Dalamud.Game.ClientState.Objects; +using Dalamud.Game.ClientState.Objects.Enums; +using Dalamud.Game.ClientState.Objects.Types; +using Dalamud.Interface.Windowing; +using Dalamud.Plugin.Services; +using ImGuiNET; +using Lumina.Excel.GeneratedSheets; +using Questionable.Model.Gathering; + +namespace GatheringPathRenderer.Windows; + +internal sealed class EditorWindow : Window +{ + private readonly RendererPlugin _plugin; + private readonly EditorCommands _editorCommands; + private readonly IDataManager _dataManager; + private readonly ITargetManager _targetManager; + private readonly IClientState _clientState; + + private readonly Dictionary _changes = []; + + private IGameObject? _target; + private (RendererPlugin.GatheringLocationContext, GatheringLocation)? _targetLocation; + private string _newFileName = string.Empty; + + public EditorWindow(RendererPlugin plugin, EditorCommands editorCommands, IDataManager dataManager, + ITargetManager targetManager, IClientState clientState) + : base("Gathering Path Editor###QuestionableGatheringPathEditor") + { + _plugin = plugin; + _editorCommands = editorCommands; + _dataManager = dataManager; + _targetManager = targetManager; + _clientState = clientState; + + SizeConstraints = new WindowSizeConstraints + { + MinimumSize = new Vector2(300, 300), + }; + } + + public override void Update() + { + _target = _targetManager.Target; + if (_target == null || _target.ObjectKind != ObjectKind.GatheringPoint) + { + _targetLocation = null; + return; + } + + var gatheringLocations = _plugin.GetLocationsInTerritory(_clientState.TerritoryType); + var location = gatheringLocations.SelectMany(context => + context.Root.Groups.SelectMany(group => + group.Nodes + .Where(node => node.DataId == _target.DataId) + .SelectMany(node => node.Locations) + .Where(location => Vector3.Distance(location.Position, _target.Position) < 0.1f) + .Select(location => new { Context = context, Location = location }))) + .FirstOrDefault(); + if (location == null) + { + _targetLocation = null; + return; + } + + _targetLocation = (location.Context, location.Location); + } + + public override bool DrawConditions() + { + return _target != null || _targetLocation != null; + } + + public override void Draw() + { + if (_target != null && _targetLocation != null) + { + var context = _targetLocation.Value.Item1; + var location = _targetLocation.Value.Item2; + ImGui.Text(context.File.Directory?.Name ?? string.Empty); + ImGui.Indent(); + ImGui.Text(context.File.Name); + ImGui.Unindent(); + ImGui.Text($"{_target.DataId} // {location.InternalId}"); + ImGui.Text(string.Create(CultureInfo.InvariantCulture, $"{location.Position:G}")); + + if (!_changes.TryGetValue(location.InternalId, out LocationOverride? locationOverride)) + { + locationOverride = new LocationOverride(); + _changes[location.InternalId] = locationOverride; + } + + int minAngle = locationOverride.MinimumAngle ?? location.MinimumAngle.GetValueOrDefault(); + if (ImGui.DragInt("Min Angle", ref minAngle, 5, -180, 360)) + { + locationOverride.MinimumAngle = minAngle; + locationOverride.MaximumAngle ??= location.MaximumAngle.GetValueOrDefault(); + _plugin.Redraw(); + } + + int maxAngle = locationOverride.MaximumAngle ?? location.MaximumAngle.GetValueOrDefault(); + if (ImGui.DragInt("Max Angle", ref maxAngle, 5, -180, 360)) + { + locationOverride.MinimumAngle ??= location.MinimumAngle.GetValueOrDefault(); + locationOverride.MaximumAngle = maxAngle; + _plugin.Redraw(); + } + + ImGui.BeginDisabled(locationOverride.MinimumAngle == null && locationOverride.MaximumAngle == null); + if (ImGui.Button("Save")) + { + location.MinimumAngle = locationOverride.MinimumAngle; + location.MaximumAngle = locationOverride.MaximumAngle; + _plugin.Save(context.File, context.Root); + } + ImGui.SameLine(); + if (ImGui.Button("Reset")) + { + _changes[location.InternalId] = new LocationOverride(); + _plugin.Redraw(); + } + ImGui.EndDisabled(); + + } + else if (_target != null) + { + var gatheringPoint = _dataManager.GetExcelSheet()!.GetRow(_target.DataId); + if (gatheringPoint == null) + return; + + var locationsInTerritory = _plugin.GetLocationsInTerritory(_clientState.TerritoryType).ToList(); + var location = locationsInTerritory.SingleOrDefault(x => x.Id == gatheringPoint.GatheringPointBase.Row); + if (location != null) + { + var targetFile = location.File; + var root = location.Root; + + if (ImGui.Button("Add to closest group")) + { + _editorCommands.AddToExistingGroup(root, _target); + _plugin.Save(targetFile, root); + } + + ImGui.BeginDisabled(root.Groups.Any(group => group.Nodes.Any(node => node.DataId == _target.DataId))); + ImGui.SameLine(); + if (ImGui.Button("Add as new group")) + { + _editorCommands.AddToNewGroup(root, _target); + _plugin.Save(targetFile, root); + } + ImGui.EndDisabled(); + } + else + { + ImGui.InputText("File Name", ref _newFileName, 128); + ImGui.BeginDisabled(string.IsNullOrEmpty(_newFileName)); + if (ImGui.Button("Create location")) + { + var (targetFile, root) = _editorCommands.CreateNewFile(gatheringPoint, _target, _newFileName); + _plugin.Save(targetFile, root); + _newFileName = string.Empty; + } + + ImGui.EndDisabled(); + } + } + } + + public bool TryGetOverride(Guid internalId, out LocationOverride? locationOverride) + => _changes.TryGetValue(internalId, out locationOverride); +} + +internal class LocationOverride +{ + public int? MinimumAngle { get; set; } + public int? MaximumAngle { get; set; } + public float? MinimumDistance { get; set; } + public float? MaximumDistance { get; set; } + + public bool IsCone() + { + return MinimumAngle != null && MaximumAngle != null && MinimumAngle != MaximumAngle; + } +} diff --git a/GatheringPaths/7.x - Dawntrail/.gitkeep b/GatheringPaths/7.x - Dawntrail/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/GatheringPaths/7.x - Dawntrail/Urqopacha/974_Mountain Chromite Ore.json b/GatheringPaths/7.x - Dawntrail/Urqopacha/974_Mountain Chromite Ore.json new file mode 100644 index 00000000..83bd6138 --- /dev/null +++ b/GatheringPaths/7.x - Dawntrail/Urqopacha/974_Mountain Chromite Ore.json @@ -0,0 +1,112 @@ +{ + "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json", + "Author": [], + "TerritoryId": 1187, + "Groups": [ + { + "Nodes": [ + { + "DataId": 34749, + "Locations": [ + { + "Position": { + "X": -392.813, + "Y": -47.04364, + "Z": -386.862 + }, + "MinimumAngle": -10, + "MaximumAngle": 240 + } + ] + }, + { + "DataId": 34750, + "Locations": [ + { + "Position": { + "X": -402.8987, + "Y": -45.59287, + "Z": -390.7613 + }, + "MinimumAngle": 220, + "MaximumAngle": 305 + }, + { + "Position": { + "X": -388.9036, + "Y": -46.86702, + "Z": -381.3985 + }, + "MinimumAngle": -50, + "MaximumAngle": 210 + } + ] + } + ] + }, + { + "Nodes": [ + { + "DataId": 34753, + "Locations": [ + { + "Position": { + "X": -541.7726, + "Y": -22.952, + "Z": -517.8604 + }, + "MinimumAngle": 215, + "MaximumAngle": 330 + } + ] + }, + { + "DataId": 34754, + "Locations": [ + { + "Position": { + "X": -522.9433, + "Y": -25.87319, + "Z": -537.3257 + }, + "MinimumAngle": 225, + "MaximumAngle": 360 + } + ] + } + ] + }, + { + "Nodes": [ + { + "DataId": 34751, + "Locations": [ + { + "Position": { + "X": -448.8079, + "Y": -14.9586, + "Z": -658.0133 + }, + "MinimumAngle": -45, + "MaximumAngle": 115 + } + ] + }, + { + "DataId": 34752, + "Locations": [ + { + "Position": { + "X": -452.2813, + "Y": -12.43015, + "Z": -665.0275 + }, + "MinimumAngle": 0, + "MaximumAngle": 150 + } + ] + } + ] + } + ] +} diff --git a/GatheringPaths/7.x - Dawntrail/Urqopacha/992_Snow Cotton.json b/GatheringPaths/7.x - Dawntrail/Urqopacha/992_Snow Cotton.json new file mode 100644 index 00000000..7cf1be27 --- /dev/null +++ b/GatheringPaths/7.x - Dawntrail/Urqopacha/992_Snow Cotton.json @@ -0,0 +1,95 @@ +{ + "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json", + "Author": [], + "TerritoryId": 1187, + "Groups": [ + { + "Nodes": [ + { + "DataId": 34857, + "Locations": [ + { + "Position": { + "X": -12.48859, + "Y": -133.2091, + "Z": -427.7497 + } + } + ] + }, + { + "DataId": 34858, + "Locations": [ + { + "Position": { + "X": -22.41956, + "Y": -129.3952, + "Z": -396.6573 + } + } + ] + } + ] + }, + { + "Nodes": [ + { + "DataId": 34861, + "Locations": [ + { + "Position": { + "X": -234.8222, + "Y": -99.01237, + "Z": -376.7287 + }, + "MinimumAngle": -180, + "MaximumAngle": 40 + } + ] + }, + { + "DataId": 34862, + "Locations": [ + { + "Position": { + "X": -236.0182, + "Y": -97.50027, + "Z": -372.1523 + }, + "MinimumAngle": -180, + "MaximumAngle": 45 + } + ] + } + ] + }, + { + "Nodes": [ + { + "DataId": 34860, + "Locations": [ + { + "Position": { + "X": -169.8177, + "Y": -85.61841, + "Z": -240.1007 + } + } + ] + }, + { + "DataId": 34859, + "Locations": [ + { + "Position": { + "X": -131.9198, + "Y": -89.88039, + "Z": -249.5422 + } + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/GatheringPaths/7.x - Dawntrail/Urqopacha/993_Turali Aloe.json b/GatheringPaths/7.x - Dawntrail/Urqopacha/993_Turali Aloe.json new file mode 100644 index 00000000..e17f0f0d --- /dev/null +++ b/GatheringPaths/7.x - Dawntrail/Urqopacha/993_Turali Aloe.json @@ -0,0 +1,95 @@ +{ + "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json", + "Author": [], + "TerritoryId": 1187, + "Groups": [ + { + "Nodes": [ + { + "DataId": 34866, + "Locations": [ + { + "Position": { + "X": 242.7737, + "Y": -135.9734, + "Z": -431.2313 + } + } + ] + }, + { + "DataId": 34865, + "Locations": [ + { + "Position": { + "X": 269.7338, + "Y": -134.0488, + "Z": -381.6242 + } + } + ] + } + ] + }, + { + "Nodes": [ + { + "DataId": 34868, + "Locations": [ + { + "Position": { + "X": 389.1952, + "Y": -154.3099, + "Z": -368.3658 + }, + "MinimumAngle": 105, + "MaximumAngle": 345 + } + ] + }, + { + "DataId": 34867, + "Locations": [ + { + "Position": { + "X": 399.1297, + "Y": -152.1141, + "Z": -394.71 + }, + "MinimumAngle": 120, + "MaximumAngle": 330 + } + ] + } + ] + }, + { + "Nodes": [ + { + "DataId": 34864, + "Locations": [ + { + "Position": { + "X": 359.517, + "Y": -161.1972, + "Z": -644.0471 + } + } + ] + }, + { + "DataId": 34863, + "Locations": [ + { + "Position": { + "X": 323.8758, + "Y": -162.9682, + "Z": -648.8156 + } + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/GatheringPaths/gatheringlocation-v1.json b/GatheringPaths/gatheringlocation-v1.json index cba558a6..5c71b876 100644 --- a/GatheringPaths/gatheringlocation-v1.json +++ b/GatheringPaths/gatheringlocation-v1.json @@ -92,8 +92,7 @@ "$schema", "Author", "TerritoryId", - "AetheryteShortcut", - "Nodes" + "Groups" ], "additionalProperties": false, "$defs": { diff --git a/Questionable.Model/Common/Converter/VectorConverter.cs b/Questionable.Model/Common/Converter/VectorConverter.cs index 7b4833ef..868e0216 100644 --- a/Questionable.Model/Common/Converter/VectorConverter.cs +++ b/Questionable.Model/Common/Converter/VectorConverter.cs @@ -57,8 +57,8 @@ public sealed class VectorConverter : JsonConverter { writer.WriteStartObject(); writer.WriteNumber(nameof(Vector3.X), value.X); - writer.WriteNumber(nameof(Vector3.Y), value.X); - writer.WriteNumber(nameof(Vector3.Z), value.X); + writer.WriteNumber(nameof(Vector3.Y), value.Y); + writer.WriteNumber(nameof(Vector3.Z), value.Z); writer.WriteEndObject(); } } diff --git a/Questionable.Model/ExpansionVersion.cs b/Questionable.Model/ExpansionVersion.cs new file mode 100644 index 00000000..fe92f160 --- /dev/null +++ b/Questionable.Model/ExpansionVersion.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; + +namespace Questionable.Model; + +public static class ExpansionData +{ + public static IReadOnlyDictionary ExpansionFolders = new Dictionary() + { + { 0, "2.x - A Realm Reborn" }, + { 1, "3.x - Heavensward" }, + { 2, "4.x - Stormblood" }, + { 3, "5.x - Shadowbringers" }, + { 4, "6.x - Endwalker" }, + { 5, "7.x - Dawntrail" } + }; +} diff --git a/Questionable.Model/Gathering/GatheringLocation.cs b/Questionable.Model/Gathering/GatheringLocation.cs index 5d14a55d..badf7c2d 100644 --- a/Questionable.Model/Gathering/GatheringLocation.cs +++ b/Questionable.Model/Gathering/GatheringLocation.cs @@ -1,4 +1,5 @@ -using System.Numerics; +using System; +using System.Numerics; using System.Text.Json.Serialization; using Questionable.Model.Common.Converter; @@ -6,16 +7,22 @@ namespace Questionable.Model.Gathering; public sealed class GatheringLocation { + [JsonIgnore] + public Guid InternalId { get; } = Guid.NewGuid(); + [JsonConverter(typeof(VectorConverter))] public Vector3 Position { get; set; } - public float? MinimumAngle { get; set; } - public float? MaximumAngle { get; set; } - public float MinimumDistance { get; set; } = 1f; - public float MaximumDistance { get; set; } = 3f; + public int? MinimumAngle { get; set; } + public int? MaximumAngle { get; set; } + public float? MinimumDistance { get; set; } + public float? MaximumDistance { get; set; } public bool IsCone() { return MinimumAngle != null && MaximumAngle != null; } + + public float CalculateMinimumDistance() => MinimumDistance ?? 1f; + public float CalculateMaximumDistance() => MaximumDistance ?? 3f; } diff --git a/Questionable/Controller/QuestRegistry.cs b/Questionable/Controller/QuestRegistry.cs index 038fe129..da557891 100644 --- a/Questionable/Controller/QuestRegistry.cs +++ b/Questionable/Controller/QuestRegistry.cs @@ -69,7 +69,16 @@ internal sealed class QuestRegistry ValidateQuests(); Reloaded?.Invoke(this, EventArgs.Empty); - _reloadDataIpc.SendMessage(); + try + { + _reloadDataIpc.SendMessage(); + } + catch (Exception e) + { + // why does this even throw + _logger.LogWarning(e, "Error during Reload.SendMessage IPC"); + } + _logger.LogInformation("Loaded {Count} quests in total", _quests.Count); } @@ -105,24 +114,10 @@ internal sealed class QuestRegistry { try { - LoadFromDirectory( - new DirectoryInfo(Path.Combine(pathProjectDirectory.FullName, "2.x - A Realm Reborn")), - LogLevel.Trace); - LoadFromDirectory( - new DirectoryInfo(Path.Combine(pathProjectDirectory.FullName, "3.x - Heavensward")), - LogLevel.Trace); - LoadFromDirectory( - new DirectoryInfo(Path.Combine(pathProjectDirectory.FullName, "4.x - Stormblood")), - LogLevel.Trace); - LoadFromDirectory( - new DirectoryInfo(Path.Combine(pathProjectDirectory.FullName, "5.x - Shadowbringers")), - LogLevel.Trace); - LoadFromDirectory( - new DirectoryInfo(Path.Combine(pathProjectDirectory.FullName, "6.x - Endwalker")), - LogLevel.Trace); - LoadFromDirectory( - new DirectoryInfo(Path.Combine(pathProjectDirectory.FullName, "7.x - Dawntrail")), - LogLevel.Trace); + foreach (var expansionFolder in ExpansionData.ExpansionFolders.Values) + LoadFromDirectory( + new DirectoryInfo(Path.Combine(pathProjectDirectory.FullName, expansionFolder)), + LogLevel.Trace); } catch (Exception e) { From 82c20bf76d46f21b743f9b26e77c6aa5a8bb864a Mon Sep 17 00:00:00 2001 From: Liza Carvelli Date: Sat, 3 Aug 2024 11:17:20 +0200 Subject: [PATCH 11/12] Auto-Moving to gathering locations --- GatheringPathRenderer/RendererPlugin.cs | 32 +++- GatheringPathRenderer/Windows/EditorWindow.cs | 69 +++++-- .../Thavnair/820_Pewter Ore.json | 15 +- .../Urqopacha/974_Mountain Chromite Ore.json | 48 ++++- .../Urqopacha/992_Snow Cotton.json | 55 ++++++ .../Urqopacha/993_Turali Aloe.json | 55 +++++- .../MIN, BTN/4154_Cooking Up a Culture.json | 9 +- QuestPaths/quest-v1.json | 24 +++ Questionable.Model/GatheringMath.cs | 53 ++++++ Questionable.Model/Questing/GatheredItem.cs | 8 + Questionable.Model/Questing/QuestStep.cs | 1 + Questionable.sln.DotSettings | 1 + .../Controller/GatheringController.cs | 179 ++++++++++++++++++ Questionable/Controller/MiniTaskController.cs | 134 +++++++++++++ Questionable/Controller/QuestController.cs | 125 +++--------- .../Steps/Gathering/MoveToLandingLocation.cs | 64 +++++++ .../Controller/Steps/Gathering/WaitGather.cs | 25 +++ .../Controller/Steps/Interactions/Interact.cs | 21 +- .../Steps/Shared/GatheringRequiredItems.cs | 75 ++++++++ Questionable/Data/GatheringData.cs | 49 +++++ Questionable/GameFunctions.cs | 31 ++- Questionable/Questionable.csproj | 1 + Questionable/QuestionablePlugin.cs | 6 + .../QuestComponents/ActiveQuestComponent.cs | 17 +- .../RemainingTasksComponent.cs | 27 ++- Questionable/packages.lock.json | 6 + 26 files changed, 976 insertions(+), 154 deletions(-) create mode 100644 Questionable.Model/GatheringMath.cs create mode 100644 Questionable.Model/Questing/GatheredItem.cs create mode 100644 Questionable/Controller/GatheringController.cs create mode 100644 Questionable/Controller/MiniTaskController.cs create mode 100644 Questionable/Controller/Steps/Gathering/MoveToLandingLocation.cs create mode 100644 Questionable/Controller/Steps/Gathering/WaitGather.cs create mode 100644 Questionable/Controller/Steps/Shared/GatheringRequiredItems.cs create mode 100644 Questionable/Data/GatheringData.cs diff --git a/GatheringPathRenderer/RendererPlugin.cs b/GatheringPathRenderer/RendererPlugin.cs index 8e1c864b..ef2b352c 100644 --- a/GatheringPathRenderer/RendererPlugin.cs +++ b/GatheringPathRenderer/RendererPlugin.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using System.Security.Cryptography; using System.Text.Json; using System.Text.Json.Nodes; using System.Text.Json.Serialization; @@ -12,6 +13,7 @@ using Dalamud.Plugin.Services; using ECommons; using ECommons.Schedulers; using ECommons.SplatoonAPI; +using FFXIVClientStructs.FFXIV.Common.Math; using GatheringPathRenderer.Windows; using Questionable.Model; using Questionable.Model.Gathering; @@ -36,14 +38,15 @@ public sealed class RendererPlugin : IDalamudPlugin public RendererPlugin(IDalamudPluginInterface pluginInterface, IClientState clientState, ICommandManager commandManager, IDataManager dataManager, ITargetManager targetManager, IChatGui chatGui, - IPluginLog pluginLog) + IObjectTable objectTable, IPluginLog pluginLog) { _pluginInterface = pluginInterface; _clientState = clientState; _pluginLog = pluginLog; _editorCommands = new EditorCommands(this, dataManager, commandManager, targetManager, clientState, chatGui); - _editorWindow = new EditorWindow(this, _editorCommands, dataManager, targetManager, clientState) { IsOpen = true }; + _editorWindow = new EditorWindow(this, _editorCommands, dataManager, targetManager, clientState, objectTable) + { IsOpen = true }; _windowSystem.AddWindow(_editorWindow); _pluginInterface.GetIpcSubscriber("Questionable.ReloadData") @@ -175,7 +178,8 @@ public sealed class RendererPlugin : IDalamudPlugin bool isCone = false; int minimumAngle = 0; int maximumAngle = 0; - if (_editorWindow.TryGetOverride(x.InternalId, out LocationOverride? locationOverride) && locationOverride != null) + if (_editorWindow.TryGetOverride(x.InternalId, out LocationOverride? locationOverride) && + locationOverride != null) { if (locationOverride.IsCone()) { @@ -192,6 +196,8 @@ public sealed class RendererPlugin : IDalamudPlugin maximumAngle = x.MaximumAngle.GetValueOrDefault(); } + var a = GatheringMath.CalculateLandingLocation(x, 0, 0); + var b = GatheringMath.CalculateLandingLocation(x, 1, 1); return new List { new Element(isCone @@ -219,6 +225,26 @@ public sealed class RendererPlugin : IDalamudPlugin Enabled = true, overlayText = $"{location.Root.Groups.IndexOf(group)} // {node.DataId} / {node.Locations.IndexOf(x)}", + }, + new Element(ElementType.CircleAtFixedCoordinates) + { + refX = a.X, + refY = a.Z, + refZ = a.Y, + color = _colors[0], + radius = 0.1f, + Enabled = true, + overlayText = "Min Angle" + }, + new Element(ElementType.CircleAtFixedCoordinates) + { + refX = b.X, + refY = b.Z, + refZ = b.Y, + color = _colors[1], + radius = 0.1f, + Enabled = true, + overlayText = "Max Angle" } }; })))) diff --git a/GatheringPathRenderer/Windows/EditorWindow.cs b/GatheringPathRenderer/Windows/EditorWindow.cs index ae8a77d3..ec7293f6 100644 --- a/GatheringPathRenderer/Windows/EditorWindow.cs +++ b/GatheringPathRenderer/Windows/EditorWindow.cs @@ -22,15 +22,19 @@ internal sealed class EditorWindow : Window private readonly IDataManager _dataManager; private readonly ITargetManager _targetManager; private readonly IClientState _clientState; + private readonly IObjectTable _objectTable; private readonly Dictionary _changes = []; private IGameObject? _target; - private (RendererPlugin.GatheringLocationContext, GatheringLocation)? _targetLocation; + + private (RendererPlugin.GatheringLocationContext Context, GatheringNode Node, GatheringLocation Location)? + _targetLocation; + private string _newFileName = string.Empty; public EditorWindow(RendererPlugin plugin, EditorCommands editorCommands, IDataManager dataManager, - ITargetManager targetManager, IClientState clientState) + ITargetManager targetManager, IClientState clientState, IObjectTable objectTable) : base("Gathering Path Editor###QuestionableGatheringPathEditor") { _plugin = plugin; @@ -38,38 +42,44 @@ internal sealed class EditorWindow : Window _dataManager = dataManager; _targetManager = targetManager; _clientState = clientState; + _objectTable = objectTable; SizeConstraints = new WindowSizeConstraints { MinimumSize = new Vector2(300, 300), }; + ShowCloseButton = false; } public override void Update() { _target = _targetManager.Target; - if (_target == null || _target.ObjectKind != ObjectKind.GatheringPoint) - { - _targetLocation = null; - return; - } - var gatheringLocations = _plugin.GetLocationsInTerritory(_clientState.TerritoryType); var location = gatheringLocations.SelectMany(context => context.Root.Groups.SelectMany(group => group.Nodes - .Where(node => node.DataId == _target.DataId) - .SelectMany(node => node.Locations) - .Where(location => Vector3.Distance(location.Position, _target.Position) < 0.1f) - .Select(location => new { Context = context, Location = location }))) + .SelectMany(node => node.Locations + .Where(location => + { + if (_target != null) + return Vector3.Distance(location.Position, _target.Position) < 0.1f; + else + return Vector3.Distance(location.Position, _clientState.LocalPlayer!.Position) < 3f; + }) + .Select(location => new { Context = context, Node = node, Location = location })))) .FirstOrDefault(); - if (location == null) + if (_target != null && _target.ObjectKind != ObjectKind.GatheringPoint || location == null) { + _target = null; _targetLocation = null; return; } - _targetLocation = (location.Context, location.Location); + _target ??= _objectTable.FirstOrDefault( + x => x.ObjectKind == ObjectKind.GatheringPoint && + x.DataId == location.Node.DataId && + Vector3.Distance(location.Location.Position, _clientState.LocalPlayer!.Position) < 3f); + _targetLocation = (location.Context, location.Node, location.Location); } public override bool DrawConditions() @@ -81,8 +91,9 @@ internal sealed class EditorWindow : Window { if (_target != null && _targetLocation != null) { - var context = _targetLocation.Value.Item1; - var location = _targetLocation.Value.Item2; + var context = _targetLocation.Value.Context; + var node = _targetLocation.Value.Node; + var location = _targetLocation.Value.Location; ImGui.Text(context.File.Directory?.Name ?? string.Empty); ImGui.Indent(); ImGui.Text(context.File.Name); @@ -97,7 +108,7 @@ internal sealed class EditorWindow : Window } int minAngle = locationOverride.MinimumAngle ?? location.MinimumAngle.GetValueOrDefault(); - if (ImGui.DragInt("Min Angle", ref minAngle, 5, -180, 360)) + if (ImGui.DragInt("Min Angle", ref minAngle, 5, -360, 360)) { locationOverride.MinimumAngle = minAngle; locationOverride.MaximumAngle ??= location.MaximumAngle.GetValueOrDefault(); @@ -105,7 +116,7 @@ internal sealed class EditorWindow : Window } int maxAngle = locationOverride.MaximumAngle ?? location.MaximumAngle.GetValueOrDefault(); - if (ImGui.DragInt("Max Angle", ref maxAngle, 5, -180, 360)) + if (ImGui.DragInt("Max Angle", ref maxAngle, 5, -360, 360)) { locationOverride.MinimumAngle ??= location.MinimumAngle.GetValueOrDefault(); locationOverride.MaximumAngle = maxAngle; @@ -119,14 +130,33 @@ internal sealed class EditorWindow : Window location.MaximumAngle = locationOverride.MaximumAngle; _plugin.Save(context.File, context.Root); } + ImGui.SameLine(); if (ImGui.Button("Reset")) { _changes[location.InternalId] = new LocationOverride(); _plugin.Redraw(); } + ImGui.EndDisabled(); + + List nodesInObjectTable = _objectTable + .Where(x => x.ObjectKind == ObjectKind.GatheringPoint && x.DataId == _target.DataId) + .ToList(); + List missingLocations = nodesInObjectTable + .Where(x => !node.Locations.Any(y => Vector3.Distance(x.Position, y.Position) < 0.1f)) + .ToList(); + if (missingLocations.Count > 0) + { + if (ImGui.Button("Add missing locations")) + { + foreach (var missing in missingLocations) + _editorCommands.AddToExistingGroup(context.Root, missing); + + _plugin.Save(context.File, context.Root); + } + } } else if (_target != null) { @@ -154,6 +184,7 @@ internal sealed class EditorWindow : Window _editorCommands.AddToNewGroup(root, _target); _plugin.Save(targetFile, root); } + ImGui.EndDisabled(); } else @@ -176,7 +207,7 @@ internal sealed class EditorWindow : Window => _changes.TryGetValue(internalId, out locationOverride); } -internal class LocationOverride +internal sealed class LocationOverride { public int? MinimumAngle { get; set; } public int? MaximumAngle { get; set; } diff --git a/GatheringPaths/6.x - Endwalker/Thavnair/820_Pewter Ore.json b/GatheringPaths/6.x - Endwalker/Thavnair/820_Pewter Ore.json index de175725..d5a75e9c 100644 --- a/GatheringPaths/6.x - Endwalker/Thavnair/820_Pewter Ore.json +++ b/GatheringPaths/6.x - Endwalker/Thavnair/820_Pewter Ore.json @@ -40,6 +40,15 @@ }, "MinimumAngle": 200, "MaximumAngle": 360 + }, + { + "Position": { + "X": -606.7445, + "Y": 38.37634, + "Z": -425.5284 + }, + "MinimumAngle": -80, + "MaximumAngle": 70 } ] } @@ -139,12 +148,12 @@ "Y": 67.64153, "Z": -477.6673 }, - "MinimumAngle": -90, - "MaximumAngle": 60 + "MinimumAngle": -105, + "MaximumAngle": 75 } ] } ] } ] -} +} \ No newline at end of file diff --git a/GatheringPaths/7.x - Dawntrail/Urqopacha/974_Mountain Chromite Ore.json b/GatheringPaths/7.x - Dawntrail/Urqopacha/974_Mountain Chromite Ore.json index 83bd6138..8b3ade12 100644 --- a/GatheringPaths/7.x - Dawntrail/Urqopacha/974_Mountain Chromite Ore.json +++ b/GatheringPaths/7.x - Dawntrail/Urqopacha/974_Mountain Chromite Ore.json @@ -2,6 +2,7 @@ "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json", "Author": [], "TerritoryId": 1187, + "AetheryteShortcut": "Urqopacha - Wachunpelo", "Groups": [ { "Nodes": [ @@ -39,6 +40,15 @@ }, "MinimumAngle": -50, "MaximumAngle": 210 + }, + { + "Position": { + "X": -394.2657, + "Y": -47.86026, + "Z": -394.9654 + }, + "MinimumAngle": -120, + "MaximumAngle": 120 } ] } @@ -71,6 +81,24 @@ }, "MinimumAngle": 225, "MaximumAngle": 360 + }, + { + "Position": { + "X": -532.3487, + "Y": -22.79275, + "Z": -510.8069 + }, + "MinimumAngle": 135, + "MaximumAngle": 270 + }, + { + "Position": { + "X": -536.2922, + "Y": -23.79476, + "Z": -526.0406 + }, + "MinimumAngle": -110, + "MaximumAngle": 35 } ] } @@ -103,10 +131,28 @@ }, "MinimumAngle": 0, "MaximumAngle": 150 + }, + { + "Position": { + "X": -431.5875, + "Y": -16.68724, + "Z": -656.528 + }, + "MinimumAngle": -35, + "MaximumAngle": 90 + }, + { + "Position": { + "X": -439.8079, + "Y": -16.67447, + "Z": -654.6749 + }, + "MinimumAngle": -45, + "MaximumAngle": 85 } ] } ] } ] -} +} \ No newline at end of file diff --git a/GatheringPaths/7.x - Dawntrail/Urqopacha/992_Snow Cotton.json b/GatheringPaths/7.x - Dawntrail/Urqopacha/992_Snow Cotton.json index 7cf1be27..494b74d6 100644 --- a/GatheringPaths/7.x - Dawntrail/Urqopacha/992_Snow Cotton.json +++ b/GatheringPaths/7.x - Dawntrail/Urqopacha/992_Snow Cotton.json @@ -2,6 +2,7 @@ "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json", "Author": [], "TerritoryId": 1187, + "AetheryteShortcut": "Urqopacha - Wachunpelo", "Groups": [ { "Nodes": [ @@ -26,6 +27,24 @@ "Y": -129.3952, "Z": -396.6573 } + }, + { + "Position": { + "X": -16.08351, + "Y": -137.6674, + "Z": -464.35 + }, + "MinimumAngle": -65, + "MaximumAngle": 145 + }, + { + "Position": { + "X": -9.000858, + "Y": -134.9256, + "Z": -439.0332 + }, + "MinimumAngle": -125, + "MaximumAngle": 105 } ] } @@ -58,6 +77,24 @@ }, "MinimumAngle": -180, "MaximumAngle": 45 + }, + { + "Position": { + "X": -249.7221, + "Y": -96.55618, + "Z": -386.2397 + }, + "MinimumAngle": 35, + "MaximumAngle": 280 + }, + { + "Position": { + "X": -241.8424, + "Y": -99.37369, + "Z": -386.2889 + }, + "MinimumAngle": -300, + "MaximumAngle": -45 } ] } @@ -74,6 +111,24 @@ "Y": -85.61841, "Z": -240.1007 } + }, + { + "Position": { + "X": -116.6446, + "Y": -93.99508, + "Z": -274.6102 + }, + "MinimumAngle": -140, + "MaximumAngle": 150 + }, + { + "Position": { + "X": -133.936, + "Y": -91.54122, + "Z": -273.3963 + }, + "MinimumAngle": -155, + "MaximumAngle": 85 } ] }, diff --git a/GatheringPaths/7.x - Dawntrail/Urqopacha/993_Turali Aloe.json b/GatheringPaths/7.x - Dawntrail/Urqopacha/993_Turali Aloe.json index e17f0f0d..b0117970 100644 --- a/GatheringPaths/7.x - Dawntrail/Urqopacha/993_Turali Aloe.json +++ b/GatheringPaths/7.x - Dawntrail/Urqopacha/993_Turali Aloe.json @@ -2,6 +2,7 @@ "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json", "Author": [], "TerritoryId": 1187, + "AetheryteShortcut": "Urqopacha - Wachunpelo", "Groups": [ { "Nodes": [ @@ -13,6 +14,24 @@ "X": 242.7737, "Y": -135.9734, "Z": -431.2313 + }, + "MinimumAngle": -55, + "MaximumAngle": 100 + }, + { + "Position": { + "X": 302.1836, + "Y": -135.4149, + "Z": -359.7965 + }, + "MinimumAngle": 5, + "MaximumAngle": 155 + }, + { + "Position": { + "X": 256.1657, + "Y": -135.744, + "Z": -414.7577 } } ] @@ -25,7 +44,9 @@ "X": 269.7338, "Y": -134.0488, "Z": -381.6242 - } + }, + "MinimumAngle": -85, + "MaximumAngle": 145 } ] } @@ -44,6 +65,24 @@ }, "MinimumAngle": 105, "MaximumAngle": 345 + }, + { + "Position": { + "X": 401.9319, + "Y": -150.0004, + "Z": -408.114 + }, + "MinimumAngle": -70, + "MaximumAngle": 85 + }, + { + "Position": { + "X": 406.1098, + "Y": -152.2166, + "Z": -364.7227 + }, + "MinimumAngle": -210, + "MaximumAngle": 35 } ] }, @@ -74,6 +113,20 @@ "Y": -161.1972, "Z": -644.0471 } + }, + { + "Position": { + "X": 307.4235, + "Y": -159.1669, + "Z": -622.6444 + } + }, + { + "Position": { + "X": 348.5925, + "Y": -165.3805, + "Z": -671.4193 + } } ] }, diff --git a/QuestPaths/6.x - Endwalker/Studium Deliveries/MIN, BTN/4154_Cooking Up a Culture.json b/QuestPaths/6.x - Endwalker/Studium Deliveries/MIN, BTN/4154_Cooking Up a Culture.json index ea7b708c..4be51dda 100644 --- a/QuestPaths/6.x - Endwalker/Studium Deliveries/MIN, BTN/4154_Cooking Up a Culture.json +++ b/QuestPaths/6.x - Endwalker/Studium Deliveries/MIN, BTN/4154_Cooking Up a Culture.json @@ -29,7 +29,14 @@ "Z": -102.983154 }, "TerritoryId": 962, - "InteractionType": "CompleteQuest" + "InteractionType": "CompleteQuest", + "RequiredGatheredItems": [ + { + "ItemId": 35600, + "ItemCount": 6, + "Collectability": 600 + } + ] } ] } diff --git a/QuestPaths/quest-v1.json b/QuestPaths/quest-v1.json index a11a610c..f18d33a7 100644 --- a/QuestPaths/quest-v1.json +++ b/QuestPaths/quest-v1.json @@ -311,6 +311,30 @@ } } }, + "RequiredGatheredItems": { + "type": "array", + "items": { + "type": "object", + "properties": { + "ItemId": { + "type": "number" + }, + "ItemCount": { + "type": "number", + "exclusiveMinimum": 0 + }, + "Collectability": { + "type": "number", + "minimum": 0, + "maximum": 1000 + } + }, + "required": [ + "ItemId", + "ItemCount" + ] + } + }, "DelaySecondsAtStart": { "description": "Time to wait before starting", "type": [ diff --git a/Questionable.Model/GatheringMath.cs b/Questionable.Model/GatheringMath.cs new file mode 100644 index 00000000..46105e1a --- /dev/null +++ b/Questionable.Model/GatheringMath.cs @@ -0,0 +1,53 @@ +using System; +using System.Numerics; +using Questionable.Model.Gathering; + +namespace GatheringPathRenderer; + +public static class GatheringMath +{ + private static readonly Random RNG = new Random(); + + public static (Vector3, int, float) CalculateLandingLocation(GatheringLocation location) + { + int degrees; + if (location.IsCone()) + degrees = RNG.Next( + location.MinimumAngle.GetValueOrDefault(), + location.MaximumAngle.GetValueOrDefault()); + else + degrees = RNG.Next(0, 360); + + float range = RNG.Next( + (int)(location.CalculateMinimumDistance() * 100), + (int)((location.CalculateMaximumDistance() - location.CalculateMinimumDistance()) * 100)) / 100f; + return (CalculateLandingLocation(location.Position, degrees, range), degrees, range); + } + + public static Vector3 CalculateLandingLocation(GatheringLocation location, float angleScale, float rangeScale) + { + int degrees; + if (location.IsCone()) + degrees = location.MinimumAngle.GetValueOrDefault() + + (int)(angleScale * (location.MaximumAngle.GetValueOrDefault() - + location.MinimumAngle.GetValueOrDefault())); + else + degrees = (int)(rangeScale * 360); + + float range = + location.CalculateMinimumDistance() + + rangeScale * (location.CalculateMaximumDistance() - location.CalculateMinimumDistance()); + return CalculateLandingLocation(location.Position, degrees, range); + } + + private static Vector3 CalculateLandingLocation(Vector3 position, int degrees, float range) + { + float rad = -(float)(degrees * Math.PI / 180); + return new Vector3 + { + X = position.X + range * (float)Math.Sin(rad), + Y = position.Y, + Z = position.Z + range * (float)Math.Cos(rad) + }; + } +} diff --git a/Questionable.Model/Questing/GatheredItem.cs b/Questionable.Model/Questing/GatheredItem.cs new file mode 100644 index 00000000..41bd0624 --- /dev/null +++ b/Questionable.Model/Questing/GatheredItem.cs @@ -0,0 +1,8 @@ +namespace Questionable.Model.Questing; + +public sealed class GatheredItem +{ + public uint ItemId { get; set; } + public int ItemCount { get; set; } + public short Collectability { get; set; } +} diff --git a/Questionable.Model/Questing/QuestStep.cs b/Questionable.Model/Questing/QuestStep.cs index 53ed7ced..4ec5f81d 100644 --- a/Questionable.Model/Questing/QuestStep.cs +++ b/Questionable.Model/Questing/QuestStep.cs @@ -66,6 +66,7 @@ public sealed class QuestStep public SkipConditions? SkipConditions { get; set; } public List?> RequiredQuestVariables { get; set; } = new(); + public List RequiredGatheredItems { get; set; } = []; public IList CompletionQuestVariablesFlags { get; set; } = new List(); public IList DialogueChoices { get; set; } = new List(); public IList PointMenuChoices { get; set; } = new List(); diff --git a/Questionable.sln.DotSettings b/Questionable.sln.DotSettings index 3588f8f8..a8a650e8 100644 --- a/Questionable.sln.DotSettings +++ b/Questionable.sln.DotSettings @@ -7,6 +7,7 @@ True True True + True True True True diff --git a/Questionable/Controller/GatheringController.cs b/Questionable/Controller/GatheringController.cs new file mode 100644 index 00000000..45fccf64 --- /dev/null +++ b/Questionable/Controller/GatheringController.cs @@ -0,0 +1,179 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Numerics; +using Dalamud.Game.ClientState.Objects.Enums; +using Dalamud.Plugin.Services; +using FFXIVClientStructs.FFXIV.Client.Game; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Questionable.Controller.Steps; +using Questionable.Controller.Steps.Common; +using Questionable.Controller.Steps.Gathering; +using Questionable.Controller.Steps.Interactions; +using Questionable.Controller.Steps.Shared; +using Questionable.Data; +using Questionable.External; +using Questionable.GatheringPaths; +using Questionable.Model.Gathering; + +namespace Questionable.Controller; + +internal sealed unsafe class GatheringController : MiniTaskController +{ + private readonly MovementController _movementController; + private readonly GatheringData _gatheringData; + private readonly GameFunctions _gameFunctions; + private readonly NavmeshIpc _navmeshIpc; + private readonly IObjectTable _objectTable; + private readonly IServiceProvider _serviceProvider; + + private CurrentRequest? _currentRequest; + + public GatheringController(MovementController movementController, GatheringData gatheringData, + GameFunctions gameFunctions, NavmeshIpc navmeshIpc, IObjectTable objectTable, IChatGui chatGui, + ILogger logger, IServiceProvider serviceProvider) + : base(chatGui, logger) + { + _movementController = movementController; + _gatheringData = gatheringData; + _gameFunctions = gameFunctions; + _navmeshIpc = navmeshIpc; + _objectTable = objectTable; + _serviceProvider = serviceProvider; + } + + public bool Start(GatheringRequest gatheringRequest) + { + if (!AssemblyGatheringLocationLoader.GetLocations() + .TryGetValue(gatheringRequest.GatheringPointId, out GatheringRoot? gatheringRoot)) + { + _logger.LogError("Unable to resolve gathering point, no path found for {ItemId} / point {PointId}", + gatheringRequest.ItemId, gatheringRequest.GatheringPointId); + return false; + } + + _currentRequest = new CurrentRequest + { + Data = gatheringRequest, + Root = gatheringRoot, + Nodes = gatheringRoot.Groups + .SelectMany(x => x.Nodes) + .ToList(), + }; + + if (HasRequestedItems()) + { + _currentRequest = null; + return false; + } + + return true; + } + + public EStatus Update() + { + if (_currentRequest == null) + return EStatus.Complete; + + if (_movementController.IsPathfinding || _movementController.IsPathfinding) + return EStatus.Moving; + + if (HasRequestedItems()) + return EStatus.Complete; + + if (_currentTask == null && _taskQueue.Count == 0) + GoToNextNode(); + + UpdateCurrentTask(); + return EStatus.Gathering; + } + + protected override void OnTaskComplete(ITask task) => GoToNextNode(); + + public override void Stop(string label) + { + _currentRequest = null; + _currentTask = null; + _taskQueue.Clear(); + } + + private void GoToNextNode() + { + if (_currentRequest == null) + return; + + if (_taskQueue.Count > 0) + return; + + var currentNode = _currentRequest.Nodes[_currentRequest.CurrentIndex++ % _currentRequest.Nodes.Count]; + + _taskQueue.Enqueue(_serviceProvider.GetRequiredService() + .With(_currentRequest.Root.TerritoryId, MountTask.EMountIf.Always)); + if (currentNode.Locations.Count > 1) + { + Vector3 averagePosition = new Vector3 + { + X = currentNode.Locations.Sum(x => x.Position.X) / currentNode.Locations.Count, + Y = currentNode.Locations.Select(x => x.Position.Y).Max() + 5f, + Z = currentNode.Locations.Sum(x => x.Position.Z) / currentNode.Locations.Count, + }; + Vector3? pointOnFloor = _navmeshIpc.GetPointOnFloor(averagePosition); + if (pointOnFloor != null) + pointOnFloor = pointOnFloor.Value with { Y = pointOnFloor.Value.Y + 3f }; + + _taskQueue.Enqueue(_serviceProvider.GetRequiredService() + .With(_currentRequest.Root.TerritoryId, pointOnFloor ?? averagePosition, 50f, fly: true, + ignoreDistanceToObject: true)); + } + + _taskQueue.Enqueue(_serviceProvider.GetRequiredService() + .With(_currentRequest.Root.TerritoryId, currentNode)); + _taskQueue.Enqueue(_serviceProvider.GetRequiredService() + .With(currentNode.DataId, true)); + _taskQueue.Enqueue(_serviceProvider.GetRequiredService()); + } + + private bool HasRequestedItems() + { + if (_currentRequest == null) + return true; + + InventoryManager* inventoryManager = InventoryManager.Instance(); + if (inventoryManager == null) + return false; + + return inventoryManager->GetInventoryItemCount(_currentRequest.Data.ItemId, + minCollectability: _currentRequest.Data.Collectability) >= _currentRequest.Data.Quantity; + } + + public override IList GetRemainingTaskNames() + { + if (_currentTask != null) + return [_currentTask.ToString() ?? "?", .. base.GetRemainingTaskNames()]; + else + return base.GetRemainingTaskNames(); + } + + private sealed class CurrentRequest + { + public required GatheringRequest Data { get; init; } + public required GatheringRoot Root { get; init; } + + /// + /// To make indexing easy with , we flatten the list of gathering locations. + /// + public required List Nodes { get; init; } + + public int CurrentIndex { get; set; } + } + + public sealed record GatheringRequest(ushort GatheringPointId, uint ItemId, int Quantity, short Collectability = 0); + + public enum EStatus + { + Gathering, + Moving, + Complete, + } +} diff --git a/Questionable/Controller/MiniTaskController.cs b/Questionable/Controller/MiniTaskController.cs new file mode 100644 index 00000000..4d19d73b --- /dev/null +++ b/Questionable/Controller/MiniTaskController.cs @@ -0,0 +1,134 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Dalamud.Plugin.Services; +using Microsoft.Extensions.Logging; +using Questionable.Controller.Steps; +using Questionable.Controller.Steps.Shared; + +namespace Questionable.Controller; + +internal abstract class MiniTaskController +{ + protected readonly IChatGui _chatGui; + protected readonly ILogger _logger; + + protected readonly Queue _taskQueue = new(); + protected ITask? _currentTask; + + public MiniTaskController(IChatGui chatGui, ILogger logger) + { + _chatGui = chatGui; + _logger = logger; + } + + protected virtual void UpdateCurrentTask() + { + if (_currentTask == null) + { + if (_taskQueue.TryDequeue(out ITask? upcomingTask)) + { + try + { + _logger.LogInformation("Starting task {TaskName}", upcomingTask.ToString()); + if (upcomingTask.Start()) + { + _currentTask = upcomingTask; + return; + } + else + { + _logger.LogTrace("Task {TaskName} was skipped", upcomingTask.ToString()); + return; + } + } + catch (Exception e) + { + _logger.LogError(e, "Failed to start task {TaskName}", upcomingTask.ToString()); + _chatGui.PrintError( + $"[Questionable] Failed to start task '{upcomingTask}', please check /xllog for details."); + Stop("Task failed to start"); + return; + } + } + else + return; + } + + ETaskResult result; + try + { + result = _currentTask.Update(); + } + catch (Exception e) + { + _logger.LogError(e, "Failed to update task {TaskName}", _currentTask.ToString()); + _chatGui.PrintError( + $"[Questionable] Failed to update task '{_currentTask}', please check /xllog for details."); + Stop("Task failed to update"); + return; + } + + switch (result) + { + case ETaskResult.StillRunning: + return; + + case ETaskResult.SkipRemainingTasksForStep: + _logger.LogInformation("{Task} → {Result}, skipping remaining tasks for step", + _currentTask, result); + _currentTask = null; + + while (_taskQueue.TryDequeue(out ITask? nextTask)) + { + if (nextTask is ILastTask) + { + _currentTask = nextTask; + return; + } + } + + return; + + case ETaskResult.TaskComplete: + _logger.LogInformation("{Task} → {Result}, remaining tasks: {RemainingTaskCount}", + _currentTask, result, _taskQueue.Count); + + OnTaskComplete(_currentTask); + + _currentTask = null; + + // handled in next update + return; + + case ETaskResult.NextStep: + _logger.LogInformation("{Task} → {Result}", _currentTask, result); + + var lastTask = (ILastTask)_currentTask; + _currentTask = null; + + OnNextStep(lastTask); + return; + + case ETaskResult.End: + _logger.LogInformation("{Task} → {Result}", _currentTask, result); + _currentTask = null; + Stop("Task end"); + return; + } + } + + protected virtual void OnTaskComplete(ITask task) + { + } + + protected virtual void OnNextStep(ILastTask task) + { + + } + + public abstract void Stop(string label); + + public virtual IList GetRemainingTaskNames() => + _taskQueue.Select(x => x.ToString() ?? "?").ToList(); +} diff --git a/Questionable/Controller/QuestController.cs b/Questionable/Controller/QuestController.cs index e50891d2..a7b77ac2 100644 --- a/Questionable/Controller/QuestController.cs +++ b/Questionable/Controller/QuestController.cs @@ -14,16 +14,15 @@ using Questionable.Model.Questing; namespace Questionable.Controller; -internal sealed class QuestController +internal sealed class QuestController : MiniTaskController { private readonly IClientState _clientState; private readonly GameFunctions _gameFunctions; private readonly MovementController _movementController; private readonly CombatController _combatController; - private readonly ILogger _logger; + private readonly GatheringController _gatheringController; private readonly QuestRegistry _questRegistry; private readonly IKeyState _keyState; - private readonly IChatGui _chatGui; private readonly ICondition _condition; private readonly Configuration _configuration; private readonly YesAlreadyIpc _yesAlreadyIpc; @@ -34,8 +33,6 @@ internal sealed class QuestController private QuestProgress? _startedQuest; private QuestProgress? _nextQuest; private QuestProgress? _simulatedQuest; - private readonly Queue _taskQueue = new(); - private ITask? _currentTask; private bool _automatic; /// @@ -50,6 +47,7 @@ internal sealed class QuestController GameFunctions gameFunctions, MovementController movementController, CombatController combatController, + GatheringController gatheringController, ILogger logger, QuestRegistry questRegistry, IKeyState keyState, @@ -58,15 +56,15 @@ internal sealed class QuestController Configuration configuration, YesAlreadyIpc yesAlreadyIpc, IEnumerable taskFactories) + : base(chatGui, logger) { _clientState = clientState; _gameFunctions = gameFunctions; _movementController = movementController; _combatController = combatController; - _logger = logger; + _gatheringController = gatheringController; _questRegistry = questRegistry; _keyState = keyState; - _chatGui = chatGui; _condition = condition; _configuration = configuration; _yesAlreadyIpc = yesAlreadyIpc; @@ -138,6 +136,7 @@ internal sealed class QuestController Stop("HP = 0"); _movementController.Stop(); _combatController.Stop("HP = 0"); + _gatheringController.Stop("HP = 0"); } } else if (_configuration.General.UseEscToCancelQuesting && _keyState[VirtualKey.ESCAPE]) @@ -147,6 +146,7 @@ internal sealed class QuestController Stop("ESC pressed"); _movementController.Stop(); _combatController.Stop("ESC pressed"); + _gatheringController.Stop("ESC pressed"); } } @@ -377,9 +377,10 @@ internal sealed class QuestController _yesAlreadyIpc.RestoreYesAlready(); _combatController.Stop("ClearTasksInternal"); + _gatheringController.Stop("ClearTasksInternal"); } - public void Stop(string label, bool continueIfAutomatic = false) + public void Stop(string label, bool continueIfAutomatic) { using var scope = _logger.BeginScope(label); @@ -401,6 +402,8 @@ internal sealed class QuestController } } + public override void Stop(string label) => Stop(label, false); + public void SimulateQuest(Quest? quest) { _logger.LogInformation("SimulateQuest: {QuestId}", quest?.QuestId); @@ -419,103 +422,23 @@ internal sealed class QuestController _nextQuest = null; } - private void UpdateCurrentTask() + protected override void UpdateCurrentTask() { if (_gameFunctions.IsOccupied()) return; - if (_currentTask == null) - { - if (_taskQueue.TryDequeue(out ITask? upcomingTask)) - { - try - { - _logger.LogInformation("Starting task {TaskName}", upcomingTask.ToString()); - if (upcomingTask.Start()) - { - _currentTask = upcomingTask; - return; - } - else - { - _logger.LogTrace("Task {TaskName} was skipped", upcomingTask.ToString()); - return; - } - } - catch (Exception e) - { - _logger.LogError(e, "Failed to start task {TaskName}", upcomingTask.ToString()); - _chatGui.PrintError( - $"[Questionable] Failed to start task '{upcomingTask}', please check /xllog for details."); - Stop("Task failed to start"); - return; - } - } - else - return; - } + base.UpdateCurrentTask(); + } - ETaskResult result; - try - { - result = _currentTask.Update(); - } - catch (Exception e) - { - _logger.LogError(e, "Failed to update task {TaskName}", _currentTask.ToString()); - _chatGui.PrintError( - $"[Questionable] Failed to update task '{_currentTask}', please check /xllog for details."); - Stop("Task failed to update"); - return; - } + protected override void OnTaskComplete(ITask task) + { + if (task is WaitAtEnd.WaitQuestCompleted) + _simulatedQuest = null; + } - switch (result) - { - case ETaskResult.StillRunning: - return; - - case ETaskResult.SkipRemainingTasksForStep: - _logger.LogInformation("{Task} → {Result}, skipping remaining tasks for step", - _currentTask, result); - _currentTask = null; - - while (_taskQueue.TryDequeue(out ITask? nextTask)) - { - if (nextTask is ILastTask) - { - _currentTask = nextTask; - return; - } - } - - return; - - 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 - return; - - case ETaskResult.NextStep: - _logger.LogInformation("{Task} → {Result}", _currentTask, result); - - var lastTask = (ILastTask)_currentTask; - _currentTask = null; - IncreaseStepCount(lastTask.QuestId, lastTask.Sequence, true); - return; - - case ETaskResult.End: - _logger.LogInformation("{Task} → {Result}", _currentTask, result); - _currentTask = null; - Stop("Task end"); - return; - } + protected override void OnNextStep(ILastTask task) + { + IncreaseStepCount(task.QuestId, task.Sequence, true); } public void ExecuteNextStep(bool automatic) @@ -536,6 +459,7 @@ internal sealed class QuestController _movementController.Stop(); _combatController.Stop("Execute next step"); + _gatheringController.Stop("Execute next step"); var newTasks = _taskFactories .SelectMany(x => @@ -568,9 +492,6 @@ internal sealed class QuestController _taskQueue.Enqueue(task); } - public IList GetRemainingTaskNames() => - _taskQueue.Select(x => x.ToString() ?? "?").ToList(); - public string ToStatString() { return _currentTask == null ? $"- (+{_taskQueue.Count})" : $"{_currentTask} (+{_taskQueue.Count})"; diff --git a/Questionable/Controller/Steps/Gathering/MoveToLandingLocation.cs b/Questionable/Controller/Steps/Gathering/MoveToLandingLocation.cs new file mode 100644 index 00000000..3336500f --- /dev/null +++ b/Questionable/Controller/Steps/Gathering/MoveToLandingLocation.cs @@ -0,0 +1,64 @@ +using System; +using System.Globalization; +using System.Linq; +using System.Numerics; +using System.Security.Cryptography; +using Dalamud.Game.ClientState.Objects.Enums; +using Dalamud.Plugin.Services; +using GatheringPathRenderer; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Questionable.Controller.Steps.Shared; +using Questionable.External; +using Questionable.Model.Gathering; + +namespace Questionable.Controller.Steps.Gathering; + +internal sealed class MoveToLandingLocation( + IServiceProvider serviceProvider, + IObjectTable objectTable, + NavmeshIpc navmeshIpc, + ILogger logger) : ITask +{ + private ushort _territoryId; + private GatheringNode _gatheringNode = null!; + private ITask _moveTask = null!; + + public ITask With(ushort territoryId, GatheringNode gatheringNode) + { + _territoryId = territoryId; + _gatheringNode = gatheringNode; + return this; + } + + public bool Start() + { + var location = _gatheringNode.Locations.First(); + if (_gatheringNode.Locations.Count > 1) + { + var gameObject = objectTable.Single(x => + x.ObjectKind == ObjectKind.GatheringPoint && x.DataId == _gatheringNode.DataId && x.IsTargetable); + location = _gatheringNode.Locations.Single(x => Vector3.Distance(x.Position, gameObject.Position) < 0.1f); + } + + var (target, degrees, range) = GatheringMath.CalculateLandingLocation(location); + logger.LogInformation("Preliminary landing location: {Location}, with degrees = {Degrees}, range = {Range}", + target.ToString("G", CultureInfo.InvariantCulture), degrees, range); + + Vector3? pointOnFloor = navmeshIpc.GetPointOnFloor(target with { Y = target.Y + 5f }); + if (pointOnFloor != null) + pointOnFloor = pointOnFloor.Value with { Y = pointOnFloor.Value.Y + 0.5f }; + + logger.LogInformation("Final landing location: {Location}", + (pointOnFloor ?? target).ToString("G", CultureInfo.InvariantCulture)); + + _moveTask = serviceProvider.GetRequiredService() + .With(_territoryId, pointOnFloor ?? target, 0.25f, dataId: _gatheringNode.DataId, fly: true, + ignoreDistanceToObject: true); + return _moveTask.Start(); + } + + public ETaskResult Update() => _moveTask.Update(); + + public override string ToString() => $"Land/{_moveTask}"; +} diff --git a/Questionable/Controller/Steps/Gathering/WaitGather.cs b/Questionable/Controller/Steps/Gathering/WaitGather.cs new file mode 100644 index 00000000..e2b3a889 --- /dev/null +++ b/Questionable/Controller/Steps/Gathering/WaitGather.cs @@ -0,0 +1,25 @@ +using Dalamud.Game.ClientState.Conditions; +using Dalamud.Plugin.Services; + +namespace Questionable.Controller.Steps.Gathering; + +internal sealed class WaitGather(ICondition condition) : ITask +{ + private bool _wasGathering; + + public bool Start() => true; + + public ETaskResult Update() + { + if (condition[ConditionFlag.Gathering]) + { + _wasGathering = true; + } + + return _wasGathering && !condition[ConditionFlag.Gathering] + ? ETaskResult.TaskComplete + : ETaskResult.StillRunning; + } + + public override string ToString() => "WaitGather"; +} diff --git a/Questionable/Controller/Steps/Interactions/Interact.cs b/Questionable/Controller/Steps/Interactions/Interact.cs index 7dba0d44..df27d3c2 100644 --- a/Questionable/Controller/Steps/Interactions/Interact.cs +++ b/Questionable/Controller/Steps/Interactions/Interact.cs @@ -59,7 +59,7 @@ internal static class Interact public bool Start() { - IGameObject? gameObject = gameFunctions.FindObjectByDataId(DataId); + IGameObject? gameObject = gameFunctions.FindObjectByDataId(DataId, targetable: true); if (gameObject == null) { logger.LogWarning("No game object with dataId {DataId}", DataId); @@ -67,17 +67,19 @@ internal static class Interact } // this is only relevant for followers on quests - if (!gameObject.IsTargetable && condition[ConditionFlag.Mounted]) + if (!gameObject.IsTargetable && condition[ConditionFlag.Mounted] && + gameObject.ObjectKind != ObjectKind.GatheringPoint) { + logger.LogInformation("Preparing interaction for {DataId} by unmounting", DataId); _needsUnmount = true; gameFunctions.Unmount(); _continueAt = DateTime.Now.AddSeconds(1); return true; } - if (gameObject.IsTargetable && HasAnyMarker(gameObject)) + if (IsTargetable(gameObject) && HasAnyMarker(gameObject)) { - _interacted = gameFunctions.InteractWith(DataId); + _interacted = gameFunctions.InteractWith(gameObject); _continueAt = DateTime.Now.AddSeconds(0.5); return true; } @@ -104,11 +106,11 @@ internal static class Interact if (!_interacted) { - IGameObject? gameObject = gameFunctions.FindObjectByDataId(DataId); - if (gameObject == null || !gameObject.IsTargetable || !HasAnyMarker(gameObject)) + IGameObject? gameObject = gameFunctions.FindObjectByDataId(DataId, targetable: true); + if (gameObject == null || !IsTargetable(gameObject) || !HasAnyMarker(gameObject)) return ETaskResult.StillRunning; - _interacted = gameFunctions.InteractWith(DataId); + _interacted = gameFunctions.InteractWith(gameObject); _continueAt = DateTime.Now.AddSeconds(0.5); return ETaskResult.StillRunning; } @@ -125,6 +127,11 @@ internal static class Interact return gameObjectStruct->NamePlateIconId != 0; } + private static bool IsTargetable(IGameObject gameObject) + { + return gameObject.IsTargetable; + } + public override string ToString() => $"Interact({DataId})"; } } diff --git a/Questionable/Controller/Steps/Shared/GatheringRequiredItems.cs b/Questionable/Controller/Steps/Shared/GatheringRequiredItems.cs new file mode 100644 index 00000000..ea602723 --- /dev/null +++ b/Questionable/Controller/Steps/Shared/GatheringRequiredItems.cs @@ -0,0 +1,75 @@ +using System; +using System.Collections.Generic; +using Dalamud.Plugin.Services; +using Microsoft.Extensions.DependencyInjection; +using Questionable.Data; +using Questionable.GatheringPaths; +using Questionable.Model; +using Questionable.Model.Gathering; +using Questionable.Model.Questing; + +namespace Questionable.Controller.Steps.Shared; + +internal static class GatheringRequiredItems +{ + internal sealed class Factory( + IServiceProvider serviceProvider, + IClientState clientState, + GatheringData gatheringData) : ITaskFactory + { + public IEnumerable CreateAllTasks(Quest quest, QuestSequence sequence, QuestStep step) + { + foreach (var requiredGatheredItems in step.RequiredGatheredItems) + { + if (!gatheringData.TryGetGatheringPointId(requiredGatheredItems.ItemId, + clientState.LocalPlayer!.ClassJob.Id, out var gatheringPointId)) + throw new TaskException($"No gathering point found for item {requiredGatheredItems.ItemId}"); + + if (!AssemblyGatheringLocationLoader.GetLocations() + .TryGetValue(gatheringPointId, out GatheringRoot? gatheringRoot)) + throw new TaskException("No path found for gathering point"); + + if (gatheringRoot.AetheryteShortcut != null && clientState.TerritoryType != gatheringRoot.TerritoryId) + { + yield return serviceProvider.GetRequiredService() + .With(null, gatheringRoot.AetheryteShortcut.Value, gatheringRoot.TerritoryId); + } + + yield return serviceProvider.GetRequiredService() + .With(gatheringPointId, requiredGatheredItems); + } + } + + public ITask CreateTask(Quest quest, QuestSequence sequence, QuestStep step) + => throw new NotImplementedException(); + } + + internal sealed class StartGathering(GatheringController gatheringController) : ITask + { + private ushort _gatheringPointId; + private GatheredItem _gatheredItem = null!; + + public ITask With(ushort gatheringPointId, GatheredItem gatheredItem) + { + _gatheringPointId = gatheringPointId; + _gatheredItem = gatheredItem; + return this; + } + + public bool Start() + { + return gatheringController.Start(new GatheringController.GatheringRequest(_gatheringPointId, + _gatheredItem.ItemId, _gatheredItem.ItemCount, _gatheredItem.Collectability)); + } + + public ETaskResult Update() + { + if (gatheringController.Update() == GatheringController.EStatus.Complete) + return ETaskResult.TaskComplete; + + return ETaskResult.StillRunning; + } + + public override string ToString() => $"Gather({_gatheredItem.ItemCount}x {_gatheredItem.ItemId})"; + } +} diff --git a/Questionable/Data/GatheringData.cs b/Questionable/Data/GatheringData.cs new file mode 100644 index 00000000..ed44fdc2 --- /dev/null +++ b/Questionable/Data/GatheringData.cs @@ -0,0 +1,49 @@ +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using Dalamud.Plugin.Services; +using Lumina.Excel.GeneratedSheets; + +namespace Questionable.Data; + +internal sealed class GatheringData +{ + private readonly Dictionary _gatheringItemToItem; + private readonly Dictionary _minerGatheringPoints = []; + private readonly Dictionary _botanistGatheringPoints = []; + + public GatheringData(IDataManager dataManager) + { + _gatheringItemToItem = dataManager.GetExcelSheet()! + .Where(x => x.RowId != 0 && x.Item != 0) + .ToDictionary(x => x.RowId, x => (uint)x.Item); + + foreach (var gatheringPointBase in dataManager.GetExcelSheet()!) + { + foreach (var gatheringItemId in gatheringPointBase.Item.Where(x => x != 0)) + { + if (_gatheringItemToItem.TryGetValue((uint)gatheringItemId, out uint itemId)) + { + if (gatheringPointBase.GatheringType.Row is 0 or 1) + _minerGatheringPoints[itemId] = (ushort)gatheringPointBase.RowId; + else if (gatheringPointBase.GatheringType.Row is 2 or 3) + _botanistGatheringPoints[itemId] = (ushort)gatheringPointBase.RowId; + } + } + } + } + + + public bool TryGetGatheringPointId(uint itemId, uint classJobId, out ushort gatheringPointId) + { + if (classJobId == 16) + return _minerGatheringPoints.TryGetValue(itemId, out gatheringPointId); + else if (classJobId == 17) + return _botanistGatheringPoints.TryGetValue(itemId, out gatheringPointId); + else + { + gatheringPointId = 0; + return false; + } + } +} diff --git a/Questionable/GameFunctions.cs b/Questionable/GameFunctions.cs index 724f2f11..1cd229d1 100644 --- a/Questionable/GameFunctions.cs +++ b/Questionable/GameFunctions.cs @@ -407,10 +407,13 @@ internal sealed unsafe class GameFunctions playerState->IsAetherCurrentUnlocked(aetherCurrentId); } - public IGameObject? FindObjectByDataId(uint dataId, ObjectKind? kind = null) + public IGameObject? FindObjectByDataId(uint dataId, ObjectKind? kind = null, bool targetable = false) { foreach (var gameObject in _objectTable) { + if (targetable && !gameObject.IsTargetable) + continue; + if (gameObject.ObjectKind is ObjectKind.Player or ObjectKind.Companion or ObjectKind.MountType or ObjectKind.Retainer or ObjectKind.Housing) continue; @@ -429,19 +432,31 @@ internal sealed unsafe class GameFunctions { IGameObject? gameObject = FindObjectByDataId(dataId, kind); if (gameObject != null) - { - _logger.LogInformation("Setting target with {DataId} to {ObjectId}", dataId, gameObject.EntityId); - _targetManager.Target = null; - _targetManager.Target = gameObject; + return InteractWith(gameObject); + _logger.LogDebug("Game object is null"); + return false; + } + + public bool InteractWith(IGameObject gameObject) + { + _logger.LogInformation("Setting target with {DataId} to {ObjectId}", gameObject.DataId, gameObject.EntityId); + _targetManager.Target = null; + _targetManager.Target = gameObject; + + if (gameObject.ObjectKind == ObjectKind.GatheringPoint) + { + TargetSystem.Instance()->OpenObjectInteraction((GameObject*)gameObject.Address); + _logger.LogInformation("Interact result: (none) for GatheringPoint"); + return true; + } + else + { long result = (long)TargetSystem.Instance()->InteractWithObject((GameObject*)gameObject.Address, false); _logger.LogInformation("Interact result: {Result}", result); return result != 7 && result > 0; } - - _logger.LogDebug("Game object is null"); - return false; } public bool UseItem(uint itemId) diff --git a/Questionable/Questionable.csproj b/Questionable/Questionable.csproj index ae232ac1..ceb37e8c 100644 --- a/Questionable/Questionable.csproj +++ b/Questionable/Questionable.csproj @@ -18,6 +18,7 @@ + diff --git a/Questionable/QuestionablePlugin.cs b/Questionable/QuestionablePlugin.cs index df100963..0febd3bd 100644 --- a/Questionable/QuestionablePlugin.cs +++ b/Questionable/QuestionablePlugin.cs @@ -13,6 +13,7 @@ using Questionable.Controller.CombatModules; using Questionable.Controller.NavigationOverrides; using Questionable.Controller.Steps.Shared; using Questionable.Controller.Steps.Common; +using Questionable.Controller.Steps.Gathering; using Questionable.Controller.Steps.Interactions; using Questionable.Data; using Questionable.External; @@ -89,6 +90,7 @@ public sealed class QuestionablePlugin : IDalamudPlugin serviceCollection.AddSingleton(); serviceCollection.AddSingleton(); serviceCollection.AddSingleton(); + serviceCollection.AddSingleton(); serviceCollection.AddSingleton(); serviceCollection.AddSingleton(); serviceCollection.AddSingleton(); @@ -102,9 +104,12 @@ public sealed class QuestionablePlugin : IDalamudPlugin // individual tasks serviceCollection.AddTransient(); serviceCollection.AddTransient(); + serviceCollection.AddTransient(); + serviceCollection.AddTransient(); // task factories serviceCollection.AddTaskWithFactory(); + serviceCollection.AddTaskWithFactory(); serviceCollection.AddTaskWithFactory(); serviceCollection.AddTaskWithFactory(); serviceCollection.AddTaskWithFactory(); @@ -149,6 +154,7 @@ public sealed class QuestionablePlugin : IDalamudPlugin serviceCollection.AddSingleton(); serviceCollection.AddSingleton(); serviceCollection.AddSingleton(); + serviceCollection.AddSingleton(); serviceCollection.AddSingleton(); } diff --git a/Questionable/Windows/QuestComponents/ActiveQuestComponent.cs b/Questionable/Windows/QuestComponents/ActiveQuestComponent.cs index 14b628d3..17ab37f4 100644 --- a/Questionable/Windows/QuestComponents/ActiveQuestComponent.cs +++ b/Questionable/Windows/QuestComponents/ActiveQuestComponent.cs @@ -22,6 +22,7 @@ internal sealed class ActiveQuestComponent private readonly QuestController _questController; private readonly MovementController _movementController; private readonly CombatController _combatController; + private readonly GatheringController _gatheringController; private readonly GameFunctions _gameFunctions; private readonly ICommandManager _commandManager; private readonly IDalamudPluginInterface _pluginInterface; @@ -29,14 +30,22 @@ internal sealed class ActiveQuestComponent private readonly QuestRegistry _questRegistry; private readonly IChatGui _chatGui; - public ActiveQuestComponent(QuestController questController, MovementController movementController, - CombatController combatController, GameFunctions gameFunctions, ICommandManager commandManager, - IDalamudPluginInterface pluginInterface, Configuration configuration, QuestRegistry questRegistry, + public ActiveQuestComponent( + QuestController questController, + MovementController movementController, + CombatController combatController, + GatheringController gatheringController, + GameFunctions gameFunctions, + ICommandManager commandManager, + IDalamudPluginInterface pluginInterface, + Configuration configuration, + QuestRegistry questRegistry, IChatGui chatGui) { _questController = questController; _movementController = movementController; _combatController = combatController; + _gatheringController = gatheringController; _gameFunctions = gameFunctions; _commandManager = commandManager; _pluginInterface = pluginInterface; @@ -93,6 +102,7 @@ internal sealed class ActiveQuestComponent { _movementController.Stop(); _questController.Stop("Manual (no active quest)"); + _gatheringController.Stop("Manual (no active quest)"); } } } @@ -233,6 +243,7 @@ internal sealed class ActiveQuestComponent { _movementController.Stop(); _questController.Stop("Manual"); + _gatheringController.Stop("Manual"); } bool lastStep = currentStep == diff --git a/Questionable/Windows/QuestComponents/RemainingTasksComponent.cs b/Questionable/Windows/QuestComponents/RemainingTasksComponent.cs index bd35f699..84d44c90 100644 --- a/Questionable/Windows/QuestComponents/RemainingTasksComponent.cs +++ b/Questionable/Windows/QuestComponents/RemainingTasksComponent.cs @@ -1,4 +1,5 @@ -using ImGuiNET; +using System.Collections.Generic; +using ImGuiNET; using Questionable.Controller; namespace Questionable.Windows.QuestComponents; @@ -6,22 +7,36 @@ namespace Questionable.Windows.QuestComponents; internal sealed class RemainingTasksComponent { private readonly QuestController _questController; + private readonly GatheringController _gatheringController; - public RemainingTasksComponent(QuestController questController) + public RemainingTasksComponent(QuestController questController, GatheringController gatheringController) { _questController = questController; + _gatheringController = gatheringController; } public void Draw() { - var remainingTasks = _questController.GetRemainingTaskNames(); - if (remainingTasks.Count > 0) + IList gatheringTasks = _gatheringController.GetRemainingTaskNames(); + if (gatheringTasks.Count > 0) { ImGui.Separator(); ImGui.BeginDisabled(); - foreach (var task in remainingTasks) - ImGui.TextUnformatted(task); + foreach (var task in gatheringTasks) + ImGui.TextUnformatted($"G: {task}"); ImGui.EndDisabled(); } + else + { + var remainingTasks = _questController.GetRemainingTaskNames(); + if (remainingTasks.Count > 0) + { + ImGui.Separator(); + ImGui.BeginDisabled(); + foreach (var task in remainingTasks) + ImGui.TextUnformatted(task); + ImGui.EndDisabled(); + } + } } } diff --git a/Questionable/packages.lock.json b/Questionable/packages.lock.json index 53ca99c0..1fd12865 100644 --- a/Questionable/packages.lock.json +++ b/Questionable/packages.lock.json @@ -179,6 +179,12 @@ "resolved": "8.0.0", "contentHash": "yev/k9GHAEGx2Rg3/tU6MQh4HGBXJs70y7j1LaM1i/ER9po+6nnQ6RRqTJn1E7Xu0fbIFK80Nh5EoODxrbxwBQ==" }, + "gatheringpaths": { + "type": "Project", + "dependencies": { + "Questionable.Model": "[1.0.0, )" + } + }, "llib": { "type": "Project", "dependencies": { From f04233a325b26af4c812bb221455b05233ad70cf Mon Sep 17 00:00:00 2001 From: Liza Carvelli Date: Sat, 3 Aug 2024 17:26:49 +0200 Subject: [PATCH 12/12] Implement min/btn collectable logic --- GatheringPathRenderer/EditorCommands.cs | 11 +- GatheringPathRenderer/Windows/EditorWindow.cs | 25 +-- .../822_Monitoring Station G_MIN.json | 158 ++++++++++++++++++ .../821_The Crushing Brand_MIN.json | 157 +++++++++++++++++ ...e.json => 820_The Hamsa Hatchery_MIN.json} | 0 ...romite Ore.json => 974_Chabameki_MIN.json} | 0 ...now Cotton.json => 992_Chabameki_BTN.json} | 0 ...rali Aloe.json => 993_Chabayuqeq_MIN.json} | 0 .../6.x - Endwalker/4807_DebugGathering.json | 27 +++ .../MIN, BTN/4153_Cultured Pursuits.json | 3 +- .../MIN, BTN/4154_Cooking Up a Culture.json | 9 +- .../4155_The Culture of Ceruleum.json | 49 ++++++ .../MIN, BTN/4156_The Culture of Carrots.json | 49 ++++++ .../MIN, BTN/4157_Hinageshi in Hingashi.json | 21 +++ Questionable.Model/Questing/EAction.cs | 12 ++ Questionable.Model/Questing/GatheredItem.cs | 2 +- .../Controller/GatheringController.cs | 52 ++++-- Questionable/Controller/MovementController.cs | 2 +- Questionable/Controller/QuestController.cs | 63 ++++--- .../Controller/Steps/Gathering/DoGather.cs | 77 +++++++++ .../Steps/Gathering/DoGatherCollectable.cs | 151 +++++++++++++++++ .../Steps/Gathering/MoveToLandingLocation.cs | 27 ++- .../Controller/Steps/Gathering/WaitGather.cs | 25 --- .../Steps/Shared/GatheringRequiredItems.cs | 9 +- Questionable/External/NavmeshIpc.cs | 4 +- Questionable/GameFunctions.cs | 2 +- Questionable/QuestionablePlugin.cs | 3 +- 27 files changed, 839 insertions(+), 99 deletions(-) create mode 100644 GatheringPaths/6.x - Endwalker/Garlemald/822_Monitoring Station G_MIN.json create mode 100644 GatheringPaths/6.x - Endwalker/Mare Lamentorum/821_The Crushing Brand_MIN.json rename GatheringPaths/6.x - Endwalker/Thavnair/{820_Pewter Ore.json => 820_The Hamsa Hatchery_MIN.json} (100%) rename GatheringPaths/7.x - Dawntrail/Urqopacha/{974_Mountain Chromite Ore.json => 974_Chabameki_MIN.json} (100%) rename GatheringPaths/7.x - Dawntrail/Urqopacha/{992_Snow Cotton.json => 992_Chabameki_BTN.json} (100%) rename GatheringPaths/7.x - Dawntrail/Urqopacha/{993_Turali Aloe.json => 993_Chabayuqeq_MIN.json} (100%) create mode 100644 QuestPaths/6.x - Endwalker/4807_DebugGathering.json create mode 100644 QuestPaths/6.x - Endwalker/Studium Deliveries/MIN, BTN/4155_The Culture of Ceruleum.json create mode 100644 QuestPaths/6.x - Endwalker/Studium Deliveries/MIN, BTN/4156_The Culture of Carrots.json create mode 100644 QuestPaths/6.x - Endwalker/Studium Deliveries/MIN, BTN/4157_Hinageshi in Hingashi.json create mode 100644 Questionable/Controller/Steps/Gathering/DoGather.cs create mode 100644 Questionable/Controller/Steps/Gathering/DoGatherCollectable.cs delete mode 100644 Questionable/Controller/Steps/Gathering/WaitGather.cs diff --git a/GatheringPathRenderer/EditorCommands.cs b/GatheringPathRenderer/EditorCommands.cs index d5008b27..d15e6207 100644 --- a/GatheringPathRenderer/EditorCommands.cs +++ b/GatheringPathRenderer/EditorCommands.cs @@ -93,7 +93,7 @@ internal sealed class EditorCommands : IDisposable } else { - (targetFile, root) = CreateNewFile(gatheringPoint, target, string.Join(" ", arguments)); + (targetFile, root) = CreateNewFile(gatheringPoint, target); _chatGui.Print($"Creating new file under {targetFile.FullName}", "qG"); } @@ -164,12 +164,8 @@ internal sealed class EditorCommands : IDisposable } } - public (FileInfo targetFile, GatheringRoot root) CreateNewFile(GatheringPoint gatheringPoint, IGameObject target, - string fileName) + public (FileInfo targetFile, GatheringRoot root) CreateNewFile(GatheringPoint gatheringPoint, IGameObject target) { - if (string.IsNullOrEmpty(fileName)) - throw new ArgumentException(nameof(fileName)); - // determine target folder DirectoryInfo? targetFolder = _plugin.GetLocationsInTerritory(_clientState.TerritoryType).FirstOrDefault() ?.File.Directory; @@ -183,7 +179,8 @@ internal sealed class EditorCommands : IDisposable FileInfo targetFile = new FileInfo( - Path.Combine(targetFolder.FullName, $"{gatheringPoint.GatheringPointBase.Row}_{fileName}.json")); + Path.Combine(targetFolder.FullName, + $"{gatheringPoint.GatheringPointBase.Row}_{gatheringPoint.PlaceName.Value!.Name}_{(_clientState.LocalPlayer!.ClassJob.Id == 16 ? "MIN" : "BTN")}.json")); var root = new GatheringRoot { TerritoryId = _clientState.TerritoryType, diff --git a/GatheringPathRenderer/Windows/EditorWindow.cs b/GatheringPathRenderer/Windows/EditorWindow.cs index ec7293f6..d2edf65e 100644 --- a/GatheringPathRenderer/Windows/EditorWindow.cs +++ b/GatheringPathRenderer/Windows/EditorWindow.cs @@ -7,6 +7,7 @@ using System.Numerics; using Dalamud.Game.ClientState.Objects; using Dalamud.Game.ClientState.Objects.Enums; using Dalamud.Game.ClientState.Objects.Types; +using Dalamud.Interface.Colors; using Dalamud.Interface.Windowing; using Dalamud.Plugin.Services; using ImGuiNET; @@ -31,8 +32,6 @@ internal sealed class EditorWindow : Window private (RendererPlugin.GatheringLocationContext Context, GatheringNode Node, GatheringLocation Location)? _targetLocation; - private string _newFileName = string.Empty; - public EditorWindow(RendererPlugin plugin, EditorCommands editorCommands, IDataManager dataManager, ITargetManager targetManager, IClientState clientState, IObjectTable objectTable) : base("Gathering Path Editor###QuestionableGatheringPathEditor") @@ -68,13 +67,19 @@ internal sealed class EditorWindow : Window }) .Select(location => new { Context = context, Node = node, Location = location })))) .FirstOrDefault(); - if (_target != null && _target.ObjectKind != ObjectKind.GatheringPoint || location == null) + if (_target != null && _target.ObjectKind != ObjectKind.GatheringPoint) { _target = null; _targetLocation = null; return; } + if (location == null) + { + _targetLocation = null; + return; + } + _target ??= _objectTable.FirstOrDefault( x => x.ObjectKind == ObjectKind.GatheringPoint && x.DataId == location.Node.DataId && @@ -123,13 +128,18 @@ internal sealed class EditorWindow : Window _plugin.Redraw(); } - ImGui.BeginDisabled(locationOverride.MinimumAngle == null && locationOverride.MaximumAngle == null); + bool unsaved = locationOverride is { MinimumAngle: not null, MaximumAngle: not null }; + ImGui.BeginDisabled(!unsaved); + if (unsaved) + ImGui.PushStyleColor(ImGuiCol.Button, ImGuiColors.DalamudRed); if (ImGui.Button("Save")) { location.MinimumAngle = locationOverride.MinimumAngle; location.MaximumAngle = locationOverride.MaximumAngle; _plugin.Save(context.File, context.Root); } + if (unsaved) + ImGui.PopStyleColor(); ImGui.SameLine(); if (ImGui.Button("Reset")) @@ -189,16 +199,11 @@ internal sealed class EditorWindow : Window } else { - ImGui.InputText("File Name", ref _newFileName, 128); - ImGui.BeginDisabled(string.IsNullOrEmpty(_newFileName)); if (ImGui.Button("Create location")) { - var (targetFile, root) = _editorCommands.CreateNewFile(gatheringPoint, _target, _newFileName); + var (targetFile, root) = _editorCommands.CreateNewFile(gatheringPoint, _target); _plugin.Save(targetFile, root); - _newFileName = string.Empty; } - - ImGui.EndDisabled(); } } } diff --git a/GatheringPaths/6.x - Endwalker/Garlemald/822_Monitoring Station G_MIN.json b/GatheringPaths/6.x - Endwalker/Garlemald/822_Monitoring Station G_MIN.json new file mode 100644 index 00000000..2ba70d89 --- /dev/null +++ b/GatheringPaths/6.x - Endwalker/Garlemald/822_Monitoring Station G_MIN.json @@ -0,0 +1,158 @@ +{ + "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json", + "Author": [], + "TerritoryId": 958, + "AetheryteShortcut": "Garlemald - Camp Broken Glass", + "Groups": [ + { + "Nodes": [ + { + "DataId": 33932, + "Locations": [ + { + "Position": { + "X": -80.95969, + "Y": -9.810837, + "Z": 462.2579 + }, + "MinimumAngle": 130, + "MaximumAngle": 260 + } + ] + }, + { + "DataId": 33933, + "Locations": [ + { + "Position": { + "X": -72.11935, + "Y": -10.90324, + "Z": 471.2258 + }, + "MinimumAngle": 105, + "MaximumAngle": 250 + }, + { + "Position": { + "X": -98.97565, + "Y": -5.664787, + "Z": 463.9966 + }, + "MinimumAngle": 60, + "MaximumAngle": 230 + }, + { + "Position": { + "X": -63.49503, + "Y": -11.21235, + "Z": 469.3839 + }, + "MinimumAngle": 80, + "MaximumAngle": 255 + } + ] + } + ] + }, + { + "Nodes": [ + { + "DataId": 33931, + "Locations": [ + { + "Position": { + "X": -61.34306, + "Y": 6.11244, + "Z": 318.3409 + }, + "MinimumAngle": -120, + "MaximumAngle": 70 + }, + { + "Position": { + "X": -61.47854, + "Y": 6.076105, + "Z": 281.4938 + }, + "MinimumAngle": 65, + "MaximumAngle": 240 + }, + { + "Position": { + "X": -73.25829, + "Y": 6.108262, + "Z": 302.9926 + }, + "MinimumAngle": 50, + "MaximumAngle": 220 + } + ] + }, + { + "DataId": 33930, + "Locations": [ + { + "Position": { + "X": -51.28564, + "Y": 6.088318, + "Z": 318.0529 + }, + "MinimumAngle": -65, + "MaximumAngle": 110 + } + ] + } + ] + }, + { + "Nodes": [ + { + "DataId": 33935, + "Locations": [ + { + "Position": { + "X": 72.58704, + "Y": -11.59895, + "Z": 354.757 + }, + "MinimumAngle": 75, + "MaximumAngle": 235 + }, + { + "Position": { + "X": 65.33016, + "Y": -11.61111, + "Z": 358.7321 + }, + "MinimumAngle": 65, + "MaximumAngle": 235 + }, + { + "Position": { + "X": 68.21196, + "Y": -11.81954, + "Z": 366.5172 + }, + "MinimumAngle": 5, + "MaximumAngle": 85 + } + ] + }, + { + "DataId": 33934, + "Locations": [ + { + "Position": { + "X": 81.30492, + "Y": -11.53227, + "Z": 347.9922 + }, + "MinimumAngle": 50, + "MaximumAngle": 215 + } + ] + } + ] + } + ] +} diff --git a/GatheringPaths/6.x - Endwalker/Mare Lamentorum/821_The Crushing Brand_MIN.json b/GatheringPaths/6.x - Endwalker/Mare Lamentorum/821_The Crushing Brand_MIN.json new file mode 100644 index 00000000..0b667246 --- /dev/null +++ b/GatheringPaths/6.x - Endwalker/Mare Lamentorum/821_The Crushing Brand_MIN.json @@ -0,0 +1,157 @@ +{ + "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json", + "Author": [], + "TerritoryId": 959, + "Groups": [ + { + "Nodes": [ + { + "DataId": 33929, + "Locations": [ + { + "Position": { + "X": 304.4121, + "Y": 118.8077, + "Z": 673.4494 + }, + "MinimumAngle": 50, + "MaximumAngle": 230 + }, + { + "Position": { + "X": 297.7666, + "Y": 119.4976, + "Z": 679.5604 + }, + "MinimumAngle": 50, + "MaximumAngle": 220 + }, + { + "Position": { + "X": 322.163, + "Y": 119.0883, + "Z": 657.4384 + }, + "MinimumAngle": 55, + "MaximumAngle": 235 + } + ] + }, + { + "DataId": 33928, + "Locations": [ + { + "Position": { + "X": 313.72, + "Y": 118.3442, + "Z": 664.8668 + }, + "MinimumAngle": 60, + "MaximumAngle": 230 + } + ] + } + ] + }, + { + "Nodes": [ + { + "DataId": 33927, + "Locations": [ + { + "Position": { + "X": 394.3838, + "Y": 144.7951, + "Z": 820.7851 + }, + "MinimumAngle": 75, + "MaximumAngle": 250 + }, + { + "Position": { + "X": 421.0549, + "Y": 143.6111, + "Z": 805.9457 + }, + "MinimumAngle": 60, + "MaximumAngle": 225 + }, + { + "Position": { + "X": 414.2961, + "Y": 143.2405, + "Z": 811.3884 + }, + "MinimumAngle": 65, + "MaximumAngle": 230 + } + ] + }, + { + "DataId": 33926, + "Locations": [ + { + "Position": { + "X": 405.2481, + "Y": 143.6621, + "Z": 816.6496 + }, + "MinimumAngle": 75, + "MaximumAngle": 230 + } + ] + } + ] + }, + { + "Nodes": [ + { + "DataId": 33925, + "Locations": [ + { + "Position": { + "X": 474.679, + "Y": 143.4776, + "Z": 698.5961 + }, + "MinimumAngle": 20, + "MaximumAngle": 170 + }, + { + "Position": { + "X": 474.8585, + "Y": 144.2588, + "Z": 685.7468 + }, + "MinimumAngle": 0, + "MaximumAngle": 155 + }, + { + "Position": { + "X": 467.506, + "Y": 144.9235, + "Z": 654.2 + }, + "MinimumAngle": 0, + "MaximumAngle": 150 + } + ] + }, + { + "DataId": 33924, + "Locations": [ + { + "Position": { + "X": 470.7754, + "Y": 144.8793, + "Z": 672.114 + }, + "MinimumAngle": -5, + "MaximumAngle": 165 + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/GatheringPaths/6.x - Endwalker/Thavnair/820_Pewter Ore.json b/GatheringPaths/6.x - Endwalker/Thavnair/820_The Hamsa Hatchery_MIN.json similarity index 100% rename from GatheringPaths/6.x - Endwalker/Thavnair/820_Pewter Ore.json rename to GatheringPaths/6.x - Endwalker/Thavnair/820_The Hamsa Hatchery_MIN.json diff --git a/GatheringPaths/7.x - Dawntrail/Urqopacha/974_Mountain Chromite Ore.json b/GatheringPaths/7.x - Dawntrail/Urqopacha/974_Chabameki_MIN.json similarity index 100% rename from GatheringPaths/7.x - Dawntrail/Urqopacha/974_Mountain Chromite Ore.json rename to GatheringPaths/7.x - Dawntrail/Urqopacha/974_Chabameki_MIN.json diff --git a/GatheringPaths/7.x - Dawntrail/Urqopacha/992_Snow Cotton.json b/GatheringPaths/7.x - Dawntrail/Urqopacha/992_Chabameki_BTN.json similarity index 100% rename from GatheringPaths/7.x - Dawntrail/Urqopacha/992_Snow Cotton.json rename to GatheringPaths/7.x - Dawntrail/Urqopacha/992_Chabameki_BTN.json diff --git a/GatheringPaths/7.x - Dawntrail/Urqopacha/993_Turali Aloe.json b/GatheringPaths/7.x - Dawntrail/Urqopacha/993_Chabayuqeq_MIN.json similarity index 100% rename from GatheringPaths/7.x - Dawntrail/Urqopacha/993_Turali Aloe.json rename to GatheringPaths/7.x - Dawntrail/Urqopacha/993_Chabayuqeq_MIN.json diff --git a/QuestPaths/6.x - Endwalker/4807_DebugGathering.json b/QuestPaths/6.x - Endwalker/4807_DebugGathering.json new file mode 100644 index 00000000..3d411f43 --- /dev/null +++ b/QuestPaths/6.x - Endwalker/4807_DebugGathering.json @@ -0,0 +1,27 @@ +{ + "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/QuestPaths/quest-v1.json", + "Author": "liza", + "QuestSequence": [ + { + "Sequence": 255, + "Steps": [ + { + "Position": { + "X": -435.39066, + "Y": -9.809827, + "Z": -594.5472 + }, + "TerritoryId": 1187, + "InteractionType": "WalkTo", + "Fly": true, + "RequiredGatheredItems": [ + { + "ItemId": 43992, + "ItemCount": 1234 + } + ] + } + ] + } + ] +} diff --git a/QuestPaths/6.x - Endwalker/Studium Deliveries/MIN, BTN/4153_Cultured Pursuits.json b/QuestPaths/6.x - Endwalker/Studium Deliveries/MIN, BTN/4153_Cultured Pursuits.json index 9e198c81..d9f54e22 100644 --- a/QuestPaths/6.x - Endwalker/Studium Deliveries/MIN, BTN/4153_Cultured Pursuits.json +++ b/QuestPaths/6.x - Endwalker/Studium Deliveries/MIN, BTN/4153_Cultured Pursuits.json @@ -59,7 +59,8 @@ }, "StopDistance": 7, "TerritoryId": 962, - "InteractionType": "CompleteQuest" + "InteractionType": "CompleteQuest", + "NextQuestId": 4154 } ] } diff --git a/QuestPaths/6.x - Endwalker/Studium Deliveries/MIN, BTN/4154_Cooking Up a Culture.json b/QuestPaths/6.x - Endwalker/Studium Deliveries/MIN, BTN/4154_Cooking Up a Culture.json index 4be51dda..30720303 100644 --- a/QuestPaths/6.x - Endwalker/Studium Deliveries/MIN, BTN/4154_Cooking Up a Culture.json +++ b/QuestPaths/6.x - Endwalker/Studium Deliveries/MIN, BTN/4154_Cooking Up a Culture.json @@ -1,7 +1,6 @@ { "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/QuestPaths/quest-v1.json", "Author": "liza", - "Disabled": true, "QuestSequence": [ { "Sequence": 0, @@ -30,13 +29,19 @@ }, "TerritoryId": 962, "InteractionType": "CompleteQuest", + "AetheryteShortcut": "Old Sharlayan", + "AethernetShortcut": [ + "[Old Sharlayan] Aetheryte Plaza", + "[Old Sharlayan] The Studium" + ], "RequiredGatheredItems": [ { "ItemId": 35600, "ItemCount": 6, "Collectability": 600 } - ] + ], + "NextQuestId": 4155 } ] } diff --git a/QuestPaths/6.x - Endwalker/Studium Deliveries/MIN, BTN/4155_The Culture of Ceruleum.json b/QuestPaths/6.x - Endwalker/Studium Deliveries/MIN, BTN/4155_The Culture of Ceruleum.json new file mode 100644 index 00000000..ca598552 --- /dev/null +++ b/QuestPaths/6.x - Endwalker/Studium Deliveries/MIN, BTN/4155_The Culture of Ceruleum.json @@ -0,0 +1,49 @@ +{ + "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/QuestPaths/quest-v1.json", + "Author": "liza", + "QuestSequence": [ + { + "Sequence": 0, + "Steps": [ + { + "DataId": 1038501, + "Position": { + "X": -367.3305, + "Y": 21.846018, + "Z": -102.983154 + }, + "TerritoryId": 962, + "InteractionType": "AcceptQuest" + } + ] + }, + { + "Sequence": 255, + "Steps": [ + { + "DataId": 1038501, + "Position": { + "X": -367.3305, + "Y": 21.846018, + "Z": -102.983154 + }, + "TerritoryId": 962, + "InteractionType": "CompleteQuest", + "AetheryteShortcut": "Old Sharlayan", + "AethernetShortcut": [ + "[Old Sharlayan] Aetheryte Plaza", + "[Old Sharlayan] The Studium" + ], + "RequiredGatheredItems": [ + { + "ItemId": 35601, + "ItemCount": 6, + "Collectability": 600 + } + ], + "NextQuestId": 4156 + } + ] + } + ] +} diff --git a/QuestPaths/6.x - Endwalker/Studium Deliveries/MIN, BTN/4156_The Culture of Carrots.json b/QuestPaths/6.x - Endwalker/Studium Deliveries/MIN, BTN/4156_The Culture of Carrots.json new file mode 100644 index 00000000..d25034d3 --- /dev/null +++ b/QuestPaths/6.x - Endwalker/Studium Deliveries/MIN, BTN/4156_The Culture of Carrots.json @@ -0,0 +1,49 @@ +{ + "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/QuestPaths/quest-v1.json", + "Author": "liza", + "QuestSequence": [ + { + "Sequence": 0, + "Steps": [ + { + "DataId": 1038501, + "Position": { + "X": -367.3305, + "Y": 21.846018, + "Z": -102.983154 + }, + "TerritoryId": 962, + "InteractionType": "AcceptQuest" + } + ] + }, + { + "Sequence": 255, + "Steps": [ + { + "DataId": 1038501, + "Position": { + "X": -367.3305, + "Y": 21.846018, + "Z": -102.983154 + }, + "TerritoryId": 962, + "InteractionType": "CompleteQuest", + "AetheryteShortcut": "Old Sharlayan", + "AethernetShortcut": [ + "[Old Sharlayan] Aetheryte Plaza", + "[Old Sharlayan] The Studium" + ], + "RequiredGatheredItems": [ + { + "ItemId": 35602, + "ItemCount": 6, + "Collectability": 600 + } + ], + "NextQuestId": 4157 + } + ] + } + ] +} diff --git a/QuestPaths/6.x - Endwalker/Studium Deliveries/MIN, BTN/4157_Hinageshi in Hingashi.json b/QuestPaths/6.x - Endwalker/Studium Deliveries/MIN, BTN/4157_Hinageshi in Hingashi.json new file mode 100644 index 00000000..a59c4db7 --- /dev/null +++ b/QuestPaths/6.x - Endwalker/Studium Deliveries/MIN, BTN/4157_Hinageshi in Hingashi.json @@ -0,0 +1,21 @@ +{ + "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/QuestPaths/quest-v1.json", + "Author": "liza", + "QuestSequence": [ + { + "Sequence": 0, + "Steps": [ + { + "DataId": 1038501, + "Position": { + "X": -367.3305, + "Y": 21.846018, + "Z": -102.983154 + }, + "TerritoryId": 962, + "InteractionType": "AcceptQuest" + } + ] + } + ] +} diff --git a/Questionable.Model/Questing/EAction.cs b/Questionable.Model/Questing/EAction.cs index 4b24dee1..c078e4a3 100644 --- a/Questionable.Model/Questing/EAction.cs +++ b/Questionable.Model/Questing/EAction.cs @@ -15,6 +15,18 @@ public enum EAction RedGulal = 29382, YellowGulal = 29383, BlueGulal = 29384, + + CollectMiner = 240, + ScourMiner = 22182, + MeticulousMiner = 22184, + ScrutinyMiner = 22185, + + CollectBotanist = 815, + ScourBotanist = 22186, + MeticulousBotanist = 22188, + ScrutinyBotanist = 22189, + + } public static class EActionExtensions diff --git a/Questionable.Model/Questing/GatheredItem.cs b/Questionable.Model/Questing/GatheredItem.cs index 41bd0624..bfc6fd1a 100644 --- a/Questionable.Model/Questing/GatheredItem.cs +++ b/Questionable.Model/Questing/GatheredItem.cs @@ -4,5 +4,5 @@ public sealed class GatheredItem { public uint ItemId { get; set; } public int ItemCount { get; set; } - public short Collectability { get; set; } + public ushort Collectability { get; set; } } diff --git a/Questionable/Controller/GatheringController.cs b/Questionable/Controller/GatheringController.cs index 45fccf64..ff19d3f4 100644 --- a/Questionable/Controller/GatheringController.cs +++ b/Questionable/Controller/GatheringController.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Numerics; +using Dalamud.Game.ClientState.Conditions; using Dalamud.Game.ClientState.Objects.Enums; using Dalamud.Plugin.Services; using FFXIVClientStructs.FFXIV.Client.Game; @@ -12,7 +13,6 @@ using Questionable.Controller.Steps.Common; using Questionable.Controller.Steps.Gathering; using Questionable.Controller.Steps.Interactions; using Questionable.Controller.Steps.Shared; -using Questionable.Data; using Questionable.External; using Questionable.GatheringPaths; using Questionable.Model.Gathering; @@ -22,25 +22,31 @@ namespace Questionable.Controller; internal sealed unsafe class GatheringController : MiniTaskController { private readonly MovementController _movementController; - private readonly GatheringData _gatheringData; private readonly GameFunctions _gameFunctions; private readonly NavmeshIpc _navmeshIpc; private readonly IObjectTable _objectTable; private readonly IServiceProvider _serviceProvider; + private readonly ICondition _condition; private CurrentRequest? _currentRequest; - public GatheringController(MovementController movementController, GatheringData gatheringData, - GameFunctions gameFunctions, NavmeshIpc navmeshIpc, IObjectTable objectTable, IChatGui chatGui, - ILogger logger, IServiceProvider serviceProvider) + public GatheringController( + MovementController movementController, + GameFunctions gameFunctions, + NavmeshIpc navmeshIpc, + IObjectTable objectTable, + IChatGui chatGui, + ILogger logger, + IServiceProvider serviceProvider, + ICondition condition) : base(chatGui, logger) { _movementController = movementController; - _gatheringData = gatheringData; _gameFunctions = gameFunctions; _navmeshIpc = navmeshIpc; _objectTable = objectTable; _serviceProvider = serviceProvider; + _condition = condition; } public bool Start(GatheringRequest gatheringRequest) @@ -58,7 +64,8 @@ internal sealed unsafe class GatheringController : MiniTaskController x.Nodes) + // at least in EW-ish, there's one node with 1 fixed location and one node with 3 random locations + .SelectMany(x => x.Nodes.OrderBy(y => y.Locations.Count)) .ToList(), }; @@ -79,7 +86,7 @@ internal sealed unsafe class GatheringController : MiniTaskController x.Position.Y).Max() + 5f, Z = currentNode.Locations.Sum(x => x.Position.Z) / currentNode.Locations.Count, }; - Vector3? pointOnFloor = _navmeshIpc.GetPointOnFloor(averagePosition); + bool fly = _gameFunctions.IsFlyingUnlocked(_currentRequest.Root.TerritoryId); + Vector3? pointOnFloor = _navmeshIpc.GetPointOnFloor(averagePosition, true); if (pointOnFloor != null) - pointOnFloor = pointOnFloor.Value with { Y = pointOnFloor.Value.Y + 3f }; + pointOnFloor = pointOnFloor.Value with { Y = pointOnFloor.Value.Y + (fly ? 3f : 0f) }; _taskQueue.Enqueue(_serviceProvider.GetRequiredService() - .With(_currentRequest.Root.TerritoryId, pointOnFloor ?? averagePosition, 50f, fly: true, + .With(_currentRequest.Root.TerritoryId, pointOnFloor ?? averagePosition, 50f, fly: fly, ignoreDistanceToObject: true)); } @@ -131,7 +139,13 @@ internal sealed unsafe class GatheringController : MiniTaskController() .With(currentNode.DataId, true)); - _taskQueue.Enqueue(_serviceProvider.GetRequiredService()); + _taskQueue.Enqueue(_serviceProvider.GetRequiredService() + .With(_currentRequest.Data, currentNode)); + if (_currentRequest.Data.Collectability > 0) + { + _taskQueue.Enqueue(_serviceProvider.GetRequiredService() + .With(_currentRequest.Data, currentNode)); + } } private bool HasRequestedItems() @@ -144,7 +158,13 @@ internal sealed unsafe class GatheringController : MiniTaskControllerGetInventoryItemCount(_currentRequest.Data.ItemId, - minCollectability: _currentRequest.Data.Collectability) >= _currentRequest.Data.Quantity; + minCollectability: (short)_currentRequest.Data.Collectability) >= _currentRequest.Data.Quantity; + } + + public bool HasNodeDisappeared(GatheringNode node) + { + return !_objectTable.Any(x => + x.ObjectKind == ObjectKind.GatheringPoint && x.IsTargetable && x.DataId == node.DataId); } public override IList GetRemainingTaskNames() @@ -168,7 +188,11 @@ internal sealed unsafe class GatheringController : MiniTaskController 0.5f; } diff --git a/Questionable/Controller/QuestController.cs b/Questionable/Controller/QuestController.cs index a7b77ac2..9b7fe9a9 100644 --- a/Questionable/Controller/QuestController.cs +++ b/Questionable/Controller/QuestController.cs @@ -461,35 +461,44 @@ internal sealed class QuestController : MiniTaskController _combatController.Stop("Execute next step"); _gatheringController.Stop("Execute next step"); - var newTasks = _taskFactories - .SelectMany(x => - { - IList tasks = x.CreateAllTasks(CurrentQuest.Quest, seq, step).ToList(); - - if (tasks.Count > 0 && _logger.IsEnabled(LogLevel.Trace)) - { - string factoryName = x.GetType().FullName ?? x.GetType().Name; - if (factoryName.Contains('.', StringComparison.Ordinal)) - factoryName = factoryName[(factoryName.LastIndexOf('.') + 1)..]; - - _logger.LogTrace("Factory {FactoryName} created Task {TaskNames}", - factoryName, string.Join(", ", tasks.Select(y => y.ToString()))); - } - - return tasks; - }) - .ToList(); - if (newTasks.Count == 0) + try { - _logger.LogInformation("Nothing to execute for step?"); - return; - } + var newTasks = _taskFactories + .SelectMany(x => + { + IList tasks = x.CreateAllTasks(CurrentQuest.Quest, seq, step).ToList(); - _logger.LogInformation("Tasks for {QuestId}, {Sequence}, {Step}: {Tasks}", - CurrentQuest.Quest.QuestId, seq.Sequence, seq.Steps.IndexOf(step), - string.Join(", ", newTasks.Select(x => x.ToString()))); - foreach (var task in newTasks) - _taskQueue.Enqueue(task); + if (tasks.Count > 0 && _logger.IsEnabled(LogLevel.Trace)) + { + string factoryName = x.GetType().FullName ?? x.GetType().Name; + if (factoryName.Contains('.', StringComparison.Ordinal)) + factoryName = factoryName[(factoryName.LastIndexOf('.') + 1)..]; + + _logger.LogTrace("Factory {FactoryName} created Task {TaskNames}", + factoryName, string.Join(", ", tasks.Select(y => y.ToString()))); + } + + return tasks; + }) + .ToList(); + if (newTasks.Count == 0) + { + _logger.LogInformation("Nothing to execute for step?"); + return; + } + + _logger.LogInformation("Tasks for {QuestId}, {Sequence}, {Step}: {Tasks}", + CurrentQuest.Quest.QuestId, seq.Sequence, seq.Steps.IndexOf(step), + string.Join(", ", newTasks.Select(x => x.ToString()))); + foreach (var task in newTasks) + _taskQueue.Enqueue(task); + } + catch (Exception e) + { + _logger.LogError(e, "Failed to create tasks"); + _chatGui.PrintError("[Questionable] Failed to start next task sequence, please check /xllog for details."); + Stop("Tasks failed to create"); + } } public string ToStatString() diff --git a/Questionable/Controller/Steps/Gathering/DoGather.cs b/Questionable/Controller/Steps/Gathering/DoGather.cs new file mode 100644 index 00000000..914d91b1 --- /dev/null +++ b/Questionable/Controller/Steps/Gathering/DoGather.cs @@ -0,0 +1,77 @@ +using System.Collections.Generic; +using System.Linq; +using Dalamud.Game.ClientState.Conditions; +using Dalamud.Plugin.Services; +using FFXIVClientStructs.FFXIV.Component.GUI; +using LLib.GameUI; +using Questionable.Model.Gathering; + +namespace Questionable.Controller.Steps.Gathering; + +internal sealed class DoGather( + GatheringController gatheringController, + IGameGui gameGui, + ICondition condition) : ITask +{ + private GatheringController.GatheringRequest _currentRequest = null!; + private GatheringNode _currentNode = null!; + private bool _wasGathering; + private List? _slots; + + + public ITask With(GatheringController.GatheringRequest currentRequest, GatheringNode currentNode) + { + _currentRequest = currentRequest; + _currentNode = currentNode; + return this; + } + + public bool Start() => true; + + public unsafe ETaskResult Update() + { + if (gatheringController.HasNodeDisappeared(_currentNode)) + return ETaskResult.TaskComplete; + + if (condition[ConditionFlag.Gathering]) + { + if (gameGui.TryGetAddonByName("GatheringMasterpiece", out AtkUnitBase* _)) + return ETaskResult.TaskComplete; + + _wasGathering = true; + + if (gameGui.TryGetAddonByName("Gathering", out AtkUnitBase* atkUnitBase)) + { + _slots ??= ReadSlots(atkUnitBase); + var slot = _slots.Single(x => x.ItemId == _currentRequest.ItemId); + atkUnitBase->FireCallbackInt(slot.Index); + } + } + + return _wasGathering && !condition[ConditionFlag.Gathering] + ? ETaskResult.TaskComplete + : ETaskResult.StillRunning; + } + + private unsafe List ReadSlots(AtkUnitBase* atkUnitBase) + { + var atkValues = atkUnitBase->AtkValues; + List slots = new List(); + for (int i = 0; i < 8; ++i) + { + // +8 = new item? + uint itemId = atkValues[i * 11 + 7].UInt; + if (itemId == 0) + continue; + + var slot = new SlotInfo(i, itemId); + slots.Add(slot); + } + + return slots; + } + + public override string ToString() => "DoGather"; + + private sealed record SlotInfo(int Index, uint ItemId); +} diff --git a/Questionable/Controller/Steps/Gathering/DoGatherCollectable.cs b/Questionable/Controller/Steps/Gathering/DoGatherCollectable.cs new file mode 100644 index 00000000..6a331ac0 --- /dev/null +++ b/Questionable/Controller/Steps/Gathering/DoGatherCollectable.cs @@ -0,0 +1,151 @@ +using System.Collections.Generic; +using Dalamud.Game.Text; +using Dalamud.Plugin.Services; +using FFXIVClientStructs.FFXIV.Component.GUI; +using LLib.GameUI; +using Microsoft.Extensions.Logging; +using Questionable.Model.Gathering; +using Questionable.Model.Questing; + +namespace Questionable.Controller.Steps.Gathering; + +internal sealed class DoGatherCollectable( + GatheringController gatheringController, + GameFunctions gameFunctions, + IClientState clientState, + IGameGui gameGui, + ILogger logger) : ITask +{ + private GatheringController.GatheringRequest _currentRequest = null!; + private GatheringNode _currentNode = null!; + private Queue? _actionQueue; + + public ITask With(GatheringController.GatheringRequest currentRequest, GatheringNode currentNode) + { + _currentRequest = currentRequest; + _currentNode = currentNode; + return this; + } + + public bool Start() => true; + + public ETaskResult Update() + { + if (gatheringController.HasNodeDisappeared(_currentNode)) + return ETaskResult.TaskComplete; + + NodeCondition? nodeCondition = GetNodeCondition(); + if (nodeCondition == null) + return ETaskResult.TaskComplete; + + if (_actionQueue != null && _actionQueue.TryPeek(out EAction nextAction)) + { + if (gameFunctions.UseAction(nextAction)) + { + logger.LogInformation("Used action {Action} on node", nextAction); + _actionQueue.Dequeue(); + } + + return ETaskResult.StillRunning; + } + + if (nodeCondition.CollectabilityToGoal(_currentRequest.Collectability) > 0) + { + _actionQueue = GetNextActions(nodeCondition); + if (_actionQueue != null) + { + foreach (var action in _actionQueue) + logger.LogInformation("Next Actions {Action}", action); + return ETaskResult.StillRunning; + } + } + + _actionQueue = new Queue(); + _actionQueue.Enqueue(PickAction(EAction.CollectMiner, EAction.CollectBotanist)); + return ETaskResult.StillRunning; + } + + private unsafe NodeCondition? GetNodeCondition() + { + if (gameGui.TryGetAddonByName("GatheringMasterpiece", out AtkUnitBase* atkUnitBase)) + { + var atkValues = atkUnitBase->AtkValues; + return new NodeCondition( + CurrentCollectability: atkValues[13].UInt, + MaxCollectability: atkValues[14].UInt, + CurrentIntegrity: atkValues[62].UInt, + MaxIntegrity: atkValues[63].UInt, + ScrutinyActive: atkValues[80].Bool, + CollectabilityFromScour: atkValues[48].UInt, + CollectabilityFromMeticulous: atkValues[51].UInt + ); + } + + return null; + } + + private Queue? GetNextActions(NodeCondition nodeCondition) + { + uint gp = clientState.LocalPlayer!.CurrentGp; + Queue actions = new(); + + uint neededCollectability = nodeCondition.CollectabilityToGoal(_currentRequest.Collectability); + if (neededCollectability <= nodeCondition.CollectabilityFromMeticulous) + { + actions.Enqueue(PickAction(EAction.MeticulousMiner, EAction.MeticulousBotanist)); + return actions; + } + + if (neededCollectability <= nodeCondition.CollectabilityFromScour) + { + actions.Enqueue(PickAction(EAction.ScourMiner, EAction.ScourBotanist)); + return actions; + } + + // neither action directly solves our problem + if (!nodeCondition.ScrutinyActive && gp >= 200) + { + actions.Enqueue(PickAction(EAction.ScrutinyMiner, EAction.ScrutinyBotanist)); + return actions; + } + + if (nodeCondition.ScrutinyActive) + { + actions.Enqueue(PickAction(EAction.MeticulousMiner, EAction.MeticulousBotanist)); + return actions; + } + else + { + actions.Enqueue(PickAction(EAction.ScourMiner, EAction.ScourBotanist)); + return actions; + } + } + + private EAction PickAction(EAction minerAction, EAction botanistAction) + { + if (clientState.LocalPlayer?.ClassJob.Id == 16) + return minerAction; + else + return botanistAction; + } + + public override string ToString() => + $"DoGatherCollectable({SeIconChar.Collectible.ToIconString()} {_currentRequest.Collectability})"; + + private sealed record NodeCondition( + uint CurrentCollectability, + uint MaxCollectability, + uint CurrentIntegrity, + uint MaxIntegrity, + bool ScrutinyActive, + uint CollectabilityFromScour, + uint CollectabilityFromMeticulous) + { + public uint CollectabilityToGoal(uint goal) + { + if (goal >= CurrentCollectability) + return goal - CurrentCollectability; + return CurrentCollectability == 0 ? 1u : 0u; + } + } +} diff --git a/Questionable/Controller/Steps/Gathering/MoveToLandingLocation.cs b/Questionable/Controller/Steps/Gathering/MoveToLandingLocation.cs index 3336500f..5f6a2844 100644 --- a/Questionable/Controller/Steps/Gathering/MoveToLandingLocation.cs +++ b/Questionable/Controller/Steps/Gathering/MoveToLandingLocation.cs @@ -16,6 +16,7 @@ namespace Questionable.Controller.Steps.Gathering; internal sealed class MoveToLandingLocation( IServiceProvider serviceProvider, + GameFunctions gameFunctions, IObjectTable objectTable, NavmeshIpc navmeshIpc, ILogger logger) : ITask @@ -36,8 +37,11 @@ internal sealed class MoveToLandingLocation( var location = _gatheringNode.Locations.First(); if (_gatheringNode.Locations.Count > 1) { - var gameObject = objectTable.Single(x => + var gameObject = objectTable.SingleOrDefault(x => x.ObjectKind == ObjectKind.GatheringPoint && x.DataId == _gatheringNode.DataId && x.IsTargetable); + if (gameObject == null) + return false; + location = _gatheringNode.Locations.Single(x => Vector3.Distance(x.Position, gameObject.Position) < 0.1f); } @@ -45,15 +49,26 @@ internal sealed class MoveToLandingLocation( logger.LogInformation("Preliminary landing location: {Location}, with degrees = {Degrees}, range = {Range}", target.ToString("G", CultureInfo.InvariantCulture), degrees, range); - Vector3? pointOnFloor = navmeshIpc.GetPointOnFloor(target with { Y = target.Y + 5f }); + bool fly = gameFunctions.IsFlyingUnlocked(_territoryId); + Vector3? pointOnFloor = navmeshIpc.GetPointOnFloor(target with { Y = target.Y + 5f }, false); if (pointOnFloor != null) - pointOnFloor = pointOnFloor.Value with { Y = pointOnFloor.Value.Y + 0.5f }; + pointOnFloor = pointOnFloor.Value with { Y = pointOnFloor.Value.Y + (fly ? 0.5f : 0f) }; + + // since we only allow points that can be landed on, the distance is important but the angle shouldn't matter + if (pointOnFloor != null && Vector3.Distance(pointOnFloor.Value, location.Position) > + location.CalculateMaximumDistance()) + { + pointOnFloor = location.Position + Vector3.Normalize(pointOnFloor.Value - location.Position) * location.CalculateMaximumDistance(); + logger.LogInformation("Adjusted landing location: {Location}", pointOnFloor.Value.ToString("G", CultureInfo.InvariantCulture)); } + else + { + logger.LogInformation("Final landing location: {Location}", + (pointOnFloor ?? target).ToString("G", CultureInfo.InvariantCulture)); + } - logger.LogInformation("Final landing location: {Location}", - (pointOnFloor ?? target).ToString("G", CultureInfo.InvariantCulture)); _moveTask = serviceProvider.GetRequiredService() - .With(_territoryId, pointOnFloor ?? target, 0.25f, dataId: _gatheringNode.DataId, fly: true, + .With(_territoryId, pointOnFloor ?? target, 0.25f, dataId: _gatheringNode.DataId, fly: fly, ignoreDistanceToObject: true); return _moveTask.Start(); } diff --git a/Questionable/Controller/Steps/Gathering/WaitGather.cs b/Questionable/Controller/Steps/Gathering/WaitGather.cs deleted file mode 100644 index e2b3a889..00000000 --- a/Questionable/Controller/Steps/Gathering/WaitGather.cs +++ /dev/null @@ -1,25 +0,0 @@ -using Dalamud.Game.ClientState.Conditions; -using Dalamud.Plugin.Services; - -namespace Questionable.Controller.Steps.Gathering; - -internal sealed class WaitGather(ICondition condition) : ITask -{ - private bool _wasGathering; - - public bool Start() => true; - - public ETaskResult Update() - { - if (condition[ConditionFlag.Gathering]) - { - _wasGathering = true; - } - - return _wasGathering && !condition[ConditionFlag.Gathering] - ? ETaskResult.TaskComplete - : ETaskResult.StillRunning; - } - - public override string ToString() => "WaitGather"; -} diff --git a/Questionable/Controller/Steps/Shared/GatheringRequiredItems.cs b/Questionable/Controller/Steps/Shared/GatheringRequiredItems.cs index ea602723..5d8022e6 100644 --- a/Questionable/Controller/Steps/Shared/GatheringRequiredItems.cs +++ b/Questionable/Controller/Steps/Shared/GatheringRequiredItems.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using Dalamud.Game.Text; using Dalamud.Plugin.Services; using Microsoft.Extensions.DependencyInjection; using Questionable.Data; @@ -70,6 +71,12 @@ internal static class GatheringRequiredItems return ETaskResult.StillRunning; } - public override string ToString() => $"Gather({_gatheredItem.ItemCount}x {_gatheredItem.ItemId})"; + public override string ToString() + { + if (_gatheredItem.Collectability == 0) + return $"Gather({_gatheredItem.ItemCount}x {_gatheredItem.ItemId})"; + else + return $"Gather({_gatheredItem.ItemCount}x {_gatheredItem.ItemId} {SeIconChar.Collectible.ToIconString()} {_gatheredItem.Collectability})"; + } } } diff --git a/Questionable/External/NavmeshIpc.cs b/Questionable/External/NavmeshIpc.cs index 2f6c5e36..0c8ce0a7 100644 --- a/Questionable/External/NavmeshIpc.cs +++ b/Questionable/External/NavmeshIpc.cs @@ -108,11 +108,11 @@ internal sealed class NavmeshIpc } } - public Vector3? GetPointOnFloor(Vector3 position) + public Vector3? GetPointOnFloor(Vector3 position, bool unlandable) { try { - return _queryPointOnFloor.InvokeFunc(position, true, 1); + return _queryPointOnFloor.InvokeFunc(position, unlandable, 0.2f); } catch (IpcError) { diff --git a/Questionable/GameFunctions.cs b/Questionable/GameFunctions.cs index 1cd229d1..00ff3c8a 100644 --- a/Questionable/GameFunctions.cs +++ b/Questionable/GameFunctions.cs @@ -743,7 +743,7 @@ internal sealed unsafe class GameFunctions _condition[ConditionFlag.OccupiedInQuestEvent] || _condition[ConditionFlag.OccupiedInCutSceneEvent] || _condition[ConditionFlag.Casting] || _condition[ConditionFlag.Unknown57] || _condition[ConditionFlag.BetweenAreas] || _condition[ConditionFlag.BetweenAreas51] || - _condition[ConditionFlag.Jumping61]; + _condition[ConditionFlag.Jumping61] || _condition[ConditionFlag.Gathering42]; } public bool IsLoadingScreenVisible() diff --git a/Questionable/QuestionablePlugin.cs b/Questionable/QuestionablePlugin.cs index 0febd3bd..944e6beb 100644 --- a/Questionable/QuestionablePlugin.cs +++ b/Questionable/QuestionablePlugin.cs @@ -105,7 +105,8 @@ public sealed class QuestionablePlugin : IDalamudPlugin serviceCollection.AddTransient(); serviceCollection.AddTransient(); serviceCollection.AddTransient(); - serviceCollection.AddTransient(); + serviceCollection.AddTransient(); + serviceCollection.AddTransient(); // task factories serviceCollection.AddTaskWithFactory();