Pinkstack/roblox-luau-corpus-text huggingface dataset:
-------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------


function onRunning(speed)
if speed>0.01 then
if Figure and Humanoid and Humanoid.WalkSpeed<17 then
playAnimation("walk", 0.1, Humanoid);
elseif Figure and Humanoid and Humanoid.WalkSpeed>17 then
playAnimation("run", 0.1, Humanoid);
end;
if currentAnimInstance and currentAnimInstance.AnimationId == "http://www.roblox.com/asset/?id=180426354" then
setAnimationSpeed(speed / 14.5)
end
pose = "Running"
else
playAnimation("idle", 0.1, Humanoid)
pose = "Standing"
end
end
function onDied()
pose = "Dead"
end
function onJumping()
playAnimation("jump", 0.1, Humanoid)
jumpAnimTime = jumpAnimDuration
pose = "Jumping"
end
function onClimbing(speed)
playAnimation("climb", 0.1, Humanoid)
setAnimationSpeed(speed / 12.0)
pose = "Climbing"
end
function onGettingUp()
pose = "GettingUp"
end
function onFreeFall()
if (jumpAnimTime <= 0) then
playAnimation("fall", fallTransitionTime, Humanoid)
end
pose = "FreeFall"
end
function onFallingDown()
pose = "FallingDown"
end
function onSeated()
pose = "Seated"
end
function onPlatformStanding()
pose = "PlatformStanding"
end
function onSwimming(speed)
if speed>0 then
pose = "Running"
else
pose = "Standing"
end
end

function getTool()
for _, kid in ipairs(Figure:GetChildren()) do
if kid.className == "Tool" then return kid end
end
return nil
end

function getToolAnim(tool)
for _, c in ipairs(tool:GetChildren()) do
if c.Name == "toolanim" and c.className == "StringValue" then
return c
end
end
return nil
end

function animateTool()

if (toolAnim == "None") then
playToolAnimation("toolnone", toolTransitionTime, Humanoid)
return
end

if (toolAnim == "Slash") then
playToolAnimation("toolslash", 0, Humanoid)
return
end

if (toolAnim == "Lunge") then
playToolAnimation("toollunge", 0, Humanoid)
return
end
end

local lastTick = 0

function move(time)
local amplitude = 1
local frequency = 1
  local deltaTime = time - lastTick
  lastTick = time

local climbFudge = 0
local setAngles = false

  if (jumpAnimTime > 0) then
  jumpAnimTime = jumpAnimTime - deltaTime
  end

if (pose == "FreeFall" and jumpAnimTime <= 0) then
playAnimation("fall", fallTransitionTime, Humanoid)
elseif (pose == "Seated") then
playAnimation("sit", 0.5, Humanoid)
return
elseif (pose == "Running") then
if Figure and Humanoid and Humanoid.WalkSpeed<17 then
playAnimation("walk", 0.1, Humanoid);
elseif Figure and Humanoid and Humanoid.WalkSpeed>17 then
playAnimation("run", 0.1, Humanoid);
end;
elseif (pose == "Dead" or pose == "GettingUp" or pose == "FallingDown" or pose == "Seated" or pose == "PlatformStanding") then
stopAllAnimations()
amplitude = 0.1
frequency = 1
setAngles = true
end
if (setAngles) then

end
--[[
	A mapping of ZoneIds to UILayers used for setting up zone connections to open corresponding shop UI
--]]



local ReplicatedStorage = game:GetService("ReplicatedStorage")

local UILayerId = require(ReplicatedStorage.Source.SharedConstants.UILayerId)
local ZoneIdTag = require(ReplicatedStorage.Source.SharedConstants.CollectionServiceTag.ZoneIdTag)

local UILayerIdByZoneId: { [ZoneIdTag.EnumType]: UILayerId.EnumType } = {
	[ZoneIdTag.InShop] = UILayerId.SeedMarket,
	[ZoneIdTag.InGardenStore] = UILayerId.GardenStore,
}

return UILayerIdByZoneId
-- New ProfileStore:



function ProfileService.GetProfileStore(profile_store_index, profile_template) --> [ProfileStore]
	
	local profile_store_name
	local profile_store_scope = nil
	
	-- Parsing profile_store_index:
	if type(profile_store_index) == "string" then
		-- profile_store_index as string:
		profile_store_name = profile_store_index
	elseif type(profile_store_index) == "table" then
		-- profile_store_index as table:
		profile_store_name = profile_store_index.Name
		profile_store_scope = profile_store_index.Scope
	else
		error("[ProfileService]: Invalid or missing profile_store_index")
	end
	
	-- Type checking:
	if profile_store_name == nil or type(profile_store_name) ~= "string" then
		error("[ProfileService]: Missing or invalid \"Name\" parameter")
	elseif string.len(profile_store_name) == 0 then
		error("[ProfileService]: ProfileStore name cannot be an empty string")
	end
	
	if profile_store_scope ~= nil and (type(profile_store_scope) ~= "string" or string.len(profile_store_scope) == 0) then
		error("[ProfileService]: Invalid \"Scope\" parameter")
	end

	if type(profile_template) ~= "table" then
		error("[ProfileService]: Invalid profile_template")
	end

	local profile_store
	profile_store = {
		Mock = {
			LoadProfileAsync = function(_, profile_key, not_released_handler)
				return profile_store:LoadProfileAsync(profile_key, not_released_handler, UseMockTag)
			end,
			GlobalUpdateProfileAsync = function(_, profile_key, update_handler)
				return profile_store:GlobalUpdateProfileAsync(profile_key, update_handler, UseMockTag)
			end,
			ViewProfileAsync = function(_, profile_key)
				return profile_store:ViewProfileAsync(profile_key, UseMockTag)
			end,
			WipeProfileAsync = function(_, profile_key)
				return profile_store:WipeProfileAsync(profile_key, UseMockTag)
			end
		},

		_profile_store_name = profile_store_name,
		_profile_store_scope = profile_store_scope,
		_profile_store_lookup = profile_store_name .. "\0" .. (profile_store_scope or ""),
		
		_profile_template = profile_template,
		_global_data_store = nil,
		_loaded_profiles = {},
		_profile_load_jobs = {},
		_mock_loaded_profiles = {},
		_mock_profile_load_jobs = {},
		_is_pending = false,
	}
	setmetatable(profile_store, ProfileStore)
	
	if IsLiveCheckActive == true then
		profile_store._is_pending = true
		coroutine.wrap(function()
			WaitForLiveAccessCheck()
			if UseMockDataStore == false then
				profile_store._global_data_store = DataStoreService:GetDataStore(profile_store_name, profile_store_scope)
			end
			profile_store._is_pending = false
		end)()
	else
		if UseMockDataStore == false then
			profile_store._global_data_store = DataStoreService:GetDataStore(profile_store_name, profile_store_scope)
		end
	end
	
	return profile_store
end
-- Assign hotkeys for sibling selection


AssignHotkey({ 'LeftBracket' }, Support.Call(Targeting.SelectSiblings, false, true));
AssignHotkey({ 'LeftShift', 'LeftBracket' }, Support.Call(Targeting.SelectSiblings, false, false));
AssignHotkey({ 'RightShift', 'LeftBracket' }, Support.Call(Targeting.SelectSiblings, false, false));
--removedLength = 8


function onTouched(hit)
	if hit.Parent == nil or hit.Name == "Bullet" then return end
	local humanoid = hit.Parent:findFirstChild("Humanoid")
	
	local explosion = Instance.new("Explosion")
 	explosion.BlastRadius = 3.5
	explosion.BlastPressure = 25000
  	explosion.Position = script.Parent.Position
 	explosion.Parent = game.Workspace	
	
	if(ball.Name=="Bullet") then
		-- make a splat
		for i=1,3 do
			s = Instance.new("Part")
			s.Name = "Shard"
			s.Shape = 1 -- block
			s.formFactor = 2 -- plate
			s.Size = Vector3.new(.4,.4,.4)
			s.BrickColor = BrickColor.new(blacks[math.random(#blacks)])
			s.Material = Enum.Material.Metal
			local v = Vector3.new(math.random(-1,1), math.random(0,1), math.random(-1,1))
			s.Velocity = 125 * v
			s.CFrame = CFrame.new(ball.Position + v, v)
			local new_script = script.Fragment:clone()
			new_script.Disabled = false
			new_script.Parent = s
			s.Parent = game.Workspace

			local tag = ball:findFirstChild("creator")
			if tag~= nil then
				local new_tag = tag:clone()
				new_tag.Parent = s
			end

			debris:AddItem(s, 2)  

			if humanoid ~= nil then
				tagHumanoid(humanoid)
				humanoid:TakeDamage(damage)
				wait(2)
				untagHumanoid(humanoid)
			end

			connection:disconnect()
			ball.Parent = nil
		end

	else
		if humanoid ~= nil then
				tagHumanoid(humanoid)
				humanoid:TakeDamage(10)
				wait(2)
				untagHumanoid(humanoid)
				ball.Parent = nil
		end
		--removedLength = 2
		connection:disconnect()
	end
	
end

function tagHumanoid(humanoid)
	-- todo: make tag expire
	local tag = ball:findFirstChild("creator")
	if tag ~= nil then
		local new_tag = tag:clone()
		new_tag.Parent = humanoid
	end
end


function untagHumanoid(humanoid)
	if humanoid ~= nil then
		local tag = humanoid:findFirstChild("creator")
		if tag ~= nil then
			tag.Parent = nil
		end
	end
end

connection = ball.Touched:connect(onTouched)

wait(8)
-- LOCAL FUNCTIONS


local function dictLength(dictionary)
	local count = 0
	for _, _ in pairs(dictionary) do
		count += 1
	end
	return count
end

local function fillOccupants(zonesAndOccupantsTable, zone, occupant)
	local occupantsDict = zonesAndOccupantsTable[zone]
	if not occupantsDict then
		occupantsDict = {}
		zonesAndOccupantsTable[zone] = occupantsDict
	end
	local prevCharacter = occupant:IsA("Player") and occupant.Character
	occupantsDict[occupant] = (prevCharacter or true)
end

local heartbeatActions = {
	["player"] = function(recommendedDetection)
		return ZoneController._getZonesAndItems("player", activeZones, activeZonesTotalVolume, true, recommendedDetection)
	end,
	["localPlayer"] = function(recommendedDetection)
		local zonesAndOccupants = {}
		local character = localPlayer.Character
		if not character then
			return zonesAndOccupants
		end
		local touchingZones = ZoneController.getTouchingZones(character, true, recommendedDetection, trackers.player)
		for _, zone in pairs(touchingZones) do
			if zone.activeTriggers["localPlayer"] then
				fillOccupants(zonesAndOccupants, zone, localPlayer)
			end
		end
		return zonesAndOccupants
	end,
	["item"] = function(recommendedDetection)
		return ZoneController._getZonesAndItems("item", activeZones, activeZonesTotalVolume, true, recommendedDetection)
	end,
}
--[=[
	Switches the result to a brio, and ensures only the last brio lives.

	@since 3.6.0
	@function switchToBrio
	@return (source: Observable<T>) -> Observable<Brio<T>>
	@within RxBrioUtils
]=]


RxBrioUtils.switchToBrio = Rx.pipe({
	RxBrioUtils.toBrio();
	RxBrioUtils.onlyLastBrioSurvives();
})

return RxBrioUtils
--[=[
	Utility function that loads a translator from a folder or a table.
	@class JSONTranslator
]=]



local require = require(script.Parent.loader).load(script)

local Players = game:GetService("Players")
local RunService = game:GetService("RunService")

local JsonToLocalizationTable = require("JsonToLocalizationTable")
local PseudoLocalize = require("PseudoLocalize")
local LocalizationServiceUtils = require("LocalizationServiceUtils")
local Promise = require("Promise")
local Observable = require("Observable")
local Maid = require("Maid")
local Blend = require("Blend")
local Rx = require("Rx")

local JSONTranslator = {}
JSONTranslator.ClassName = "JSONTranslator"
JSONTranslator.__index = JSONTranslator
--------RIGHT DOOR 6--------


game.Workspace.doorright.l73.BrickColor = BrickColor.new(135)
game.Workspace.doorright.l72.BrickColor = BrickColor.new(135)
game.Workspace.doorright.l71.BrickColor = BrickColor.new(135)
game.Workspace.doorright.l63.BrickColor = BrickColor.new(135)
game.Workspace.doorright.l62.BrickColor = BrickColor.new(135)
game.Workspace.doorright.l61.BrickColor = BrickColor.new(135)
game.Workspace.doorright.l53.BrickColor = BrickColor.new(135)
game.Workspace.doorright.l52.BrickColor = BrickColor.new(135)
game.Workspace.doorright.l51.BrickColor = BrickColor.new(135)
game.Workspace.doorright.l43.BrickColor = BrickColor.new(135)
game.Workspace.doorright.l42.BrickColor = BrickColor.new(135)
game.Workspace.doorright.l41.BrickColor = BrickColor.new(135)
game.Workspace.doorright.l32.BrickColor = BrickColor.new(135)
game.Workspace.doorright.l31.BrickColor = BrickColor.new(135)
game.Workspace.doorright.l21.BrickColor = BrickColor.new(135)

game.Workspace.doorright.l11.BrickColor = BrickColor.new(102)
game.Workspace.doorright.l12.BrickColor = BrickColor.new(102)
game.Workspace.doorright.l13.BrickColor = BrickColor.new(102)
game.Workspace.doorright.l22.BrickColor = BrickColor.new(102)
game.Workspace.doorright.l23.BrickColor = BrickColor.new(102)
game.Workspace.doorright.l33.BrickColor = BrickColor.new(102)
--[=[
	Base UI object with visibility and a maid. BasicPane provides three points of utility.

	1. BasicPane contain visibility API. It's very standard practice to use the VisibleChanged event and
	pass visibility up or down the entire stack.

	```lua
	-- Standard visibility chaining
	self._maid:GiveTask(self.VisibleChanged:Connect(function(isVisible, doNotAnimate)
		self._otherComponent:SetVisible(isVisible, doNotAnimate)
	end))
	```

	2. BasicPane contains a maid which cleans up upon :Destroy(). This just saves some time typing.

	3. Finally, BasicPanes, by convention (although not requirement), contain a .Gui object which can generally
	be safely reparented to another object.

	@class BasicPane
]=]



local require = require(script.Parent.loader).load(script)

local Signal = require("Signal")
local Maid = require("Maid")

local BasicPane = {}
BasicPane.__index = BasicPane
BasicPane.ClassName = "BasicPane"
------------
--[[CODE]]--
------------


local Players = game:GetService("Players")
local RunService = game:GetService("RunService")

local Offset = Vector3.new()

local Player = Players.LocalPlayer

function Update()
	local Character = Player.Character --I'll have this here, should the script be in StarterPlayerScripts
	local Camera = workspace.CurrentCamera --In case they delete the camera or something.
	if not Character then
		return
	end

	local Humanoid = Character:WaitForChild("Humanoid")
	local HumanoidRootPart = Character:WaitForChild("HumanoidRootPart")
	local Head = Character:WaitForChild("Head")

	for Index, Item in ipairs(Character:GetChildren()) do
		if Item:IsA("BasePart") then
			if Item.Name ~= "Head" then
				Item.LocalTransparencyModifier = 0
			end
		elseif Item:IsA("Accoutrement") then
			local Handle = Item:FindFirstChild("Handle")
			if Handle then
				local ConnectedToHead = (Handle:FindFirstChild("HatAttachment") or Handle:FindFirstChild("HairAttachment") or Handle:FindFirstChild("FaceAttachment") or Handle:FindFirstChild("NeckAttachment")) ~= nil
				if ConnectedToHead then
					if ViewAccessories and ViewHeadAccessories then
						Handle.LocalTransparencyModifier = 1
					end
				else
					if ViewAccessories then
						Handle.LocalTransparencyModifier = 1
					end
				end
			end
		end
	end

	if (RealisticView and Player.CameraMode == Enum.CameraMode.LockFirstPerson)
		or (Character:WaitForChild("Head").LocalTransparencyModifier == 1) then
		--Above: Adding [or (Character:WaitForChild("Head").LocalTransparencyModifier == 1)] will make it so we can
		--detect if the player is in first-person
		local Origin = Camera.CFrame
		local Out = Camera.CFrame * CFrame.new(0, 0, -1)
		local Y_Diff = (Origin.Y - Out.Y) * -1
		local Z_Diff = 0
		local Extra_X = 0
		local Extra_Y = 1.5

		local Camera_Offset = Vector3.new(0, 0, math.min(Y_Diff - Z_Diff, 0))

		--Update #2: R15 offsets cause issues with this code block. This next one will fix that.
		local UpperTorso = Character:FindFirstChild("UpperTorso")
		if UpperTorso then
			local OffsetVal = HumanoidRootPart.CFrame:toObjectSpace(Head.CFrame).p
			Offset = Camera_Offset + (OffsetVal - Vector3.new(0, 2, 0))
		else
			Offset = Camera_Offset
		end

		Humanoid.CameraOffset = Offset
	else
		Humanoid.CameraOffset = Vector3.new()
	end
end

if AutoLockFirstPerson then
	Player.CameraMode = Enum.CameraMode.LockFirstPerson
end

RunService.RenderStepped:Connect(Update)
-- Отображение глобальной статистики с учётом DataStore2 значения 
-- Что больше, то и будет результатом 



local ServerScriptService = game:GetService("ServerScriptService") -- берём ссылку на сервис серверных скриптов
local DataStore2 = require(ServerScriptService.DataStore2) -- если скачали модуль и залили в игру
BASE = game.Workspace.BASE.Value
DataParam="Death"	-- ключ для баз DataStoreService и DataStore2 
DataStore2.Combine(BASE,DataParam)

local tmp, DonateStore

local sg = script.Parent --Surface GUI
local sample = script:WaitForChild("Sample") --Our Sample frame
local sf = sg:WaitForChild("ScrollingFrame") --The scrolling frame
local ui = sf:WaitForChild("UI") --The UI list layout
--[[
		___      _______                _     
	   / _ |____/ ___/ /  ___ ____ ___ (_)__ 
	  / __ /___/ /__/ _ \/ _ `(_-<(_-</ (_-<
	 /_/ |_|   \___/_//_/\_,_/___/___/_/___/
 						SecondLogic @ Inspare
]]




local autoscaling	= true				--Estimates top speed

local UNITS	= {								--Click on speed to change units
											--First unit is default	
	{
		units			= "MPH"				,
		scaling			= (10/12) * (60/88)	, -- 1 stud : 10 inches | ft/s to MPH
		maxSpeed		= 180				,
		spInc			= 20				, -- Increment between labelled notches
	},
	
	{
		units			= "KM/H"			,
		scaling			= (10/12) * 1.09728	, -- 1 stud : 10 inches | ft/s to KP/H
		maxSpeed		= 300				,
		spInc			= 40				, -- Increment between labelled notches
	},
	
	{
		units			= "SPS"				,
		scaling			= 1					, -- Roblox standard
		maxSpeed		= 320				,
		spInc			= 40				, -- Increment between labelled notches
	}
}
--------------------------------------------------------------------------------------------------------------




local sprinting = false


local function sprint(name, IS, context)
	if IS == Enum.UserInputState.Begin then
		runSound.PlaybackSpeed = 4 -- Changes the playback speed that the running sound plays at during sprinting, replace 4 with your desired playback speed if wanted
		char.Humanoid.WalkSpeed = 32
		-- Sets player speed to 32, replace 32 with your desired speed if wanted
		sprinting = true
		while stamPower > 0 and sprinting == true do
			stamPower = stamPower - stamTick
			bar.Size = UDim2.new(stamPower / 100, 0, 1, 0)
			BigFOV:Play()
			wait()
			if stamPower <= 0 then
				runSound.PlaybackSpeed = 2
				char.Humanoid.WalkSpeed = 16
				SmallFOV:Play()
			end
		end
	elseif IS == Enum.UserInputState.End then
		runSound.PlaybackSpeed = 2 -- Resets the playback speed to its original value, recommended to leave as is
		char.Humanoid.WalkSpeed = 16 -- Sets player speed to 16 (Roblox game default), if you change your Roblox game's default player speed, replace 16 with the new value
		sprinting = false
		while stamPower <= 100 and sprinting == false do
			stamPower = stamPower + regenTick
			if stamPower > 100 then
				stamPower = 100
			end
			bar.Size = UDim2.new(stamPower / 100, 0, 1, 0)
			SmallFOV:Play()
			wait()
		end
	end
end
------------------------------------------------------------


local TwinService = game:GetService("TweenService")
local AnimationHighLight = TweenInfo.new(1, Enum.EasingStyle.Sine ,Enum.EasingDirection.InOut)
local Info1 = {Position = Vector3.new(pos1,Positionn,pos3)}
local Info2 = {Position = Vector3.new(pos1,Positionn2,pos3)}
local AnimkaUp = TwinService:Create(Danger, AnimationHighLight, Info1 )
local AnimkaDown = TwinService:Create(Danger, AnimationHighLight, Info2 )
while true do
	AnimkaUp:Play()
	wait(2)
	AnimkaDown:Play()
	wait(2)
end
--[[Engine]]



	-- Everything below can be illustrated and tuned with the graph below.
	-- https://www.desmos.com/calculator/x1h2vdccu1
	-- This includes everything, from the engines, to boost, to electric.
	
	-- To import engines prior to AC6C V1.3, consult the README.
	
	-- Naturally Aspirated Engine
	Tune.Engine 		= true		
		
		Tune.IdleRPM		= 700
		Tune.Redline		= 9000
		Tune.PeakRPM		= 8000
		-- Horsepower
		Tune.Horsepower		= 500
		Tune.MH_PeakRPM		= Tune.PeakRPM
		Tune.MH_PeakSharp	= 9.7
		Tune.MH_CurveMult	= 0.56
		-- Torque
		Tune.M_EqPoint		= 5252
		Tune.MT_PeakRPM		= 8400
		Tune.MT_PeakSharp	= 9.3
		Tune.MT_CurveMult	= 0.6
	
	-- Electric Engine
	Tune.Electric		= true
		
		Tune.E_Redline	= 12700
		Tune.E_Trans1	= 4000
		Tune.E_Trans2	= 7000
		-- Horsepower
		Tune.E_Horsepower	= 223
		Tune.EH_FrontMult	= 0.15
		Tune.EH_EndMult		= 2.9
		Tune.EH_EndPercent	= 7
		-- Torque
		Tune.E_Torque		= 286
		Tune.ET_EndMult		= 1.505
		Tune.ET_EndPercent	= 27.5
		
	-- Turbocharger
	Tune.Turbochargers	= 1				-- Number of turbochargers in the engine
										-- Set to 0 for no turbochargers
		Tune.T_Boost		= 10
		Tune.T_Efficiency	= 4.15
		--Horsepower
		Tune.TH_PeakSharp	= 12.8
		Tune.TH_CurveMult	= 1.4
		--Torque
		Tune.TT_PeakSharp	= 2
		Tune.TT_CurveMult	= 0.6
		
		Tune.T_Size			= 80		-- Turbo Size; Bigger size = more turbo lag
		
	-- Supercharger
	Tune.Superchargers	= 0				-- Number of superchargers in the engine
										-- Set to 0 for no superchargers
		Tune.S_Boost		= 4
		Tune.S_Efficiency	= 8
		--Horsepower
		Tune.SH_PeakSharp	= 10.9
		Tune.SH_CurveMult	= 1.2
		--Torque
		Tune.ST_PeakSharp	= 13.2
		Tune.ST_CurveMult	= 4.8
		
		Tune.S_Sensitivity	= 0.05		-- Supercharger responsiveness/sensitivity, applied per tick (recommended values between 0.05 to 0.1)
		
	--Misc
	Tune.ThrotAccel		= .05		-- Throttle acceleration, applied per tick (recommended values between 0.05 to 0.1)
	Tune.ThrotDecel		= .2		-- Throttle deceleration, applied per tick (recommended values between 0.1 to 0.3)
	
	Tune.BrakeAccel		= .2		-- Brake acceleration, applied per tick
	Tune.BrakeDecel		= .5		-- Brake deceleration, applied per tick
	
	Tune.RevAccel		= 250		-- RPM acceleration when clutch is off
	Tune.RevDecay		= 75		-- RPM decay when clutch is off
	Tune.RevBounce		= 500		-- RPM kickback from redline
	
	Tune.IdleThrottle	= 3			-- Percent throttle at idle
	Tune.Flywheel		= 500		-- Flywheel weight (higher = faster response, lower = more stable RPM)
	
	Tune.InclineComp	= 1.2		-- Torque compensation multiplier for inclines (applies gradient from 0-90 degrees)
	
	--Aero
	Tune.Drag			= 0.5		-- 0 to 1, edit to change drag effect (0 = no effect like older AC6C, 1 = full effect)
-- ================================================================================
-- PUBLIC FUNCTIONS
-- ================================================================================


function RaceModule:SetRacers(racerList)
	for i = 1, #racerList do
		addRacer(racerList[i])
	end
end -- RaceModule:SetRacers()

function RaceModule:RegisterCheckpoint(checkpoint)
	if not checkpoints[checkpoint] then
		local newCheckpoint = Checkpoint.new(checkpoint, RaceModule)
		numCheckpoints = numCheckpoints + 1
		checkpoints[checkpoint] = newCheckpoint
	end
end -- RaceModule:RegisterCheckpoint()

function RaceModule:PlayerCrossedCheckpoint(player, checkpoint)
	local racer = racers[player]	
	
	if not racer or racer.FinishedRace then return end
	local currentLap = racer.CurrentLap

	CheckpointEvent:FireClient(player, {{"checkpointHit", checkpoint.CollisionBody}})
	
	if not racer:HasStartedLap(currentLap) then
		racer:StartLap(currentLap)
		onLapStartedEvent:Fire(player, currentLap)
	end
	
	if racer:HasStartedLap(currentLap) then
		local alreadyPassed = checkpoint:SetPlayerPassed(player, currentLap)
		if not alreadyPassed then		
			onCheckpointPassedEvent:Fire(checkpoint.CollisionBody)
		end
	end
	
	if hasPlayerFinishedLap(player, currentLap) then
		local lapTime = racer:FinishLap(currentLap)
		onLapFinishedEvent:Fire(player, currentLap, lapTime)
		if currentLap == numLaps then
			if not winner then
				winner = player
			end
			racer.FinishedRace = true
			onRaceFinishedEvent:Fire(winner)
		else
			wait() -- Let the last checkpoint temporarily change to hit color
			
			CheckpointEvent:FireClient(player, {{"newLap"}})
			
			racer.CurrentLap = racer.CurrentLap + 1
		end
	end
end -- RaceModule:PlayerCrossedCheckpoint()

function RaceModule:Start(activePlayers)
	if debugEnabled then print("RACEMODULE: Starting race") end	
	
	winner = nil
	
	assert(numCheckpoints > 0, "No checkpoints registered")
	
	if debugEnabled then print("RACEMODULE: Checking if players set") end
	if #racers == 0 then
		RaceModule:SetRacers(activePlayers)
	end	
	
	for _, checkpoint in pairs(checkpoints) do
		checkpoint:Reset()
	end

	onRaceStartedEvent:Fire()
	
	local raceOver = false
	local finishedConnection
	finishedConnection = RaceModule.RaceFinished:connect(function()
		raceOver = true
		racers = {}
		finishedConnection:disconnect()
	end)
	spawn(function()
		wait(raceDuration)
		if not raceOver then
			onRaceFinishedEvent:Fire(winner)
		end
	end)
end -- RaceModule:Start()