Pepper Bus
Bus driver career with real line service, schedules, 50 levels and an in-game route editor – ESX Legacy.
Overview
Pepper Bus is a long-term bus driver career for ESX Legacy: real lines with stops, NPC passengers who get on and off, a running schedule with punctuality, 50 levels, reputation, ratings, challenges and an optional player-run bus company. Admins build their own lines in the in-game line editor. Everything runs through the driver tablet (F7) at the bus depot.
- 14 default lines, 10 line types, 9 passenger types with their own fare and comfort needs
- Stops with doors, minimum dwell time and schedule – punctual stops pay a bonus
- 6 buses from the shuttle bus to the festival bus, unlocked through the career
- 1–5 stars from punctuality, driving style, speed, collisions and damage, reputation from Bronze to Legend
- Charter rides with real players, bus company (public or player-owned)
- Line editor and admin panel with audit log, German and English
Requirements
| Dependency | Required/optional | Used for | Link |
|---|---|---|---|
| FiveM server build 7290+ with OneSync | required | declared in fxmanifest.lua as /server:7290 and /onesync |
https://docs.fivem.net/docs/server-manual/setting-up-a-server/ |
ESX Legacy 1.9+ (es_extended) |
required | players, money, admin groups, characters | https://github.com/esx-framework/esx_core |
| oxmysql | required | database (career, lines and stops, company, logs) | https://github.com/overextended/oxmysql |
| Fuel script | optional | buses get the fuel state bag set when they spawn (Config.VehicleRules.Fuel) |
– |
ox_lib, ox_target and ox_inventory are not required. No ESX job is needed. Pepper Bus only runs on ESX Legacy (no QBCore/Qbox).
Installation
- Download the resource from the Cfx.re portal → Granted Assets.
- Extract it to
resources/[pepper]/pepper_bus. Do not rename thepepper_busfolder – other resources call the exports viaexports.pepper_bus. - Add it to your
server.cfgafter its dependencies:
ensure oxmysql
ensure es_extended
ensure pepper_bus
- Database: with
Config.Database.AutoInstall = true(default) the resource creates missing tables on start (14 tables prefixedbus_). The manual way is importingsql/install.sql– it can safely be imported more than once. On first start the 14 default lines fromconfig/routes.luaare created (Config.Database.SeedDefaultRoutes). - Grant admin rights (details under “Commands and permissions”), for example:
add_ace group.admin pepper_bus.admin allow
- Drive the default lines once and fix stops in the line editor if needed.
Pepper Bus uses no inventory items – there are no items or images to add.
First test
- Start the server and check the console that
pepper_busstarts without errors. - Drive to the bus depot (bus icon on the map, Los Santos Transit) and press
Eat the terminal. - Pick the shuttle bus, open the tablet with
F7and choose an unlocked line. - Stop inside the radius of the first stop, let passengers get on and off and drive to the last stop – stars, payout and XP appear.
- As an admin, check under Admin → Line editor in the tablet that the default lines exist.
Configuration
All settings are open in config/ (readable and editable under Asset Escrow):
| File | Controls |
|---|---|
config/config.lua |
language, database, depot, tablet, dispatch, stops, schedule, AFK, security, passengers, pay, damage, rating, reputation, duty bonus, vehicle rules, charter rides, company, admin |
config/vehicles.lua |
bus classes, 6 buses with seats, doors and requirements |
config/routetypes.lua |
10 line types |
config/routes.lua |
14 default lines and stops (only imported on first start) |
config/passengers.lua |
9 passenger types |
config/levels.lua |
XP curve, titles, level rewards |
config/challenges.lua |
pools for daily and weekly challenges |
config/server.lua |
optional Discord webhook for logs (server-side only) |
locales/de.lua, locales/en.lua |
all in-game and tablet texts |
General
Config.Locale = 'de'
Config.TimeSource = 'game'
Config.Database = { AutoInstall = true, SeedDefaultRoutes = true, SaveInterval = 300 }
| Option | Default | Description |
|---|---|---|
Config.Locale |
'de' |
language (de or en) |
Config.Debug |
false |
verbose logs for troubleshooting |
Config.TimeSource |
'game' |
time of day for lines and passengers: 'game' or 'server' |
Config.Database.SeedDefaultRoutes |
true |
create the default lines if no lines exist yet |
Config.Center.MaxStartDistance |
70.0 |
start of duty only this close to the depot (checked server-side) |
Tablet and dispatch
By default drivers pick their line themselves in the tablet. With Config.Dispatch.Enabled = true dispatch also sends
line offers; lines nobody has driven for a long time then pay up to +25 % demand bonus.
| Option | Default | Description |
|---|---|---|
Config.Tablet.DefaultKey |
'F7' |
key for the tablet |
Config.Tablet.AcceptKey / DeclineKey |
'Y' / 'N' |
accept / decline a dispatch offer |
Config.Dispatch.Enabled |
false |
dispatch also sends offers |
Config.Dispatch.OfferTimeout |
30 |
seconds to accept |
Config.Dispatch.DemandBonusMax |
0.25 |
maximum demand bonus |
Stops and schedule
Config.Stops = { Radius = 14.0, MaxStopSpeed = 1.5, BaseDwell = 4, DwellPerPassenger = 1.2, MaxDwell = 25, ... }
Config.Schedule = { ExpectedSpeed = 12.0, OnTimeTolerance = 45, EarlyLimit = 60, ... }
| Option | Default | Description |
|---|---|---|
Config.Stops.Radius |
14.0 |
default radius of a stop (changeable per stop in the editor) |
Config.Stops.MaxStopSpeed |
1.5 |
m/s (~5 km/h) – below that the bus counts as stopped |
Config.Stops.BaseDwell |
4 |
seconds minimum dwell time … |
Config.Stops.DwellPerPassenger |
1.2 |
… plus seconds per passenger (at most MaxDwell = 25) |
Config.Schedule.OnTimeTolerance |
45 |
seconds early/late that still count as on time |
Config.Schedule.EarlyLimit |
60 |
more than 60 s early = schedule not kept |
Config.PassengerDoors |
{ 1, 3 } |
door slots that open at stops (changeable per bus via doors) |
Passengers and pay
| Option | Default | Description |
|---|---|---|
Config.Passengers.RushHours |
{ { 7, 9 }, { 16, 19 } } |
rush hours with more passengers (RushFactor 1.6) |
Config.Passengers.MaxBoardPerStop |
8 |
at most this many boarding per stop |
Config.Passengers.MaxVisible |
12 |
visible NPCs in the bus (the rest is counted) |
Config.Economy.PayAccount |
'bank' |
account for payouts |
Config.Economy.GlobalMultiplier |
1.0 |
multiplier on all payouts |
Config.Economy.FarePerStop / FareBase |
9 / 6 |
fare per passenger and stop / base amount |
Config.Economy.PunctualBonus |
10 |
bonus per punctual stop |
Config.Economy.AbortPayout |
0.4 |
on abort 40 % of the fares collected so far |
Config.Economy.MinPayout |
50 |
minimum payout per completed line |
Company and admin
| Option | Default | Description |
|---|---|---|
Config.Company.AllowPurchase |
true |
players can take over the company |
Config.Company.PurchasePrice |
900000 |
purchase price |
Config.Company.VehicleSpawnCost |
250 |
operating cost per bus handed out |
Config.Admin.EditorCommand |
'busstop' |
command for stops in the editor |
Config.Admin.MaxRoutes |
100 |
maximum number of lines |
Config.Admin.MaxStopsPerRoute |
40 |
stops per line |
Config.Admin.AllowTeleport |
true |
teleport to stops in the editor |
Discord webhook
In config/server.lua (never sent to clients):
ServerConfig = {
LogWebhook = '', -- empty = off
LogWebhookName = 'Pepper Bus',
}
Gameplay
- Start a shift: press
Eat the depot and pick an unlocked bus – it spawns on a free parking spot. - Choose a line in the tablet (
F7). Locked lines show the reason (level, reputation, time, wrong bus). - Stop: halt inside the stop radius (below about 5 km/h) – the doors open automatically.
- Boarding: the HUD shows the dwell time (“Doors open”). Leave too early and passengers are left behind.
- Schedule: starts with the first departure; you see punctuality live in the HUD.
- Last stop: stars, payout, XP and reputation.
| Bus | Class | Seats |
|---|---|---|
Shuttle bus (rentalbus) |
shuttle | 9 |
City bus (bus) |
city | 16 |
Airport bus (airbus) |
airport | 16 |
Sightseeing bus (tourbus) |
tour | 10 |
Coach (coach) |
coach | 16 |
Festival bus (pbus2) |
party | 12 |
Line types: shuttle, city line, school bus, airport, night line, city tour, express, regional, event shuttle, party charter. Bus company: public (everyone drives, full payout) or player-owned (only owner and employees; payouts go to the company, drivers receive their share, salaries come from the company account).
Line editor
Tablet (F7) → Admin → Line editor:
- New line: number, name, line type and optionally a minimum level.
- Stops: drive the route with a bus and press “Stop at my position” at every stop – or type
/busstopwithout opening the tablet (the open draft is kept). - Fine-tuning: rename (the street name is suggested), reorder, recapture the position, set radius, passenger demand (0.2–3.0) and extra dwell time.
- Preview and save: “Preview on map” shows the numbered stops, “Save” makes the line available immediately (if active), “Test run” drives it without requirements or rewards, “Copy”/“Reverse direction” creates an inactive copy.
A line needs at least 2 and at most Config.Admin.MaxStopsPerRoute stops, at least 40 m apart
(Config.Stops.MinStopDistance). Running trips use a copy of the line – changes apply from the next trip. “Default lines”
recreates missing lines from config/routes.lua without changing existing ones. Lines live in the database – resource
updates never overwrite them.
Commands and permissions
| Command / key | Who | What |
|---|---|---|
F7 / /bustablet |
everyone | open the tablet (anywhere on duty or as admin, otherwise at the depot) |
Y / /busaccept |
drivers on duty | accept a dispatch offer |
N / /busdecline |
drivers on duty | decline a dispatch offer |
/busstop |
admins | append the current position as a stop to the open editor draft |
E |
everyone | terminal at the depot |
Every player can change the keys in GTA settings → Key Bindings → FiveM.
Admin rights (always checked server-side): ESX group from Config.Admin.Groups (default superadmin, admin)
or ACE pepper_bus.admin:
add_ace group.admin pepper_bus.admin allow
Config.Admin.RequireReason = true requires a reason for player and company changes (the line editor logs without a
reason); everything ends up in the audit log. Permissions inside the player company depend on the rank in
Config.Company.DefaultRanks.
Exports and events
All exports are server-side:
| Export | Returns / description |
|---|---|
GetBusPlayerData(source) |
career and statistics |
IsBusDriverOnDuty(source) |
boolean |
GetBusDriverStatus(source) |
status, e.g. 'OFF_DUTY', 'AVAILABLE', 'AT_STOP', 'ON_ROUTE' |
GetBusDriverLine(source) |
current line (number, label, segment, stops, passengers on board) or nil |
SetPlayerCharterActive(source, active) |
switch a charter ride on/off – returns ok, reason |
GetOnDutyDrivers() |
drivers on duty with their line |
GetBusRoutes() |
all lines incl. stops (e.g. for a timetable app) |
GetBusCompany() |
company info (label, mode, balance, employees, owner) |
IsBusCompanyEmployee(sourceOrIdentifier) |
employee check |
local line = exports.pepper_bus:GetBusDriverLine(source)
There is deliberately no export that lets other resources create money, XP or reputation. Pepper Bus offers no public events for other resources.
FAQ
The resource does not start or reports missing dependencies.
oxmysql and es_extended must come before pepper_bus in your server.cfg. The manifest requires server build 7290+
and OneSync – without OneSync the resource does not start.
The tables are missing in the database.
Keep Config.Database.AutoInstall = true or import sql/install.sql. All tables start with bus_.
Does Pepper Bus run on QBCore or Qbox?
No. The resource uses es_extended directly and is built for ESX Legacy 1.9+ only.
Do players need an ESX job?
No. Everyone can go on duty at the depot.
There are no lines in the tablet.
Admin → Line editor → “Default lines” creates the 14 lines from config/routes.lua. Alternatively create your own line
and set it active.
A line is locked.
The tablet shows the reason: level, reputation, time of day or the wrong bus for the line type.
The stop is not detected.
Stop inside the radius (below about 5 km/h, Config.Stops.MaxStopSpeed). Increase the radius in the editor or set
the stop again.
Passengers stay behind at the stop.
You left too early – the HUD shows the dwell time (“Doors open”). Every stop left too early costs rating
(Config.Rating.EarlyDeparturePenalty).
The message “The trip was not plausible” appears.
A teleport or shortcut between two stops was detected (less than 60 % of the straight-line distance driven or faster than
Config.Security.MaxPlausibleSpeed). Details are in the server console.
Why do I not get line offers from dispatch?
By default drivers pick their lines themselves (Config.Dispatch.Enabled = false). Set it to true to receive offers as well.
The admin section in the tablet is missing.
Your ESX group must be listed in Config.Admin.Groups or you need the ACE pepper_bus.admin.
Does F7 clash with Pepper Taxi or Pepper Trucking?
No – Taxi uses F6 and Trucking F9. Every player can also rebind the key.
Can I use add-on buses?
Yes. Add them to config/vehicles.lua with spawn name, class and seats; doors defines which doors open at stops.
How do I change texts?
All texts are in locales/de.lua and locales/en.lua; pick the language with Config.Locale.
How much performance does the resource need?
Measured with resmon: 0.01 ms active.
Will an update overwrite my lines?
No. Lines live in the database and are never overwritten by updates. Back up your changed files in config/ and
locales/ before updating and carry your changes over to the new version.
Support
Questions and bugs: open a ticket in our Discord: https://discord.gg/6NaFJWKDYu – link your purchase with /verify first.
Permanently tested on the Pepper Scripts dev server.
Changelog
Current version: 1.0.0 (26 Sep 2026) – first release. All changes are listed in the CHANGELOG.md file in the
resource folder.
Found a mistake? Report it on Discord.