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 = 'alizadev-vehiclesale:client:OpenContract', icon = 'fas fa-car', label = Lang:t('menu.view_contract'), Contract = i } }, distance = 2.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 = Config.okokBanking and (pData.iban or Lang:t('error.not_have_iban')) or pData.charinfo.account, phone = Config.lbPhone and exports["lb-phone"]:GetEquippedPhoneNumber() or 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 = Config.okokBanking and (sellerData.iban or Lang:t('error.not_have_iban')) or sellerData.charinfo.account, phone = Config.lbPhone and exports["lb-phone"]:GetEquippedPhoneNumber(sellerData) or 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('alizadev-vehiclesale:server:CheckModelName', function(DataReturning) -- Emergency araç kontrolü local vehicle = QBCore.Shared.Vehicles[DataReturning] if vehicle and vehicle.category == "emergency" then QBCore.Functions.Notify(Lang:t('error.no_car_sale'), 'error') return end local vehicleData = {} vehicleData.ent = GetVehiclePedIsUsing(PlayerPedId()) vehicleData.model = DataReturning vehicleData.plate = model vehicleData.mods = QBCore.Functions.GetVehicleProperties(vehicleData.ent) vehicleData.desc = data.desc TriggerServerEvent('alizadev-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('alizadev-vehiclesale:client:OpenContract', data) else if IsPedInAnyVehicle(PlayerPedId(), false) then listen = false TriggerEvent('alizadev-occasions:client:MainMenu') --TriggerEvent('alizadev-vehiclesale: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('alizadev-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) -- Satın alma öncesi kontrol local PlayerData = QBCore.Functions.GetPlayerData() if CurrentVehicle and CurrentVehicle.owner == PlayerData.citizenid then QBCore.Functions.Notify(Lang:t('error.not_buy_own_car'), 'error', 3500) SetNuiFocus(false, false) CurrentVehicle = {} cb('error') return end TriggerServerEvent('alizadev-occasions:server:buyVehicle', CurrentVehicle) cb('ok') end) RegisterNUICallback('takeVehicleBack', function(_, cb) TriggerServerEvent('alizadev-occasions:server:ReturnVehicle', CurrentVehicle) cb('ok') end) -- Events RegisterNetEvent('alizadev-occasions:client:BuyFinished', function(vehdata) -- Kontrol et - eğer araç satıcının kendisiyse işlemi engelle local PlayerData = QBCore.Functions.GetPlayerData() 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('alizadev-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('alizadev-occasions:server:checkVehicleOwner', function(owned, balance) if owned then if balance < 1 then TriggerServerEvent('alizadev-occasions:server:sellVehicleBack', vehicleData) QBCore.Functions.DeleteVehicle(vehicle) 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, vehicleData.plate) else QBCore.Functions.Notify(Lang:t('error.not_in_veh'), 'error', 4500) end end) RegisterNetEvent('alizadev-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('alizadev-occasions:server:getVehicles', function(vehicles) despawnOccasionsVehicles() spawnOccasionsVehicles(vehicles) end) end end) RegisterNetEvent('alizadev-vehiclesale:client:SellVehicle', function() local VehiclePlate = QBCore.Functions.GetPlate(GetVehiclePedIsIn(PlayerPedId())) if Config.JGDealer then QBCore.Functions.TriggerCallback('jg-advancedgarages:server:checkVehicleOwner', function(owned, balance) CheckVehicleOwnership(owned, balance, VehiclePlate) end, VehiclePlate) else QBCore.Functions.TriggerCallback('alizadev-occasions:server:checkVehicleOwner', function(owned, balance) CheckVehicleOwnership(owned, balance, VehiclePlate) end, VehiclePlate) end end) -- Helper function to handle the ownership check logic function CheckVehicleOwnership(owned, balance, VehiclePlate) if owned then if balance < 1 then QBCore.Functions.TriggerCallback('alizadev-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 RegisterNetEvent('alizadev-vehiclesale:client:OpenContract', function(data) CurrentVehicle = occasionVehicles[Zone][data.Contract] if CurrentVehicle then QBCore.Functions.TriggerCallback('alizadev-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('alizadev-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 = 'alizadev-vehiclesale:client:SellVehicle', } } } -- Add sell back option only if Config.sellBack is true if Config.sellBack then table.insert(MainMenu, { header = Lang:t('menu.sell_back'), txt = Lang:t('menu.sell_back_help'), params = { event = 'alizadev-occasions:client:SellBackCar', } }) end exports['qb-menu']:openMenu(MainMenu) end) -- Threads CreateThread(function() for _, cars in pairs(Config.Zones) do local OccasionBlip = AddBlipForCoord(cars.SellVehicle.x, cars.SellVehicle.y, cars.SellVehicle.z) -- Blip ayarlarını config'den al veya varsayılan değerleri kullan SetBlipSprite(OccasionBlip, cars.Blip and cars.Blip.Sprite or 326) SetBlipDisplay(OccasionBlip, cars.Blip and cars.Blip.Display or 4) SetBlipScale(OccasionBlip, cars.Blip and cars.Blip.Scale or 0.75) SetBlipColour(OccasionBlip, cars.Blip and cars.Blip.Color or 3) SetBlipAsShortRange(OccasionBlip, cars.Blip and cars.Blip.ShortRange or true) BeginTextCommandSetBlipName('STRING') AddTextComponentSubstringPlayerName(Lang:t('info.used_vehicle_lot')) EndTextCommandSetBlipName(OccasionBlip) 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'), 'left') 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'), 'left') 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)