How to make button change text when player has insufficient coins and they try to buy a car

I have a button that fires a remote event and when its fired a server script checks if the player has enough money for the car they want to buy. I want to make it so that if they don’t have enough money, the text on the button changes to say that but I don’t know how to do that with a server script
My code:

game.ReplicatedStorage.DealershipEvents.BuyCar.OnServerEvent:Connect(function(player,Car)
	local Price = game.ServerStorage.ShopCars:FindFirstChild(Car).Price.Value
	local Coins = player.leaderstats.Coins
	if Price and Coins.Value >= Price and player.OwnedCars:FindFirstChild(Car).Value == false then
		Coins.Value = Coins.Value - Price
		player.OwnedCars:FindFirstChild(Car).Value = true
	end
end)

Either you can change the text from server accessing players PlayerGui, or you can send the client a remote event so the player will locally change the text. It’s always better to force client change UI things instead of doing it on server, but it’s possible. Players → PlayerName → PlayerGui → …

Important thing to remember is even if server can change player’s UI, there are some limits, for example listeners, you’re unable to add on click listener to the button from the server side. Server can change UI only visibly.

image
This is server’s view on Player, there you can see his PlayerGui

1 Like

I tried using a remote event and having it fire when there wasn’t enofuh coins and the button was clicked and then having it show that on the client but it didn’t work

You gotta show us the code. I can’t tell you whats wrong.

More of the code is broken so I’m gonna wait until I fix the other part to see if that’s why it isn’t working

You can use Return

Local script:

script.Parent.MouseButton1Click:Connect(function()
	local result = game.ReplicatedStorage.DealershipEvents:WaitForChild('BuyCar'):InvokeServer(player, Car)
	if result == "Sufficient" then
		-- if works change gui text and etc
	else
		--code that says you're extremely poor, try again.
	end

end

Server Script:

game.ReplicatedStorage.DealershipEvents:WaitForChild("BuyCar").OnServerInvoke  =  function(player, car, price) -- change as needed
	if player.leaderstats.Coins >= price then
		-- code to remove coins from player and give car
		return("Sufficient")
	else
		return("Insufficient Funds")
	end
end
1 Like

I can try that but i need to see how to fix the problem where if you don’t have enough money for the car but click the button, the next time you join it’ll say you own the car
If you want me to ill give you the data saving code part

Send the code where it checks if you do not have enough money ServerScript

It doesnt really check if you don’t have the money but checks if you do have it

game.ReplicatedStorage.DealershipEvents.BuyCar.OnServerEvent:Connect(function(player,Car)
	local Price = game.ServerStorage.ShopCars:FindFirstChild(Car).Price.Value
	local Coins = player.leaderstats.Coins
	if Price and Coins.Value >= Price and player.OwnedCars:FindFirstChild(Car).Value == false then
		Coins.Value = Coins.Value - Price
		player.OwnedCars:FindFirstChild(Car).Value = true
	end
end)

Yes, you can use RemoteFunction and return a value.
What you could do is, that after successful buy, you’re gonna return true boolean, if unsuccessful, you’re gonna return a value indicating this error. By this conversation I assume, you’re not very into programming at this time, so you can return a string value with the error message.

game.ReplicatedStorage.DealershipEvents.BuyCar.OnServerInvoke = function(player,Car)
	local Price = game.ServerStorage.ShopCars:FindFirstChild(Car).Price.Value
	local Coins = player.leaderstats.Coins
	if Price and Coins.Value >= Price and player.OwnedCars:FindFirstChild(Car).Value == false then
		Coins.Value = Coins.Value - Price
		player.OwnedCars:FindFirstChild(Car).Value = true
		return true
	end
	return "Insufficient Funds"
end
1 Like

This solution is not very secure. On your server script, I see that you’re accepting price parameter, which is wrong. You never ask a client about the price, since any exploiter could just modify this piece of code, and always provide a price of 1 or 0.
Price must be always defined server-side.

Another wrong practice is checking value by string, which is on client script. Easier and well deterministic solution would be, that server would return an integer indicating the status of purchase. 1 => success, 0 => Insufficient Funds.
In my previous response, I suggested using boolean | string type, where string would be returned only in cases where purchase was unsuccessful.

Okay thank you yeah I haven’t programmed in a while so I’m not used to everything but could i make the return message part change the ui text instead

You have three options.

  • After purchase, you can directly change the button text on player’s UI in the server-script
  • You can use RemoteFunction and return an integer or boolean stating the result of purchase ((1/true) => Success, (0/false) => Failure)
  • You can use RemoteFunction and return true if purchase was success or a string if failure.

I’d recommend using the second option in all use-cases, because this is the most optimal way how to it, since you just send one integer over network, sending as less data as possible is always better.

Server Script:

game.ReplicatedStorage.DealershipEvents.BuyCar.OnServerInvoke = function(player,Car)
	local Price = game.ServerStorage.ShopCars:FindFirstChild(Car).Price.Value
	local Coins = player.leaderstats.Coins
	if Price and Coins.Value >= Price and player.OwnedCars:FindFirstChild(Car).Value == false then
		Coins.Value = Coins.Value - Price
		player.OwnedCars:FindFirstChild(Car).Value = true
		return true
	end
	return false
end

Client Script:

local button = ...
button.Activated:Connect(function()
    local result = game.ReplicatedStorage.DealershipEvents.BuyCar:InvokeServer(Car)
    if result then return end -- We don't need to do anything else if payment was success
    
    button.Text = "No Funds!"
    task.spawn(function() -- Creates new thread
        task.wait(5) -- Waits 5 seconds
        button.Text = "Buy" -- After 5 seconds, set the button text back to its default value
    end)
end)

I made this my button code and it doesn’t work but I feel like I did something wrong should I have the second part of the code in the first part


script.Parent.MouseButton1Down:Connect(function()
	local player = game.Players.LocalPlayer
	local Car = script.Parent.Parent.Car.Value
	if player and script.Parent.Parent.Selected.Value == true then
		game.ReplicatedStorage.DealershipEvents.BuyCar:FireServer(Car)
		if player.OwnedCars:FindFirstChild(Car).Value == true then
			script.Parent.Text = "Car already owned!"
			wait(2)
			script.Parent.Text = "Purchase car"
		end
	end
end)

local button = script.Parent
button.Activated:Connect(function()
local Car = script.Parent.Parent.Car.Value
    local result = game.ReplicatedStorage.DealershipEvents.BuyCar.InvokeServer(Car)
    if result then return end -- We don't need to do anything else if payment was success
    
    button.Text = "Not enough coins!"
    task.spawn(function() -- Creates new thread
        task.wait(2) -- Waits 2 seconds
        button.Text = "Purchase car" -- After 2 seconds, set the button text back to its default value
    end)
end)