CCCPaste

Races Server

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
local ServerStorage = game:GetService("ServerStorage")
local Workspace = game:GetService("Workspace")

local RaceFolder = ReplicatedStorage:WaitForChild("Race")

local RaceMapsFolder = ServerStorage:WaitForChild("RaceMaps")
local RaceMaps = RaceMapsFolder:GetChildren()

local Remotes = ReplicatedStorage:WaitForChild("Remotes")
local Bindables = ReplicatedStorage:WaitForChild("Bindables")

local RaceGUI = RaceFolder:WaitForChild("Race")
local WinGUI = RaceFolder:WaitForChild("Winner")

local RaceConfig = require(ReplicatedStorage:WaitForChild("Configs"):WaitForChild("Races"))

local ChosenMap = nil

local GuiShown = false

local GuiClones = {}
local NotDecided = {}
local FinishedPlayers = {}

local function SpawnGui()
	for _, Player: Player in pairs(Players:GetPlayers()) do
		local GuiClone = RaceGUI:Clone()
		GuiClone.Parent = Player.PlayerGui
		table.insert(GuiClones, GuiClone)
		table.insert(NotDecided, Player)
	end
end

local function SpawnWinnerGui()
	for _, Player in pairs(Players:GetPlayers()) do
		local GuiClone = WinGUI:Clone()

		if #FinishedPlayers >= 3 then
			GuiClone.Frame.First.Icon.Image = Players:GetUserThumbnailAsync(FinishedPlayers[1].UserId, Enum.ThumbnailType.AvatarBust, Enum.ThumbnailSize.Size420x420)
			GuiClone.Frame.First.Title.Text = FinishedPlayers[1].Name

			GuiClone.Frame.Second.Icon.Image = Players:GetUserThumbnailAsync(FinishedPlayers[2].UserId, Enum.ThumbnailType.AvatarBust, Enum.ThumbnailSize.Size420x420)
			GuiClone.Frame.Second.Title.Text = FinishedPlayers[2].Name

			GuiClone.Frame.Third.Icon.Image = Players:GetUserThumbnailAsync(FinishedPlayers[3].UserId, Enum.ThumbnailType.AvatarBust, Enum.ThumbnailSize.Size420x420)
			GuiClone.Frame.Third.Title.Text = FinishedPlayers[3].Name
		elseif #FinishedPlayers == 2 then
			GuiClone.Frame.First.Icon.Image = Players:GetUserThumbnailAsync(FinishedPlayers[1].UserId, Enum.ThumbnailType.AvatarBust, Enum.ThumbnailSize.Size420x420)
			GuiClone.Frame.First.Title.Text = FinishedPlayers[1].Name

			GuiClone.Frame.Second.Icon.Image = Players:GetUserThumbnailAsync(FinishedPlayers[2].UserId, Enum.ThumbnailType.AvatarBust, Enum.ThumbnailSize.Size420x420)
			GuiClone.Frame.Second.Title.Text = FinishedPlayers[2].Name

			GuiClone.Frame.Third:Destroy()
		elseif #FinishedPlayers == 1 then
			GuiClone.Frame.First.Icon.Image = Players:GetUserThumbnailAsync(FinishedPlayers[1].UserId, Enum.ThumbnailType.AvatarBust, Enum.ThumbnailSize.Size420x420)
			GuiClone.Frame.First.Title.Text = FinishedPlayers[1].Name

			GuiClone.Frame.Second:Destroy()
			GuiClone.Frame.Third:Destroy()
		end

		GuiClone.Parent = Player.PlayerGui

		if #FinishedPlayers == 0 then
			GuiClone:Destroy()
		end
	end
end

local function DestroyGui(RemoveAll: boolean)
	if RemoveAll == false then
		for i, v in pairs(NotDecided) do
			local Index = table.find(GuiClones, v.PlayerGui.Race)
			if Index then
				table.remove(NotDecided, table.find(NotDecided, v))
				table.remove(GuiClones, Index)
				v.PlayerGui.Race:Destroy()
			end
		end

		for i, v in pairs(GuiClones) do
			v.Parent:WaitForChild("Top"):WaitForChild("RaceStatus").Text = `Race ending in`
		end
	else
		for i, v in pairs(GuiClones) do
			v:Destroy()
		end

		GuiClones = {}
	end
end

local function DestroyWinGui()
	for _, Player in pairs(Players:GetPlayers()) do
		if Player.PlayerGui:FindFirstChild("Winner") then
			Player.PlayerGui.Winner:Destroy()
		end
	end
end

local function UpdateGuiTimer(RaceInProgress: boolean)
	if RaceInProgress == false then
		for i, v in pairs(GuiClones) do
			if v.Parent:WaitForChild("Top"):WaitForChild("RaceStatus") and v:WaitForChild("Prompt") then
				v.Parent.Top.RaceStatus.Text = `Race starts in {string.format("%02i:%02i", RaceConfig.Timer / 60, RaceConfig.Timer % 60)}`
				v.Prompt.Title.Text = `A race is starting, want to join? ({RaceConfig.Timer})`
			end
		end
	else
		for i, v in pairs(GuiClones) do
			if v.Parent:WaitForChild("Top"):WaitForChild("RaceStatus") and v:WaitForChild("Prompt") then
				v.Parent.Top.RaceStatus.Text = `Race ends in {string.format("%02i:%02i", RaceConfig.InProgressTimer / 60, RaceConfig.InProgressTimer % 60)}`
			end
		end
	end
end

local function StartRace()
	FinishedPlayers = {}
	NotDecided = {}
	GuiShown = false
	ChosenMap.Wall.CanCollide = true
	
	local StartTimer = coroutine.create(RaceConfig.StartTimer)
	coroutine.resume(StartTimer)
end

Remotes.TeleportPlayer.OnServerEvent:Connect(function(Player: Player)
	if Player.Character then
		local Spawns = ChosenMap.SpawnParts:GetChildren()
		local Index = math.random(#Spawns)

		Player.Character:PivotTo(Spawns[Index].CFrame + Vector3.new(0, 2, 0))

		local TableIndex = table.find(NotDecided, Player)
		if TableIndex then
			table.remove(NotDecided, TableIndex)
		end
	end
end)

Remotes.DismissRace.OnServerEvent:Connect(function(Player: Player, GUI: ScreenGui)
	local Index = table.find(GuiClones, GUI)
	if Index then
		table.remove(NotDecided, table.find(NotDecided, Player))
		table.remove(GuiClones, Index)
		GUI:Destroy()
	end
end)

Bindables.StartRace.Event:Connect(function()
	DestroyGui(false)

	local RaceInProgress = coroutine.create(RaceConfig.RaceInProgress)
	coroutine.resume(RaceInProgress)

	local Wall = ChosenMap:WaitForChild("Wall")
	Wall.CanCollide = false
end)

Bindables.FinishRace.Event:Connect(function()
	DestroyGui(true)

	ChosenMap.Parent = RaceFolder

	for _, Player: Player in pairs(Players:GetPlayers()) do
		if Player.PlayerGui:WaitForChild("Top"):WaitForChild("RaceStatus") then
			Player.PlayerGui.Top.RaceStatus.Text = ``
		end
	end

	SpawnWinnerGui()

	if #FinishedPlayers >= 3 then
		FinishedPlayers[1]:WaitForChild("leaderstats"):WaitForChild("Races").Value += 1
		FinishedPlayers[1]:WaitForChild("Gems").Value += 500

		FinishedPlayers[2]:WaitForChild("leaderstats"):WaitForChild("Races").Value += 1
		FinishedPlayers[2]:WaitForChild("Gems").Value += 250

		FinishedPlayers[3]:WaitForChild("leaderstats"):WaitForChild("Races").Value += 1
		FinishedPlayers[3]:WaitForChild("Gems").Value += 100
	elseif #FinishedPlayers == 2 then
		FinishedPlayers[1]:WaitForChild("leaderstats"):WaitForChild("Races").Value += 1
		FinishedPlayers[1]:WaitForChild("Gems").Value += 500

		FinishedPlayers[2]:WaitForChild("leaderstats"):WaitForChild("Races").Value += 1
		FinishedPlayers[2]:WaitForChild("Gems").Value += 250
	elseif #FinishedPlayers == 1 then
		FinishedPlayers[1]:WaitForChild("leaderstats"):WaitForChild("Races").Value += 1
		FinishedPlayers[1]:WaitForChild("Gems").Value += 500
	end
	
	local Intermission = coroutine.create(RaceConfig.Intermission)
	coroutine.resume(Intermission)
end)

local function RandomMap()
	local ChosenMapIndex = math.random(#RaceMaps)
	RaceMaps[ChosenMapIndex].Parent = Workspace
	ChosenMap = RaceMaps[ChosenMapIndex]
end

local function LoadFirstRace()
	RandomMap()
	StartRace()
end

LoadFirstRace()

while task.wait(1) do
	if RaceConfig.Timer > 0 then
		if #RaceMapsFolder:GetChildren() == #RaceMaps then
			RandomMap()
		end

		if GuiShown == false then
			GuiShown = true
			SpawnGui()
		end

		UpdateGuiTimer(false)
	else
		UpdateGuiTimer(true)
		
		ChosenMap.FinishArea.Touched:Connect(function(Hit: BasePart)
			if Hit.Parent then
				local Player = Players:GetPlayerFromCharacter(Hit.Parent)
				if Player then
					if table.find(FinishedPlayers, Player) then
						return
					end
					
					table.insert(FinishedPlayers, Player)
					
					if Player.Character then
						Player.Character:PivotTo(Workspace.SpawnLocation.CFrame + Vector3.new(0, 2, 0))
					end
				end
			end
		end)
	end

	if RaceConfig.Timer <= 0 and RaceConfig.InProgressTimer <= 0 then
		task.wait(5)
		DestroyWinGui()
		
		if RaceConfig.IntermissionTimer <= 0 then
			StartRace()
		end
	end
end