Transfer item between player inventory and chest inventory

Godot Version

Godot Engine v4.2.2.stable.official

Question

I am trying to transfer item from player inventory to chest inventory. Item gets transferred by selecting slot in player inventory and pressing ‘enter’:

When I try to transfer item from chest inventory to player inventory it gets weird:
If item is still in player inventory - it gets transferred (stacks)

If item has to be transferred to a empty slot I get in my output:
‘Error: Null item’

Could anyone please help me out? I’ve been trying to figure this out for a while with no success.

Code

extends Resource

class_name Inventory

signal update

@export var slots: Array[InventorySlot]

func insert(item: InventoryItem):
	# Stack item to the same slot
	var item_slots = slots.filter(func(slot): return slot.item == item)
	if !item_slots.is_empty():
		item_slots[0].amount += 1
	else:
		# Add item to the new slot
		var empty_slots = slots.filter(func(slot): return slot.item == null)
		if  !empty_slots.is_empty():
			empty_slots[0].item = item
			empty_slots[0].amount = 1
	update.emit()
	

func remove_item(item: InventoryItem):
	# Reduce item amount / remove item in slot
	for slot in slots:
		if slot.item != null and slot.item.name == item.name:
			if slot.amount > 1:
				slot.amount -= 1
			else:
				slot.item = null
				slot.amount = 0
			update.emit()
			return
	print('Item not found in inventory')

### Inventory_ui.gd
extends Control

@onready var inventory: Inventory = preload("res://scenes/inventory/player_inventory.tres")
@onready var chest_inventory: Chest_inventory = preload("res://scenes/inventory/chest/chest_inventory.tres")
@onready var chest_ui = $"../Chest_UI"
@onready var slots: Array = $inventory_background/inventory_slots.get_children()
@onready var is_open = false

func _ready():
	# Get signal from func in backend inventory
	inventory.update.connect(update_slots)
	chest_inventory.update.connect(update_slots)
	update_slots()
	close()

func _process(_delta):
	inputs()

func inputs():
	
	# Arrow up to check inventory slots
	if Input.is_action_just_pressed("nav_up"):
		print('Slot1: ', inventory.slots[0].item, ' item name: ', inventory.slots[0].item.name)
	
	# 'ENTER' to transfer selected items from inventory
	if is_open and chest_ui.is_open and Input.is_action_just_pressed("enter"):
		var selected_slot = null
		for i in range(slots.size()):
			if slots[i].is_selected:
				selected_slot = inventory.slots[i]
				transfer_item(selected_slot.item)
		
	# 'E' to open inventory
	if Input.is_action_just_pressed("use"):
		toggle_inventory()
		chest_ui.close()
			
	# 'ESC' to close all inventories
	if Input.is_action_just_pressed("esc"):
		close()
		chest_ui.close()


func transfer_item(item: InventoryItem):
	
	if item == null:
		print('Error: Null item')
	
	# Transfer items to chest inventory from player inventory
	if chest_ui.is_open:
		# Check if chest inventory can accept items
		chest_inventory.transfer_item(item)
		inventory.remove_item(item)
		update_slots()
		chest_ui.update_slots()
		
		
func update_slots():
	for i in range(min(inventory.slots.size(), slots.size())):
		slots[i].update(inventory.slots[i])

# Funcs to open/close inventory
func toggle_inventory():
	if is_open:
		close()
	else:
		open()

func close():
	# Remove selected slots
	for i in range(slots.size()):
			if slots[i].is_selected:
				slots[i].item_selected.visible = false
	# Close inventory
	visible = false
	is_open = false
	
func open():
	# Open inventory
	visible = true
	is_open = true
	

### Chest_inventory.gd
extends Resource

class_name Chest_inventory

signal update

@export var slots: Array[InventorySlot]

func transfer_item(item: InventoryItem):
	# Stack item to the same slot
	var item_slots = slots.filter(func(slot): return slot.item == item)
	if !item_slots.is_empty():
		item_slots[0].amount += 1
	else:
		# Add item to the new slot
		var empty_slots = slots.filter(func(slot): return slot.item == null)
		if  !empty_slots.is_empty():
			empty_slots[0].item = item
			empty_slots[0].amount = 1
	update.emit()


func remove_item(item: InventoryItem):
	# Reduce item amount / remove item in slot
	for slot in slots:
		if slot.item == item:
			if slot.amount > 1:
				slot.amount -= 1
			else:
				slot.item = null
				slot.amount = 0
			update.emit()
			return
	print('Item not found in inventory')

###Chest_ui.gd
extends Control

@onready var chest_inventory: Chest_inventory = preload("res://scenes/inventory/chest/chest_inventory.tres")
@onready var inventory: Inventory = preload("res://scenes/inventory/player_inventory.tres")
@onready var inventory_ui = $"../Inventory_UI"
@onready var slots: Array = $inventory_background/inventory_slots.get_children()
@onready var is_open = false

func _ready():
	# Get signal from func in backend inventory
	chest_inventory.update.connect(update_slots)
	inventory.update.connect(update_slots)
	update_slots()
	close()
	
func _process(_delta):
	
	if Input.is_action_just_pressed("enter"):
		var selected_slot = null
		for i in range(slots.size()):
			if slots[i].is_selected:
				selected_slot = inventory.slots[i]
				transfer_item(selected_slot.item)
			

func transfer_item(item: InventoryItem):
	if item == null:
		print('Error: Null item')
	
	if inventory_ui.is_open:
		inventory.insert(item)
		chest_inventory.remove_item(item)
		update_slots()
		inventory_ui.update_slots()

func update_slots():
	for i in range(min(chest_inventory.slots.size(), slots.size())):
		slots[i].update(chest_inventory.slots[i])

# Funcs to open/close chest UI
func toggle_chest():
	if is_open:
		close()
	else:
		open()

func close():
	# Remove selected slots
	for i in range(slots.size()):
			if slots[i].is_selected:
				slots[i].item_selected.visible = false
	
	# Close chest
	visible = false
	is_open = false
	
func open():
	# Open chest
	visible = true
	is_open = true

Please update your post to use the preformatted text functionality with ``` for the code snippets. In the current state it’s very hard to read.

Sorry about that. Should be more readable now.

What I find weird is that right before you call your transfer_item() method, you are iterating over slots array, but then you are assigning a slot from the inventory.slots array to be a selected_slot and ultimately passed into the function.

func _process(_delta):
	
	if Input.is_action_just_pressed("enter"):
		var selected_slot = null
		for i in range(slots.size()):
			if slots[i].is_selected:
				selected_slot = inventory.slots[i]
				transfer_item(selected_slot.item)

Is this correct? Shouldn’t it be selected_slot = slots[i]?
You have this line twice in your code, so check both instances.

2 Likes

I appreciate you trying to figure this out but sadly I was not able to fix. Ultimately, I decided to re-do the whole system from scratch. Thank you for time.

1 Like