2024-06-12 17:18:55 +00:00
using System ;
2024-06-13 02:43:54 +00:00
using System.Collections ;
2024-06-12 17:18:55 +00:00
using System.Collections.Generic ;
using System.Linq ;
2024-06-12 13:33:29 +00:00
using ColdMint.scripts.character ;
2024-06-12 17:18:55 +00:00
using ColdMint.scripts.item ;
2024-06-13 05:53:10 +00:00
using ColdMint.scripts.item.itemStacks ;
2024-06-12 13:33:29 +00:00
using ColdMint.scripts.utils ;
using Godot ;
2024-06-13 02:43:54 +00:00
using JetBrains.Annotations ;
2024-06-12 13:33:29 +00:00
namespace ColdMint.scripts.inventory ;
/// <summary>
/// <para>UniversalItemContainer</para>
/// <para>通用的物品容器</para>
/// </summary>
public class UniversalItemContainer : IItemContainer
{
private readonly PackedScene ? _itemSlotPackedScene = GD . Load < PackedScene > ( "res://prefab/ui/ItemSlot.tscn" ) ;
2024-06-14 04:44:31 +00:00
private readonly List < ItemSlotNode > ? _itemSlotNodes = [ ] ;
2024-06-12 13:33:29 +00:00
/// <summary>
/// <para>Character</para>
/// <para>角色</para>
/// </summary>
public CharacterTemplate ? CharacterTemplate { get ; set ; }
/// <summary>
/// <para>UnknownIndex</para>
/// <para>未知位置</para>
/// </summary>
private const int UnknownIndex = - 1 ;
//_selectIndex默认为0.
private int _selectIndex ;
2024-06-19 14:33:00 +00:00
public bool SupportSelect { get ; set ; } = true ;
2024-06-12 19:07:55 +00:00
public bool CanAddItem ( IItem item )
2024-06-12 13:33:29 +00:00
{
2024-06-12 17:18:55 +00:00
return Match ( item ) ! = null ;
2024-06-12 13:33:29 +00:00
}
2024-06-12 19:07:55 +00:00
public bool AddItem ( IItem item )
2024-06-12 13:33:29 +00:00
{
2024-06-12 17:18:55 +00:00
var itemSlotNode = Match ( item ) ;
2024-06-12 13:33:29 +00:00
if ( itemSlotNode = = null )
{
return false ;
}
2024-06-12 17:18:55 +00:00
return itemSlotNode . AddItem ( item ) ;
}
2024-06-14 04:22:44 +00:00
public int CanAddItemStack ( IItemStack itemStack )
{
var testItem = itemStack . GetItem ( ) ;
if ( testItem is null ) return 0 ;
var slots = MatchAll ( slot = > slot . CanAddItem ( testItem ) ) ;
return
Math . Min ( itemStack . Quantity ,
2024-06-17 14:12:51 +00:00
slots . Select ( slot = > slot . CanAddItemStack ( itemStack ) ) . Sum ( ) ) ;
2024-06-14 04:22:44 +00:00
}
2024-06-12 17:18:55 +00:00
public bool AddItemStack ( IItemStack itemStack )
{
2024-06-16 09:22:43 +00:00
ItemSlotNode ? itemSlotNode = Match ( itemStack ) ;
while ( itemSlotNode is not null )
2024-06-12 17:18:55 +00:00
{
if ( itemSlotNode . AddItemStack ( itemStack ) )
return true ;
2024-06-17 14:12:51 +00:00
2024-06-16 09:22:43 +00:00
itemSlotNode = Match ( itemStack ) ;
2024-06-12 17:18:55 +00:00
}
2024-06-16 09:22:43 +00:00
return false ;
2024-06-12 13:33:29 +00:00
}
public int GetSelectIndex ( )
{
2024-06-19 14:33:00 +00:00
if ( ! SupportSelect )
{
return 0 ;
}
2024-06-12 13:33:29 +00:00
return _selectIndex ;
}
public ItemSlotNode ? GetSelectItemSlotNode ( )
{
2024-06-19 14:33:00 +00:00
if ( ! SupportSelect | | _itemSlotNodes = = null | | _itemSlotNodes . Count = = 0 )
2024-06-12 13:33:29 +00:00
{
return null ;
}
if ( _selectIndex < _itemSlotNodes . Count )
{
//Prevent subscripts from going out of bounds.
//防止下标越界。
return _itemSlotNodes [ _selectIndex ] ;
}
return null ;
}
2024-06-19 14:33:00 +00:00
public IItem ? PickItemFromItemSlotBySelectIndex ( )
{
if ( ! SupportSelect )
{
return null ;
}
return PickItemFromItemSlot ( _selectIndex ) ;
}
2024-06-12 17:18:55 +00:00
2024-06-19 14:33:00 +00:00
public IItemStack ? PickItemsFromItemSlotBySelectIndex ( int value )
{
if ( ! SupportSelect )
{
return null ;
}
2024-06-12 17:18:55 +00:00
2024-06-19 14:33:00 +00:00
return PickItemsFromItemSlot ( _selectIndex , value ) ;
}
public int RemoveItemFromItemSlotBySelectIndex ( int number )
{
if ( ! SupportSelect )
{
return 0 ;
}
return RemoveItemFromItemSlot ( _selectIndex , number ) ;
}
2024-06-12 13:33:29 +00:00
public int GetItemSlotCount ( )
{
if ( _itemSlotNodes = = null )
{
return 0 ;
}
return _itemSlotNodes . Count ;
}
public ItemSlotNode ? GetItemSlotNode ( int index )
{
if ( _itemSlotNodes = = null )
{
return null ;
}
var safeIndex = GetSafeIndex ( index ) ;
return _itemSlotNodes [ safeIndex ] ;
}
2024-06-12 19:07:55 +00:00
public IItem ? PickItemFromItemSlot ( int itemSlotIndex )
2024-06-12 13:33:29 +00:00
{
2024-06-12 17:18:55 +00:00
if ( _itemSlotNodes = = null ) return null ;
2024-06-12 13:33:29 +00:00
var safeIndex = GetSafeIndex ( itemSlotIndex ) ;
if ( safeIndex = = UnknownIndex )
{
2024-06-12 17:18:55 +00:00
return null ;
2024-06-12 13:33:29 +00:00
}
var itemSlot = _itemSlotNodes [ safeIndex ] ;
2024-06-12 17:18:55 +00:00
return itemSlot . PickItem ( ) ;
2024-06-12 13:33:29 +00:00
}
2024-06-12 17:18:55 +00:00
public IItemStack ? PickItemsFromItemSlot ( int itemSlotIndex , int value )
2024-06-12 13:33:29 +00:00
{
2024-06-12 17:18:55 +00:00
if ( _itemSlotNodes = = null ) return null ;
var safeIndex = GetSafeIndex ( itemSlotIndex ) ;
if ( safeIndex = = UnknownIndex )
2024-06-12 13:33:29 +00:00
{
return null ;
}
2024-06-12 17:18:55 +00:00
var itemSlot = _itemSlotNodes [ safeIndex ] ;
return itemSlot . PickItems ( value ) ;
}
2024-06-12 13:33:29 +00:00
2024-06-12 17:18:55 +00:00
public int RemoveItemFromItemSlot ( int itemSlotIndex , int number )
{
if ( _itemSlotNodes = = null ) return number ;
var safeIndex = GetSafeIndex ( itemSlotIndex ) ;
if ( safeIndex = = UnknownIndex )
2024-06-12 13:33:29 +00:00
{
2024-06-12 17:18:55 +00:00
return number ;
2024-06-12 13:33:29 +00:00
}
2024-06-12 17:18:55 +00:00
var itemSlot = _itemSlotNodes [ safeIndex ] ;
return itemSlot . RemoveItem ( number ) ;
}
2024-06-12 19:07:55 +00:00
public ItemSlotNode ? Match ( IItem item )
2024-06-12 17:18:55 +00:00
{
//Find and return the first slot that can hold this item, if the list is null or not found, return null
//寻找并返回第一个遇到的可放置此物品的物品槽, 若列表为空或不存在, 将返回null
return _itemSlotNodes ? . FirstOrDefault ( itemSlotNode = > itemSlotNode . CanAddItem ( item ) ) ;
}
public ItemSlotNode ? Match ( IItemStack stack )
{
2024-06-16 12:18:44 +00:00
var item = stack . GetItem ( ) ;
return item = = null ? null : _itemSlotNodes ? . FirstOrDefault ( itemSlotNode = > itemSlotNode . CanAddItem ( item ) ) ;
2024-06-12 17:18:55 +00:00
}
2024-06-14 04:22:44 +00:00
public ItemSlotNode ? Match ( Func < ItemSlotNode , bool > predicate )
2024-06-12 17:18:55 +00:00
{
2024-06-14 04:22:44 +00:00
return _itemSlotNodes ? . FirstOrDefault ( predicate ) ;
2024-06-12 17:18:55 +00:00
}
2024-06-14 04:22:44 +00:00
public IEnumerable < ItemSlotNode > MatchAll ( Func < ItemSlotNode , bool > predicate )
2024-06-12 17:18:55 +00:00
{
2024-06-14 04:22:44 +00:00
return from node in _itemSlotNodes where predicate ( node ) select node ;
2024-06-12 13:33:29 +00:00
}
/// <summary>
/// <para>Gets a secure subscript index</para>
/// <para>获取安全的下标索引</para>
/// </summary>
/// <param name="itemSlotIndex"></param>
/// <returns>
2024-06-12 17:18:55 +00:00
/// <para>-1 is returned on failure, and the index that does not result in an out-of-bounds subscript is returned on success</para>
/// <para>失败返回-1, 成功返回不会导致下标越界的索引</para>
2024-06-12 13:33:29 +00:00
/// </returns>
private int GetSafeIndex ( int itemSlotIndex )
{
if ( _itemSlotNodes = = null )
{
return UnknownIndex ;
}
var count = _itemSlotNodes . Count ;
if ( count = = 0 )
{
//Prevents the dividend from being 0
//防止被除数为0
return UnknownIndex ;
}
return itemSlotIndex % count ;
}
/// <summary>
/// <para>Add items tank</para>
/// <para>添加物品槽</para>
/// </summary>
2024-06-17 14:12:51 +00:00
public ItemSlotNode ? AddItemSlot ( Node rootNode )
2024-06-12 13:33:29 +00:00
{
if ( _itemSlotNodes = = null | | _itemSlotPackedScene = = null )
{
2024-06-17 14:12:51 +00:00
return null ;
2024-06-12 13:33:29 +00:00
}
var itemSlotNode = NodeUtils . InstantiatePackedScene < ItemSlotNode > ( _itemSlotPackedScene , rootNode ) ;
if ( itemSlotNode = = null )
{
2024-06-17 14:12:51 +00:00
return null ;
2024-06-12 13:33:29 +00:00
}
2024-06-19 14:33:00 +00:00
if ( SupportSelect )
{
itemSlotNode . IsSelect = ( _itemSlotNodes . Count ) = = _selectIndex ;
}
else
{
itemSlotNode . IsSelect = false ;
}
2024-06-12 13:33:29 +00:00
_itemSlotNodes . Add ( itemSlotNode ) ;
2024-06-18 15:37:18 +00:00
// itemSlotNode.ItemStackChangeEvent += @event =>
// {
// if (_itemSlotNodes == null)
// {
// return;
// }
//
// var index = _itemSlotNodes.IndexOf(itemSlotNode);
// // LogCat.Log("位于" + index + "的堆改变了。" + _selectIndex + "空的吗" + (@event.ItemStack == null));
// if (index == -1)
// {
// return;
// }
//
// if (index == _selectIndex)
// {
// if (@event.ItemStack == null)
// {
// HideItem(index);
// }
// else
// {
// DisplayItem(index);
// }
// }
// };
2024-06-17 14:12:51 +00:00
return itemSlotNode ;
2024-06-12 13:33:29 +00:00
}
public void SelectTheNextItemSlot ( )
{
2024-06-19 14:33:00 +00:00
if ( ! SupportSelect | | _itemSlotNodes = = null )
2024-06-12 13:33:29 +00:00
{
return ;
}
var count = _itemSlotNodes . Count ;
if ( count = = 0 )
{
return ;
}
var oldSelectIndex = _selectIndex ;
var newSelectIndex = _selectIndex + 1 ;
if ( newSelectIndex > = count )
{
newSelectIndex = 0 ;
}
PrivateSelectItemSlot ( oldSelectIndex , newSelectIndex ) ;
}
public void SelectThePreviousItemSlot ( )
{
2024-06-19 14:33:00 +00:00
if ( ! SupportSelect | | _itemSlotNodes = = null )
2024-06-12 13:33:29 +00:00
{
return ;
}
var count = _itemSlotNodes . Count ;
if ( count = = 0 )
{
return ;
}
var oldSelectIndex = _selectIndex ;
var newSelectIndex = _selectIndex - 1 ;
if ( newSelectIndex < 0 )
{
newSelectIndex = count - 1 ;
}
PrivateSelectItemSlot ( oldSelectIndex , newSelectIndex ) ;
}
public void SelectItemSlot ( int newSelectIndex )
{
2024-06-19 14:33:00 +00:00
if ( ! SupportSelect | | newSelectIndex = = _selectIndex )
2024-06-12 13:33:29 +00:00
{
return ;
}
var safeIndex = GetSafeIndex ( newSelectIndex ) ;
if ( safeIndex = = UnknownIndex )
{
return ;
}
PrivateSelectItemSlot ( _selectIndex , newSelectIndex ) ;
}
/// <summary>
/// <para>Select an item slot</para>
/// <para>选中某个物品槽</para>
/// </summary>
private void PrivateSelectItemSlot ( int oldSelectIndex , int newSelectIndex )
{
2024-06-19 14:33:00 +00:00
if ( ! SupportSelect )
{
return ;
}
2024-06-12 13:33:29 +00:00
if ( oldSelectIndex = = newSelectIndex )
{
return ;
}
if ( _itemSlotNodes = = null )
{
return ;
}
_itemSlotNodes [ oldSelectIndex ] . IsSelect = false ;
_itemSlotNodes [ newSelectIndex ] . IsSelect = true ;
2024-06-18 15:37:18 +00:00
HideItem ( oldSelectIndex ) ;
DisplayItem ( newSelectIndex ) ;
_selectIndex = newSelectIndex ;
}
/// <summary>
/// <para>HideItem</para>
/// <para>隐藏某个物品</para>
/// </summary>
/// <param name="index"></param>
private void HideItem ( int index )
{
if ( _itemSlotNodes = = null )
{
return ;
}
var oldItem = _itemSlotNodes [ index ] . GetItemStack ( ) ? . GetItem ( ) ;
2024-06-12 13:33:29 +00:00
if ( oldItem is Node2D oldNode2D )
{
oldNode2D . ProcessMode = Node . ProcessModeEnum . Disabled ;
oldNode2D . Hide ( ) ;
}
2024-06-18 15:37:18 +00:00
}
2024-06-12 13:33:29 +00:00
2024-06-18 15:37:18 +00:00
/// <summary>
/// <para>Displays the items in an item slot</para>
/// <para>显示某个物品槽内的物品</para>
/// </summary>
/// <remarks>
///<para>This method can also be used to refresh items held by the character, for example when a new item is dragged to the current display location, then call this method to refresh items held by the character.</para>
///<para>此方法也可用于刷新角色手上持有的物品,例如当新的物品被拖动到当前显示位置,那么请调用此方法刷新角色持有的物品。</para>
/// </remarks>
/// <param name="index"></param>
private void DisplayItem ( int index )
{
if ( _itemSlotNodes = = null )
{
return ;
}
var item = _itemSlotNodes [ index ] . GetItemStack ( ) ? . GetItem ( ) ;
2024-06-12 13:33:29 +00:00
switch ( item )
{
case null :
{
if ( CharacterTemplate ! = null )
{
CharacterTemplate . CurrentItem = null ;
}
break ;
}
case Node2D node2D :
{
node2D . ProcessMode = Node . ProcessModeEnum . Inherit ;
node2D . Show ( ) ;
if ( CharacterTemplate ! = null )
{
CharacterTemplate . CurrentItem = node2D ;
}
break ;
}
default :
{
if ( CharacterTemplate ! = null )
{
CharacterTemplate . CurrentItem = null ;
}
break ;
}
}
}
2024-06-13 02:43:54 +00:00
[MustDisposeResource]
public IEnumerator < ItemSlotNode > GetEnumerator ( )
{
return _itemSlotNodes ? . GetEnumerator ( ) ? ? Enumerable . Empty < ItemSlotNode > ( ) . GetEnumerator ( ) ;
}
[MustDisposeResource]
IEnumerator IEnumerable . GetEnumerator ( )
{
return GetEnumerator ( ) ;
}
2024-06-12 13:33:29 +00:00
}