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