r_vehicleshop Configuration
Every r_vehicleshop config.lua option: framework, currency and payment, test drives and plates, stats and colors, blocklist, showcase and shops.
Everything lives in config.lua. Edit it, run restart r_vehicleshop, and reconnect.
config.lua is left open (escrow-ignored) so you can tweak it freely. Notifications, fuel and
key hooks live in client/cl_custom.lua; the Discord webhook, the database insert and the
server-side key hook live in server/sv_custom.lua. Both are open as well.
Framework & integrations
R.Framework = 'auto' -- 'auto' | 'esx' | 'qb' | 'qbox'
R.CoreName = 'es_extended' -- ESX only: change if your es_extended is renamed
R.Inventory = 'ox_inventory' -- ESX cash: 'esx' | 'ox_inventory' | 'qs-inventory'
R.Target = 'ox_target' -- 'ox_target' | 'qb-target' | 'none'
R.Notify = 'ox_lib' -- 'ox_lib' | 'esx' | 'qb' | 'okok' | 'custom'Leave R.Framework on auto unless detection guesses wrong. R.Inventory only matters on ESX.
QBCore and QBX always use the player's cash account. With R.Target = 'none' players walk up
to the seller and press E.
Language
R_Vehicleshop uses the ox_lib locale system. Set the language with a convar in server.cfg:
setr ox:locale "en" # en | fiShips with English and Finnish. Add your own by copying locales/en.json to
locales/<code>.json. The ui block inside it translates the showroom.
Currency, speed unit & payment
R.Currency = {
symbol = '$', -- currency symbol
after = false, -- false -> $1,000 | true -> 1,000$
separator = ',' -- thousands separator: ',' | ' ' | '.' | '' (none)
}
R.SpeedUnit = 'kmh' -- 'kmh' | 'mph'
R.Payment = { cash = true, bank = true } -- methods offered in the purchase dialogFor euro servers, try symbol = '€', after = true, separator = ' ' to get 1 000€. The
same format is used for prices, balances and the Discord log.
Set a payment method to false to hide it. The purchase dialog shows the player's balance for
each method and only lets them confirm when they can afford the vehicle.
Test drives & plates
R.TestDriveCooldown = 30 -- seconds to wait after a test drive before the next one (0 = none)
R.ShowroomPlate = 'SHOWROOM' -- plate on showroom and showcase vehicles (max 8 characters)
R.TestDrivePlate = 'TESTDRIV' -- plate on test drive vehicles (max 8 characters)
R.Plate = { -- generated plates look like 'ABC 123'
letters = 3,
numbers = 3,
space = true
}Plates are generated on the server and checked against your vehicle table, so they are always unique. Keep letters + numbers (+ space) at 8 characters or less.
The test drive duration and what happens when it ends are set per shop (TestDrive.Time,
TestDrive.End). The cooldown is enforced server-side per character, so it survives reconnects
and can't be bypassed from the client.
Stats & colors
R.Stats = { -- values that fill a stat bar to 100 %
maxSpeed = 250, -- km/h
maxAcceleration = 0.5,
maxBraking = 1.5,
maxHandling = 3.0
}
R.AllowColorPick = true -- colour picker in the showroom
R.Colors = { -- preset swatches
'#f4f4f5', '#0b0b0e', '#9a27ea', '#2563eb', '#dc2626', '#f59e0b', '#16a34a', '#64748b'
}Stats are read from the game's handling data (GetVehicleModelEstimatedMaxSpeed,
GetVehicleModelAcceleration, GetVehicleModelMaxBraking, GetVehicleModelMaxTraction), so they
also work for add-on vehicles. Raise the max* values if your fastest vehicles all show a full bar.
Blocklist
R.Blocklist = { 'police', 'police2', 'police3', 'police4', 'ambulance', 'firetruk' }Models that are never sold, even when a shop takes its catalog from your framework's vehicle list (see Adding Vehicles).
Ambient traffic
R.NoTraffic = {
enabled = true,
radius = 100.0, -- metres around each shop's Showroom
clearOnEnter = true -- remove NPC vehicles already inside the radius when a player arrives
}Inside the radius the game stops spawning ambient traffic and parked NPC cars, so nothing blocks
the showroom floor, the delivery spots or the test drive route. clearOnEnter additionally
deletes the game's own population vehicles that are already there. Only vehicles the game
spawned (random traffic, parked and scenario cars) with no player inside are touched. Anything
created by a script (garages, other shops, your own showcase vehicles, player-owned cars) is
never removed.
Showcase & UI
R.ShowcaseRange = 80.0 -- showcase vehicles spawn locally within this many metres
R.ShowroomHideRadius = 8.0 -- while browsing: showcase vehicles are hidden, and so is any other vehicle this close to the Showroom spot
R.HidePlayerWhileBrowsing = true -- hide the player's own ped for themselves while browsing (rendered locally only, nothing changes on the network)
R.HideTopHud = true -- hide R_Tophud while the showroom is open (uses its setVisible export)
R.UI = { Accent = '#9a27ea' } -- accent colour of the showroom UI
R.EnableLogs = true -- Discord webhook logs (webhook in server/sv_custom.lua)
R.EnableAutoinsert = true -- create the vehicle table on first start if it is missing
R.Debug = false -- prints skipped (unknown) vehicle models to the client consoleShops
R.Shops holds one entry per dealership. Everything about a shop (ped, blip, showroom, test
drive, delivery, showcase vehicles and catalog) lives inside its entry.
R.Shops = {
pdm = {
Label = 'Premium Deluxe Motorsport',
Ped = { Model = 'cs_siemonyetarian', Scenario = 'WORLD_HUMAN_CLIPBOARD', Coords = vector4(-56.6807, -1098.6229, 26.4224, 23.5315) },
Blip = { Sprite = 820, Colour = 43, Scale = 0.9, Name = 'Vehicle Shop' },
Showroom = vector4(-45.9936, -1096.9407, 26.4224, 253.3419),
TestDrive = { Coords = vector4(-45.5232, -1112.4572, 26.6702, 68.3817), Time = 60, End = 'showroom' },
Delivery = {
vector4(-17.0262, -1085.0742, 27.0418, 219.34),
vector4(-59.61, -1104.74, 25.85, 70.13),
},
Exit = vector4(-32.7195, -1096.0895, 27.2744, 75.0),
Garage = 'pillboxgarage',
UseFrameworkVehicles = false,
Showcase = {
{ Model = 'elegy2', Coords = vector4(-43.2449, -1101.9443, 26.4223, 16.8891) },
},
Categories = {
{ key = 'super', label = 'Super' },
{ key = 'sports', label = 'Sports' },
},
Vehicles = {
super = {
{ model = 'adder', price = 900000 },
},
sports = {
{ model = 'elegy2', price = 95000 },
},
},
},
}| Key | What it does |
|---|---|
Label | Shop name shown at the top of the vehicle list |
Ped | Seller model, scenario and position (vector4 with heading). Targeting the ped opens the showroom |
Blip | Map blip at the ped. Remove the table to hide it |
Showroom | Where the showroom vehicle is placed and the camera orbits. The player stays at the seller, only the camera moves |
TestDrive | Coords: one vector4 or a list of them (the first free spot is used) · Time in seconds · End: 'showroom' (back to the showroom, default), 'return' (player placed at Exit) or 'destroy' (vehicle removed, player stays where they are) |
Delivery | Where a bought vehicle is spawned: one vector4 or a list of them; the first spot without a vehicle on it is used and the player is warped in |
Exit | Where the player is placed when a test drive ends (End = 'showroom' or 'return') |
Garage | QBCore only: garage name saved on the bought vehicle |
Showcase | Parked display vehicles; targeting one opens the showroom on that model |
Categories | Tabs of the vehicle list, in order. Each tab shows a picture of its first vehicle (or its own image). See Adding Vehicles |
UseFrameworkVehicles | true fills every category from your framework's vehicle list (QB / QBX shared vehicles, ESX vehicles table). See Adding Vehicles |
Vehicles | The catalog, one list per category key. See Adding Vehicles |
The showroom vehicle is spawned locally. Other players never see it, so the Showroom
spot can be a real display floor without blocking anyone. While a player browses, the showcase
vehicles and their own ped are hidden for them (plus any other vehicle within
R.ShowroomHideRadius of the spot), so the camera always has a clear view of the vehicle they
picked. All of this is local rendering only. No invisibility flags, teleports or god mode are
set, so anticheats have nothing to trip on.
A second shop ships pre-configured as boats (Los Santos Marina). Copy either entry to add
more dealerships. Every key is independent per shop.
Hooks (open files)
client/cl_custom.lua
function Notify(text, type) end -- notification by R.Notify, or your own
function SetFuel(vehicle) end -- fills the tank (ox_fuel state bag + common fuel exports)
function OnVehicleDelivered(vehicle, plate) end
function OnTestDriveStarted(vehicle) end
function OnShowroomOpened() end -- hides R_Tophud by default; hide your own HUD here
function OnShowroomClosed() end -- shows it againserver/sv_custom.lua
local Webhook = '' -- Discord webhook for purchase logs
function RegisterOwnedVehicle(src, data) end -- the database insert per framework
function GiveKeys(src, netId, plate) end -- qbx_vehiclekeys / qb-vehiclekeys by defaultRegisterOwnedVehicle receives { model, plate, props, vehicleType, shop, garage, price, method }
and must return true. If it returns false the player is refunded automatically.
Next Steps
Interface Colours
Every R-Scripts resource shares the same colour tokens, so you can match the UI to your server's branding without touching any code:
R.UI = {
Accent = "#9a27ea", -- icons, bars, badges and highlights
Primary = "#ffffff", -- main action buttons (buy / play / confirm)
PrimaryText = "#000000", -- text on those buttons
NavActive = "", -- selected tab background, "" keeps the neutral default
NavActiveText = "#ffffff", -- selected tab text
}Leave a value empty to keep the shipped look — the defaults above are exactly what you see out of
the box. Accent stays a signal colour (icons, progress bars, badges); Primary is the solid
button colour, so setting it to your brand colour turns every confirm button at once.