1
0
Fork 0
forked from aly/qstbak
qstbak/Questionable/Questionable.Controller.Steps.Shared/RedeemRewardItems.cs
2026-08-17 20:29:32 +10:00

201 lines
5.4 KiB
C#

using System;
using System.Collections.Generic;
using Dalamud.Game.ClientState.Conditions;
using Dalamud.Plugin.Services;
using FFXIVClientStructs.FFXIV.Client.Game;
using LLib.Gear;
using LLib.Inventory;
using Microsoft.Extensions.Logging;
using Questionable.Controller.Steps.Common;
using Questionable.Data;
using Questionable.Functions;
using Questionable.Model;
using Questionable.Model.Questing;
namespace Questionable.Controller.Steps.Shared;
internal static class RedeemRewardItems
{
internal sealed class Factory(QuestData questData, Configuration configuration) : ITaskFactory
{
public unsafe IEnumerable<ITask> CreateAllTasks(Quest quest, QuestSequence sequence, QuestStep step)
{
if (step.InteractionType != EInteractionType.AcceptQuest)
{
return Array.Empty<ITask>();
}
List<ITask> list = new List<ITask>();
InventoryManager* ptr = InventoryManager.Instance();
if (ptr == null)
{
return list;
}
bool hasFreeInventorySlot = InventoryHelper.HasFreeInventorySlot();
foreach (ItemReward redeemableItem in questData.RedeemableItems)
{
if (ptr->GetInventoryItemCount(redeemableItem.ItemId, isHq: false, checkEquipped: true, checkArmory: true, 0) != 0 && !redeemableItem.IsUnlocked() && PassesRedemptionFilters(redeemableItem.Type, redeemableItem.IsUntradable, configuration.General, hasFreeInventorySlot))
{
list.Add(new Task(redeemableItem));
}
}
if (list.Count > 0)
{
list.Insert(0, new Mount.UnmountTask());
}
return list;
}
}
internal sealed record Task(ItemReward ItemReward) : ITask
{
public int OriginalGearsetIndex { get; set; } = -1;
public override string ToString()
{
return "TryRedeem(" + ItemReward.Name + ")";
}
}
internal sealed class Executor(GameFunctions gameFunctions, Configuration configuration, ICondition condition, ILogger<Executor> logger) : TaskExecutor<Task>(), IStoppableTaskExecutor, ITaskExecutor
{
private static readonly TimeSpan MinimumCastTime = TimeSpan.FromSeconds(4L);
private const long GearsetSettleDelayMs = 1000L;
private const long UseItemRetryDelayMs = 1000L;
private const int MaxUseItemAttempts = 5;
private long _useItemAt;
private long _continueAt;
private int _useItemAttempts;
private bool _itemUsed;
protected override bool Start()
{
if (condition[ConditionFlag.Mounted] && base.Task.OriginalGearsetIndex < 0)
{
return false;
}
long num = (_useItemAt = Environment.TickCount64);
if (base.Task.ItemReward is CofferReward)
{
int? cofferGearsetIndex = configuration.General.CofferGearsetIndex;
if (cofferGearsetIndex.HasValue)
{
int valueOrDefault = cofferGearsetIndex.GetValueOrDefault();
if (base.Task.OriginalGearsetIndex < 0)
{
int currentGearsetIndex = GearsetHelper.GetCurrentGearsetIndex();
if (currentGearsetIndex != valueOrDefault && GearsetHelper.TryEquipGearset(valueOrDefault))
{
base.Task.OriginalGearsetIndex = currentGearsetIndex;
_useItemAt = num + 1000;
}
}
else if (GearsetHelper.GetCurrentGearsetIndex() != valueOrDefault)
{
GearsetHelper.TryEquipGearset(valueOrDefault);
_useItemAt = num + 1000;
}
}
}
return true;
}
public override ETaskResult Update()
{
long tickCount = Environment.TickCount64;
if (!_itemUsed)
{
if (tickCount < _useItemAt)
{
return ETaskResult.StillRunning;
}
if (base.Task.ItemReward.IsUnlocked() || !HasItemInInventory(base.Task.ItemReward.ItemId))
{
RestoreGearset();
return ETaskResult.TaskComplete;
}
if (gameFunctions.UseItem(base.Task.ItemReward.ItemId))
{
_itemUsed = true;
TimeSpan timeSpan = base.Task.ItemReward.CastTime;
if (timeSpan < MinimumCastTime)
{
timeSpan = MinimumCastTime;
}
_continueAt = tickCount + (long)timeSpan.TotalMilliseconds + 3000;
return ETaskResult.StillRunning;
}
_useItemAttempts++;
if (_useItemAttempts >= 5)
{
logger.LogWarning("Unable to use {ItemName} after {Attempts} attempts, giving up", base.Task.ItemReward.Name, _useItemAttempts);
RestoreGearset();
return ETaskResult.TaskComplete;
}
_useItemAt = tickCount + 1000;
return ETaskResult.StillRunning;
}
if (condition[ConditionFlag.Casting])
{
return ETaskResult.StillRunning;
}
if (tickCount <= _continueAt)
{
return ETaskResult.StillRunning;
}
RestoreGearset();
return ETaskResult.TaskComplete;
}
public void StopNow()
{
RestoreGearset();
}
private void RestoreGearset()
{
if (base.Task.OriginalGearsetIndex >= 0 && GearsetHelper.TryEquipGearset(base.Task.OriginalGearsetIndex))
{
base.Task.OriginalGearsetIndex = -1;
}
}
private unsafe static bool HasItemInInventory(uint itemId)
{
InventoryManager* ptr = InventoryManager.Instance();
if (ptr != null)
{
return ptr->GetInventoryItemCount(itemId, isHq: false, checkEquipped: true, checkArmory: true, 0) > 0;
}
return false;
}
public override bool ShouldInterruptOnDamage()
{
return true;
}
}
internal static bool PassesRedemptionFilters(EItemRewardType type, bool isUntradable, Configuration.GeneralConfiguration general, bool hasFreeInventorySlot)
{
if (general.DisabledRewardTypes.Contains(type))
{
return false;
}
if (general.SkipTradableRewards && !isUntradable)
{
return false;
}
if (type == EItemRewardType.Coffer && !hasFreeInventorySlot)
{
return false;
}
return true;
}
}