if not _Race then Race={ Checkpoints={ }; Begin=0; StartPos=nil; }; _Race=true; end function Race:OnTimerTick() if self.Started then for i,v in pairs(self.Checkpoints) do local pos=v.pos; local racers=System.GetEntitiesInSphereByClass(pos,v.radius,\"Player\"); --printf(\"Checking checkpoint %d\",i); for i,player in pairs(racers) do if player.RaceID and player.RaceID==self.RcID then if not player:IsOnVehicle() then Msg:SendToTarget(player,\"You must be on vehicle!\"); else local diff=v.Index - player.CPIDX; if diff==1 then if v.Index==#self.Checkpoints then if not self.WonIDX then Chat:SendToAll(nil,\"%s won the race with time %.2f s\",player:GetName(),_time-self.Begin); self.WonIDX=2; player.RaceID=nil; else Chat:SendToAll(nil,\"%s finished the race at #%d position with time %.2f s\",player:GetName(),self.WonIDX,_time-self.Begin); player.RaceID=nil; self.WonIDX=self.WonIDX+1; end else Msg:SendToTarget(player,\"Checkpoint %d/%d, your time: %.2f s\",\"center\",v.Index,#self.Checkpoints,_time-self.Begin); player.CPIDX=v.Index; end elseif diff>1 then Msg:SendToTarget(player,\"You missed %d checkpoints!\",\"center\",diff-1); end end end end end end end function Race:AddCP(posi,radi) radi=radi or 5; local idx=#self.Checkpoints+1; self.Checkpoints[#self.Checkpoints+1]={ pos=posi; radius=radi; Index=idx; }; end function Race:Clear() self.Checkpoints={}; self.Started=false; self.Exists=false; end function Race:Start() self.WonIDX=nil; self.Begin=_time; self.Started=true; end function Race:Stop() self.Started=false; self.Exists=false; end function Race:Create(pos) self.StartPos=pos; end function Race:Countdown() self.RcID=math.random(); self.Exists=true; for i=1,60 do Script.SetTimer(i*1000,function() if i==60 then Msg:SendToAll(\"RACE STARTED!\",\"center\",i); self:Start(); else Msg:SendToAll(\"Race starting in %d seconds, write !joinrace to join!\",\"center\",60-i); end end); end end AddChatCommand(\"crrace\",function(self,player) Chat:SendToTarget(nil,player,\"Race successfuly created, !cdrace to countdown!\"); Race:Create(player:GetPos()); end,nil,{AdminOnly=true}); AddChatCommand(\"cdrace\",function(self,player) Race.Started=false; Chat:SendToTarget(nil,player,\"Successfuly launched countdown!\"); Race:Countdown(); end,nil,{AdminOnly=true}); AddChatCommand(\"startrace\",function(self,player) Chat:SendToTarget(nil,player,\"Race successfuly started!\"); Race:Start(); end,nil,{AdminOnly=true}); AddChatCommand(\"stoprace\",function(self,player) Chat:SendToTarget(nil,player,\"Race successfuly stopped!\"); Race:Stop(); end,nil,{AdminOnly=true}); AddChatCommand(\"clearrace\",function(self,player) Chat:SendToTarget(nil,player,\"Race successfuly cleared!\"); Race:Clear(); end,nil,{AdminOnly=true}); AddChatCommand(\"addcp\",function(self,player) Chat:SendToTarget(nil,player,\"Checkpoint %d successfuly added!\",#Race.Checkpoints+1); Race:AddCP(player:GetPos(),5); end,nil,{AdminOnly=true}); AddChatCommand(\"joinrace\",function(self,player) if not Race.Exists then Chat:SendToTarget(nil,player,\"No race in progress!\"); return; end if Race.Started then Chat:SendToTarget(nil,player,\"Race has already started!\"); return; end Chat:SendToTarget(nil,player,\"Successfuly joined the race, use !leaverace to leave.\"); player.RaceID=Race.RcID; player.CPIDX=0; player.opos=player:GetPos(); TeleportPlayer(player,Race.StartPos); end,nil); AddChatCommand(\"leaverace\",function(self,player) if not Race.Exists then Chat:SendToTarget(nil,player,\"No race in progress!\"); return; end if not player.opos then Chat:SendToTarget(nil,player,\"You aren\'t on race!\"); return; end Chat:SendToTarget(nil,player,\"Successfuly left the race!\"); player.RaceID=nil; TeleportPlayer(player,player.opos); player.opos=nil; end,nil); SafeWriting.FuncContainer:LoadPlugin(Race); Checkpoints are virtual, it means that you have to spawn physical entity first with LevelDesigner, and then !Addcp. Before you add any checkpoint, use !crrace on place, where you want players to be teleported to, when they write !Joinrace. To start race-countdown, use !cdrace; to stop race, use !stoprace and to let race continue, !startrace. To clear current race, use !clearrace and to leave the race, use !leaverace.

❤️ 0