🚗[QB] Auto Dealer
Installation Guide for the [QB] Auto Dealer Script!
Step 1 - Ace Permissions
In order to add the dealer jobs to the database, you must first add the Ace Permissions which allow the use of the command /autodealer!!
Below are the common perms needed for QBCore Admin / God. Copy and paste these to the bottom of your server.cfg. You may edit them to your liking. Restart the server.
add_ace group.admin command.autodealer allow # Allow dealer commands
add_ace qbcore.god command.autodealer allow # Allow dealer command commands
add_ace qbcore.admin command.autodealer allow # Allow dealer commands
After successfully adding the ACE Permissions, an Admin or God can use the command in-game to add Auto Dealer jobs to the database when a shop has been created in the config.lua of the script. To do this, type /autodealer [jobName]
Also, be sure that the jobs for the dealerships are added to your QBCore Shared Jobs. Navigate to qb-core/shared/jobs.lua and add new jobs like the PDM job example below:
['pdm'] = {
label = 'PDM Auto Dealer',
defaultDuty = false, -- ensure default duty is false!
offDutyPay = false, -- your decision if employees are paid while off-duty!
grades = {
['0'] = { name = 'Recruit', payment = 50 },
['1'] = { name = 'Showroom Sales', payment = 75 },
['2'] = { name = 'Business Sales', payment = 100 },
['3'] = { name = 'Finance', payment = 125 },
['4'] = { name = 'Manager', isboss = true, payment = 150 },
},
},
Step 2 - SQL Uploads
This script was developed for the QBCore Framework and based off of the data that should already be in the database for player_vehicles
, however, there is one small change that needs to be made in order for the vehicle financing to work properly.
If you skipped this step, do NOT request support if you have issues!
With the player_vehicles.sql file found in the script, open in your word editor (visual studio code, etc.). If you already have this in your database, the only part you will need to add to the database is the part at the bottom so delete everything above it before executing the sql into the database.
Alternatively, if you know what you are doing when it comes to database stuff, you can directly execute the query below. This adds the purchase_timestamp
column to the player_vehicles
table if the table already exists with all of the other columns.
ALTER TABLE player_vehicles
ADD COLUMN purchase_timestamp INT(11) NOT NULL DEFAULT 0;
Below is the full player_vehicles sql query if needed:
CREATE TABLE IF NOT EXISTS `player_vehicles` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`license` varchar(50) DEFAULT NULL,
`citizenid` varchar(50) DEFAULT NULL,
`vehicle` varchar(50) DEFAULT NULL,
`hash` varchar(50) DEFAULT NULL,
`mods` text CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL,
`plate` varchar(15) NOT NULL,
`fakeplate` varchar(50) DEFAULT NULL,
`garage` varchar(50) DEFAULT 'pillboxgarage',
`fuel` int(11) DEFAULT 100,
`engine` float DEFAULT 1000,
`body` float DEFAULT 1000,
`state` int(11) DEFAULT 1,
`depotprice` int(11) NOT NULL DEFAULT 0,
`drivingdistance` int(50) DEFAULT NULL,
`status` text DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `plate` (`plate`),
KEY `citizenid` (`citizenid`),
KEY `license` (`license`)
) ENGINE=InnoDB AUTO_INCREMENT=1;
ALTER TABLE `player_vehicles`
ADD UNIQUE INDEX UK_playervehicles_plate (plate);
ALTER TABLE `player_vehicles`
ADD CONSTRAINT FK_playervehicles_players FOREIGN KEY (citizenid)
REFERENCES `players` (citizenid) ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE `player_vehicles`
ADD COLUMN `balance` int(11) NOT NULL DEFAULT 0;
ALTER TABLE `player_vehicles`
ADD COLUMN `paymentamount` int(11) NOT NULL DEFAULT 0;
TABLE `player_vehicles`
ADD COLUMN `paymentsleft` int(11) NOT NULL DEFAULT 0;
ALTER TABLE `player_vehicles`
ADD COLUMN `financetime` int(11) NOT NULL DEFAULT 0;
ALTER TABLE `player_vehicles`
ADD COLUMN `purchase_timestamp` int(11) NOT NULL DEFAULT 0;
Next,
Locate the display.sql
file in the INSTALL folder and upload it into your database.
It is MANDATORY for saving the display vehicle models, vehicle coordinates, rotation state, and color options, as well as a unique VehicleID that is used within the code for creating the vehicles.
Or, you could execute the below code directly:
CREATE TABLE IF NOT EXISTS `xmmx_cardealer` (
`id` INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
`job` VARCHAR(50) NOT NULL UNIQUE,
`display` LONGTEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL CHECK (json_valid(`display`))
) COLLATE='utf8mb4_general_ci' ENGINE=InnoDB AUTO_INCREMENT=1;
Step 3 - Credit Metadata
This script uses a credit score system for vehicle financing. In order for the system to work properly, you must add the below information to your QBCore Metadata Table.
Navigate to: qb-core/server/player.lua and insert the following line anywhere around lines 90 to 100: Older QBCore:
PlayerData.metadata['creditscore'] = PlayerData.metadata['creditscore'] or 100
It should look something like this:

Latest QBCore:
creditscore = 100,
It should look something like this:
metadata = {
hunger = 100,
thirst = 100,
stress = 0,
isdead = false,
inlaststand = false,
armor = 0,
ishandcuffed = false,
tracker = false,
injail = 0,
jailitems = {},
status = {},
phone = {},
rep = {},
currentapartment = nil,
callsign = 'NO CALLSIGN',
creditscore = 100, -- added for XMMX QB Autodealer
This will give each player a starting credit score of 100. Alternatively, you may adjust to your standards or liking. If your server already uses a Credit Score Meta System, then you can exclude this step and rename the meta table in the config.lua of the script, to your credit metadata.
Bonus Info: If you want to implement the credit system into other scripts, such as when players make a house loan payment, then you can add to their "creditscore" metadata by implementing the below code into other scripts. (Requires Basic Lua Knowledge) This is not something we will be supporting you with.
-- Server Side:
local src = source
local player = QBCore.Functions.GetPlayer(src)
local creditscore = player.PlayerData.metadata["creditscore"]
newscore = creditscore + 1 -- or any amount you wish to increase it by
player.Functions.SetMetaData("creditscore", newscore)
Step 4 - Dealerships
You should remove qb-vehicleshop as this script alters the database table for player_vehicles. I have not tested it as of yet to see if there is any interference so if you run both scripts, you are doing so at your own risk!
PDM and Ottos Autos have been pre-established, but feel free to make modifications as needed. Should you wish to create additional dealerships, please use the same format as the PDM shop in the Config.lua file. This task requires proficient use of PolyZone. If you're unfamiliar with creating PolyZones, we recommend seeking assistance from an experienced developer (not myself).
The process is relatively straightforward; just refer to the README.md of the PolyZone script for guidance. However, please note that we won't be providing support for setting up PolyZones or explaining the process. Alternatively, you can find an excellent YouTube tutorial on PolyZone creation below:
Step 5 - Vehicles
Next, In the Shared Folder of this script, there is a vehicles.lua file. Your task is to review each vehicle and set the pricing based on your server's preferences. The majority of the content is the default from qb-core/shared/vehicles.lua, with the addition of server build 2944 vehicles, which are commented out at the top.
If you have already customized your qb-core/shared/vehicles.lua to your liking, you can simply copy those vehicles and replace the vehicles tables in the vehicles.lua file located in the shared folder of this script. The vehicles must be present in the script's vehicles.lua file for the dealerships to function correctly. It does not utilize the data from qb-core/shared/vehicles.lua.
You have the flexibility to assign, create, or modify the ["category"] = "name"
(name only) for any vehicle as you see fit.
Afterward, you can assign these categories to specific dealerships to grant them access to the respective vehicles.
Now,
Navigate to the INSTALL folder of the script and locate the dealertablet.png image. Drag and Drop, or Copy this image into your servers inventory images folder. For example:
QBCore Inventory: qb-inventory/html/images
Ox Inventory: ox_inventory
/web/images
Then, Copy the below item to your qb-core/shared/items.lua. This is required in order for the tablet to work.
['dealertablet'] = {['name'] = 'dealertablet', ['label'] = 'Dealership Tablet', ['weight'] = 2000, ['type'] = 'item', ['image'] = 'dealertablet.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Auto Dealer Tablet'},
VEHICLE IMAGES: You can find the Vehicle Images in the html/images folder of this script. In case a vehicle doesn't have an image, or you're introducing custom vehicles, you can take a screenshot of the vehicle and add it to this folder. Afterward, make sure to restart the script so that the vehicle image will be visible in the menus. This way, players will be able to see the vehicle representation when browsing through the available options. Please make sure the image size is no larger than 300x169 to avoid player UI lag.

VEHICLE CATEGORIES: The Vehicle Categories are fully customizable, allowing you to name them according to your preferences. However, to make a category appear, you need to assign it to the appropriate dealership in the Config file.
Please take the time to carefully review the vehicles in the xmmx_autodealer/shared/vehicles.lua file and adjust the prices and categories to suit your server's preferences.
Important: Do not modify the model name of the vehicle as it must remain identical to the legitimate spawn name of the vehicle. This ensures the proper functioning of the script. See the example below for clarity:
[Example] If the legitimate spawn name of a vehicle is "CometSR," you must not change it in the script. However, you can create or modify a category such as ["category"] = "sports" to categorize the "CometSR" under the "Sports" category. Then, make sure to assign the "sports" category to the appropriate dealership in the Config file to display this vehicle in that dealership's menu.
['buffalo5'] = { -- Vehicle Model (must match spawn name)
['name'] = 'Buffalo 5', -- Vehicle Name (can be whatever you choose)
['brand'] = 'Bravado', -- Vehicle Brand (can be whatever you choose)
['model'] = 'buffalo5', -- Vehicle Model (must match spawn name)
['price'] = 345000, -- Vehicle Price (can be whatever you set)
['category'] = 'muscle', -- Vehicle Category (can rename 'muscle' to whatever you choose)
},


Step 6 - Config File
---@param Warning: Do NOT rename this resource or it will not work!
--- __ __ __ __ __ __ __ __ ______ ______ _______ ______ _______ ________ ______ -----
-- | \ | \| \ / \| \ / \| \ | \ / \ / \ | \ | \| \| \ / \ ----
-- | $$ | $$| $$\ / $$| $$\ / $$| $$ | $$ | $$$$$$\| $$$$$$\| $$$$$$$\ \$$$$$$| $$$$$$$\\$$$$$$$$| $$$$$$\ ---
--- \$$\/ $$| $$$\ / $$$| $$$\ / $$$ \$$\/ $$ | $$___\$$| $$ \$$| $$__| $$ | $$ | $$__/ $$ | $$ | $$___\$$ ---
---- >$$ $$ | $$$$\ $$$$| $$$$\ $$$$ >$$ $$ \$$ \ | $$ | $$ $$ | $$ | $$ $$ | $$ \$$ \ ----
--- / $$$$\ | $$\$$ $$ $$| $$\$$ $$ $$ / $$$$\ _\$$$$$$\| $$ __ | $$$$$$$\ | $$ | $$$$$$$ | $$ _\$$$$$$\ ---
-- | $$ \$$\| $$ \$$$| $$| $$ \$$$| $$| $$ \$$\ | \__| $$| $$__/ \| $$ | $$ _| $$_ | $$ | $$ | \__| $$ ---
-- | $$ | $$| $$ \$ | $$| $$ \$ | $$| $$ | $$ \$$ $$ \$$ $$| $$ | $$| $$ \| $$ | $$ \$$ $$ ----
--- \$$ \$$ \$$ \$$ \$$ \$$ \$$ \$$ \$$$$$$ \$$$$$$ \$$ \$$ \$$$$$$ \$$ \$$ \$$$$$$ -----
Config = Config or {}
Locales = Locales or {}
Config = {
VersionCheck = true,
CoreObject = 'qb-core',
Debug = false, -- Debug the PolyZones, Targets, etc. (client-side)
FinanceDebug = false, -- Debug the finance timer (server-side)
DatabaseDebug = false, -- Debug the database queries (server-side)
MinLoanAmt = 5000, -- Min loan amount if crecit score less than the minScore in GetPlayerLoanAmt (see function below).
MinDownPmt = 1000, -- Minimum down payment if loan amount exceeds price of vehicle.
PmtWindow = 2, -- If Pmt days are 7 below, then player must wait 5 days make a payment. (prevents purchase spam to build credit).
PmtDays = 7, -- Amount of actual IRL days. 7 days = 1 week. (I wouldn't advise changing this!)
PmtWks = 8, -- Max number of weeks a salesperson can finance a vehicle to player. 8 weeks = 2 months (IRL)
ChkTime = 30, -- checks time every 60 minutes and deducts the time (os.time() or IRL time) from players financetimer.
PaymentDue = 30, -- Time in minutes player will have to make a payment before repossession.
Target = "qb-target", -- Currently only supports qb-target.
Distance = 2.0, -- Target Distance.
TabletItem = "dealertablet", -- Tablet/Laptop Employee Item.
DefaultVeh = "buffalo4", -- Default display vehicle used for vehicle placement.
TempPlate = "BUY ME", -- License Plate of Showroom Vehicles.
TestPlate = "TESTDRIV", -- License Plate of Test Drive Vehicles.
PrvwPlate = "PREVIEW", -- License Plate of Preview Vehicle.
TestTime = 2.0, -- Test drive time limit in minutes.
RotationSpeed = 0.5, -- Rotation speed of vehicle when rotation is true. (I wouldn't set this higher than 1.0)
DisableVehRotate = false, -- Added option to disable rotate button in the menu if problems with high resmon.
CreditMetaData = "creditscore", -- Change to your Credit MetaData if your server has a credit system already.
CreditPayment = 1, -- The amount of credit score to add when a vehicle loan payment is made.
CreditRepo = 20, -- The amount of the credit score to deduct if a vehicle is repossessed for none payment.
CreditPayoff = 5, -- The amount of credit score to add if a financed vehicle is paid off early.
-- [[ CONFIGURE THE FINANCE MENU LOCATIONS HERE, 1ST FIELD MUST BE UNIQUE - ALSO AVAILABLE IN TABLET]]
FinanceMgr = { -- Set location(s) and job that can access the finance menu.
["PDMBossOffice1"] = { coords = vector3(-26.4551, -1104.2767, 27.5069), radius = 0.3, job = "pdm", boss = 4, }, -- First field name must be unique.
["PDMBossOffice2"] = { coords = vector3(-27.6717, -1107.4602, 27.4592), radius = 0.3, job = "pdm", boss = 4, },
["PDMCubicle1"] = { coords = vector3(-30.7252, -1089.047, 27.3754), radius = 0.3, job = "pdm", boss = 4, },
["PDMCubicle2"] = { coords = vector3(-33.2064, -1088.1691, 27.3677), radius = 0.45, job = "pdm", boss = 4, },
["PDMCubicle3"] = { coords = vector3(-39.4239, -1085.8807, 27.3768), radius = 0.3, job = "pdm", boss = 4, },
["PDMCubicle4"] = { coords = vector3(-41.9705, -1084.9822, 27.3788), radius = 0.45, job = "pdm", boss = 4, },
["OttosAutos"] = { coords = vector3(797.9901, -829.6176, 26.2738), radius = 0.3, job = "ottosautos", boss = 4, },
},
-- [[ CONFIGURE LOCATION(s) WHERE THE FINANCE PAYMENT PROP WILL SPAWN ]]
PaymentProp = `prop_parkingpay`, -- The prop that spawn so players can make vehicle loan payments.
FinancePmts = { -- Set locations for the props where players make their payments.
["pdm"] = { coords = vector3(-45.14, -1105.24, 27.26), heading = 336.97 }, -- Set First Field to the name of the job that will receive the money for the payment.
["ottosautos"] = { coords = vector3(804.08, -823.27, 26.18), heading = 180.0 }, -- The heading on the particular prop is backward so face opposite.
},
--[[ CONFIGURE THE VEHICLE SPAWN COORDS WHEN A PLAYER FINANCES OR PURCHASES A VEHICLE ]]
FinanceVehSpawn = { -- Set Car Dealer Job and Spawn Locations Here
["pdm"] = { coords = vector3(-13.83, -1082.26, 27.05), heading = 97.47 },
["ottosautos"] = { coords = vector3(806.23, -826.82, 26.34), heading = 90.58 },
},
--[[ CONFIGURE EACH DEALERSHIP LOCATION HERE, FOLLOW THE FORMAT FOR NEW LOCATIONS ]]
--[[ AVAILABLE CATEGORIES (YOU CAN CREATE MORE IN SHARED/VEHICLES.LUA): compacts, coupes, super, cycles, motorcycles, muscle, --]]
--[[ vans, offroad, suvs, sedans, sports, sportsclassics, boats, helicopters, planes, commercial, industrial, ]]
Locations = {
["pdm"] = { -- Name must match a cardealer job (Mandatory).
enableBlip = true,
blipLabel = 'Premium Deluxe Motorsport', -- Blip name
blipCoords = vector3(-40.1, -1097.86, 27.27),
blipSprite = 523, -- Blip sprite
blipColor = 1, -- Blip color
blipDisplay = 6,
blipScale = 0.6, -- Blip size
categories = { "compacts", "coupes", "cycles", "motorcycles", "muscle", "sedans", "super", "sportsclassics", "offroad", "suvs", "sports" },
catalogLocation = { coords = vector3(-31.6335, -1095.6293, 27.3208), radius = 1.0 }, -- Also the employee duty toggle location.
vehPreview = vector4(-23.69, -1094.48, 26.93, 340.5),
vehTest = vector4(-51.05, -1074.71, 27.07, 70.15), -- Vehicle Test Drive Spawn Location.
Zone = { -- Vector2 PolyZone of the Shop. (Only needed for Display vehicle area.)
vector2(-83.175010681152, -1128.2227783203),
vector2(-61.137794494629, -1067.1298828125),
vector2(-3.4031567573547, -1087.2928466797),
vector2(-17.621864318848, -1126.3126220703)
},
minZ = 22.03784866333,
maxZ = 32.362775802612,
},
["ottosautos"] = { -- Name must match a cardealer job (Mandatory).
enableBlip = true,
blipLabel = 'Ottos Auto Sales', -- Blip name
blipCoords = vector3(800.87, -821.65, 26.18),
blipSprite = 530, -- Blip sprite
blipColor = 1, -- Blip color
blipDisplay = 6,
blipScale = 0.6, -- Blip size
categories = { "compacts", "coupes", "cycles", "motorcycles", "muscle", "sedans", "offroad" },
catalogLocation = { coords = vector3(804.9619, -825.2139, 25.8027), radius = 0.3 }, -- Also the employee duty toggle location.
vehPreview = vector4(802.85, -842.01, 26.33, 92.0),
vehTest = vector4(805.53, -819.97, 25.7, 269.44),
Zone = { -- Vector2 PolyZone of the Shop.
vector2(787.07293701172, -846.21435546875),
vector2(787.25189208984, -784.43701171875),
vector2(824.03283691406, -784.64825439453),
vector2(823.44793701172, -845.73431396484)
},
minZ = 22.181016921997,
maxZ = 30.096039581299,
},
-- ["jobnamehere"] = { -- Name must match a cardealer job (Mandatory).
-- label = 'Blip Name Here', -- Blip name
-- blipLoc = vector3(-41.94, -1683.5, 29.43),
-- blipSprite = 326, -- Blip sprite
-- blipColor = 1, -- Blip color
-- blipSize = 0.7, -- Blip size
-- categories = { "compacts", "coupes", "cycles", "motorcycles", "muscle", "sedans", "offroad" },
-- catalogLocation = { coords = vector3(804.9619, -825.2139, 25.8027), radius = 0.3 }, -- Also the employee duty toggle location.
-- vehPreview = vector4(802.85, -842.01, 26.33, 92.0),
-- vehTest = vector4(805.53, -819.97, 25.7, 269.44),
-- Zone = { -- Vector2 PolyZone of the Shop.
-- vector2(-47.412616729736, -1666.2598876953),
-- vector2(-65.808685302734, -1687.6629638672),
-- vector2(-54.760898590088, -1698.4791259766),
-- vector2(-28.693429946899, -1688.1431884766)
-- },
-- minZ = 29.43-5,
-- maxZ = 29.43+5,
-- }
},
}
-- [[ CONFIGURE BELOW YOUR FUEL EXPORT ]]
function FuelSystem(veh, amount)
-- exports["ti_fuel"]:setFuel(veh, 100.0)
exports['cdn-fuel']:SetFuel(veh, 100)
-- exports['LegacyFuel']:SetFuel(veh, 100)
end
-- [[ HERE YOU CAN CUSTOMIZE YOUR SCORE RANGE AND LOAN AMOUNTS --]]
function GetPlayerLoanAmt(score)
local minScore = 100
local maxScore = 700
local minAmount = 500
local maxAmount = 225000
local scoreRange = maxScore - minScore
local amountRange = maxAmount - minAmount
local scoreInterval = scoreRange / amountRange
local amount = ((score - minScore) / scoreInterval) + minAmount
amount = math.floor(amount / 1000) * 1000
return amount
end
-- [[ THIS IS ANOTHER EXAMPLE OF HOW YOU COULD FACTOR THE CREDIT SCORE AND LOAN AMOUNTS --]]
--[[function GetPlayerLoanAmt(score)
local amount = 0
if score <= 125 then
amount = 25000
elseif score >= 126 and score < 150 then
amount = 35000
elseif score >= 151 and score < 200 then
amount = 45000
elseif score >= 201 and score < 250 then
amount = 55000
elseif score >= 251 and score < 300 then
amount = 66000
end
return amount
end--]]
Last updated