Main/resources/[qb]/qb-lapraces/client/main.lua
2025-06-07 08:51:21 +02:00

859 lines
38 KiB
Lua

local QBCore = exports['qb-core']:GetCoreObject()
local Countdown = 10
local ToFarCountdown = 10
local FinishedUITimeout = false
local RaceData = {
InCreator = false,
InRace = false,
ClosestCheckpoint = 0,
}
local CreatorData = {
RaceName = nil,
Checkpoints = {},
TireDistance = 3.0,
ConfirmDelete = false,
}
local CurrentRaceData = {
RaceId = nil,
RaceName = nil,
Checkpoints = {},
Started = false,
CurrentCheckpoint = nil,
TotalLaps = 0,
Lap = 0,
}
-- Handlers
AddEventHandler('onResourceStop', function(resource)
if resource == GetCurrentResourceName() then
for k, _ in pairs(CreatorData.Checkpoints) do
if CreatorData.Checkpoints[k].pileleft ~= nil then
local coords = CreatorData.Checkpoints[k].offset.right
local Obj = GetClosestObjectOfType(coords.x, coords.y, coords.z, 5.0, `prop_offroad_tyres02`, 0, 0, 0)
DeleteObject(Obj)
ClearAreaOfObjects(coords.x, coords.y, coords.z, 50.0, 0)
CreatorData.Checkpoints[k].pileright = nil
end
if CreatorData.Checkpoints[k].pileright ~= nil then
local coords = CreatorData.Checkpoints[k].offset.right
local Obj = GetClosestObjectOfType(coords.x, coords.y, coords.z, 5.0, `prop_offroad_tyres02`, 0, 0, 0)
DeleteObject(Obj)
ClearAreaOfObjects(coords.x, coords.y, coords.z, 50.0, 0)
CreatorData.Checkpoints[k].pileright = nil
end
end
for k, _ in pairs(CurrentRaceData.Checkpoints) do
if CurrentRaceData.Checkpoints[k] ~= nil then
if CurrentRaceData.Checkpoints[k].pileleft ~= nil then
local coords = CurrentRaceData.Checkpoints[k].offset.right
local Obj = GetClosestObjectOfType(coords.x, coords.y, coords.z, 5.0, `prop_offroad_tyres02`, 0, 0, 0)
DeleteObject(Obj)
ClearAreaOfObjects(coords.x, coords.y, coords.z, 50.0, 0)
CurrentRaceData.Checkpoints[k].pileright = nil
end
if CurrentRaceData.Checkpoints[k].pileright ~= nil then
local coords = CurrentRaceData.Checkpoints[k].offset.right
local Obj = GetClosestObjectOfType(coords.x, coords.y, coords.z, 5.0, `prop_offroad_tyres02`, 0, 0, 0)
DeleteObject(Obj)
ClearAreaOfObjects(coords.x, coords.y, coords.z, 50.0, 0)
CurrentRaceData.Checkpoints[k].pileright = nil
end
end
end
end
end)
-- Functions
local function DrawText3Ds(x, y, z, text)
SetTextScale(0.35, 0.35)
SetTextFont(4)
SetTextProportional(1)
SetTextColour(255, 255, 255, 215)
BeginTextCommandDisplayText("STRING")
SetTextCentre(true)
AddTextComponentSubstringPlayerName(text)
SetDrawOrigin(x,y,z, 0)
EndTextCommandDisplayText(0.0, 0.0)
local factor = (string.len(text)) / 370
DrawRect(0.0, 0.0+0.0125, 0.017+ factor, 0.03, 0, 0, 0, 75)
ClearDrawOrigin()
end
local function GetClosestCheckpoint()
local pos = GetEntityCoords(PlayerPedId(), true)
local current = nil
local dist = nil
for id, _ in pairs(CreatorData.Checkpoints) do
if current ~= nil then
if #(pos - vector3(CreatorData.Checkpoints[id].coords.x, CreatorData.Checkpoints[id].coords.y, CreatorData.Checkpoints[id].coords.z)) < dist then
current = id
dist = #(pos - vector3(CreatorData.Checkpoints[id].coords.x, CreatorData.Checkpoints[id].coords.y, CreatorData.Checkpoints[id].coords.z))
end
else
dist = #(pos - vector3(CreatorData.Checkpoints[id].coords.x, CreatorData.Checkpoints[id].coords.y, CreatorData.Checkpoints[id].coords.z))
current = id
end
end
RaceData.ClosestCheckpoint = current
end
local function CreatorUI()
CreateThread(function()
while true do
if RaceData.InCreator then
SendNUIMessage({
action = "Update",
type = "creator",
data = CreatorData,
racedata = RaceData,
active = true,
})
else
SendNUIMessage({
action = "Update",
type = "creator",
data = CreatorData,
racedata = RaceData,
active = false,
})
break
end
Wait(200)
end
end)
end
local function DeleteCheckpoint()
local NewCheckpoints = {}
if RaceData.ClosestCheckpoint ~= 0 then
if CreatorData.Checkpoints[RaceData.ClosestCheckpoint] ~= nil then
if CreatorData.Checkpoints[RaceData.ClosestCheckpoint].blip ~= nil then
RemoveBlip(CreatorData.Checkpoints[RaceData.ClosestCheckpoint].blip)
CreatorData.Checkpoints[RaceData.ClosestCheckpoint].blip = nil
end
if CreatorData.Checkpoints[RaceData.ClosestCheckpoint].pileleft ~= nil then
local coords = CreatorData.Checkpoints[RaceData.ClosestCheckpoint].offset.left
local Obj = GetClosestObjectOfType(coords.x, coords.y, coords.z, 5.0, `prop_offroad_tyres02`, 0, 0, 0)
DeleteObject(Obj)
ClearAreaOfObjects(coords.x, coords.y, coords.z, 50.0, 0)
CreatorData.Checkpoints[RaceData.ClosestCheckpoint].pileleft = nil
end
if CreatorData.Checkpoints[RaceData.ClosestCheckpoint].pileright ~= nil then
local coords = CreatorData.Checkpoints[RaceData.ClosestCheckpoint].offset.right
local Obj = GetClosestObjectOfType(coords.x, coords.y, coords.z, 5.0, `prop_offroad_tyres02`, 0, 0, 0)
DeleteObject(Obj)
ClearAreaOfObjects(coords.x, coords.y, coords.z, 50.0, 0)
CreatorData.Checkpoints[RaceData.ClosestCheckpoint].pileright = nil
end
for id, data in pairs(CreatorData.Checkpoints) do
if id ~= RaceData.ClosestCheckpoint then
NewCheckpoints[#NewCheckpoints+1] = data
end
end
CreatorData.Checkpoints = NewCheckpoints
else
QBCore.Functions.Notify('You cant go to fast', 'error')
end
else
QBCore.Functions.Notify('You cant go too fast', 'error')
end
end
local function SaveRace()
local RaceDistance = 0
for k, v in pairs(CreatorData.Checkpoints) do
if k + 1 <= #CreatorData.Checkpoints then
local checkpointdistance = #(vector3(v.coords.x, v.coords.y, v.coords.z) - vector3(CreatorData.Checkpoints[k + 1].coords.x, CreatorData.Checkpoints[k + 1].coords.y, CreatorData.Checkpoints[k + 1].coords.z))
RaceDistance = RaceDistance + checkpointdistance
end
end
CreatorData.RaceDistance = RaceDistance
TriggerServerEvent('qb-lapraces:server:SaveRace', CreatorData)
QBCore.Functions.Notify('Race: '..CreatorData.RaceName..' is saved!', 'success')
for id,_ in pairs(CreatorData.Checkpoints) do
if CreatorData.Checkpoints[id].blip ~= nil then
RemoveBlip(CreatorData.Checkpoints[id].blip)
CreatorData.Checkpoints[id].blip = nil
end
if CreatorData.Checkpoints[id] ~= nil then
if CreatorData.Checkpoints[id].pileleft ~= nil then
local coords = CreatorData.Checkpoints[id].offset.left
local Obj = GetClosestObjectOfType(coords.x, coords.y, coords.z, 5.0, `prop_offroad_tyres02`, 0, 0, 0)
DeleteObject(Obj)
ClearAreaOfObjects(coords.x, coords.y, coords.z, 50.0, 0)
CreatorData.Checkpoints[id].pileleft = nil
end
if CreatorData.Checkpoints[id].pileright ~= nil then
local coords = CreatorData.Checkpoints[id].offset.right
local Obj = GetClosestObjectOfType(coords.x, coords.y, coords.z, 5.0, `prop_offroad_tyres02`, 0, 0, 0)
DeleteObject(Obj)
ClearAreaOfObjects(coords.x, coords.y, coords.z, 50.0, 0)
CreatorData.Checkpoints[id].pileright = nil
end
end
end
RaceData.InCreator = false
CreatorData.RaceName = nil
CreatorData.Checkpoints = {}
end
local function AddCheckpoint()
local PlayerPed = PlayerPedId()
local PlayerPos = GetEntityCoords(PlayerPed)
local PlayerVeh = GetVehiclePedIsIn(PlayerPed)
local Offset = {
left = {
x = (GetOffsetFromEntityInWorldCoords(PlayerVeh, -CreatorData.TireDistance, 0.0, 0.0)).x,
y = (GetOffsetFromEntityInWorldCoords(PlayerVeh, -CreatorData.TireDistance, 0.0, 0.0)).y,
z = (GetOffsetFromEntityInWorldCoords(PlayerVeh, -CreatorData.TireDistance, 0.0, 0.0)).z,
},
right = {
x = (GetOffsetFromEntityInWorldCoords(PlayerVeh, CreatorData.TireDistance, 0.0, 0.0)).x,
y = (GetOffsetFromEntityInWorldCoords(PlayerVeh, CreatorData.TireDistance, 0.0, 0.0)).y,
z = (GetOffsetFromEntityInWorldCoords(PlayerVeh, CreatorData.TireDistance, 0.0, 0.0)).z,
}
}
CreatorData.Checkpoints[#CreatorData.Checkpoints+1] = {
coords = {
x = PlayerPos.x,
y = PlayerPos.y,
z = PlayerPos.z,
},
offset = Offset,
}
for id, CheckpointData in pairs(CreatorData.Checkpoints) do
if CheckpointData.blip ~= nil then
RemoveBlip(CheckpointData.blip)
end
CheckpointData.blip = AddBlipForCoord(CheckpointData.coords.x, CheckpointData.coords.y, CheckpointData.coords.z)
SetBlipSprite(CheckpointData.blip, 1)
SetBlipDisplay(CheckpointData.blip, 4)
SetBlipScale(CheckpointData.blip, 0.8)
SetBlipAsShortRange(CheckpointData.blip, true)
SetBlipColour(CheckpointData.blip, 26)
ShowNumberOnBlip(CheckpointData.blip, id)
SetBlipShowCone(CheckpointData.blip, false)
BeginTextCommandSetBlipName("STRING")
AddTextComponentSubstringPlayerName("Checkpoint: "..id)
EndTextCommandSetBlipName(CheckpointData.blip)
end
end
local function CreatorLoop()
CreateThread(function()
while RaceData.InCreator do
local PlayerPed = PlayerPedId()
local PlayerVeh = GetVehiclePedIsIn(PlayerPed)
if PlayerVeh ~= 0 then
if IsControlJustPressed(0, 161) or IsDisabledControlJustPressed(0, 161) then
AddCheckpoint()
end
if IsControlJustPressed(0, 162) or IsDisabledControlJustPressed(0, 162) then
if CreatorData.Checkpoints ~= nil and next(CreatorData.Checkpoints) ~= nil then
DeleteCheckpoint()
else
QBCore.Functions.Notify('You have not placed any checkpoints yet..', 'error')
end
end
if IsControlJustPressed(0, 311) or IsDisabledControlJustPressed(0, 311) then
if CreatorData.Checkpoints ~= nil and #CreatorData.Checkpoints >= 2 then
SaveRace()
else
QBCore.Functions.Notify('You must have at least 10 checkpoints', 'error')
end
end
if IsControlJustPressed(0, 40) or IsDisabledControlJustPressed(0, 40) then
if CreatorData.TireDistance + 1.0 ~= 16.0 then
CreatorData.TireDistance = CreatorData.TireDistance + 1.0
else
QBCore.Functions.Notify('You can not go higher than 15')
end
end
if IsControlJustPressed(0, 39) or IsDisabledControlJustPressed(0, 39) then
if CreatorData.TireDistance - 1.0 ~= 1.0 then
CreatorData.TireDistance = CreatorData.TireDistance - 1.0
else
QBCore.Functions.Notify('You cannot go lower than 2')
end
end
else
local coords = GetEntityCoords(PlayerPedId())
DrawText3Ds(coords.x, coords.y, coords.z, 'You must be in a vehicle')
end
if IsControlJustPressed(0, 163) or IsDisabledControlJustPressed(0, 163) then
if not CreatorData.ConfirmDelete then
CreatorData.ConfirmDelete = true
QBCore.Functions.Notify('Press [9] again to confirm', 'error', 5000)
else
for _, CheckpointData in pairs(CreatorData.Checkpoints) do
if CheckpointData.blip ~= nil then
RemoveBlip(CheckpointData.blip)
end
end
for id,_ in pairs(CreatorData.Checkpoints) do
if CreatorData.Checkpoints[id].pileleft ~= nil then
local coords = CreatorData.Checkpoints[id].offset.left
local Obj = GetClosestObjectOfType(coords.x, coords.y, coords.z, 8.0, `prop_offroad_tyres02`, 0, 0, 0)
DeleteObject(Obj)
ClearAreaOfObjects(coords.x, coords.y, coords.z, 50.0, 0)
CreatorData.Checkpoints[id].pileleft = nil
end
if CreatorData.Checkpoints[id].pileright ~= nil then
local coords = CreatorData.Checkpoints[id].offset.right
local Obj = GetClosestObjectOfType(coords.x, coords.y, coords.z, 8.0, `prop_offroad_tyres02`, 0, 0, 0)
DeleteObject(Obj)
ClearAreaOfObjects(coords.x, coords.y, coords.z, 50.0, 0)
CreatorData.Checkpoints[id].pileright = nil
end
end
RaceData.InCreator = false
CreatorData.RaceName = nil
CreatorData.Checkpoints = {}
QBCore.Functions.Notify('Race-editor canceled!', 'error')
CreatorData.ConfirmDelete = false
end
end
Wait(3)
end
end)
end
local function RaceUI()
CreateThread(function()
while true do
if CurrentRaceData.Checkpoints ~= nil and next(CurrentRaceData.Checkpoints) ~= nil then
if CurrentRaceData.Started then
CurrentRaceData.RaceTime = CurrentRaceData.RaceTime + 1
CurrentRaceData.TotalTime = CurrentRaceData.TotalTime + 1
end
SendNUIMessage({
action = "Update",
type = "race",
data = {
CurrentCheckpoint = CurrentRaceData.CurrentCheckpoint,
TotalCheckpoints = #CurrentRaceData.Checkpoints,
TotalLaps = CurrentRaceData.TotalLaps,
CurrentLap = CurrentRaceData.Lap,
RaceStarted = CurrentRaceData.Started,
RaceName = CurrentRaceData.RaceName,
Time = CurrentRaceData.RaceTime,
TotalTime = CurrentRaceData.TotalTime,
BestLap = CurrentRaceData.BestLap,
},
racedata = RaceData,
active = true,
})
else
if not FinishedUITimeout then
FinishedUITimeout = true
SetTimeout(10000, function()
FinishedUITimeout = false
SendNUIMessage({
action = "Update",
type = "race",
data = {},
racedata = RaceData,
active = false,
})
end)
end
break
end
Wait(12)
end
end)
end
local function SetupRace(sRaceData, Laps)
RaceData.RaceId = sRaceData.RaceId
CurrentRaceData = {
RaceId = sRaceData.RaceId,
Creator = sRaceData.Creator,
RaceName = sRaceData.RaceName,
Checkpoints = sRaceData.Checkpoints,
Started = false,
CurrentCheckpoint = 1,
TotalLaps = Laps,
Lap = 1,
RaceTime = 0,
TotalTime = 0,
BestLap = 0,
Racers = {}
}
for k, v in pairs(CurrentRaceData.Checkpoints) do
ClearAreaOfObjects(v.offset.left.x, v.offset.left.y, v.offset.left.z, 50.0, 0)
CurrentRaceData.Checkpoints[k].pileleft = CreateObject(`prop_offroad_tyres02`, v.offset.left.x, v.offset.left.y, v.offset.left.z, 0, 0, 0)
PlaceObjectOnGroundProperly(CurrentRaceData.Checkpoints[k].pileleft)
FreezeEntityPosition(CurrentRaceData.Checkpoints[k].pileleft, 1)
SetEntityAsMissionEntity(CurrentRaceData.Checkpoints[k].pileleft, 1, 1)
ClearAreaOfObjects(v.offset.right.x, v.offset.right.y, v.offset.right.z, 50.0, 0)
CurrentRaceData.Checkpoints[k].pileright = CreateObject(`prop_offroad_tyres02`, v.offset.right.x, v.offset.right.y, v.offset.right.z, 0, 0, 0)
PlaceObjectOnGroundProperly(CurrentRaceData.Checkpoints[k].pileright)
FreezeEntityPosition(CurrentRaceData.Checkpoints[k].pileright, 1)
SetEntityAsMissionEntity(CurrentRaceData.Checkpoints[k].pileright, 1, 1)
CurrentRaceData.Checkpoints[k].blip = AddBlipForCoord(v.coords.x, v.coords.y, v.coords.z)
SetBlipSprite(CurrentRaceData.Checkpoints[k].blip, 1)
SetBlipDisplay(CurrentRaceData.Checkpoints[k].blip, 4)
SetBlipScale(CurrentRaceData.Checkpoints[k].blip, 0.6)
SetBlipAsShortRange(CurrentRaceData.Checkpoints[k].blip, true)
SetBlipColour(CurrentRaceData.Checkpoints[k].blip, 26)
ShowNumberOnBlip(CurrentRaceData.Checkpoints[k].blip, k)
BeginTextCommandSetBlipName("STRING")
AddTextComponentSubstringPlayerName("Checkpoint: "..k)
EndTextCommandSetBlipName(CurrentRaceData.Checkpoints[k].blip)
end
RaceUI()
end
local function showNonLoopParticle(dict, particleName, coords, scale)
RequestNamedPtfxAsset(dict)
while not HasNamedPtfxAssetLoaded(dict) do
Wait(0)
end
UseParticleFxAssetNextCall(dict)
local particleHandle = StartParticleFxLoopedAtCoord(particleName, coords.x, coords.y, coords.z, 0.0, 0.0, 0.0, scale, false, false, false)
SetParticleFxLoopedColour(particleHandle, 0, 255, 0 ,0)
return particleHandle
end
local function DoPilePfx()
if CurrentRaceData.Checkpoints[CurrentRaceData.CurrentCheckpoint] ~= nil then
local Timeout = 500
local Size = 2.0
local left = showNonLoopParticle('core', 'ent_sht_flame', CurrentRaceData.Checkpoints[CurrentRaceData.CurrentCheckpoint].offset.left, Size)
local right = showNonLoopParticle('core', 'ent_sht_flame', CurrentRaceData.Checkpoints[CurrentRaceData.CurrentCheckpoint].offset.right, Size)
SetTimeout(Timeout, function()
StopParticleFxLooped(left, false)
StopParticleFxLooped(right, false)
end)
end
end
local function SetupPiles()
for k, v in pairs(CreatorData.Checkpoints) do
if CreatorData.Checkpoints[k].pileleft == nil then
ClearAreaOfObjects(v.offset.left.x, v.offset.left.y, v.offset.left.z, 50.0, 0)
CreatorData.Checkpoints[k].pileleft = CreateObject(`prop_offroad_tyres02`, v.offset.left.x, v.offset.left.y, v.offset.left.z, 0, 0, 0)
PlaceObjectOnGroundProperly(CreatorData.Checkpoints[k].pileleft)
FreezeEntityPosition(CreatorData.Checkpoints[k].pileleft, 1)
SetEntityAsMissionEntity(CreatorData.Checkpoints[k].pileleft, 1, 1)
end
if CreatorData.Checkpoints[k].pileright == nil then
ClearAreaOfObjects(v.offset.right.x, v.offset.right.y, v.offset.right.z, 50.0, 0)
CreatorData.Checkpoints[k].pileright = CreateObject(`prop_offroad_tyres02`, v.offset.right.x, v.offset.right.y, v.offset.right.z, 0, 0, 0)
PlaceObjectOnGroundProperly(CreatorData.Checkpoints[k].pileright)
FreezeEntityPosition(CreatorData.Checkpoints[k].pileleft, 1)
SetEntityAsMissionEntity(CreatorData.Checkpoints[k].pileleft, 1, 1)
end
end
end
local function GetMaxDistance(OffsetCoords)
local Distance = #(vector3(OffsetCoords.left.x, OffsetCoords.left.y, OffsetCoords.left.z) - vector3(OffsetCoords.right.x, OffsetCoords.right.y, OffsetCoords.right.z))
local Retval = 7.5
if Distance > 20.0 then
Retval = 12.5
end
return Retval
end
local function SecondsToClock(seconds)
seconds = tonumber(seconds)
local retval
if seconds <= 0 then
retval = "00:00:00";
else
local hours = string.format("%02.f", math.floor(seconds/3600));
local mins = string.format("%02.f", math.floor(seconds/60 - (hours*60)));
local secs = string.format("%02.f", math.floor(seconds - hours*3600 - mins *60));
retval = hours..":"..mins..":"..secs
end
return retval
end
local function FinishRace()
TriggerServerEvent('qb-lapraces:server:FinishPlayer', CurrentRaceData, CurrentRaceData.TotalTime, CurrentRaceData.TotalLaps, CurrentRaceData.BestLap)
if CurrentRaceData.BestLap ~= 0 then
QBCore.Functions.Notify('Race finished in '..SecondsToClock(CurrentRaceData.TotalTime)..', with the best lap: '..SecondsToClock(CurrentRaceData.BestLap))
else
QBCore.Functions.Notify('Race finished in '..SecondsToClock(CurrentRaceData.TotalTime))
end
for k, _ in pairs(CurrentRaceData.Checkpoints) do
if CurrentRaceData.Checkpoints[k].blip ~= nil then
RemoveBlip(CurrentRaceData.Checkpoints[k].blip)
CurrentRaceData.Checkpoints[k].blip = nil
end
if CurrentRaceData.Checkpoints[k].pileleft ~= nil then
local coords = CurrentRaceData.Checkpoints[k].offset.left
local Obj = GetClosestObjectOfType(coords.x, coords.y, coords.z, 5.0, `prop_offroad_tyres02`, 0, 0, 0)
DeleteObject(Obj)
ClearAreaOfObjects(coords.x, coords.y, coords.z, 50.0, 0)
CurrentRaceData.Checkpoints[k].pileleft = nil
end
if CurrentRaceData.Checkpoints[k].pileright ~= nil then
local coords = CurrentRaceData.Checkpoints[k].offset.right
local Obj = GetClosestObjectOfType(coords.x, coords.y, coords.z, 5.0, `prop_offroad_tyres02`, 0, 0, 0)
DeleteObject(Obj)
ClearAreaOfObjects(coords.x, coords.y, coords.z, 50.0, 0)
CurrentRaceData.Checkpoints[k].pileright = nil
end
end
CurrentRaceData.RaceName = nil
CurrentRaceData.Checkpoints = {}
CurrentRaceData.Started = false
CurrentRaceData.CurrentCheckpoint = 0
CurrentRaceData.TotalLaps = 0
CurrentRaceData.Lap = 0
CurrentRaceData.RaceTime = 0
CurrentRaceData.TotalTime = 0
CurrentRaceData.BestLap = 0
CurrentRaceData.RaceId = nil
RaceData.InRace = false
end
local function Info()
local PlayerPed = PlayerPedId()
local plyVeh = GetVehiclePedIsIn(PlayerPed, false)
local IsDriver = GetPedInVehicleSeat(plyVeh, -1) == PlayerPed
local returnValue = plyVeh ~= 0 and plyVeh ~= nil and IsDriver
return returnValue, plyVeh
end
local function IsInRace()
local retval = false
if RaceData.InRace then
retval = true
end
return retval
end
local function IsInEditor()
local retval = false
if RaceData.InCreator then
retval = true
end
return retval
end
exports('IsInEditor', IsInEditor)
exports('IsInRace', IsInRace)
-- Events
RegisterNetEvent('qb-lapraces:client:StartRaceEditor', function(RaceName)
if not RaceData.InCreator then
CreatorData.RaceName = RaceName
RaceData.InCreator = true
CreatorUI()
CreatorLoop()
else
QBCore.Functions.Notify('You are already making a race.', 'error')
end
end)
RegisterNetEvent('qb-lapraces:client:UpdateRaceRacerData', function(RaceId, aRaceData)
if (CurrentRaceData.RaceId ~= nil) and CurrentRaceData.RaceId == RaceId then
CurrentRaceData.Racers = aRaceData.Racers
end
end)
RegisterNetEvent('qb-lapraces:client:JoinRace', function(Data, Laps)
if not RaceData.InRace then
RaceData.InRace = true
SetupRace(Data, Laps)
TriggerServerEvent('qb-lapraces:server:UpdateRaceState', CurrentRaceData.RaceId, false, true)
else
QBCore.Functions.Notify('Youre already in a race..', 'error')
end
end)
RegisterNetEvent('qb-lapraces:client:LeaveRace', function(_)
QBCore.Functions.Notify('You have completed the race!')
for k, _ in pairs(CurrentRaceData.Checkpoints) do
if CurrentRaceData.Checkpoints[k].blip ~= nil then
RemoveBlip(CurrentRaceData.Checkpoints[k].blip)
CurrentRaceData.Checkpoints[k].blip = nil
end
if CurrentRaceData.Checkpoints[k].pileleft ~= nil then
local coords = CurrentRaceData.Checkpoints[k].offset.left
local Obj = GetClosestObjectOfType(coords.x, coords.y, coords.z, 5.0, `prop_offroad_tyres02`, 0, 0, 0)
DeleteObject(Obj)
ClearAreaOfObjects(coords.x, coords.y, coords.z, 50.0, 0)
CurrentRaceData.Checkpoints[k].pileleft = nil
end
if CurrentRaceData.Checkpoints[k].pileright ~= nil then
local coords = CurrentRaceData.Checkpoints[k].offset.right
local Obj = GetClosestObjectOfType(coords.x, coords.y, coords.z, 5.0, `prop_offroad_tyres02`, 0, 0, 0)
DeleteObject(Obj)
ClearAreaOfObjects(coords.x, coords.y, coords.z, 50.0, 0)
CurrentRaceData.Checkpoints[k].pileright = nil
end
end
CurrentRaceData.RaceName = nil
CurrentRaceData.Checkpoints = {}
CurrentRaceData.Started = false
CurrentRaceData.CurrentCheckpoint = 0
CurrentRaceData.TotalLaps = 0
CurrentRaceData.Lap = 0
CurrentRaceData.RaceTime = 0
CurrentRaceData.TotalTime = 0
CurrentRaceData.BestLap = 0
CurrentRaceData.RaceId = nil
RaceData.InRace = false
FreezeEntityPosition(GetVehiclePedIsIn(PlayerPedId(), false), false)
end)
RegisterNetEvent('qb-lapraces:client:RaceCountdown', function()
TriggerServerEvent('qb-lapraces:server:UpdateRaceState', CurrentRaceData.RaceId, true, false)
if CurrentRaceData.RaceId ~= nil then
while Countdown ~= 0 do
if CurrentRaceData.RaceName ~= nil then
if Countdown == 10 then
QBCore.Functions.Notify('The race will start in 10 seconds', 'error', 2500)
PlaySound(-1, "slow", "SHORT_PLAYER_SWITCH_SOUND_SET", 0, 0, 1)
elseif Countdown <= 5 then
QBCore.Functions.Notify(Countdown, 'error', 500)
PlaySound(-1, "slow", "SHORT_PLAYER_SWITCH_SOUND_SET", 0, 0, 1)
end
Countdown = Countdown - 1
FreezeEntityPosition(GetVehiclePedIsIn(PlayerPedId(), true), true)
else
break
end
Wait(1000)
end
if CurrentRaceData.RaceName ~= nil then
SetNewWaypoint(CurrentRaceData.Checkpoints[CurrentRaceData.CurrentCheckpoint + 1].coords.x, CurrentRaceData.Checkpoints[CurrentRaceData.CurrentCheckpoint + 1].coords.y)
QBCore.Functions.Notify('GO!', 'success', 1000)
SetBlipScale(CurrentRaceData.Checkpoints[CurrentRaceData.CurrentCheckpoint + 1].blip, 1.0)
FreezeEntityPosition(GetVehiclePedIsIn(PlayerPedId(), true), false)
DoPilePfx()
CurrentRaceData.Started = true
Countdown = 10
else
FreezeEntityPosition(GetVehiclePedIsIn(PlayerPedId(), true), false)
Countdown = 10
end
else
QBCore.Functions.Notify('You are not currently in a race..', 'error')
end
end)
RegisterNetEvent('qb-lapraces:client:PlayerFinishs', function(RaceId, Place, FinisherData)
if CurrentRaceData.RaceId ~= nil then
if CurrentRaceData.RaceId == RaceId then
QBCore.Functions.Notify(FinisherData.PlayerData.charinfo.firstname..' is finished on spot: '..Place, 'error', 3500)
end
end
end)
RegisterNetEvent('qb-lapraces:client:WaitingDistanceCheck', function()
Wait(1000)
CreateThread(function()
while true do
if not CurrentRaceData.Started then
local ped = PlayerPedId()
local pos = GetEntityCoords(ped)
if CurrentRaceData.Checkpoints[1] ~= nil then
local cpcoords = CurrentRaceData.Checkpoints[1].coords
local dist = #(pos - vector3(cpcoords.x, cpcoords.y, cpcoords.z))
if dist > 115.0 then
if ToFarCountdown ~= 0 then
ToFarCountdown = ToFarCountdown - 1
QBCore.Functions.Notify('Go back to the start or you will be kicked from the race: '..ToFarCountdown..'s', 'error', 500)
else
TriggerServerEvent('qb-lapraces:server:LeaveRace', CurrentRaceData)
ToFarCountdown = 10
break
end
Wait(1000)
else
if ToFarCountdown ~= 10 then
ToFarCountdown = 10
end
end
end
else
break
end
Wait(3)
end
end)
end)
-- Threads
CreateThread(function()
while true do
if RaceData.InCreator then
local PlayerPed = PlayerPedId()
local PlayerVeh = GetVehiclePedIsIn(PlayerPed)
if PlayerVeh ~= 0 then
local Offset = {
left = {
x = (GetOffsetFromEntityInWorldCoords(PlayerVeh, -CreatorData.TireDistance, 0.0, 0.0)).x,
y = (GetOffsetFromEntityInWorldCoords(PlayerVeh, -CreatorData.TireDistance, 0.0, 0.0)).y,
z = (GetOffsetFromEntityInWorldCoords(PlayerVeh, -CreatorData.TireDistance, 0.0, 0.0)).z,
},
right = {
x = (GetOffsetFromEntityInWorldCoords(PlayerVeh, CreatorData.TireDistance, 0.0, 0.0)).x,
y = (GetOffsetFromEntityInWorldCoords(PlayerVeh, CreatorData.TireDistance, 0.0, 0.0)).y,
z = (GetOffsetFromEntityInWorldCoords(PlayerVeh, CreatorData.TireDistance, 0.0, 0.0)).z,
}
}
DrawText3Ds(Offset.left.x, Offset.left.y, Offset.left.z, 'Checkpoint L')
DrawText3Ds(Offset.right.x, Offset.right.y, Offset.right.z, 'Checkpoint R')
end
end
Wait(3)
end
end)
CreateThread(function()
while true do
local ped = PlayerPedId()
local pos = GetEntityCoords(ped)
if CurrentRaceData.RaceName ~= nil then
if CurrentRaceData.Started then
local cp
if CurrentRaceData.CurrentCheckpoint + 1 > #CurrentRaceData.Checkpoints then
cp = 1
else
cp = CurrentRaceData.CurrentCheckpoint + 1
end
local data = CurrentRaceData.Checkpoints[cp]
local CheckpointDistance = #(pos - vector3(data.coords.x, data.coords.y, data.coords.z))
local MaxDistance = GetMaxDistance(CurrentRaceData.Checkpoints[cp].offset)
if CheckpointDistance < MaxDistance then
if CurrentRaceData.TotalLaps == 0 then
if CurrentRaceData.CurrentCheckpoint + 1 < #CurrentRaceData.Checkpoints then
CurrentRaceData.CurrentCheckpoint = CurrentRaceData.CurrentCheckpoint + 1
SetNewWaypoint(CurrentRaceData.Checkpoints[CurrentRaceData.CurrentCheckpoint + 1].coords.x, CurrentRaceData.Checkpoints[CurrentRaceData.CurrentCheckpoint + 1].coords.y)
TriggerServerEvent('qb-lapraces:server:UpdateRacerData', CurrentRaceData.RaceId, CurrentRaceData.CurrentCheckpoint, CurrentRaceData.Lap, false)
DoPilePfx()
PlaySound(-1, "SELECT", "HUD_FRONTEND_DEFAULT_SOUNDSET", 0, 0, 1)
SetBlipScale(CurrentRaceData.Checkpoints[CurrentRaceData.CurrentCheckpoint].blip, 0.6)
SetBlipScale(CurrentRaceData.Checkpoints[CurrentRaceData.CurrentCheckpoint + 1].blip, 1.0)
else
DoPilePfx()
PlaySound(-1, "SELECT", "HUD_FRONTEND_DEFAULT_SOUNDSET", 0, 0, 1)
CurrentRaceData.CurrentCheckpoint = CurrentRaceData.CurrentCheckpoint + 1
TriggerServerEvent('qb-lapraces:server:UpdateRacerData', CurrentRaceData.RaceId, CurrentRaceData.CurrentCheckpoint, CurrentRaceData.Lap, true)
FinishRace()
end
else
if CurrentRaceData.CurrentCheckpoint + 1 > #CurrentRaceData.Checkpoints then
if CurrentRaceData.Lap + 1 > CurrentRaceData.TotalLaps then
DoPilePfx()
PlaySound(-1, "SELECT", "HUD_FRONTEND_DEFAULT_SOUNDSET", 0, 0, 1)
CurrentRaceData.CurrentCheckpoint = CurrentRaceData.CurrentCheckpoint + 1
TriggerServerEvent('qb-lapraces:server:UpdateRacerData', CurrentRaceData.RaceId, CurrentRaceData.CurrentCheckpoint, CurrentRaceData.Lap, true)
FinishRace()
else
DoPilePfx()
PlaySound(-1, "SELECT", "HUD_FRONTEND_DEFAULT_SOUNDSET", 0, 0, 1)
if CurrentRaceData.RaceTime < CurrentRaceData.BestLap then
CurrentRaceData.BestLap = CurrentRaceData.RaceTime
elseif CurrentRaceData.BestLap == 0 then
CurrentRaceData.BestLap = CurrentRaceData.RaceTime
end
CurrentRaceData.RaceTime = 0
CurrentRaceData.Lap = CurrentRaceData.Lap + 1
CurrentRaceData.CurrentCheckpoint = 1
SetNewWaypoint(CurrentRaceData.Checkpoints[CurrentRaceData.CurrentCheckpoint + 1].coords.x, CurrentRaceData.Checkpoints[CurrentRaceData.CurrentCheckpoint + 1].coords.y)
TriggerServerEvent('qb-lapraces:server:UpdateRacerData', CurrentRaceData.RaceId, CurrentRaceData.CurrentCheckpoint, CurrentRaceData.Lap, false)
end
else
CurrentRaceData.CurrentCheckpoint = CurrentRaceData.CurrentCheckpoint + 1
if CurrentRaceData.CurrentCheckpoint ~= #CurrentRaceData.Checkpoints then
SetNewWaypoint(CurrentRaceData.Checkpoints[CurrentRaceData.CurrentCheckpoint + 1].coords.x, CurrentRaceData.Checkpoints[CurrentRaceData.CurrentCheckpoint + 1].coords.y)
TriggerServerEvent('qb-lapraces:server:UpdateRacerData', CurrentRaceData.RaceId, CurrentRaceData.CurrentCheckpoint, CurrentRaceData.Lap, false)
SetBlipScale(CurrentRaceData.Checkpoints[CurrentRaceData.CurrentCheckpoint].blip, 0.6)
SetBlipScale(CurrentRaceData.Checkpoints[CurrentRaceData.CurrentCheckpoint + 1].blip, 1.0)
else
SetNewWaypoint(CurrentRaceData.Checkpoints[1].coords.x, CurrentRaceData.Checkpoints[1].coords.y)
TriggerServerEvent('qb-lapraces:server:UpdateRacerData', CurrentRaceData.RaceId, CurrentRaceData.CurrentCheckpoint, CurrentRaceData.Lap, false)
SetBlipScale(CurrentRaceData.Checkpoints[#CurrentRaceData.Checkpoints].blip, 0.6)
SetBlipScale(CurrentRaceData.Checkpoints[1].blip, 1.0)
end
DoPilePfx()
PlaySound(-1, "SELECT", "HUD_FRONTEND_DEFAULT_SOUNDSET", 0, 0, 1)
end
end
end
else
local data = CurrentRaceData.Checkpoints[CurrentRaceData.CurrentCheckpoint]
-- DrawText3Ds(data.coords.x, data.coords.y, data.coords.z, 'Ga hier staan')
DrawMarker(4, data.coords.x, data.coords.y, data.coords.z + 1.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.9, 1.5, 1.5, 255, 255, 255, 255, 0, 1, 0, 0, 0, 0, 0)
end
else
Wait(1000)
end
Wait(3)
end
end)
CreateThread(function()
while true do
if RaceData.InCreator then
GetClosestCheckpoint()
SetupPiles()
end
Wait(1000)
end
end)
CreateThread(function()
while true do
local Driver, plyVeh = Info()
if Driver then
if GetVehicleCurrentGear(plyVeh) < 3 and GetVehicleCurrentRpm(plyVeh) == 1.0 and math.ceil(GetEntitySpeed(plyVeh) * 2.236936) > 50 then
while GetVehicleCurrentRpm(plyVeh) > 0.6 do
SetVehicleCurrentRpm(plyVeh, 0.3)
Wait(1)
end
Wait(800)
end
end
Wait(500)
end
end)