NullSect
Systems nominal

Docs / Bus / Configuration

Configuration

Everything lives in config.lua. Career ranks live in data/career.lua, texts in locales/. New settings are added to this file as each phase ships.

General

SettingDefaultMeaning
Config.Framework'auto''auto', 'qbox', 'qbcore', 'esx'
Config.Locale'en'Any file name in locales/. Missing keys fall back to English.
Config.Debug.EnabledfalseExtra console output (state changes, bridge failures)
Config.Debug.CommandsfalseEnables /busdebug, /buscareer, /busxp, /busreputation (also needs the ns-bus.dev ACE)

Database

SettingDefaultMeaning
Config.Database.AutoMigratetrueCreate and update tables on start. Never deletes data.

Admin

SettingDefaultMeaning
Config.Admin.Ace'ns-bus.admin'ACE that always grants admin tools
Config.Admin.DevAce'ns-bus.dev'ACE for developer commands
Config.Admin.UseFrameworkAdmintrueAlso accept the framework's admin groups below
Config.Admin.QBPermissions{ 'admin', 'god' }Qbox / QBCore permission names
Config.Admin.EsxGroups{ 'admin', 'superadmin' }ESX groups

Security

SettingDefaultMeaning
Config.Security.RateLimitssee fileMinimum ms between two calls of the same action per player. default applies to actions without their own value.
Config.Security.FlagThrottleMs30000How often the same suspicious-behaviour warning may be printed per player
Config.Security.MaxTextLength64Max length of free text sent by clients
Config.Security.MaxAverageSpeed40.0m/s, straight line from where the bus left the last stop. A stop reached faster is refused and flagged (a teleport earns nothing faster than driving). false: off. Admin test drives are not checked

Career

SettingDefaultMeaning
Config.Career.MaxLevel50Highest level
Config.Career.NotifyLevelUptrueNotification and sound on level up
Config.Career.Command'busprofile'Player command for the career menu (also at the depot desk and in the route menu); nil turns it off
Config.XP.Base / Growth / Exponent400 / 45 / 1.45XP from level L to L+1 = floor(Base + Growth * (L-1)^Exponent)
Config.XP.MaxSingleAward5000Safety cap for a single XP award
Config.Reputation.Start50Reputation of a new driver
Config.Reputation.Min / Max0 / 100Reputation range
Config.Reputation.MaxSingleChange25Safety cap for a single change

With the default curve: level 5 at 1,988 XP, level 10 at 7,064, level 20 at 30,949, level 30 at 78,938, level 50 at 267,368.

Ranks (data/career.lua)

{ level = 10, key = 'rank_city' },                    -- name from locales
{ level = 10, key = 'rank_city', label = 'Metro' },   -- fixed name, ignores locales

Levels must be ascending and start at 1.

Job and shift

SettingDefaultMeaning
Config.Job.RequiredfalseOnly players with one of Config.Job.Names can start a shift
Config.Job.Names{ 'bus' }Accepted jobs
Config.Job.RequireDutyfalseAlso require the framework's on-duty flag
Config.Shift.TargetDistance2.5Target reach at the desk
Config.Shift.DeskDistance8.0Server-checked max distance to the desk
Config.Shift.RequireVehicleReturntrueThe bus must be returned before ending the shift

Depots

Config.Depots = {
    {
        id = 'downtown',
        label = 'depot_downtown',                        -- locale key or plain text
        blip = { enabled = true, sprite = 513, color = 5, scale = 0.8 },
        ped = { model = 's_m_m_gentransport', coords = vector4(...) },
        vehicleSpawns = { vector4(...), vector4(...) }, -- first free bay is used
        returnPoint = { coords = vector3(...), radius = 12.0 },
        servicePoint = { coords = vector3(...), radius = 10.0 }, -- optional, Phase 13
    },
}

The default coordinates are examples. Stand where you want the desk or a bay and run /buscoords (needs dev commands): the vector4 is copied to your clipboard. Invalid depots are skipped with a console message.

Vehicles

SettingDefaultMeaning
Config.Vehicles.PlatePrefix'NSB'Up to 3 characters, 5 random digits follow
Config.Vehicles.WarpIntoVehicletruePut the driver in the seat after spawning
Config.Vehicles.StartFuel100.0Fuel on spawn when Config.Condition is off (otherwise the bus keeps its own fuel)
Config.Vehicles.SpawnClearRadius4.0A bay counts as free when no vehicle is closer than this
Config.Vehicles.SpawnTimeoutMs5000Give up spawning after this long
Config.Vehicles.WatchIntervalMs5000How often active buses are checked (only while any exist)
Config.Vehicles.DestroyedEngineHealth-3500.0Engine health at which the bus counts as destroyed
Config.Vehicles.AbandonDistance300.0Driver farther than this from the bus...
Config.Vehicles.AbandonSeconds300...for this long: the bus is taken back (a warning comes first)
Config.Vehicles.Models5 modelsid, model, label, tier, capacity, requiredLevel, class, optional seats and doors
Config.VehicleKeys'auto''qbx_vehiclekeys', 'qb-vehiclekeys', 'custom', 'none'

With VehicleKeys = 'custom', ns-bus fires the server events ns-bus:giveKeys and ns-bus:removeKeys with (src, netId, plate).

Bus condition, fuel, cleaning and upgrades

Every driver has their own bus of each model. Fuel, engine, body, cleanliness and interior (0 to 100) and the distance it has driven carry over to the next shift (table ns_bus_fleet). The server keeps the numbers; the game only shows them.

SettingDefaultMeaning
Config.Condition.Enabledtruefalse: buses spawn as before, no wear, no service bay, no upgrades
Config.Condition.Startall 100Condition of a driver's new bus
Config.Condition.FuelMode'auto''auto': a running fuel resource (ox_fuel, LegacyFuel, cdn-fuel, ps-fuel) owns the fuel and the bus reports its level; otherwise ns-bus uses fuel by distance. 'internal' / 'external' to force one
Config.Condition.FuelPerKm2.5Percent per km in internal mode; a model can set its own fuelPerKm
Config.Condition.FuelWarnAt{ 25, 10 }Notices when fuel drops below these
Config.Condition.MinFuelToStart / MinEngineToStart15 / 25A route cannot start below these
Config.Condition.DirtPerKm / LitterPerPassenger1.2 / 0.6Cleanliness lost per km and per passenger
Config.Condition.WearPerPassenger0.15Interior wear per passenger
Config.Condition.AcceptWorldRepairsfalsetrue: repairs by other scripts during a shift count. Mechanic scripts can call exports['ns-bus']:RepairBus(src) instead
Config.Condition.WreckedRestore35A destroyed bus comes back from the yard with this engine and body
Config.Condition.Moodsee fileMood points passengers lose when they sit down in a dirty (below 40), worn (below 40) or damaged (body below 50) bus
Config.Condition.ComplaintChance0.35Chance of a complaint notice in such a bus, once per route
Config.Condition.SafeDrivingsee fileA body health drop of CollisionDrop points between two readings during a route is a collision or an impact the driver's game felt (a velocity change of ImpactKmh within a tenth of a second; hard braking stays far below it). At most one per CollisionGapMs, so scraping along a wall counts once: ScorePenalty route score points, Reputation per collision (at most MaxReputationPerRun), and a perfect route needs none. A route without a collision of at least MinKm km gives XpBonus XP
Config.Condition.Servicesee fileService bay: Base + missing points * PerPoint seconds (at most Max); CostPerPoint money per missing point (default only the repair costs, $2 per point of engine + body + interior), paid from Account
Config.Condition.MaxSampleSpeed60.0m/s; a longer jump between two checks is a teleport and uses no fuel
Config.Condition.PushIntervalMs5000Condition updates to the driver at most this often

Service bay. Drive the bus into Config.Depots[].servicePoint (or the return point when a depot has none) and press G (or use the buttons in the dashboard's Vehicle tab): refuel, clean or repair. The server checks that the bus stays in the bay until the time is up; a route cannot start during a service.

Upgrades (data/upgrades.lua) are fitted at the depot desk and belong to that driver's bus of that model. Each level has a price, a career level and optionally a distance the bus must have driven. Active in this version: comfort (passenger mood), economy engine tune (fuel use), easy-clean interior (dirt), heavy-duty seats (interior wear). Brakes, engine, suspension, doors and safety are defined but not offered yet; new effects can be read with Condition.Effect(rec, name).

Stops

Stops are created in game with /busadmin and stored in the database. config.lua only holds the rules:

SettingDefaultMeaning
Config.Stops.SeedExamplestrueInsert the example stops from data/stops.lua once, on the very first start
Config.Stops.ShowBlipsfalseShow every enabled stop on the map for all players
Config.Stops.Blipsprite 513, color 3, scale 0.6Default blip for new stops
Config.Stops.DefaultRadius15.0Zone in which the bus counts as at the stop
Config.Stops.MinRadius / MaxRadius5.0 / 40.0Allowed radius range
Config.Stops.MaxLayoutDistance40.0Every captured point must be this close to the bus position
Config.Stops.MaxNpcSpawns8NPC spawn points per stop
Config.Stops.AdminDrawDistance150.0Admin markers are drawn for stops closer than this

Creating a stop

  1. Park a bus where it should stop (or stand there) and run /busadmin.
  2. Create stop, set a code (legion_01) and a display name.
  3. Select Bus stopping position: your vehicle's position and heading are stored.
  4. Walk to the sidewalk and capture the waiting area, NPC spawn points, boarding and exit points and the ticket inspection area.
  5. Save stop.

Routes

Routes are built in game with /busadmin and stored in the database.

SettingDefaultMeaning
Config.Routes.SeedExamplestrueInsert the example route from data/routes.lua once (only if all its stops exist)
Config.Routes.MinStops / MaxStops2 / 30Stops per route (in-service stops count toward the minimum)
Config.Routes.DefaultColor5Map color of new routes
Config.Routes.MinPayoutMultiplier / MaxPayoutMultiplier0.5 / 3.0Allowed payout multiplier range
Config.Routes.MaxDwellSeconds120Longest waiting time override per stop
Config.Routes.ReturnCodeSuffix'_r'Code suffix of generated return routes
Config.Routes.CopyCodeSuffix'_copy'Code suffix of duplicated routes

Building a route

  1. /busadmin → Create route, set a code (ls-101) and a name.
  2. Stops → Add stop in driving order. Open a stop to move it, skip it on express routes, set a waiting time or remove it.
  3. Set type, difficulty, direction, required level, minimum bus tier and payout multiplier.
  4. The route is drawn on your map while you edit. Save route.
  5. For the way back, open the saved route and pick Create return route.

Driving routes

SettingDefaultMeaning
Config.Runs.MenuKey'F6'Default key of the route menu (players can rebind it in GTA settings)
Config.Runs.MaxStopSpeed2.0m/s; the bus must be (almost) stopped to arrive
Config.Runs.MaxHeadingDiff100.0Degrees from the stop's captured heading; false disables the check
Config.Runs.DefaultDwellSeconds6Doors-open time when the route sets none
Config.Runs.ZoneMargin5.0Extra meters the server accepts (network delay)
Config.Runs.PassDistance80.0A "drove past" report is accepted only this close to the stop
Config.Runs.MaxSkipAhead3Arriving up to this many stops ahead marks the ones between as missed
Config.Runs.ExpectedSpeed / RoadFactor11.0 / 1.4Schedule: straight distance x RoadFactor / ExpectedSpeed
Config.Runs.LateSeconds / VeryLateSeconds60 / 180Grace before "late", and "very late"
Config.Runs.NearDistance, FarWait, NearWait, ZoneWait200 m, 1000/250/100 msClient check intervals while a route is active
Config.Runs.Paysee fileAccount, Base, PerStop, PerPassenger, MissedPenalty, OnTimeBonus, Difficulty multipliers
Config.Runs.XPsee fileBase, PerStop, PerPassenger, PerKm (long routes), PerRequest (requested stops served), OnTimeBonus, CleanBonus (no missed stop), PerfectBonus (perfect route)
Config.Runs.CleanRunReputation1Reputation for a route with no missed stops and at least 80% on time
Config.Runs.MissedReputationPerStop = 1, MaxPerRun = 3Reputation lost per missed stop, capped per route

Pay = (Base + PerStop x served + PerPassenger x delivered - MissedPenalty x missed) x route multiplier x difficulty x (1 + OnTimeBonus x on-time ratio), never below 0. delivered counts passengers taken to their stop.

XP = (Base + PerStop x served + PerPassenger x delivered + PerKm x km + PerRequest x requests served) x difficulty x (1 + OnTimeBonus x on-time ratio) + ticket XP + CleanBonus + PerfectBonus + conversation XP. XP never goes down; mistakes cost pay and reputation.

NPC passengers

Passenger models and idle animations live in data/passengers.lua.

SettingDefaultMeaning
Config.Passengers.EnabledtruePassengers on routes
Config.Passengers.InTestRunstrueAdmin test drives get passengers too
Config.Passengers.TestMaxSeats16Seat limit for test drives in your own vehicle
Config.Passengers.NetworkedtrueEveryone sees the passengers. Set false with sv_entityLockdown strict (then only the driver sees them)
Config.Passengers.PerStop{ min = 0, max = 4 }Waiting passengers per stop (the final stop gets none; 0 makes empty stops possible)
Config.Passengers.MaxWaitingPerStop8Upper limit after the route type multiplier
Config.Passengers.RouteTypeMultipliersee fileMore at airports and events, fewer at night
Config.Passengers.AlightSecondsEach / BoardSecondsEach4 / 6Time allowed per passenger getting off / on
Config.Passengers.MaxServiceSeconds60Hard limit on top of the stop's waiting time
Config.Passengers.ServiceTickMs2000Longest gap between server checks while the bus is at a stop
Config.Passengers.SpawnDistance / DespawnDistance150.0 / 250.0Waiting passengers appear / disappear by bus distance
Config.Passengers.ReactDistance45.0They turn towards the bus when it is this close
Config.Passengers.BoardTimeoutMs / AlightTimeoutMs15000 / 8000A stuck passenger is placed in the seat / outside
Config.Passengers.RemoveAfterMs20000Passengers who left are removed after this (or once out of sight)

At a stop, people get off first, then the queue boards into free seats. The doors close when everyone is done and the stop's waiting time has passed. Anyone who does not fit stays at the stop and you get a "no available seats" notice. A stuck NPC never costs you anything: the server settles it when its time runs out.

Capacity is the smaller of the model's capacity and the real number of passenger seats of the bus. To use only some seats, give the model a seats list; to choose which doors open at stops, give it a doors list.

Better stops: capture the waiting area, NPC spawn points, the boarding point (where the queue forms, next to the front door) and the exit point in /busadmin. Without them, passengers stand on the nearest pavement and queue beside the bus.

Stop requests

SettingDefaultMeaning
Config.StopRequest.EnabledtrueRiders press the stop button before their stop
Config.StopRequest.SkipEmptyStopstrueA stop where nobody waits and nobody wants off may be driven past without penalty (and without pay for it). The final stop is always served
Config.StopRequest.RequestDistance120 - 320 mHow far before their stop riders press the button
Config.StopRequest.RandomRequestChance0.05A rider changes their mind and gets off at the next stop
Config.StopRequest.CheckMs1000Server check while riders are about to press (no loop otherwise)
Config.StopRequest.Sound'chime''chime' (the bundled bell nui/sounds/stop.ogg), 'file' (nui/sounds/<SoundFile>), 'frontend' (GTA sound), 'none'
Config.StopRequest.SoundFile'stop.ogg'Your own sound for 'file': put it in nui/sounds/
Config.StopRequest.Volume0.60.0 - 1.0 ('chime' and 'file')
Config.StopRequest.FrontendTIMER_STOPGTA sound name and set for 'frontend'
Config.StopRequest.RepeatCooldownMs4000More requests for the same stop chime again at most this often
Config.StopRequest.ReputationMissed = 1, MaxPerRun = 2Reputation per requested stop you drove past, capped per route (completed routes only)

The HUD shows what waits at the coming stop: STOP REQUEST with the number of riders (bell icon), the number of people waiting, or "Nobody waiting, no request" when you may drive past. F6 lists the passengers on board, where each gets off and who pressed the button. A rider whose stop you drive past sits down unhappy and gets off at the next stop that is served.

Passengers: personality, conversations, events

Personalities and their effects are in data/passengers.lua, conversations in data/dialogues.lua (texts are locale keys), events in server/events/ (one file each).

SettingDefaultMeaning
Config.Satisfaction.Latelate = 8, very_late = 20Mood lost by everyone on board when you arrive late (x personality lateness)
Config.Satisfaction.MissedRequest15Mood lost when you drive past their stop
Config.Satisfaction.High / Low80 / 40Route average at or above / at or below gives +Reputation.High / -Reputation.Low
Config.Social.EnabledtruePassengers talk to you
Config.Social.ChancePerLeg0.3A rider starts talking between two stops (x personality talk)
Config.Social.DelaySeconds6 - 20After leaving the stop
Config.Social.AnswerSeconds20Unanswered: they give up and lose IgnoredMood
Config.Social.LateComplaintChance0.6Someone complains when you arrive late
Config.Social.ByeChance0.5Passengers say goodbye (or grumble) when they get off
Config.Social.AnswerKeys'1', '2', '3'Answers while a passenger talks to you: positive, neutral or refusing, no answer (counts like letting the time run out). While the card is up these keys do not select weapons or use the ox_inventory hotbar
Config.Social.MaxReputationPerRun2Reputation from conversations and events per route (completed routes only)
Config.Social.XpPerPositive = 10, MaxPerRun = 40XP for conversations that went well, capped per route
Config.Events.EnabledtrueRandom passenger events
Config.Events.ChancePerLeg / ChancePerStop0.12 / 0.06How often an event happens
Config.Events.AnswerSeconds / EmergencySeconds25 / 30Time to answer an event / a sick passenger
Config.Events.BlockDoorSeconds8Extra stop time while someone blocks the door
Config.Events.LostItemFoundChance0.6Searching finds the lost item
Config.Events.Weightssee fileHow often each event is picked; 0 turns one off

When a passenger talks to you, their line shows in the HUD and as a subtitle; press F6 to answer. A sick passenger is an emergency: the route waits until you decide (stop the bus, call EMS or drive on to the next stop). Stopping only works when the bus is standing still. On foot near a passenger you can Talk to them or Ask destination with the target eye.

The route report shows the average satisfaction of the passengers you took to their stop.

Police inspections and fines

SettingDefaultMeaning
Config.Inspection.EnabledtruePolice inspections
Config.Inspection.InTestRunsfalseRoutine inspections in admin test drives (never fines or records)
Config.Inspection.NetworkedtrueThe officer and the police car are networked so riders and other players see the inspection. false with sv_entityLockdown strict: only the driver sees them
Config.Inspection.Chancesee fileChance that a route gets a routine inspection, by route type (city 35%, airport 45%, night 60%, event 50%). It happens when the doors close at one of the stops, spread evenly, so a long line is not inspected more often than a short one
Config.Inspection.MaxPerRun / CooldownMinutes1 / 10At most one routine inspection per route, then a break per driver
Config.Inspection.NpcSeconds15How long a routine inspection takes without Dialogue
Config.Inspection.Dialoguesee fileThe officer talks to the driver like a passenger (answers 1 / 2 / 3): walks to the bus (ArriveSeconds per kind), greets you, checks the bus for CheckSeconds, tells you the result. Polite both times: driver fine x Cooperative (0.75); silent or short both times: x Uncooperative (1.25). Enabled = false: the timed check without talking
Config.Inspection.Pulloversee fileRoutine inspections on the road: Share of them (0.4) are a police car with its siren on behind the bus, DelaySeconds after leaving a stop. Standing still (StopSpeed m/s) for StopSeconds lets the officer out; not stopping within TimeoutSeconds is fleeing: Fled.Fine, Fled.Reputation and a failed inspection. Vehicle / Officer models. The other routine inspections: the officer waits at the coming stop (the stop's inspection point, else its waiting area)
Config.Inspection.CheckShare1.0Share of the riders whose tickets are checked
Config.Inspection.FareEvasion.PassengerFine150What fare dodgers pay (shown in the report)
Config.Inspection.FareEvasion.DriverFine300Per fare dodger found, before the factors
Config.Inspection.FareEvasion.DriverPenaltyEnabledtrueFine the driver at all
Config.Inspection.FareEvasion.Factorsforced = 0, allowed_without_check = 0.5, accepted = 1How much the driver is to blame, by how the dodger got on
Config.Inspection.FareEvasion.CheckedDiscount0.5You checked tickets on this route: the fine is halved
Config.Inspection.FareEvasion.RepeatStep / RepeatMax0.25 / 4Each earlier failed inspection raises the fine by 25%, counting at most 4
Config.Inspection.FareEvasion.MaxDriverFine1500Highest driver fine
Config.Inspection.FareEvasion.Account'bank'Taken from here, or from the other account if short
Config.Inspection.ReputationPassed = 1, Failed = 2Reputation after an inspection
Config.Inspection.XPPassed = 75XP for the driver when an inspection is passed
Config.Inspection.Police.EnabledtruePolice players can inspect buses
Config.Inspection.Police.Jobs / RequireDutynil / truePolice jobs (nil uses Config.Dispatch.PoliceJobs), on duty only
Config.Inspection.Police.Distance / TimeoutSeconds10.0 / 180The officer must stay close; an unfinished inspection is dropped
Config.Inspection.Police.CooldownMinutes10Per driver, between two player inspections
Config.Inspection.Police.Accessall trueWhat officers see: driver info, route, history, ticket list

During an inspection the route waits and goes on where it was afterwards. Fare dodgers found are taken off the bus. The driver is fined only for dodgers they let on: nothing for one who slipped past unnoticed, half when you ignored "Ticket required", in full when you checked and let them in anyway. The amount is always calculated by the server; a police player only decides to issue or waive it.

Assignments and achievements

SettingDefaultMeaning
Config.Progress.Account'bank'Where money rewards of assignments and achievements go
Config.Progress.PerfectMinStops = 4, MinSatisfaction = 75A perfect route: no missed stop, every stop on time, no fare dodger got through, no requested stop driven past, at least MinStops stops and (with passengers) this average satisfaction
Config.Assignments.EnabledtrueDaily and weekly assignments
Config.Assignments.Daily / Weekly3 / 2Assignments per driver per day and per week
Config.Assignments.ResetHour6Server local time; a new day starts at this hour, a new week on Monday at this hour
Config.Assignments.AutoClaimtrueRewards are paid as soon as an assignment is done; false: collected in the career menu
Config.Assignments.KeepDays21Old periods are removed from the database after this
Config.Achievements.EnabledtrueAchievements

Drivers open the career menu at the depot desk, in the route menu (F6 while on shift) or with /busprofile. It shows level, rank and XP, reputation, the daily and weekly assignments with their progress and time left, achievements and statistics.

Assignments (data/assignments.lua)

Each period a driver gets a pick from this pool, weighted, by level, and only assignments for a route type that exists on the server. The pick is saved and does not change during the period.

{ id = 'd_city_routes', period = 'daily', key = 'asg_city_routes', event = 'route_completed',
    filter = { routeType = 'CITY' }, target = 3, reward = { money = 450, xp = 200 } },
{ id = 'w_distance', period = 'weekly', key = 'asg_distance', event = 'route_completed',
    amount = 'distance', unit = 'km', target = 500000, reward = { money = 3000, xp = 1200 } },
  • event: route_completed (completed, paid routes only) or inspection
  • amount: 1 (default), a number, or a field of the event: passengers, ticketsChecked, caught, requestsServed, served, distance (meters) ...
  • filter: every field must match: a value (clean = true), a list (routeType = { 'CITY', 'NIGHT' }) or a range (onTimePct = { min = 90 })
  • route fields: routeType, difficulty, served, missed, total, onTimePct, passengers, ticketsChecked, caught, evaded, requestsServed, requestsMissed, satisfaction, distance, clean, perfect, inspection; inspection fields: passed, kind, violations
  • minLevel, maxLevel, weight are optional
  • reward: money, xp, reputation, unlock (an id other resources can check with exports['ns-bus']:HasUnlock)

Never reuse an id for a different task. key is a locale key that gets the target as %d, or use label = 'My text %d'.

Achievements (data/achievements.lua)

{ id = 'routes_100', key = 'ach_routes_100', icon = 'route', stat = 'completed_routes', target = 100,
    reward = { xp = 1500, money = 5000 } },
{ id = 'perfect_route', key = 'ach_perfect_route', counter = 'perfect_routes', target = 1 },
{ id = 'master_driver', key = 'ach_master_driver', level = 40, hidden = true },
{ id = 'zero_fare_evasion', key = 'ach_zero_fare_evasion', event = 'route_completed',
    filter = { evaded = 0, ticketsChecked = { min = 10 } } },

One condition each: a career statistic (stat), a counter (perfect_routes, clean_routes, stops_served, requests_served, inspections_passed), a level, or a single matching event. The description is the locale key key .. '_desc'. Achievements are checked when a driver loads, so new ones also unlock for drivers who already reached them. Never rename a released id.

Interface (NUI) and statistics

SettingDefaultMeaning
Config.UI.Dashboard'nui'Driver dashboard at the depot desk, with the route key between routes and with /busprofile; 'menu': the ox_lib career menu and route list
Config.UI.Hud'nui'Route panel while driving; 'text': the ox_lib text UI
Config.UI.Reports'nui'Route report, inspection report and ticket card as cards; 'notify': ox_lib notifications
Config.UI.Admin'nui'/busadmin opens the admin dashboard; 'menu': the ox_lib menus
Config.UI.HudPosition'bottom-right''bottom-right', 'bottom-left', 'top-right', 'top-left', 'right-center'
Config.UI.Scale1.0Size of every panel, 0.75 to 1.25
Config.UI.ReportSeconds / TicketCardSeconds12 / 6How long reports and ticket cards stay on screen
Config.Statistics.RecentRuns / TopRoutes / RecentInspections10 / 5 / 5List lengths in the dashboard

The texts of every panel come from locales/; change them there. "Today" starts at midnight server time. The admin dashboard needs the same permission as before (ns-bus.admin or framework admin); the server checks it on every action.

Stops in the admin dashboard: stand where a point belongs (or park the bus on the stopping position) and press Capture here. Hide panel closes it but keeps your draft: walk to the next point and type /busadmin again. Routes: drag stops in the list to reorder them, click a grey stop on the map to add it, click a numbered stop to change its settings.

Tickets and fare dodgers

SettingDefaultMeaning
Config.Tickets.Enabledtruefalse: passengers just get on (no door, no tickets)
Config.Tickets.Distributionsee fileWeights of what passengers carry: standard, discount and special pass are valid; none, expired and BORROWED_TICKET (someone else's card: the validator accepts it, only the names on the ticket and the ID card differ) are not
Config.Tickets.SlipChance0.5Share of fare dodgers who walk past the validator without a word
Config.Tickets.RetryChance0.35A refused fare dodger tries once more
Config.Tickets.DriverDecidestrueEvery passenger waits at the door until you let them in or refuse them (checking first is up to you); the stop waits for it too
Config.Tickets.DriverDecideSeconds30With DriverDecides: after this they give up waiting and walk in (counted as let in without a check)
Config.Tickets.TapSeconds2Without DriverDecides: a passenger validates their ticket and gets on after this, unless you check
Config.Tickets.DecisionSeconds6Without DriverDecides: after "Ticket required", time to decide before they walk in anyway
Config.Tickets.CheckDecisionSeconds10After a check: time to let them in or refuse
Config.Tickets.KeysAccept = 'Y', Refuse = 'N'Default keys while a passenger is at the door (players can rebind them in GTA settings; they do nothing otherwise)
Config.Tickets.XPCheck = 0, Caught = 15XP per checked ticket (every passenger shows it now) and per stopped fare dodger
Config.Tickets.Reputationsee fileCaught, Ignored, Knowingly, WrongRefusal, capped at MaxPerRun per route

While passengers get on, one of them stands at the door at a time. A validator beep means they have a ticket. "Ticket required" means they do not, and they say so. Silence means someone is walking past without paying, and only a spot check catches them. Doing nothing lets the passenger in. Checking shows a ticket card (name, ticket, destination, valid or not).

XP, reputation and statistics for tickets are settled only when the route is completed, never for a cancelled route. Letting someone in without checking after a warning, or letting them in after seeing an invalid ticket, costs reputation; so does refusing a valid passenger. A dodger who slipped past unnoticed costs nothing yet, but police inspections (Phase 10) may find them.

Ticket machine (real players)

Players can ride a bus that is on a route like any passenger. On board they open the ticket machine with K and buy a ticket; the driver opens the same machine, sees the players on board and offers them a ticket. Prices, validity, money and the commission are decided on the server; a ticket is printed in the character's name and stored in ns_bus_tickets, so it survives a relog.

SettingDefaultMeaning
Config.TicketMachine.Enabledtruefalse: no machine, and police checks leave player riders alone
Config.TicketMachine.Key'K'Default key for the machine (rebindable in GTA settings; it does nothing off a bus on a route)
Config.TicketMachine.Account'cash'Tickets and fines are paid from this account first, the other one if it is short
Config.TicketMachine.DriverCommission0.15Share of every sale on the bus paid to its driver at once (rounded down)
Config.TicketMachine.CommissionAccount'bank'Where the commission goes
Config.TicketMachine.OfferSeconds30How long a ticket the driver offers waits for an answer
Config.TicketMachine.KeysAccept = 'Y', Decline = 'N'Answering an offer (rebindable; only active while an offer is up)
Config.TicketMachine.PassengerFine150A player rider without a valid ticket at a police inspection pays this
Config.TicketMachine.RemoveDodgerstrueThey also get off the bus once it stands still
Config.TicketMachine.KeepDays30Expired tickets are removed from the database after this many days (at start)
Config.TicketMachine.Productssingle, discount, dayWhat the machine sells, in this order: id, kind (a valid ticket type: VALID_TICKET, DISCOUNT_TICKET, SPECIAL_TICKET), price, minutes, rideOnly (valid only on the route run it was bought on), optional label (plain text; otherwise the locale key tm_product_<id>), enabled = false to stop selling it

A rider holds one covering ticket at a time: buying again while a ticket is valid on this bus is refused. The driver cannot buy (drivers ride for free) and can only offer tickets to players on their own bus who have none. The machine works on real routes only, not on admin test drives.

Police inspections (routine and police players) check every player rider. One without a valid ticket pays PassengerFine themselves (an unpaid fine is written to the audit log); the driver is never blamed or fined for them. Tickets sold on a route show on the route report.

Integrations

SettingDefaultOptions
Config.Target'auto''ox_target', 'qb-target'
Config.Inventory'auto''ox_inventory', 'qb', 'esx', 'none'
Config.Fuel'auto''ox_fuel', 'LegacyFuel', 'cdn-fuel', 'ps-fuel', 'native'
Config.Dispatch.Provider'auto''qs-dispatch', 'ps-dispatch', 'cd_dispatch', 'custom', 'none'
Config.Dispatch.PoliceJobs{ 'police', 'sheriff' }Jobs that receive police alerts
Config.Dispatch.EmsJobs{ 'ambulance' }Jobs that receive EMS alerts

Custom dispatch

With Provider = 'custom', ns-bus fires the client event ns-bus:dispatch with a ready alert (service, code, title, message, coords, blip). Listen to it from your own script, or edit Adapters.custom in bridge/dispatch.lua (that file is not escrowed).

Dispatch export signatures are based on each resource's public documentation. They change between versions, so test alerts with the version you run.

Notifications

SettingDefault
Config.Notifications.Position'top-right'
Config.Notifications.Duration5000

Cart

Your cart is empty.