diff --git a/QuestPathGenerator/RoslynElements/QuestStepExtensions.cs b/QuestPathGenerator/RoslynElements/QuestStepExtensions.cs index ecfea639..12b27ef4 100644 --- a/QuestPathGenerator/RoslynElements/QuestStepExtensions.cs +++ b/QuestPathGenerator/RoslynElements/QuestStepExtensions.cs @@ -97,6 +97,9 @@ internal static class QuestStepExtensions .AsSyntaxNodeOrToken(), Assignment(nameof(QuestStep.Status), step.Status, emptyStep.Status) .AsSyntaxNodeOrToken(), + Assignment(nameof(QuestStep.TargetClass), step.TargetClass, + emptyStep.TargetClass) + .AsSyntaxNodeOrToken(), Assignment(nameof(QuestStep.EnemySpawnType), step.EnemySpawnType, emptyStep.EnemySpawnType) .AsSyntaxNodeOrToken(), diff --git a/QuestPaths/3.x - Heavensward/Custom Deliveries/Zhloe/S1_Zhloe Aliapoh.json b/QuestPaths/3.x - Heavensward/Custom Deliveries/Zhloe/S1_Zhloe Aliapoh.json index 1422190e..87ef448e 100644 --- a/QuestPaths/3.x - Heavensward/Custom Deliveries/Zhloe/S1_Zhloe Aliapoh.json +++ b/QuestPaths/3.x - Heavensward/Custom Deliveries/Zhloe/S1_Zhloe Aliapoh.json @@ -5,6 +5,11 @@ { "Sequence": 0, "Steps": [ + { + "TerritoryId": 478, + "InteractionType": "SwitchClass", + "TargetClass": "Blue Mage" + }, { "TerritoryId": 478, "InteractionType": "Gather", diff --git a/QuestPaths/4.x - Stormblood/Custom Deliveries/Adkiragh/S4_Adkiragh.json b/QuestPaths/4.x - Stormblood/Custom Deliveries/Adkiragh/S4_Adkiragh.json index 99762b5b..cf54ae7c 100644 --- a/QuestPaths/4.x - Stormblood/Custom Deliveries/Adkiragh/S4_Adkiragh.json +++ b/QuestPaths/4.x - Stormblood/Custom Deliveries/Adkiragh/S4_Adkiragh.json @@ -5,6 +5,11 @@ { "Sequence": 0, "Steps": [ + { + "TerritoryId": 478, + "InteractionType": "SwitchClass", + "TargetClass": "Blue Mage" + }, { "TerritoryId": 478, "InteractionType": "Gather", diff --git a/QuestPaths/4.x - Stormblood/Custom Deliveries/Kurenai/S3_Kurenai.json b/QuestPaths/4.x - Stormblood/Custom Deliveries/Kurenai/S3_Kurenai.json index 9b1f82dc..887dbdd4 100644 --- a/QuestPaths/4.x - Stormblood/Custom Deliveries/Kurenai/S3_Kurenai.json +++ b/QuestPaths/4.x - Stormblood/Custom Deliveries/Kurenai/S3_Kurenai.json @@ -5,6 +5,11 @@ { "Sequence": 0, "Steps": [ + { + "TerritoryId": 613, + "InteractionType": "SwitchClass", + "TargetClass": "Blue Mage" + }, { "TerritoryId": 613, "InteractionType": "Gather", diff --git a/QuestPaths/4.x - Stormblood/Custom Deliveries/M'naago/S2_M'naago.json b/QuestPaths/4.x - Stormblood/Custom Deliveries/M'naago/S2_M'naago.json index ba9858d8..43cd2ebc 100644 --- a/QuestPaths/4.x - Stormblood/Custom Deliveries/M'naago/S2_M'naago.json +++ b/QuestPaths/4.x - Stormblood/Custom Deliveries/M'naago/S2_M'naago.json @@ -5,6 +5,11 @@ { "Sequence": 0, "Steps": [ + { + "TerritoryId": 635, + "InteractionType": "SwitchClass", + "TargetClass": "Blue Mage" + }, { "TerritoryId": 635, "InteractionType": "Gather", diff --git a/QuestPaths/5.x - Shadowbringers/Custom Deliveries/Charlemend/S7_Charlemend.json b/QuestPaths/5.x - Shadowbringers/Custom Deliveries/Charlemend/S7_Charlemend.json index 18b2d648..169f78bd 100644 --- a/QuestPaths/5.x - Shadowbringers/Custom Deliveries/Charlemend/S7_Charlemend.json +++ b/QuestPaths/5.x - Shadowbringers/Custom Deliveries/Charlemend/S7_Charlemend.json @@ -5,6 +5,11 @@ { "Sequence": 0, "Steps": [ + { + "TerritoryId": 886, + "InteractionType": "SwitchClass", + "TargetClass": "Blue Mage" + }, { "TerritoryId": 886, "InteractionType": "Gather", diff --git a/QuestPaths/5.x - Shadowbringers/Custom Deliveries/Ehll Tou/S6_Ehll Tou.json b/QuestPaths/5.x - Shadowbringers/Custom Deliveries/Ehll Tou/S6_Ehll Tou.json index ec41fc8c..adc20fb6 100644 --- a/QuestPaths/5.x - Shadowbringers/Custom Deliveries/Ehll Tou/S6_Ehll Tou.json +++ b/QuestPaths/5.x - Shadowbringers/Custom Deliveries/Ehll Tou/S6_Ehll Tou.json @@ -5,6 +5,11 @@ { "Sequence": 0, "Steps": [ + { + "TerritoryId": 886, + "InteractionType": "SwitchClass", + "TargetClass": "Blue Mage" + }, { "TerritoryId": 886, "InteractionType": "Gather", diff --git a/QuestPaths/5.x - Shadowbringers/Custom Deliveries/Kai-Shirr/S5_Kai-Shirr.json b/QuestPaths/5.x - Shadowbringers/Custom Deliveries/Kai-Shirr/S5_Kai-Shirr.json index 00702053..7e4b595d 100644 --- a/QuestPaths/5.x - Shadowbringers/Custom Deliveries/Kai-Shirr/S5_Kai-Shirr.json +++ b/QuestPaths/5.x - Shadowbringers/Custom Deliveries/Kai-Shirr/S5_Kai-Shirr.json @@ -5,6 +5,11 @@ { "Sequence": 0, "Steps": [ + { + "TerritoryId": 820, + "InteractionType": "SwitchClass", + "TargetClass": "Blue Mage" + }, { "TerritoryId": 820, "InteractionType": "Gather", diff --git a/QuestPaths/6.x - Endwalker/Custom Deliveries/Ameliance/S8_Ameliance.json b/QuestPaths/6.x - Endwalker/Custom Deliveries/Ameliance/S8_Ameliance.json index 9cd56890..56f16b92 100644 --- a/QuestPaths/6.x - Endwalker/Custom Deliveries/Ameliance/S8_Ameliance.json +++ b/QuestPaths/6.x - Endwalker/Custom Deliveries/Ameliance/S8_Ameliance.json @@ -5,6 +5,11 @@ { "Sequence": 0, "Steps": [ + { + "TerritoryId": 962, + "InteractionType": "SwitchClass", + "TargetClass": "Blue Mage" + }, { "TerritoryId": 962, "InteractionType": "Gather", diff --git a/QuestPaths/6.x - Endwalker/Custom Deliveries/Anden/S9_Anden.json b/QuestPaths/6.x - Endwalker/Custom Deliveries/Anden/S9_Anden.json index b36972b0..8f0e1831 100644 --- a/QuestPaths/6.x - Endwalker/Custom Deliveries/Anden/S9_Anden.json +++ b/QuestPaths/6.x - Endwalker/Custom Deliveries/Anden/S9_Anden.json @@ -5,6 +5,11 @@ { "Sequence": 0, "Steps": [ + { + "TerritoryId": 816, + "InteractionType": "SwitchClass", + "TargetClass": "Blue Mage" + }, { "TerritoryId": 816, "InteractionType": "Gather", diff --git a/QuestPaths/6.x - Endwalker/Custom Deliveries/Margrat/S10_Margrat.json b/QuestPaths/6.x - Endwalker/Custom Deliveries/Margrat/S10_Margrat.json index e4d27b17..6bd9ee4a 100644 --- a/QuestPaths/6.x - Endwalker/Custom Deliveries/Margrat/S10_Margrat.json +++ b/QuestPaths/6.x - Endwalker/Custom Deliveries/Margrat/S10_Margrat.json @@ -5,6 +5,11 @@ { "Sequence": 0, "Steps": [ + { + "TerritoryId": 956, + "InteractionType": "SwitchClass", + "TargetClass": "Blue Mage" + }, { "TerritoryId": 956, "InteractionType": "Gather", diff --git a/QuestPaths/quest-v1.json b/QuestPaths/quest-v1.json index 58c1d16a..72ee6318 100644 --- a/QuestPaths/quest-v1.json +++ b/QuestPaths/quest-v1.json @@ -128,6 +128,7 @@ "Craft", "Gather", "Snipe", + "SwitchClass", "Instruction", "AcceptQuest", "CompleteQuest", @@ -1365,6 +1366,25 @@ "Comment" ] } + }, + { + "if": { + "properties": { + "InteractionType": { + "const": "SwitchClass" + } + } + }, + "then": { + "properties": { + "TargetClass": { + "$ref": "https://git.carvel.li/liza/Questionable/raw/branch/master/Questionable.Model/common-schema.json#/$defs/ClassJob" + } + }, + "required": [ + "TargetClass" + ] + } } ] } diff --git a/Questionable.Model/Questing/Converter/ExtendedClassJobConverter.cs b/Questionable.Model/Questing/Converter/ExtendedClassJobConverter.cs index c92ca0bc..2eaffe5e 100644 --- a/Questionable.Model/Questing/Converter/ExtendedClassJobConverter.cs +++ b/Questionable.Model/Questing/Converter/ExtendedClassJobConverter.cs @@ -7,6 +7,7 @@ internal sealed class ExtendedClassJobConverter() : EnumConverter Values = new() { + { EExtendedClassJob.None, "None" }, { EExtendedClassJob.Gladiator, "Gladiator" }, { EExtendedClassJob.Pugilist, "Pugilist" }, { EExtendedClassJob.Marauder, "Marauder" }, diff --git a/Questionable.Model/Questing/Converter/InteractionTypeConverter.cs b/Questionable.Model/Questing/Converter/InteractionTypeConverter.cs index b8367ebb..9de1ad0e 100644 --- a/Questionable.Model/Questing/Converter/InteractionTypeConverter.cs +++ b/Questionable.Model/Questing/Converter/InteractionTypeConverter.cs @@ -31,6 +31,7 @@ public sealed class InteractionTypeConverter() : EnumConverter { EInteractionType.Craft, "Craft" }, { EInteractionType.Gather, "Gather" }, { EInteractionType.Snipe, "Snipe" }, + { EInteractionType.SwitchClass, "SwitchClass" }, { EInteractionType.Instruction, "Instruction" }, { EInteractionType.AcceptQuest, "AcceptQuest" }, { EInteractionType.CompleteQuest, "CompleteQuest" }, diff --git a/Questionable.Model/Questing/EExtendedClassJob.cs b/Questionable.Model/Questing/EExtendedClassJob.cs index 79c771d1..e0f0d3fe 100644 --- a/Questionable.Model/Questing/EExtendedClassJob.cs +++ b/Questionable.Model/Questing/EExtendedClassJob.cs @@ -6,6 +6,7 @@ namespace Questionable.Model.Questing; [JsonConverter(typeof(ExtendedClassJobConverter))] public enum EExtendedClassJob { + None, Gladiator, Pugilist, Marauder, @@ -53,3 +54,4 @@ public enum EExtendedClassJob DoH, DoL, } + diff --git a/Questionable.Model/Questing/EInteractionType.cs b/Questionable.Model/Questing/EInteractionType.cs index 137078eb..2b9a75fc 100644 --- a/Questionable.Model/Questing/EInteractionType.cs +++ b/Questionable.Model/Questing/EInteractionType.cs @@ -30,6 +30,7 @@ public enum EInteractionType Craft, Gather, Snipe, + SwitchClass, /// /// Needs to be manually continued. diff --git a/Questionable.Model/Questing/QuestStep.cs b/Questionable.Model/Questing/QuestStep.cs index df2b7b12..0b4a05a2 100644 --- a/Questionable.Model/Questing/QuestStep.cs +++ b/Questionable.Model/Questing/QuestStep.cs @@ -64,6 +64,7 @@ public sealed class QuestStep public ChatMessage? ChatMessage { get; set; } public EAction? Action { get; set; } public EStatus? Status { get; set; } + public EExtendedClassJob TargetClass { get; set; } = EExtendedClassJob.None; public EEnemySpawnType? EnemySpawnType { get; set; } public List KillEnemyDataIds { get; set; } = []; diff --git a/Questionable/Controller/ContextMenuController.cs b/Questionable/Controller/ContextMenuController.cs index f35e8343..c3d6c4c5 100644 --- a/Questionable/Controller/ContextMenuController.cs +++ b/Questionable/Controller/ContextMenuController.cs @@ -71,14 +71,16 @@ internal sealed class ContextMenuController : IDisposable if (_gatheringData.TryGetCustomDeliveryNpc(itemId, out uint npcId)) { - AddContextMenuEntry(args, itemId, npcId, EClassJob.Miner, "Mine"); - AddContextMenuEntry(args, itemId, npcId, EClassJob.Botanist, "Harvest"); + AddContextMenuEntry(args, itemId, npcId, EExtendedClassJob.Miner, "Mine"); + AddContextMenuEntry(args, itemId, npcId, EExtendedClassJob.Botanist, "Harvest"); } } - private void AddContextMenuEntry(IMenuOpenedArgs args, uint itemId, uint npcId, EClassJob classJob, string verb) + private void AddContextMenuEntry(IMenuOpenedArgs args, uint itemId, uint npcId, EExtendedClassJob extendedClassJob, + string verb) { EClassJob currentClassJob = (EClassJob)_clientState.LocalPlayer!.ClassJob.Id; + EClassJob classJob = ClassJobUtils.AsIndividualJobs(extendedClassJob).Single(); if (classJob != currentClassJob && currentClassJob is EClassJob.Miner or EClassJob.Botanist) return; @@ -123,19 +125,25 @@ internal sealed class ContextMenuController : IDisposable Prefix = SeIconChar.Hyadelyn, PrefixColor = 52, Name = name, - OnClicked = _ => StartGathering(npcId, itemId, quantityToGather, collectability), + OnClicked = _ => StartGathering(npcId, itemId, quantityToGather, collectability, extendedClassJob), IsEnabled = string.IsNullOrEmpty(lockedReasonn), }); } - private void StartGathering(uint npcId, uint itemId, int quantity, ushort collectability) + private void StartGathering(uint npcId, uint itemId, int quantity, ushort collectability, + EExtendedClassJob extendedClassJob) { var info = (SatisfactionSupplyInfo)_questData.GetAllByIssuerDataId(npcId) .Single(x => x is SatisfactionSupplyInfo); if (_questRegistry.TryGetQuest(info.QuestId, out Quest? quest)) { - var step = quest.FindSequence(0)!.Steps.Single(x => x.InteractionType == EInteractionType.Gather); - step.ItemsToGather = + var sequence = quest.FindSequence(0)!; + + var switchClassStep = sequence.Steps.Single(x => x.InteractionType == EInteractionType.SwitchClass); + switchClassStep.TargetClass = extendedClassJob; + + var gatherStep = sequence.Steps.Single(x => x.InteractionType == EInteractionType.Gather); + gatherStep.ItemsToGather = [ new GatheredItem { diff --git a/Questionable/Controller/Steps/Shared/SwitchClassJob.cs b/Questionable/Controller/Steps/Shared/SwitchClassJob.cs index 37ddf1ee..48b153c3 100644 --- a/Questionable/Controller/Steps/Shared/SwitchClassJob.cs +++ b/Questionable/Controller/Steps/Shared/SwitchClassJob.cs @@ -1,13 +1,27 @@ -using Dalamud.Plugin.Services; -using FFXIVClientStructs.FFXIV.Client.Game; +using System.Linq; +using Dalamud.Plugin.Services; using FFXIVClientStructs.FFXIV.Client.UI.Misc; using LLib.GameData; using Questionable.Controller.Steps.Common; +using Questionable.Data; +using Questionable.Model; +using Questionable.Model.Questing; namespace Questionable.Controller.Steps.Shared; internal static class SwitchClassJob { + internal sealed class Factory : SimpleTaskFactory + { + public override ITask? CreateTask(Quest quest, QuestSequence sequence, QuestStep step) + { + if (step.InteractionType != EInteractionType.SwitchClass) + return null; + + EClassJob classJob = ClassJobUtils.AsIndividualJobs(step.TargetClass).Single(); + return new Task(classJob); + } + } internal sealed record Task(EClassJob ClassJob) : ITask { public override string ToString() => $"SwitchJob({ClassJob})"; diff --git a/Questionable/QuestionablePlugin.cs b/Questionable/QuestionablePlugin.cs index 9289b120..ea0eefca 100644 --- a/Questionable/QuestionablePlugin.cs +++ b/Questionable/QuestionablePlugin.cs @@ -137,7 +137,8 @@ public sealed class QuestionablePlugin : IDalamudPlugin .AddTaskExecutor(); serviceCollection.AddTaskExecutor(); serviceCollection.AddTaskExecutor(); - serviceCollection.AddTaskExecutor(); + serviceCollection.AddTaskFactoryAndExecutor(); serviceCollection.AddTaskExecutor(); serviceCollection.AddTaskExecutor();