> 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-poker.md).

# Pepper Poker

Texas Hold'em at freely placeable tables – in-game table editor, side pots, spectators, private games with a PIN, rake, stats and a leaderboard for ESX Legacy, QBCore and Qbox.

On most servers poker was a chat command or a slot-machine style minigame: press a button, read the result, done. With **Pepper Poker** your players sit down at a real table, buy in and play **no-limit Texas Hold'em** against each other – with blinds, side pots, all-ins and spectators at the table.

You place the tables yourself: walk to the spot, open `/pokeradmin`, hit **New table here** – no coordinates in a config file.

{% hint style="success" %}
**Get Pepper Poker:** [pepper-scripts.tebex.store](https://pepper-scripts.tebex.store)
{% 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

* **No-limit Texas Hold'em** for 2–8 players per table, up to 40 tables per server
* **In-game table editor** (`/pokeradmin`) – create, move, edit, enable/disable, delete, remove players from a table
* **Per-table settings** – name, seats, small/big blind, minimum and maximum buy-in, account, rake, PIN, spawn table and chairs
* **4 accounts** – cash, bank, dirty money or chips as an item (`poker_chips`)
* **Complete rules** – blinds, minimum raise, all-in, side pots, split pots, heads-up order, automatic runout when players are all-in
* **The server decides everything** – it shuffles, deals and calculates; other players' cards never leave the server before the showdown
* **Turn timer** – 25 s to act, then an automatic check or fold; after 2 timeouts in a row the player sits out
* **Rebuy, sit out, stand up** right at the table – your stack is paid out as soon as you stand up
* **Spectating** at every table (up to 12 spectators), **private tables** with a PIN (4–8 digits)
* **Rake** with a percentage, a cap and "no flop, no drop" – optionally paid to a company account
* **Money safety** – every stack is stored in the database; on disconnect, character switch, restart or crash it is paid out, or paid on the next login
* **Stats & leaderboard** (`/pokerstats`) – hands, win rate, biggest pot, won/lost, best hand
* **6 quick reactions** instead of free chat, a log of recent actions, a hint showing your current hand strength
* **Discord webhooks** for big pots and table changes, a hand log in the database, 2 server exports
* German & English, open config, locales and bridges

{% hint style="info" %}
**No tables are pre-installed.** An admin places them in game with `/pokeradmin` – it takes about a minute per table. That way tables end up exactly where your server needs them: in the casino, in a bar or in a back room.
{% endhint %}

{% hint style="warning" %}
**Play money only.** Pepper Poker is meant for in-game money. Do not connect it to real money or to currencies that can be bought with real money – Rockstar's and Cfx.re's rules forbid real-money gambling.
{% endhint %}

### At a glance

|                             |                                                                                                       |
| --------------------------- | ----------------------------------------------------------------------------------------------------- |
| **Version**                 | 1.1.0                                                                                                 |
| **Framework**               | ESX Legacy (`es_extended`), QBCore (`qb-core`) or Qbox (`qbx_core`) – detected automatically          |
| **FiveM server**            | build 7290 or newer, **OneSync** required                                                             |
| **Dependencies (required)** | [oxmysql](https://github.com/overextended/oxmysql), [ox\_lib](https://github.com/overextended/ox_lib) |
| **Optional**                | ox\_target (interaction at the table), ox\_inventory (chips as an item)                               |
| **Database**                | MySQL or MariaDB – tables are created automatically                                                   |
| **Languages**               | German, English                                                                                       |
| **Delivery**                | Cfx.re Asset Escrow (`config/`, `locales/`, `bridge/`, `install/` open)                               |

### Pages

* **Installation** – step by step to your first table
* **Configuration** – accounts, game flow, rake, table models, webhooks
* **Gameplay** – taking a seat, the table screen, rules, table management, stats
* **Commands & Exports** – commands, keys, permissions, exports
* **FAQ** – questions and troubleshooting
* **Changelog**

### Installation

Plan about **10–15 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                                                           | positions and distances are checked on the server   | yes         |
| **MySQL/MariaDB** + **oxmysql**                                               | tables, stored stacks, payouts, stats, hand log     | yes         |
| **ox\_lib**                                                                   | server calls and notifications                      | yes         |
| **ESX Legacy**, **QBCore** or **Qbox**                                        | characters, money, admin groups                     | exactly one |
| **ox\_target**                                                                | interact with the table via target instead of a key | no          |
| Inventory: **ox\_inventory**, **qb-inventory** (ps-/lj-) or the ESX inventory | only for tables using the "chips" account           | 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` and your framework.
{% endhint %}

#### Step 2 – Download and extract

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

The folder contains, among others, `config/` (`config.lua`, `server.lua`), `locales/`, `bridge/`, `install/` and `fxmanifest.lua`.

{% hint style="danger" %}
**Never rename the `pepper_poker` folder.** The interface and the exports 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 – server.cfg

Add Pepper Poker **after** all of its dependencies. The order:

1. `ensure oxmysql`
2. `ensure ox_lib`
3. `ensure es_extended` (or `qb-core` / `qbx_core`)
4. optional: `ensure ox_target` and your inventory
5. `ensure pepper_poker`

Grant the admin permission (the name is set in `config/server.lua`, `ServerConfig.AdminAce`):

```cfg
add_ace group.admin pepper_poker.admin allow
```

The framework groups from `Config.AdminGroups` (`admin`, `superadmin`, `god`) count as admins as well.

{% hint style="success" %}
**Checkpoint:** `ensure pepper_poker` sits in `server.cfg` below your framework, `oxmysql` and `ox_lib`.
{% endhint %}

#### Step 4 – Chips item (optional)

You **only** need this step if a table should use the **chips** account. Tables using cash, bank or dirty money need no item. 1 `poker_chips` item equals `Config.Chips.Value` play money (default: 1).

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

1. Open `install/ox_items.lua`.
2. Copy **only the entry** between `return {` and the last `}`.
3. Paste it into `ox_inventory/data/items.lua` **before the very last closing brace `}`**.

Image: put your own `poker_chips.png` into `ox_inventory/web/images/`.
{% endtab %}

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

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

Also applies to ps-inventory and lj-inventory. Image: `poker_chips.png` into `qb-inventory/html/images/`.
{% endtab %}

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

If your item has a different name, set it in `Config.Chips.Item`. The script does not ship an item image. The item labels in the install files are German ("Pokerchips") – change them if you like.

{% hint style="info" %}
Pepper Poker neither sells nor buys chips. How players get the item (shop, casino cashier, job) is up to your own resources.
{% endhint %}

#### Step 5 – Database

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

#### Step 6 – Check the config and start

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

* `Config.Locale = 'en'` (default is `'de'`)
* `Config.Framework = 'auto'` – detects Qbox, ESX and QBCore on its own
* `Config.Accounts` – which accounts can be picked in the editor (see **Configuration**)
* `Config.Rake` – the house cut per pot

Webhooks and the rake account live in `config/server.lua`. Then start the server.

{% hint style="success" %}
**Checkpoint:** the console shows `Pepper Poker 1.0.0 started (framework: esx, tables: 0)` – with your framework.
{% endhint %}

#### Step 7 – Create your first table

{% stepper %}
{% step %}
**Pick the spot**

In game, stand exactly where the **centre of the table** should be. Turn so that you face the direction where the **players should sit**. With the default half-round casino table the players sit in a half circle in front of you, with round tables all around.
{% endstep %}

{% step %}
**Open table management**

Type `/pokeradmin` and choose **New table here**.
{% endstep %}

{% step %}
**Fill in the values**

Name, seats (2–8), small and big blind, minimum and maximum buy-in, account. Rake and PIN can stay empty (empty = value from the config, or a public table).
{% endstep %}

{% step %}
**Table and chairs**

Leave **Spawn table** and **Spawn chairs** on if nothing stands at that spot yet. Turn them off if a table or chairs are already there (see below).
{% endstep %}

{% step %}
**Create**

**Create table** – the table appears for all players, with a blip and floating text.
{% endstep %}
{% endstepper %}

{% hint style="success" %}
**Checkpoint:** at the table you see "Open poker table" (target or `[E]`), the table screen opens, and after **Take seat** your character sits at the table.
{% endhint %}

**"Spawn table" and "Spawn chairs"**

| Toggle           | On                                                                 | Off                                                        |
| ---------------- | ------------------------------------------------------------------ | ---------------------------------------------------------- |
| **Spawn table**  | the script places a table model at the position                    | a table is already there (MLO, casino, your own furniture) |
| **Spawn chairs** | the script places one chair per seat in a circle around the centre | chairs are already there                                   |

The models are created locally and only when a player is nearby (`Config.Table.StreamDistance`). The script uses the first model from `Config.Table.Models` / `ChairModels` that exists in your game.

When you use existing furniture, stand in the middle of the existing table while creating it. Seat positions are always calculated as a circle around the centre – adjust `Config.Table.SeatRadius` until players sit on the existing chairs.

**If seats or chairs do not fit**

All values are in `config/config.lua` under `Config.Table` and apply to every table:

| Problem                                       | Setting                                                     |
| --------------------------------------------- | ----------------------------------------------------------- |
| Players float above the chair or sink into it | `SeatZ` (seat height above the ground, default `0.5`)       |
| Chairs are too high or too low                | `ChairZ` (height correction of the chair models)            |
| Table is too high or too low                  | `TableZ` (height correction of the table model)             |
| Chairs stand inside the table or too far away | `SeatRadius` (distance seat ↔ table centre, default `1.35`) |
| Chairs face the wrong way                     | `ChairHeadingOffset` (default `180.0`, otherwise `0.0`)     |
| Different table or chair model                | `Models` / `ChairModels` (the first existing model is used) |

After a change run `ensure pepper_poker` in the console. Running hands are aborted, all bets are returned and stacks are paid out.

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

### Configuration

| File                | Contents                                                                |
| ------------------- | ----------------------------------------------------------------------- |
| `config/config.lua` | all settings for client and server                                      |
| `config/server.lua` | admin ACE, webhooks, rake account, hand log – **never** sent to clients |

Times are in seconds, money is always a whole number. Blinds, buy-in, account, rake and PIN of a table are **not** set in the config but in game with `/pokeradmin` (see **Gameplay**).

#### Basics

| Option             | Default  | Meaning                                                                                          |
| ------------------ | -------- | ------------------------------------------------------------------------------------------------ |
| `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.Debug`     | `false`  | extra output in the console and F8                                                               |
| `Config.Currency`  | `'$'`    | currency symbol in the interface                                                                 |

#### Commands and permissions

| Option                  | Default                      | Meaning                                                                                           |
| ----------------------- | ---------------------------- | ------------------------------------------------------------------------------------------------- |
| `Config.Commands.Admin` | `'pokeradmin'`               | table management (admins only) – `''` = off                                                       |
| `Config.Commands.Stats` | `'pokerstats'`               | your stats + leaderboard – `''` = off                                                             |
| `Config.Commands.Leave` | `'pokerleave'`               | emergency: leave the table if the interface hangs – `''` = off                                    |
| `Config.Commands.Bot`   | `'pokerbot'`                 | add bots to your table or remove them (admins only, only with `Config.Bots.Enabled`) – `''` = off |
| `Config.AdminGroups`    | `admin`, `superadmin`, `god` | framework groups that count as admin                                                              |
| `ServerConfig.AdminAce` | `'pepper_poker.admin'`       | ACE permission for admins (in addition to the groups)                                             |

An admin is anyone with the ACE permission **or** one of the groups. This is checked on every server call.

#### Accounts and chips

Every table uses exactly one account. You pick it in the editor – the choices are the entries of `Config.Accounts`.

| Option               | Default                                | Meaning                                                                  |
| -------------------- | -------------------------------------- | ------------------------------------------------------------------------ |
| `Config.Accounts`    | `cash`, `bank`, `black_money`, `chips` | accounts selectable in the editor – remove what you do not want to offer |
| `Config.DirtyMoney`  | see below                              | what the `black_money` account maps to per framework                     |
| `Config.Chips.Item`  | `'poker_chips'`                        | item name for the `chips` account                                        |
| `Config.Chips.Value` | `1`                                    | 1 item = this much play money                                            |

| Account       | ESX                   | QBCore | Qbox   |
| ------------- | --------------------- | ------ | ------ |
| `cash`        | cash (`money`)        | `cash` | `cash` |
| `bank`        | `bank`                | `bank` | `bank` |
| `black_money` | `black_money` account | `cash` | `cash` |
| `chips`       | item                  | item   | item   |

The `black_money` row is the default from `Config.DirtyMoney`:

```lua
Config.DirtyMoney = { esx = 'black_money', qbcore = 'cash', qbox = 'cash', standalone = 'black_money' }
```

{% hint style="info" %}
**QBCore/Qbox:** by default dirty money is the same as cash there. Put your own money account into `Config.DirtyMoney` – or remove `'black_money'` from `Config.Accounts` so it cannot be picked in the editor.
{% endhint %}

**Chips tables:** if `Config.Chips.Value` is greater than 1, the minimum and maximum buy-in as well as every buy-in and rebuy must be a multiple of it. Payouts are made in whole items – a remainder below the chip value is paid in cash.

#### Game flow

| Option                         | Default | Meaning                                                                     |
| ------------------------------ | ------- | --------------------------------------------------------------------------- |
| `Config.Game.MinPlayers`       | `2`     | a hand starts once this many players with chips are seated                  |
| `Config.Game.StartDelay`       | `6`     | seconds until the next hand                                                 |
| `Config.Game.TurnTime`         | `25`    | seconds to act per turn                                                     |
| `Config.Game.ShowdownTime`     | `7`     | seconds the result stays on screen (at most 4 without a showdown)           |
| `Config.Game.TimeoutsToSitOut` | `2`     | this many timeouts in a row → the player sits out                           |
| `Config.Game.SitOutKick`       | `180`   | seconds of sitting out until the seat is freed (`0` = never)                |
| `Config.Game.BrokeKick`        | `45`    | seconds without chips until the seat is freed (`0` = never) – time to rebuy |
| `Config.Game.MaxSpectators`    | `12`    | spectators per table                                                        |
| `Config.Game.ShowFoldedCards`  | `false` | `true` = also show folded cards at the showdown                             |
| `Config.Game.AutoMuck`         | `true`  | losers do not show their cards at the showdown                              |
| `Config.Game.MaxDistance`      | `6.0`   | metres: how close to the table centre you must stand to take a seat         |

#### Rake

The rake is the house cut per pot.

| Option                     | Default | Meaning                                                                       |
| -------------------------- | ------- | ----------------------------------------------------------------------------- |
| `Config.Rake.Percent`      | `5`     | percent of the pot (`0` = off) – applies to every table without its own value |
| `Config.Rake.Cap`          | `5000`  | at most this much per pot (`0` = no cap)                                      |
| `Config.Rake.NoFlopNoDrop` | `true`  | no rake if the hand ends before the flop                                      |
| `ServerConfig.RakeAccount` | `nil`   | company account for the rake – `nil` = the money leaves circulation           |

* **Per table:** in the editor the **Rake in %** field overrides the percentage for that table (0 to 50, empty = value from the config). Cap and "no flop, no drop" always come from the config.
* **Calculation:** percent of the whole pot, rounded down to whole amounts, at most the cap. It is taken from the main pot.
* **Company account:** on ESX the rake goes to the shared account of `esx_addonaccount` (e.g. `'society_casino'`). On QBCore/Qbox it goes to `Renewed-Banking`, otherwise to `qb-banking`. If none of these resources is running, the amount is dropped.

#### Limits and defaults for the editor

| Option                                | Default                                             | Meaning                                                |
| ------------------------------------- | --------------------------------------------------- | ------------------------------------------------------ |
| `Config.Limits.MinSeats` / `MaxSeats` | `2` / `8`                                           | seats per table                                        |
| `Config.Limits.MinBlind` / `MaxBlind` | `1` / `1000000`                                     | allowed range for small and big blind                  |
| `Config.Limits.MinBuyinBB`            | `10`                                                | smallest buy-in in big blinds                          |
| `Config.Limits.MaxBuyinBB`            | `500`                                               | largest buy-in in big blinds                           |
| `Config.Limits.MaxTables`             | `40`                                                | tables per server                                      |
| `Config.TableDefaults`                | 6 seats, blinds 50/100, buy-in 2,000–10,000, `cash` | defaults for new tables (can be changed in the editor) |

The big blind must be greater than the small blind. The name needs 2 to 40 characters, the PIN 4 to 8 digits.

#### Table in the world

| Option                            | Default                                         | Meaning                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| --------------------------------- | ----------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Config.Table.Models`             | 6 entries, first `vw_prop_casino_3cardpoker_01` | table models. Each table uses the first entry whose model exists in the game and has enough seats. Default: 2–4 seats = casino table with 4 built-in stools, 5–8 seats = large table with chairs all around. An entry is a model name or a table: `model`, `maxSeats` = the model is used up to this many seats, `chairs` = number of built-in chairs (the script then creates none of its own), `arc` = arc of the seats in degrees (half-round table: 180), `heading` = rotation of the model, `radius` = distance seat ↔ table centre, `seatZ` = seat height, `chair` = chair model for this table only |
| `Config.Table.ChairModels`        | 3 models, first `vw_prop_casino_chair_01a`      | chair models, same rule                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| `Config.Table.SeatRadius`         | `1.35`                                          | distance seat ↔ table centre (metres)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| `Config.Table.SeatArc`            | `360.0`                                         | degrees the seats are spread over when the model has no value of its own: `360` = all around the table, `180` = half circle                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| `Config.Table.SeatSpacing`        | `0.68`                                          | minimum distance between two chairs on an arc (metres) – with many seats the chairs move outwards                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| `Config.Table.ChairGap`           | `0.55`                                          | tables without built-in chairs: distance chair centre ↔ table edge (metres). Chairs are placed around the table top based on the dimensions of the table model – larger = further away                                                                                                                                                                                                                                                                                                                                                                                                                     |
| `Config.Table.SeatZ`              | `0.5`                                           | seat height above the ground (for the sitting animation)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| `Config.Table.TableZ`             | `0.0`                                           | height correction of the table model                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| `Config.Table.ChairZ`             | `0.0`                                           | height correction of the chair models                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| `Config.Table.ChairHeadingOffset` | `180.0`                                         | rotation of the chair models (if they face the wrong way: `0.0`)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| `Config.Table.StreamDistance`     | `60.0`                                          | metres: table and chairs are created within this range                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| `Config.Table.Scenario`           | `'PROP_HUMAN_SEAT_CHAIR_MP_PLAYER'`             | sitting scenario of the character                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |

These values apply to every table. Whether a table creates models at all is set per table in the editor (**Spawn table**, **Spawn chairs**).

#### Interaction, label and blips

| Option                                   | Default             | Meaning                                                                  |
| ---------------------------------------- | ------------------- | ------------------------------------------------------------------------ |
| `Config.Interact.Mode`                   | `'auto'`            | `auto` = ox\_target if it is running, otherwise a key · `target` · `key` |
| `Config.Interact.Key`                    | `38`                | GTA control ID of the key (38 = E)                                       |
| `Config.Interact.Distance`               | `2.4`               | metres to the table centre                                               |
| `Config.Label.Enabled`                   | `true`              | floating text above the table (name, blinds, players)                    |
| `Config.Label.Distance`                  | `8.0`               | visibility range of the text in metres                                   |
| `Config.Label.Height`                    | `1.45`              | height of the text above the ground                                      |
| `Config.Blip.Enabled`                    | `true`              | map blip for every active table                                          |
| `Config.Blip.Sprite` / `Color` / `Scale` | `680` / `1` / `0.7` | look of the blip                                                         |

If ox\_target is not running, the script uses the key even in `target` mode.

#### Reactions, stats, interface

| Option                    | Default                                                     | Meaning                                                                        |
| ------------------------- | ----------------------------------------------------------- | ------------------------------------------------------------------------------ |
| `Config.Reactions`        | `nice_hand`, `good_game`, `thanks`, `wow`, `bluff`, `hurry` | quick reactions – texts in `locales/<language>/ui.json` under `ui.react_<key>` |
| `Config.Stats.Enabled`    | `true`                                                      | stats and leaderboard on/off                                                   |
| `Config.Stats.TopSize`    | `20`                                                        | leaderboard size (at most 100)                                                 |
| `Config.UI.FourColorDeck` | `false`                                                     | `true` = four-colour deck (clubs green, diamonds blue)                         |
| `Config.UI.Sounds`        | `true`                                                      | interface sounds                                                               |
| `Config.UI.ShowHandHint`  | `true`                                                      | show your own hand strength ("Two Pair")                                       |

#### Bots (for testing)

Computer-controlled players so you can test hands on your own. **Off** by default.

{% hint style="warning" %}
Bots play with chips that come from nowhere. Chips a real player wins from a bot are paid out as **real in-game money** when they stand up; chips lost to a bot disappear. The rake from such hands also goes to `ServerConfig.RakeAccount`. Leave bots off on live servers unless that is exactly what you want.
{% endhint %}

| Option                    | Default                  | Meaning                                                                |
| ------------------------- | ------------------------ | ---------------------------------------------------------------------- |
| `Config.Bots.Enabled`     | `false`                  | allow bots. Only admins can add them (table management or `/pokerbot`) |
| `Config.Bots.MaxPerTable` | `7`                      | at most this many bots per table                                       |
| `Config.Bots.ThinkMin`    | `1200`                   | shortest thinking time of a bot in milliseconds                        |
| `Config.Bots.ThinkMax`    | `3200`                   | longest thinking time of a bot in milliseconds                         |
| `Config.Bots.Names`       | `Bot Anna`, `Bot Ben`, … | display names (each name is used once per table)                       |

Bots start with 100 big blinds (within the table's buy-in range) and get new chips as soon as they are broke. A hand only starts if at least one real player takes part; when the last real player stands up, the bots disappear. Bots never show up in the stats or on the leaderboard.

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

| Option                          | Default          | Meaning                                                            |
| ------------------------------- | ---------------- | ------------------------------------------------------------------ |
| `ServerConfig.Webhooks.bigPots` | `''`             | Discord webhook for big pots (`''` = off)                          |
| `ServerConfig.Webhooks.admin`   | `''`             | Discord webhook: table created, changed, deleted                   |
| `ServerConfig.WebhookName`      | `'Pepper Poker'` | sender name in Discord                                             |
| `ServerConfig.BigPot`           | `50000`          | pots of this size or more are posted to `bigPots`                  |
| `ServerConfig.HandLogDays`      | `14`             | hand log: days after which entries are deleted (`0` = never store) |
| `ServerConfig.VersionCheck`     | `true`           | update notice in the server console – never downloads code         |

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

The **hand log** lives in the `pepper_poker_hands` table: table, hand number, pot, rake, board and winners. It is meant for disputes. Old entries are deleted when the resource starts.

{% hint style="info" %}
In version 1.0.0 no check address is set for `VersionCheck` yet – the option currently has no effect.
{% endhint %}

#### Customising texts

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

### Gameplay

#### Getting to the table

Every active table has a map blip and floating text with its name, blinds and player count (e.g. "Players 3/6"). Private tables also show "Private table (PIN)".

{% stepper %}
{% step %}
**Open the table**

At the table choose **Open poker table** – via ox\_target or with `[E]`, depending on `Config.Interact`.
{% endstep %}

{% step %}
**Watch**

The table screen opens and you start as a **spectator**. You see the board, pot, bets and the log – but no hidden cards. Up to 12 players can watch a table.
{% endstep %}

{% step %}
**Take a seat**

Click a free seat (**Take seat**). You have to stand within 6 m of the table centre.
{% endstep %}

{% step %}
**Buy-in**

Pick the amount in the dialog – with the slider, the input field or **Min**/**Max**. The range runs from the table's minimum to its maximum buy-in, limited by your balance on the table's account. The amount is charged right away.
{% endstep %}

{% step %}
**Play**

Your character sits down at the table. You are dealt in from the next hand. A hand starts as soon as 2 players with chips are seated.
{% endstep %}
{% endstepper %}

A character can only sit at one table at a time. While seated, weapons and attacks are blocked.

#### The table screen

| Area                  | Contents                                                                                                                          |
| --------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
| **Seats**             | name, stack, two cards (yours face up, others face down), current bet, last action, dealer button, small/big blind, "Sitting out" |
| **Centre**            | board with 5 card slots, pot, side pots, winners and hand name at the showdown                                                    |
| **Turn timer**        | runs at the seat of the player to act (default 25 s)                                                                              |
| **Action bar**        | **Fold**, **Check**/**Call** with the amount, **Bet**/**Raise** – only active when it is your turn                                |
| **Raise**             | slider, input field, plus/minus (1 big blind each), quick buttons **½ Pot**, **Pot**, **All-in**                                  |
| **Your hand**         | your current hand strength, e.g. "Two Pair" (can be turned off with `Config.UI.ShowHandHint`)                                     |
| **Log**               | the last 30 entries: blinds, actions, flop/turn/river, winners                                                                    |
| **Reactions**         | 6 quick reactions ("Nice hand", "Good game", "Thanks", "Wow!", "Bluff?", "Hurry up") – shown at your seat                         |
| **Header**            | table name, hand number, blinds, buy-in, account, number of spectators                                                            |
| **Buttons top right** | sound on/off, **Sit out**/**I'm back**, **Rebuy**, **Stand up**, close                                                            |

Only seated players can send reactions. There is deliberately no free text at the table.

#### Keys

The keys work on the table screen when it is your turn:

| Key     | Action                                                    |
| ------- | --------------------------------------------------------- |
| `F`     | fold                                                      |
| `C`     | check or call                                             |
| `R`     | jumps to the raise input field                            |
| `Enter` | confirms the raise (in the input field or on the slider)  |
| `ESC`   | leaves the raise field, otherwise: close the table screen |

**Close and ESC:** as a spectator this leaves the table. If you are seated, the script asks whether you want to stand up and cash out.

#### Private tables

If a table has a PIN (4–8 digits), the script asks for it when you open the table – for watching as well. After 5 wrong attempts the input is locked for 60 seconds. The admin sets the PIN in the editor; an empty field makes the table public.

#### Rules

The game is **no-limit Texas Hold'em**. The server shuffles, deals and calculates everything.

* **Button and blinds:** the dealer button moves on every hand. The player to its left posts the small blind, the next one the big blind. If a stack does not cover the blind, the player is all-in.
* **Heads-up (2 players):** the button posts the small blind, acts first before the flop and last after it.
* **Betting rounds:** preflop → flop (3 cards) → turn (1) → river (1) → showdown. The big blind has the option preflop.
* **Minimum raise:** a raise must be at least as big as the previous one, and at least one big blind. An all-in below the minimum raise does not reopen the betting for players who have already acted.
* **All-in and side pots:** an all-in player plays for the part of the pot they paid into. Side pots are created for the rest. Uncalled bets are returned.
* **Automatic runout:** if all players but at most one are all-in, the remaining cards are dealt right away.
* **Winning without a showdown:** if only one player is left, they win the pot. Their cards stay hidden.
* **Showdown:** winners show their cards. Losers do not (`Config.Game.AutoMuck`).
* **Split pot:** equal hands split the pot. An odd remainder goes to the first winner left of the button.
* **Hand ranking:** High Card, Pair, Two Pair, Three of a Kind, Straight, Flush, Full House, Four of a Kind, Straight Flush, Royal Flush. A-2-3-4-5 is the lowest straight.
* **Rake:** the house cut is taken from the pot at the end of the hand (see **Configuration**).

#### Time, sitting out and rebuys

* **Time is up:** the script checks for you if that is possible – otherwise it folds.
* **Automatic sit-out:** after 2 timeouts in a row you sit out. If you act yourself later in the same hand or press **I'm back**, you are in again.
* **Sit out:** with **Sit out** you are no longer dealt in from the next hand. You finish the current hand. After 180 seconds of sitting out your seat is freed – your stack is paid out.
* **Rebuy:** with **Rebuy** you top up your stack up to the table's maximum buy-in. The money is charged right away, the chips are added to your stack before the next hand.
* **Out of chips:** with no chips left you have 45 seconds to rebuy. After that the seat is freed.
* **Stand up:** you get your stack back immediately. If a hand is running, your cards are folded – chips already bet stay in the pot.

All times are in `Config.Game`.

#### Money safety

Every stack is also stored in the database. If the script cannot pay out directly, it records a pending payout – it is paid automatically the next time the character is loaded.

| Situation                                                | What happens                                                                                                                                                                |
| -------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Stand up**                                             | the stack is paid out immediately                                                                                                                                           |
| **Disconnect or game crash**                             | cards are folded, the stack is paid out on the next login. Exception: a player who is already all-in stays in the hand until it ends and receives their winnings afterwards |
| **Character switch**                                     | like a disconnect – the money goes to the character that sat at the table                                                                                                   |
| **Resource restart / server restart via txAdmin**        | running hands are aborted, all bets are returned, stacks are paid out directly                                                                                              |
| **Server crash**                                         | on the next start all stored stacks become pending payouts (as of the start of the hand)                                                                                    |
| **Table edited, moved or deleted**                       | the hand is aborted, bets are returned, everyone is paid out and stands up                                                                                                  |
| **Payout not possible** (e.g. inventory full with chips) | the amount stays pending – make room and log in again                                                                                                                       |

{% hint style="info" %}
Payouts always go to the table's account: cash table → cash, chips table → chip items.
{% endhint %}

#### Table management

`/pokeradmin` opens table management (admins only). It lists all tables with name, blinds, buy-in, account, player count and status.

| Action              | Effect                                                                            |
| ------------------- | --------------------------------------------------------------------------------- |
| **New table here**  | creates a table at your position – you face the side where the players should sit |
| **Edit table**      | name, seats, blinds, buy-in, account, rake, PIN, spawn table/chairs, active       |
| **Move here**       | saves the changes and moves the table to your position                            |
| **Active** off      | the table disappears for everyone (models, blip, text) but stays saved            |
| **Remove a player** | the player on the chosen seat stands up and gets their stack                      |
| **Delete**          | removes the table permanently                                                     |

{% hint style="warning" %}
Saving, moving and deleting abort a running hand at that table. All bets are returned, all players are paid out and stand up.
{% endhint %}

Fields in the editor:

| Field                          | Rule                                               |
| ------------------------------ | -------------------------------------------------- |
| **Name**                       | 2 to 40 characters                                 |
| **Seats**                      | 2 to 8                                             |
| **Small blind / Big blind**    | the big blind must be greater than the small blind |
| **Minimum / Maximum buy-in**   | 10 to 500 big blinds (`Config.Limits`)             |
| **Account for buy-ins**        | one of `Config.Accounts`                           |
| **Rake in %**                  | empty = value from the config                      |
| **PIN**                        | empty = public table, otherwise 4 to 8 digits      |
| **Spawn table / Spawn chairs** | off if furniture is already there                  |

#### Stats and leaderboard

`/pokerstats` shows your numbers and the leaderboard. Stats are counted per character.

* **Your numbers:** net result (winnings minus losses), hands played, hands won with win rate, biggest pot, total won, total lost, best hand
* **Leaderboard:** sortable by **Net**, **Won**, **Biggest pot** and **Hands** – 20 places by default

The leaderboard is recalculated at most once per minute. `Config.Stats.Enabled = false` turns both off.

### Commands & Exports

#### Commands

The names are set in `Config.Commands` – an empty string (`''`) disables a command.

| Command             | Who      | Purpose                                                                                                                                                                                                                                |
| ------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `/pokeradmin`       | admins   | opens table management: create, edit, move and delete tables, remove players from a table                                                                                                                                              |
| `/pokerstats`       | everyone | your stats and the leaderboard                                                                                                                                                                                                         |
| `/pokerleave`       | everyone | emergency: leave the table if the interface hangs – the stack is paid out                                                                                                                                                              |
| `/pokerbot [count]` | admins   | only with `Config.Bots.Enabled`: adds bots to the table you are seated at or watching (no number: one); `/pokerbot 0` removes all bots. With the table screen open, type it in the F8 console – or use the buttons in table management |

Nobody needs a command to play: the table opens through the interaction at the table.

#### Keys

| Where                | Key     | Action                                                                           |
| -------------------- | ------- | -------------------------------------------------------------------------------- |
| At the table (world) | `E`     | open the poker table (without ox\_target) – change it with `Config.Interact.Key` |
| Table screen         | `F`     | fold                                                                             |
| Table screen         | `C`     | check or call                                                                    |
| Table screen         | `R`     | jump to the raise input field                                                    |
| Table screen         | `Enter` | confirm the raise                                                                |
| Table screen         | `ESC`   | leave the raise field, or close the table screen                                 |

`F`, `C` and `R` only work when it is your turn.

#### Permissions

Pepper Poker has exactly one permission: **admin**. Admins may use table management.

```cfg
add_ace group.admin pepper_poker.admin allow
```

Anyone in a group from `Config.AdminGroups` (`admin`, `superadmin`, `god`) is an admin as well:

| Framework | What is checked                   |
| --------- | --------------------------------- |
| ESX       | the player's group                |
| QBCore    | the QBCore permission             |
| Qbox      | the ACE permission `group.<name>` |

The server re-checks the permission on **every** table management call. Whether `/pokeradmin` opens the panel at all is read by the client when the character loads – so log in again once after granting a new permission.

#### Exports (server)

Both exports are **read-only** – on purpose there is no export that lets other resources change money, stacks or cards.

| Export                                | Returns                                                                        |
| ------------------------------------- | ------------------------------------------------------------------------------ |
| `exports.pepper_poker:isPlaying(src)` | `true` while the player is seated at a poker table (spectating does not count) |
| `exports.pepper_poker:getTables()`    | list of all tables                                                             |

Example – block an action while someone is seated:

```lua
if exports.pepper_poker:isPlaying(source) then
    return -- player is sitting at a poker table
end
```

Example – print every table with its player count:

```lua
for _, t in ipairs(exports.pepper_poker:getTables()) do
    print(t.name, t.players .. '/' .. t.seats)
end
```

Fields per table from `getTables()`:

| Field                                  | Contents                                                         |
| -------------------------------------- | ---------------------------------------------------------------- |
| `id`, `name`                           | table ID and name                                                |
| `coords`, `heading`                    | position (`x`, `y`, `z`) and heading                             |
| `seats`, `players`                     | seats and currently occupied seats                               |
| `sb`, `bb`                             | small and big blind                                              |
| `minBuyin`, `maxBuyin`                 | buy-in range                                                     |
| `account`                              | `cash`, `bank`, `black_money` or `chips`                         |
| `private`                              | `true` if the table has a PIN (the PIN itself is never included) |
| `spawnTable`, `spawnChairs`, `enabled` | toggles from the editor                                          |

While Pepper Poker is still starting, `getTables()` returns an empty list.

#### Webhooks

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

| Key       | Contents                                                                                                               |
| --------- | ---------------------------------------------------------------------------------------------------------------------- |
| `bigPots` | pots of `ServerConfig.BigPot` or more (default 50,000): table, pot, winners with their hand, hand number, blinds, rake |
| `admin`   | table created, changed or deleted: admin, blinds, buy-in, seats, account                                               |

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

#### Bridges (open)

| File                                                                | Job                                                                            |
| ------------------------------------------------------------------- | ------------------------------------------------------------------------------ |
| `bridge/detect.lua`                                                 | framework detection                                                            |
| `bridge/server/esx.lua`, `qbcore.lua`, `qbox.lua`, `standalone.lua` | money, groups, identifier, character switch                                    |
| `bridge/server/inventory.lua`                                       | check, give and take the chips item (ox\_inventory, qb-/ps-/lj-inventory, ESX) |
| `bridge/client/frameworks.lua`                                      | notifications on the client                                                    |

### FAQ

{% hint style="warning" %}
**Play money only.** Pepper Poker is meant for in-game money. Do not connect it to real money or to currencies that can be bought with real money – Rockstar's and Cfx.re's rules forbid real-money gambling.
{% endhint %}

#### Troubleshooting

| Problem                                                       | Solution                                                                                                                                                                                       |
| ------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| No table anywhere                                             | No tables are pre-installed – create one with `/pokeradmin` → **New table here**. Is the table set to **Active** in the editor?                                                                |
| "You don't have permission to do that." on `/pokeradmin`      | Set `add_ace group.admin pepper_poker.admin allow` or assign a group from `Config.AdminGroups`. Then log in again. The message also appears if Pepper Poker did not start – check the console. |
| "Pepper Poker is still starting"                              | Database not reachable – start `oxmysql` before `pepper_poker`, check the console. Without CREATE permission import `install/pepper_poker.sql`.                                                |
| Console: "Config.Framework = 'auto', aber keines von … läuft" | Start the framework **before** `pepper_poker` in `server.cfg`. (Console warnings of the resource are in German.)                                                                               |
| Blip and text are there, but no table and no chairs           | Turn on **Spawn table** / **Spawn chairs** in the editor. If none of the models in `Config.Table.Models` / `ChairModels` exists in your game, nothing is created – enter a model that exists.  |
| Players float or sink into the chair                          | Adjust `Config.Table.SeatZ` (see **Installation**).                                                                                                                                            |
| Chairs face the wrong way                                     | Change `Config.Table.ChairHeadingOffset` from `180.0` to `0.0`.                                                                                                                                |
| Chairs stand inside the table or too far away                 | Adjust `Config.Table.ChairGap` (distance chair ↔ table edge). Without a spawned table `Config.Table.SeatRadius` applies. `/pokerdebug` in the F8 console shows model and seat positions.       |
| Only 4 players can sit at the casino table                    | The model has 4 built-in stools. Tables with 5–8 seats automatically get the large table with chairs all around (`Config.Table.Models`).                                                       |
| "You are too far away from the table."                        | Move closer to the table centre or raise `Config.Game.MaxDistance`.                                                                                                                            |
| "You do not have enough on you"                               | The money must be on the table's account (cash, bank, dirty money or chips). For chips tables the item must be registered.                                                                     |
| "The amount must be a multiple of …"                          | Chips table with `Config.Chips.Value` greater than 1 – pick a matching buy-in.                                                                                                                 |
| Chips item only shows its internal name                       | Add the item file from `install/` to your inventory (see **Installation**).                                                                                                                    |
| Interface hangs, player cannot leave the table                | `/pokerleave` – the player stands up and gets their stack.                                                                                                                                     |
| "… is still waiting for you – make room in your inventory"    | A pending payout in chips could not be given. Make room and log in again.                                                                                                                      |
| Rake does not arrive on the company account                   | Is `ServerConfig.RakeAccount` set? ESX needs `esx_addonaccount` and an existing shared account, QBCore/Qbox `Renewed-Banking` or `qb-banking`.                                                 |
| No target at the table                                        | `ox_target` is not running or `Config.Interact.Mode = 'key'` – then the `E` key is used.                                                                                                       |

#### Questions

<details>

<summary>Are tables included?</summary>

No, no tables are pre-installed. An admin places them in game: walk to the spot, `/pokeradmin`, **New table here**. It takes about a minute per table and needs no coordinates in a config file. The script can spawn the table and chair models for you.

</details>

<details>

<summary>Which money can be used?</summary>

Every table uses exactly one account: cash, bank, dirty money or chips as an item. `Config.Accounts` defines which accounts can be picked in the editor. On QBCore and Qbox dirty money maps to cash by default – change that in `Config.DirtyMoney`.

</details>

<details>

<summary>What happens to my chips when I disconnect or the server restarts?</summary>

Nothing is lost. Every stack is also stored in the database. On a disconnect your cards are folded and your stack is paid out automatically on your next login. On a resource restart running hands are aborted, all bets are returned and stacks are paid out. After a crash the server turns all stored stacks into pending payouts on its next start.

</details>

<details>

<summary>How does the rake work and where does it go?</summary>

The rake is a percentage of the pot (default 5 %), at most the cap (default 5,000). If the hand ends before the flop, no rake is taken by default ("no flop, no drop"). You can override the percentage per table. Without `ServerConfig.RakeAccount` the money leaves circulation. With an account it goes to `esx_addonaccount` (ESX) or to `Renewed-Banking` / `qb-banking` (QBCore/Qbox).

</details>

<details>

<summary>Can players see each other's cards? Is it cheat-safe?</summary>

The server shuffles, deals and calculates everything. Other players' cards are not sent to other players or spectators before the showdown – so there is nothing on the client to read out. Every action, every amount and every permission is checked on the server, and all calls are rate-limited.

</details>

<details>

<summary>Can I use existing casino furniture or MLOs?</summary>

Yes. Stand in the middle of the existing table while creating it and turn off **Spawn table** and – if chairs are there – **Spawn chairs** in the editor. The script calculates seat positions as a circle around the table centre. Use `Config.Table.SeatRadius` and `SeatZ` to match the existing chairs. These values apply to every table.

</details>

<details>

<summary>The chairs face the wrong way or players float – what do I change?</summary>

Everything is in `Config.Table`: `ChairHeadingOffset` rotates the chair models (`180.0` or `0.0`), `SeatZ` is the character's seat height, `ChairZ` and `TableZ` correct the height of the models, `SeatRadius` the distance to the table centre. The full table is in the **Installation**.

</details>

<details>

<summary>ox_target or a key?</summary>

Both work. With `Config.Interact.Mode = 'auto'` the script uses ox\_target if it is running, otherwise the `E` key with an on-screen prompt. `'key'` forces the key.

</details>

<details>

<summary>Is poker a gambling problem for my server?</summary>

Pepper Poker is meant for play money only. As long as players play for in-game money that cannot be bought with or exchanged for real money, it is a roleplay activity. Do not connect it to real money or paid currencies – Rockstar's and Cfx.re's rules forbid that. You are responsible for the rules on your own server.

</details>

<details>

<summary>How many tables and players are possible?</summary>

2 to 8 seats per table, plus up to 12 spectators. By default 40 tables per server are allowed (`Config.Limits.MaxTables`). A character can only sit at one table at a time.

</details>

<details>

<summary>Does it support tournaments?</summary>

No, not in version 1.0.0. The tables are cash tables: you buy in, can rebuy and can stand up at any time.

</details>

<details>

<summary>Can I translate Pepper Poker?</summary>

Yes. All texts are in `locales/de/` and `locales/en/` (`core.json`, `game.json`, `ui.json`) and are open. For a new language copy the `en` folder, translate it and set `Config.Locale`. If a text is missing, the script falls back to English.

</details>

<details>

<summary>Can I change the turn time or the blinds?</summary>

The turn time is `Config.Game.TurnTime` and applies to every table. Blinds, buy-in, account, rake and PIN are set per table in the editor (`/pokeradmin`).

</details>

<details>

<summary>Can an admin remove a player from a table?</summary>

Yes. Open the table in table management, choose **Remove a player** and pick the seat. The player stands up and gets their stack paid out.

</details>

<details>

<summary>How do updates work?</summary>

Download the new version from the [Cfx.re Portal](https://portal.cfx.re/assets/granted-assets) and replace the folder – back up `config/` and customised `locales/` first. Tables, stats and pending payouts live in the database and are kept. More: **Updates**.

</details>

### Changelog

#### 1.1.0 – 2026-10-04

**Added**

* Bots for testing (`Config.Bots`, off by default): admins add computer-controlled players to a table – in the table management or with `/pokerbot [count]`

**Fixed**

* Duplicate chairs at the casino table: the model has 4 built-in stools – the script no longer creates its own chairs there, players sit on the table's stools
* Chairs of earlier table settings stayed behind: old table and chair props are now removed reliably when a table is changed, deleted or on start
* Chairs stood halfway inside oblong tables: they are now placed around the table edge based on the dimensions of the table model
* Half-round casino table: players sit in a half circle on the player side instead of all around the table

**Changed**

* The table model depends on the number of seats: 2–4 seats = casino table with built-in stools, 5–8 seats = large table with chairs all around
* `Config.Table.Models` accepts `maxSeats`, `chairs`, `arc`, `heading`, `radius`, `seatZ` and `chair` per model; new `Config.Table.ChairGap` and `Config.Table.SeatSpacing`
* `/pokerdebug` (F8 console) lists the table model, seat positions and props at the nearest table

#### 1.0.1 – 2026-10-04

**Fixed**

* Black screen for all players after the resource started

#### 1.0.0 – 2026-10-04

**First release**

* Texas Hold'em (no-limit) at freely placeable tables for 2–8 players – ESX Legacy, QBCore and Qbox
* In-game table editor (`/pokeradmin`): create a table at your own position, move, edit, enable/disable, delete; remove players from a table
* Per-table settings: name, seats, small/big blind, minimum and maximum buy-in, account (cash, bank, dirty money or chips item), rake, PIN for private games, spawn table and chairs
* Complete rules: blinds, minimum raise, all-in, side pots, split pots, heads-up order, automatic runout when players are all-in, uncalled bets returned
* The server shuffles, deals and calculates everything – other players' cards never leave the server before the showdown
* Turn timer with automatic check/fold, automatic sit-out after timeouts; seats are freed after sitting out too long or having no chips
* Rebuy at the table, sit out, quick reactions, log of recent actions
* Spectating at every table (limited per table), private tables with a PIN
* Rake with a percentage, a cap and "no flop, no drop"; optional transfer to a company account (esx\_addonaccount, qb-banking, Renewed-Banking)
* Money safety: every stack is stored in the database; on disconnect, character switch, restart or crash it is paid out automatically, or paid the next time the character loads
* Stats per character (hands, hands won, biggest pot, won/lost, best hand) and a leaderboard (`/pokerstats`)
* Hand log in the database for disputes (retention configurable)
* Discord webhooks for big pots and table changes
* Optional chips item `poker_chips` (ox\_inventory, qb-inventory, ESX inventory)
* Server exports `isPlaying(src)` and `getTables()`
* German and English, all texts in `locales/` can be customised
