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 ;
2024-06-19 16:02:32 +00:00
using ColdMint.scripts.map.events ;
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>
2024-09-22 08:51:42 +00:00
public class UniversalItemContainer ( int totalCapacity ) : IItemContainer
2024-06-12 13:33:29 +00:00
{
2024-09-22 08:51:42 +00:00
private readonly List < IItem > _itemList = [ ] ;
2024-06-12 13:33:29 +00:00
/// <summary>
/// <para>UnknownIndex</para>
/// <para>未知位置</para>
/// </summary>
private const int UnknownIndex = - 1 ;
2024-09-22 08:51:42 +00:00
//_selectIndex defaults to 0.
2024-06-12 13:33:29 +00:00
//_selectIndex默认为0.
private int _selectIndex ;
2024-06-21 11:16:40 +00:00
[MustDisposeResource]
2024-09-22 08:51:42 +00:00
public IEnumerator < IItem > GetEnumerator ( )
2024-06-21 11:16:40 +00:00
{
2024-09-22 08:51:42 +00:00
return _itemList . GetEnumerator ( ) ;
2024-06-21 11:16:40 +00:00
}
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-09-22 08:51:42 +00:00
public Action < SelectedItemChangeEvent > ? SelectedItemChangeEvent { get ; set ; }
2024-09-23 13:03:39 +00:00
public Action < ItemDataChangeEvent > ? ItemDataChangeEvent { get ; set ; }
2024-06-19 16:02:32 +00:00
2024-06-12 19:07:55 +00:00
public bool CanAddItem ( IItem item )
2024-06-12 13:33:29 +00:00
{
2024-09-22 08:51:42 +00:00
//If the capacity is not full, directly return to add items
//如果未占满容量,直接返回可添加物品
2024-09-23 15:17:57 +00:00
if ( GetUsedCapacity ( ) < totalCapacity )
2024-09-22 08:51:42 +00:00
{
return true ;
}
2024-06-12 13:33:29 +00:00
2024-09-22 08:51:42 +00:00
if ( item . MaxQuantity = = 1 )
2024-06-12 13:33:29 +00:00
{
2024-09-22 08:51:42 +00:00
//New items do not support overlay, capacity is full, return cannot add.
//新物品不支持叠加,容量已满,返回不能添加。
2024-06-12 13:33:29 +00:00
return false ;
}
2024-09-22 08:51:42 +00:00
//If the capacity is full, we calculate whether we can spread the new items evenly among the existing items.
//如果容量占满了,我们计算是否能将新物品均摊在已有的物品内。
var unallocatedQuantity = item . Quantity ;
foreach ( var unitItem in _itemList )
{
var number = unitItem . MergeableItemCount ( item , unallocatedQuantity ) ;
if ( number = = 0 )
{
continue ;
}
unallocatedQuantity - = number ;
if ( unallocatedQuantity < 1 )
{
return true ;
}
}
2024-06-12 13:33:29 +00:00
2024-09-22 08:51:42 +00:00
return unallocatedQuantity < 1 ;
2024-06-12 13:33:29 +00:00
}
2024-09-23 15:17:57 +00:00
private void UpdateSelectStatus ( int index , IItem item )
{
item . IsSelect = index = = _selectIndex ;
}
2024-09-23 13:03:39 +00:00
2024-09-22 08:51:42 +00:00
public int AddItem ( IItem item )
2024-06-12 13:33:29 +00:00
{
2024-09-22 08:51:42 +00:00
if ( item . MaxQuantity = = 1 )
2024-06-12 13:33:29 +00:00
{
2024-09-23 15:17:57 +00:00
if ( GetUsedCapacity ( ) > = totalCapacity )
2024-09-22 08:51:42 +00:00
{
//Items cannot be stacked and cannot be added if the capacity is full.
//物品不能叠加,且容量已满,则无法添加。
return 0 ;
}
_itemList . Add ( item ) ;
2024-09-23 15:17:57 +00:00
UpdateSelectStatus ( _itemList . Count - 1 , item ) ;
2024-09-23 13:03:39 +00:00
ItemDataChangeEvent ? . Invoke ( new ItemDataChangeEvent
{
NewItem = item ,
NewIndex = _itemList . Count - 1 ,
Type = Config . ItemDataChangeEventType . QuantityAdded
} ) ;
2024-09-22 08:51:42 +00:00
return item . Quantity ;
2024-06-12 13:33:29 +00:00
}
2024-09-22 08:51:42 +00:00
//There can be more than one item, try to share equally.
//物品可有多个,尝试均摊。
var originalQuantity = item . Quantity ;
2024-09-23 13:03:39 +00:00
var index = 0 ;
2024-09-22 08:51:42 +00:00
foreach ( var unitItem in _itemList )
2024-06-12 13:33:29 +00:00
{
2024-09-22 08:51:42 +00:00
var number = unitItem . MergeableItemCount ( item , item . Quantity ) ;
if ( number = = 0 )
{
continue ;
}
item . Quantity - = number ;
unitItem . Quantity + = number ;
2024-09-23 13:03:39 +00:00
ItemDataChangeEvent ? . Invoke ( new ItemDataChangeEvent
{
NewItem = unitItem ,
NewIndex = index ,
Type = Config . ItemDataChangeEventType . QuantityAdded
} ) ;
2024-09-22 08:51:42 +00:00
if ( item . Quantity < 1 )
{
//New items are fully shared.
//新物品完全被均摊。
return originalQuantity ;
}
2024-06-12 13:33:29 +00:00
2024-09-23 13:03:39 +00:00
index + + ;
2024-09-22 08:51:42 +00:00
}
2024-06-12 13:33:29 +00:00
2024-09-22 08:51:42 +00:00
//New items have some left over.
//新物品有一些剩余。
2024-09-23 15:17:57 +00:00
if ( GetUsedCapacity ( ) > = totalCapacity )
2024-06-12 13:33:29 +00:00
{
2024-09-22 08:51:42 +00:00
//The capacity is full. The remaining capacity cannot be stored.
//容量已满,无法存放剩余。
return originalQuantity - item . Quantity ;
2024-06-12 13:33:29 +00:00
}
2024-09-22 08:51:42 +00:00
//Add the rest to the container.
//添加剩余到容器内。
_itemList . Add ( item ) ;
2024-09-23 15:17:57 +00:00
UpdateSelectStatus ( _itemList . Count - 1 , item ) ;
2024-09-23 13:03:39 +00:00
ItemDataChangeEvent ? . Invoke ( new ItemDataChangeEvent
{
NewItem = item ,
NewIndex = _itemList . Count - 1 ,
Type = Config . ItemDataChangeEventType . Add
} ) ;
2024-09-22 08:51:42 +00:00
return originalQuantity ;
2024-06-12 13:33:29 +00:00
}
2024-09-22 08:51:42 +00:00
public bool SupportSelect { get ; set ; }
2024-09-23 15:17:57 +00:00
public bool EnablePlaceholder { get ; set ; }
public IItem ? GetPlaceHolderItem ( )
{
return EnablePlaceholder ? new PlaceholderItem ( ) : null ;
}
2024-09-22 08:51:42 +00:00
public int GetSelectIndex ( )
2024-06-12 13:33:29 +00:00
{
2024-09-22 08:51:42 +00:00
return _selectIndex ;
}
2024-06-12 13:33:29 +00:00
2024-09-22 08:51:42 +00:00
public IItem ? GetSelectItem ( )
{
2024-09-25 13:56:54 +00:00
var count = _itemList . Count ;
if ( count = = 0 )
2024-09-23 15:17:57 +00:00
{
return null ;
}
2024-09-25 13:56:54 +00:00
return _selectIndex < count ? _itemList [ _selectIndex ] : null ;
2024-06-12 13:33:29 +00:00
}
2024-09-22 08:51:42 +00:00
public IItem ? GetItem ( int index )
2024-06-12 17:18:55 +00:00
{
2024-09-25 13:56:54 +00:00
return GetValidIndex ( index ) = = UnknownIndex ? null : _itemList [ index ] ;
}
/// <summary>
/// <para>Get valid index</para>
/// <para>获取有效的索引</para>
/// </summary>
/// <param name="index"></param>
/// <returns>
///<para>Return -1 if the given index exceeds the valid range of the list, otherwise return the given index itself.</para>
///<para>如果给定的索引超过了列表的有效范围,那么返回-1,否则返回给定的索引本身。</para>
/// </returns>
private int GetValidIndex ( int index )
{
var count = _itemList . Count ;
if ( count = = 0 )
2024-06-12 13:33:29 +00:00
{
2024-09-25 13:56:54 +00:00
return UnknownIndex ;
2024-06-12 13:33:29 +00:00
}
2024-09-25 13:56:54 +00:00
if ( index > = count | | index < 0 )
{
return UnknownIndex ;
}
return index ;
2024-06-12 17:18:55 +00:00
}
2024-06-12 13:33:29 +00:00
/// <summary>
2024-09-25 13:56:54 +00:00
/// <para>Gets a normalized subscript index</para>
/// <para>获取规范化的下标索引</para>
2024-06-12 13:33:29 +00:00
/// </summary>
2024-09-22 08:51:42 +00:00
/// <param name="index"></param>
2024-06-12 13:33:29 +00:00
/// <returns>
2024-09-25 13:56:54 +00:00
/// <para>The difference between this method and <see cref="GetValidIndex"/> is that if the given index is out of range, the result will be returned after rounding.</para>
/// <para>失败返回-1, 成功返回不会导致下标越界的索引, 此方法和<see cref="GetValidIndex"/>区别是,如果给定的索引超出了范围,那么会将结果取余后返回。</para>
2024-06-12 13:33:29 +00:00
/// </returns>
2024-09-25 13:56:54 +00:00
private int GetNormalizeIndex ( int index )
2024-06-12 13:33:29 +00:00
{
2024-09-22 08:51:42 +00:00
var count = _itemList . Count ;
2024-09-25 13:56:54 +00:00
if ( count = = 0 | | index < 0 )
2024-06-12 13:33:29 +00:00
{
//Prevents the dividend from being 0
//防止被除数为0
return UnknownIndex ;
}
2024-09-22 08:51:42 +00:00
return index % count ;
2024-06-12 13:33:29 +00:00
}
2024-09-22 08:51:42 +00:00
public int RemoveSelectItem ( int number )
2024-06-21 11:16:40 +00:00
{
2024-09-22 08:51:42 +00:00
return RemoveItem ( _selectIndex , number ) ;
2024-06-21 11:16:40 +00:00
}
2024-09-22 08:51:42 +00:00
public int RemoveItem ( int itemIndex , int number )
2024-06-12 13:33:29 +00:00
{
2024-09-22 08:51:42 +00:00
if ( number = = 0 )
2024-06-12 13:33:29 +00:00
{
2024-09-22 08:51:42 +00:00
return 0 ;
2024-06-12 13:33:29 +00:00
}
2024-09-25 13:56:54 +00:00
var index = GetValidIndex ( itemIndex ) ;
if ( index = = UnknownIndex )
2024-06-12 13:33:29 +00:00
{
2024-09-22 08:51:42 +00:00
return 0 ;
2024-06-12 13:33:29 +00:00
}
2024-09-22 08:51:42 +00:00
2024-09-25 13:56:54 +00:00
var item = _itemList [ index ] ;
2024-09-22 08:51:42 +00:00
var originalQuantity = item . Quantity ;
if ( number < 0 )
2024-06-21 14:55:31 +00:00
{
2024-09-22 08:51:42 +00:00
//If the number entered is less than 0, all items are removed.
//输入的数量小于0,则移除全部物品。
item . Quantity = 0 ;
2024-09-25 13:56:54 +00:00
_itemList . RemoveAt ( index ) ;
2024-09-22 08:51:42 +00:00
return originalQuantity ;
2024-06-21 14:55:31 +00:00
}
2024-09-22 08:51:42 +00:00
var removed = Math . Min ( number , item . Quantity ) ;
item . Quantity - = removed ;
if ( item . Quantity < 1 )
2024-06-21 14:55:31 +00:00
{
2024-09-25 13:56:54 +00:00
_itemList . RemoveAt ( index ) ;
2024-06-21 14:55:31 +00:00
}
2024-09-22 08:51:42 +00:00
return removed ;
2024-06-12 13:33:29 +00:00
}
2024-09-22 08:51:42 +00:00
public int GetUsedCapacity ( )
2024-06-12 13:33:29 +00:00
{
2024-09-22 08:51:42 +00:00
return _itemList . Count ;
}
public int GetTotalCapacity ( )
{
return totalCapacity ;
}
2024-06-12 13:33:29 +00:00
2024-09-22 08:51:42 +00:00
public void SelectNextItem ( )
{
2024-09-23 15:17:57 +00:00
var count = EnablePlaceholder ? totalCapacity : _itemList . Count ;
2024-06-12 13:33:29 +00:00
if ( count = = 0 )
{
return ;
}
var oldSelectIndex = _selectIndex ;
var newSelectIndex = _selectIndex + 1 ;
if ( newSelectIndex > = count )
{
2024-09-23 15:17:57 +00:00
newSelectIndex = 0 ;
2024-06-12 13:33:29 +00:00
}
2024-09-22 08:51:42 +00:00
PrivateSelectItem ( oldSelectIndex , newSelectIndex ) ;
2024-06-12 13:33:29 +00:00
}
2024-09-22 08:51:42 +00:00
public void SelectPreviousItem ( )
2024-06-12 13:33:29 +00:00
{
2024-09-23 15:17:57 +00:00
var count = EnablePlaceholder ? totalCapacity : _itemList . Count ;
2024-06-12 13:33:29 +00:00
if ( count = = 0 )
{
return ;
}
var oldSelectIndex = _selectIndex ;
var newSelectIndex = _selectIndex - 1 ;
if ( newSelectIndex < 0 )
{
newSelectIndex = count - 1 ;
}
2024-09-22 08:51:42 +00:00
PrivateSelectItem ( oldSelectIndex , newSelectIndex ) ;
2024-06-12 13:33:29 +00:00
}
2024-06-21 14:55:31 +00:00
2024-06-12 13:33:29 +00:00
/// <summary>
2024-09-22 08:51:42 +00:00
/// <para>Private methods for selecting items</para>
/// <para>选择物品的私有方法</para>
2024-06-12 13:33:29 +00:00
/// </summary>
2024-09-22 08:51:42 +00:00
/// <param name="oldIndex"></param>
/// <param name="newIndex"></param>
private void PrivateSelectItem ( int oldIndex , int newIndex )
2024-06-12 13:33:29 +00:00
{
2024-09-22 08:51:42 +00:00
if ( ! SupportSelect | | oldIndex = = newIndex )
2024-06-12 13:33:29 +00:00
{
return ;
}
2024-09-23 15:17:57 +00:00
//There is no need to broadcast placeholders when an event is invoked.
//在调用事件时,无需广播占位符。
var oldItem = GetItem ( oldIndex ) ;
if ( oldItem ! = null )
{
oldItem . IsSelect = false ;
}
//There is no need to broadcast placeholders when an event is invoked.
//在调用事件时,无需广播占位符。
var newItem = GetItem ( newIndex ) ;
if ( newItem ! = null )
{
newItem . IsSelect = true ;
}
_selectIndex = newIndex ;
2024-09-22 08:51:42 +00:00
SelectedItemChangeEvent ? . Invoke ( new SelectedItemChangeEvent
2024-06-19 16:02:32 +00:00
{
2024-09-22 15:13:59 +00:00
NewIndex = newIndex ,
OldIndex = oldIndex ,
2024-09-22 08:51:42 +00:00
NewItem = newItem ,
OldItem = oldItem
2024-06-19 16:02:32 +00:00
} ) ;
2024-06-18 15:37:18 +00:00
}
2024-06-21 14:55:31 +00:00
2024-06-13 02:43:54 +00:00
2024-09-22 08:51:42 +00:00
public void SelectItem ( int index )
2024-06-13 02:43:54 +00:00
{
2024-09-23 15:17:57 +00:00
if ( EnablePlaceholder )
2024-06-21 11:16:40 +00:00
{
2024-09-23 15:17:57 +00:00
if ( totalCapacity = = 0 )
{
return ;
}
PrivateSelectItem ( _selectIndex , index % totalCapacity ) ;
2024-06-21 11:16:40 +00:00
}
2024-09-23 15:17:57 +00:00
else
{
2024-09-25 13:56:54 +00:00
var safeIndex = GetNormalizeIndex ( index ) ;
2024-09-23 15:17:57 +00:00
if ( safeIndex = = UnknownIndex )
{
return ;
}
2024-06-21 11:16:40 +00:00
2024-09-23 15:17:57 +00:00
PrivateSelectItem ( _selectIndex , safeIndex ) ;
}
2024-06-13 02:43:54 +00:00
}
2024-06-12 13:33:29 +00:00
}