So i have an already working script for shop purchases, it is working but its very messy.
Any help needed to make it less messy is appreciated!
However i do need a sanity check to see if the leaderstats value matches with the tool price, also if possible detect if a tool name found in T2 folder matches with the remote event parameter.
local ServerStorage = game:GetService("ServerStorage")
local Tools = ServerStorage:FindFirstChild("T2")
local BAT = Tools:FindFirstChild("Normal Bat")
local CHAINSAW = Tools:FindFirstChild("Chainsaw")
local Katana = Tools:FindFirstChild("Katana")
local EVENTS = ReplicatedStorage:FindFirstChild("PurchaseEVENTS")
local PURCAHSE = EVENTS:FindFirstChild("Normal Shop")
local Room = game.Workspace.Map["Map Rooms"]["main hallway"]
local Minimum = 10
PURCAHSE:FindFirstChild("Bat").OnServerEvent:Connect(function(Player)
local Character = Player.Character
local Close = Room:FindFirstChild("Shop22")
local Distance = (Character.HumanoidRootPart.Position - Close.Position).magnitude
if Character and Distance <= Minimum then
if Player.Backpack:FindFirstChild("Normal Bat") then
return
end
if Player:WaitForChild("leaderstats"):FindFirstChild("TIX").Value >= 1 then
BAT:Clone().Parent = Player.Backpack
end
else return
end
end)
PURCAHSE:FindFirstChild("Katana").OnServerEvent:Connect(function(Player)
local Character = Player.Character
local Close = Room:FindFirstChild("Shop22")
local Distance = (Character.HumanoidRootPart.Position - Close.Position).magnitude
if Character and Distance <= Minimum then
if Player.Backpack:FindFirstChild("Katana") then
return
end
if Player:WaitForChild("leaderstats"):FindFirstChild("TIX").Value >= 720 then
Katana:Clone().Parent = Player.Backpack
end
else return
end
end)
PURCAHSE:FindFirstChild("Chainsaw").OnServerEvent:Connect(function(Player)
local Character = Player.Character
local Close = Room:FindFirstChild("Shop22")
local Distance = (Character.HumanoidRootPart.Position - Close.Position).magnitude
if Character and Distance <= Minimum then
if Player.Backpack:FindFirstChild("Katana") then
return
end
if Player:WaitForChild("leaderstats"):FindFirstChild("TIX").Value >= 890 then
CHAINSAW:Clone().Parent = Player.Backpack
end
else return
end
end)
How i fire every single remote event
local buy = script.Parent.Parent.Purchase
local item = script.Parent.Parent.Purchase.CurrentValue
local player = game.Players.LocalPlayer
buy.MouseButton1Click:Connect(function()
local Leaderstats = game.Players.LocalPlayer.leaderstats.TIX.Value
if Leaderstats > 890 then -- TOOL PRICE
if script.Parent.Parent.Purchase.CurrentValue.Value == "Chainsaw" then
if player == game.Players.LocalPlayer then
game.ReplicatedStorage.PurchaseEVENTS["Normal Shop"].Chainsaw:FireServer()
end
end
end
end)
All your function definitions are duplicates except for the item name and cost in TIX, so you could do something like:
--other declarations
--[...]
local prices = {["Bat"] = 1, ["Katana"] = 720, ["Chainsaw"] = 890}
--let "Purchase" be a remote event in "PURCASHE"
PURCASHE:WaitForChild("Purchase").OnServerEvent:connect(function(ply, itemName)
if not (table.find(prices, itemName) and Tools:FindFirstChild(itemName)) then return end
--Assert you have a price and an instance of the tool name
local Close = Room:FindFirstChild("Shop22")
--If this is a constant everywhere, consider moving the variable declaration outside of the function
if (ply.Backpack:FindFirstChild(itemName)) or not (ply:WaitForChild("leaderstats"):WaitForChild("TIX").Value >= prices[itemName] and (ply.Character.PrimaryPart.CFrame.Position - Close.Position).Magnitude <= Minimum) then return end
--Assert the player has enough money and is close enough, and that they don't already have the item.
--prices[itemName] for "Katana" would be prices["Katana"] == prices.Katana = 720
Tools[itemName]:Clone().Parent = Player.Backpack
--Since we asserted itemName is a child of tools, it can be table referenced without a variable
end)
Then the client would have an additional parameter to be responsible for:
local buy = script.Parent.Parent:WaitForChild("Purchase")
local item = buy:WaitForChild("CurrentValue")
buy.MouseButton1Click:Connect(function()
game:GetService("ReplicatedStorage"):WaitForChild("PurchaseEVENTS"):WaitForChild("Normal Shop"):WaitForChild("Purchase"):FireServer(item.Value)
--if item.Value == "Chainsaw" this fires to the server the player clicked the chainsaw.
end)
You don’t need to verify on the client that they are the local player, as there’s no other way a localscript would be running. The player doesn’t have to check they have enough money unless you’re concerned about exhausting the remote event limit and want to save the server a little processing time.
I get which item they are buying with a stringvalue that is found inside a textbutton and the price is usually defined on the script, is it ideal touse numbervalues to define prices just like the tool name stringvalue?
Edit: nvm the server script handles the prices!
Hmm, i seem to be having an issue, i tried to debug the script but it only prints that i fired the server and nothing else
local prices = {["Bat"] = 1, ["Katana"] = 720, ["Chainsaw"] = 890}
local PURCASHE = game:GetService("ReplicatedStorage"):WaitForChild("PurchaseEVENTS"):WaitForChild("Normal Shop")
local Tools = game.ServerStorage.T2
local Minimum = 22
--let "Purchase" be a remote event in "PURCASHE"
PURCASHE:WaitForChild("Purchase").OnServerEvent:connect(function(ply, itemName)
print("Player Fired Server")
if not (table.find(prices, itemName) and Tools:FindFirstChild(itemName)) then return end
print("Got tool name and price")
local Close = Room:FindFirstChild("Shop22")
if (ply.Backpack:FindFirstChild(itemName)) or not (ply:WaitForChild("leaderstats"):WaitForChild("TIX").Value >= prices[itemName] and (ply.Character.PrimaryPart.CFrame.Position - Close.Position).Magnitude <= Minimum) then return end
print("Player is close to shop therefore should be earning their item")
Tools[itemName]:Clone().Parent = Player.Backpack
end)
Try replacing your first print statement with this: print(string.format("%s wants to purchase a(n) %s.", ply.Name, tostring(itemName))
To see that itemName is properly what you expect, like Katana, Chainsaw, Bat. If the string isn’t arriving the following assertion will fail and return before the “Got tool name…” print.
You could also follow along the logic of the first assertions with: print(string.format("%s %s a price!", itemName, table.find(prices, itemName) and "has" or "does not have")
and: print(string.format("%s %s exist within the Tools folder!", itemName, Tools:FindFirstChild(itemName) and "does" or "does not")
The result for first print statement.
Nothing else prints.
PURCASHE:WaitForChild("Purchase").OnServerEvent:connect(function(ply, itemName)
print(string.format("%s wants to purchase a(n) %s.", ply.Name, tostring(itemName)))
if not (table.find(prices, itemName) and Tools:FindFirstChild(itemName)) then return end
print(string.format("%s %s a price!", itemName, table.find(prices, itemName) and "has" or "does not have"))
local Close = Room:FindFirstChild("Shop22")
if (ply.Backpack:FindFirstChild(itemName)) or not (ply:WaitForChild("leaderstats"):WaitForChild("TIX").Value >= prices[itemName] and (ply.Character.PrimaryPart.CFrame.Position - Close.Position).Magnitude <= Minimum) then return end
print("Player is close to shop therefore should be earning their item")
Tools[itemName]:Clone().Parent = Player.Backpack
end)
Is it possible to use string.match instead of table.find?
Ok, so that first assertion is failing, and the function is returning before any other lines are ran.
That means either table.find(prices, itemName) and/or Tools:FindFirstChild(itemName) is evaluating to False.
Here’s why it’s not working: I wrote it wrong, woops
table.find() is used to find an index given value… so we actually need to check if not (prices[itemName] and Tools:FindFirstChild(itemName)) then return end
to see if itemName is a key in prices rather than a value. My bad, let me know if that fixes it
Right so that print statement I wrote wrong too, it should be prices[itemName] instead of table.find(...) there as well.
For character, try local char = (ply.Character or ply.CharacterAdded:Wait())
then that comparison to where they are would be char.PrimaryPart.Position
It’s a logical operation making sure both of those operators evaluate true. If they don’t, the function returns (leaves and doesn’t run the rest)
Ideally this evaluates to: if not (true and true) → if not true → if false → the return is skipped, and the function moves on.
For this to happen, prices[itemName] must return true. If itemName is Chainsaw, prices["Chainsaw"] is seeing if there is a key named “Chainsaw” in the dictionary “prices.” Since there is, it returns the value, 890, and 890 in boolean is True. Thus, prices["Chainsaw"] = True
Tools:FindFirstChild(itemName) must also be true. FindFirstChild returns the instance if it exists, or nil if it does not. Nil in boolean is False. If itemName is “Chainsaw”, and there is an instance of that name within Tools, that function returns an instance, which in boolean is True. Thus, Tools:FindFirstChild("Chainsaw") = True