From fb0c14c3f1cb0895370d15a5be30e4e827ac67ad Mon Sep 17 00:00:00 2001 From: cblech Date: Thu, 17 Apr 2025 16:10:12 +0200 Subject: [PATCH] Added item stacking --- prefabs/UI/Inventory/Slot.tscn | 18 ++++ .../Common/Inventory/InventoryInstance.cs | 86 ++++++++++++++----- .../Common/Inventory/InventoryManager.cs | 20 +++-- .../CSharp/Common/Inventory/InventoryUi.cs | 12 ++- .../CSharp/Common/Inventory/ItemInstance.cs | 9 ++ .../CSharp/Common/Inventory/ItemOnGround.cs | 2 +- scripts/CSharp/Common/Inventory/SlotUi.cs | 2 + 7 files changed, 118 insertions(+), 31 deletions(-) diff --git a/prefabs/UI/Inventory/Slot.tscn b/prefabs/UI/Inventory/Slot.tscn index 8e7c2ac..cb8252c 100644 --- a/prefabs/UI/Inventory/Slot.tscn +++ b/prefabs/UI/Inventory/Slot.tscn @@ -41,4 +41,22 @@ label_settings = SubResource("LabelSettings_7emux") horizontal_alignment = 1 vertical_alignment = 1 +[node name="AmountLabel" type="Label" parent="."] +layout_mode = 1 +anchors_preset = -1 +anchor_left = 1.0 +anchor_top = 1.0 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_left = -409.0 +offset_top = -329.0 +offset_right = -10.0 +offset_bottom = -10.0 +grow_horizontal = 0 +grow_vertical = 0 +theme_override_colors/font_color = Color(0, 0, 0, 1) +text = "999" +horizontal_alignment = 2 +vertical_alignment = 2 + [connection signal="gui_input" from="." to="." method="_on_gui_input"] diff --git a/scripts/CSharp/Common/Inventory/InventoryInstance.cs b/scripts/CSharp/Common/Inventory/InventoryInstance.cs index 0991199..5070b69 100644 --- a/scripts/CSharp/Common/Inventory/InventoryInstance.cs +++ b/scripts/CSharp/Common/Inventory/InventoryInstance.cs @@ -12,6 +12,7 @@ public partial class InventoryInstance : Node [Signal] public delegate void SlotAmountChangedEventHandler(); + [Signal] public delegate void InventoryContentsChangedEventHandler(); @@ -32,54 +33,99 @@ public partial class InventoryInstance : Node _slots.Add(new InventorySlot()); } } + EmitSignal(SignalName.SlotAmountChanged); } } - - public InventoryActionResult AddItem(ItemInstance newItem, int inventorySlot = -1) + + public InventoryActionResult AddItem(ItemInstance newItem) { - if (inventorySlot < 0) + var result = AddItemAndStackRecursive(newItem, 0); + EmitSignal(SignalName.InventoryContentsChanged); + return result; + } + + private InventoryActionResult AddItemAndStackRecursive(ItemInstance newItem, int slotSearch) + { + if (newItem.blueprint == null || newItem.amount == 0) + return InventoryActionResult.SourceDoesNotExists; + + var slotIndex = -1; + // find stackable slot + for (var i = slotSearch; i < _slots.Count; i++) { - inventorySlot = _slots.FindIndex(slot => slot.IsEmpty()); + if (_slots[i].itemInstance?.blueprint == newItem.blueprint) + { + slotIndex = i; + break; + } } - - if (inventorySlot < 0 || !_slots[inventorySlot].IsEmpty()) + + if (slotIndex < 0) { - return InventoryActionResult.DestinationFull; + // find empty slot + for (var i = slotSearch; i < _slots.Count; i++) + { + if (_slots[i].IsEmpty()) + { + slotIndex = i; + break; + } + } } - - if (inventorySlot >= _slots.Count) + + if (slotIndex < 0) { - return InventoryActionResult.DestinationDoesNotExists; + return InventoryActionResult.DestinationFull; } - - _slots[inventorySlot].itemInstance = newItem; - EmitSignal(SignalName.InventoryContentsChanged); - return InventoryActionResult.Success; + + var itemInstance = _slots[slotIndex].itemInstance ?? new ItemInstance { blueprint = newItem.blueprint, amount = 0 }; + var maxStack = itemInstance!.blueprint.maxStack; + var freeOnStack = maxStack - itemInstance.amount; + var moveAmount = Math.Min(freeOnStack, newItem.amount); + itemInstance.amount += moveAmount; + newItem.amount -= moveAmount; + _slots[slotIndex].itemInstance = itemInstance; + return newItem.amount <= 0 + ? InventoryActionResult.Success + : AddItemAndStackRecursive(newItem, slotIndex + 1); } - - public InventoryActionResult RemoveItem(int inventorySlot, out ItemInstance? itemInstance ) + + public InventoryActionResult RemoveItem(int inventorySlot, out ItemInstance? itemInstance) { if (inventorySlot < 0 || inventorySlot >= _slots.Count) { itemInstance = null; return InventoryActionResult.SourceDoesNotExists; } - + if (_slots[inventorySlot].IsEmpty()) { itemInstance = null; return InventoryActionResult.SourceIsEmpty; } - + itemInstance = _slots[inventorySlot].itemInstance; _slots[inventorySlot].itemInstance = null; EmitSignal(SignalName.InventoryContentsChanged); return InventoryActionResult.Success; } - + public InventoryActionResult RemoveItem(int inventorySlot) { return RemoveItem(inventorySlot, out _); } -} + + public InventoryActionResult AddItemToSlot(ItemInstance itemInstance, int destinationSlot) + { + if (destinationSlot < 0 || destinationSlot >= _slots.Count) + return InventoryActionResult.DestinationDoesNotExists; + + if (!_slots[destinationSlot].IsEmpty()) + return InventoryActionResult.DestinationFull; + + _slots[destinationSlot].itemInstance = itemInstance; + EmitSignal(SignalName.InventoryContentsChanged); + return InventoryActionResult.Success; + } +} \ No newline at end of file diff --git a/scripts/CSharp/Common/Inventory/InventoryManager.cs b/scripts/CSharp/Common/Inventory/InventoryManager.cs index ed44999..b191e98 100644 --- a/scripts/CSharp/Common/Inventory/InventoryManager.cs +++ b/scripts/CSharp/Common/Inventory/InventoryManager.cs @@ -6,7 +6,7 @@ namespace Babushka.scripts.CSharp.Common.Inventory; public partial class InventoryManager : Node { public static InventoryManager Instance { get; private set; } - + public InventoryInstance playerInventory; public override void _EnterTree() @@ -23,11 +23,13 @@ public partial class InventoryManager : Node public InventoryActionResult CreateItem( ItemResource itemBlueprint, InventoryInstance inventory, + int amount = 1, int inventorySlot = -1) { - var newItem = new ItemInstance { blueprint = itemBlueprint }; - var addResult = inventory.AddItem(newItem, inventorySlot); - return addResult; + var newItem = new ItemInstance { blueprint = itemBlueprint, amount = amount }; + return inventorySlot < 0 + ? inventory.AddItem(newItem) + : inventory.AddItemToSlot(newItem, inventorySlot); } public InventoryActionResult MoveItem( @@ -39,10 +41,11 @@ public partial class InventoryManager : Node var remResult = sourceInventory.RemoveItem(sourceSlot, out var item); if (remResult != InventoryActionResult.Success) return remResult; - var addResult = destinationInventory.AddItem(item!, destinationSlot); - if(addResult == InventoryActionResult.Success) return InventoryActionResult.Success; + var addResult = destinationInventory.AddItemToSlot(item!, destinationSlot); + if (addResult == InventoryActionResult.Success) return InventoryActionResult.Success; - sourceInventory.AddItem(item!, sourceSlot); // can not fail ... in theory + // if adding in the destination failed, re-add the item into the source + sourceInventory.AddItemToSlot(item!, sourceSlot); // can not fail ... in theory return addResult; } @@ -60,8 +63,9 @@ public partial class InventoryManager : Node { return inventory.RemoveItem(inventorySlot); } + public InventoryActionResult CollectItem(ItemInstance itemInstance) { return playerInventory.AddItem(itemInstance); } -} +} \ No newline at end of file diff --git a/scripts/CSharp/Common/Inventory/InventoryUi.cs b/scripts/CSharp/Common/Inventory/InventoryUi.cs index 3b8ed7d..eb92b91 100644 --- a/scripts/CSharp/Common/Inventory/InventoryUi.cs +++ b/scripts/CSharp/Common/Inventory/InventoryUi.cs @@ -43,6 +43,12 @@ public partial class InventoryUi : Control uiSlot!.nameLabel.Text = inventorySlot.itemInstance?.blueprint.name ?? ""; uiSlot!.nameLabel.LabelSettings = uiSlot!.nameLabel.LabelSettings.Duplicate() as LabelSettings; uiSlot!.nameLabel.LabelSettings!.FontColor = inventorySlot.itemInstance?.blueprint.color ?? Colors.White; + + var amountText = inventorySlot.itemInstance != null && + inventorySlot.itemInstance.amount != 1 + ? inventorySlot.itemInstance.amount.ToString() + : ""; + uiSlot!.amountLabel.Text = amountText; } } @@ -99,6 +105,7 @@ public partial class InventoryUi : Control { InputInventoryOpenClose(); } + if (Input.IsActionJustPressed("ui_inventory_disadvance")) { _selectedSlot++; @@ -106,7 +113,8 @@ public partial class InventoryUi : Control _selectedSlot = 0; SetSlotSelectPosition(); } - if(Input.IsActionJustPressed("ui_inventory_advance")) + + if (Input.IsActionJustPressed("ui_inventory_advance")) { _selectedSlot--; if (_selectedSlot < 0) @@ -143,4 +151,4 @@ public partial class InventoryUi : Control _slotOnMouse = null; } } -} +} \ No newline at end of file diff --git a/scripts/CSharp/Common/Inventory/ItemInstance.cs b/scripts/CSharp/Common/Inventory/ItemInstance.cs index abf6e4f..0aaa528 100644 --- a/scripts/CSharp/Common/Inventory/ItemInstance.cs +++ b/scripts/CSharp/Common/Inventory/ItemInstance.cs @@ -4,4 +4,13 @@ public class ItemInstance { public ItemResource blueprint; public int amount = 1; + + public ItemInstance Clone() + { + return new ItemInstance + { + blueprint = blueprint, + amount = amount + }; + } } diff --git a/scripts/CSharp/Common/Inventory/ItemOnGround.cs b/scripts/CSharp/Common/Inventory/ItemOnGround.cs index 75ba3d8..d9c7cbe 100644 --- a/scripts/CSharp/Common/Inventory/ItemOnGround.cs +++ b/scripts/CSharp/Common/Inventory/ItemOnGround.cs @@ -25,7 +25,7 @@ public partial class ItemOnGround : Node3D { GD.Print("Trying to pick up item"); - var result = InventoryManager.Instance.CollectItem(itemInstance); + var result = InventoryManager.Instance.CollectItem(itemInstance.Clone()); if (result == InventoryActionResult.Success) { if (!_infiniteSupply) diff --git a/scripts/CSharp/Common/Inventory/SlotUi.cs b/scripts/CSharp/Common/Inventory/SlotUi.cs index 2c174b2..753447d 100644 --- a/scripts/CSharp/Common/Inventory/SlotUi.cs +++ b/scripts/CSharp/Common/Inventory/SlotUi.cs @@ -7,12 +7,14 @@ public partial class SlotUi : Control { public Label nameLabel; public int index; + public Label amountLabel; [Signal] public delegate void ClickedEventHandler(int index); public override void _EnterTree() { nameLabel = GetNode