Accommodating for Multiple Stacks of Items in an Inventory System

local function AddItem(player,args)
	local PlayerID = args.PlayerID
	local Location = args.Location

	for i,tbl in pairs(InventoryTables) do
		--Find player's inventory
		if tbl["PlayerKeycodeID"] == PlayerID then
			print("Found Correct Player Inventory")
			if #tbl == 29 then
				Location:FindFirstChild("Full"):Fire()
				warn("Inventory is full!")
			else
				
				local i = 1
				while true do
					print("Starting Proccess for Item"..i)
					if args["Item"..i] then
						
					local Num = args["Num"..i]
					local Item = args["Item"..i]
			--Check for existing item	
			--Item
				if tbl[Item] then
						print("Item"..i.." already exists.  Attempting to add onto it")	
					tbl[Item] += Num
					
					if tbl[Item] > StackLimits[Item] then		
						local Extra = tbl[Item] - StackLimits[Item]
						local Amount = "Num"..i
						warn("Item"..i.." has gone over the stack limit.  Sending "..Extra.." back")
						Location:FindFirstChild("GetBack"):Fire(Amount,Extra)
							else
								Location:FindFirstChild("Success"):Fire()
								warn("Successfully added Item"..i)
							end
					
				elseif Item then
					print("Item"..i.." is a new item.  Attempting to add it")		
					if #tbl < 29 then
						tbl[Item] = Num
						Location:FindFirstChild("Success"):Fire()
						warn("Successfully added Item"..i)	
					else
						Location:FindFirstChild("Full"):Fire()
						warn("Inventory is full!")
						return
					end
					end
					
					i+=1
					else
						break
					end
					
				end
				end
		else
			return
		end
		print(tbl)
	end
	warn("Finished")
end

I’ve written this script to add items to a table for a player’s inventory, but currently, it would only allow for a single stack of a type of item, so I wouldn’t be able to have 2 slots filled with the same item. How can I accommodate for this to work, and how would I know which stack of an item to add to when the player receives an item and they already have multiple stacks of that same item?

This section:

if tbl[Item] then
	print("Item"..i.." already exists.  Attempting to add onto it")	
tbl[Item] += Num
					
if tbl[Item] > StackLimits[Item] then		
	local Extra = tbl[Item] - StackLimits[Item]
	local Amount = "Num"..i
	warn("Item"..i.." has gone over the stack limit.  Sending "..Extra.." back")
	Location:FindFirstChild("GetBack"):Fire(Amount,Extra)
		else
			Location:FindFirstChild("Success"):Fire()
			warn("Successfully added Item"..i)
		end
2 Likes

well first of all, you can scrap the whole stack limits thing cause it works contrary to what you want

stacking should be handled visually not here

I’m sorry but the code is just awful, the way you handle slots especially makes it hard to implement stacking

So how would I be able to still tell when the inventory reaches max capacity? Since it only has 28 slots (29th is the PlayerID) and it should create a new stack when it reaches the limit

Sorry about that. I’ve never worked with this sort of stuff before and I just winged it.

you’d have to calculate the number of slots of which every type of item occupies, this shouldn’t be too challenging

Something like taking the value of that item and dividing it by the stack limit, then rounding it down?


local function get_stacks(tbl)
   local stacks = 0
   for item_name, value in pairs(tbl) do
      local stack_limit = StackLimits[Item]
      local stacks = math.ceil(value / stack_limit)
      stacks += stacks
   end
   return stacks
end

uh kinda, you’d have to always round it up

You have to stop using the Item as the index, cuz that will result in overwriting when multiple items exist (unless ofc Item is an instance but in that case it’s gonna be difficult to check if they are related). Rather let the index be numbers denoting slot number.

I might end up rewriting this code because it’s hot garbage and hard to follow, but I will use your stack code. I had it all worked out client side, but I have to switch it over to the server so exploits can’t occur.

Does your system follow a specific amount of slots? Or is it infinite?

For this, should I then have two tables, one for the item type and one for the amount of that item?

It has 28 slots, the 29th slot mentoined in the code is the PlayerID so that each table can be identified for each player

try not to nest so much in one function, you can always create sub-functions

1 Like

Yep, exactly that’s how my previous system was set, basically you will have an item data table generally in the format:

Item = {
    ID: string,
    Amount: number
}

And you would assign it to a slot like:

local Inventory = {}

Inventory[1] = {
    ID = "Sword",
    Amount = 1,
}
2 Likes

would that still be compatible with the tbl variable in the for loop?

This is a bad idea cuz it offers less flexibility as later on you myt decide to scale the system and this will become a hindrance. It’s better if you followed an OOP approach by creating an inventory instance for each player.

What’s an OOP? Never heard the term before

I realized the top of the script wasn’t put in the original post. Here’s what I did at the top:

local StackLimits = require(workspace.StackLimits)
local InventoryTables = {}

game.Players.PlayerAdded:Connect(function(Player)
	local PlayerKeycodeID = Player.UserId
	local PlayerInventory = table.create(0)
	PlayerInventory["PlayerKeycodeID"] = PlayerKeycodeID
	table.insert(InventoryTables,PlayerInventory)
	print(InventoryTables)
end)