using System; using System.Collections; using System.Collections.Generic; using ColdMint.scripts.map.events; using JetBrains.Annotations; namespace ColdMint.scripts.inventory; /// /// UniversalItemContainer /// 通用的物品容器 /// public class UniversalItemContainer(int totalCapacity) : IItemContainer { private readonly List _itemList = []; /// /// UnknownIndex /// 未知位置 /// private const int UnknownIndex = -1; //_selectIndex defaults to 0. //_selectIndex默认为0. private int _selectIndex; [MustDisposeResource] public IEnumerator GetEnumerator() { return _itemList.GetEnumerator(); } [MustDisposeResource] IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } public Action? SelectedItemChangeEvent { get; set; } public Action? ItemDataChangeEvent { get; set; } public bool CanAddItem(IItem item) { //If the capacity is not full, directly return to add items //如果未占满容量,直接返回可添加物品 if (GetUsedCapacity() < totalCapacity) { return true; } if (item.MaxQuantity == 1) { //New items do not support overlay, capacity is full, return cannot add. //新物品不支持叠加,容量已满,返回不能添加。 return false; } //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; } } return unallocatedQuantity < 1; } private void UpdateSelectStatus(int index, IItem item) { item.IsSelect = index == _selectIndex; } public int AddItem(IItem item) { if (item.MaxQuantity == 1) { if (GetUsedCapacity() >= totalCapacity) { //Items cannot be stacked and cannot be added if the capacity is full. //物品不能叠加,且容量已满,则无法添加。 return 0; } _itemList.Add(item); UpdateSelectStatus(_itemList.Count - 1, item); ItemDataChangeEvent?.Invoke(new ItemDataChangeEvent { NewItem = item, NewIndex = _itemList.Count - 1, Type = Config.ItemDataChangeEventType.QuantityAdded }); return item.Quantity; } //There can be more than one item, try to share equally. //物品可有多个,尝试均摊。 var originalQuantity = item.Quantity; var index = 0; foreach (var unitItem in _itemList) { var number = unitItem.MergeableItemCount(item, item.Quantity); if (number == 0) { continue; } item.Quantity -= number; unitItem.Quantity += number; ItemDataChangeEvent?.Invoke(new ItemDataChangeEvent { NewItem = unitItem, NewIndex = index, Type = Config.ItemDataChangeEventType.QuantityAdded }); if (item.Quantity < 1) { //New items are fully shared. //新物品完全被均摊。 return originalQuantity; } index++; } //New items have some left over. //新物品有一些剩余。 if (GetUsedCapacity() >= totalCapacity) { //The capacity is full. The remaining capacity cannot be stored. //容量已满,无法存放剩余。 return originalQuantity - item.Quantity; } //Add the rest to the container. //添加剩余到容器内。 _itemList.Add(item); UpdateSelectStatus(_itemList.Count - 1, item); ItemDataChangeEvent?.Invoke(new ItemDataChangeEvent { NewItem = item, NewIndex = _itemList.Count - 1, Type = Config.ItemDataChangeEventType.Add }); return originalQuantity; } public bool SupportSelect { get; set; } public bool EnablePlaceholder { get; set; } public IItem? GetPlaceHolderItem() { return EnablePlaceholder ? new PlaceholderItem() : null; } public int GetSelectIndex() { return _selectIndex; } public IItem? GetSelectItem() { var count = _itemList.Count; if (count == 0) { return null; } return _selectIndex < count ? _itemList[_selectIndex] : null; } public IItem? GetItem(int index) { return GetValidIndex(index) == UnknownIndex ? null : _itemList[index]; } /// /// Get valid index /// 获取有效的索引 /// /// /// ///Return -1 if the given index exceeds the valid range of the list, otherwise return the given index itself. ///如果给定的索引超过了列表的有效范围,那么返回-1,否则返回给定的索引本身。 /// private int GetValidIndex(int index) { var count = _itemList.Count; if (count == 0) { return UnknownIndex; } if (index >= count || index < 0) { return UnknownIndex; } return index; } /// /// Gets a normalized subscript index /// 获取规范化的下标索引 /// /// /// /// The difference between this method and is that if the given index is out of range, the result will be returned after rounding. /// 失败返回-1,成功返回不会导致下标越界的索引,此方法和区别是,如果给定的索引超出了范围,那么会将结果取余后返回。 /// private int GetNormalizeIndex(int index) { var count = _itemList.Count; if (count == 0 || index < 0) { //Prevents the dividend from being 0 //防止被除数为0 return UnknownIndex; } return index % count; } public int RemoveSelectItem(int number) { return RemoveItem(_selectIndex, number); } public int RemoveItem(int itemIndex, int number) { if (number == 0) { return 0; } var index = GetValidIndex(itemIndex); if (index == UnknownIndex) { return 0; } var item = _itemList[index]; var originalQuantity = item.Quantity; if (number < 0) { //If the number entered is less than 0, all items are removed. //输入的数量小于0,则移除全部物品。 item.Quantity = 0; _itemList.RemoveAt(index); return originalQuantity; } var removed = Math.Min(number, item.Quantity); item.Quantity -= removed; if (item.Quantity < 1) { _itemList.RemoveAt(index); } return removed; } public int GetUsedCapacity() { return _itemList.Count; } public int GetTotalCapacity() { return totalCapacity; } public void SelectNextItem() { var count = EnablePlaceholder ? totalCapacity : _itemList.Count; if (count == 0) { return; } var oldSelectIndex = _selectIndex; var newSelectIndex = _selectIndex + 1; if (newSelectIndex >= count) { newSelectIndex = 0; } PrivateSelectItem(oldSelectIndex, newSelectIndex); } public void SelectPreviousItem() { var count = EnablePlaceholder ? totalCapacity : _itemList.Count; if (count == 0) { return; } var oldSelectIndex = _selectIndex; var newSelectIndex = _selectIndex - 1; if (newSelectIndex < 0) { newSelectIndex = count - 1; } PrivateSelectItem(oldSelectIndex, newSelectIndex); } /// /// Private methods for selecting items /// 选择物品的私有方法 /// /// /// private void PrivateSelectItem(int oldIndex, int newIndex) { if (!SupportSelect || oldIndex == newIndex) { return; } //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; SelectedItemChangeEvent?.Invoke(new SelectedItemChangeEvent { NewIndex = newIndex, OldIndex = oldIndex, NewItem = newItem, OldItem = oldItem }); } public void SelectItem(int index) { if (EnablePlaceholder) { if (totalCapacity == 0) { return; } PrivateSelectItem(_selectIndex, index % totalCapacity); } else { var safeIndex = GetNormalizeIndex(index); if (safeIndex == UnknownIndex) { return; } PrivateSelectItem(_selectIndex, safeIndex); } } }