Only purchase one item script

Hello again, I am looking to make it so people can only purchase an item once unless that item is removed from their inventory. Below is the code I have already added, I understand some of it might be kind of ugly and or messy so I apologize in advance.

ServiceScript located in ServerScriptService

local serverstorage = game:GetService("ServerStorage")
local buyRemote = game:GetService("ReplicatedStorage").BuyItem

local itemCosts = {
	Item1 = 2,
	Item2 = 4,
	Item3 = 6,
	Item4 = 8,
	Item5 = 10,
}

buyRemote.OnServerEvent:Connect(function(player,item)
	
	local playerPoints = player.leaderstats.Points
	
	if playerPoints.Value < itemCosts[item] then return end
	
	playerPoints.Value -= itemCosts[item]
	
	
	local toolToGive = serverstorage.Tools:FindFirstChild(item)
	local starterGear = player:WaitForChild("StarterGear")
	toolToGive.Parent = player.Backpack
	local Copy = toolToGive:Clone()
	local Copy2 = toolToGive:Clone()
	Copy.Parent = game.ServerStorage.Tools
	Copy2.Parent = starterGear
	if toolToGive.Name == "Item1" then
		toolToGive.Name = "Entry Pass"
		
	end
	if toolToGive.Name == "Item2" then
		toolToGive.Name = "Basketball Pass"

	end
	if toolToGive.Name == "Item3" then
		toolToGive.Name = "Dodgeball Pass"

	end
	if toolToGive.Name == "Item4" then
		toolToGive.Name = "Parkour Pass"

	end
	if toolToGive.Name == "Item5" then
		toolToGive.Name = "Food Discount"

	end
	if Copy2.Name == "Item1" then
		Copy2.Name = "Entry Pass"
	end
	if Copy2.Name == "Item2" then
		Copy2.Name = "Basketball Pass"
	end
	if Copy2.Name == "Item3" then
		Copy2.Name = "Dodgeball Pass"
	end
	if Copy2.Name == "Item4" then
		Copy2.Name = "Parkour Pass"
	end
	if Copy2.Name == "Item5" then
		Copy2.Name = "Food Discount"
	end
	
	
end)

If you can help me figure out how to make it so people can’t spam purchase a bunch of a single item that would be great!

2 Likes

You can try this!

local itemOwnership = {}

local function onItemAdded(item)
local player = game.Players:GetPlayerFromCharacter(item.Parent)
if not player then return end
if itemOwnership[player.UserId] and itemOwnership[player.UserId][item.Name] then
item:Destroy()
else
itemOwnership[player.UserId] = itemOwnership[player.UserId] or {}
itemOwnership[player.UserId][item.Name] = true
end
end

local function onCharacterAdded(character)
character.ChildAdded:Connect(onItemAdded)
for _, item in ipairs(character:GetChildren()) do
onItemAdded(item)
end
end

game.Players.PlayerAdded:Connect(function(player)
player.CharacterAdded:Connect(onCharacterAdded)
end)

Do I add this near the bottom or do I replace it with anything?

You can add it to your code wherever it makes sense, but typically it would be added to the bottom of your code.

It appears to not be working as I can still spam buy items.

you can try adding a timer that limits the frequency of purchases.

The names of the Tool should not be handled as you are doing it, checking if its “Item3” to change its name to Dodgeball Pass.

The names of the Tools in ServerStorage already should be the final name so you dont need to change it.

After that, then check if the tool exist in character or in backpack before to letting player to buy it. If player has the tool just return:

Rebuild the logic on how you are cloning the Tool, you dont need to grab the original Tool in ServerStorage and give it to player and clone it again to return it to ServerStorage.
Since the begining Clone() the tool and give it to player.

If you want to add another Clone to StarterGear so when player dies gets the Tool again, ok, but if you dont remove the Tool from there at certain point, player will have the tool forever on respawn.

local serverstorage = game:GetService("ServerStorage")
local buyRemote = game:GetService("ReplicatedStorage").BuyItem

local itemCosts = {
	Item1 = 2,
	Item2 = 4,
	Item3 = 6,
	Item4 = 8,
	Item5 = 10,
}

buyRemote.OnServerEvent:Connect(function(player,item)
	if player.Character:FindFirstChild(item) or player.Backpack:FindFirstChild(item) then return end
	
	local playerPoints = player.leaderstats.Points
	if playerPoints.Value < itemCosts[item] then return end
	playerPoints.Value -= itemCosts[item]

	local toolToGive = serverstorage.Tools:FindFirstChild(item):Clone()
	local Copy = toolToGive:Clone()
	
	toolToGive.Parent = player.Backpack
	Copy.Parent = player:WaitForChild("StarterGear") -- if you dont remove the tool parented here at some point, player will always have the tool
end)
1 Like

Thank you, this fixed it all. One problem though, if I want to name the items like Entry Pass, how would I put that in the script?

Why you wanna name them inside the Script? if you can name them from the ServerStorage?

The script identifies them as Item1, Item2, etc which means the ones in server storage have to be named Item1, Item 2, etc otherwise it won’t detect the items.

Change the table in script that identifies it as Item1 etc, to:

local itemCosts = {
	["Entry Pass"] = 2,
	["Basketball Pass"] = 4,
	["Dodgeball Pass"] = 6,
	["Parkour Pass"] = 8,
	["Food Discount"] = 10,
}

An error shows up saying attempt to compare number < nil on line 17.

show the script you are using. and the output error. You changed the names of the tools in serverStorage too? make sure theres not loose ends

All the tools names in ServerStorage have been changed.

Script:

local serverstorage = game:GetService("ServerStorage")
local buyRemote = game:GetService("ReplicatedStorage").BuyItem

local itemCosts = {
		["Entry Pass"] = 2,
		["Basketball Pass"] = 4,
		["Dodgeball Pass"] = 6,
		["Parkour Pass"] = 8,
		["Food Discount"] = 10,
	}


buyRemote.OnServerEvent:Connect(function(player,item)
	if player.Character:FindFirstChild(item) or player.Backpack:FindFirstChild(item) then return end

	local playerPoints = player.leaderstats.Points
	if playerPoints.Value < itemCosts[item] then return end
	playerPoints.Value -= itemCosts[item]

	local toolToGive = serverstorage.Tools:FindFirstChild(item):Clone()
	local Copy = toolToGive:Clone()

	toolToGive.Parent = player.Backpack
	Copy.Parent = player:WaitForChild("StarterGear") -- if you dont remove the tool parented here at some point, player will always have the tool
end)

Error code: 06:14:23.278 ServerScriptService.TicketPurchase:17: attempt to compare number < nil - Server - TicketPurchase:17

Probably your client script is not sending the right name, and still sending the Item1 etc
Run this debug and paste in here the output:

local serverstorage = game:GetService("ServerStorage")
local buyRemote = game:GetService("ReplicatedStorage").BuyItem

local itemCosts = {
	["Entry Pass"] = 2,
	["Basketball Pass"] = 4,
	["Dodgeball Pass"] = 6,
	["Parkour Pass"] = 8,
	["Food Discount"] = 10,
}


buyRemote.OnServerEvent:Connect(function(player,item)
	warn("this is the name of the tool that client sent:", item) -- probably your client script is not sending the right name, and still sending the Item1 etc
	warn("this is the table to find that key:")
	print(itemCosts)
	warn("this is the key in question")
	print(itemCosts[item])
	
	if player.Character:FindFirstChild(item) or player.Backpack:FindFirstChild(item) then return end

	local playerPoints = player.leaderstats.Points
	if playerPoints.Value < itemCosts[item] then return end
	playerPoints.Value -= itemCosts[item]

	local toolToGive = serverstorage.Tools:FindFirstChild(item):Clone()
	local Copy = toolToGive:Clone()

	toolToGive.Parent = player.Backpack
	Copy.Parent = player:WaitForChild("StarterGear") -- if you dont remove the tool parented here at some point, player will always have the tool
end)
1 Like

You were right, the client still had it set as Item1, etc. I just fixed it and it’s working beautifully. Thank you again for your help!

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.