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-19 16:02:32 +00:00
using ColdMint.scripts.map.events ;
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
{
2024-06-14 04:44:31 +00:00
private readonly List < ItemSlotNode > ? _itemSlotNodes = [ ] ;
2024-06-12 13:33:29 +00:00
2024-06-21 11:16:40 +00:00
private readonly PackedScene ? _itemSlotPackedScene = GD . Load < PackedScene > ( "res://prefab/ui/ItemSlot.tscn" ) ;
2024-06-12 13:33:29 +00:00
/// <summary>
/// <para>UnknownIndex</para>
/// <para>未知位置</para>
/// </summary>
private const int UnknownIndex = - 1 ;
//_selectIndex默认为0.
private int _selectIndex ;
2024-06-21 11:16:40 +00:00
[MustDisposeResource]
public IEnumerator < ItemSlotNode > GetEnumerator ( )
{
return _itemSlotNodes ? . GetEnumerator ( ) ? ? Enumerable . Empty < ItemSlotNode > ( ) . GetEnumerator ( ) ;
}
2024-06-19 14:33:00 +00:00
2024-06-21 11:16:40 +00:00
[MustDisposeResource]
IEnumerator IEnumerable . GetEnumerator ( )
{
return GetEnumerator ( ) ;
}
2024-06-19 14:33:00 +00:00
2024-06-19 16:02:32 +00:00
public Action < SelectedItemSlotChangeEvent > ? SelectedItemSlotChangeEvent { get ; set ; }
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-21 11:16:40 +00:00
public bool SupportSelect { get ; set ; }
2024-06-12 13:33:29 +00:00
public int GetSelectIndex ( )
{
return _selectIndex ;
}
public ItemSlotNode ? GetSelectItemSlotNode ( )
{
2024-06-21 11:16:40 +00:00
if ( _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-21 11:16:40 +00:00
public int RemoveItemFromItemSlotBySelectIndex ( int number ) = > 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 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 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 ;
}
2024-06-21 11:16:40 +00:00
public ItemSlotNode ? Match ( IItem item )
{
//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 ) ) ;
}
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
}
2024-06-24 14:19:12 +00:00
var itemSlotNode = NodeUtils . InstantiatePackedScene < ItemSlotNode > ( _itemSlotPackedScene ) ;
2024-06-12 13:33:29 +00:00
if ( itemSlotNode = = null )
{
2024-06-17 14:12:51 +00:00
return null ;
2024-06-12 13:33:29 +00:00
}
2024-06-24 14:19:12 +00:00
NodeUtils . CallDeferredAddChild ( rootNode , itemSlotNode ) ;
2024-06-21 14:55:31 +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-17 14:12:51 +00:00
return itemSlotNode ;
2024-06-12 13:33:29 +00:00
}
public void SelectTheNextItemSlot ( )
{
2024-06-21 11:16:40 +00:00
if ( _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-21 11:16:40 +00:00
if ( _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 ) ;
}
2024-06-21 14:55:31 +00:00
2024-06-12 13:33:29 +00:00
/// <summary>
/// <para>Select an item slot</para>
/// <para>选中某个物品槽</para>
/// </summary>
private void PrivateSelectItemSlot ( int oldSelectIndex , int newSelectIndex )
{
2024-06-19 16:02:32 +00:00
if ( ! SupportSelect | | _itemSlotNodes = = null | | oldSelectIndex = = newSelectIndex )
2024-06-12 13:33:29 +00:00
{
return ;
}
2024-06-19 16:02:32 +00:00
var oldItemSlotNode = _itemSlotNodes [ oldSelectIndex ] ;
oldItemSlotNode . IsSelect = false ;
var newItemSlotNode = _itemSlotNodes [ newSelectIndex ] ;
newItemSlotNode . IsSelect = true ;
2024-06-18 15:37:18 +00:00
HideItem ( oldSelectIndex ) ;
DisplayItem ( newSelectIndex ) ;
2024-06-19 16:02:32 +00:00
SelectedItemSlotChangeEvent ? . Invoke ( new SelectedItemSlotChangeEvent
{
NewItemSlotNode = newItemSlotNode ,
OldItemSlotNode = oldItemSlotNode
} ) ;
2024-06-18 15:37:18 +00:00
_selectIndex = newSelectIndex ;
}
2024-06-21 14:55:31 +00:00
2024-06-18 15:37:18 +00:00
/// <summary>
/// <para>HideItem</para>
/// <para>隐藏某个物品</para>
/// </summary>
/// <param name="index"></param>
private void HideItem ( int index )
{
2024-06-21 11:16:40 +00:00
var oldItem = _itemSlotNodes ? [ index ] . GetItem ( ) ;
2024-06-19 16:02:32 +00:00
if ( oldItem is not Node2D oldNode2D ) return ;
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 )
{
2024-06-21 11:16:40 +00:00
var item = _itemSlotNodes ? [ index ] . GetItem ( ) ;
2024-06-19 16:02:32 +00:00
if ( item is not Node2D newNode2D ) return ;
newNode2D . ProcessMode = Node . ProcessModeEnum . Inherit ;
newNode2D . Show ( ) ;
2024-06-12 13:33:29 +00:00
}
2024-06-13 02:43:54 +00:00
2024-06-21 11:16:40 +00:00
public void SelectItemSlot ( int newSelectIndex )
2024-06-13 02:43:54 +00:00
{
2024-06-21 11:16:40 +00:00
if ( newSelectIndex = = _selectIndex )
{
return ;
}
2024-06-13 02:43:54 +00:00
2024-06-21 11:16:40 +00:00
var safeIndex = GetSafeIndex ( newSelectIndex ) ;
if ( safeIndex = = UnknownIndex )
{
return ;
}
PrivateSelectItemSlot ( _selectIndex , newSelectIndex ) ;
2024-06-13 02:43:54 +00:00
}
2024-06-12 13:33:29 +00:00
}