Merge branch 'master' of github.com:Cold-Mint/Traveller

This commit is contained in:
Cold-Mint 2024-06-14 19:33:21 +08:00
commit 30a0a6539f
Signed by: Cold-Mint
GPG Key ID: C5A9BF8A98E0CE99
7 changed files with 156 additions and 37 deletions

View File

@ -20,7 +20,7 @@ public partial class HotBar : HBoxContainer
NodeUtils.DeleteAllChild(this);
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>
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>
/// <para>Add an stack of items to this container</para>
/// <para>向当前容器中存入一堆物品</para>
@ -179,8 +190,8 @@ public interface IItemContainer : IEnumerable<ItemSlotNode>
ItemSlotNode? Match(IItemStack stack);
/// <summary>
/// <para>Match the first item slot that has item stack that satisfies the predicate</para>
/// <para>匹配首个拥有满足指定条件的物品堆的物品槽</para>
/// <para>Match the first item slot that satisfies the predicate</para>
/// <para>匹配首个拥有满足指定条件的物品槽</para>
/// </summary>
/// <param name="predicate"></param>
/// <returns>
@ -188,11 +199,11 @@ public interface IItemContainer : IEnumerable<ItemSlotNode>
/// <para>若没有满足条件的槽位返回null</para>
/// </returns>
/// <seealso cref="MatchAll"/>
ItemSlotNode? Match(Func<IItemStack?, bool> predicate);
ItemSlotNode? Match(Func<ItemSlotNode, bool> predicate);
/// <summary>
/// <para>Match all item slots that has item stack that satisfies the predicate</para>
/// <para>匹配所有拥有满足指定条件的物品堆的物品槽</para>
/// <para>Match all item slots that satisfies the predicate</para>
/// <para>匹配所有拥有满足指定条件的物品槽</para>
/// </summary>
/// <param name="predicate"></param>
/// <returns>
@ -200,7 +211,7 @@ public interface IItemContainer : IEnumerable<ItemSlotNode>
/// <para>包含匹配到的槽位的IEnumerable当没有满足条件的槽位时为空</para>
/// </returns>
/// <seealso cref="Match(Func{IItemStack?,bool})"/>
IEnumerable<ItemSlotNode> MatchAll(Func<IItemStack?, bool> predicate);
IEnumerable<ItemSlotNode> MatchAll(Func<ItemSlotNode, bool> predicate);
/// <summary>
@ -208,8 +219,7 @@ public interface IItemContainer : IEnumerable<ItemSlotNode>
/// <para>添加物品槽</para>
/// </summary>
/// <param name="rootNode"></param>
/// <param name="index"></param>
void AddItemSlot(Node rootNode, int index);
void AddItemSlot(Node rootNode);
/// <summary>
/// <para>SelectTheNextItemSlot</para>

View File

@ -143,18 +143,6 @@ public partial class ItemSlotNode : MarginContainer
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>
/// <para>
/// Set item stack for this slot, this will completely replace current item stack.
@ -176,6 +164,18 @@ public partial class ItemSlotNode : MarginContainer
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>
/// <para>Try to add an item to this slot, if it can't be added to this slot, return false</para>
/// <para>尝试向当前槽位中加入物品如果该物品不能被放入该槽位返回false</para>
@ -201,6 +201,21 @@ public partial class ItemSlotNode : MarginContainer
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>
/// <para>Try to combine an item stack into this slot</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 List<ItemSlotNode>? _itemSlotNodes = new();
private readonly List<ItemSlotNode>? _itemSlotNodes = [];
/// <summary>
/// <para>Character</para>
@ -55,6 +55,16 @@ public class UniversalItemContainer : IItemContainer
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)
{
while (true)
@ -169,14 +179,14 @@ public class UniversalItemContainer : IItemContainer
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>添加物品槽</para>
/// </summary>
public void AddItemSlot(Node rootNode, int index)
public void AddItemSlot(Node rootNode)
{
if (_itemSlotNodes == null || _itemSlotPackedScene == null)
{
@ -224,7 +234,7 @@ public class UniversalItemContainer : IItemContainer
return;
}
itemSlotNode.IsSelect = index == _selectIndex;
itemSlotNode.IsSelect = (_itemSlotNodes.Count ) == _selectIndex;
_itemSlotNodes.Add(itemSlotNode);
}

View File

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

View File

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