forked from Simnation/Main
367 lines
No EOL
12 KiB
Lua
367 lines
No EOL
12 KiB
Lua
local washingVehicle = false
|
|
local WaitingForWash = false
|
|
|
|
local ptfxData = {
|
|
{
|
|
dict = 'cut_test',
|
|
name = 'exp_hydrant',
|
|
offset = {0.0,0.0,4.0},
|
|
rot = {0.0, 180.0, 0.0},
|
|
scale = 0.5,
|
|
},
|
|
|
|
{
|
|
dict = 'cut_test',
|
|
name = 'exp_hydrant',
|
|
offset = {-0.5,0.0,4.0},
|
|
rot = {0.0, 180.0, 0.0},
|
|
scale = 0.5,
|
|
},
|
|
|
|
{
|
|
dict = 'cut_test',
|
|
name = 'exp_hydrant',
|
|
offset = {-1.0,0.0,4.0},
|
|
rot = {0.0, 180.0, 0.0},
|
|
scale = 0.5,
|
|
},
|
|
|
|
{
|
|
dict = 'cut_test',
|
|
name = 'exp_hydrant',
|
|
offset = {-1.5,0.0,4.0},
|
|
rot = {0.0, 180.0, 0.0},
|
|
scale = 0.5,
|
|
},
|
|
|
|
{
|
|
dict = 'cut_test',
|
|
name = 'exp_hydrant',
|
|
offset = {-2.0,0.0,4.0},
|
|
rot = {0.0, 180.0, 0.0},
|
|
scale = 0.5,
|
|
},
|
|
|
|
|
|
{
|
|
dict = 'cut_test',
|
|
name = 'exp_hydrant',
|
|
offset = {0.5,0.0,4.0},
|
|
rot = {0.0, 180.0, 0.0},
|
|
scale = 0.5,
|
|
},
|
|
|
|
{
|
|
dict = 'cut_test',
|
|
name = 'exp_hydrant',
|
|
offset = {1.0,0.0,4.0},
|
|
rot = {0.0, 180.0, 0.0},
|
|
scale = 0.5,
|
|
},
|
|
|
|
{
|
|
dict = 'cut_test',
|
|
name = 'exp_hydrant',
|
|
offset = {1.5,0.0,4.0},
|
|
rot = {0.0, 180.0, 0.0},
|
|
scale = 0.5,
|
|
},
|
|
|
|
{
|
|
dict = 'cut_test',
|
|
name = 'exp_hydrant',
|
|
offset = {2.0,0.0,4.0},
|
|
rot = {0.0, 180.0, 0.0},
|
|
scale = 0.5,
|
|
},
|
|
|
|
{
|
|
dict = 'scr_fbi5a',
|
|
name = 'scr_tunnel_vent_bubbles',
|
|
offset = {0.0,0.0,0.0},
|
|
rot = {0.0,180.0,0.0},
|
|
scale = 2.0,
|
|
},
|
|
|
|
{
|
|
dict = 'scr_fbi5a',
|
|
name = 'scr_tunnel_vent_bubbles',
|
|
offset = {0.0,-1.0,0.0},
|
|
rot = {0.0,180.0,0.0},
|
|
scale = 1.0,
|
|
},
|
|
|
|
{
|
|
dict = 'scr_fbi5a',
|
|
name = 'scr_tunnel_vent_bubbles',
|
|
offset = {0.0,1.0,0.0},
|
|
rot = {0.0,180.0,0.0},
|
|
scale = 1.0,
|
|
},
|
|
|
|
{
|
|
dict = 'scr_fbi5a',
|
|
name = 'scr_tunnel_vent_bubbles',
|
|
offset = {0.0,-2.0,0.0},
|
|
rot = {0.0,180.0,0.0},
|
|
scale = 1.0,
|
|
},
|
|
|
|
{
|
|
dict = 'scr_fbi5a',
|
|
name = 'scr_tunnel_vent_bubbles',
|
|
offset = {0.0,2.0,0.0},
|
|
rot = {0.0,180.0,0.0},
|
|
scale = 1.0,
|
|
},
|
|
}
|
|
|
|
local function RequestNetworkControlOfEntity(entity)
|
|
NetworkRequestControlOfEntity(entity)
|
|
|
|
local timeout = 2000
|
|
|
|
while timeout > 0 and not NetworkHasControlOfEntity(entity) do
|
|
Wait(100)
|
|
timeout = timeout - 100
|
|
end
|
|
|
|
timeout = 2000
|
|
|
|
SetEntityAsMissionEntity(entity, true, true)
|
|
|
|
while timeout > 0 and not IsEntityAMissionEntity(entity) do
|
|
Wait(100)
|
|
timeout = timeout - 100
|
|
end
|
|
end
|
|
|
|
local function RequestParticleFX(dict)
|
|
RequestNamedPtfxAsset(dict)
|
|
while not HasNamedPtfxAssetLoaded(dict) do Wait(0) end
|
|
end
|
|
|
|
local function LoadPropDict(model)
|
|
if not IsModelInCdimage(model) then
|
|
print('ERROR: The model that is required does not exist, Contact a developer of the server.')
|
|
return
|
|
end
|
|
local time = 30
|
|
while not HasModelLoaded(model) and time > 0 do RequestModel(model) Wait(100) time -= 1 end
|
|
if time <= 0 then print('ERROR: loading required model failed, Contact a server developer.') end
|
|
end
|
|
|
|
local function CreateProp(model, coords)
|
|
if not HasModelLoaded(model) then; LoadPropDict(model); end
|
|
local prop = CreateObjectNoOffset(model, coords.x, coords.y, coords.z, false, false, false)
|
|
SetEntityAsMissionEntity(prop, true, true)
|
|
FreezeEntityPosition(prop, true)
|
|
SetEntityCollision(prop, false, true)
|
|
return prop
|
|
end
|
|
|
|
RegisterNetEvent('carwash:DoVehicleWashParticles')
|
|
AddEventHandler('carwash:DoVehicleWashParticles', function(vehNet, washer, use_props)
|
|
if NetworkDoesEntityExistWithNetworkId(vehNet) then
|
|
if washer == GetPlayerServerId(PlayerId()) then
|
|
WaitingForWash = true
|
|
washer = true
|
|
end
|
|
|
|
local vehicle = NetworkGetEntityFromNetworkId(vehNet)
|
|
local ptfxHandles = {}
|
|
local side_props = nil
|
|
local min_offsets, max_offsets = GetModelDimensions(GetEntityModel(vehicle))
|
|
|
|
if use_props then
|
|
local _, max_prop_dim = GetModelDimensions(`prop_carwash_roller_vert`)
|
|
local left_offest = GetOffsetFromEntityInWorldCoords(vehicle, min_offsets.x, min_offsets.y, min_offsets.z - 0.5);left_offest = vector3(left_offest.x + max_prop_dim.x, left_offest.y, left_offest.z)
|
|
local right_offset = GetOffsetFromEntityInWorldCoords(vehicle, max_offsets.x, min_offsets.y, min_offsets.z - 0.5);right_offset = vector3(right_offset.x - max_prop_dim.x, right_offset.y, right_offset.z)
|
|
|
|
side_props = {
|
|
{prop = CreateProp(`prop_carwash_roller_vert`, left_offest), offset = vector3(min_offsets.x - (max_prop_dim.x - 0.2), min_offsets.y, max_prop_dim.z/2)},
|
|
{prop = CreateProp(`prop_carwash_roller_vert`, right_offset), offset = vector3(max_offsets.x + (max_prop_dim.x - 0.2), min_offsets.y, max_prop_dim.z/2)},
|
|
}
|
|
|
|
for i =1, #side_props, 1 do
|
|
Citizen.CreateThread(function()
|
|
while side_props and side_props[i] and DoesEntityExist(side_props[i].prop) do
|
|
if i == 1 then
|
|
SetEntityHeading(side_props[i].prop, ((GetEntityHeading(side_props[i].prop) + 0.75) + 360) %360)
|
|
elseif i == 2 then
|
|
SetEntityHeading(side_props[i].prop, ((GetEntityHeading(side_props[i].prop) - 0.75) + 360) %360)
|
|
end
|
|
Citizen.Wait(0)
|
|
end
|
|
end)
|
|
end
|
|
end
|
|
|
|
for index, ptfx in pairs(ptfxData) do
|
|
RequestParticleFX(ptfx.dict)
|
|
UseParticleFxAssetNextCall(ptfx.dict)
|
|
local CreatedParticle = StartNetworkedParticleFxLoopedOnEntity(ptfx.name, vehicle, ptfx.offset[1], ptfx.offset[2], ptfx.offset[3], ptfx.rot[1], ptfx.rot[2], ptfx.rot[3], ptfx.scale, false, false, false)
|
|
table.insert(ptfxHandles, CreatedParticle)
|
|
end
|
|
|
|
local offset = min_offsets.y
|
|
local prop_offset = min_offsets.y
|
|
|
|
while offset < max_offsets.y and DoesEntityExist(vehicle) do
|
|
for i = 1, #ptfxHandles do
|
|
SetParticleFxLoopedOffsets(ptfxHandles[i], ptfxData[i].offset[1], offset, ptfxData[i].offset[3], ptfxData[i].rot[1], ptfxData[i].rot[2], ptfxData[i].rot[3])
|
|
end
|
|
|
|
if side_props ~= nil then
|
|
for i = 1, #side_props, 1 do
|
|
SetEntityCoordsNoOffset(side_props[i].prop, GetOffsetFromEntityInWorldCoords(vehicle, side_props[i].offset.x, prop_offset, side_props[i].offset.z))
|
|
end
|
|
prop_offset += 0.0055
|
|
end
|
|
|
|
offset += 0.0055
|
|
Wait(0)
|
|
end
|
|
|
|
if Config.double_clean == true then
|
|
while min_offsets.y < offset and DoesEntityExist(vehicle) do
|
|
for i = 1, #ptfxHandles, 1 do
|
|
SetParticleFxLoopedOffsets(ptfxHandles[i], ptfxData[i].offset[1], offset, ptfxData[i].offset[3], ptfxData[i].rot[1], ptfxData[i].rot[2], ptfxData[i].rot[3])
|
|
end
|
|
if side_props ~= nil then
|
|
for i = 1, #side_props, 1 do
|
|
SetEntityCoordsNoOffset(side_props[i].prop, GetOffsetFromEntityInWorldCoords(vehicle, side_props[i].offset.x, prop_offset, side_props[i].offset.z))
|
|
end
|
|
prop_offset -= 0.0055
|
|
end
|
|
offset -= 0.0055
|
|
Wait(0)
|
|
end
|
|
end
|
|
|
|
for i = 1, #ptfxHandles do StopParticleFxLooped(ptfxHandles[i], false) end
|
|
|
|
if side_props ~= nil then
|
|
for i = 1, #side_props, 1 do DeleteEntity(side_props[i].prop) end
|
|
side_props = nil
|
|
end
|
|
|
|
if washer == true then
|
|
RequestNetworkControlOfEntity(vehicle)
|
|
SetVehicleDirtLevel(vehicle, 0.0)
|
|
WashDecalsFromVehicle(vehicle, 1.0)
|
|
Wait(1000)
|
|
FreezeEntityPosition(vehicle, false)
|
|
Notify('Vehicle Washed', 'success')
|
|
WaitingForWash = false
|
|
washingVehicle = false
|
|
end
|
|
end
|
|
end)
|
|
|
|
local function WashVehicle(vehicle, use_props)
|
|
if washingVehicle then return end
|
|
washingVehicle = true
|
|
TriggerCallback("carwash:CanPurchaseCarWash", function(paid)
|
|
if paid then
|
|
FreezeEntityPosition(vehicle, true)
|
|
TriggerServerEvent('carwash:DoVehicleWashParticles', VehToNet(vehicle), use_props)
|
|
else
|
|
washingVehicle = false
|
|
end
|
|
end)
|
|
end
|
|
|
|
local function ShowHelpNotification(msg, thisFrame, beep, duration)
|
|
AddTextEntry('HelpNotification', msg)
|
|
|
|
if thisFrame then
|
|
DisplayHelpTextThisFrame('HelpNotification', false)
|
|
else
|
|
if (beep == nil or beep == false) then beep = false else beep = true end
|
|
BeginTextCommandDisplayHelp('HelpNotification')
|
|
EndTextCommandDisplayHelp(0, false, beep, duration or -1)
|
|
end
|
|
end
|
|
|
|
Citizen.CreateThread(function()
|
|
while true do
|
|
local sleep = 1000
|
|
local PlayerPed = PlayerPedId()
|
|
if IsPedInAnyVehicle(PlayerPed, false) and not isWashingVehicle then
|
|
local myVehicle = GetVehiclePedIsIn(PlayerPed)
|
|
if GetPedInVehicleSeat(myVehicle, -1) == PlayerPed and (Config.only_dirty_vehicles == true and GetVehicleDirtLevel(myVehicle) >= 0.1 or Config.only_dirty_vehicles == false) then
|
|
local coords = GetEntityCoords(PlayerPed)
|
|
for _, carwash in pairs(Config.locations) do
|
|
local dist = #(coords - carwash.location)
|
|
if dist <= 10.0 then
|
|
sleep = 100
|
|
if dist <= 2.0 then
|
|
ShowHelpNotification((Config.button[1]):format(Config.cost), true, false, -1)
|
|
sleep = 0
|
|
if IsControlJustPressed(Config.button[2], Config.button[3]) then
|
|
WashVehicle(myVehicle, carwash.use_props)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
Citizen.Wait(sleep)
|
|
end
|
|
end)
|
|
|
|
local function CreateCarwashBlip(coords, name)
|
|
local blip = AddBlipForCoord(coords)
|
|
|
|
SetBlipSprite(blip, 100)
|
|
SetBlipScale(blip, 0.8)
|
|
SetBlipColour(blip, 2)
|
|
SetBlipDisplay(blip, 4)
|
|
SetBlipAsShortRange(blip, true)
|
|
|
|
BeginTextCommandSetBlipName("STRING")
|
|
AddTextComponentString(name)
|
|
EndTextCommandSetBlipName(blip)
|
|
|
|
return blip
|
|
end
|
|
|
|
if Config.show_all_blips then
|
|
local blips = {}
|
|
|
|
for _, carwash in pairs(Config.locations) do
|
|
if carwash.show_blip == true then
|
|
blips[#blips +1] = CreateCarwashBlip(carwash.location, carwash.name)
|
|
end
|
|
end
|
|
else
|
|
Citizen.CreateThread(function()
|
|
local currentCarWashBlip = nil
|
|
local currentCarWashBlipLocation = nil
|
|
|
|
while true do
|
|
local coords = GetEntityCoords(PlayerPedId())
|
|
local closest = 999999
|
|
local closestCoords, closestName
|
|
|
|
for _, carwash in pairs(Config.locations) do
|
|
local dstcheck = #(coords.xy - carwash.location.xy)
|
|
|
|
if dstcheck < closest and carwash.show_blip == true then
|
|
closest = dstcheck
|
|
closestCoords = carwash.location
|
|
closestName = carwash.name
|
|
end
|
|
end
|
|
|
|
if currentCarWashBlipLocation ~= closestCoords then
|
|
if DoesBlipExist(currentCarWashBlip) then RemoveBlip(currentCarWashBlip) end
|
|
currentCarWashBlip = CreateCarwashBlip(closestCoords, closestName)
|
|
currentCarWashBlipLocation = closestCoords
|
|
end
|
|
|
|
Citizen.Wait(10000)
|
|
end
|
|
end)
|
|
end |