using System; using System.Collections.Generic; using ColdMint.scripts.map.events; namespace ColdMint.scripts.inventory; /// /// UniversalItemContainer /// 通用的物品容器 /// public class UniversalItemContainer(int totalCapacity) : IItemContainer { private readonly Dictionary _itemDictionary = []; /// /// UnknownIndex /// 未知位置 /// private const int UnknownIndex = -1; //_selectIndex defaults to 0. //_selectIndex默认为0. private int _selectIndex; /// /// The next available index /// 下个可用的索引 /// /// ///For example, the variable [1,2,3,5,6] represents 4, or the variable [1,2,3,4,5,6,7] represents 8. ///例如[1,2,3,5,6]这个变量表示4,再或者[1,2,3,4,5,6,7]这个变量表示8。 /// private int _nextAvailableIndex; 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 _itemDictionary.Values) { 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; } /// /// Update the next available index location /// 更新下个可用的索引位置 /// private void UpdateNextAvailableIndex() { _nextAvailableIndex = UnknownIndex; if (totalCapacity <= 0) { return; } for (var i = 0; i < totalCapacity; i++) { var contains = _itemDictionary.ContainsKey(i); if (!contains) { _nextAvailableIndex = i; return; } } } public int AddItem(IItem item) { if (item.MaxQuantity == 1) { if (_nextAvailableIndex == UnknownIndex) { return 0; } var nextAvailableIndex = _nextAvailableIndex; _itemDictionary[nextAvailableIndex] = item; item.ItemContainer = this; UpdateNextAvailableIndex(); UpdateSelectStatus(nextAvailableIndex, item); ItemDataChangeEvent?.Invoke(new ItemDataChangeEvent { NewItem = item, NewIndex = nextAvailableIndex, 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 _itemDictionary.Values) { 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. //添加剩余到容器内。 if (_nextAvailableIndex == UnknownIndex) { return 0; } var finalNextAvailableIndex = _nextAvailableIndex; _itemDictionary[finalNextAvailableIndex] = item; item.ItemContainer = this; UpdateNextAvailableIndex(); UpdateSelectStatus(finalNextAvailableIndex, item); ItemDataChangeEvent?.Invoke(new ItemDataChangeEvent { NewItem = item, NewIndex = finalNextAvailableIndex, 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() { return _itemDictionary.TryGetValue(_selectIndex, out var item) ? item : null; } public IItem? GetItem(int index) { return _itemDictionary.TryGetValue(index, out var item) ? item : null; } public bool ReplaceItem(int index, IItem item) { var oldItem = GetItem(index); _itemDictionary[index] = item; ItemDataChangeEvent?.Invoke(new ItemDataChangeEvent { NewItem = item, NewIndex = index, OldIndex = index, OldItem = oldItem, Type = Config.ItemDataChangeEventType.Replace }); return true; } public bool ReplaceItem(IItem oldItem, IItem newItem) { var index = GetIndexByItem(oldItem); return index != UnknownIndex && ReplaceItem(index, newItem); } public int RemoveSelectItem(int number) { return RemoveItem(_selectIndex, number); } public int RemoveItem(int itemIndex, int number) { if (number == 0) { return 0; } if (!_itemDictionary.TryGetValue(itemIndex, out var item)) { return 0; } var originalQuantity = item.Quantity; if (number < 0) { //If the number entered is less than 0, all items are removed. //输入的数量小于0,则移除全部物品。 item.Quantity = 0; _itemDictionary.Remove(itemIndex); UpdateNextAvailableIndex(); ItemDataChangeEvent?.Invoke(new ItemDataChangeEvent { NewItem = item, NewIndex = itemIndex, Type = Config.ItemDataChangeEventType.Remove }); return originalQuantity; } var removed = Math.Min(number, item.Quantity); item.Quantity -= removed; if (item.Quantity < 1) { _itemDictionary.Remove(itemIndex); UpdateNextAvailableIndex(); ItemDataChangeEvent?.Invoke(new ItemDataChangeEvent { NewItem = item, NewIndex = itemIndex, Type = Config.ItemDataChangeEventType.Remove }); } return removed; } public int RemoveItem(IItem item, int number) { var index = GetIndexByItem(item); return index == UnknownIndex ? 0 : RemoveItem(index, number); } /// /// Find the corresponding index based on the item object /// 根据物品对象查找对应的索引 /// /// /// private int GetIndexByItem(IItem item) { if (totalCapacity <= 0) { return UnknownIndex; } for (var i = 0; i < totalCapacity; i++) { var contains = _itemDictionary.ContainsKey(i); if (!contains) continue; if (item == _itemDictionary[i]) { return i; } } return UnknownIndex; } public int GetUsedCapacity() { return _itemDictionary.Count; } public int GetTotalCapacity() { return totalCapacity; } public void SelectNextItem() { var count = totalCapacity; if (count == 0) { return; } var oldSelectIndex = _selectIndex; var newSelectIndex = _selectIndex + 1; if (newSelectIndex >= count) { newSelectIndex = 0; } PrivateSelectItem(oldSelectIndex, newSelectIndex); } public void SelectPreviousItem() { var count = totalCapacity; 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 (totalCapacity == 0 || index < 0) { return; } PrivateSelectItem(_selectIndex, index % totalCapacity); } }