> For the complete documentation index, see [llms.txt](https://pepper-scripts.gitbook.io/pepper-scripts-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://pepper-scripts.gitbook.io/pepper-scripts-docs/activities/pepper-racing.md).

# Pepper Racing

Racing tablet with a legal club and an underground scene – starting grid with start lights, race control, protests, ghosts, crews, seasons and a track editor for ESX, QBCore and Qbox.

On most servers racing meant: drive through checkpoints, read the time, done. With **Pepper Racing** your players line up on their grid slot, wait for five red lights, and race control watches every corner – or they race at night in the underground, where the meetup only hits the GPS shortly before the start.

Everything runs through the **racing tablet** (item `racing_tablet`) with two worlds: the bright **Pepper Racing Club** in a timing-screen look and the dark neon **Underground**.

{% hint style="success" %}
**Get Pepper Racing:** [shop.pepperscripts.de](https://shop.pepperscripts.de)
{% endhint %}

{% hint style="info" %}
🧪 **Tested on our dev server:** Of course we test all scripts continuously on our own dev server “Pepper Scripts”.
{% endhint %}

### Features

* **6 modes** – sprint, circuit (1–50 laps), elimination, drag, drift, time trial with leaderboard
* **Starting grid** with up to 16 slots (by rating, sign-up or random), marker + GPS, 90 s to get there
* **Start lights** – 5 red lights with a random hold; drag races use a christmas tree with jump-start detection
* **Steward** – detects shortcuts (warning, then a 5 s time penalty), checks checkpoint order and times on the server
* **Race control as an RP role** – live map, timing, time penalties, disqualification, red flag, announcements, incident log
* **Protests** in the club – 120 s window, provisional → official result, prize money and rating only after that
* **Live HUD** – timing tower, delta to your best, sector times purple/green/yellow, mini map, tires, drift meter, freely movable
* **Ghost & ideal line** – your personal best or the track record drives along semi-transparently
* **Tire wear & pit stops** on circuits with 3+ laps, **photo finish** below 0.1 s
* **Performance classes D–X** calculated from vehicle stats incl. tuning (PI 100–999)
* **Underground** – district + time instead of a location, secret meetup, scene heat per district, police alerts, street rep
* **Underground career** – 5 job types (courier run, speed trap hunt, drift trail, lose the heat, rival duel) and 6 street tiers with unlocks; dirty money as an item if you like
* **Betting** (pari-mutuel with live odds), **pink slips** (can be enabled by the server owner, off by default)
* **Racer rating** (Elo) with 6 ranks, **crews/teams**, **seasons** with rewards, **knockout tournaments** and **championships**
* **In-game track editor** with record mode, pit lane and camera preview – plus **track approval**
* **Broadcast overlay** for streamers and commentators, Discord webhooks, server exports
* German & English with German motorsport terms, open config, locales and bridges

{% hint style="info" %}
**4 default tracks included:** Sandy Shores Short Loop, Grand Senora Loop, Sandy Shores Airfield Drag and LSIA Runway Drag are installed on first start (`install/default_tracks.json`, can be turned off with `Config.Tracks.InstallDefaults`). Build more tracks yourself in the editor – anywhere on the map. Admin tracks are approved instantly, tracks by other players go through track approval.
{% endhint %}

### At a glance

|                             |                                                                                                       |
| --------------------------- | ----------------------------------------------------------------------------------------------------- |
| **Version**                 | 1.0.0                                                                                                 |
| **Framework**               | ESX Legacy (`es_extended`), QBCore (`qb-core`) or Qbox (`qbx_core`) – auto-detected                   |
| **FiveM server**            | build 7290 or newer, **OneSync** required                                                             |
| **Dependencies (required)** | [oxmysql](https://github.com/overextended/oxmysql), [ox\_lib](https://github.com/overextended/ox_lib) |
| **Inventory**               | ox\_inventory, qb-inventory (also ps-/lj-inventory) or the default ESX inventory                      |
| **Optional**                | ps-dispatch, cd\_dispatch, qs-dispatch, rcore\_dispatch or core\_dispatch                             |
| **Database**                | MySQL or MariaDB – tables are created automatically                                                   |
| **Languages**               | German, English                                                                                       |
| **Delivery**                | Cfx.re Asset Escrow (`config/`, `locales/`, `bridge/`, `install/` open)                               |

### Installation

Plan about **15–20 minutes**. Follow the steps in order – every step ends with a **checkpoint**.

{% hint style="warning" %}
**Always open files with a text editor** such as [Visual Studio Code](https://code.visualstudio.com/) or [Notepad++](https://notepad-plus-plus.org/) – never with Word or WordPad.
{% endhint %}

#### Step 1 – Check the requirements

| What                                                                              | Why                                                          | Required?   |
| --------------------------------------------------------------------------------- | ------------------------------------------------------------ | ----------- |
| FiveM server **build 7290 or newer**                                              | older servers cannot start the script                        | yes         |
| **OneSync** enabled                                                               | grid slots, positions and vehicles are checked on the server | yes         |
| **MySQL/MariaDB** + **oxmysql**                                                   | profiles, tracks, best times, ghosts, crews, seasons         | yes         |
| **ox\_lib**                                                                       | server calls and notifications                               | yes         |
| **ESX Legacy**, **QBCore** or **Qbox**                                            | characters, money, jobs                                      | exactly one |
| Inventory: **ox\_inventory**, **qb-inventory** (ps-/lj-) or the ESX inventory     | items `racing_tablet` etc.                                   | one of them |
| Dispatch: ps-dispatch, cd\_dispatch, qs-dispatch, rcore\_dispatch, core\_dispatch | police alerts in the underground                             | no          |

**OneSync:** in txAdmin under **Settings → FXServer** set it to **On** – without txAdmin add `set onesync on` at the top of `server.cfg`.

{% hint style="success" %}
**Checkpoint:** on server start the console shows `Started resource <name>` for `oxmysql`, `ox_lib`, your framework and your inventory.
{% endhint %}

#### Step 2 – Download and extract

1. Open the [Cfx.re Portal → Granted Assets](https://portal.cfx.re/assets/granted-assets) and download **pepper\_racing**.
2. Copy the `pepper_racing` folder to `resources/[pepper]/`.

```
resources/
└── [pepper]/
    └── pepper_racing/
        ├── bridge/
        ├── client/
        ├── config/
        │   ├── config.lua
        │   ├── server.lua
        │   └── vehicles.lua
        ├── html/
        ├── install/
        │   ├── esx_items.sql
        │   ├── ox_items.lua
        │   ├── ox_items_en.lua
        │   ├── pepper_racing.sql
        │   └── qb_items.lua
        ├── locales/
        ├── server/
        ├── shared/
        └── fxmanifest.lua
```

{% hint style="danger" %}
**Never rename the `pepper_racing` folder.** The tablet and the ox\_inventory export rely on the resource name.
{% endhint %}

{% hint style="warning" %}
**Asset Escrow:** the script only starts on a server whose license key (`sv_licenseKey`) belongs to the same Cfx.re account you bought it with. More: **Asset Escrow**.
{% endhint %}

#### Step 3 – Add the items

Pepper Racing uses three items:

| Item            | Name                  | Purpose                                                                        |
| --------------- | --------------------- | ------------------------------------------------------------------------------ |
| `racing_tablet` | Racing Tablet         | opens the tablet (usable)                                                      |
| `race_license`  | Race Director License | default permission to create races                                             |
| `race_usb`      | Underground Stick     | optional underground access (only if `Config.Illegal.AccessItem = 'race_usb'`) |

{% tabs %}
{% tab title="ox\_inventory (ESX, QBCore, Qbox)" %}

1. Open `install/ox_items_en.lua` (English names) or `install/ox_items.lua` (German names).
2. Copy **only the entries** between `return {` and the last `}`.
3. Paste them into `ox_inventory/data/items.lua` **before the very last closing bracket `}`**.

The tablet entry contains `server = { export = 'pepper_racing.racing_tablet' }` – it makes the item usable and must stay.
{% endtab %}

{% tab title="qb-inventory (QBCore)" %}

1. Open `install/qb_items.lua`.
2. Copy the entries between `return {` and the last `}`.
3. Paste them into the `QBShared.Items` table in `qb-core/shared/items.lua` (before its closing bracket).

Also works for ps-inventory and lj-inventory.
{% endtab %}

{% tab title="Default ESX inventory" %}
Import `install/esx_items.sql` into your database (e.g. with HeidiSQL or phpMyAdmin). It adds the three items to the `items` table.
{% endtab %}
{% endtabs %}

**Item images:** copy the included images from `install/images/` (`racing_tablet.png`, `race_license.png`, `race_usb.png`) into your inventory's image folder (ox\_inventory: `web/images/`, qb-inventory: `html/images/`).

{% hint style="success" %}
**Checkpoint:** after a restart you can give yourself the tablet (e.g. `/giveitem <id> racing_tablet 1`) and it shows up with its name in the inventory.
{% endhint %}

#### Step 4 – Database

Nothing to do: the resource creates all tables (`pepper_racing_*`) on first start. If your database user has **no CREATE permission**, import `install/pepper_racing.sql` first.

#### Step 5 – Check the config

Open `config/config.lua` and check at least:

* `Config.Locale = 'en'` (default is `'de'`)
* `Config.Framework = 'auto'` – detects Qbox, ESX and QBCore
* `Config.Permissions` – who may create races, build tracks, approve tracks and run race control (see **Configuration**)
* `Config.Economy` and `Config.DirtyMoney` – accounts for club (bank) and underground

Webhooks, pink slips and the sponsor bonus live in `config/server.lua`.

#### Step 6 – server.cfg

Add Pepper Racing **after** all dependencies:

```cfg
ensure oxmysql
ensure ox_lib
ensure es_extended      # or qb-core / qbx_core
ensure ox_inventory     # or qb-inventory
# optional: your dispatch system
ensure pepper_racing
```

Grant admin rights (recommended):

```cfg
add_ace group.admin pepper_racing.admin allow
```

#### Step 7 – First start

1. Start the server. The console shows `Installed 4 default tracks` and `Pepper Racing … started (framework: esx, tracks: 4, season: …)`.
2. Use the tablet in-game.
3. **Tracks** – the 4 included tracks are already approved. Your own tracks: **New track** – pick a name, type and area, open the editor (see **Race Control & Editor**).
4. **Create** – set up a test race.

{% hint style="success" %}
**Checkpoint:** the console shows the right framework, the tablet opens, and the 4 default tracks are listed under **Tracks** as "Approved".
{% endhint %}

{% hint style="info" %}
Problems? See the **FAQ**.
{% endhint %}

### Configuration

| File                  | Contents                                                                   |
| --------------------- | -------------------------------------------------------------------------- |
| `config/config.lua`   | all settings for client and server                                         |
| `config/vehicles.lua` | fixed classes per model, blocked models and vehicle classes                |
| `config/server.lua`   | webhooks, pink slips, sponsor bonus, admin ACE – **never** sent to clients |

Times without a unit in the name are seconds, money is always an integer.

#### Basics

| Option             | Default           | Description                                                                                      |
| ------------------ | ----------------- | ------------------------------------------------------------------------------------------------ |
| `Config.Locale`    | `'de'`            | language (`de` / `en`) – folder in `locales/`                                                    |
| `Config.Framework` | `'auto'`          | `auto`, `esx`, `qbcore`, `qbox`, `standalone` (`auto` checks qbx\_core → es\_extended → qb-core) |
| `Config.Item`      | `'racing_tablet'` | item that opens the tablet                                                                       |
| `Config.Command`   | `false`           | optional chat command (e.g. `'racing'`) – opens the tablet **without** the item                  |
| `Config.Tablet`    | `prop_cs_tablet`  | prop and animation when opening                                                                  |

#### Permissions

Admin = ACE `pepper_racing.admin` **or** a group from `Config.AdminGroups` (`admin`, `superadmin`, `god`). Admins automatically have every permission. All permissions are checked again on **every** server call.

| Permission     | For                                                      | Default                              |
| -------------- | -------------------------------------------------------- | ------------------------------------ |
| `createRace`   | create races and events (club + underground)             | group `admin` or item `race_license` |
| `createTrack`  | build tracks in the editor (non-admins → track approval) | group `admin`                        |
| `approveTrack` | approve or reject submitted tracks                       | group `admin`                        |
| `control`      | race control for **all** races                           | group `admin`                        |

The **organizer** of a race always has race control for their own race. Any matching condition is enough:

```lua
Config.Permissions = {
    createTrack = {
        ace = 'pepper_racing.createTrack',  -- add_ace group.mod pepper_racing.createTrack allow
        groups = { 'admin' },               -- framework groups
        jobs = { mechanic = 2 },            -- job from grade 2
        items = {},                         -- item in inventory
        everyone = false,                   -- true = every player
    },
}
```

{% hint style="info" %}
**RP idea:** give a job (e.g. a racing club job) the `control` permission – race control becomes a real role on your server instead of an admin tool.
{% endhint %}

#### Races

| Option                         | Default               | Description                                       |
| ------------------------------ | --------------------- | ------------------------------------------------- |
| `Config.Races.MaxActive`       | `10`                  | open races at the same time (1 per organizer)     |
| `Config.Races.MinRacers`       | `2`                   | minimum racers to start                           |
| `Config.Races.MaxRacers`       | `16`                  | max racers (2–16)                                 |
| `Config.Races.MaxLaps`         | `50`                  | max laps                                          |
| `Config.Races.LobbyTimeout`    | `1800`                | an open lobby without a start closes after 30 min |
| `Config.Races.LeaveVehicleDnf` | `15`                  | leaving the vehicle this long → DNF               |
| `Config.Races.StartDelays`     | `0, 2, 5, 10, 15, 30` | selectable start times in minutes                 |
| `Config.Grid.Time`             | `90`                  | seconds to drive onto your grid slot              |
| `Config.Grid.Radius`           | `4.0`                 | how close (m) the vehicle must be to the slot     |
| `Config.Grid.Teleport`         | `false`               | put racers straight onto their slot               |
| `Config.Grid.Order`            | `'rating'`            | `rating` (best in front), `signup`, `random`      |
| `Config.Lights`                | `200`–`3000` ms       | random hold after the 5th red light               |
| `Config.FinishTimeout`         | `120`                 | time for everyone else after the first finisher   |
| `Config.PhotoFinish`           | `100`                 | photo finish flag below this many milliseconds    |

#### Steward, anti-cheat and protests

| Option                           | Default   | Description                                          |
| -------------------------------- | --------- | ---------------------------------------------------- |
| `Config.Steward.Corridor`        | `2.5`     | corridor = checkpoint width × factor (min. 35 m)     |
| `Config.Steward.CutWarnAfter`    | `1.5`     | seconds outside → warning                            |
| `Config.Steward.CutPenaltyAfter` | `3.0`     | seconds outside → time penalty                       |
| `Config.Steward.CutPenalty`      | `5`       | time penalty (s), max. 1 per track section           |
| `Config.AntiCheat.MaxSpeed`      | `110.0`   | m/s – nobody can be faster between two checkpoints   |
| `Config.AntiCheat.MaxViolations` | `2`       | this many violations → disqualification              |
| `Config.Protest.Enabled`         | `true`    | protests (club only)                                 |
| `Config.Protest.Window`          | `120`     | window after the race, then the result is official   |
| `Config.Protest.Reasons`         | 4 reasons | contact, cutting, blocking, unsportsmanlike behavior |

#### Money and betting

| Option                           | Default                                            | Description                                                 |
| -------------------------------- | -------------------------------------------------- | ----------------------------------------------------------- |
| `Config.Economy.LegalAccount`    | `'bank'`                                           | entry fee/prize money in the club                           |
| `Config.Economy.IllegalAccount`  | `'black_money'`                                    | underground (account per framework via `Config.DirtyMoney`) |
| `Config.Economy.MaxEntryFee`     | `50000`                                            | max entry fee                                               |
| `Config.Economy.HouseCut`        | `0.05`                                             | 5 % of the pot is kept                                      |
| `Config.Economy.PrizeSplits`     | winner 100 · podium 60/30/10 · top 5 40/25/15/12/8 | prize split in percent                                      |
| `Config.DirtyMoney`              | ESX `black_money`, QBCore/Qbox `cash`              | QBCore/Qbox have no dirty money account by default          |
| `Config.Bets.Enabled`            | `true`                                             | betting (pari-mutuel)                                       |
| `Config.Bets.Min` / `Max`        | `100` / `25000`                                    | stake limits                                                |
| `Config.Bets.HouseCut`           | `0.05`                                             | house share                                                 |
| `Config.Bets.RacersMayBetOnSelf` | `true`                                             | racers may bet on themselves – never on opponents           |
| `Config.Bets.Legal` / `Illegal`  | `true` / `true`                                    | allow betting in the club / underground                     |

**Sponsor bonus** (`config/server.lua`): `ServerConfig.Sponsor = { Enabled = false, PerRacer = 500, Max = 10000 }` – the server adds money per starting racer to the prize pot of legal races (new money, not from players).

#### Underground and police

| Option                                   | Default                      | Description                                                                                                  |
| ---------------------------------------- | ---------------------------- | ------------------------------------------------------------------------------------------------------------ |
| `Config.Illegal.HiddenForJobs`           | `police`, `sheriff`, `state` | these jobs never see the underground                                                                         |
| `Config.Illegal.AccessItem`              | `nil`                        | e.g. `'race_usb'` – then only with the item                                                                  |
| `Config.Illegal.RevealBefore`            | `120`                        | meetup revealed via GPS this many seconds before the start                                                   |
| `Config.Illegal.MeetupRadius`            | `60.0`                       | meetup radius (m)                                                                                            |
| `Config.Illegal.Heat`                    | `18` / `1.0` / `60`          | heat per race / decay per minute / warning threshold                                                         |
| `Config.Illegal.StreetRepWin` / `Podium` | `25` / `10`                  | street rep for a win / P2–3                                                                                  |
| `Config.Police.Jobs`                     | `police`, `sheriff`          | who gets the alert                                                                                           |
| `Config.Police.BaseChance`               | `0.15`                       | base chance of an alert                                                                                      |
| `Config.Police.HeatFactor`               | `0.006`                      | + heat × factor (heat 100 → +60 %)                                                                           |
| `Config.Police.MaxChance`                | `0.85`                       | max. 85 %                                                                                                    |
| `Config.Police.BlipTime`                 | `90`                         | seconds the alert blip stays visible                                                                         |
| `Config.Police.Dispatch`                 | `'auto'`                     | `auto`, `builtin`, `ps-dispatch`, `cd_dispatch`, `qs-dispatch`, `rcore_dispatch`, `core_dispatch` or `false` |

**Pink slips**

{% hint style="danger" %}
**Off by default.** With pink slips both racers bet their own vehicle, and the winner gets the loser's vehicle **permanently** – ownership is rewritten in the database. Only enable it if it fits your server rules, and tell your players.
{% endhint %}

```lua
-- config/server.lua
ServerConfig.PinkSlips = { Enabled = true, Table = 'auto' } -- 'auto' | 'owned_vehicles' | 'player_vehicles'
```

`auto` uses `owned_vehicles` (ESX) or `player_vehicles` (QBCore/Qbox). If the table or column is missing, the console warns on start and pink slips stay off. Keys: qbx\_vehiclekeys, qb-vehiclekeys, wasabi\_carlock, MrNewbVehicleKeys – add your own system in `bridge/server/vehicles.lua`.

#### Street rep and jobs (since 1.2.0)

**Tiers** (`config/config.lua` → `Config.StreetRep`):

| Option                 | Default                           | Meaning                                                                                        |
| ---------------------- | --------------------------------- | ---------------------------------------------------------------------------------------------- |
| `Tiers`                | 0 / 150 / 400 / 900 / 1800 / 3000 | rep needed for each tier (names in `locales/*/core.json` → `core.tier_<key>`)                  |
| `Unlocks.createRace`   | `1`                               | from which tier players can host underground races (the `createRace` permission still applies) |
| `Unlocks.pinkSlips`    | `3`                               | host and join pink slip races                                                                  |
| `Unlocks.minTierRaces` | `4`                               | host races "only from tier X"                                                                  |
| `BetLimit`             | 2,500 / 5,000 / 10,000 / 25,000 … | max stake per underground race by tier (never above `Config.Bets.Max`)                         |
| `MissionBonus`         | 0 / 5 / 10 / 15 / 20 / 25         | % bonus on job rewards by tier                                                                 |

Admins bypass all tier locks.

**Jobs** (`config/missions.lua`, never sent to clients):

| Option                    | Default                                             | Meaning                                                                                                                               |
| ------------------------- | --------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| `Enabled`                 | `true`                                              | Jobs tab on/off                                                                                                                       |
| `Offers` / `SlotCooldown` | `3` / `240`                                         | offers on the board / seconds until a slot is refilled                                                                                |
| `DailyLimit`              | `20`                                                | jobs per character and day (0 = unlimited)                                                                                            |
| `TravelMinutes`           | `10`                                                | time to reach the meeting point                                                                                                       |
| `Reroll`                  | `250` $ / `60` s                                    | price and cooldown of "Reroll"                                                                                                        |
| `FailRep` / `AbortRep`    | `2` / `4`                                           | rep lost on failure / when cancelling a started job                                                                                   |
| `Difficulty`              | easy ×1 · medium ×1.6 (tier 2) · hard ×2.6 (tier 5) | reward, rep and time factor                                                                                                           |
| `Types.<type>`            | see file                                            | `Enabled`, `tier`, `Money = { min, max }`, `Rep` and the values of each type (time limit, minimum speed, target score, search area …) |
| `Items`                   | empty                                               | random bonus items, e.g. `{ name = 'race_usb', count = 1, chance = 0.05, types = { 'rival' }, minDifficulty = 'normal' }`             |
| `Locations`               | 20 spots                                            | pick-up, drop-off and meeting points – just add your own coordinates                                                                  |
| `DriftZones`              | 4 zones                                             | large open areas with a radius                                                                                                        |
| `SpeedTraps`              | empty                                               | your own speed trap routes; the script also finds long straights on your approved sprint/circuit tracks                               |

{% hint style="info" %}
**Rival duels** need other drivers' best times (time trial or sprint) on approved tracks. On a fresh server they show up once someone has driven a time trial.
{% endhint %}

**Dirty money as an item:** if underground money should be an item (e.g. `markedbills` on QBCore/Qbox), set `Config.DirtyMoney.Item`:

```lua
Config.DirtyMoney = {
    esx = 'black_money', qbcore = 'cash', qbox = 'cash', standalone = 'black_money',
    Item = { name = 'markedbills', worth = true }, -- worth = value stored in the metadata (otherwise 1 item = $1)
}
```

Entry fees, bets, prize money and job rewards then use the item (ox\_inventory, qb-/ps-/lj-inventory). Whole bundles are taken and the change comes back as a new bundle.

#### Rating, ranks and season

| Option                              | Default                                | Description                                                                           |
| ----------------------------------- | -------------------------------------- | ------------------------------------------------------------------------------------- |
| `Config.Elo`                        | start `1000`, K `32`, SoftReset `0.5`  | racer rating; the soft reset halves the distance to 1000 at season end                |
| `Config.Ranks`                      | 6 ranks                                | Rookie < 1000 ≤ Amateur < 1200 ≤ Semi-Pro < 1400 ≤ Pro < 1600 ≤ Elite < 1800 ≤ Legend |
| `Config.Points`                     | 25, 18, 15, 12, 10, 8, 6, 4, 2, 1      | season and championship points per position                                           |
| `Config.Season.Days`                | `30`                                   | season length (a new season starts automatically)                                     |
| `Config.Season.Factor`              | club `1.0`, underground `1.0`          | season points factor (time trials never count)                                        |
| `Config.Season.Rewards`             | P1 50,000 · P2–3 25,000 · P4–10 10,000 | rewards (money and/or items), claimable even if offline                               |
| `Config.Profile.AliasCooldownHours` | `24`                                   | how often the alias may be changed                                                    |

#### Crews and events

| Option                                | Default        | Description                                         |
| ------------------------------------- | -------------- | --------------------------------------------------- |
| `Config.Crews.Cost`                   | `25000` (bank) | founding cost                                       |
| `Config.Crews.MaxMembers`             | `20`           | members per crew                                    |
| `Config.Crews.InviteDistance`         | `10.0`         | invite by server ID only nearby (by alias anywhere) |
| `Config.Crews.Emblems` / `Colors`     | 12 / 12        | selectable emblems and colors                       |
| `Config.Events.MaxOpen`               | `5`            | open events at the same time                        |
| `Config.Events.KnockoutSizes`         | `4, 8, 16`     | field sizes for knockout tournaments                |
| `Config.Events.MinRaces` / `MaxRaces` | `2` / `10`     | races per championship                              |

#### Ghost, tires, drift, drag

| Option                                       | Default                                   | Description                                                      |
| -------------------------------------------- | ----------------------------------------- | ---------------------------------------------------------------- |
| `Config.Ghost`                               | interval `100` ms, max. 15 min            | ghost recording, transparency `Alpha = 120`                      |
| `Config.IdealLine`                           | `Ahead = 120.0`                           | meters of ideal line ahead of the car                            |
| `Config.Tires.WearPerKm`                     | `4.0`                                     | % wear per km (× `SlipFactor 3.0` for slip, drift, hard braking) |
| `Config.Tires.GripLossStart` / `MaxGripLoss` | `40` / `0.18`                             | less grip from 40 % wear, max. −18 %                             |
| `Config.Tires.PitTime`                       | `6`                                       | seconds for a tire change in the box                             |
| `Config.Drift`                               | angle `12°`, speed `8 m/s`, combo `2.5 s` | drift scoring                                                    |
| `Config.Drag.Distances`                      | `201, 402`                                | common drag distances (m)                                        |

#### Tracks, editor, blips, HUD

| Option                               | Default                            | Description                                                               |
| ------------------------------------ | ---------------------------------- | ------------------------------------------------------------------------- |
| `Config.Tracks.InstallDefaults`      | `true`                             | install the 4 default tracks on first start (only if no track exists yet) |
| `Config.Tracks.AdminAutoApprove`     | `true`                             | admin tracks approved instantly                                           |
| `Config.Tracks.MaxCheckpoints`       | `120`                              | checkpoints per track                                                     |
| `Config.Tracks.MaxPerCreator`        | `10`                               | tracks per creator (admins unlimited)                                     |
| `Config.Tracks.SnapToRoad`           | `true`                             | snap checkpoints to the road                                              |
| `Config.Tracks.RecordSpacing`        | `60.0`                             | record mode: a checkpoint every N meters                                  |
| `Config.Tracks.DefaultWidth`         | `14.0`                             | default width of new checkpoints (m)                                      |
| `Config.Keys`                        | E, Backspace, G, H, R, F, Enter, X | editor keys (GTA control IDs)                                             |
| `Config.Blips` / `Config.Checkpoint` | –                                  | blips, checkpoint types and colors (club red, underground magenta)        |
| `Config.Hud.Units`                   | `'kmh'`                            | `kmh` or `mph`                                                            |
| `Config.Hud.Draggable`               | `true`                             | players may move the race HUD                                             |

#### Vehicles (`config/vehicles.lua`)

The script calculates the class from top speed, acceleration, braking and traction **incl. tuning** (performance index PI 100–999: D < 400 ≤ C < 500 ≤ B < 600 ≤ A < 700 ≤ S < 800 ≤ X).

```lua
Config.VehicleClasses = { ['zentorno'] = 'S', ['bmx'] = 'D' }        -- fixed class per model
Config.BlockedModels = { 'oppressor2', 'deluxo', 'rhino' }            -- never allowed
Config.BlockedVehicleClasses = { 14, 15, 16, 21 }                     -- boats, helicopters, planes, trains
```

#### Webhooks (`config/server.lua`)

| Key        | Content                                                   |
| ---------- | --------------------------------------------------------- |
| `results`  | official club results, track records, events, season end  |
| `tracks`   | submitted and reviewed tracks                             |
| `illegal`  | underground results and events, police alerts, pink slips |
| `security` | steward suspicion reports                                 |

Empty URL = off. Webhooks only contain aliases, never player identifiers.

#### Customizing texts

All texts live in `locales/de/*.json` and `locales/en/*.json` (`core`, `race`, `ui`, `admin`). For a new language copy the `en` folder, translate it and set `Config.Locale`.

### Gameplay

#### The racing tablet

The **Racing Tablet** item opens the tablet (with prop and animation). At the top you switch between the two worlds:

|           | 🏁 Club (legal)                         | 🌃 Underground                                     |
| --------- | --------------------------------------- | -------------------------------------------------- |
| Look      | bright, timing screen, signal red       | dark, neon magenta and cyan                        |
| Name      | player name / racer license             | racer alias                                        |
| Money     | bank account                            | dirty money (QBCore/Qbox: cash)                    |
| Race list | track, start time, entrants             | district and time only                             |
| Result    | provisional → protest window → official | official right away                                |
| Extras    | race control, protests, sponsor bonus   | meetup, scene heat, police, street rep, pink slips |

Sections: **Home** (profile card, next races, season countdown, crew, rewards), **Races**, **Create**, **Tracks**, **Leaderboards**, **Events**, **Crew**, **Profile** – with permissions also **Race Control** and **Admin**.

Police jobs (`Config.Illegal.HiddenForJobs`) never see the underground. If `Config.Illegal.AccessItem` is set, players also need the **Underground Stick**.

#### The 6 modes

| Mode            | Track             | Scoring                                                         |
| --------------- | ----------------- | --------------------------------------------------------------- |
| **Sprint**      | A → B             | time                                                            |
| **Circuit**     | loop, 1–50 laps   | time, best lap                                                  |
| **Elimination** | loop, 2+ laps     | the last racer of every lap is out                              |
| **Drag**        | straight, 2 lanes | reaction time, ET, trap speed – jump start = red light          |
| **Drift**       | any track         | drift points from angle × speed × combo                         |
| **Time trial**  | any track, solo   | time against the ghost, leaderboard (does not count for rating) |

#### Creating a race

Permission `createRace` (default: admins or the **Race Director License** item). Tablet → **Create**:

1. **Mode & track** – only approved tracks that fit the mode and the world
2. **Rules** – laps, class limit (D/C/B/A/S/X/open), max racers (2–16), collisions or phasing, ghost, ideal line, tires & pit stops (circuit with 3+ laps)
3. **Stakes** – entry fee (up to 50,000), prize split winner / podium / top 5, betting on/off, optional pink slip in the underground
4. **Start** – now (started by the organizer) or in 2, 5, 10, 15 or 30 minutes, optionally private with a code

#### How a race works

{% stepper %}
{% step %}
**Join**

Players get behind the wheel and join in the tablet. The server checks class, blocked models and the entry fee. Spectators can bet on racers until the start lights (if betting is on).
{% endstep %}

{% step %}
**Meetup (underground only)**

120 s before the start the meetup is revealed via GPS – until then everyone only knows district and time.
{% endstep %}

{% step %}
**Starting grid**

The entry fee is charged and every racer gets a **grid slot** (by rating, sign-up or random) with marker and GPS. 90 s to get there – no-shows are **did not start (DNS)** and get their fee back.
{% endstep %}

{% step %}
**Start lights**

Circuit, sprint & co.: **5 red lights**, then a random pause until "lights out" – vehicles are frozen until then. Drag: **christmas tree** (yellow – yellow – yellow – green), not frozen – rolling more than 0.5 m before green means red.
{% endstep %}

{% step %}
**Race**

Checkpoints must be passed in order. The **steward** warns after 1.5 s off track and gives a 5 s time penalty after 3 s. Leaving the vehicle for more than 15 s = **did not finish (DNF)**.
{% endstep %}

{% step %}
**Finish & result**

After the first racer finishes, everyone else has 120 s. If two racers are less than 0.1 s apart, they get a **photo finish** flag. The result screen shows podium, times, penalties, rating change and prize money.
{% endstep %}

{% step %}
**Protest & official result (club)**

The result is **provisional** at first. For 120 s every racer can file a **protest** against another (contact, cutting, blocking, unsportsmanlike behavior). Race control decides – after that, or when the window expires, the result becomes **official**. Only then are prize money, bet payouts, rating and season points paid out.
{% endstep %}
{% endstepper %}

{% hint style="info" %}
**Money is safe:** a red flag, too few racers on the grid or a resource restart refund entry fees and bets immediately.
{% endhint %}

#### The race HUD

| Element           | Content                                                                                                                                   |
| ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| **Timing**        | positions, gaps, crew colors, penalties                                                                                                   |
| **Time & delta**  | lap, total and lap time, best lap, **live delta to your best**, sector times **purple** (record) / **green** (personal best) / **yellow** |
| **Mini map**      | track layout with all racers                                                                                                              |
| **Speed & tires** | speed (km/h or mph), tire wear and grip                                                                                                   |
| **Drift meter**   | drift points and combo (drift mode)                                                                                                       |

Plus banners (race control, shortcut, penalty, police), the big start lights and checkpoint arrows. **Customise HUD** (tablet → Profile): drag the elements, they snap to a grid – saved per player.

#### Ghost, ideal line, tires

* **Ghost:** your personal best or the track record drives along as a semi-transparent vehicle without collision. In time trials you pick in the track view: none, my PB or record.
* **Ideal line:** the line of the record lap runs 120 m ahead of your car.
* **Tires & pit stops:** on circuits with 3+ laps tires wear (faster when drifting, slipping or braking hard). From 40 % wear grip drops. Stop in the pit box → 6 s tire change.

#### Performance classes

Every vehicle gets a performance index (PI 100–999) from top speed, acceleration, braking and traction – **incl. tuning**. That gives the class D, C, B, A, S or X. The tablet shows your class before you join.

#### Underground

* **Scene heat:** every district has a heat value from 0 to 100. Every race adds 18, it decays by 1 per minute. From 60 the tablet warns: "The scene is being watched".
* **Police alert:** rolled at the start – 15 % plus heat × 0.6 %, max. 85 %. Police get an alert with a blip (via your dispatch system or built in).
* **Street rep:** +25 for a win, +10 for P2–3, plus rep from jobs – its own "Street" leaderboard and 6 tiers with unlocks (see below).
* **Pink slips** (only if the server enabled them): 1 vs 1, both bet their current own vehicle, double confirmation – the winner gets the loser's vehicle.

#### Underground career: jobs & street tiers

The underground tablet has a **Jobs** tab with 3 offers – difficulty, time limit and reward (dirty money + street rep). Accept one and the target plus GPS appear on the map; a panel at the top right shows the goal, time limit and progress. A taken slot is refilled after a few minutes, **Reroll** swaps all offers for some dirty money.

| Job                 | From tier | What to do                                                                                                                       |
| ------------------- | --------- | -------------------------------------------------------------------------------------------------------------------------------- |
| **Courier run**     | Newcomer  | Pick up a package (stop inside the circle) and deliver it against the clock. Damage to the car costs reward.                     |
| **Speed trap hunt** | Known     | Pass 4 speed traps at minimum speed, any order. The traps sit on the straights of your tracks.                                   |
| **Drift trail**     | Known     | Score a drift target in an open zone (airfield, runway, quarry …).                                                               |
| **Lose the heat**   | Respected | From the meeting point a search area follows you. Get out of the circle and stay out long enough. Often real police get alerted. |
| **Rival duel**      | Feared    | Time trial against the best time **and ghost** of a real driver. Win and your rival loses street rep.                            |

Hard jobs unlock at **Kingpin** with a much bigger reward. Failing or cancelling a started job costs a few points of street rep (cancelling before the meeting point is free).

**Street tiers:** street rep comes from underground wins, podiums and jobs. It climbs through 6 tiers – Newcomer, Known, Respected, Feared, Kingpin, Legend. Every tier unlocks something: new job types, higher bets, pink slips, races only for drivers from a certain tier and a reward bonus. The tablet shows the ladder with all unlocks.

#### Betting

Spectators (and racers on themselves) bet on a racer until the start. All stakes go into one pot (**pari-mutuel**), odds change live. Payout comes with the official result – if nobody bet on the winner, all stakes are refunded.

#### Rating, ranks and badges

* **Racer rating** (Elo, start 1000): beating stronger opponents earns more. Time trials do not count.
* **6 ranks:** Rookie, Amateur, Semi-Pro, Pro, Elite, Legend.
* **Profile:** stats, rating history, recent races, best times and **11 badges** (e.g. first win, clean sheet, marathon, pink slip king, legend).
* **Leaderboards:** season, all-time, street (street rep) and crews.

#### Crews

In the club they are called **teams**, in the underground **crews**. Founding costs 25,000: name, tag (2–4 characters), one of 12 colors, one of 12 emblems, motto. Roles boss, officer, member – up to 20 members, invite by alias or by server ID nearby. **Crew rating** is the average of the 5 best racers, plus a separate crew season ranking.

#### Season

A season lasts 30 days. Every rated race gives season points (25-18-15-12-10-8-6-4-2-1). At season end the top 10 get rewards – claimable in the tablet, even if they were offline at season end. Ratings get a soft reset and the next season starts automatically.

#### Events

Permission `createRace`. Tablet → **Events**:

* **Knockout tournament:** 4, 8 or 16 racers, 1-vs-1 heats (sprint, circuit or drag), bracket as a graphic.
* **Championship:** 2–10 races (sprint, circuit, elimination or drift), points table 25-18-15-…

The organizer creates the next race with **Next match / Next race** – entrants are notified.

#### Broadcast overlay

While a race is running, pick **Spectate** in the race view: the tablet closes and a large timing tower with a lap counter sits on top of the screen – made for streamers and commentators. Turn it off in the tablet.

### Commands & Exports

#### Commands

Pepper Racing needs **no** chat command – the tablet opens via the `racing_tablet` item.

| Command                                                       | Default                              | Function                                                               |
| ------------------------------------------------------------- | ------------------------------------ | ---------------------------------------------------------------------- |
| `Config.Command`                                              | off (`false`)                        | e.g. `'racing'` → `/racing` opens the tablet **without** the item      |
| `/racingrep <ID> <+/-amount>` · `/racingrep <ID> set <value>` | on (`Config.StreetRep.AdminCommand`) | admins/console only: change or set a player's street rep (since 1.2.0) |

Admin tasks (track approval, season, locking tracks) live in the tablet's admin area, not in commands.

#### Keys

| Where  | Key                   | Function                      |
| ------ | --------------------- | ----------------------------- |
| Editor | `E`                   | place checkpoint              |
| Editor | `Backspace`           | remove last checkpoint        |
| Editor | Mouse wheel / `←` `→` | change width                  |
| Editor | `G`                   | grid slot                     |
| Editor | `H`                   | pit lane (entry → box → exit) |
| Editor | `R`                   | record mode                   |
| Editor | `F`                   | camera preview                |
| Editor | `Enter`               | save                          |
| Editor | `X`                   | cancel                        |

Change in `Config.Keys` (GTA control IDs: `Place = 38, Remove = 177, Grid = 47, Pit = 74, Record = 45, Preview = 23, Save = 191, Exit = 73`).

#### Permissions (ACE)

```cfg
add_ace group.admin pepper_racing.admin allow          # every permission
add_ace group.mod pepper_racing.createRace allow       # create races and events
add_ace group.mod pepper_racing.createTrack allow      # build tracks
add_ace group.mod pepper_racing.approveTrack allow     # track approval
add_ace group.mod pepper_racing.control allow          # race control for all races
```

Alternatively via groups, jobs with a minimum grade, items or `everyone = true` – see **Configuration**.

#### Exports (server)

All exports are **read-only** – on purpose there is no export that lets other resources change money, rating or results.

| Export                                   | Returns                                                                     |
| ---------------------------------------- | --------------------------------------------------------------------------- |
| `exports.pepper_racing:getProfile(src)`  | public racer profile (pid, alias, rating, rank, stats, crew) or `nil`       |
| `exports.pepper_racing:isRacing(src)`    | `true` if the player is on the grid, in the light sequence or racing        |
| `exports.pepper_racing:getActiveRaces()` | list of active races (id, area, mode, track, state, racers, entry fee, pot) |

Example – block a phone or emergency call during a race:

```lua
if exports.pepper_racing:isRacing(source) then
    return -- player is racing right now
end
```

#### Webhooks

In `config/server.lua` (`''` = off):

```lua
ServerConfig.Webhooks = {
    results = '',  -- official results (podium, records), events, season end
    tracks = '',   -- submitted/reviewed tracks
    illegal = '',  -- underground: results, police alerts, pink slips
    security = '', -- steward suspicion reports
}
ServerConfig.WebhookName = 'Pepper Racing'
```

Webhooks only contain aliases, never player identifiers. Never share webhook URLs publicly.

#### Dispatch

`Config.Police.Dispatch` in `config/config.lua`:

| Value                                                                                    | Behavior                                                                                                                              |
| ---------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| `'auto'` (default)                                                                       | first running integration in this order: ps-dispatch, cd\_dispatch, qs-dispatch, rcore\_dispatch, core\_dispatch – otherwise built in |
| `'ps-dispatch'`, `'cd_dispatch'`, `'qs-dispatch'`, `'rcore_dispatch'`, `'core_dispatch'` | exactly this integration (not running → built in)                                                                                     |
| `'builtin'`                                                                              | built-in alert: notification + blip for every player with a job from `Config.Police.Jobs`                                             |
| `false`                                                                                  | no police alert                                                                                                                       |

The alert uses code `10-94` and stays visible for `Config.Police.BlipTime` seconds. Wire up your own system in `bridge/server/dispatch.lua` (open).

#### Bridges (open)

| File                                                                | Purpose                                                                          |
| ------------------------------------------------------------------- | -------------------------------------------------------------------------------- |
| `bridge/detect.lua`                                                 | framework detection                                                              |
| `bridge/server/esx.lua`, `qbcore.lua`, `qbox.lua`, `standalone.lua` | money, job, identifier, character switch                                         |
| `bridge/server/inventory.lua`                                       | make items usable, check, add, remove (ox\_inventory, qb-/ps-/lj-inventory, ESX) |
| `bridge/server/vehicles.lua`                                        | check/transfer vehicle ownership (pink slips), key hook                          |
| `bridge/server/dispatch.lua`                                        | police alert                                                                     |
| `bridge/client/frameworks.lua`                                      | job and notifications on the client                                              |

### Race Control & Editor

#### Race control

Race control is an **RP role**: whoever has the `control` permission runs all races – the organizer of a race always runs their own race. Tablet → **Race Control**.

| Area             | Content                                                                                                                     |
| ---------------- | --------------------------------------------------------------------------------------------------------------------------- |
| **Live map**     | the track with all racers in real time                                                                                      |
| **Live timing**  | positions, gaps, laps, penalties – click a racer to act                                                                     |
| **Incident log** | everything that happens: shortcuts, jump starts, penalties, retirements – marked as "steward" (automatic) or "race control" |
| **Protests**     | incoming protests with reason, description and deadline                                                                     |

**Tools**

| Action                      | Effect                                                                                                                                                      |
| --------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Time penalty**            | +5 s, +10 s or +30 s for a racer, with a reason                                                                                                             |
| **Disqualify**              | the racer is classified as DSQ                                                                                                                              |
| **Announcement**            | text (max. 120 characters) as a banner for all racers – presets: "Yellow flag – no overtaking!", "Car on track – caution!", "Track clear – racing resumes!" |
| **Red flag**                | abort the race immediately – entry fees and bets are refunded (hold to confirm)                                                                             |
| **Declare result official** | open protests expire, prize money, bets and rating are paid out                                                                                             |

Every action is written to the incident log and shown to racers as a banner.

#### Steward (automatic)

The steward works in every race, even without race control:

* **Corridor:** there is a corridor around the track (checkpoint width × 2.5, at least 35 m). Leaving it triggers a warning after 1.5 s and a **5 s time penalty** after 3 s – max. one per track section.
* **Order:** checkpoints only count in the right order.
* **Server-side plausibility:** position at the checkpoint, minimum time between two checkpoints, client clock drift, unrealistic drag times and drift points. 2 violations: disqualification. Suspicion reports appear in the admin area ("Steward log") and optionally in the `security` webhook.
* **Jump start (drag):** rolling more than 0.5 m before green means red – and the heat is lost.

#### Protests (club only)

1. After the race the result is **provisional**.
2. For 120 s (`Config.Protest.Window`) every racer can **file a protest** on the result screen: against whom, reason (contact, cutting, blocking, unsportsmanlike behavior) and a short description.
3. Race control and the organizer are notified and decide: **reject**, **time penalty** or **disqualification**.
4. After the decision (or when the window expires) the result becomes **official** – only then are prize money, bet payouts, rating and season points paid out.

If no race control is online, the result becomes official automatically after the window. Underground races are always official right away.

#### Track editor

Permission `createTrack`. Tablet → **Tracks → New track**: pick a name, type and area, then **Open editor**. The editor starts at your position.

| Key                   | Function                                                              |
| --------------------- | --------------------------------------------------------------------- |
| `E`                   | place checkpoint                                                      |
| `Backspace`           | remove last checkpoint                                                |
| Mouse wheel / `←` `→` | width of the next checkpoint (6–40 m)                                 |
| `G`                   | grid slot at your current vehicle position (max. 16)                  |
| `H`                   | pit lane: 1× entry, 2× box, 3× exit (circuits only)                   |
| `R`                   | record mode on/off – drive the track, a checkpoint appears every 60 m |
| `F`                   | camera preview                                                        |
| `Enter`               | save (with confirmation)                                              |
| `X`                   | cancel                                                                |

Change the keys in `Config.Keys`. Checkpoints can snap to the middle of the road (`Config.Tracks.SnapToRoad`). An info panel shows checkpoint count, length, width and mode.

**Track types**

| Type        | Rules                                                                                 |
| ----------- | ------------------------------------------------------------------------------------- |
| **Circuit** | checkpoint 1 is start and finish, min. 3 checkpoints, optional pit lane               |
| **Sprint**  | the last checkpoint is the finish                                                     |
| **Drag**    | exactly 2 checkpoints (start and finish line), 2 grid slots side by side, max. 1000 m |
| **Drift**   | any layout, scored by drift points                                                    |

Every track needs at least one grid slot, at least 100 m length and at most 120 checkpoints. Area: **club**, **underground** or **both**. Creators without admin rights can own up to 10 tracks.

**Tips**

* Place grid slots staggered in pairs – like a real starting grid.
* Use **record mode** for long tracks and fix single checkpoints afterwards.
* Watch the **preview** before saving – track approval sees exactly this camera run.

#### Track approval

Tracks by players without admin rights are **"Awaiting approval"** after saving. Players with the `approveTrack` permission find them in the tablet under **Admin → Track approval**:

* play the **camera preview** or set the start as a **waypoint** and drive it yourself
* **Approve** (optional comment) or **Reject** (reason required)
* the creator is notified, optionally the `tracks` webhook gets a message

Admin tracks are approved instantly (`Config.Tracks.AdminAutoApprove`). Under **Admin → Manage tracks** you can lock, unlock and delete tracks.

#### Admin area

| Area           | Content                                                                                          |
| -------------- | ------------------------------------------------------------------------------------------------ |
| Overview       | racer profiles, tracks, pending approvals, active races, crews, racers online                    |
| Track approval | see above                                                                                        |
| Season         | current season, **end season now** (rewards + soft reset), **start a new season** (name, length) |
| Tracks         | change the status of every track                                                                 |
| Steward log    | suspicion reports                                                                                |

### FAQ

#### Troubleshooting

| Problem                                     | Solution                                                                                                                                                                                      |
| ------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Tablet does not open                        | Item added? With ox\_inventory `server = { export = 'pepper_racing.racing_tablet' }` must be in the item. Do not rename the folder. Start framework and inventory **before** `pepper_racing`. |
| Item only shows its internal name           | Add the item file from `install/` to your inventory (see **Installation**).                                                                                                                   |
| "Timing is still starting up"               | Database not reachable – start `oxmysql` before `pepper_racing`, check the console. Without CREATE permission import `install/pepper_racing.sql`.                                             |
| "You do not have permission for this."      | Grant the permission in `Config.Permissions` or `add_ace group.admin pepper_racing.admin allow`.                                                                                              |
| "No matching track"                         | No approved track for this mode and world yet – build or approve one. Drag needs a drag track.                                                                                                |
| Underground missing in the tablet           | Your job is in `Config.Illegal.HiddenForJobs`, or `AccessItem` is set and the item is missing.                                                                                                |
| "Did not start (DNS)"                       | Not on the grid slot within 90 s. Raise `Config.Grid.Time` or set `Config.Grid.Teleport = true`.                                                                                              |
| "This vehicle is not allowed in races."     | The model is in `Config.BlockedModels` or its GTA class in `Config.BlockedVehicleClasses`.                                                                                                    |
| Vehicle lands in the wrong class            | Add a fixed class for the model in `Config.VehicleClasses`.                                                                                                                                   |
| Underground entry fee missing (QBCore/Qbox) | `Config.DirtyMoney` uses cash (`cash`) there – or set your own account.                                                                                                                       |
| Pink slip cannot be selected                | Set `ServerConfig.PinkSlips.Enabled = true`. If the console says the table was not found, set `Table` accordingly.                                                                            |
| Police get no alert                         | Check `Config.Police.Jobs` and `Config.Police.Dispatch` – alerts are based on a chance (15 % + heat).                                                                                         |
| Result stays "provisional"                  | Normal in the club: 120 s protest window. Race control can declare it official right away.                                                                                                    |

#### Questions

<details>

<summary>Are tracks included?</summary>

Yes, 4 tracks are included: Sandy Shores Short Loop, Grand Senora Loop (circuits), Sandy Shores Airfield Drag and LSIA Runway Drag (drag). They are installed on first start as long as no track exists yet (`install/default_tracks.json`, turn off with `Config.Tracks.InstallDefaults = false`). Build more tracks yourself in the editor – anywhere on the map, in a few minutes with record mode. Admin tracks are approved instantly.

</details>

<details>

<summary>Do I need addon vehicles?</summary>

No. Every vehicle – addon vehicles too – gets its class automatically from its own stats incl. tuning.

</details>

<details>

<summary>Who can create races?</summary>

By default admins and everyone with the **Race Director License** item (`race_license`). Change it in `Config.Permissions.createRace` – e.g. for a job or with `everyone = true` for all players.

</details>

<details>

<summary>Does race control have to be online?</summary>

No. The steward works automatically, and without a decision the result becomes official after the protest window. Race control is an RP bonus.

</details>

<details>

<summary>What happens on a server restart mid-race?</summary>

Running races are aborted, entry fees and bets are refunded immediately. Profiles, tracks, best times, ghosts, crews and seasons are stored in the database.

</details>

<details>

<summary>Are pink slips dangerous for my server economy?</summary>

Pink slips are **off by default**. If you enable them, vehicles change owners permanently – the server checks ownership and plate first, both racers confirm twice, and they only exist in the underground, 1 vs 1. Only enable them if it fits your rules.

</details>

<details>

<summary>Can the police see the underground?</summary>

No. Jobs from `Config.Illegal.HiddenForJobs` never see the underground. Police only learn about races through the police alert.

</details>

<details>

<summary>How does the rating work?</summary>

Elo rating starting at 1000: beating stronger opponents earns more points. Races with at least 2 racers count, time trials do not. At season end the distance to 1000 is halved.

</details>

<details>

<summary>Can I show mph instead of km/h?</summary>

Yes: `Config.Hud.Units = 'mph'`.

</details>

<details>

<summary>How do I switch to English?</summary>

`Config.Locale = 'en'` in `config/config.lua`. Use `install/ox_items_en.lua` for the items.

</details>

<details>

<summary>How do I show a race on stream?</summary>

While a race is running, pick **Spectate** in the race view – the broadcast overlay shows a large timing tower and the lap counter, without the tablet.

</details>

### Changelog

#### 1.2.0 – 2026-10-25

**Underground career**

* New **Jobs** tab in the underground tablet: courier run, speed trap hunt, drift trail, lose the heat and rival duel – rewards in dirty money + street rep
* **6 street tiers** (Newcomer to Legend) unlock jobs, hard jobs, higher bets, pink slips and a reward bonus
* Host underground races only from a certain tier
* **Dirty money as an item** (`Config.DirtyMoney.Item`, e.g. `markedbills`)
* Admin command `/racingrep`, webhooks for tier-ups and won rival duels
* New file `config/missions.lua`; underground bets limited by tier, pink slips from tier 3

#### 1.1.0 – 2026-10-02

**Track update**

* 4 tracks included: Sandy Shores Short Loop, Grand Senora Loop, Sandy Shores Airfield Drag, LSIA Runway Drag
* Installed automatically on first start (only if no track exists yet), can be turned off with `Config.Tracks.InstallDefaults`

#### 1.0.1 – 2026-10-02

**Bugfixes**

* Various fixes, improved stability

#### 1.0.0 – 2026-10-01

**First release**

* Racing tablet with two worlds: the bright Pepper Racing Club and the dark Underground
* 6 modes: sprint, circuit, elimination, drag, drift, time trial
* Starting grid with up to 16 slots, F1 start lights, drag christmas tree with jump-start detection
* Steward with shortcut detection and time penalties, server-side plausibility checks
* Race control as an RP role: live map, time penalties, disqualification, red flag, announcements
* Protests with provisional and official results
* Live HUD with delta, sector colors, mini map – freely movable
* Ghost, ideal line, tire wear with pit stops, photo finish
* Performance classes D–X from vehicle stats incl. tuning
* Underground with secret meetup, scene heat, police alerts (5 dispatch integrations + built in), street rep
* Betting (pari-mutuel), pink slips (off by default)
* Racer rating with 6 ranks, 11 badges, crews/teams, seasons with rewards
* Knockout tournaments with bracket and championships
* Track editor with record mode, pit lane and preview, track approval
* Broadcast overlay, Discord webhooks, server exports
* ESX Legacy, QBCore and Qbox · German and English
