master #3

Open
cacahuetes wants to merge 653 commits from liza/Questionable:master into cacahuetes-ShB-Healer
48 changed files with 436 additions and 62 deletions
Showing only changes of commit 8baf287604 - Show all commits

View File

@ -8,7 +8,14 @@
{ {
"TerritoryId": 153, "TerritoryId": 153,
"InteractionType": "EquipItem", "InteractionType": "EquipItem",
"ItemId": 4546 "ItemId": 4546,
"AetheryteShortcut": "South Shroud - Quarrymill",
"Fly": true,
"SkipConditions": {
"AetheryteShortcutIf": {
"InSameTerritory": true
}
}
}, },
{ {
"TerritoryId": 153, "TerritoryId": 153,
@ -22,14 +29,7 @@
"Z": -7.3396606 "Z": -7.3396606
}, },
"TerritoryId": 153, "TerritoryId": 153,
"InteractionType": "AcceptQuest", "InteractionType": "AcceptQuest"
"AetheryteShortcut": "South Shroud - Quarrymill",
"Fly": true,
"SkipConditions": {
"AetheryteShortcutIf": {
"InSameTerritory": true
}
}
} }
] ]
}, },

View File

@ -13,7 +13,20 @@
"Z": -142.93127 "Z": -142.93127
}, },
"TerritoryId": 133, "TerritoryId": 133,
"InteractionType": "AcceptQuest" "InteractionType": "AcceptQuest",
"AetheryteShortcut": "Gridania",
"AethernetShortcut": [
"[Gridania] Aetheryte Plaza",
"[Gridania] Botanists' Guild"
],
"SkipConditions": {
"AetheryteShortcutIf": {
"InSameTerritory": true,
"InTerritory": [
133
]
}
}
} }
] ]
}, },

View File

@ -14,6 +14,19 @@
}, },
"TerritoryId": 131, "TerritoryId": 131,
"InteractionType": "AcceptQuest", "InteractionType": "AcceptQuest",
"AetheryteShortcut": "Ul'dah",
"AethernetShortcut": [
"[Ul'dah] Aetheryte Plaza",
"[Ul'dah] Miners' Guild"
],
"SkipConditions": {
"AetheryteShortcutIf": {
"InSameTerritory": true,
"InTerritory": [
131
]
}
},
"DialogueChoices": [ "DialogueChoices": [
{ {
"Type": "YesNo", "Type": "YesNo",

View File

@ -13,7 +13,20 @@
"Z": 153.2157 "Z": 153.2157
}, },
"TerritoryId": 131, "TerritoryId": 131,
"InteractionType": "AcceptQuest" "InteractionType": "AcceptQuest",
"AetheryteShortcut": "Ul'dah",
"AethernetShortcut": [
"[Ul'dah] Aetheryte Plaza",
"[Ul'dah] Miners' Guild"
],
"SkipConditions": {
"AetheryteShortcutIf": {
"InSameTerritory": true,
"InTerritory": [
131
]
}
}
} }
] ]
}, },

View File

@ -13,7 +13,20 @@
"Z": 157.42725 "Z": 157.42725
}, },
"TerritoryId": 131, "TerritoryId": 131,
"InteractionType": "AcceptQuest" "InteractionType": "AcceptQuest",
"AetheryteShortcut": "Ul'dah",
"AethernetShortcut": [
"[Ul'dah] Aetheryte Plaza",
"[Ul'dah] Miners' Guild"
],
"SkipConditions": {
"AetheryteShortcutIf": {
"InSameTerritory": true,
"InTerritory": [
131
]
}
}
} }
] ]
}, },

View File

@ -13,7 +13,20 @@
"Z": 157.42725 "Z": 157.42725
}, },
"TerritoryId": 131, "TerritoryId": 131,
"InteractionType": "AcceptQuest" "InteractionType": "AcceptQuest",
"AetheryteShortcut": "Ul'dah",
"AethernetShortcut": [
"[Ul'dah] Aetheryte Plaza",
"[Ul'dah] Miners' Guild"
],
"SkipConditions": {
"AetheryteShortcutIf": {
"InSameTerritory": true,
"InTerritory": [
131
]
}
}
} }
] ]
}, },

View File

@ -13,7 +13,13 @@
"Z": -51.163513 "Z": -51.163513
}, },
"TerritoryId": 130, "TerritoryId": 130,
"InteractionType": "AcceptQuest" "InteractionType": "AcceptQuest",
"AetheryteShortcut": "Ul'dah",
"SkipConditions": {
"AetheryteShortcutIf": {
"InSameTerritory": true
}
}
} }
] ]
}, },

View File

@ -14,7 +14,13 @@
"Z": -51.163513 "Z": -51.163513
}, },
"TerritoryId": 130, "TerritoryId": 130,
"InteractionType": "AcceptQuest" "InteractionType": "AcceptQuest",
"AetheryteShortcut": "Ul'dah",
"SkipConditions": {
"AetheryteShortcutIf": {
"InSameTerritory": true
}
}
} }
] ]
} }

View File

@ -14,6 +14,7 @@
}, },
"TerritoryId": 131, "TerritoryId": 131,
"InteractionType": "AcceptQuest", "InteractionType": "AcceptQuest",
"AetheryteShortcut": "Ul'dah",
"AethernetShortcut": [ "AethernetShortcut": [
"[Ul'dah] Aetheryte Plaza", "[Ul'dah] Aetheryte Plaza",
"[Ul'dah] Gladiators' Guild" "[Ul'dah] Gladiators' Guild"

View File

@ -13,7 +13,20 @@
"Z": 39.81079 "Z": 39.81079
}, },
"TerritoryId": 131, "TerritoryId": 131,
"InteractionType": "AcceptQuest" "InteractionType": "AcceptQuest",
"AetheryteShortcut": "Ul'dah",
"AethernetShortcut": [
"[Ul'dah] Aetheryte Plaza",
"[Ul'dah] Gladiators' Guild"
],
"SkipConditions": {
"AetheryteShortcutIf": {
"InSameTerritory": true,
"InTerritory": [
131
]
}
}
} }
] ]
}, },

View File

@ -12,7 +12,13 @@
"Z": 4.017052 "Z": 4.017052
}, },
"TerritoryId": 129, "TerritoryId": 129,
"InteractionType": "WalkTo" "InteractionType": "WalkTo",
"AetheryteShortcut": "Limsa Lominsa",
"SkipConditions": {
"AetheryteShortcutIf": {
"InSameTerritory": true
}
}
}, },
{ {
"DataId": 1000895, "DataId": 1000895,

View File

@ -8,7 +8,20 @@
{ {
"TerritoryId": 128, "TerritoryId": 128,
"InteractionType": "EquipItem", "InteractionType": "EquipItem",
"ItemId": 4550 "ItemId": 4550,
"AetheryteShortcut": "Limsa Lominsa",
"AethernetShortcut": [
"[Limsa Lominsa] Aetheryte Plaza",
"[Limsa Lominsa] Marauders' Guild"
],
"SkipConditions": {
"AetheryteShortcutIf": {
"InSameTerritory": true,
"InTerritory": [
128
]
}
}
}, },
{ {
"DataId": 1006757, "DataId": 1006757,

View File

@ -13,7 +13,20 @@
"Z": -250.56848 "Z": -250.56848
}, },
"TerritoryId": 128, "TerritoryId": 128,
"InteractionType": "AcceptQuest" "InteractionType": "AcceptQuest",
"AetheryteShortcut": "Limsa Lominsa",
"AethernetShortcut": [
"[Limsa Lominsa] Aetheryte Plaza",
"[Limsa Lominsa] Marauders' Guild"
],
"SkipConditions": {
"AetheryteShortcutIf": {
"InSameTerritory": true,
"InTerritory": [
128
]
}
}
} }
] ]
}, },

View File

@ -13,7 +13,20 @@
"Z": -250.56848 "Z": -250.56848
}, },
"TerritoryId": 128, "TerritoryId": 128,
"InteractionType": "AcceptQuest" "InteractionType": "AcceptQuest",
"AetheryteShortcut": "Limsa Lominsa",
"AethernetShortcut": [
"[Limsa Lominsa] Aetheryte Plaza",
"[Limsa Lominsa] Marauders' Guild"
],
"SkipConditions": {
"AetheryteShortcutIf": {
"InSameTerritory": true,
"InTerritory": [
128
]
}
}
} }
] ]
}, },

View File

@ -13,7 +13,20 @@
"Z": -250.56848 "Z": -250.56848
}, },
"TerritoryId": 128, "TerritoryId": 128,
"InteractionType": "AcceptQuest" "InteractionType": "AcceptQuest",
"AetheryteShortcut": "Limsa Lominsa",
"AethernetShortcut": [
"[Limsa Lominsa] Aetheryte Plaza",
"[Limsa Lominsa] Marauders' Guild"
],
"SkipConditions": {
"AetheryteShortcutIf": {
"InSameTerritory": true,
"InTerritory": [
128
]
}
}
} }
] ]
}, },

View File

@ -13,7 +13,20 @@
"Z": -250.56848 "Z": -250.56848
}, },
"TerritoryId": 128, "TerritoryId": 128,
"InteractionType": "AcceptQuest" "InteractionType": "AcceptQuest",
"AetheryteShortcut": "Limsa Lominsa",
"AethernetShortcut": [
"[Limsa Lominsa] Aetheryte Plaza",
"[Limsa Lominsa] Marauders' Guild"
],
"SkipConditions": {
"AetheryteShortcutIf": {
"InSameTerritory": true,
"InTerritory": [
128
]
}
}
} }
] ]
}, },

View File

@ -35,7 +35,8 @@
"Y": 8.712891, "Y": 8.712891,
"Z": 281.69678 "Z": 281.69678
}, },
"MaximumDistance": 3 "MaximumDistance": 3,
"TerritoryId": 153
} }
} }
} }
@ -157,7 +158,8 @@
"Y": 8.712891, "Y": 8.712891,
"Z": 281.69678 "Z": 281.69678
}, },
"MaximumDistance": 3 "MaximumDistance": 3,
"TerritoryId": 153
} }
} }
} }

View File

@ -13,7 +13,13 @@
"Z": 195.94104 "Z": 195.94104
}, },
"TerritoryId": 129, "TerritoryId": 129,
"InteractionType": "AcceptQuest" "InteractionType": "AcceptQuest",
"AetheryteShortcut": "Limsa Lominsa",
"SkipConditions": {
"AetheryteShortcutIf": {
"InSameTerritory": true
}
}
} }
] ]
}, },

View File

@ -13,7 +13,17 @@
"Z": 201.9226 "Z": 201.9226
}, },
"TerritoryId": 819, "TerritoryId": 819,
"InteractionType": "AcceptQuest" "InteractionType": "AcceptQuest",
"AetheryteShortcut": "Crystarium",
"AethernetShortcut": [
"[Crystarium] Aetheryte Plaza",
"[Crystarium] Musica Universalis Markets"
],
"SkipConditions": {
"AetheryteShortcutIf": {
"InSameTerritory": true
}
}
} }
] ]
}, },

View File

@ -14,7 +14,17 @@
"Z": 251.75854 "Z": 251.75854
}, },
"TerritoryId": 819, "TerritoryId": 819,
"InteractionType": "AcceptQuest" "InteractionType": "AcceptQuest",
"AetheryteShortcut": "Crystarium",
"AethernetShortcut": [
"[Crystarium] Aetheryte Plaza",
"[Crystarium] Musica Universalis Markets"
],
"SkipConditions": {
"AetheryteShortcutIf": {
"InSameTerritory": true
}
}
} }
] ]
} }

View File

@ -20,7 +20,20 @@
"Prompt": "TEXT_KINGBB201_04854_Q1_000_000", "Prompt": "TEXT_KINGBB201_04854_Q1_000_000",
"Answer": "TEXT_KINGBB201_04854_A1_000_002" "Answer": "TEXT_KINGBB201_04854_A1_000_002"
} }
] ],
"AetheryteShortcut": "Gridania",
"AethernetShortcut": [
"[Gridania] Aetheryte Plaza",
"[Gridania] Conjurers' Guild"
],
"SkipConditions": {
"AetheryteShortcutIf": {
"InSameTerritory": true,
"InTerritory": [
133
]
}
}
} }
] ]
}, },

View File

@ -14,11 +14,15 @@
"TerritoryId": 132, "TerritoryId": 132,
"InteractionType": "UseItem", "InteractionType": "UseItem",
"ItemId": 43538, "ItemId": 43538,
"AetheryteShortcut": "Gridania",
"SkipConditions": { "SkipConditions": {
"StepIf": { "StepIf": {
"Item": { "Item": {
"NotInInventory": true "NotInInventory": true
} }
},
"AetheryteShortcutIf": {
"InSameTerritory": true
} }
} }
}, },

View File

@ -13,7 +13,13 @@
"Z": -99.321045 "Z": -99.321045
}, },
"TerritoryId": 130, "TerritoryId": 130,
"InteractionType": "AcceptQuest" "InteractionType": "AcceptQuest",
"AetheryteShortcut": "Ul'dah",
"SkipConditions": {
"AetheryteShortcutIf": {
"InSameTerritory": true
}
}
} }
] ]
}, },

View File

@ -17,16 +17,27 @@
"TerritoryId": 131, "TerritoryId": 131,
"InteractionType": "UseItem", "InteractionType": "UseItem",
"ItemId": 43537, "ItemId": 43537,
"AetheryteShortcut": "Ul'dah",
"AethernetShortcut": [
"[Ul'dah] Aetheryte Plaza",
"[Ul'dah] Weavers' Guild"
],
"SkipConditions": { "SkipConditions": {
"StepIf": { "StepIf": {
"Item": { "Item": {
"NotInInventory": true "NotInInventory": true
} }
},
"AetheryteShortcutIf": {
"InSameTerritory": true,
"InTerritory": [
131
]
} }
} }
}, },
{ {
"TerritoryId": 131, "TerritoryId": 131,
"InteractionType": "EquipItem", "InteractionType": "EquipItem",
"ItemId": 41808, "ItemId": 41808,
"SkipConditions": { "SkipConditions": {

View File

@ -13,7 +13,13 @@
"Z": 194.72034 "Z": 194.72034
}, },
"TerritoryId": 1185, "TerritoryId": 1185,
"InteractionType": "AcceptQuest" "InteractionType": "AcceptQuest",
"AetheryteShortcut": "Tuliyollal",
"SkipConditions": {
"AetheryteShortcutIf": {
"InSameTerritory": true
}
}
} }
] ]
}, },

View File

@ -13,7 +13,13 @@
"Z": 628.3817 "Z": 628.3817
}, },
"TerritoryId": 957, "TerritoryId": 957,
"InteractionType": "AcceptQuest" "InteractionType": "AcceptQuest",
"AetheryteShortcut": "Thavnair - Yedlihmad",
"SkipConditions": {
"AetheryteShortcutIf": {
"InSameTerritory": true
}
}
} }
] ]
}, },

View File

@ -13,7 +13,13 @@
"Z": 628.3817 "Z": 628.3817
}, },
"TerritoryId": 957, "TerritoryId": 957,
"InteractionType": "AcceptQuest" "InteractionType": "AcceptQuest",
"AetheryteShortcut": "Thavnair - Yedlihmad",
"SkipConditions": {
"AetheryteShortcutIf": {
"InSameTerritory": true
}
}
} }
] ]
}, },

View File

@ -14,6 +14,12 @@
}, },
"TerritoryId": 957, "TerritoryId": 957,
"InteractionType": "AcceptQuest", "InteractionType": "AcceptQuest",
"AetheryteShortcut": "Thavnair - Yedlihmad",
"SkipConditions": {
"AetheryteShortcutIf": {
"InSameTerritory": true
}
},
"DialogueChoices": [ "DialogueChoices": [
{ {
"Type": "List", "Type": "List",

View File

@ -13,7 +13,13 @@
"Z": 628.3817 "Z": 628.3817
}, },
"TerritoryId": 957, "TerritoryId": 957,
"InteractionType": "AcceptQuest" "InteractionType": "AcceptQuest",
"AetheryteShortcut": "Thavnair - Yedlihmad",
"SkipConditions": {
"AetheryteShortcutIf": {
"InSameTerritory": true
}
}
} }
] ]
}, },

View File

@ -16,7 +16,13 @@
"Z": 628.3817 "Z": 628.3817
}, },
"TerritoryId": 957, "TerritoryId": 957,
"InteractionType": "AcceptQuest" "InteractionType": "AcceptQuest",
"AetheryteShortcut": "Thavnair - Yedlihmad",
"SkipConditions": {
"AetheryteShortcutIf": {
"InSameTerritory": true
}
}
} }
] ]
}, },

View File

@ -13,7 +13,13 @@
"Z": -3.6469727 "Z": -3.6469727
}, },
"TerritoryId": 621, "TerritoryId": 621,
"InteractionType": "AcceptQuest" "InteractionType": "AcceptQuest",
"AetheryteShortcut": "Lochs - Porta Praetoria",
"SkipConditions": {
"AetheryteShortcutIf": {
"InSameTerritory": true
}
}
} }
] ]
}, },

View File

@ -13,7 +13,13 @@
"Z": 739.4979 "Z": 739.4979
}, },
"TerritoryId": 620, "TerritoryId": 620,
"InteractionType": "AcceptQuest" "InteractionType": "AcceptQuest",
"AetheryteShortcut": "Peaks - Ala Ghiri",
"SkipConditions": {
"AetheryteShortcutIf": {
"InSameTerritory": true
}
}
} }
] ]
}, },

View File

@ -13,7 +13,13 @@
"Z": 739.4979 "Z": 739.4979
}, },
"TerritoryId": 620, "TerritoryId": 620,
"InteractionType": "AcceptQuest" "InteractionType": "AcceptQuest",
"AetheryteShortcut": "Peaks - Ala Ghiri",
"SkipConditions": {
"AetheryteShortcutIf": {
"InSameTerritory": true
}
}
} }
] ]
}, },

View File

@ -16,7 +16,13 @@
"Z": 618.09717 "Z": 618.09717
}, },
"TerritoryId": 621, "TerritoryId": 621,
"InteractionType": "AcceptQuest" "InteractionType": "AcceptQuest",
"AetheryteShortcut": "Lochs - Ala Mhigan Quarter",
"SkipConditions": {
"AetheryteShortcutIf": {
"InSameTerritory": true
}
}
} }
] ]
}, },

View File

@ -13,7 +13,13 @@
"Z": 203.14331 "Z": 203.14331
}, },
"TerritoryId": 1185, "TerritoryId": 1185,
"InteractionType": "AcceptQuest" "InteractionType": "AcceptQuest",
"AetheryteShortcut": "Tuliyollal",
"SkipConditions": {
"AetheryteShortcutIf": {
"InSameTerritory": true
}
}
} }
] ]
}, },

View File

@ -13,7 +13,13 @@
"Z": -48.05072 "Z": -48.05072
}, },
"TerritoryId": 418, "TerritoryId": 418,
"InteractionType": "AcceptQuest" "InteractionType": "AcceptQuest",
"AetheryteShortcut": "Ishgard",
"SkipConditions": {
"AetheryteShortcutIf": {
"InSameTerritory": true
}
}
} }
] ]
}, },

View File

@ -14,6 +14,12 @@
}, },
"TerritoryId": 418, "TerritoryId": 418,
"InteractionType": "AcceptQuest", "InteractionType": "AcceptQuest",
"AetheryteShortcut": "Ishgard",
"SkipConditions": {
"AetheryteShortcutIf": {
"InSameTerritory": true
}
},
"DialogueChoices": [ "DialogueChoices": [
{ {
"Type": "List", "Type": "List",

View File

@ -13,7 +13,13 @@
"Z": -1.7243042 "Z": -1.7243042
}, },
"TerritoryId": 418, "TerritoryId": 418,
"InteractionType": "AcceptQuest" "InteractionType": "AcceptQuest",
"AetheryteShortcut": "Ishgard",
"SkipConditions": {
"AetheryteShortcutIf": {
"InSameTerritory": true
}
}
} }
] ]
}, },

View File

@ -14,7 +14,13 @@
}, },
"StopDistance": 5, "StopDistance": 5,
"TerritoryId": 418, "TerritoryId": 418,
"InteractionType": "AcceptQuest" "InteractionType": "AcceptQuest",
"AetheryteShortcut": "Ishgard",
"SkipConditions": {
"AetheryteShortcutIf": {
"InSameTerritory": true
}
}
} }
] ]
}, },

View File

@ -16,7 +16,13 @@
"Z": -48.17273 "Z": -48.17273
}, },
"TerritoryId": 418, "TerritoryId": 418,
"InteractionType": "AcceptQuest" "InteractionType": "AcceptQuest",
"AetheryteShortcut": "Ishgard",
"SkipConditions": {
"AetheryteShortcutIf": {
"InSameTerritory": true
}
}
} }
] ]
}, },

View File

@ -12,6 +12,7 @@ namespace Questionable.Model.Questing;
public sealed class QuestStep public sealed class QuestStep
{ {
public const float DefaultStopDistance = 3f; public const float DefaultStopDistance = 3f;
public const int VesperBayAetheryteTicket = 30362;
public uint? DataId { get; set; } public uint? DataId { get; set; }
@ -110,4 +111,19 @@ public sealed class QuestStep
else else
return StopDistance ?? DefaultStopDistance; return StopDistance ?? DefaultStopDistance;
} }
/// <summary>
/// Only relevant for the step 0 in sequence 0: Whether this step is valid for teleporting to it.
/// </summary>
/// <returns></returns>
public bool IsTeleportableForPriorityQuests()
{
if (AetheryteShortcut != null)
return true;
if (InteractionType == EInteractionType.UseItem && ItemId == VesperBayAetheryteTicket)
return true;
return false;
}
} }

View File

@ -23,8 +23,6 @@ namespace Questionable.Controller.Steps.Interactions;
internal static class UseItem internal static class UseItem
{ {
public const int VesperBayAetheryteTicket = 30362;
internal sealed class Factory( internal sealed class Factory(
Mount.Factory mountFactory, Mount.Factory mountFactory,
MoveTo.Factory moveFactory, MoveTo.Factory moveFactory,
@ -47,7 +45,7 @@ internal static class UseItem
ArgumentNullException.ThrowIfNull(step.ItemId); ArgumentNullException.ThrowIfNull(step.ItemId);
if (step.ItemId == VesperBayAetheryteTicket) if (step.ItemId == QuestStep.VesperBayAetheryteTicket)
{ {
unsafe unsafe
{ {
@ -196,7 +194,7 @@ internal static class UseItem
if (StartingCombat && condition[ConditionFlag.InCombat]) if (StartingCombat && condition[ConditionFlag.InCombat])
return ETaskResult.TaskComplete; return ETaskResult.TaskComplete;
if (ItemId == VesperBayAetheryteTicket && _usedItem) if (ItemId == QuestStep.VesperBayAetheryteTicket && _usedItem)
{ {
InventoryManager* inventoryManager = InventoryManager.Instance(); InventoryManager* inventoryManager = InventoryManager.Instance();
if (inventoryManager == null) if (inventoryManager == null)
@ -228,7 +226,7 @@ internal static class UseItem
private TimeSpan GetRetryDelay() private TimeSpan GetRetryDelay()
{ {
if (ItemId == VesperBayAetheryteTicket) if (ItemId == QuestStep.VesperBayAetheryteTicket)
return TimeSpan.FromSeconds(11); return TimeSpan.FromSeconds(11);
else else
return TimeSpan.FromSeconds(5); return TimeSpan.FromSeconds(5);

View File

@ -137,7 +137,7 @@ internal static class AetheryteShortcut
if (skipConditions.NearPosition is { } nearPosition && if (skipConditions.NearPosition is { } nearPosition &&
clientState.TerritoryType == step.TerritoryId) clientState.TerritoryType == nearPosition.TerritoryId)
{ {
if (Vector3.Distance(nearPosition.Position, clientState.LocalPlayer!.Position) <= if (Vector3.Distance(nearPosition.Position, clientState.LocalPlayer!.Position) <=
nearPosition.MaximumDistance) nearPosition.MaximumDistance)

View File

@ -204,7 +204,7 @@ internal static class SkipCondition
} }
} }
if (skipConditions.NearPosition is { } nearPosition && clientState.TerritoryType == step.TerritoryId) if (skipConditions.NearPosition is { } nearPosition && clientState.TerritoryType == nearPosition.TerritoryId)
{ {
if (Vector3.Distance(nearPosition.Position, clientState.LocalPlayer!.Position) <= if (Vector3.Distance(nearPosition.Position, clientState.LocalPlayer!.Position) <=
nearPosition.MaximumDistance) nearPosition.MaximumDistance)

View File

@ -262,14 +262,7 @@ internal sealed unsafe class QuestFunctions
if (firstStep == null) if (firstStep == null)
return false; return false;
if (firstStep.AetheryteShortcut != null) return firstStep.IsTeleportableForPriorityQuests();
return true;
if (firstStep is
{ InteractionType: EInteractionType.UseItem, ItemId: UseItem.VesperBayAetheryteTicket })
return true;
return false;
}) })
.FirstOrDefault(x => .FirstOrDefault(x =>
{ {

View File

@ -223,6 +223,7 @@ public sealed class QuestionablePlugin : IDalamudPlugin
serviceCollection.AddSingleton<IQuestValidator, CompletionFlagsValidator>(); serviceCollection.AddSingleton<IQuestValidator, CompletionFlagsValidator>();
serviceCollection.AddSingleton<IQuestValidator, AethernetShortcutValidator>(); serviceCollection.AddSingleton<IQuestValidator, AethernetShortcutValidator>();
serviceCollection.AddSingleton<IQuestValidator, DialogueChoiceValidator>(); serviceCollection.AddSingleton<IQuestValidator, DialogueChoiceValidator>();
serviceCollection.AddSingleton<IQuestValidator, ClassQuestShouldHaveShortcutValidator>();
serviceCollection.AddSingleton<JsonSchemaValidator>(); serviceCollection.AddSingleton<JsonSchemaValidator>();
serviceCollection.AddSingleton<IQuestValidator>(sp => sp.GetRequiredService<JsonSchemaValidator>()); serviceCollection.AddSingleton<IQuestValidator>(sp => sp.GetRequiredService<JsonSchemaValidator>());
} }

View File

@ -17,4 +17,5 @@ public enum EIssueType
UnexpectedCompleteQuestStep, UnexpectedCompleteQuestStep,
InvalidAethernetShortcut, InvalidAethernetShortcut,
InvalidExcelRef, InvalidExcelRef,
ClassQuestWithoutAetheryteShortcut,
} }

View File

@ -1,6 +1,51 @@
namespace Questionable.Validation.Validators; using System.Collections.Generic;
using LLib.GameData;
using Questionable.Data;
using Questionable.Model;
using Questionable.Model.Questing;
public class ClassQuestShouldHaveShortcut namespace Questionable.Validation.Validators;
internal sealed class ClassQuestShouldHaveShortcutValidator : IQuestValidator
{ {
private readonly HashSet<ElementId> _classJobQuests = [];
public ClassQuestShouldHaveShortcutValidator(QuestData questData)
{
foreach (EClassJob classJob in typeof(EClassJob).GetEnumValues())
{
if (classJob == EClassJob.Adventurer)
continue;
foreach (var questInfo in questData.GetClassJobQuests(classJob))
{
// TODO maybe remove the level check
if (questInfo.Level > 1)
_classJobQuests.Add(questInfo.QuestId);
}
}
}
public IEnumerable<ValidationIssue> Validate(Quest quest)
{
if (!_classJobQuests.Contains(quest.Id))
yield break;
var firstStep = quest.FindSequence(0)?.FindStep(0);
if (firstStep == null)
yield break;
if (firstStep.IsTeleportableForPriorityQuests())
yield break;
yield return new ValidationIssue
{
ElementId = quest.Id,
Sequence = 0,
Step = 0,
Type = EIssueType.ClassQuestWithoutAetheryteShortcut,
Severity = EIssueSeverity.Error,
Description = "Class quest should have an aetheryte shortcut to be done automatically",
};
}
} }