master #3

Open
cacahuetes wants to merge 640 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,
"InteractionType": "EquipItem",
"ItemId": 4546
"ItemId": 4546,
"AetheryteShortcut": "South Shroud - Quarrymill",
"Fly": true,
"SkipConditions": {
"AetheryteShortcutIf": {
"InSameTerritory": true
}
}
},
{
"TerritoryId": 153,
@ -22,14 +29,7 @@
"Z": -7.3396606
},
"TerritoryId": 153,
"InteractionType": "AcceptQuest",
"AetheryteShortcut": "South Shroud - Quarrymill",
"Fly": true,
"SkipConditions": {
"AetheryteShortcutIf": {
"InSameTerritory": true
}
}
"InteractionType": "AcceptQuest"
}
]
},

View File

@ -13,7 +13,20 @@
"Z": -142.93127
},
"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,
"InteractionType": "AcceptQuest",
"AetheryteShortcut": "Ul'dah",
"AethernetShortcut": [
"[Ul'dah] Aetheryte Plaza",
"[Ul'dah] Miners' Guild"
],
"SkipConditions": {
"AetheryteShortcutIf": {
"InSameTerritory": true,
"InTerritory": [
131
]
}
},
"DialogueChoices": [
{
"Type": "YesNo",

View File

@ -13,7 +13,20 @@
"Z": 153.2157
},
"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
},
"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
},
"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
},
"TerritoryId": 130,
"InteractionType": "AcceptQuest"
"InteractionType": "AcceptQuest",
"AetheryteShortcut": "Ul'dah",
"SkipConditions": {
"AetheryteShortcutIf": {
"InSameTerritory": true
}
}
}
]
},

View File

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

View File

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

View File

@ -13,7 +13,20 @@
"Z": 39.81079
},
"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
},
"TerritoryId": 129,
"InteractionType": "WalkTo"
"InteractionType": "WalkTo",
"AetheryteShortcut": "Limsa Lominsa",
"SkipConditions": {
"AetheryteShortcutIf": {
"InSameTerritory": true
}
}
},
{
"DataId": 1000895,

View File

@ -8,7 +8,20 @@
{
"TerritoryId": 128,
"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,

View File

@ -13,7 +13,20 @@
"Z": -250.56848
},
"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
},
"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
},
"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
},
"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,
"Z": 281.69678
},
"MaximumDistance": 3
"MaximumDistance": 3,
"TerritoryId": 153
}
}
}
@ -157,7 +158,8 @@
"Y": 8.712891,
"Z": 281.69678
},
"MaximumDistance": 3
"MaximumDistance": 3,
"TerritoryId": 153
}
}
}

View File

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

View File

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

View File

@ -20,8 +20,21 @@
"Prompt": "TEXT_KINGBB201_04854_Q1_000_000",
"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,
"InteractionType": "UseItem",
"ItemId": 43538,
"AetheryteShortcut": "Gridania",
"SkipConditions": {
"StepIf": {
"Item": {
"NotInInventory": true
}
},
"AetheryteShortcutIf": {
"InSameTerritory": true
}
}
},

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -16,7 +16,13 @@
"Z": -48.17273
},
"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 const float DefaultStopDistance = 3f;
public const int VesperBayAetheryteTicket = 30362;
public uint? DataId { get; set; }
@ -110,4 +111,19 @@ public sealed class QuestStep
else
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
{
public const int VesperBayAetheryteTicket = 30362;
internal sealed class Factory(
Mount.Factory mountFactory,
MoveTo.Factory moveFactory,
@ -47,7 +45,7 @@ internal static class UseItem
ArgumentNullException.ThrowIfNull(step.ItemId);
if (step.ItemId == VesperBayAetheryteTicket)
if (step.ItemId == QuestStep.VesperBayAetheryteTicket)
{
unsafe
{
@ -196,7 +194,7 @@ internal static class UseItem
if (StartingCombat && condition[ConditionFlag.InCombat])
return ETaskResult.TaskComplete;
if (ItemId == VesperBayAetheryteTicket && _usedItem)
if (ItemId == QuestStep.VesperBayAetheryteTicket && _usedItem)
{
InventoryManager* inventoryManager = InventoryManager.Instance();
if (inventoryManager == null)
@ -228,7 +226,7 @@ internal static class UseItem
private TimeSpan GetRetryDelay()
{
if (ItemId == VesperBayAetheryteTicket)
if (ItemId == QuestStep.VesperBayAetheryteTicket)
return TimeSpan.FromSeconds(11);
else
return TimeSpan.FromSeconds(5);

View File

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

View File

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

View File

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

View File

@ -17,4 +17,5 @@ public enum EIssueType
UnexpectedCompleteQuestStep,
InvalidAethernetShortcut,
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",
};
}
}