2024-04-28 13:55:19 +00:00
|
|
|
|
using System.Collections.Generic;
|
2024-05-07 09:38:50 +00:00
|
|
|
|
using ColdMint.scripts.utils;
|
2024-04-28 13:55:19 +00:00
|
|
|
|
using Godot;
|
|
|
|
|
|
|
|
|
|
namespace ColdMint.scripts.inventory;
|
|
|
|
|
|
2024-05-04 14:59:46 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// <para>HotBar</para>
|
|
|
|
|
/// <para>快捷物品栏</para>
|
|
|
|
|
/// </summary>
|
2024-05-06 10:59:39 +00:00
|
|
|
|
public partial class HotBar : HBoxContainer, IItemContainer
|
2024-04-28 13:55:19 +00:00
|
|
|
|
{
|
2024-05-08 10:22:04 +00:00
|
|
|
|
private PackedScene? _itemSlotPackedScene;
|
|
|
|
|
|
|
|
|
|
private List<ItemSlotNode>? _itemSlotNodes;
|
|
|
|
|
|
2024-06-06 14:43:07 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// <para>UnknownIndex</para>
|
|
|
|
|
/// <para>未知位置</para>
|
|
|
|
|
/// </summary>
|
|
|
|
|
private const int UnknownIndex = -1;
|
|
|
|
|
|
2024-05-08 10:22:04 +00:00
|
|
|
|
//_selectIndex默认为0.
|
|
|
|
|
private int _selectIndex;
|
2024-04-28 13:55:19 +00:00
|
|
|
|
|
|
|
|
|
public override void _Ready()
|
|
|
|
|
{
|
|
|
|
|
base._Ready();
|
2024-05-07 09:38:50 +00:00
|
|
|
|
NodeUtils.DeleteAllChild(this);
|
2024-04-28 13:55:19 +00:00
|
|
|
|
_itemSlotNodes = new List<ItemSlotNode>();
|
|
|
|
|
_itemSlotPackedScene = GD.Load<PackedScene>("res://prefab/ui/ItemSlot.tscn");
|
2024-05-03 14:35:54 +00:00
|
|
|
|
for (var i = 0; i < Config.HotBarSize; i++)
|
2024-04-28 13:55:19 +00:00
|
|
|
|
{
|
2024-05-03 14:35:54 +00:00
|
|
|
|
AddItemSlot(i);
|
2024-04-28 13:55:19 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-08 10:22:04 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// <para>Select the next item slot</para>
|
|
|
|
|
/// <para>选择下一个物品槽</para>
|
|
|
|
|
/// </summary>
|
|
|
|
|
private void SelectTheNextItemSlot()
|
|
|
|
|
{
|
|
|
|
|
if (_itemSlotNodes == null)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var count = _itemSlotNodes.Count;
|
|
|
|
|
if (count == 0)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var oldSelectIndex = _selectIndex;
|
|
|
|
|
_selectIndex++;
|
|
|
|
|
if (_selectIndex >= count)
|
|
|
|
|
{
|
|
|
|
|
_selectIndex = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SelectItemSlot(oldSelectIndex, _selectIndex);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// <para>Select the previous item slot</para>
|
|
|
|
|
/// <para>选择上一个物品槽</para>
|
|
|
|
|
/// </summary>
|
|
|
|
|
private void SelectThePreviousItemSlot()
|
|
|
|
|
{
|
|
|
|
|
if (_itemSlotNodes == null)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var count = _itemSlotNodes.Count;
|
|
|
|
|
if (count == 0)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var oldSelectIndex = _selectIndex;
|
|
|
|
|
_selectIndex--;
|
|
|
|
|
if (_selectIndex < 0)
|
|
|
|
|
{
|
|
|
|
|
_selectIndex = count - 1;
|
|
|
|
|
}
|
2024-06-06 13:05:51 +00:00
|
|
|
|
|
2024-05-08 10:22:04 +00:00
|
|
|
|
SelectItemSlot(oldSelectIndex, _selectIndex);
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-03 14:35:54 +00:00
|
|
|
|
public override void _Process(double delta)
|
|
|
|
|
{
|
|
|
|
|
base._Process(delta);
|
|
|
|
|
if (Input.IsActionJustPressed("hotbar_next"))
|
|
|
|
|
{
|
|
|
|
|
//Mouse wheel down
|
|
|
|
|
//鼠标滚轮向下
|
2024-05-08 10:22:04 +00:00
|
|
|
|
SelectTheNextItemSlot();
|
2024-05-03 14:35:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (Input.IsActionJustPressed("hotbar_previous"))
|
|
|
|
|
{
|
|
|
|
|
//Mouse wheel up
|
|
|
|
|
//鼠标滚轮向上
|
2024-05-08 10:22:04 +00:00
|
|
|
|
SelectThePreviousItemSlot();
|
2024-05-03 14:35:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (Input.IsActionJustPressed("hotbar_1"))
|
|
|
|
|
{
|
|
|
|
|
SelectItemSlotByHotBarShortcutKey(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (Input.IsActionJustPressed("hotbar_2"))
|
|
|
|
|
{
|
|
|
|
|
SelectItemSlotByHotBarShortcutKey(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (Input.IsActionJustPressed("hotbar_3"))
|
|
|
|
|
{
|
|
|
|
|
SelectItemSlotByHotBarShortcutKey(2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (Input.IsActionJustPressed("hotbar_4"))
|
|
|
|
|
{
|
|
|
|
|
SelectItemSlotByHotBarShortcutKey(3);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (Input.IsActionJustPressed("hotbar_5"))
|
|
|
|
|
{
|
|
|
|
|
SelectItemSlotByHotBarShortcutKey(4);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (Input.IsActionJustPressed("hotbar_6"))
|
|
|
|
|
{
|
|
|
|
|
SelectItemSlotByHotBarShortcutKey(5);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (Input.IsActionJustPressed("hotbar_7"))
|
|
|
|
|
{
|
|
|
|
|
SelectItemSlotByHotBarShortcutKey(6);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (Input.IsActionJustPressed("hotbar_8"))
|
|
|
|
|
{
|
|
|
|
|
SelectItemSlotByHotBarShortcutKey(7);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (Input.IsActionJustPressed("hotbar_9"))
|
|
|
|
|
{
|
|
|
|
|
SelectItemSlotByHotBarShortcutKey(8);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// <para>Select the HotBar project using the shortcut keys</para>
|
|
|
|
|
/// <para>通过快捷键选择HotBar项目</para>
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <para>The Pc version of the shortcut key index is 0-9</para>
|
|
|
|
|
/// <para>Pc版本的快捷键索引为0-9</para>
|
|
|
|
|
/// <param name="shortcutKeyIndex"></param>
|
|
|
|
|
private void SelectItemSlotByHotBarShortcutKey(int shortcutKeyIndex)
|
|
|
|
|
{
|
2024-05-08 10:22:04 +00:00
|
|
|
|
if (_itemSlotNodes == null)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-06 14:43:07 +00:00
|
|
|
|
var safeIndex = GetSafeIndex(shortcutKeyIndex);
|
|
|
|
|
if (safeIndex == UnknownIndex)
|
2024-05-03 14:35:54 +00:00
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-06 14:43:07 +00:00
|
|
|
|
SelectItemSlot(_selectIndex, safeIndex);
|
|
|
|
|
_selectIndex = safeIndex;
|
2024-05-03 14:35:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-05-04 14:59:46 +00:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// <para>Removes an item from the currently selected inventory</para>
|
|
|
|
|
/// <para>移除当前选中的物品栏内的物品</para>
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="number"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public bool RemoveItemFromItemSlotBySelectIndex(int number)
|
|
|
|
|
{
|
2024-05-08 10:22:04 +00:00
|
|
|
|
return RemoveItemFromItemSlot(_selectIndex, number);
|
2024-05-04 14:59:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-06-06 14:43:07 +00:00
|
|
|
|
public int GetItemSlotCount()
|
|
|
|
|
{
|
|
|
|
|
if (_itemSlotNodes == null)
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return _itemSlotNodes.Count;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public ItemSlotNode? GetItemSlotNode(int index)
|
|
|
|
|
{
|
|
|
|
|
if (_itemSlotNodes == null)
|
|
|
|
|
{
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var safeIndex = GetSafeIndex(index);
|
|
|
|
|
return _itemSlotNodes[safeIndex];
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-04 14:59:46 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// <para>Remove items from the item slot</para>
|
|
|
|
|
/// <para>从物品槽内移除物品</para>
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="itemSlotIndex">
|
|
|
|
|
///<para>When this number is greater than the number of item slots, residual filtering is used.</para>
|
|
|
|
|
///<para>当此数量大于物品槽的数量时,会使用余数筛选。</para>
|
|
|
|
|
/// </param>
|
2024-05-08 10:22:04 +00:00
|
|
|
|
/// <param name="number">
|
|
|
|
|
///<para>The number of items removed</para>
|
|
|
|
|
///<para>移除物品的数量</para>
|
|
|
|
|
/// </param>
|
2024-05-04 14:59:46 +00:00
|
|
|
|
public bool RemoveItemFromItemSlot(int itemSlotIndex, int number)
|
|
|
|
|
{
|
2024-05-08 10:22:04 +00:00
|
|
|
|
if (_itemSlotNodes == null)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-06 14:43:07 +00:00
|
|
|
|
var safeIndex = GetSafeIndex(itemSlotIndex);
|
|
|
|
|
if (safeIndex == UnknownIndex)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var itemSlot = _itemSlotNodes[safeIndex];
|
|
|
|
|
return itemSlot.RemoveItem(number);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// <para>Gets a secure subscript index</para>
|
|
|
|
|
/// <para>获取安全的下标索引</para>
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="itemSlotIndex"></param>
|
|
|
|
|
/// <returns>
|
|
|
|
|
///<para>-1 is returned on failure, and the index that does not result in an out-of-bounds subscript is returned on success</para>
|
|
|
|
|
///<para>失败返回-1,成功返回不会导致下标越界的索引</para>
|
|
|
|
|
/// </returns>
|
|
|
|
|
private int GetSafeIndex(int itemSlotIndex)
|
|
|
|
|
{
|
|
|
|
|
if (_itemSlotNodes == null)
|
|
|
|
|
{
|
|
|
|
|
return UnknownIndex;
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-04 14:59:46 +00:00
|
|
|
|
var count = _itemSlotNodes.Count;
|
|
|
|
|
if (count == 0)
|
|
|
|
|
{
|
|
|
|
|
//Prevents the dividend from being 0
|
|
|
|
|
//防止被除数为0
|
2024-06-06 14:43:07 +00:00
|
|
|
|
return UnknownIndex;
|
2024-05-04 14:59:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-06-06 14:43:07 +00:00
|
|
|
|
return itemSlotIndex % count;
|
2024-05-04 14:59:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-05-03 14:35:54 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// <para>Select an item slot</para>
|
|
|
|
|
/// <para>选中某个物品槽</para>
|
|
|
|
|
/// </summary>
|
|
|
|
|
private void SelectItemSlot(int oldSelectIndex, int newSelectIndex)
|
|
|
|
|
{
|
2024-06-06 13:05:51 +00:00
|
|
|
|
if (oldSelectIndex == newSelectIndex)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-08 10:22:04 +00:00
|
|
|
|
if (_itemSlotNodes == null)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-03 14:35:54 +00:00
|
|
|
|
_itemSlotNodes[oldSelectIndex].IsSelect = false;
|
|
|
|
|
_itemSlotNodes[newSelectIndex].IsSelect = true;
|
2024-05-04 14:59:46 +00:00
|
|
|
|
var oldItem = _itemSlotNodes[oldSelectIndex].GetItem();
|
|
|
|
|
if (oldItem != null && oldItem is Node2D oldNode2D)
|
|
|
|
|
{
|
|
|
|
|
oldNode2D.ProcessMode = ProcessModeEnum.Disabled;
|
|
|
|
|
oldNode2D.Hide();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var item = _itemSlotNodes[newSelectIndex].GetItem();
|
|
|
|
|
if (item == null)
|
|
|
|
|
{
|
2024-05-06 10:59:39 +00:00
|
|
|
|
if (GameSceneNodeHolder.Player != null)
|
|
|
|
|
{
|
|
|
|
|
GameSceneNodeHolder.Player.CurrentItem = null;
|
|
|
|
|
}
|
2024-05-04 14:59:46 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (item is Node2D node2D)
|
|
|
|
|
{
|
|
|
|
|
node2D.ProcessMode = ProcessModeEnum.Inherit;
|
|
|
|
|
node2D.Show();
|
2024-05-06 10:59:39 +00:00
|
|
|
|
if (GameSceneNodeHolder.Player != null)
|
|
|
|
|
{
|
|
|
|
|
GameSceneNodeHolder.Player.CurrentItem = node2D;
|
|
|
|
|
}
|
2024-05-04 14:59:46 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2024-05-06 10:59:39 +00:00
|
|
|
|
if (GameSceneNodeHolder.Player != null)
|
|
|
|
|
{
|
|
|
|
|
GameSceneNodeHolder.Player.CurrentItem = null;
|
|
|
|
|
}
|
2024-05-04 14:59:46 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2024-05-03 14:35:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-05-06 10:59:39 +00:00
|
|
|
|
|
|
|
|
|
public bool CanAddItem(IItem item)
|
|
|
|
|
{
|
|
|
|
|
return Matching(item) != null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2024-04-28 13:55:19 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// <para>Add an item to the HotBar</para>
|
|
|
|
|
/// <para>在HotBar内添加一个物品</para>
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="item"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public bool AddItem(IItem item)
|
|
|
|
|
{
|
2024-05-06 10:59:39 +00:00
|
|
|
|
var itemSlotNode = Matching(item);
|
|
|
|
|
if (itemSlotNode == null)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2024-06-10 13:05:18 +00:00
|
|
|
|
|
2024-06-06 13:05:51 +00:00
|
|
|
|
return itemSlotNode.SetItem(item);
|
2024-05-06 10:59:39 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-06-06 14:43:07 +00:00
|
|
|
|
public int GetSelectIndex()
|
|
|
|
|
{
|
|
|
|
|
return _selectIndex;
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-06 10:59:39 +00:00
|
|
|
|
public ItemSlotNode? GetSelectItemSlotNode()
|
|
|
|
|
{
|
2024-05-08 10:22:04 +00:00
|
|
|
|
if (_itemSlotNodes == null || _itemSlotNodes.Count == 0)
|
2024-05-06 10:59:39 +00:00
|
|
|
|
{
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-08 10:22:04 +00:00
|
|
|
|
if (_selectIndex < _itemSlotNodes.Count)
|
2024-05-06 10:59:39 +00:00
|
|
|
|
{
|
|
|
|
|
//Prevent subscripts from going out of bounds.
|
|
|
|
|
//防止下标越界。
|
2024-05-08 10:22:04 +00:00
|
|
|
|
return _itemSlotNodes[_selectIndex];
|
2024-05-06 10:59:39 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return null;
|
2024-04-28 13:55:19 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-05-06 10:59:39 +00:00
|
|
|
|
public ItemSlotNode? Matching(IItem item)
|
|
|
|
|
{
|
2024-05-08 10:22:04 +00:00
|
|
|
|
if (_itemSlotNodes == null || _itemSlotNodes.Count == 0)
|
2024-05-06 10:59:39 +00:00
|
|
|
|
{
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
foreach (var itemSlotNode in _itemSlotNodes)
|
|
|
|
|
{
|
|
|
|
|
if (itemSlotNode.CanSetItem(item))
|
|
|
|
|
{
|
|
|
|
|
//If there is an item slot to put this item in, then we return it.
|
|
|
|
|
//如果有物品槽可放置此物品,那么我们返回它。
|
|
|
|
|
return itemSlotNode;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
2024-04-28 13:55:19 +00:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// <para>Add items tank</para>
|
|
|
|
|
/// <para>添加物品槽</para>
|
|
|
|
|
/// </summary>
|
2024-05-03 14:35:54 +00:00
|
|
|
|
private void AddItemSlot(int index)
|
2024-04-28 13:55:19 +00:00
|
|
|
|
{
|
2024-05-08 10:22:04 +00:00
|
|
|
|
if (_itemSlotNodes == null || _itemSlotPackedScene == null)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-10 13:05:18 +00:00
|
|
|
|
var itemSlotNode = NodeUtils.InstantiatePackedScene<ItemSlotNode>(_itemSlotPackedScene);
|
2024-05-03 14:35:54 +00:00
|
|
|
|
if (itemSlotNode == null)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AddChild(itemSlotNode);
|
2024-05-08 10:22:04 +00:00
|
|
|
|
itemSlotNode.IsSelect = index == _selectIndex;
|
2024-05-03 14:35:54 +00:00
|
|
|
|
_itemSlotNodes.Add(itemSlotNode);
|
2024-04-28 13:55:19 +00:00
|
|
|
|
}
|
|
|
|
|
}
|