gta6/prompts
vehicles
Freeintermediatevehicles

Car Dealership: Preview, Purchase, Deliver

A QBCore dealership that spawns a frozen preview car, charges the bank server-side, writes the owned vehicle to the DB, and delivers it.

NON-TESTÉ — the reference Lua is syntax-validated, not run in a live FiveM server. Adapt and test on your own dev server before shipping.
Est. Lua
~68 loc
Claude
Claude Opus 4.x / Sonnet 4.x
Validation
syntax-validated
Updated
2026-06-24

Description

A showroom dealership for QBCore servers: a player previews a model (a frozen, locked display car), confirms purchase, the server validates funds and charges the bank, the vehicle is written to player_vehicles, and a real owned car with a generated plate is delivered. This is the economy backbone of any roleplay server's vehicle gameplay.

Prompt Template

You are writing a FiveM resource for QBCore. Produce ONE Lua file with clearly
separated client and server sections (banner comments). Use
`exports['qb-core']:GetCoreObject()` on BOTH sides.

Client:
- A preview spawn function: RequestModel + `while not HasModelLoaded do Wait(0) end`,
  CreateVehicle at a fixed showroom vector4 [PREVIEW_COORDS], then
  FreezeEntityPosition(veh,true) and SetVehicleDoorsLocked(veh,2). Delete any prior
  preview before spawning a new one.
- RegisterNetEvent "dealership:preview" (model) and "dealership:buy"
  (model, price) — buy only TriggerServerEvent("dealership:purchase", model, price).
- RegisterNetEvent "dealership:deliver" (model, plate) that spawns the real car
  under the player, SetVehicleNumberPlateText, seats them, deletes the preview.

Server:
- RegisterNetEvent "dealership:purchase": resolve Player via
  QBCore.Functions.GetPlayer(source); reject if nil. Check money.bank >= price
  SERVER-SIDE (never trust the client). RemoveMoney("bank", price, "vehicle-purchase").
- Generate a plate, INSERT into player_vehicles (citizenid, vehicle, plate, state).
- TriggerClientEvent("dealership:deliver", src, model, plate).

Requirements: all money logic server-side; price [PRICES per model]; showroom coords
[PREVIEW_COORDS]. Modern natives, no placeholders.

Expected Output

The reference Lua at content/expected-outputs/vehicles/02-car-dealership.lua implements the full preview → server-validated purchase → DB insert → delivery loop. The fxmanifest splits client_script 'client.lua' / server_script 'server.lua', depends on qb-core and oxmysql, and the money check + DB write live entirely server-side.

02-car-dealership.lua69 lines
-- Resource: qb-dealership
-- Car dealership: spawn a preview vehicle, purchase it server-side, deliver to player.
-- Framework: QBCore. Client + server in one file (separated by banners).

-- ===== client.lua =====
local QBCore = exports['qb-core']:GetCoreObject()
local previewVeh = nil
local previewSpawn = vector4(-56.7, -1097.2, 26.4, 160.0)

local function spawnPreview(model)
    local hash = GetHashKey(model)
    RequestModel(hash)
    while not HasModelLoaded(hash) do Wait(0) end
    if previewVeh and DoesEntityExist(previewVeh) then
        DeleteEntity(previewVeh)
    end
    previewVeh = CreateVehicle(hash, previewSpawn.x, previewSpawn.y, previewSpawn.z, previewSpawn.w, false, false)
    SetEntityAsMissionEntity(previewVeh, true, true)
    FreezeEntityPosition(previewVeh, true)
    SetVehicleDoorsLocked(previewVeh, 2)
    SetModelAsNoLongerNeeded(hash)
end

RegisterNetEvent("dealership:preview", function(model)
    spawnPreview(model)
end)

RegisterNetEvent("dealership:buy", function(model, price)
    TriggerServerEvent("dealership:purchase", model, price)
end)

RegisterNetEvent("dealership:deliver", function(model, plate)
    local ped = PlayerPedId()
    local hash = GetHashKey(model)
    RequestModel(hash)
    while not HasModelLoaded(hash) do Wait(0) end
    local coords = GetEntityCoords(ped)
    local veh = CreateVehicle(hash, coords.x, coords.y, coords.z, GetEntityHeading(ped), true, false)
    SetVehicleNumberPlateText(veh, plate)
    SetPedIntoVehicle(ped, veh, -1)
    SetEntityAsMissionEntity(veh, true, true)
    SetModelAsNoLongerNeeded(hash)
    if previewVeh and DoesEntityExist(previewVeh) then DeleteEntity(previewVeh) end
    QBCore.Functions.Notify("Vehicle delivered", "success")
end)

-- ===== server.lua =====
local QBCoreSv = exports['qb-core']:GetCoreObject()

RegisterNetEvent("dealership:purchase", function(model, price)
    local src = source
    local Player = QBCoreSv.Functions.GetPlayer(src)
    if not Player then return end

    if Player.PlayerData.money.bank < price then
        TriggerClientEvent("QBCore:Notify", src, "Not enough money in bank", "error")
        return
    end

    Player.Functions.RemoveMoney("bank", price, "vehicle-purchase")
    local plate = ("QB%05d"):format(math.random(0, 99999))

    MySQL.insert.await(
        "INSERT INTO player_vehicles (citizenid, vehicle, plate, state) VALUES (?, ?, ?, ?)",
        { Player.PlayerData.citizenid, model, plate, 0 }
    )
    TriggerClientEvent("dealership:deliver", src, model, plate)
end)

Known Failure Modes

  • Client-side money — Claude deducts cash in the client event, trivially exploitable. Require the balance check and RemoveMoney in the server event only.
  • No DB row — it delivers a car but never inserts into player_vehicles, so the garage is empty. Mandate the INSERT.
  • Drivable preview — the showroom car isn't frozen/locked and gets stolen. Demand FreezeEntityPosition + SetVehicleDoorsLocked(veh,2).
  • Plate collisions — naive plates duplicate; generate a unique formatted plate and rely on the DB to surface clashes.

Integration Notes

Split into client.lua and server.lua; fxmanifest.lua declares client_scripts and server_scripts (include @oxmysql/lib/MySQL.lua) and dependencies { 'qb-core', 'oxmysql' }. Assumes the standard QBCore player_vehicles table. Test with ensure then trigger dealership:preview and dealership:buy from a target/menu; confirm a row appears in player_vehicles.

Profit Potential

$250–$3800/mo on Tebex (expected ~$950). [INFERRED] A server-authoritative dealership is a core economy purchase with steady demand; it sits mid-to-high in the $50-389 band against the corpus median seller.

Trend Signal

rising — vehicle modding/tuning niche-selection 3.75; corpus ox_fuel active.

Sales Angle

Position as the economy backbone every roleplay server needs: frozen preview, server-validated purchase, and DB-delivered ownership in one drop-in. Recommend $149 on Tebex, undercutting bloated all-in-one vehicle-shop bundles.

Difficulty & Ship Time

intermediate · ships in 1 day.