diff --git a/QuestPathGenerator/RoslynElements/QuestStepExtensions.cs b/QuestPathGenerator/RoslynElements/QuestStepExtensions.cs index 0e4e9dd0..11cdc214 100644 --- a/QuestPathGenerator/RoslynElements/QuestStepExtensions.cs +++ b/QuestPathGenerator/RoslynElements/QuestStepExtensions.cs @@ -44,6 +44,8 @@ internal static class QuestStepExtensions Assignment(nameof(QuestStep.DelaySecondsAtStart), step.DelaySecondsAtStart, emptyStep.DelaySecondsAtStart) .AsSyntaxNodeOrToken(), + Assignment(nameof(QuestStep.PickUpItemId), step.PickUpItemId, emptyStep.PickUpItemId) + .AsSyntaxNodeOrToken(), Assignment(nameof(QuestStep.Disabled), step.Disabled, emptyStep.Disabled) .AsSyntaxNodeOrToken(), Assignment(nameof(QuestStep.DisableNavmesh), step.DisableNavmesh, diff --git a/QuestPaths/2.x - A Realm Reborn/MSQ-1/Limsa/402_Thanks a Million.json b/QuestPaths/2.x - A Realm Reborn/MSQ-1/Limsa/402_Thanks a Million.json index 2f02ad56..88a45ef3 100644 --- a/QuestPaths/2.x - A Realm Reborn/MSQ-1/Limsa/402_Thanks a Million.json +++ b/QuestPaths/2.x - A Realm Reborn/MSQ-1/Limsa/402_Thanks a Million.json @@ -29,7 +29,8 @@ }, "TerritoryId": 134, "InteractionType": "Interact", - "Comment": "Technically triggers combat, but can be ignored" + "Comment": "Technically triggers combat, but can be ignored", + "PickUpItemId": 2000342 } ] }, 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 8a9700f8..2619b49f 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 @@ -59,6 +59,7 @@ "StopDistance": 5, "TerritoryId": 134, "InteractionType": "Interact", + "DelaySecondsAtStart": 3, "DialogueChoices": [ { "Type": "List", diff --git a/QuestPaths/quest-v1.json b/QuestPaths/quest-v1.json index 06f9a711..c717679f 100644 --- a/QuestPaths/quest-v1.json +++ b/QuestPaths/quest-v1.json @@ -440,6 +440,11 @@ } }, "then": { + "properties": { + "PickUpItemId": { + "type": "number" + } + }, "required": [ "DataId" ] diff --git a/Questionable.Model/Questing/QuestStep.cs b/Questionable.Model/Questing/QuestStep.cs index bb2f7140..a09386bc 100644 --- a/Questionable.Model/Questing/QuestStep.cs +++ b/Questionable.Model/Questing/QuestStep.cs @@ -27,6 +27,7 @@ public sealed class QuestStep public float? NpcWaitDistance { get; set; } public ushort? TargetTerritoryId { get; set; } public float? DelaySecondsAtStart { get; set; } + public uint? PickUpItemId { get; set; } public bool Disabled { get; set; } public bool DisableNavmesh { get; set; } diff --git a/Questionable/Controller/Steps/Interactions/Interact.cs b/Questionable/Controller/Steps/Interactions/Interact.cs index 49b9e419..0482d88b 100644 --- a/Questionable/Controller/Steps/Interactions/Interact.cs +++ b/Questionable/Controller/Steps/Interactions/Interact.cs @@ -4,6 +4,7 @@ using Dalamud.Game.ClientState.Conditions; using Dalamud.Game.ClientState.Objects.Enums; using Dalamud.Game.ClientState.Objects.Types; using Dalamud.Plugin.Services; +using FFXIVClientStructs.FFXIV.Client.Game; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Questionable.Controller.Steps.Shared; @@ -15,7 +16,8 @@ namespace Questionable.Controller.Steps.Interactions; internal static class Interact { - internal sealed class Factory(GameFunctions gameFunctions, ICondition condition, ILoggerFactory loggerFactory) : ITaskFactory + internal sealed class Factory(GameFunctions gameFunctions, ICondition condition, ILoggerFactory loggerFactory) + : ITaskFactory { public IEnumerable CreateAllTasks(Quest quest, QuestSequence sequence, QuestStep step) { @@ -39,13 +41,14 @@ internal static class Interact yield return new WaitAtEnd.WaitDelay(); yield return Interact(step.DataId.Value, quest, step.InteractionType, - step.TargetTerritoryId != null || quest.Id is SatisfactionSupplyNpcId); + step.TargetTerritoryId != null || quest.Id is SatisfactionSupplyNpcId, step.PickUpItemId); } - internal ITask Interact(uint dataId, Quest? quest, EInteractionType interactionType, bool skipMarkerCheck = false) + internal ITask Interact(uint dataId, Quest? quest, EInteractionType interactionType, + bool skipMarkerCheck = false, uint? pickUpItemId = null) { - return new DoInteract(dataId, quest, interactionType, skipMarkerCheck, gameFunctions, condition, - loggerFactory.CreateLogger()); + return new DoInteract(dataId, quest, interactionType, skipMarkerCheck, pickUpItemId, gameFunctions, + condition, loggerFactory.CreateLogger()); } } @@ -54,6 +57,7 @@ internal static class Interact Quest? quest, EInteractionType interactionType, bool skipMarkerCheck, + uint? pickUpItemId, GameFunctions gameFunctions, ICondition condition, ILogger logger) @@ -64,6 +68,7 @@ internal static class Interact private DateTime _continueAt = DateTime.MinValue; public Quest? Quest => quest; + public EInteractionType InteractionType { get => interactionType; @@ -119,11 +124,23 @@ internal static class Interact _needsUnmount = false; } - if (_interactionState == EInteractionState.InteractionConfirmed) - return ETaskResult.TaskComplete; + if (pickUpItemId != null) + { + unsafe + { + InventoryManager* inventoryManager = InventoryManager.Instance(); + if (inventoryManager->GetInventoryItemCount(pickUpItemId.Value) > 0) + return ETaskResult.TaskComplete; + } + } + else + { + if (_interactionState == EInteractionState.InteractionConfirmed) + return ETaskResult.TaskComplete; - if (interactionType == EInteractionType.InternalGather && condition[ConditionFlag.Gathering]) - return ETaskResult.TaskComplete; + if (interactionType == EInteractionType.InternalGather && condition[ConditionFlag.Gathering]) + return ETaskResult.TaskComplete; + } IGameObject? gameObject = gameFunctions.FindObjectByDataId(dataId); if (gameObject == null || !gameObject.IsTargetable || !HasAnyMarker(gameObject))