Merge pull request #6 from Web13234/master

Add Packsack Stack
This commit is contained in:
Cold-Mint 2024-06-14 19:32:43 +08:00 committed by GitHub
commit b3436dcb73
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 156 additions and 37 deletions

View File

@ -20,7 +20,7 @@ public partial class HotBar : HBoxContainer
NodeUtils.DeleteAllChild(this); NodeUtils.DeleteAllChild(this);
for (var i = 0; i < Config.HotBarSize; i++) for (var i = 0; i < Config.HotBarSize; i++)
{ {
_itemContainer.AddItemSlot(this, i); _itemContainer.AddItemSlot(this);
} }
} }

View File

@ -34,6 +34,17 @@ public interface IItemContainer : IEnumerable<ItemSlotNode>
/// <returns></returns> /// <returns></returns>
bool AddItem(IItem item); bool AddItem(IItem item);
/// <summary>
/// <para>Determines the number of items that can be received from the specified pile</para>
/// <para>判断能从指定物品堆中接收的物品数量</para>
/// </summary>
/// <param name="itemStack">
/// <para>Item stack to add to the current container</para>
/// <para>向该容器中放入物品的物品堆</para>
/// </param>
/// <returns></returns>
int CanAddItemStack(IItemStack itemStack);
/// <summary> /// <summary>
/// <para>Add an stack of items to this container</para> /// <para>Add an stack of items to this container</para>
/// <para>向当前容器中存入一堆物品</para> /// <para>向当前容器中存入一堆物品</para>
@ -179,8 +190,8 @@ public interface IItemContainer : IEnumerable<ItemSlotNode>
ItemSlotNode? Match(IItemStack stack); ItemSlotNode? Match(IItemStack stack);
/// <summary> /// <summary>
/// <para>Match the first item slot that has item stack that satisfies the predicate</para> /// <para>Match the first item slot that satisfies the predicate</para>
/// <para>匹配首个拥有满足指定条件的物品堆的物品槽</para> /// <para>匹配首个拥有满足指定条件的物品槽</para>
/// </summary> /// </summary>
/// <param name="predicate"></param> /// <param name="predicate"></param>
/// <returns> /// <returns>
@ -188,11 +199,11 @@ public interface IItemContainer : IEnumerable<ItemSlotNode>
/// <para>若没有满足条件的槽位返回null</para> /// <para>若没有满足条件的槽位返回null</para>
/// </returns> /// </returns>
/// <seealso cref="MatchAll"/> /// <seealso cref="MatchAll"/>
ItemSlotNode? Match(Func<IItemStack?, bool> predicate); ItemSlotNode? Match(Func<ItemSlotNode, bool> predicate);
/// <summary> /// <summary>
/// <para>Match all item slots that has item stack that satisfies the predicate</para> /// <para>Match all item slots that satisfies the predicate</para>
/// <para>匹配所有拥有满足指定条件的物品堆的物品槽</para> /// <para>匹配所有拥有满足指定条件的物品槽</para>
/// </summary> /// </summary>
/// <param name="predicate"></param> /// <param name="predicate"></param>
/// <returns> /// <returns>
@ -200,7 +211,7 @@ public interface IItemContainer : IEnumerable<ItemSlotNode>
/// <para>包含匹配到的槽位的IEnumerable当没有满足条件的槽位时为空</para> /// <para>包含匹配到的槽位的IEnumerable当没有满足条件的槽位时为空</para>
/// </returns> /// </returns>
/// <seealso cref="Match(Func{IItemStack?,bool})"/> /// <seealso cref="Match(Func{IItemStack?,bool})"/>
IEnumerable<ItemSlotNode> MatchAll(Func<IItemStack?, bool> predicate); IEnumerable<ItemSlotNode> MatchAll(Func<ItemSlotNode, bool> predicate);
/// <summary> /// <summary>
@ -208,8 +219,7 @@ public interface IItemContainer : IEnumerable<ItemSlotNode>
/// <para>添加物品槽</para> /// <para>添加物品槽</para>
/// </summary> /// </summary>
/// <param name="rootNode"></param> /// <param name="rootNode"></param>
/// <param name="index"></param> void AddItemSlot(Node rootNode);
void AddItemSlot(Node rootNode, int index);
/// <summary> /// <summary>
/// <para>SelectTheNextItemSlot</para> /// <para>SelectTheNextItemSlot</para>

View File

@ -144,18 +144,6 @@ public partial class ItemSlotNode : MarginContainer
UpdateAllDisplay(); UpdateAllDisplay();
} }
/// <summary>
/// <para>Can the specified item be placed in the item slot?</para>
/// <para>指定的物品是否可设置在物品槽内?</para>
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
public bool CanAddItem(IItem item)
{
if (_itemStack == null) return true;
return _itemStack.CanAddItem(item);
}
/// <summary> /// <summary>
/// <para> /// <para>
/// Set item stack for this slot, this will completely replace current item stack. /// Set item stack for this slot, this will completely replace current item stack.
@ -177,6 +165,18 @@ public partial class ItemSlotNode : MarginContainer
return result; return result;
} }
/// <summary>
/// <para>Can the specified item be placed in the item slot?</para>
/// <para>指定的物品是否可设置在物品槽内?</para>
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
public bool CanAddItem(IItem item)
{
if (_itemStack == null) return true;
return _itemStack.CanAddItem(item);
}
/// <summary> /// <summary>
/// <para>Try to add an item to this slot, if it can't be added to this slot, return false</para> /// <para>Try to add an item to this slot, if it can't be added to this slot, return false</para>
/// <para>尝试向当前槽位中加入物品如果该物品不能被放入该槽位返回false</para> /// <para>尝试向当前槽位中加入物品如果该物品不能被放入该槽位返回false</para>
@ -202,6 +202,21 @@ public partial class ItemSlotNode : MarginContainer
return result; return result;
} }
/// <summary>
/// <para>Determines the number of items that can be received from the specified pile</para>
/// <para>判断能从指定物品堆中接收的物品数量</para>
/// </summary>
/// <param name="itemStack">
/// <para>Item stack to add to the current slot</para>
/// <para>向该物品槽中放入物品的物品堆</para>
/// </param>
/// <returns></returns>
public int CanAddItemStack(IItemStack itemStack)
{
if (_itemStack is null) return itemStack.Quantity;
return _itemStack.CanTakeFrom(itemStack);
}
/// <summary> /// <summary>
/// <para>Try to combine an item stack into this slot</para> /// <para>Try to combine an item stack into this slot</para>
/// <para>尝试将一个物品堆合并至该槽位中</para> /// <para>尝试将一个物品堆合并至该槽位中</para>

View File

@ -22,7 +22,7 @@ public class UniversalItemContainer : IItemContainer
{ {
private readonly PackedScene? _itemSlotPackedScene = GD.Load<PackedScene>("res://prefab/ui/ItemSlot.tscn"); private readonly PackedScene? _itemSlotPackedScene = GD.Load<PackedScene>("res://prefab/ui/ItemSlot.tscn");
private readonly List<ItemSlotNode>? _itemSlotNodes = new(); private readonly List<ItemSlotNode>? _itemSlotNodes = [];
/// <summary> /// <summary>
/// <para>Character</para> /// <para>Character</para>
@ -55,6 +55,16 @@ public class UniversalItemContainer : IItemContainer
return itemSlotNode.AddItem(item); return itemSlotNode.AddItem(item);
} }
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,
slots.Select(slot => slot.CanAddItemStack(itemStack)).Sum());
}
public bool AddItemStack(IItemStack itemStack) public bool AddItemStack(IItemStack itemStack)
{ {
while (true) while (true)
@ -169,14 +179,14 @@ public class UniversalItemContainer : IItemContainer
return _itemSlotNodes?.FirstOrDefault(itemSlotNode => itemSlotNode.CanAddItem(stack.GetItem()!)); return _itemSlotNodes?.FirstOrDefault(itemSlotNode => itemSlotNode.CanAddItem(stack.GetItem()!));
} }
public ItemSlotNode? Match(Func<IItemStack?, bool> predicate) public ItemSlotNode? Match(Func<ItemSlotNode, bool> predicate)
{ {
return _itemSlotNodes?.FirstOrDefault(node => predicate(node.GetItemStack())); return _itemSlotNodes?.FirstOrDefault(predicate);
} }
public IEnumerable<ItemSlotNode> MatchAll(Func<IItemStack?, bool> predicate) public IEnumerable<ItemSlotNode> MatchAll(Func<ItemSlotNode, bool> predicate)
{ {
return from node in _itemSlotNodes where predicate(node.GetItemStack()) select node; return from node in _itemSlotNodes where predicate(node) select node;
} }
@ -211,7 +221,7 @@ public class UniversalItemContainer : IItemContainer
/// <para>Add items tank</para> /// <para>Add items tank</para>
/// <para>添加物品槽</para> /// <para>添加物品槽</para>
/// </summary> /// </summary>
public void AddItemSlot(Node rootNode, int index) public void AddItemSlot(Node rootNode)
{ {
if (_itemSlotNodes == null || _itemSlotPackedScene == null) if (_itemSlotNodes == null || _itemSlotPackedScene == null)
{ {
@ -224,7 +234,7 @@ public class UniversalItemContainer : IItemContainer
return; return;
} }
itemSlotNode.IsSelect = index == _selectIndex; itemSlotNode.IsSelect = (_itemSlotNodes.Count ) == _selectIndex;
_itemSlotNodes.Add(itemSlotNode); _itemSlotNodes.Add(itemSlotNode);
} }

View File

@ -1,4 +1,5 @@
using ColdMint.scripts.inventory; using ColdMint.scripts.inventory;
using ColdMint.scripts.item.itemStacks;
using Godot; using Godot;
@ -25,8 +26,8 @@ public partial class Packsack : RigidBody2D, IItem
public void Destroy() public void Destroy()
{ {
if (_itemContainer == null) return; if (ItemContainer == null) return;
foreach (var itemSlot in _itemContainer) foreach (var itemSlot in ItemContainer)
{ {
itemSlot.ClearSlot(); itemSlot.ClearSlot();
} }
@ -36,16 +37,20 @@ public partial class Packsack : RigidBody2D, IItem
public bool CanStackWith(IItem item) => false; public bool CanStackWith(IItem item) => false;
private IItemContainer? _itemContainer; public IItemStack? SpecialStack()
{
return new PacksackStack(this);
}
public IItemContainer? ItemContainer { get; private set; }
public override void _Ready() public override void _Ready()
{ {
base._Ready(); base._Ready();
_itemContainer = new UniversalItemContainer(); ItemContainer = new UniversalItemContainer();
}
public IItemContainer? GetItemContainer() //Test: Add one ItemSlot for pack
{ ItemContainer.AddItemSlot(this);
return _itemContainer;
} }
} }

View File

@ -78,8 +78,8 @@ public interface IItemStack
/// <para>判断能从指定物品堆中接收的物品数量</para> /// <para>判断能从指定物品堆中接收的物品数量</para>
/// </summary> /// </summary>
/// <param name="itemStack"> /// <param name="itemStack">
/// <para>向该物品堆中放入物品的物品堆</para>
/// <para>Item stack to add to the current stack</para> /// <para>Item stack to add to the current stack</para>
/// <para>向该物品堆中放入物品的物品堆</para>
/// </param> /// </param>
/// <returns></returns> /// <returns></returns>
public int CanTakeFrom(IItemStack itemStack); public int CanTakeFrom(IItemStack itemStack);

View File

@ -0,0 +1,79 @@
using System;
using Godot;
namespace ColdMint.scripts.item.itemStacks;
/// <summary>
/// <para>ItemStack for <see cref="Packsack"/> item. Can add items into pack by stack them to this stack.</para>
/// <para>用于<see cref="Packsack"/>物品的堆栈。可以将物品堆叠到此堆栈中,从而将物品添加到背包中。</para>
/// </summary>
/// <param name="packsack"></param>
public class PacksackStack(Packsack packsack) : IItemStack
{
public int MaxQuantity => 1;
public int Quantity => 1;
public bool Empty { get; private set; }
public Texture2D Icon => packsack.Icon;
public string Name => packsack.Name;
public string? Description => packsack.Description;
//todo: 只拒绝是背包的物品是权宜之计,应该为物品加入一个“是否可以放入背包”的属性来实现这个判断。
public bool CanAddItem(IItem item)
{
if (item is Packsack) return false;
return packsack.ItemContainer?.CanAddItem(item) ?? false;
}
public bool AddItem(IItem item)
{
if (item is Packsack) return false;
return packsack.ItemContainer?.AddItem(item) ?? false;
}
public int CanTakeFrom(IItemStack itemStack)
{
if (itemStack.GetItem() is Packsack) return 0;
return packsack.ItemContainer?.CanAddItemStack(itemStack) ?? 0;
}
public bool TakeFrom(IItemStack itemStack)
{
if (itemStack.GetItem() is Packsack) return false;
return packsack.ItemContainer?.AddItemStack(itemStack) ?? false;
}
public IItem? GetItem()
{
return Empty ? packsack : null;
}
public IItem? PickItem()
{
if (Empty) return null;
Empty = true;
return packsack;
}
public IItemStack? PickItems(int value)
{
if (Empty || value == 0) return null;
Empty = true;
return new PacksackStack(packsack);
}
public int RemoveItem(int number)
{
if (Empty || number == 0) return number;
Empty = true;
packsack.Destroy();
return Math.Max(0, number - 1);
}
public void ClearStack()
{
if (Empty) return;
packsack.Destroy();
Empty = true;
}
}