177 lines
4.2 KiB
C#
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);
|
|
}
|
|
}
|
|
}
|