punish v6.8.18.0
This commit is contained in:
commit
cfb4dea47e
316 changed files with 554088 additions and 0 deletions
23
LLib/LLib.Shop/IShopWindow.cs
Normal file
23
LLib/LLib.Shop/IShopWindow.cs
Normal file
|
@ -0,0 +1,23 @@
|
|||
using System.Numerics;
|
||||
using FFXIVClientStructs.FFXIV.Component.GUI;
|
||||
|
||||
namespace LLib.Shop;
|
||||
|
||||
public interface IShopWindow
|
||||
{
|
||||
bool IsEnabled { get; }
|
||||
|
||||
bool IsOpen { get; set; }
|
||||
|
||||
Vector2? Position { get; set; }
|
||||
|
||||
int GetCurrencyCount();
|
||||
|
||||
unsafe void UpdateShopStock(AtkUnitBase* addon);
|
||||
|
||||
unsafe void TriggerPurchase(AtkUnitBase* addonShop, int buyNow);
|
||||
|
||||
void SaveExternalPluginState();
|
||||
|
||||
void RestoreExternalPluginState();
|
||||
}
|
275
LLib/LLib.Shop/RegularShopBase.cs
Normal file
275
LLib/LLib.Shop/RegularShopBase.cs
Normal file
|
@ -0,0 +1,275 @@
|
|||
using System;
|
||||
using System.Numerics;
|
||||
using Dalamud.Game.Addon.Lifecycle;
|
||||
using Dalamud.Game.Addon.Lifecycle.AddonArgTypes;
|
||||
using Dalamud.Plugin.Services;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game;
|
||||
using FFXIVClientStructs.FFXIV.Component.GUI;
|
||||
using LLib.GameUI;
|
||||
using LLib.Shop.Model;
|
||||
|
||||
namespace LLib.Shop;
|
||||
|
||||
public class RegularShopBase
|
||||
{
|
||||
private readonly IShopWindow _parentWindow;
|
||||
|
||||
private readonly string _addonName;
|
||||
|
||||
private readonly IPluginLog _pluginLog;
|
||||
|
||||
private readonly IGameGui _gameGui;
|
||||
|
||||
private readonly IAddonLifecycle _addonLifecycle;
|
||||
|
||||
public ItemForSale? ItemForSale { get; set; }
|
||||
|
||||
public PurchaseState? PurchaseState { get; private set; }
|
||||
|
||||
public bool AutoBuyEnabled => PurchaseState != null;
|
||||
|
||||
public bool IsAwaitingYesNo
|
||||
{
|
||||
get
|
||||
{
|
||||
return PurchaseState?.IsAwaitingYesNo ?? false;
|
||||
}
|
||||
set
|
||||
{
|
||||
PurchaseState.IsAwaitingYesNo = value;
|
||||
}
|
||||
}
|
||||
|
||||
public RegularShopBase(IShopWindow parentWindow, string addonName, IPluginLog pluginLog, IGameGui gameGui, IAddonLifecycle addonLifecycle)
|
||||
{
|
||||
_parentWindow = parentWindow;
|
||||
_addonName = addonName;
|
||||
_pluginLog = pluginLog;
|
||||
_gameGui = gameGui;
|
||||
_addonLifecycle = addonLifecycle;
|
||||
_addonLifecycle.RegisterListener(AddonEvent.PostSetup, _addonName, ShopPostSetup);
|
||||
_addonLifecycle.RegisterListener(AddonEvent.PreFinalize, _addonName, ShopPreFinalize);
|
||||
_addonLifecycle.RegisterListener(AddonEvent.PostUpdate, _addonName, ShopPostUpdate);
|
||||
}
|
||||
|
||||
private unsafe void ShopPostSetup(AddonEvent type, AddonArgs args)
|
||||
{
|
||||
if (!_parentWindow.IsEnabled)
|
||||
{
|
||||
ItemForSale = null;
|
||||
_parentWindow.IsOpen = false;
|
||||
return;
|
||||
}
|
||||
_parentWindow.UpdateShopStock((AtkUnitBase*)args.Addon.Address);
|
||||
PostUpdateShopStock();
|
||||
if (ItemForSale != null)
|
||||
{
|
||||
_parentWindow.IsOpen = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void ShopPreFinalize(AddonEvent type, AddonArgs args)
|
||||
{
|
||||
PurchaseState = null;
|
||||
_parentWindow.RestoreExternalPluginState();
|
||||
_parentWindow.IsOpen = false;
|
||||
}
|
||||
|
||||
private unsafe void ShopPostUpdate(AddonEvent type, AddonArgs args)
|
||||
{
|
||||
if (!_parentWindow.IsEnabled)
|
||||
{
|
||||
ItemForSale = null;
|
||||
_parentWindow.IsOpen = false;
|
||||
return;
|
||||
}
|
||||
_parentWindow.UpdateShopStock((AtkUnitBase*)args.Addon.Address);
|
||||
PostUpdateShopStock();
|
||||
if (ItemForSale != null)
|
||||
{
|
||||
AtkUnitBase* address = (AtkUnitBase*)args.Addon.Address;
|
||||
short num = 0;
|
||||
short num2 = 0;
|
||||
address->GetPosition(&num, &num2);
|
||||
short num3 = 0;
|
||||
short num4 = 0;
|
||||
address->GetSize(&num3, &num4, scaled: true);
|
||||
num += num3;
|
||||
Vector2? position = _parentWindow.Position;
|
||||
if (position.HasValue)
|
||||
{
|
||||
Vector2 valueOrDefault = position.GetValueOrDefault();
|
||||
if ((short)valueOrDefault.X != num || (short)valueOrDefault.Y != num2)
|
||||
{
|
||||
_parentWindow.Position = new Vector2(num, num2);
|
||||
}
|
||||
}
|
||||
_parentWindow.IsOpen = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
_parentWindow.IsOpen = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void PostUpdateShopStock()
|
||||
{
|
||||
if (ItemForSale != null && PurchaseState != null)
|
||||
{
|
||||
int ownedItems = (int)ItemForSale.OwnedItems;
|
||||
if (PurchaseState.OwnedItems != ownedItems)
|
||||
{
|
||||
PurchaseState.OwnedItems = ownedItems;
|
||||
PurchaseState.NextStep = DateTime.Now.AddSeconds(0.25);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public unsafe int GetItemCount(uint itemId)
|
||||
{
|
||||
return InventoryManager.Instance()->GetInventoryItemCount(itemId, isHq: false, checkEquipped: false, checkArmory: false, 0);
|
||||
}
|
||||
|
||||
public int GetMaxItemsToPurchase()
|
||||
{
|
||||
if (ItemForSale == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return (int)(_parentWindow.GetCurrencyCount() / ItemForSale.Price);
|
||||
}
|
||||
|
||||
public void CancelAutoPurchase()
|
||||
{
|
||||
PurchaseState = null;
|
||||
_parentWindow.RestoreExternalPluginState();
|
||||
}
|
||||
|
||||
public void StartAutoPurchase(int toPurchase)
|
||||
{
|
||||
PurchaseState = new PurchaseState((int)ItemForSale.OwnedItems + toPurchase, (int)ItemForSale.OwnedItems);
|
||||
_parentWindow.SaveExternalPluginState();
|
||||
}
|
||||
|
||||
public unsafe void HandleNextPurchaseStep()
|
||||
{
|
||||
if (ItemForSale == null || PurchaseState == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
int num = DetermineMaxStackSize(ItemForSale.ItemId);
|
||||
if (num == 0 && !HasFreeInventorySlot())
|
||||
{
|
||||
_pluginLog.Warning("No free inventory slots, can't buy more " + ItemForSale.ItemName);
|
||||
PurchaseState = null;
|
||||
_parentWindow.RestoreExternalPluginState();
|
||||
}
|
||||
else if (!PurchaseState.IsComplete)
|
||||
{
|
||||
if (PurchaseState.NextStep <= DateTime.Now && _gameGui.TryGetAddonByName<AtkUnitBase>(_addonName, out var addonPtr))
|
||||
{
|
||||
int num2 = Math.Min(PurchaseState.ItemsLeftToBuy, num);
|
||||
_pluginLog.Information($"Buying {num2}x {ItemForSale.ItemName}");
|
||||
_parentWindow.TriggerPurchase(addonPtr, num2);
|
||||
PurchaseState.NextStep = DateTime.MaxValue;
|
||||
PurchaseState.IsAwaitingYesNo = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_pluginLog.Information($"Stopping item purchase (desired = {PurchaseState.DesiredItems}, owned = {PurchaseState.OwnedItems})");
|
||||
PurchaseState = null;
|
||||
_parentWindow.RestoreExternalPluginState();
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_addonLifecycle.UnregisterListener(AddonEvent.PostSetup, _addonName, ShopPostSetup);
|
||||
_addonLifecycle.UnregisterListener(AddonEvent.PreFinalize, _addonName, ShopPreFinalize);
|
||||
_addonLifecycle.UnregisterListener(AddonEvent.PostUpdate, _addonName, ShopPostUpdate);
|
||||
}
|
||||
|
||||
public bool HasFreeInventorySlot()
|
||||
{
|
||||
return CountFreeInventorySlots() > 0;
|
||||
}
|
||||
|
||||
public unsafe int CountFreeInventorySlots()
|
||||
{
|
||||
InventoryManager* ptr = InventoryManager.Instance();
|
||||
if (ptr == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
int num = 0;
|
||||
for (InventoryType inventoryType = InventoryType.Inventory1; inventoryType <= InventoryType.Inventory4; inventoryType++)
|
||||
{
|
||||
InventoryContainer* inventoryContainer = ptr->GetInventoryContainer(inventoryType);
|
||||
for (int i = 0; i < inventoryContainer->Size; i++)
|
||||
{
|
||||
InventoryItem* inventorySlot = inventoryContainer->GetInventorySlot(i);
|
||||
if (inventorySlot == null || inventorySlot->ItemId == 0)
|
||||
{
|
||||
num++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
private unsafe int DetermineMaxStackSize(uint itemId)
|
||||
{
|
||||
InventoryManager* ptr = InventoryManager.Instance();
|
||||
if (ptr == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
int num = 0;
|
||||
for (InventoryType inventoryType = InventoryType.Inventory1; inventoryType <= InventoryType.Inventory4; inventoryType++)
|
||||
{
|
||||
InventoryContainer* inventoryContainer = ptr->GetInventoryContainer(inventoryType);
|
||||
for (int i = 0; i < inventoryContainer->Size; i++)
|
||||
{
|
||||
InventoryItem* inventorySlot = inventoryContainer->GetInventorySlot(i);
|
||||
if (inventorySlot == null || inventorySlot->ItemId == 0)
|
||||
{
|
||||
return 99;
|
||||
}
|
||||
if (inventorySlot->ItemId == itemId)
|
||||
{
|
||||
num += 999 - inventorySlot->Quantity;
|
||||
if (num >= 99)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return Math.Min(99, num);
|
||||
}
|
||||
|
||||
public unsafe int CountInventorySlotsWithCondition(uint itemId, Predicate<int> predicate)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(predicate, "predicate");
|
||||
InventoryManager* ptr = InventoryManager.Instance();
|
||||
if (ptr == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
int num = 0;
|
||||
for (InventoryType inventoryType = InventoryType.Inventory1; inventoryType <= InventoryType.Inventory4; inventoryType++)
|
||||
{
|
||||
InventoryContainer* inventoryContainer = ptr->GetInventoryContainer(inventoryType);
|
||||
for (int i = 0; i < inventoryContainer->Size; i++)
|
||||
{
|
||||
InventoryItem* inventorySlot = inventoryContainer->GetInventorySlot(i);
|
||||
if (inventorySlot != null && inventorySlot->ItemId != 0 && inventorySlot->ItemId == itemId && predicate(inventorySlot->Quantity))
|
||||
{
|
||||
num++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return num;
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue