Moonfire Faire + add logic for skipping steps depending on (un)locked aetherytes
authorLiza Carvelli <liza@carvel.li>
Thu, 8 Aug 2024 22:53:05 +0000 (00:53 +0200)
committerLiza Carvelli <liza@carvel.li>
Thu, 8 Aug 2024 22:53:05 +0000 (00:53 +0200)
13 files changed:
QuestPaths/7.x - Dawntrail/Seasonal Events/Moonfire Faire (2024)/5182_Fire Red, Beast Green.json [new file with mode: 0644]
QuestPaths/7.x - Dawntrail/Seasonal Events/Moonfire Faire (2024)/5183_Festival Fan Frenzy.json [new file with mode: 0644]
QuestPaths/quest-v1.json
Questionable.Model/Questing/Converter/EmoteConverter.cs
Questionable.Model/Questing/EEmote.cs
Questionable.Model/Questing/SkipAetheryteCondition.cs
Questionable.Model/Questing/SkipStepConditions.cs
Questionable/Controller/GameUiController.cs
Questionable/Controller/Steps/Shared/AethernetShortcut.cs
Questionable/Controller/Steps/Shared/AetheryteShortcut.cs
Questionable/Controller/Steps/Shared/SkipCondition.cs
Questionable/Data/QuestData.cs
Questionable/Model/QuestInfo.cs

diff --git a/QuestPaths/7.x - Dawntrail/Seasonal Events/Moonfire Faire (2024)/5182_Fire Red, Beast Green.json b/QuestPaths/7.x - Dawntrail/Seasonal Events/Moonfire Faire (2024)/5182_Fire Red, Beast Green.json
new file mode 100644 (file)
index 0000000..4b146ee
--- /dev/null
@@ -0,0 +1,171 @@
+{
+  "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/QuestPaths/quest-v1.json",
+  "Author": "JerryWester",
+  "QuestSequence": [
+    {
+      "Sequence": 0,
+      "Steps": [
+        {
+          "DataId": 1050816,
+          "Position": {
+            "X": 14.328186,
+            "Y": 45.665993,
+            "Z": 131.33435
+          },
+          "TerritoryId": 128,
+          "InteractionType": "AcceptQuest",
+          "AetheryteShortcut": "Limsa Lominsa",
+          "AethernetShortcut": [
+            "[Limsa Lominsa] Aetheryte Plaza",
+            "[Limsa Lominsa] The Aftcastle"
+          ],
+          "SkipConditions": {
+            "AetheryteShortcutIf": {
+              "InSameTerritory": true,
+              "InTerritory": [
+                129
+              ]
+            }
+          }
+        }
+      ]
+    },
+    {
+      "Sequence": 1,
+      "Steps": [
+        {
+          "DataId": 1000868,
+          "Position": {
+            "X": -192.00433,
+            "Y": 0.9999907,
+            "Z": 211.68835
+          },
+          "TerritoryId": 129,
+          "InteractionType": "Interact",
+          "AethernetShortcut": [
+            "[Limsa Lominsa] The Aftcastle",
+            "[Limsa Lominsa] Fishermens' Guild"
+          ],
+          "SkipConditions": {
+            "StepIf": {
+              "AetheryteUnlocked": "Eastern La Noscea - Costa Del Sol",
+              "InTerritory": [137]
+            },
+            "AethernetShortcutIf": {
+              "AetheryteUnlocked": "Eastern La Noscea - Costa Del Sol"
+            }
+          },
+          "TargetTerritoryId": 137
+        },
+        {
+          "TerritoryId": 137,
+          "InteractionType": "AttuneAetheryte",
+          "Aetheryte": "Eastern La Noscea - Costa Del Sol",
+          "SkipConditions": {
+            "StepIf": {
+              "AetheryteUnlocked": "Eastern La Noscea - Costa Del Sol"
+            }
+          }
+        },
+        {
+          "Position": {
+            "X": 732.0986,
+            "Y": 11.349089,
+            "Z": 262.19138
+          },
+          "TerritoryId": 137,
+          "InteractionType": "WalkTo"
+        },
+        {
+          "DataId": 1050817,
+          "Position": {
+            "X": 735.25586,
+            "Y": 11.306824,
+            "Z": 261.8601
+          },
+          "StopDistance": 5,
+          "TerritoryId": 137,
+          "InteractionType": "Interact",
+          "AetheryteShortcut": "Eastern La Noscea - Costa Del Sol",
+          "Fly": true
+        }
+      ]
+    },
+    {
+      "Sequence": 2,
+      "Steps": [
+        {
+          "DataId": 1050818,
+          "Position": {
+            "X": 681.3915,
+            "Y": 9.601691,
+            "Z": 202.86865
+          },
+          "StopDistance": 5,
+          "TerritoryId": 137,
+          "InteractionType": "Interact"
+        }
+      ]
+    },
+    {
+      "Sequence": 3,
+      "Steps": [
+        {
+          "DataId": 1050819,
+          "Position": {
+            "X": 770.13806,
+            "Y": 9.687993,
+            "Z": 246.29578
+          },
+          "TerritoryId": 137,
+          "InteractionType": "Interact"
+        }
+      ]
+    },
+    {
+      "Sequence": 4,
+      "Steps": [
+        {
+          "DataId": 2014098,
+          "Position": {
+            "X": 769.0698,
+            "Y": 9.719971,
+            "Z": 246.99768
+          },
+          "TerritoryId": 137,
+          "InteractionType": "Interact",
+          "DialogueChoices": [
+            {
+              "Type": "List",
+              "Prompt": "TEXT_FESSUX001_05182_Q1_000_000",
+              "Answer": "TEXT_FESSUX001_05182_A1_000_001"
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "Sequence": 255,
+      "Steps": [
+        {
+          "DataId": 1050820,
+          "Position": {
+            "X": 695.46045,
+            "Y": 9.614362,
+            "Z": 295.70447
+          },
+          "TerritoryId": 137,
+          "InteractionType": "CompleteQuest",
+          "DialogueChoices": [
+            {
+              "Type": "List",
+              "Prompt": "TEXT_FESSUX001_05182_Q2_000_000",
+              "Answer": "TEXT_FESSUX001_05182_A2_000_001"
+            }
+          ],
+          "NextQuestId": 5183
+        }
+      ]
+    }
+  ]
+}
diff --git a/QuestPaths/7.x - Dawntrail/Seasonal Events/Moonfire Faire (2024)/5183_Festival Fan Frenzy.json b/QuestPaths/7.x - Dawntrail/Seasonal Events/Moonfire Faire (2024)/5183_Festival Fan Frenzy.json
new file mode 100644 (file)
index 0000000..4a95c4c
--- /dev/null
@@ -0,0 +1,115 @@
+{
+  "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/QuestPaths/quest-v1.json",
+  "Author": "JerryWester",
+  "QuestSequence": [
+    {
+      "Sequence": 0,
+      "Steps": [
+        {
+          "DataId": 1050828,
+          "Position": {
+            "X": 694.5753,
+            "Y": 9.578133,
+            "Z": 297.59656
+          },
+          "StopDistance": 5,
+          "TerritoryId": 137,
+          "InteractionType": "AcceptQuest"
+        }
+      ]
+    },
+    {
+      "Sequence": 1,
+      "Steps": [
+        {
+          "DataId": 1050824,
+          "Position": {
+            "X": 507.68274,
+            "Y": 9.541115,
+            "Z": 428.54944
+          },
+          "TerritoryId": 137,
+          "InteractionType": "Emote",
+          "Emote": "uchiwasshoi",
+          "Fly": true,
+          "CompletionQuestVariablesFlags": [
+            null,
+            null,
+            null,
+            null,
+            null,
+            128
+          ]
+        },
+        {
+          "DataId": 1050825,
+          "Position": {
+            "X": 641.44336,
+            "Y": 11.697773,
+            "Z": 526.604
+          },
+          "TerritoryId": 137,
+          "InteractionType": "Emote",
+          "Emote": "uchiwasshoi",
+          "Fly": true,
+          "CompletionQuestVariablesFlags": [
+            null,
+            null,
+            null,
+            null,
+            null,
+            64
+          ]
+        }
+      ]
+    },
+    {
+      "Sequence": 2,
+      "Steps": [
+        {
+          "DataId": 1050829,
+          "Position": {
+            "X": 694.2092,
+            "Y": 9.619679,
+            "Z": 294.81946
+          },
+          "TerritoryId": 137,
+          "InteractionType": "Interact",
+          "Fly": true
+        }
+      ]
+    },
+    {
+      "Sequence": 255,
+      "Steps": [
+        {
+          "Position": {
+            "X": 732.0986,
+            "Y": 11.349089,
+            "Z": 262.19138
+          },
+          "TerritoryId": 137,
+          "InteractionType": "WalkTo"
+        },
+        {
+          "DataId": 1050817,
+          "Position": {
+            "X": 735.25586,
+            "Y": 11.306824,
+            "Z": 261.8601
+          },
+          "TerritoryId": 137,
+          "InteractionType": "CompleteQuest",
+          "StopDistance": 5,
+          "DialogueChoices": [
+            {
+              "Type": "List",
+              "Prompt": "TEXT_FESSUX002_05183_Q1_000_000",
+              "Answer": "TEXT_FESSUX002_05183_A1_000_002"
+            }
+          ]
+        }
+      ]
+    }
+  ]
+}
index 313239f43f40907cfe19c681878ac2842daeff9e..25d083b6c20faa84bf72add11063a6fd9a65e54b 100644 (file)
                             "type": "number"
                           }
                         },
+                        "AetheryteLocked": {
+                          "$ref": "https://git.carvel.li/liza/Questionable/raw/branch/master/Questionable.Model/common-schema.json#/$defs/Aetheryte"
+                        },
+                        "AetheryteUnlocked": {
+                          "$ref": "https://git.carvel.li/liza/Questionable/raw/branch/master/Questionable.Model/common-schema.json#/$defs/Aetheryte"
+                        },
                         "ExtraCondition": {
                           "type": "string",
                           "enum": [
                           "items": {
                             "type": "integer"
                           }
+                        },
+                        "AetheryteLocked": {
+                          "$ref": "https://git.carvel.li/liza/Questionable/raw/branch/master/Questionable.Model/common-schema.json#/$defs/Aetheryte"
+                        },
+                        "AetheryteUnlocked": {
+                          "$ref": "https://git.carvel.li/liza/Questionable/raw/branch/master/Questionable.Model/common-schema.json#/$defs/Aetheryte"
                         }
                       },
                       "additionalProperties": false
                         },
                         "InSameTerritory": {
                           "type": "boolean"
+                        },
+                        "AetheryteLocked": {
+                          "$ref": "https://git.carvel.li/liza/Questionable/raw/branch/master/Questionable.Model/common-schema.json#/$defs/Aetheryte"
+                        },
+                        "AetheryteUnlocked": {
+                          "$ref": "https://git.carvel.li/liza/Questionable/raw/branch/master/Questionable.Model/common-schema.json#/$defs/Aetheryte"
                         }
                       },
                       "additionalProperties": false
                           "respect",
                           "lookout",
                           "kneel",
-                          "bow"
+                          "bow",
+                          "uchiwasshoi"
                         ]
                       }
                     }
index 20c97694c237b9b1f442c00d742798b663b6fc84..5de1c5c5b30e77698b6982b4907d544f3c190160 100644 (file)
@@ -29,5 +29,6 @@ public sealed class EmoteConverter() : EnumConverter<EEmote>(Values)
         { EEmote.Lookout, "lookout" },
         { EEmote.Kneel, "kneel" },
         { EEmote.Bow, "bow" },
+        { EEmote.Uchiwasshoi, "uchiwasshoi" },
     };
 }
index 022930e903ff3fa61e4792641b106b6daba3030e..c03be6110ddea911f7547b54a97dee03f5810b5f 100644 (file)
@@ -30,4 +30,5 @@ public enum EEmote
     Lookout = 22,
     Kneel = 19,
     Bow = 5,
+    Uchiwasshoi = 278,
 }
index 870abe667572d13bc73185d6ce9055d5ff4f0acd..ad636e323742fcea152290cf0859a699b2223191 100644 (file)
@@ -1,4 +1,5 @@
 using System.Collections.Generic;
+using Questionable.Model.Common;
 
 namespace Questionable.Model.Questing;
 
@@ -7,4 +8,6 @@ public sealed class SkipAetheryteCondition
     public bool Never { get; set; }
     public bool InSameTerritory { get; set; }
     public List<ushort> InTerritory { get; set; } = new();
+    public EAetheryteLocation? AetheryteLocked { get; set; }
+    public EAetheryteLocation? AetheryteUnlocked { get; set; }
 }
index c336abe66a4c0430b6c792d4a020ac68674a8b42..dd0a3f3ed2266badac68c77d215587613466df6a 100644 (file)
@@ -1,5 +1,6 @@
 using System.Collections.Generic;
 using System.Linq;
+using Questionable.Model.Common;
 
 namespace Questionable.Model.Questing;
 
@@ -15,6 +16,8 @@ public sealed class SkipStepConditions
     public SkipItemConditions? Item { get; set; }
     public List<ElementId> QuestsAccepted { get; set; } = new();
     public List<ElementId> QuestsCompleted { get; set; } = new();
+    public EAetheryteLocation? AetheryteLocked { get; set; }
+    public EAetheryteLocation? AetheryteUnlocked { get; set; }
     public EExtraSkipCondition? ExtraCondition { get; set; }
 
     public bool HasSkipConditions()
@@ -30,6 +33,8 @@ public sealed class SkipStepConditions
                Item != null ||
                QuestsAccepted.Count > 0 ||
                QuestsCompleted.Count > 0 ||
+               AetheryteLocked != null ||
+               AetheryteUnlocked != null ||
                ExtraCondition != null;
     }
 
index 829953c1e0d0d3a41cb4919035d428cbcb4fa6aa..e57aef5fe53ec44eec093b4c5892e9a4e44f09ee 100644 (file)
@@ -786,9 +786,23 @@ internal sealed class GameUiController : IDisposable
             string questName = addon->AtkTextNode250->NodeText.ToString();
             if (_questController.CurrentQuest is { Quest.Id: LeveId } &&
                 GameFunctions.GameStringEquals(_questController.CurrentQuest.Quest.Info.Name, questName))
+            {
+                _logger.LogInformation("JournalResult has the current leve, auto-accepting it");
                 addon->FireCallbackInt(0);
-            else
-                addon->FireCallbackInt(1);
+            }
+            else if (_targetManager.Target is { } target)
+            {
+                var issuedLeves = _questData.GetAllByIssuerDataId(target.DataId)
+                    .Where(x => x.QuestId is LeveId)
+                    .ToList();
+
+                if (issuedLeves.Any(x => GameFunctions.GameStringEquals(x.Name, questName)))
+                {
+                    _logger.LogInformation(
+                        "JournalResult has a leve but not the one we're currently on, auto-declining it");
+                    addon->FireCallbackInt(1);
+                }
+            }
         }
     }
 
index 82643de17f303a96e7e27e30bcbd08db2c7a8162..236f270c442e6e30e56680fc38c65c4801b2bdaf 100644 (file)
@@ -63,6 +63,27 @@ internal static class AethernetShortcut
                     logger.LogInformation("Skipping aethernet shortcut because the target is in the same territory");
                     return false;
                 }
+
+                if (SkipConditions.InTerritory.Contains(clientState.TerritoryType))
+                {
+                    logger.LogInformation(
+                        "Skipping aethernet shortcut because the target is in the specified territory");
+                    return false;
+                }
+
+                if (SkipConditions.AetheryteLocked != null &&
+                    !gameFunctions.IsAetheryteUnlocked(SkipConditions.AetheryteLocked.Value))
+                {
+                    logger.LogInformation("Skipping aethernet shortcut because the target aetheryte is locked");
+                    return false;
+                }
+
+                if (SkipConditions.AetheryteUnlocked != null &&
+                    gameFunctions.IsAetheryteUnlocked(SkipConditions.AetheryteUnlocked.Value))
+                {
+                    logger.LogInformation("Skipping aethernet shortcut because the target aetheryte is unlocked");
+                    return false;
+                }
             }
 
             if (gameFunctions.IsAetheryteUnlocked(From) &&
index b73f9585b94bd19050ec138146ed1959296f9df1..cf6ecec0cf0e7d6046f13947b440eba2df65124a 100644 (file)
@@ -71,13 +71,27 @@ internal static class AetheryteShortcut
             if (Step != null)
             {
                 var skipConditions = Step.SkipConditions?.AetheryteShortcutIf ?? new();
-                if (skipConditions is { Never: false, InTerritory.Count: > 0 })
+                if (skipConditions is { Never: false })
                 {
                     if (skipConditions.InTerritory.Contains(territoryType))
                     {
                         logger.LogInformation("Skipping aetheryte teleport due to SkipCondition (InTerritory)");
                         return false;
                     }
+
+                    if (skipConditions.AetheryteLocked != null &&
+                        !gameFunctions.IsAetheryteUnlocked(skipConditions.AetheryteLocked.Value))
+                    {
+                        logger.LogInformation("Skipping aetheryte teleport due to SkipCondition (AetheryteLocked)");
+                        return false;
+                    }
+
+                    if (skipConditions.AetheryteUnlocked != null &&
+                        gameFunctions.IsAetheryteUnlocked(skipConditions.AetheryteUnlocked.Value))
+                    {
+                        logger.LogInformation("Skipping aetheryte teleport due to SkipCondition (AetheryteUnlocked)");
+                        return false;
+                    }
                 }
 
                 if (ExpectedTerritoryId == territoryType)
index 3bab5526d6eba736ac991d841a90fb7a08512227..d5e8e5d12a3c3818f9d937fdc32e42cd33d279f2 100644 (file)
@@ -151,6 +151,20 @@ internal static class SkipCondition
                 return true;
             }
 
+            if (SkipConditions.AetheryteLocked != null &&
+                !gameFunctions.IsAetheryteUnlocked(SkipConditions.AetheryteLocked.Value))
+            {
+                logger.LogInformation("Skipping step, as aetheryte is locked");
+                return true;
+            }
+
+            if (SkipConditions.AetheryteUnlocked != null &&
+                gameFunctions.IsAetheryteUnlocked(SkipConditions.AetheryteUnlocked.Value))
+            {
+                logger.LogInformation("Skipping step, as aetheryte is unlocked");
+                return true;
+            }
+
             if (Step is { DataId: not null, InteractionType: EInteractionType.AttuneAetherCurrent } &&
                 gameFunctions.IsAetherCurrentUnlocked(Step.DataId.Value))
             {
index 7ea55ca978eb38bffcb294a86f6ff5121f9f96cd..8f42db9aabe5c849fb2d4c1560d282ef7f0fc963 100644 (file)
@@ -20,7 +20,6 @@ internal sealed class QuestData
             ..dataManager.GetExcelSheet<Quest>()!
                 .Where(x => x.RowId > 0)
                 .Where(x => x.IssuerLocation.Row > 0)
-                .Where(x => x.Festival.Row == 0)
                 .Select(x => new QuestInfo(x)),
             ..dataManager.GetExcelSheet<SatisfactionNpc>()!
                 .Where(x => x.RowId > 0)
@@ -50,7 +49,7 @@ internal sealed class QuestData
     public List<QuestInfo> GetAllByJournalGenre(uint journalGenre)
     {
         return _quests.Values
-            .Where(x => x is QuestInfo)
+            .Where(x => x is QuestInfo { IsSeasonalEvent: false })
             .Cast<QuestInfo>()
             .Where(x => x.JournalGenre == journalGenre)
             .OrderBy(x => x.SortKey)
index 6737aab0d6468cc2bcfadcf3452da8934399c601..769ad7cbc8fced7d675a13bb966fdfb6cd9330f7 100644 (file)
@@ -53,6 +53,7 @@ internal sealed class QuestInfo : IQuestInfo
         GrandCompany = (GrandCompany)quest.GrandCompany.Row;
         BeastTribe = (EBeastTribe)quest.BeastTribe.Row;
         ClassJobs = QuestInfoUtils.AsList(quest.ClassJobCategory0.Value!);
+        IsSeasonalEvent = quest.Festival.Row != 0;
     }
 
 
@@ -74,6 +75,7 @@ internal sealed class QuestInfo : IQuestInfo
     public GrandCompany GrandCompany { get; }
     public EBeastTribe BeastTribe { get; }
     public IReadOnlyList<EClassJob> ClassJobs { get; }
+    public bool IsSeasonalEvent { get; }
 
     [UsedImplicitly(ImplicitUseKindFlags.Assign, ImplicitUseTargetFlags.Members)]
     public enum QuestJoin : byte