How to make this Laps, checkpoints, and rewarding system more reliable

Hello! I am wondering how I could make this existing code more reliable.

local ch1
local ch2
local ch3
local ch4
local laps
local place = 1
local plrWon
local won = false
local mps = game:GetService("MarketplaceService")
local remote = game.ReplicatedStorage.EndRaceServer

game.Players.PlayerAdded:Connect(function(plr)
	local int = Instance.new("IntValue", game.ServerStorage:WaitForChild("PlayerLaps"))
	int.Name = plr.Name
	int.Value = 1
	local plrFolder = Instance.new("Folder", game:GetService("ServerStorage"):WaitForChild("PlayerCheckpoints"))
	plrFolder.Name = plr.Name
	ch1 = Instance.new("BoolValue")
	ch1.Parent = plrFolder
	ch1.Name = "Ch1"
	ch1.Value = false
	ch2 = Instance.new("BoolValue")
	ch2.Parent = plrFolder
	ch2.Name = "Ch2"
	ch2.Value = false
	ch3 = Instance.new("BoolValue")
	ch3.Parent = plrFolder
	ch3.Name = "Ch3"
	ch3.Value = false
	ch4 = Instance.new("BoolValue")
	ch4.Parent = plrFolder
	ch4.Name = "Ch4"
	ch4.Value = false
	laps = Instance.new("IntValue")
	laps.Parent = plrFolder
	laps.Name = "Laps"
	laps.Value = 1
	plrWon = Instance.new("BoolValue")
	plrWon.Parent = plrFolder
	plrWon.Name = "PlayerWon"
	plrWon.Value = false

	local save = Instance.new("IntValue")
	save.Parent = game:GetService("ServerStorage"):WaitForChild("PlayerSpawnSaves")
	save.Name = plr.Name
	save.Value = 1

	local plrRemote = Instance.new("RemoteEvent")
	plrRemote.Parent = game.ReplicatedStorage
	plrRemote.Name = plr.Name.."Remote"
end)

local map = game.Workspace:WaitForChild("Map")
local checkpoints = map:WaitForChild("Checkpoints")
local lapsReq = map:WaitForChild("MaxLaps").Value
local name = map:WaitForChild("name").Value
local savingCheck = map:WaitForChild("SavingCheckpoints")
local spawns = map:WaitForChild("GoToCheckpoint")

checkpoints:WaitForChild("Check1").Touched:Connect(function(hit)
	if hit.Parent:FindFirstChild("Humanoid") then
		local plr = game.Players:GetPlayerFromCharacter(hit.Parent)
		local plrFolder = game.ServerStorage.PlayerCheckpoints:FindFirstChild(plr.Name)
		if plrFolder then
			local ch1 = plrFolder.Ch1
			local ch2 = plrFolder.Ch2
			local ch3 = plrFolder.Ch3
			local ch4 = plrFolder.Ch4
			if ch4.Value == false then
				ch1.Value = true
				print("Ch1")
			end
		end
	end
end)

checkpoints.Check2.Touched:Connect(function(hit)
	if hit.Parent:FindFirstChild("Humanoid") then
		local plr = game.Players:GetPlayerFromCharacter(hit.Parent)
		local plrFolder = game.ServerStorage.PlayerCheckpoints:FindFirstChild(plr.Name)
		if plrFolder then
			local ch1 = plrFolder.Ch1
			local ch2 = plrFolder.Ch2
			local ch3 = plrFolder.Ch3
			local ch4 = plrFolder.Ch4
			if ch1.Value == true then
				ch2.Value = true
				print("Ch2")
			end
		end
	end
end)

checkpoints.Check3.Touched:Connect(function(hit)
	if hit.Parent:FindFirstChild("Humanoid") then
		local plr = game.Players:GetPlayerFromCharacter(hit.Parent)
		local plrFolder = game.ServerStorage.PlayerCheckpoints:FindFirstChild(plr.Name)
		if plrFolder then
			local ch1 = plrFolder.Ch1
			local ch2 = plrFolder.Ch2
			local ch3 = plrFolder.Ch3
			local ch4 = plrFolder.Ch4
			if ch2.Value and ch1.Value == true then
				ch3.Value = true
				print("Ch3")
			end
		end
	end
end)

checkpoints.Check4.Touched:Connect(function(hit)
	if hit.Parent:FindFirstChild("Humanoid") then
		local plr = game.Players:GetPlayerFromCharacter(hit.Parent)
		local plrFolder = game.ServerStorage.PlayerCheckpoints:FindFirstChild(plr.Name)
		if plrFolder then
			local ch1 = plrFolder.Ch1
			local ch2 = plrFolder.Ch2
			local ch3 = plrFolder.Ch3
			local ch4 = plrFolder.Ch4
			if ch1.Value and ch2.Value and ch3.Value == true then
				ch4.Value = true
				print("Ch4")
			end
		end
	end
end)

checkpoints.EndRace.Touched:Connect(function(plrhit)
	if plrhit.Parent:FindFirstChild("Humanoid") then
		local plr = game.Players:GetPlayerFromCharacter(plrhit.Parent)
		local plrFolder = game.ServerStorage.PlayerCheckpoints:FindFirstChild(plr.Name)
		if plrFolder then
			local ch1 = plrFolder.Ch1
			local ch2 = plrFolder.Ch2
			local ch3 = plrFolder.Ch3
			local ch4 = plrFolder.Ch4
			local laps = plrFolder.Laps
			if ch1.Value and ch2.Value and ch3.Value and ch4.Value then
				if laps.Value >= lapsReq then
					laps.Value = 0
					--if plrWon.Value == false then
					--	plrWon.Value = true
						local plr = game.Players:GetPlayerFromCharacter(plrhit.Parent)
						game.ReplicatedStorage.Finish:FireClient(plr)
						game.ReplicatedStorage.UpdateLeaderboards:FireAllClients(plr, place)
--[[
Points = plr.leaderstats.Points
Wins = RaceData.CasualWins
XP = LevelsSystem.Current

1st place - 500 points, 1 Win, 200 XP
2nd place - 250 points, 150 XP
3rd place - 100 points, 100 XP
4th place - 60 points, 90 XP
5th place - 45 points, 80 XP
6th place - 30 points, 65 XP
7th place - 25 points, 50 XP
8th place - 10 points,  25 XP
]]--

						if place == 1 then
							plr.leaderstats.Points.Value += 500 
							plr.RaceData.CasualWins.Value += 1
							plr.LevelsSystem.Current.Value += 200
							game.ReplicatedStorage.Music:FireClient(plr, "Win")
							game.ReplicatedStorage.SendPoints:FireClient(plr, 500)
							game.ReplicatedStorage.SendXP:FireClient(plr, 200)
							if mps:UserOwnsGamePassAsync(plr.UserId, 12460579) then
								plr.leaderstats.Points.Value += 500 
							end
						elseif place == 2 then
							plr.leaderstats.Points.Value += 250
							plr.LevelsSystem.Current.Value += 150
							game.ReplicatedStorage.Music:FireClient(plr, "Win")
							game.ReplicatedStorage.SendPoints:FireClient(plr, 250)
							game.ReplicatedStorage.SendXP:FireClient(plr, 150)
							if mps:UserOwnsGamePassAsync(plr.UserId, 12460579) then
								plr.leaderstats.Points.Value += 250 
							end
						elseif place == 3 then
							plr.leaderstats.Points.Value += 100
							plr.LevelsSystem.Current.Value += 100
							game.ReplicatedStorage.Music:FireClient(plr, "Win")
							game.ReplicatedStorage.SendPoints:FireClient(plr, 100)
							game.ReplicatedStorage.SendXP:FireClient(plr, 100)
							if mps:UserOwnsGamePassAsync(plr.UserId, 12460579) then
								plr.leaderstats.Points.Value += 100 
							end
						elseif place == 4 then
							plr.leaderstats.Points.Value += 60
							plr.LevelsSystem.Current.Value += 90
							game.ReplicatedStorage.Music:FireClient(plr, "Win")
							game.ReplicatedStorage.SendPoints:FireClient(plr, 60)
							game.ReplicatedStorage.SendXP:FireClient(plr, 90)
							if mps:UserOwnsGamePassAsync(plr.UserId, 12460579) then
								plr.leaderstats.Points.Value += 60 
							end
						elseif place == 5 then
							plr.leaderstats.Points.Value += 45
							plr.LevelsSystem.Current.Value += 80
							game.ReplicatedStorage.Music:FireClient(plr, "Lose")
							game.ReplicatedStorage.SendPoints:FireClient(plr, 45)
							game.ReplicatedStorage.SendXP:FireClient(plr, 80)
							if mps:UserOwnsGamePassAsync(plr.UserId, 12460579) then
								plr.leaderstats.Points.Value += 45 
							end
						elseif place == 6 then
							plr.leaderstats.Points.Value += 30
							plr.LevelsSystem.Current.Value += 65
							game.ReplicatedStorage.Music:FireClient(plr, "Lose")
							game.ReplicatedStorage.SendPoints:FireClient(plr, 30)
							game.ReplicatedStorage.SendXP:FireClient(plr, 65)
							if mps:UserOwnsGamePassAsync(plr.UserId, 12460579) then
								plr.leaderstats.Points.Value += 30 
							end
						elseif place == 7 then
							plr.leaderstats.Points.Value += 25
							plr.LevelsSystem.Current.Value += 50
							game.ReplicatedStorage.SendPoints:FireClient(plr, 25)
							game.ReplicatedStorage.Music:FireClient(plr, "Lose")
							game.ReplicatedStorage.SendXP:FireClient(plr, 50)
							if mps:UserOwnsGamePassAsync(plr.UserId, 12460579) then
								plr.leaderstats.Points.Value += 25 
							end
						elseif place == 8 then
							plr.leaderstats.Points.Value += 10
							plr.LevelsSystem.Current.Value += 25
							game.ReplicatedStorage.SendPoints:FireClient(plr, 10)
							game.ReplicatedStorage.Music:FireClient(plr, "Lose")
							game.ReplicatedStorage.SendXP:FireClient(plr, 25)
							if mps:UserOwnsGamePassAsync(plr.UserId, 12460579) then
								plr.leaderstats.Points.Value += 10 
							end
						end
						place += 1
						laps.Value = 0
					elseif laps.Value == lapsReq - 1 then
						local plr = game.Players:GetPlayerFromCharacter(plrhit.Parent)
						game.ReplicatedStorage.FinalLap:FireClient(plr)
						laps.Value += 1
						ch1.Value = false
						ch2.Value = false
						ch3.Value = false
						ch4.Value = false
					else
						--if plrWon.Value == false then
						laps.Value += 1
						local plr = game.Players:GetPlayerFromCharacter(plrhit.Parent)
						game.ReplicatedStorage.AddPlrLap:FireClient(plr)
						ch1.Value = false
						ch2.Value = false
						ch3.Value = false
						ch4.Value = false
					end
				end
			--end
		end
	end
end)

for i = 0, 100 do
	if savingCheck:FindFirstChild("Save"..i) then
		savingCheck:FindFirstChild("Save"..i).Touched:Connect(function(hit)
			if hit.Parent:FindFirstChild("Humanoid") then
				local char = hit.Parent
				local plr = game.Players:GetPlayerFromCharacter(char)
				if plr then
					local save = game:GetService("ServerStorage"):WaitForChild("PlayerSpawnSaves"):WaitForChild(plr.Name)
					save.Value = i
				end
			end
		end)
	end
end

This code rewards the player their money, xp, and also manages Players laps, and checkpoints.

If you have some questions about the code, please feel free to ask! Thanks, WE

Loads of if-else statements, and a ton of repetition!
We can cut those down by using tables and loops

for i=1, 4 do --loop to create 4 checkpoints
    local checkpoint = Instance.new("BoolValue")
	checkpoint.Parent = plrFolder
	checkpoint.Name = "Ch"..i
	checkpoint.Value = false
end

This will create all the checkpoint data, instead of having Ch1, Ch2, etc…

Next up, regarding the events. We should create a single function that all events can call (this simplifies everything so we don’t have as much copy and paste)

local function onTouched(checkpoint, hit)
    checkpoint = tonumber(checkpoint) -- turning the checkpoint into a number so we can compare later
    local plr = game:GetService("Players"):GetPlayerFromCharacter(hit.Parent)
    if plr then
        local plrFolder = game.ServerStorage.PlayerCheckpoints:FindFirstChild(plr.Name)
        if plrFolder:FindFirstChild("Ch"..(checkpoint-1)) and plrFolder:FindFirstChild("Ch"..(checkpoint-1)) .Value == true then
           plrFolder:FindFirstChild("Ch"..(checkpoint)).Value = true
        elseif checkpoint == 1 then
            plrFolder:FindFirstChild("Ch"..(checkpoint)).Value = true
        end
    end
end

-- We can use a for loop within the checkpoints folder/group for even less repetition
for _, checkpoint in ipairs(checkpoints:GetChildren()) do
    checkpoint.Touched:Connect(function(hit)
        onTouched(checkpoint.Name, hit)
    end
end

Same thing regarding the place award system

local placeRewards = {
    [1] = {Points = 500, Xp = 200}.
    -- etc
}
-- this goes in the after the player finishes 
if placeRewards[place] then
    plr.leaderstats.Points.Value += placeRewards[place].Points
    game.ReplicatedStorage.SendXP:FireClient(plr, placeRewards[place].Xp)
    -- etc, do this for the rest of the data
end

You should get the point of these tables and for loops :stuck_out_tongue: , it’s all about cutting down the copy and paste you have in your code. It makes it easier to edit it (like adding a checkpoint)

1 Like

Everythign works! The only thing is, tonumber() only converts when a string has nothing but numbers, but I managed to make it work with the power of Attributes :wink:

1 Like