local QBCore = exports['qb-core']:GetCoreObject() local Zone = nil local TextShown = false local AcitveZone = {} local CurrentVehicle = {} local SpawnZone = {} local EntityZones = {} local occasionVehicles = {} -- Functions local function spawnOccasionsVehicles(vehicles) if Zone then local oSlot = Config.Zones[Zone].VehicleSpots if not occasionVehicles[Zone] then occasionVehicles[Zone] = {} end if vehicles then for i = 1, #vehicles, 1 do local model = GetHashKey(vehicles[i].model) RequestModel(model) while not HasModelLoaded(model) do Wait(0) end occasionVehicles[Zone][i] = { car = CreateVehicle(model, oSlot[i].x, oSlot[i].y, oSlot[i].z, false, false), loc = vector3(oSlot[i].x, oSlot[i].y, oSlot[i].z), price = vehicles[i].price, owner = vehicles[i].seller, model = vehicles[i].model, plate = vehicles[i].plate, oid = vehicles[i].occasionid, desc = vehicles[i].description, mods = vehicles[i].mods } QBCore.Functions.SetVehicleProperties(occasionVehicles[Zone][i].car, json.decode(occasionVehicles[Zone][i].mods)) SetModelAsNoLongerNeeded(model) SetVehicleOnGroundProperly(occasionVehicles[Zone][i].car) SetEntityInvincible(occasionVehicles[Zone][i].car,true) SetEntityHeading(occasionVehicles[Zone][i].car, oSlot[i].w) SetVehicleDoorsLocked(occasionVehicles[Zone][i].car, 3) SetVehicleNumberPlateText(occasionVehicles[Zone][i].car, occasionVehicles[Zone][i].oid) FreezeEntityPosition(occasionVehicles[Zone][i].car,true) if Config.UseTarget then if not EntityZones then EntityZones = {} end EntityZones[i] = exports['qb-target']:AddTargetEntity(occasionVehicles[Zone][i].car, { options = { { type = "client", event = "qb-vehiclesales:client:OpenContract", icon = "fas fa-car", label = Lang:t("menu.view_contract"), Contract = i } }, distance = 3.0 }) end end end end end local function despawnOccasionsVehicles() if not Zone then return end local oSlot = Config.Zones[Zone].VehicleSpots for i = 1, #oSlot, 1 do local loc = oSlot[i] local oldVehicle = GetClosestVehicle(loc.x, loc.y, loc.z, 1.3, 0, 70) if oldVehicle then QBCore.Functions.DeleteVehicle(oldVehicle) end if EntityZones[i] and Config.UseTarget then exports['qb-target']:RemoveZone(EntityZones[i]) end end EntityZones = {} end local function openSellContract(bool) local pData = QBCore.Functions.GetPlayerData() SetNuiFocus(bool, bool) SendNUIMessage({ action = "sellVehicle", showTakeBackOption = false, bizName = Config.Zones[Zone].BusinessName, sellerData = { firstname = pData.charinfo.firstname, lastname = pData.charinfo.lastname, account = pData.charinfo.account, phone = pData.charinfo.phone }, plate = QBCore.Functions.GetPlate(GetVehiclePedIsUsing(PlayerPedId())) }) end local function openBuyContract(sellerData, vehicleData) local pData = QBCore.Functions.GetPlayerData() SetNuiFocus(true, true) SendNUIMessage({ action = "buyVehicle", showTakeBackOption = sellerData.charinfo.firstname == pData.charinfo.firstname and sellerData.charinfo.lastname == pData.charinfo.lastname, bizName = Config.Zones[Zone].BusinessName, sellerData = { firstname = sellerData.charinfo.firstname, lastname = sellerData.charinfo.lastname, account = sellerData.charinfo.account, phone = sellerData.charinfo.phone }, vehicleData = { desc = vehicleData.desc, price = vehicleData.price }, plate = vehicleData.plate }) end local function sellVehicleWait(price) DoScreenFadeOut(250) Wait(250) QBCore.Functions.DeleteVehicle(GetVehiclePedIsIn(PlayerPedId())) Wait(1500) DoScreenFadeIn(250) QBCore.Functions.Notify(Lang:t('success.car_up_for_sale', { value = price }), 'success') PlaySound(-1, "SELECT", "HUD_FRONTEND_DEFAULT_SOUNDSET", 0, 0, 1) end local function SellData(data, model) QBCore.Functions.TriggerCallback("qb-vehiclesales:server:CheckModelName",function(DataReturning) local vehicleData = {} vehicleData.ent = GetVehiclePedIsUsing(PlayerPedId()) vehicleData.model = DataReturning vehicleData.plate = model vehicleData.mods = QBCore.Functions.GetVehicleProperties(vehicleData.ent) vehicleData.desc = data.desc TriggerServerEvent('qb-occasions:server:sellVehicle', data.price, vehicleData) sellVehicleWait(data.price) end, model) end local listen = false local function Listen4Control(spot) -- Uses this to listen for controls to open various menus. listen = true CreateThread(function() while listen do if IsControlJustReleased(0, 38) then -- E if spot then local data = {Contract = spot} TriggerEvent('qb-vehiclesales:client:OpenContract', data) else if IsPedInAnyVehicle(PlayerPedId(), false) then listen = false TriggerEvent('qb-occasions:client:MainMenu') --TriggerEvent('qb-vehiclesales:client:SellVehicle') else QBCore.Functions.Notify(Lang:t("error.not_in_veh"), "error", 4500) end end end Wait(0) end end) end ---- ** Main Zone Functions ** ---- local function CreateZones() for k, v in pairs(Config.Zones) do local SellSpot = PolyZone:Create(v.PolyZone, { name = k, minZ = v.MinZ, maxZ = v.MaxZ, debugPoly = false }) SellSpot:onPlayerInOut(function(isPointInside) if isPointInside and Zone ~= k then Zone = k QBCore.Functions.TriggerCallback('qb-occasions:server:getVehicles', function(vehicles) despawnOccasionsVehicles() spawnOccasionsVehicles(vehicles) end) else despawnOccasionsVehicles() Zone = nil end end) AcitveZone[k] = SellSpot end end local function DeleteZones() for k in pairs(AcitveZone) do AcitveZone[k]:destroy() end AcitveZone = {} end local function IsCarSpawned(Car) local bool = false if occasionVehicles then for k in pairs(occasionVehicles[Zone]) do if k == Car then bool = true break end end end return bool end -- NUI Callbacks RegisterNUICallback('sellVehicle', function(data, cb) local plate = QBCore.Functions.GetPlate(GetVehiclePedIsUsing(PlayerPedId())) --Getting the plate and sending to the function SellData(data,plate) cb('ok') end) RegisterNUICallback('close', function(_, cb) SetNuiFocus(false, false) cb('ok') end) RegisterNUICallback('buyVehicle', function(_, cb) TriggerServerEvent('qb-occasions:server:buyVehicle', CurrentVehicle) cb('ok') end) RegisterNUICallback('takeVehicleBack', function(_, cb) TriggerServerEvent('qb-occasions:server:ReturnVehicle', CurrentVehicle) cb('ok') end) -- Events RegisterNetEvent('qb-occasions:client:BuyFinished', function(vehdata) local vehmods = json.decode(vehdata.mods) DoScreenFadeOut(250) Wait(500) QBCore.Functions.TriggerCallback('QBCore:Server:SpawnVehicle', function(netId) local veh = NetToVeh(netId) SetVehicleNumberPlateText(veh, vehdata.plate) SetEntityHeading(veh, Config.Zones[Zone].BuyVehicle.w) TaskWarpPedIntoVehicle(PlayerPedId(), veh, -1) SetVehicleFuelLevel(veh, 100) QBCore.Functions.Notify(Lang:t('success.vehicle_bought'), "success", 2500) TriggerEvent("vehiclekeys:client:SetOwner", vehdata.plate) SetVehicleEngineOn(veh, true, true) Wait(500) QBCore.Functions.SetVehicleProperties(veh, vehmods) end, vehdata.model, Config.Zones[Zone].BuyVehicle, true) Wait(500) DoScreenFadeIn(250) CurrentVehicle = {} end) RegisterNetEvent('qb-occasions:client:SellBackCar', function() local ped = PlayerPedId() if IsPedInAnyVehicle(ped, false) then local vehicleData = {} local vehicle = GetVehiclePedIsIn(ped, false) vehicleData.model = GetEntityModel(vehicle) vehicleData.plate = GetVehicleNumberPlateText(vehicle) QBCore.Functions.TriggerCallback('qb-garage:server:checkVehicleOwner', function(owned, balance) if owned then TriggerServerEvent('qb-occasions:server:sellVehicleBack', vehicleData) QBCore.Functions.DeleteVehicle(vehicle) else QBCore.Functions.Notify(Lang:t('error.not_your_vehicle'), 'error', 3500) end end, vehicleData.plate) else QBCore.Functions.Notify(Lang:t("error.not_in_veh"), "error", 4500) end end) RegisterNetEvent('qb-occasions:client:ReturnOwnedVehicle', function(vehdata) local vehmods = json.decode(vehdata.mods) DoScreenFadeOut(250) Wait(500) QBCore.Functions.TriggerCallback('QBCore:Server:SpawnVehicle', function(netId) local veh = NetToVeh(netId) SetVehicleNumberPlateText(veh, vehdata.plate) SetEntityHeading(veh, Config.Zones[Zone].BuyVehicle.w) TaskWarpPedIntoVehicle(PlayerPedId(), veh, -1) SetVehicleFuelLevel(veh, 100) QBCore.Functions.Notify(Lang:t('info.vehicle_returned')) TriggerEvent("vehiclekeys:client:SetOwner", vehdata.plate) SetVehicleEngineOn(veh, true, true) Wait(500) QBCore.Functions.SetVehicleProperties(veh, vehmods) end, vehdata.model, Config.Zones[Zone].BuyVehicle, true) Wait(500) DoScreenFadeIn(250) CurrentVehicle = {} end) RegisterNetEvent('qb-occasion:client:refreshVehicles', function() if Zone then QBCore.Functions.TriggerCallback('qb-occasions:server:getVehicles', function(vehicles) despawnOccasionsVehicles() spawnOccasionsVehicles(vehicles) end) end end) RegisterNetEvent('qb-vehiclesales:client:SellVehicle', function() local VehiclePlate = QBCore.Functions.GetPlate(GetVehiclePedIsIn(PlayerPedId())) QBCore.Functions.TriggerCallback('qb-garage:server:checkVehicleOwner', function(owned, balance) if owned then -- if balance < 1 then QBCore.Functions.TriggerCallback('qb-occasions:server:getVehicles', function(vehicles) if vehicles == nil or #vehicles < #Config.Zones[Zone].VehicleSpots then openSellContract(true) else QBCore.Functions.Notify(Lang:t('error.no_space_on_lot'), 'error', 3500) end end) -- else -- QBCore.Functions.Notify(Lang:t('error.finish_payments'), 'error', 3500) -- end else QBCore.Functions.Notify(Lang:t('error.not_your_vehicle'), 'error', 3500) end end, VehiclePlate) end) RegisterNetEvent('qb-vehiclesales:client:OpenContract', function(data) CurrentVehicle = occasionVehicles[Zone][data.Contract] if CurrentVehicle then QBCore.Functions.TriggerCallback('qb-occasions:server:getSellerInformation', function(info) if info then info.charinfo = json.decode(info.charinfo) else info = {} info.charinfo = { firstname = Lang:t('charinfo.firstname'), lastname = Lang:t('charinfo.lastname'), account = Lang:t('charinfo.account'), phone = Lang:t('charinfo.phone') } end openBuyContract(info, CurrentVehicle) end, CurrentVehicle.owner) else QBCore.Functions.Notify(Lang:t("error.not_for_sale"), 'error', 7500) end end) RegisterNetEvent('qb-occasions:client:MainMenu', function() local MainMenu = { { isMenuHeader = true, header = Config.Zones[Zone].BusinessName }, { header = Lang:t("menu.sell_vehicle"), txt = Lang:t("menu.sell_vehicle_help"), params = { event = 'qb-vehiclesales:client:SellVehicle', } }, { header = Lang:t("menu.sell_back"), txt = Lang:t("menu.sell_back_help"), params = { event = 'qb-occasions:client:SellBackCar', } } } exports['qb-menu']:openMenu(MainMenu) end) -- Threads CreateThread(function() RequestStreamedTextureDict("shops", 1) while not HasStreamedTextureDictLoaded("shops") do Wait(0) end for _, cars in pairs(Config.Zones) do local OccasionBlip = AddBlipForCoord(cars.SellVehicle.x, cars.SellVehicle.y, cars.SellVehicle.z) SetBlipSprite (OccasionBlip, 326) SetBlipDisplay(OccasionBlip, 4) SetBlipScale (OccasionBlip, 0.75) SetBlipAsShortRange(OccasionBlip, true) SetBlipColour(OccasionBlip, 3) BeginTextCommandSetBlipName("STRING") AddTextComponentSubstringPlayerName(Lang:t('info.used_vehicle_lot')) EndTextCommandSetBlipName(OccasionBlip) exports['blip_info']:SetBlipInfoTitle(OccasionBlip, Lang:t('info.used_vehicle_lot'), 0) exports['blip_info']:SetBlipInfoImage(OccasionBlip, "shops", "usedcars") exports['blip_info']:AddBlipInfoName(OccasionBlip, "Ejet af", "Larry") exports['blip_info']:AddBlipInfoName(OccasionBlip, "Type", "Forhandler") exports['blip_info']:AddBlipInfoHeader(OccasionBlip, "") exports['blip_info']:AddBlipInfoHeader(OccasionBlip, "") exports['blip_info']:AddBlipInfoText(OccasionBlip, "Ikke tilfreds med din bil mere? Du kan sælge den her og tjene lidt penge") end end) CreateThread(function() for k, cars in pairs(Config.Zones) do SpawnZone[k] = CircleZone:Create(vector3(cars.SellVehicle.x, cars.SellVehicle.y, cars.SellVehicle.z), 3.0, { name="OCSell"..k, debugPoly = false, }) SpawnZone[k]:onPlayerInOut(function(isPointInside) if isPointInside and IsPedInAnyVehicle(PlayerPedId(), false) then exports['qb-core']:DrawText(Lang:t("menu.interaction"), 'top') TextShown = true Listen4Control() else listen = false if TextShown then TextShown = false exports['qb-core']:HideText() end end end) if not Config.UseTarget then for k2, v in pairs(Config.Zones[k].VehicleSpots) do local VehicleZones = BoxZone:Create(vector3(v.x, v.y, v.z), 4.3, 3.6, { name="VehicleSpot"..k..k2, debugPoly = false, minZ = v.z-2, maxZ = v.z+2, }) VehicleZones:onPlayerInOut(function(isPointInside) if isPointInside and IsCarSpawned(k2) then exports['qb-core']:DrawText(Lang:t("menu.view_contract_int"), 'top') TextShown = true Listen4Control(k2) else listen = false if TextShown then TextShown = false exports['qb-core']:HideText() end end end) end end end end) ---- ** Mostly just to ensure you can restart resources live without issues, also improves the code slightly. ** ---- RegisterNetEvent('QBCore:Client:OnPlayerLoaded', function() CreateZones() end) RegisterNetEvent('QBCore:Client:OnPlayerUnload', function() DeleteZones() end) AddEventHandler('onResourceStart', function(resourceName) if GetCurrentResourceName() == resourceName then CreateZones() end end) AddEventHandler('onResourceStop', function(resourceName) if GetCurrentResourceName() == resourceName then DeleteZones() despawnOccasionsVehicles() end end)