qstbak/Questionable/Questionable.Controller.GameUi/ShopController.cs
2025-10-09 07:47:19 +10:00

177 lines
4.2 KiB
C#

using System;
using System.Linq;
using System.Numerics;
using Dalamud.Plugin.Services;
using FFXIVClientStructs.FFXIV.Component.GUI;
using LLib.GameUI;
using LLib.Shop;
using LLib.Shop.Model;
using Microsoft.Extensions.Logging;
using Questionable.Model.Questing;
namespace Questionable.Controller.GameUi;
internal sealed class ShopController : IDisposable, IShopWindow
{
private readonly QuestController _questController;
private readonly IGameGui _gameGui;
private readonly IFramework _framework;
private readonly RegularShopBase _shop;
private readonly ILogger<ShopController> _logger;
public bool IsEnabled => _questController.IsRunning;
public bool IsOpen { get; set; }
public bool IsAutoBuyEnabled => _shop.AutoBuyEnabled;
public bool IsAwaitingYesNo
{
get
{
return _shop.IsAwaitingYesNo;
}
set
{
_shop.IsAwaitingYesNo = value;
}
}
public Vector2? Position { get; set; }
public ShopController(QuestController questController, IGameGui gameGui, IAddonLifecycle addonLifecycle, IFramework framework, ILogger<ShopController> logger, IPluginLog pluginLog)
{
_questController = questController;
_gameGui = gameGui;
_framework = framework;
_shop = new RegularShopBase(this, "Shop", pluginLog, gameGui, addonLifecycle);
_logger = logger;
_framework.Update += FrameworkUpdate;
}
public void Dispose()
{
_framework.Update -= FrameworkUpdate;
_shop.Dispose();
}
private void FrameworkUpdate(IFramework framework)
{
if (!IsOpen || _shop.ItemForSale == null)
{
return;
}
if (_shop.PurchaseState != null)
{
_shop.HandleNextPurchaseStep();
return;
}
QuestStep questStep = FindCurrentStep();
if (questStep != null && questStep.InteractionType == EInteractionType.PurchaseItem)
{
int num = Math.Max(0, questStep.ItemCount.GetValueOrDefault() - (int)_shop.ItemForSale.OwnedItems);
if (Math.Min(_shop.GetMaxItemsToPurchase(), num) > 0)
{
_logger.LogDebug("Auto-buying {MissingItems} {ItemName}", num, _shop.ItemForSale.ItemName);
_shop.StartAutoPurchase(num);
_shop.HandleNextPurchaseStep();
}
else
{
_shop.CancelAutoPurchase();
}
}
}
public int GetCurrencyCount()
{
return _shop.GetItemCount(1u);
}
private QuestStep? FindCurrentStep()
{
QuestController.QuestProgress currentQuest = _questController.CurrentQuest;
return (currentQuest?.Quest.FindSequence(currentQuest.Sequence))?.FindStep(currentQuest?.Step ?? 0);
}
public unsafe void UpdateShopStock(AtkUnitBase* addon)
{
QuestStep currentStep = FindCurrentStep();
if (currentStep == null || currentStep.InteractionType != EInteractionType.PurchaseItem)
{
_shop.ItemForSale = null;
return;
}
if (addon->AtkValuesCount != 625)
{
_logger.LogError("Unexpected amount of atkvalues for Shop addon ({AtkValueCount})", addon->AtkValuesCount);
_shop.ItemForSale = null;
return;
}
AtkValue* atkValues = addon->AtkValues;
if (atkValues->UInt != 0)
{
_shop.ItemForSale = null;
return;
}
uint uInt = atkValues[2].UInt;
if (uInt == 0)
{
_shop.ItemForSale = null;
return;
}
_shop.ItemForSale = (from i in Enumerable.Range(0, (int)uInt)
select new ItemForSale
{
Position = i,
ItemName = atkValues[14 + i].ReadAtkString(),
Price = atkValues[75 + i].UInt,
OwnedItems = atkValues[136 + i].UInt,
ItemId = atkValues[441 + i].UInt
}).FirstOrDefault((ItemForSale x) => x.ItemId == currentStep.ItemId);
}
public unsafe void TriggerPurchase(AtkUnitBase* addonShop, int buyNow)
{
AtkValue* values = stackalloc AtkValue[4]
{
new AtkValue
{
Type = FFXIVClientStructs.FFXIV.Component.GUI.ValueType.Int,
Int = 0
},
new AtkValue
{
Type = FFXIVClientStructs.FFXIV.Component.GUI.ValueType.Int,
Int = _shop.ItemForSale.Position
},
new AtkValue
{
Type = FFXIVClientStructs.FFXIV.Component.GUI.ValueType.Int,
Int = buyNow
},
new AtkValue
{
Type = FFXIVClientStructs.FFXIV.Component.GUI.ValueType.Undefined,
Int = 0
}
};
addonShop->FireCallback(4u, values);
}
public void SaveExternalPluginState()
{
}
public unsafe void RestoreExternalPluginState()
{
if (_gameGui.TryGetAddonByName<AtkUnitBase>("Shop", out var addonPtr))
{
addonPtr->FireCallbackInt(-1);
}
}
}