Job Owned Vehicles
A job vehicle belongs to the job itself, not to a person. It never shows up in
anyone's personal garage, it cannot be transferred or given sub-owners, and
while restrictToJobGarages is on, it can only be parked and taken out at a
garage of type job that the owning job owns.
Everything on this page is configured in shared/job_vehicles.lua.
How ownership is stored
The owning job's name goes in its own column on the vehicle table (job by
default, Config.JobOwnedVehicles.column). It is created automatically if your
table does not already have one, ESX's owned_vehicles already ships it.
The owner column (citizenid on QB/Qbox, owner on ESX) still holds a real
citizen id, called the registered keeper, because those schemas put a
foreign key on it. The keeper gains nothing from this: every personal-ownership
query excludes rows that have a job set, so the vehicle is not theirs in any
sense the script recognises. It exists to satisfy the constraint and to record
who bought it.
A vehicle whose owner column holds job:<name> is also read as job-owned,
for servers where another resource writes ownership that way. This resource
never writes that form.
Configuration
Config.JobOwnedVehicles = {
enabled = true,
column = "job", -- column holding the owning job's name
ownerPrefix = "job:", -- also read as job ownership, never written
restrictToJobGarages = true, -- job garages only
minGrade = { police = 2 }, -- minimum grade to take one out
requireOnDuty = false, -- must be clocked in
chargeFees = false, -- charge the usual retrieval/parking fees
keeperCitizenId = nil, -- fallback registered keeper
bossOnlyManage = true, -- only a boss may add or remove
}Selling to a job from a dealership
PurchaseJobVehicle is the entry point for a shop. Call it after you have
taken payment, this resource never touches anyone's money.
local ok, plate = exports['kartik-garages']:PurchaseJobVehicle({
job = 'police', -- required, the job that will own it
model = 'police3', -- required, spawn name
plate = nil, -- optional, a free plate is generated
buyer = Player.citizenid, -- optional, becomes the registered keeper
garage = nil, -- optional, defaults to the job's own garage
props = props, -- optional, table or json string
price = 45000, -- optional, for the log and the event only
})
if not ok then
print(plate) -- holds the reason on failure
endIf holding an export reference is awkward, trigger the server-only event instead. It is not a net event, so nothing a player sends can forge a sale:
TriggerEvent('kartik-garages:server:purchaseJobVehicle', {
job = 'police', model = 'police3', buyer = Player.citizenid,
})Either way, a completed sale fires an event you can listen for:
AddEventHandler('kartik-garages:server:jobVehiclePurchased', function(sale)
-- sale = { job, jobLabel, plate, model, garage, buyer, price }
end)The registered keeper
buyer is used when you pass one. Otherwise the fallback keeper is resolved in
this order:
/jobkeeper <citizenid>: set in game, stored in the database, survives restarts.Config.JobOwnedVehicles.keeperCitizenId.
With neither set, a call that names no buyer fails with A registered keeper Citizen ID is required.
The keeper must be a character that really exists. An invented id is rejected both when it is set and when a vehicle is filed.
Managing a fleet in game
A boss of the job gets a Fleet button in the garage menu at their own job garages. It lists every vehicle the job owns and lets them move a stored vehicle between the job's garages or delete one from the fleet.
Set bossOnlyManage = false to let any member of the job manage it. Admins can
manage any job's fleet through the commands below.
Every panel action is re-checked on the server; the button only decides what gets drawn.
Commands
| Command | Description |
|---|---|
/addjobcar [job] | Files the vehicle you are sitting in under a job, yours by default |
/deljobcar <plate> | Deletes a job vehicle |
/jobkeeper [citizenid | clear] | Shows or sets the fallback registered keeper |
Exports
See Server Exports for the full list.