Buying and Equipping Tools From A Shop

Hello, I am working on a shop for a combat system. I would like the player to only be able to equip one weapon at a time, but always have one equipped. I plan on adding extra equipment/tools like power-ups and grenades, so I can’t just clear the player’s backpack. My current script allows players to buy weapons and it clones it from replicatedstorage and brings it to the players backpack. This means that they can buy multiple of the same tool. Only restriction is if they have a sufficient amount of cash to buy the weapon, and if they don’t a GUI pops up asking them to give me their money. How can I add something to detect whether the tool has been purchased before, even if it isn’t in their inventory? (for later on when it isn’t in their inv.)This is even more necessary because I need to be able to toggle off the buy button and toggle on an equip button. Sorry if my wording was a bit off, I can clarify if you need me to.
current code for the purchase handling script:

local player = game.Players.LocalPlayer
local camera = workspace.CurrentCamera


script.Parent.Buy.MouseButton1Click:Connect(function()
if camera.CFrame == workspace.Cameras.Camera2.CFrame and player.leaderstats.Cash.value >= 1000 then
	player.leaderstats.Cash.Value = player.leaderstats.Cash.Value - 1000

	game.ReplicatedStorage.Sword:Clone().Parent = player:WaitForChild("Backpack")

else if player.leaderstats.Cash.Value < 1000 then
		script.Parent.broke.Visible = true
		
			else if camera.CFrame == workspace.Cameras.Camera3.CFrame and player.leaderstats.Cash.value >= 2500 then
				player.leaderstats.Cash.Value = player.leaderstats.Cash.Value - 2500
			
				game.ReplicatedStorage.Longsword:Clone().Parent = player:WaitForChild("Backpack")
			
				else if player.leaderstats.Cash.Value < 2500 then
				script.Parent.broke.Visible = true
			end
		end
	end
end
end)
5 Likes

I would like a shop too, but I am not going to make one because I don’t have any game to put it in and I’m not good at coding.

1 Like

i figured it out, and its really simple. Add in a new local value named something like ownedsword = false, and make sure as an if statement requirement it is false. It will be false the first time, then you toggle it true in the function after where it gives the player the cloned sword. They can’t buy it twice now.

1 Like

So the first issue I see is that your not using remote events to handle the replicating of the object along with purchasing, essentially when you clone things inside of the client it doesn’t show up for other players and same with taking away cash. > Remote Events

Also your code appears to be a little jumbled up. So its a bit hard to read, however I can see that you want to detect if the player is at a certain camera. I would go about that doing something like this and this is not the most secure method so keep that in mind:

--[[
Create a remote event in replicatedstorage named "PurchaseEvent"
]]--
---//Client//--- leave this in your normal local script
local player = game.Players.LocalPlayer
local camera = workspace.CurrentCamera
local cash = player.leaderstats.Cash
local purchase = game.ReplicatedStorage:WaitForChild("PurchaseEvent")
local cameras = workspace.Cameras


script.Parent.Buy.MouseButton1Click:Connect(function()
	if camera.CFrame == camera.Camera2.CFrame and cash.Value >= 1000 then
		purchase:FireServer(1000, "Sword")  -- send through (cash amount, item)
	elseif camera.CFrame == camera.Camera3.CFrame and cash.Value >= 2500 then
		purchase:FireServer(2500, "longword") -- send through (cash amount, item)
	else
		spawn(function() -- this just makes it not slow down the clicking
			script.Parent.Broke.Visible = true
			wait(.5)
			script.Parent.Broke.Visible = false
		end)
	end
end)

---//Server//--- Put into a serverscript inside of serverscriptservice
local purchase = game.ReplicatedStorage:WaitForChild("PurchaseEvent")

purchase.OnServerEvent:connect(function(player, amount, item)
    player.leaderstats.Cash.Value = player.leaderstats.Cash.Value - amount
    game.ReplicatedStorage:FindFirstChild(item):Clone().Parent = player.Backpack
end)

Let me know if you have any issues understanding, thank you.

1 Like

Now there is no limit to how many times each item can be bought. I was hoping they could purchase it only once, and then I would have to figure out a way to make it so that the equip button is only visible when their current camera is in the CFrame of an item they own (I guess would be the best approach for it.)

Would it be the same way that I did above? And how can I make it so that I only have to use one button for the whole thing, instead of copying and pasting the same button over and over for different items?

so the way I would do this is like you said not copying and pasting the same code, I would get all of the cameras inside of the cameras folder and then put inside of those cameras a String Value for the name of the item, a Number Value for the cash amount, it would be something like this;
image
after having done that, inside the script you could do something like this;
This is an example for the client

script.Parent.Buy.MouseButton1Click:Connect(function()
  for i, v in pairs(cameras:GetChildren()) do
    if camera.CFrame == v.CFrame then 
         --I would make sure the cash check is not in the client because its not secure
         --We will handle the checking through the server so they cant buy it twice
        purchase:FireServer(v.Cost.Value, v.Toolname.Value)
    end
  end
end)

This is an example for the server

local purchase = game.ReplicatedStorage:WaitForChild("PurchaseEvent")

purchase.OnServerEvent:connect(function(player, amount, item)
    if player.leaderstats.Cash.Value >= amount and not player.Character:FindFirstChild(item) and not player.Backpack:FindFirstChild(item) then
        --Checks their cash amount through the server the make sure its >= the amount
        --Checks their character and their backpack to make sure its not there
        player.leaderstats.Cash.Value = player.leaderstats.Cash.Value - amount
        game.ReplicatedStorage:FindFirstChild(item):Clone().Parent = player.Backpack
    end
end)

I am not sure if this clears anything up, just make sure you use remote events because an exploiter can give themselves 100000+ cash and buy everything. Remote events for the most part keep that from happening and are much more secure.

I forgot to add this but if you want to equip or unequip, use an if statement to check if the tool is or isnt inside the player, these are what you would use to unequip or equip tools; player.Character.Humanoid:UnequipTools(player.Character.Sword),
player.Character.Humanoid:EquipTool(player.Character.Sword).
make sure to use a remote event for equiping and unequiping because again the other players will not be able to see or be damaged by them.
Just an example from the client:

local Tool = "Sword"
local Equip = true
game.ReplicatedStorage.toolEquipper:FireServer(Tool, Equip)

example from the server

game.ReplicatedStorage.toolEquipper.OnServerEvent:connect(function(player, tool, equip)
    if equip then --Equip is true so lets equip the tool
        if player.Backpack:FindFirstChild(tool) then -- if the tool is inside the backpack then continue
           --lets unequip the other tools
           for i, v in pairs(player.Character:GetChildren()) do
               if v:IsA("Tool") then
                   player.Character.Humanoid:UnequipTools(v)
               end
           end
            --this will equip the players tool from their backpack
            player.Character.Humanoid:EquipTool(tool)
        end
    else --They dont want to equip this tool so lets unequip it 
        --Unequip the tool
        for i, v in pairs(player.Character:GetChildren()) do -- since the player can only have 1 tool at a time, we can still use this just to make sure all the tools are unequipped.
            if v:IsA("Tool") then
               player.Character.Humanoid:UnequipTools(v)
            end
        end
    end
end)

in my case, I want to make sure that it is specifically a weapon that is being unequipped. I would like to have other tools that are not really main weapons like the swords. For instance, a player can equip a sword but also have a health potion in their inventory. Also, how can i make the buy button turn into an equip button? (only using 2 buttons, instead of 2 for each item?)

perhaps I can add a bool value inside of all of the tools and mark it true if it is a weapon and false if it isn’t, or just put it in the weapons and check if it exists before removing them

its a matter of checking inside the player. a robust way of it would be “If the selected weapon is inside of the character then make it unequip it” and vise versa. When a player equips a weapon on the hotbar, it moves it into the character. And when they unselected it from the hotbar, it goes into the backpack.

Thank you for your help! I will mark the solution after I have everything working, so if I encounter a problem I can ask again.

My current code looks like post 5 from this topic. I came back and I need to be refreshed on what the heck is going on, and here are some notes I made about equipping the item.

Using an if statement, find which camera a player is at and if they own the according item or find which item it is and if they already have it equipped. Toggle visible false for the buy button while at that camera’s CFrame. This is where it needs to be decided whether the equipped text should be displayed or the equip button.

Does this seem reasonable? And to make the code look more like post 6, do I need to add/change things? It looks like you are using a new remote event called toolEquipper, which I don’t have. Just very confused, because obviously I am not good at scripting lol.

Edit: I just thought about it, what if I added a folder to hold the player’s cloned weapons inside of the character/player and moved them each time they equipped a different weapon?

Post #6 should be in a seperate server script with a seperate remote event. The local script should end up looking like this, modified from post #5:

script.Parent.Buy.MouseButton1Click:Connect(function()
  for i, v in pairs(cameras:GetChildren()) do
    if camera.CFrame == v.CFrame and not player.Backpack:FindFirstChild(v.Toolname.Value) and not player.Character:FindFirstChild(v.Toolname.Value) then 
--Add this if statement, because the remote event already make sure that there is an item in the backpack or character this will do anything bad.
        purchase:FireServer(v.Cost.Value, v.Toolname.Value)
      elseif camera.CFrame == v.CFrame and player.Backpack:FindFirstChild(v.Toolname.Value) or player.Character:FindFirstChild(v.Toolname.Value) then 
        if script.Parent.Text ~= "Equipped" then
           script.Parent.Text = "Equipped"
           script.Parent.BackgroundColor3 = BrickColor.Red().Color
           game.ReplicatedStorage.toolEquipper:FireServer(v.Toolname, true) -- Equiptool
        else
           script.Parent.Text = "Equip"  
           script.Parent.BackgroundColor3 = BrickColor.Green().Color
           game.ReplicatedStorage.toolEquipper:FireServer(v.Toolname, false) -- Unequiptool    
        end
    end
  end
end)

this should be all the local script needs, I will still be on if you need more help.

Don’t send the cash client sided, hackers can falsely write data like this and get money:

purchase:FireServer(-93837392778393873, nil)

It would be better if the prices get stored in the server, like in a table. And you could only Fire the sword name, and in the server check if the player have the enough cash to buy it, that’s called “Sanity Checks” Thanks for reading.

That is true, I was aware it was unsecured but for the case of examples I made it very robust and simple. More or less an idea of what happening. Thank you anyways though! :+1:

toe_s a better way to do this is fire the camera through the server and check for the Amount via server, I should have done that in the first place.

if you could elaborate on what you mean by this that would be great.
On a side note, I made it so a new folder is created under the player called ownedtools which is where the tools will be stored. I also made it so when you buy the weapons, they immediately go there instead of the player’s backpack. So, I now need to add a way for the player to click the equip button, that appears instead of the buy button after purchasing, so that the tool goes into their backpack. I don’t know where to put it because all of this bouncing back and forth between scripts :confused:

–[[
Create a remote event in replicatedstorage named “PurchaseEvent”
]]–
—//Client//— leave this in your normal local script
local player = game.Players.LocalPlayer
local camera = workspace.CurrentCamera
local cash = player.leaderstats.Cash
local purchase = game.ReplicatedStorage:WaitForChild(“PurchaseEvent”)
local cameras = workspace.Cameras

LOCAL SCRIPT
script.Parent.BuyButton.MouseButton1Click:Connect(function()
for i, v in pairs(cameras:GetChildren()) do
if camera.CFrame == v.CFrame and not player.Backpack:FindFirstChild(v.Toolname.Value) and not player.Character:FindFirstChild(v.Toolname.Value) then
–Add this if statement, because the remote event already make sure that there is an item in the backpack or character this will do anything bad.
purchase:FireServer(v.Cost.Value, v.Toolname.Value)
script.Parent.BuyButton.Visible = false
script.Parent.Equip.Visible = true
elseif camera.CFrame == v.CFrame and player.Backpack:FindFirstChild(v.Toolname.Value) or player.Character:FindFirstChild(v.Toolname.Value) then
if script.Parent.Equip.Text ~= “Equipped” then
script.Parent.Equip.Text = “Equipped”
script.Parent.Equip.BackgroundColor3 = BrickColor.Red().Color
game.ReplicatedStorage.toolEquipper:FireServer(v.Toolname, true) – Equiptool
else
script.Parent.Equip.Text = “Equip”
script.Parent.BackgroundColor3 = BrickColor.Green().Color
game.ReplicatedStorage.toolEquipper:FireServer(v.Toolname, false) – Unequiptool
end
end
end
end)

SERVERSCRIPT
local purchase = game.ReplicatedStorage:WaitForChild(“PurchaseEvent”)

purchase.OnServerEvent:connect(function(player, amount, item)
if player.leaderstats.Cash.Value >= amount and not player.Character:FindFirstChild(item) and not player.Backpack:FindFirstChild(item) then
–Checks their cash amount through the server the make sure its >= the amount
–Checks their character and their backpack to make sure its not there
player.leaderstats.Cash.Value = player.leaderstats.Cash.Value - amount
game.ReplicatedStorage:FindFirstChild(item):Clone().Parent = player.ownedtools

end

end)

game.Players.PlayerAdded:Connect(function(player)
local ownedtools = Instance.new(“Folder”, player)
ownedtools.Name = “ownedtools”
end)

I apologize about formatting it is acting glitchy for me…

why dont you just clone the tool into the backpack and the owned items? That way you can just check if its in the owned items.

The only thing you would need to check in the if statements is if player.OwnedItems:FindFirstChild(tool).

My mind is boggled. Can you explain/show me what you mean by adding/correcting the code above?

Hmmm, I can understand how your confused :sweat_smile:
The only other way I could help explain is if you showed me your scripts individually with of course the code block format so its easier to read.

local script

local player = game.Players.LocalPlayer
local camera = workspace.CurrentCamera
local cash = player.leaderstats.Cash
local purchase = game.ReplicatedStorage:WaitForChild("PurchaseEvent")
local cameras = workspace.Cameras


script.Parent.BuyButton.MouseButton1Click:Connect(function()
  for i, v in pairs(cameras:GetChildren()) do
if camera.CFrame == v.CFrame and not player.Backpack:FindFirstChild(v.Toolname.Value) and not     player.Character:FindFirstChild(v.Toolname.Value) then 
    purchase:FireServer(v.Cost.Value, v.Toolname.Value)
	script.Parent.BuyButton.Visible = false
	script.Parent.Equip.Visible = true
  elseif camera.CFrame == v.CFrame and player.Backpack:FindFirstChild(v.Toolname.Value) or player.Character:FindFirstChild(v.Toolname.Value) then 
    if script.Parent.Equip.Text ~= "Equipped" then
       script.Parent.Equip.Text = "Equipped"
       script.Parent.Equip.BackgroundColor3 = BrickColor.Red().Color
       game.ReplicatedStorage.toolEquipper:FireServer(v.Toolname, true)
    else
       script.Parent.Equip.Text = "Equip"  
       script.Parent.BackgroundColor3 = BrickColor.Green().Color
       game.ReplicatedStorage.toolEquipper:FireServer(v.Toolname, false)  
        end
    end
  end
end)