Please help me How to make a Crates Cash

Hey everyone :wave:

I’m making an RP themed game, and I really want to make Crates like this where the Crates will get Money and also Tools, but I have a problem where when I open the Crates and get Money… The money doesn’t add to the Leaderstats. so what should I do??
Video

Example of Crates that I want to make

This is the script and Localscript that I used I took this Crates model from Youtube but if you are confused by this code or can’t see the objects from this game you can open my studio file or even watch this Video Crates

LocalScript Code

CratesClient

--Variables
local rs = game:GetService("ReplicatedStorage")
local remotes = rs:WaitForChild("RemoteEvents")
local rarityProperties = rs:WaitForChild("RarityProperties")
local items = rs:WaitForChild("Items")
local crates = rs:WaitForChild("Crates")

local shopGui = script.Parent:WaitForChild("CrateShopGui");shopGui.Enabled = true
local openShopBtn = shopGui:WaitForChild("OpenButton");openShopBtn.Visible = true
local shopFrame = shopGui:WaitForChild("CrateShopFrame");shopFrame.Visible = false
local closeShopBtn = shopFrame:WaitForChild("CloseButton")
local cratesList = shopFrame:WaitForChild("CratesList")
local selectedCrate = shopFrame:WaitForChild("SelectedCrate");selectedCrate.Visible = false

local openedGui = script.Parent:WaitForChild("OpenedCrateGui");openedGui.Enabled = false
local openedFrame = openedGui:WaitForChild("CrateFrame");openedFrame.Visible = false
local closeOpenedBtn = openedFrame:WaitForChild("ContinueButton")
local openedItemsFrame = openedFrame:WaitForChild("ItemsFrame")

local crateButtonTemplate = script:WaitForChild("CrateShopButton")
local selectedCrateItemTemplate = script:WaitForChild("SelectedCrateItemFrame")
local openingCrateItemTemplate = script:WaitForChild("OpeningCrateItemFrame")

local rnd = Random.new()


openShopBtn.MouseButton1Click:Connect(function()
	if openedFrame.Visible == false then
		shopFrame.Visible = not shopFrame.Visible
	end
end)

closeShopBtn.MouseButton1Click:Connect(function()
	shopFrame.Visible = false
end)

closeOpenedBtn.MouseButton1Click:Connect(function()
	openedFrame.Visible = false
	openedGui.Enabled = false
	
	for _, child in pairs(openedItemsFrame.ItemsContainer:GetChildren()) do
		if child:IsA("Frame") then
			child:Destroy()
		end
	end
end)


--Setting up crates shop
local crateButtons = {}

for _, crate in pairs(crates:GetChildren()) do
	
	local crateProperties = require(crate)
	
	local newBtn = crateButtonTemplate:Clone()
	newBtn.Name = crate.Name
	newBtn.CrateName.Text = crate.Name
	newBtn.CrateImage.Image = crateProperties["Image"]
	
	newBtn.MouseButton1Click:Connect(function()
		
		if selectedCrate.CrateName.Text ~= crate.Name then
			
			selectedCrate.CrateName.Text = crate.Name
			selectedCrate.CrateImage.Image = crateProperties["Image"]
			selectedCrate.UnboxButton.Text = "$" .. crateProperties["Price"]
			
			local rarities = {}
			for rarityName, chance in pairs(crateProperties["Chances"]) do
				table.insert(rarities, {rarityName, chance})
			end
			table.sort(rarities, function(a, b)
				return rarityProperties[a[1]].Order.Value <rarityProperties[b[1]].Order.Value
			end)
			
			local raritiesText = ""
			for _, rarity in pairs(rarities) do
				local color = rarityProperties[rarity[1]].Color.Value
				color = {R = math.round(color.R*255); G = math.round(color.G*255); B = math.round(color.B*255)}
				raritiesText = raritiesText .. '<font color="rgb(' .. color.R .. ',' .. color.G .. ',' .. color.B .. ')">' .. rarity[1] .. ': <b>' .. rarity[2] .. '%</b></font><br />'
			end
			selectedCrate.RaritiesText.RichText = true
			selectedCrate.RaritiesText.Text = raritiesText
			
			for _, child in pairs(selectedCrate.ItemsList:GetChildren()) do
				if child:IsA("Frame") then
					child:Destroy()
				end
			end
			
			local unboxableItems = crateProperties["Items"]
			table.sort(unboxableItems, function(a, b)
				return 
					(rarityProperties[items:FindFirstChild(a, true).Parent.Name].Order.Value < rarityProperties[items:FindFirstChild(b, true).Parent.Name].Order.Value)
					or (rarityProperties[items:FindFirstChild(a, true).Parent.Name].Order.Value == rarityProperties[items:FindFirstChild(b, true).Parent.Name].Order.Value)
					and (a < b)
			end)
			
			for _, unboxableItemName in pairs(unboxableItems) do
				local newItemFrame = selectedCrateItemTemplate:Clone()
				newItemFrame.ItemName.Text = unboxableItemName
				newItemFrame.ItemName.TextColor3 = rarityProperties[items:FindFirstChild(unboxableItemName, true).Parent.Name].Color.Value
				
				local itemModel = Instance.new("Model")
				
				for _, child in pairs(items:FindFirstChild(unboxableItemName, true):GetChildren()) do
					if not (child:IsA("Script") or child:IsA("LocalScript") or child:IsA("ModuleScript") or child:IsA("Sound")) then
						child:Clone().Parent = itemModel
					end
				end
				
				itemModel:PivotTo(CFrame.new() * CFrame.Angles(math.rad(-39), 0, 0))
				
				itemModel.Parent = newItemFrame.ItemImage
				
				local currentCamera = Instance.new("Camera")
				currentCamera.CFrame = CFrame.new(Vector3.new(-itemModel:GetExtentsSize().Y*0.7, 0, 0), itemModel:GetPivot().Position + Vector3.new(0, -0.1, 0))
				currentCamera.Parent = newItemFrame.ItemImage
				newItemFrame.ItemImage.CurrentCamera = currentCamera
				
				newItemFrame.Parent = selectedCrate.ItemsList
			end
			
			selectedCrate.Visible = true
		end
	end)
	
	table.insert(crateButtons, {newBtn, crateProperties["Price"]})
end

table.sort(crateButtons, function(a, b)
	return (a[2] < b[2]) or (a[2] == b[2] and a[1].Name < b[1].Name)
end)

for _, crateButton in pairs(crateButtons) do
	crateButton[1].Parent = cratesList
end


--Purchasing crates
selectedCrate.UnboxButton.MouseButton1Click:Connect(function()
	if selectedCrate.Visible == true and game.Players.LocalPlayer.leaderstats.Cash.Value >= tonumber(string.sub(selectedCrate.UnboxButton.Text, 2, -1)) then
		remotes:WaitForChild("BuyCrate"):FireServer(selectedCrate.CrateName.Text)
	end
end)


--Unboxing crates
function lerp(a, b, t)
	return a + (b-a) * t
end

function tweenGraph(x, pow)
	x = math.clamp(x, 0, 1)
	return 1 - (1-x)^pow
end


remotes:WaitForChild("CrateOpened").OnClientEvent:Connect(function(crateName, itemChosen, unboxTime)
	
	local crateProperties = require(crates[crateName])
	
	local numItems = rnd:NextInteger(20, 100)
	local chosenPosition = rnd:NextInteger(15, numItems-5)
	
	for i = 1, numItems do
		
		local rarityChosen = itemChosen.Parent.Name
		local randomItemChosen = itemChosen
		
		if i ~= chosenPosition then
			local rndChance = rnd:NextNumber() * 100
			local n = 0
			
			for rarity, chance in pairs(crateProperties["Chances"]) do	
				n += chance
				if rndChance <= n then
					rarityChosen = rarity
					break
				end
			end

			local unboxableItems = crateProperties["Items"]
			for i = #unboxableItems, 2, -1 do
				local j = rnd:NextInteger(1, i)
				unboxableItems[i], unboxableItems[j] = unboxableItems[j], unboxableItems[i]
			end
			
			for _, itemName in pairs(unboxableItems) do
				if items:FindFirstChild(itemName, true).Parent.Name == rarityChosen then
					randomItemChosen = items:FindFirstChild(itemName, true)
					break
				end
			end
		end
		
		local newItemFrame = openingCrateItemTemplate:Clone()
		newItemFrame.ItemName.Text = randomItemChosen.Name
		newItemFrame.ItemName.TextColor3 = rarityProperties[rarityChosen].Color.Value
		
		local itemModel = Instance.new("Model")

		for _, child in pairs(randomItemChosen:GetChildren()) do
			if not (child:IsA("Script") or child:IsA("LocalScript") or child:IsA("ModuleScript") or child:IsA("Sound")) then
				child:Clone().Parent = itemModel
			end
		end

		itemModel:PivotTo(CFrame.new() * CFrame.Angles(math.rad(-39), 0, 0))

		itemModel.Parent = newItemFrame.ItemImage

		local currentCamera = Instance.new("Camera")
		currentCamera.CFrame = CFrame.new(Vector3.new(-itemModel:GetExtentsSize().Y*0.7, 0, 0), itemModel:GetPivot().Position + Vector3.new(0, -0.1, 0))
		currentCamera.Parent = newItemFrame.ItemImage
		newItemFrame.ItemImage.CurrentCamera = currentCamera
		
		newItemFrame.Parent = openedItemsFrame.ItemsContainer
	end
	
	openedItemsFrame.ItemsContainer.Position = UDim2.new(0, 0, 0.5, 0)
	
	local cellSize = openingCrateItemTemplate.Size.X.Scale
	local padding = openedItemsFrame.ItemsContainer.UIListLayout.Padding.Scale
	local pos1 = 0.5 - cellSize/2
	local nextOffset = -cellSize - padding
	
	local posFinal = pos1 + (chosenPosition-1) * nextOffset
	local rndOffset = rnd:NextNumber(-cellSize/2, cellSize/2)
	posFinal += rndOffset
	
	local timeOpened = tick()
	
	openedFrame.CrateName.Text = crateName
	shopFrame.Visible = false
	closeOpenedBtn.Visible = false
	openedFrame.Visible = true
	openedGui.Enabled = true
	
	local pow = rnd:NextNumber(2, 10)
	local lastSlot = 0
	
	while true do
		local timeSinceOpened = tick() - timeOpened
		local x = timeSinceOpened / unboxTime
		
		local t = tweenGraph(x, pow)
		local newXPos = lerp(0, posFinal, t)
		
		local currentSlot = math.abs(math.floor((newXPos+rndOffset)/cellSize))+1
		if currentSlot ~= lastSlot then
			script.TickSound:Play()
			lastSlot = currentSlot
		end
		
		openedItemsFrame.ItemsContainer.Position = UDim2.new(newXPos, 0, 0.5, 0)
		
		if x >= 1 then
			break
		end
		
		game:GetService("RunService").Heartbeat:Wait()
	end
	
	closeOpenedBtn.Visible = true
end)

Script Code

CratesServer

local rs = game:GetService("ReplicatedStorage")
local remotes = rs:WaitForChild("RemoteEvents")
local items = rs:WaitForChild("Items")
local crates = rs:WaitForChild("Crates")

local rnd = Random.new()

local playersUnboxing = {}

local dss = game:GetService("DataStoreService")
local ds = dss:GetDataStore("UNBOXING SYSTEM DATA")


function saveData(plr:Player)

	if not plr:FindFirstChild("DATA FAILED TO LOAD") then
		
		local cash = plr.leaderstats.Cash.Value
		
		local inventory = {}
		for _, item in pairs(plr.StarterGear:GetChildren()) do
			table.insert(inventory, item.Name)
		end
		if playersUnboxing[plr] then
			table.insert(inventory, playersUnboxing[plr])
		end
		
		local compiledData = {
			Cash = cash;
			Inventory = inventory;
		}

		local success, err = nil, nil
		while not success do
			success, err = pcall(function()
				ds:SetAsync(plr.UserId, compiledData)
			end)
			if err then
				warn(err)
			end
			task.wait(0.02)
		end
	end
end


game.Players.PlayerRemoving:Connect(saveData)
game:BindToClose(function()
	for _, plr in pairs(game.Players:GetPlayers()) do
		saveData(plr)
	end
end)

game.Players.PlayerAdded:Connect(function(plr)

	local dataFailedWarning = Instance.new("StringValue")
	dataFailedWarning.Name = "DATA FAILED TO LOAD"
	dataFailedWarning.Parent = plr

	local success, plrData = nil, nil
	while not success do
		success, plrData = pcall(function()
			return ds:GetAsync(plr.UserId)
		end)
		task.wait(0.02)
	end
	dataFailedWarning:Destroy()

	if not plrData then
		plrData = {
			Cash = 30000;
			Inventory = {};
		}
	end
	
	local ls = Instance.new("Folder")
	ls.Name = "leaderstats"
	ls.Parent = plr
	
	local cashValue = Instance.new("IntValue")
	cashValue.Name = "Cash"
	cashValue.Value = plrData.Cash
	cashValue.Parent = ls

	for _, itemName in pairs(plrData.Inventory) do
		local foundItem = items:FindFirstChild(itemName, true)
		
		if foundItem and foundItem.Parent.Parent == items then
			foundItem:Clone().Parent = plr:WaitForChild("StarterGear")
			
			if plr.Character then
				foundItem:Clone().Parent = plr:WaitForChild("Backpack")
			end
		end
	end
end)


remotes:WaitForChild("BuyCrate").OnServerEvent:Connect(function(plr, crateName)
	
	local plrCash = plr.leaderstats.Cash
	
	if crates:FindFirstChild(crateName) and not playersUnboxing[plr] then
		local crateProperties = require(crates[crateName])
		
		if plrCash.Value >= crateProperties["Price"] then
			plrCash.Value -= crateProperties["Price"]
			
			local chances = crateProperties["Chances"]
			local plrChance = rnd:NextNumber() * 100
			
			local n = 0
			local rarityChosen = nil
			
			for rarity, chance in pairs(chances) do	
				n += chance
				if plrChance <= n then
					rarityChosen = rarity
					break
				end
			end
			
			local unboxableItems = crateProperties["Items"]
			
			for i = #unboxableItems, 2, -1 do
				local j = rnd:NextInteger(1, i)
				unboxableItems[i], unboxableItems[j] = unboxableItems[j], unboxableItems[i]
			end
			
			local itemChosen = nil
			
			for _, itemName in pairs(unboxableItems) do
				if items:FindFirstChild(itemName, true).Parent.Name == rarityChosen then
					itemChosen = items:FindFirstChild(itemName, true)
					break
				end
			end
			playersUnboxing[plr] = itemChosen.Name
			
			local unboxTime = rnd:NextNumber(3, 7)
			remotes:WaitForChild("CrateOpened"):FireClient(plr, crateName, itemChosen, unboxTime)
			
			local timeStarted = tick()
			while true do
				if (tick() - timeStarted >= unboxTime) or (not plr.Character) then
					break
				end
				game:GetService("RunService").Heartbeat:Wait()
			end
			
			playersUnboxing[plr] = nil
			
			itemChosen:Clone().Parent = plr:WaitForChild("StarterGear")
			if plr.Character then
				itemChosen:Clone().Parent = plr:WaitForChild("Backpack")
			end
		end
	end
end)

Studio File

Crates Studio.rbxl (89.5 KB)

1 Like

I didn’t find server-side code that adds cash to the player when the crate is opened that may be the reason, I tried to add it by guessing not sure if it will work though

local rs = game:GetService("ReplicatedStorage")
local remotes = rs:WaitForChild("RemoteEvents")
local items = rs:WaitForChild("Items")
local crates = rs:WaitForChild("Crates")

local rnd = Random.new()

local playersUnboxing = {}

local dss = game:GetService("DataStoreService")
local ds = dss:GetDataStore("UNBOXING SYSTEM DATA")


function saveData(plr:Player)

	if not plr:FindFirstChild("DATA FAILED TO LOAD") then

		local cash = plr.leaderstats.Cash.Value

		local inventory = {}
		for _, item in pairs(plr.StarterGear:GetChildren()) do
			table.insert(inventory, item.Name)
		end
		if playersUnboxing[plr] then
			table.insert(inventory, playersUnboxing[plr])
		end

		local compiledData = {
			Cash = cash;
			Inventory = inventory;
		}

		local success, err = nil, nil
		while not success do
			success, err = pcall(function()
				ds:SetAsync(plr.UserId, compiledData)
			end)
			if err then
				warn(err)
			end
			task.wait(0.02)
		end
	end
end


game.Players.PlayerRemoving:Connect(saveData)
game:BindToClose(function()
	for _, plr in pairs(game.Players:GetPlayers()) do
		saveData(plr)
	end
end)

game.Players.PlayerAdded:Connect(function(plr)

	local dataFailedWarning = Instance.new("StringValue")
	dataFailedWarning.Name = "DATA FAILED TO LOAD"
	dataFailedWarning.Parent = plr

	local success, plrData = nil, nil
	while not success do
		success, plrData = pcall(function()
			return ds:GetAsync(plr.UserId)
		end)
		task.wait(0.02)
	end
	dataFailedWarning:Destroy()

	if not plrData then
		plrData = {
			Cash = 30000;
			Inventory = {};
		}
	end

	local ls = Instance.new("Folder")
	ls.Name = "leaderstats"
	ls.Parent = plr

	local cashValue = Instance.new("IntValue")
	cashValue.Name = "Cash"
	cashValue.Value = plrData.Cash
	cashValue.Parent = ls

	for _, itemName in pairs(plrData.Inventory) do
		local foundItem = items:FindFirstChild(itemName, true)

		if foundItem and foundItem.Parent.Parent == items then
			foundItem:Clone().Parent = plr:WaitForChild("StarterGear")

			if plr.Character then
				foundItem:Clone().Parent = plr:WaitForChild("Backpack")
			end
		end
	end
end)


remotes:WaitForChild("BuyCrate").OnServerEvent:Connect(function(plr, crateName)

	local plrCash = plr.leaderstats.Cash

	if crates:FindFirstChild(crateName) and not playersUnboxing[plr] then
		local crateProperties = require(crates[crateName])

		if plrCash.Value >= crateProperties["Price"] then
			plrCash.Value -= crateProperties["Price"]

			local chances = crateProperties["Chances"]
			local plrChance = rnd:NextNumber() * 100

			local n = 0
			local rarityChosen = nil

			for rarity, chance in pairs(chances) do	
				n += chance
				if plrChance <= n then
					rarityChosen = rarity
					break
				end
			end

			local unboxableItems = crateProperties["Items"]

			for i = #unboxableItems, 2, -1 do
				local j = rnd:NextInteger(1, i)
				unboxableItems[i], unboxableItems[j] = unboxableItems[j], unboxableItems[i]
			end

			local itemChosen = nil

			for _, itemName in pairs(unboxableItems) do
				if items:FindFirstChild(itemName, true).Parent.Name == rarityChosen then
					itemChosen = items:FindFirstChild(itemName, true)
					break
				end
			end
			playersUnboxing[plr] = itemChosen.Name

			local unboxTime = rnd:NextNumber(3, 7)
			remotes:WaitForChild("CrateOpened"):FireClient(plr, crateName, itemChosen, unboxTime)
			plr.leaderstats.Cash.Value += require(crates[itemChosen])["Price"] -- added this not sure if it will work
			local timeStarted = tick()
			while true do
				if (tick() - timeStarted >= unboxTime) or (not plr.Character) then
					break
				end
				game:GetService("RunService").Heartbeat:Wait()
			end

			playersUnboxing[plr] = nil

			itemChosen:Clone().Parent = plr:WaitForChild("StarterGear")
			if plr.Character then
				itemChosen:Clone().Parent = plr:WaitForChild("Backpack")
			end
		end
	end
end)

It seems that you aren’t updating plrCash to add the money that the player just unboxed, I only see plrCash being used to deduct the price of the crate from the players money.

I know this is off-topic, but just a heads up that roblox might see this as gambling.