local function Q(Q)if not activePlayer then return end local A=1 if#Q>=1 then A=Q[1]end inRace=true if A and _numLaps==0 then _numLaps=A numCheckpoints=numCheckpoints*_numLaps end for Q,A in ipairs(checkpointList)do local P=A:FindFirstChild("\067\104\101\099\107\112\111\105\110\116")P.Color=NOT_HIT_COLOR local V=A:FindFirstChild("\082\105\110\103")if V then V.Color=NOT_HIT_COLOR end end if not ArrowGuide then ArrowGuide=require(script:WaitForChild("\065\114\114\111\119\071\117\105\100\101"))end arrow=ArrowGuide.new(checkpointList)end local function A(Q)if not(activePlayer and inRace)then return end local A=false if#Q>=1 then A=Q[1]else return end local P=A.Parent local V=P:FindFirstChild("\072\105\116")if not V then V=Instance.new("\066\111\111\108\086\097\108\117\101")V.Name="\072\105\116"V.Parent=P V.Value=true else return end A.Color=HIT_COLOR local x=A.Parent:FindFirstChild("\082\105\110\103")if x then x.Color=HIT_COLOR end local h=checkpointParticle:Clone()local X=player.Character or player.CharacterAdded:wait()h.CFrame=X.PrimaryPart.CFrame h.Parent=X.PrimaryPart local K=h:GetChildren()for Q,A in pairs(K)do if A:IsA("\080\097\114\116\105\099\108\101\069\109\105\116\116\101\114")then A:Emit(10)end end spawn(function()wait(PARTICLE_DURATION)h:Destroy()end)checkpointSound.Parent=A checkpointSound:Play()numCheckpointsHit=numCheckpointsHit+1 CheckpointCount.Text=tostring(numCheckpointsHit)..("\047"..tostring(numCheckpoints))end local function P()if not(activePlayer and inRace)then return end for Q,A in ipairs(checkpointList)do local P=A:FindFirstChild("\067\104\101\099\107\112\111\105\110\116")local V=A:FindFirstChild("\072\105\116")if V then V:Destroy()end P.Color=NOT_HIT_COLOR local x=A:FindFirstChild("\082\105\110\103")if x then x.Color=NOT_HIT_COLOR end end end local function V()inRace=false numCheckpointsHit=0 for Q,A in ipairs(checkpointList)do local P=A:FindFirstChild("\067\104\101\099\107\112\111\105\110\116")local V=A:FindFirstChild("\072\105\116")if V then V:Destroy()end P.Color=HIT_COLOR local x=A:FindFirstChild("\082\105\110\103")if x then x.Color=HIT_COLOR end end arrow:Destroy()CheckpointCount.Text=tostring(numCheckpointsHit)..("\047"..tostring(numCheckpoints))end local function x(Q)local A=false if#Q>=1 then A=Q[1]else return end activePlayer=A if not A and inRace then inRace=false V()end if not A then local Q=player.PlayerGui local A=Q:FindFirstChild("\084\111\112\066\097\114")A.Enabled=false end end local function h()RaceFinishedSound:Play()end local function X(X)for X,K in pairs(X)do if K[1]=="\115\101\116\117\112"then table.remove(K,1)Q(K)elseif K[1]=="\099\104\101\099\107\112\111\105\110\116\072\105\116"then table.remove(K,1)A(K)elseif K[1]=="\110\101\119\076\097\112"then P()elseif K[1]=="\114\101\115\101\116"then V()elseif K[1]=="\115\101\116\065\099\116\105\118\101"then table.remove(K,1)x(K)elseif K[1]=="\114\097\099\101\070\105\110\105\115\104\101\100"then table.remove(K,1)h()end end end
-- ================================================================================
-- LOCAL FUNCTIONS
-- ================================================================================
local function setupCheckpoints(args)
	if not activePlayer then
		return
	end

	local numLaps = 1
	if #args >= 1 then
		numLaps = args[1]
	end

	-- Player is in race
	inRace = true

	-- Set the number of laps in the race and use it to calc the total number
	-- of checkpoints
	if numLaps and _numLaps == 0 then
		_numLaps = numLaps
		numCheckpoints = numCheckpoints * _numLaps
	end

	-- Set up checkpoints (color as not hit)
	for _, checkpoint in ipairs(checkpointList) do
		local checkpointCollisionBody = checkpoint:FindFirstChild("Checkpoint")

		-- Set color of checkpoint
		checkpointCollisionBody.Color = NOT_HIT_COLOR

		-- Set color of checkpoint ring if one exists
		local ring = checkpoint:FindFirstChild("Ring")
		if ring then
			ring.Color = NOT_HIT_COLOR
		end
	end

	if not ArrowGuide then
		ArrowGuide = require(script:WaitForChild("ArrowGuide"))
	end
	arrow = ArrowGuide.new(checkpointList)
end -- setupCheckpoints()

local function checkpointHit(args)
	if not (activePlayer and inRace) then
		return
	end

	local checkpointCollisionBody = false
	if #args >= 1 then
		checkpointCollisionBody = args[1]
	else
		return
	end

	local parent = checkpointCollisionBody.Parent

	-- Mark checkpoint as hit
	local hit = parent:FindFirstChild("Hit")
	if not hit then
		hit = Instance.new("BoolValue")
		hit.Name = "Hit"
		hit.Parent = parent
		hit.Value = true
	else
		-- Checkpoint already hit
		return
	end

	-- Set color of checkpoint
	checkpointCollisionBody.Color = HIT_COLOR

	-- Set color of checkpoint ring if one exists
	local ring = checkpointCollisionBody.Parent:FindFirstChild("Ring")
	if ring then
		ring.Color = HIT_COLOR
	end

	-- Create particle effect
	local particle = checkpointParticle:Clone()
	local character = player.Character or player.CharacterAdded:wait()
	particle.CFrame = character.PrimaryPart.CFrame
	particle.Parent = character.PrimaryPart

	--particle.CFrame = checkpointCollisionBody.CFrame
	--particle.Parent = checkpointCollisionBody

	local emitterChildren = particle:GetChildren()

	for _, child in pairs(emitterChildren) do
		-- If the child is a particle, then cause it to emit
		if child:IsA("ParticleEmitter") then
			child:Emit(10)
		end
	end

	-- Destroy particle after PARTICLE_DURATION seconds
	spawn(function()
		wait(PARTICLE_DURATION)
		particle:Destroy()
	end)

	-- Play checkpoint sound
	checkpointSound.Parent = checkpointCollisionBody
	checkpointSound:Play()

	-- Increment checkpoints hit count
	numCheckpointsHit = numCheckpointsHit + 1

	-- Display checkpoint count
	CheckpointCount.Text = tostring(numCheckpointsHit) .. "/" .. tostring(numCheckpoints)
end -- checkpointHit()

local function newLap()
	if not (activePlayer and inRace) then
		return
	end

	-- Set up checkpoints (color as not hit)
	for _, checkpoint in ipairs(checkpointList) do
		local checkpointCollisionBody = checkpoint:FindFirstChild("Checkpoint")

		-- Delete hit BoolValue
		local hit = checkpoint:FindFirstChild("Hit")
		if hit then
			hit:Destroy()
		end

		-- Set color of checkpoint
		checkpointCollisionBody.Color = NOT_HIT_COLOR

		-- Set color of checkpoint ring if one exists
		local ring = checkpoint:FindFirstChild("Ring")
		if ring then
			ring.Color = NOT_HIT_COLOR
		end
	end
end -- newLap()

local function resetCheckpoints()
	inRace = false
	numCheckpointsHit = 0

	-- Set up checkpoints (color as not hit)
	for _, checkpoint in ipairs(checkpointList) do
		local checkpointCollisionBody = checkpoint:FindFirstChild("Checkpoint")

		-- Delete hit BoolValue
		local hit = checkpoint:FindFirstChild("Hit")
		if hit then
			hit:Destroy()
		end

		-- Set color of checkpoint
		checkpointCollisionBody.Color = HIT_COLOR

		-- Set color of checkpoint ring if one exists
		local ring = checkpoint:FindFirstChild("Ring")
		if ring then
			ring.Color = HIT_COLOR
		end
	end

	arrow:Destroy()

	-- Display checkpoint count
	CheckpointCount.Text = tostring(numCheckpointsHit) .. "/" .. tostring(numCheckpoints)
end -- resetCheckpoints()

local function setActive(args)
	local active = false
	if #args >= 1 then
		active = args[1]
	else
		return
	end

	activePlayer = active

	-- No longer in current race if no longer active
	if not active and inRace then
		inRace = false
		resetCheckpoints()
	end

	if not active then
		-- Hide racing GUIs
		local PlayerGui = player.PlayerGui
		local TopBar = PlayerGui:FindFirstChild("TopBar")
		TopBar.Enabled = false
	end
end -- setActive()

local function raceFinished()
	RaceFinishedSound:Play()
end

local function checkpointEvent(args)
	for _, arg in pairs(args) do
		if arg[1] == "setup" then
			table.remove(arg, 1)
			setupCheckpoints(arg)
		elseif arg[1] == "checkpointHit" then
			table.remove(arg, 1)
			checkpointHit(arg)
		elseif arg[1] == "newLap" then
			newLap()
		elseif arg[1] == "reset" then
			resetCheckpoints()
		elseif arg[1] == "setActive" then
			table.remove(arg, 1)
			setActive(arg)
		elseif arg[1] == "raceFinished" then
			table.remove(arg, 1)
			raceFinished()
		end
	end
end -- checkpointEvent()
