> 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/docs/de/activities/pepper-poker.md).

# Pepper Poker

Texas Hold'em an frei platzierbaren Tischen – Tisch-Editor im Spiel, Side-Pots, Zuschauer, private Runden mit PIN, Rake, Statistik und Bestenliste für ESX, QBCore und Qbox.

Poker war auf den meisten Servern ein Chat-Befehl oder ein Minispiel im Automaten-Stil: Knopf drücken, Ergebnis lesen, fertig. Mit **Pepper Poker** setzen sich deine Spieler an einen echten Tisch, kaufen sich ein und spielen **No-Limit Texas Hold'em** gegeneinander – mit Blinds, Side-Pots, All-ins und Zuschauern am Tisch.

Die Tische stellst du selbst auf: an die gewünschte Stelle gehen, `/pokeradmin` öffnen, **Neuer Tisch hier** – ohne Koordinaten in einer Config.

{% hint style="success" %}
**Pepper Poker holen:** [pepper-scripts.tebex.store](https://pepper-scripts.tebex.store)
{% endhint %}

{% hint style="info" %}
🧪 **Getestet auf unserem Dev-Server:** Wir testen alle Skripte selbstverständlich permanent auf unserem eigenen Dev-Server „Pepper Scripts“.
{% endhint %}

### Funktionen

* **No-Limit Texas Hold'em** für 2–8 Spieler pro Tisch, bis zu 40 Tische pro Server
* **Tisch-Editor im Spiel** (`/pokeradmin`) – anlegen, versetzen, ändern, ein-/ausschalten, löschen, Spieler vom Tisch nehmen
* **Je Tisch einstellbar** – Name, Plätze, Small/Big Blind, Mindest- und Höchst-Buy-in, Konto, Rake, PIN, Tisch und Stühle erzeugen
* **4 Konten** – Bargeld, Bankkonto, Schwarzgeld oder Chips als Item (`poker_chips`)
* **Vollständige Regeln** – Blinds, Mindest-Raise, All-in, Side-Pots, Split-Pots, Heads-up-Reihenfolge, automatisches Aufdecken bei All-in
* **Der Server entscheidet alles** – er mischt, gibt und rechnet; fremde Karten verlassen den Server erst am Showdown
* **Zug-Timer** – 25 s Bedenkzeit, danach automatisch Check oder Fold; nach 2 Zeitüberschreitungen in Folge setzt der Spieler aus
* **Nachkaufen, Aussetzen, Aufstehen** direkt am Tisch – der Stack wird beim Aufstehen sofort ausgezahlt
* **Zuschauen** an jedem Tisch (bis zu 12 Zuschauer), **private Tische** nur mit PIN (4–8 Ziffern)
* **Rake** mit Prozentsatz, Deckel und „No Flop, No Drop“ – optional an ein Firmenkonto
* **Geld-Sicherheit** – jeder Stack ist in der Datenbank gesichert; bei Disconnect, Charakterwechsel, Neustart oder Absturz wird ausgezahlt bzw. beim nächsten Einloggen nachgezahlt
* **Statistik & Bestenliste** (`/pokerstats`) – Hände, Gewinnquote, größter Pot, Gewinn/Verlust, beste Hand
* **6 Schnell-Reaktionen** statt freiem Chat, Protokoll der letzten Aktionen, Anzeige der eigenen Handstärke
* **Discord-Webhooks** für große Pots und Tisch-Änderungen, Hand-Protokoll in der Datenbank, 2 Server-Exports
* Deutsch & Englisch, Config, Sprachdateien und Bridges offen

{% hint style="info" %}
**Es sind keine Tische vorinstalliert.** Ein Admin stellt sie im Spiel mit `/pokeradmin` auf – das dauert etwa eine Minute pro Tisch. So stehen die Tische genau dort, wo dein Server sie braucht: im Casino, in einer Bar oder im Hinterzimmer.
{% endhint %}

{% hint style="warning" %}
**Nur für Spielgeld.** Pepper Poker ist für Ingame-Geld gedacht. Verbinde es nicht mit echtem Geld oder mit Währungen, die man für echtes Geld kaufen kann – die Regeln von Rockstar und Cfx.re verbieten Glücksspiel um echtes Geld.
{% endhint %}

### Auf einen Blick

|                              |                                                                                                       |
| ---------------------------- | ----------------------------------------------------------------------------------------------------- |
| **Version**                  | 1.1.0                                                                                                 |
| **Framework**                | ESX Legacy (`es_extended`), QBCore (`qb-core`) oder Qbox (`qbx_core`) – automatische Erkennung        |
| **FiveM-Server**             | Build 7290 oder neuer, **OneSync** erforderlich                                                       |
| **Abhängigkeiten (Pflicht)** | [oxmysql](https://github.com/overextended/oxmysql), [ox\_lib](https://github.com/overextended/ox_lib) |
| **Optional**                 | ox\_target (Interaktion am Tisch), ox\_inventory (Chips als Item)                                     |
| **Datenbank**                | MySQL oder MariaDB – Tabellen werden automatisch angelegt                                             |
| **Sprachen**                 | Deutsch, Englisch                                                                                     |
| **Auslieferung**             | Cfx.re Asset Escrow (`config/`, `locales/`, `bridge/`, `install/` offen)                              |

### Seiten

* **Installation** – Schritt für Schritt bis zum ersten Tisch
* **Konfiguration** – Konten, Spielablauf, Rake, Tisch-Modelle, Webhooks
* **Spielablauf** – Platz nehmen, Tischansicht, Regeln, Tisch-Verwaltung, Statistik
* **Befehle & Exports** – Befehle, Tasten, Rechte, Exports
* **FAQ** – Fragen und Fehlerbehebung
* **Changelog**

### Installation

Rechne mit etwa **10–15 Minuten**. Arbeite die Schritte in der angegebenen Reihenfolge ab – nach jedem Schritt gibt es einen **Kontrollpunkt**.

{% hint style="warning" %}
**Dateien immer mit einem Text-Editor öffnen**, zum Beispiel [Visual Studio Code](https://code.visualstudio.com/) oder [Notepad++](https://notepad-plus-plus.org/) – niemals mit Word oder WordPad.
{% endhint %}

#### Schritt 1 – Voraussetzungen prüfen

| Was                                                                       | Wozu                                                               | Pflicht?   |
| ------------------------------------------------------------------------- | ------------------------------------------------------------------ | ---------- |
| FiveM-Server **Build 7290 oder neuer**                                    | ältere Server starten das Script nicht                             | ja         |
| **OneSync** eingeschaltet                                                 | Positionen und Abstände werden am Server geprüft                   | ja         |
| **MySQL/MariaDB** + **oxmysql**                                           | Tische, gesicherte Stacks, Auszahlungen, Statistik, Hand-Protokoll | ja         |
| **ox\_lib**                                                               | Server-Aufrufe und Hinweise                                        | ja         |
| **ESX Legacy**, **QBCore** oder **Qbox**                                  | Charaktere, Geld, Admin-Gruppen                                    | genau eins |
| **ox\_target**                                                            | Interaktion am Tisch per Target statt Taste                        | nein       |
| Inventar: **ox\_inventory**, **qb-inventory** (ps-/lj-) oder ESX-Inventar | nur für Tische mit dem Konto „Chips“                               | nein       |

**OneSync:** in txAdmin unter **Settings → FXServer** auf **On** – ohne txAdmin `set onesync on` ganz oben in die `server.cfg`.

{% hint style="success" %}
**Kontrollpunkt:** Beim Serverstart steht für `oxmysql`, `ox_lib` und dein Framework jeweils `Started resource <name>` in der Konsole.
{% endhint %}

#### Schritt 2 – Herunterladen und entpacken

1. [Cfx.re-Portal → Granted Assets](https://portal.cfx.re/assets/granted-assets) öffnen und **pepper\_poker** herunterladen.
2. Den Ordner `pepper_poker` nach `resources/[pepper]/` kopieren – der Pfad ist dann `resources/[pepper]/pepper_poker`.

Im Ordner liegen unter anderem `config/` (`config.lua`, `server.lua`), `locales/`, `bridge/`, `install/` und die `fxmanifest.lua`.

{% hint style="danger" %}
**Den Ordnernamen `pepper_poker` nie ändern.** Oberfläche und Exports nutzen den Ressourcennamen.
{% endhint %}

{% hint style="warning" %}
**Asset Escrow:** Das Script startet nur auf einem Server, dessen Lizenzschlüssel (`sv_licenseKey`) zum selben Cfx.re-Konto gehört, mit dem du gekauft hast. Mehr dazu: **Asset Escrow**.
{% endhint %}

#### Schritt 3 – server.cfg

Trag Pepper Poker **nach** allen Abhängigkeiten ein. Die Reihenfolge:

1. `ensure oxmysql`
2. `ensure ox_lib`
3. `ensure es_extended` (bzw. `qb-core` oder `qbx_core`)
4. optional: `ensure ox_target` und dein Inventar
5. `ensure pepper_poker`

Admin-Recht vergeben (der Name steht in `config/server.lua` bei `ServerConfig.AdminAce`):

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

Zusätzlich gelten die Framework-Gruppen aus `Config.AdminGroups` (`admin`, `superadmin`, `god`) als Admins.

{% hint style="success" %}
**Kontrollpunkt:** `ensure pepper_poker` steht in der `server.cfg` unter Framework, `oxmysql` und `ox_lib`.
{% endhint %}

#### Schritt 4 – Chips-Item (optional)

Diesen Schritt brauchst du **nur**, wenn ein Tisch das Konto **Chips** nutzen soll. Tische mit Bargeld, Bankkonto oder Schwarzgeld brauchen kein Item. 1 Item `poker_chips` entspricht `Config.Chips.Value` Spielgeld (Standard: 1).

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

1. Öffne `install/ox_items.lua`.
2. Kopiere **nur den Eintrag** zwischen `return {` und der letzten `}`.
3. Füge ihn in `ox_inventory/data/items.lua` **vor der allerletzten schließenden Klammer `}`** ein.

Bild: ein eigenes `poker_chips.png` nach `ox_inventory/web/images/` legen.
{% endtab %}

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

1. Öffne `install/qb_items.lua`.
2. Kopiere den Eintrag zwischen `return {` und der letzten `}`.
3. Füge ihn in `qb-core/shared/items.lua` in die Tabelle `QBShared.Items` ein (vor deren schließender Klammer).

Gilt auch für ps-inventory und lj-inventory. Bild: `poker_chips.png` nach `qb-inventory/html/images/`.
{% endtab %}

{% tab title="ESX-Standardinventar" %}
Importiere `install/esx_items.sql` in deine Datenbank (z. B. mit HeidiSQL oder phpMyAdmin). Die Datei fügt das Item `poker_chips` in die Tabelle `items` ein.
{% endtab %}
{% endtabs %}

Heißt dein Item anders, trag den Namen in `Config.Chips.Item` ein. Ein Item-Bild liegt dem Script nicht bei.

{% hint style="info" %}
Pepper Poker verkauft und kauft keine Chips. Wie Spieler an das Item kommen (Shop, Casino-Kasse, Job), regelst du mit deinen eigenen Ressourcen.
{% endhint %}

#### Schritt 5 – Datenbank

Nichts zu tun: Die Ressource legt beim ersten Start alle Tabellen (`pepper_poker_*`) selbst an. Hat dein Datenbank-Benutzer **kein CREATE-Recht**, importiere vorher `install/pepper_poker.sql`.

#### Schritt 6 – Config prüfen und starten

Öffne `config/config.lua` und prüfe mindestens:

* `Config.Locale = 'de'` (oder `'en'`)
* `Config.Framework = 'auto'` – erkennt Qbox, ESX und QBCore selbst
* `Config.Accounts` – welche Konten im Editor wählbar sind (siehe **Konfiguration**)
* `Config.Rake` – Hausanteil pro Pot

Webhooks und das Rake-Konto stehen in `config/server.lua`. Danach den Server starten.

{% hint style="success" %}
**Kontrollpunkt:** In der Konsole steht `Pepper Poker 1.0.0 gestartet (Framework: esx, Tische: 0)` – mit deinem Framework.
{% endhint %}

#### Schritt 7 – Ersten Tisch anlegen

{% stepper %}
{% step %}
**Position wählen**

Stell dich im Spiel genau dorthin, wo die **Tischmitte** sein soll. Dreh dich so, dass du in die Richtung schaust, in der die **Spieler sitzen** sollen. Beim mitgelieferten halbrunden Casino-Tisch sitzen die Spieler im Halbkreis vor dir, bei runden Tischen rundherum.
{% endstep %}

{% step %}
**Tisch-Verwaltung öffnen**

`/pokeradmin` eingeben und **Neuer Tisch hier** wählen.
{% endstep %}

{% step %}
**Werte eintragen**

Name, Plätze (2–8), Small und Big Blind, Mindest- und Höchst-Buy-in, Konto. Rake und PIN können leer bleiben (leer = Wert aus der Config bzw. öffentlicher Tisch).
{% endstep %}

{% step %}
**Tisch und Stühle**

Lass **Tisch erzeugen** und **Stühle erzeugen** an, wenn an der Stelle noch nichts steht. Schalte sie aus, wenn dort schon ein Tisch bzw. Stühle stehen (siehe unten).
{% endstep %}

{% step %}
**Anlegen**

**Tisch anlegen** – der Tisch erscheint für alle Spieler, mit Blip und schwebendem Text.
{% endstep %}
{% endstepper %}

{% hint style="success" %}
**Kontrollpunkt:** Am Tisch erscheint „Pokertisch öffnen“ (Target oder `[E]`), die Tischansicht öffnet sich, und nach **Platz nehmen** sitzt dein Charakter am Tisch.
{% endhint %}

**„Tisch erzeugen“ und „Stühle erzeugen“**

| Schalter            | An                                                           | Aus                                                             |
| ------------------- | ------------------------------------------------------------ | --------------------------------------------------------------- |
| **Tisch erzeugen**  | Das Script stellt ein Tisch-Modell an die Position           | An der Stelle steht schon ein Tisch (MLO, Casino, eigene Möbel) |
| **Stühle erzeugen** | Das Script stellt je Platz einen Stuhl im Kreis um die Mitte | Dort stehen schon Stühle                                        |

Die Modelle werden nur lokal und nur in der Nähe erzeugt (`Config.Table.StreamDistance`). Benutzt wird das erste Modell aus `Config.Table.Models` bzw. `ChairModels`, das in deinem Spiel existiert.

Nutzt du vorhandene Möbel, stell dich beim Anlegen in die Mitte des vorhandenen Tisches. Die Sitzpositionen berechnet das Script immer als Kreis um die Mitte – passe `Config.Table.SeatRadius` an, bis die Spieler auf den vorhandenen Stühlen sitzen.

**Wenn Sitz oder Stuhl nicht passen**

Alle Werte stehen in `config/config.lua` unter `Config.Table` und gelten für alle Tische:

| Problem                                         | Einstellung                                                         |
| ----------------------------------------------- | ------------------------------------------------------------------- |
| Spieler schweben über dem Stuhl oder sinken ein | `SeatZ` (Sitzhöhe über dem Boden, Standard `0.5`)                   |
| Stühle stehen zu hoch oder zu tief              | `ChairZ` (Höhenkorrektur der Stuhl-Modelle)                         |
| Tisch steht zu hoch oder zu tief                | `TableZ` (Höhenkorrektur des Tisch-Modells)                         |
| Stühle stehen im Tisch oder zu weit weg         | `SeatRadius` (Abstand Sitz ↔ Tischmitte, Standard `1.35`)           |
| Stühle stehen verkehrt herum                    | `ChairHeadingOffset` (Standard `180.0`, sonst `0.0`)                |
| Anderes Tisch- oder Stuhl-Modell                | `Models` / `ChairModels` (das erste vorhandene Modell wird benutzt) |

Nach einer Änderung `ensure pepper_poker` in der Konsole ausführen. Laufende Hände werden dabei abgebrochen, alle Einsätze gehen zurück und die Stacks werden ausgezahlt.

{% hint style="info" %}
Probleme? Siehe **FAQ**.
{% endhint %}

### Konfiguration

| Datei               | Inhalt                                                                             |
| ------------------- | ---------------------------------------------------------------------------------- |
| `config/config.lua` | alle Einstellungen für Client und Server                                           |
| `config/server.lua` | Admin-ACE, Webhooks, Rake-Konto, Hand-Protokoll – wird **nie** an Clients gesendet |

Zeiten sind Sekunden, Geld ist immer ganzzahlig. Blinds, Buy-in, Konto, Rake und PIN eines Tisches stellst du **nicht** in der Config ein, sondern im Spiel mit `/pokeradmin` (siehe **Spielablauf**).

#### Grundlagen

| Option             | Standard | Bedeutung                                                                                       |
| ------------------ | -------- | ----------------------------------------------------------------------------------------------- |
| `Config.Locale`    | `'de'`   | Sprache (`de` / `en`) – Ordner in `locales/`                                                    |
| `Config.Framework` | `'auto'` | `auto`, `esx`, `qbcore`, `qbox`, `standalone` (`auto` prüft qbx\_core → es\_extended → qb-core) |
| `Config.Debug`     | `false`  | zusätzliche Ausgaben in Konsole und F8                                                          |
| `Config.Currency`  | `'$'`    | Währungszeichen in der Oberfläche                                                               |

#### Befehle und Rechte

| Option                  | Standard                     | Bedeutung                                                                                                |
| ----------------------- | ---------------------------- | -------------------------------------------------------------------------------------------------------- |
| `Config.Commands.Admin` | `'pokeradmin'`               | Tisch-Verwaltung (nur Admins) – `''` = aus                                                               |
| `Config.Commands.Stats` | `'pokerstats'`               | eigene Statistik + Bestenliste – `''` = aus                                                              |
| `Config.Commands.Leave` | `'pokerleave'`               | Notfall: Tisch verlassen, falls die Oberfläche hängt – `''` = aus                                        |
| `Config.Commands.Bot`   | `'pokerbot'`                 | Bots an den eigenen Tisch setzen bzw. entfernen (nur Admins, nur mit `Config.Bots.Enabled`) – `''` = aus |
| `Config.AdminGroups`    | `admin`, `superadmin`, `god` | Framework-Gruppen, die als Admin gelten                                                                  |
| `ServerConfig.AdminAce` | `'pepper_poker.admin'`       | ACE-Recht für Admins (zusätzlich zu den Gruppen)                                                         |

Admin ist, wer das ACE-Recht **oder** eine der Gruppen hat. Geprüft wird bei jedem Server-Aufruf.

#### Konten und Chips

Jeder Tisch nutzt genau ein Konto. Welches, wählst du im Editor – zur Auswahl stehen die Einträge aus `Config.Accounts`.

| Option               | Standard                               | Bedeutung                                                          |
| -------------------- | -------------------------------------- | ------------------------------------------------------------------ |
| `Config.Accounts`    | `cash`, `bank`, `black_money`, `chips` | im Editor wählbare Konten – entferne, was du nicht anbieten willst |
| `Config.DirtyMoney`  | siehe unten                            | worauf das Konto `black_money` je Framework zeigt                  |
| `Config.Chips.Item`  | `'poker_chips'`                        | Item-Name für das Konto `chips`                                    |
| `Config.Chips.Value` | `1`                                    | 1 Item = so viel Spielgeld                                         |

| Konto         | ESX                 | QBCore | Qbox   |
| ------------- | ------------------- | ------ | ------ |
| `cash`        | Bargeld (`money`)   | `cash` | `cash` |
| `bank`        | `bank`              | `bank` | `bank` |
| `black_money` | Konto `black_money` | `cash` | `cash` |
| `chips`       | Item                | Item   | Item   |

Die Zeile `black_money` ist die Vorgabe aus `Config.DirtyMoney`:

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

{% hint style="info" %}
**QBCore/Qbox:** In der Vorgabe ist Schwarzgeld dort dasselbe wie Bargeld. Trag in `Config.DirtyMoney` dein eigenes Geldkonto ein – oder nimm `'black_money'` aus `Config.Accounts`, damit es im Editor nicht zur Auswahl steht.
{% endhint %}

**Chips-Tische:** Ist `Config.Chips.Value` größer als 1, müssen Mindest- und Höchst-Buy-in sowie jeder Buy-in und Nachkauf ein Vielfaches davon sein. Ausgezahlt wird in ganzen Items – ein Rest unter dem Chip-Wert kommt als Bargeld.

#### Spielablauf

| Option                         | Standard | Bedeutung                                                                      |
| ------------------------------ | -------- | ------------------------------------------------------------------------------ |
| `Config.Game.MinPlayers`       | `2`      | ab so vielen Spielern mit Chips startet eine Hand                              |
| `Config.Game.StartDelay`       | `6`      | Sekunden bis zur nächsten Hand                                                 |
| `Config.Game.TurnTime`         | `25`     | Sekunden Bedenkzeit pro Zug                                                    |
| `Config.Game.ShowdownTime`     | `7`      | Sekunden, die das Ergebnis stehen bleibt (ohne Showdown höchstens 4)           |
| `Config.Game.TimeoutsToSitOut` | `2`      | so viele Zeitüberschreitungen in Folge → Spieler setzt aus                     |
| `Config.Game.SitOutKick`       | `180`    | Sekunden aussetzen, bis der Platz frei wird (`0` = nie)                        |
| `Config.Game.BrokeKick`        | `45`     | Sekunden ohne Chips, bis der Platz frei wird (`0` = nie) – Zeit zum Nachkaufen |
| `Config.Game.MaxSpectators`    | `12`     | Zuschauer pro Tisch                                                            |
| `Config.Game.ShowFoldedCards`  | `false`  | `true` = am Showdown auch weggeworfene Karten zeigen                           |
| `Config.Game.AutoMuck`         | `true`   | Verlierer am Showdown zeigen ihre Karten nicht                                 |
| `Config.Game.MaxDistance`      | `6.0`    | Meter: so nah muss man an der Tischmitte stehen, um Platz zu nehmen            |

#### Rake

Der Rake ist der Hausanteil pro Pot.

| Option                     | Standard | Bedeutung                                                            |
| -------------------------- | -------- | -------------------------------------------------------------------- |
| `Config.Rake.Percent`      | `5`      | Prozent vom Pot (`0` = aus) – gilt für alle Tische ohne eigenen Wert |
| `Config.Rake.Cap`          | `5000`   | höchstens so viel pro Pot (`0` = ohne Deckel)                        |
| `Config.Rake.NoFlopNoDrop` | `true`   | kein Rake, wenn die Hand vor dem Flop endet                          |
| `ServerConfig.RakeAccount` | `nil`    | Firmenkonto für den Rake – `nil` = das Geld verlässt den Umlauf      |

* **Je Tisch:** Im Editor überschreibt das Feld **Rake in %** den Prozentsatz für diesen Tisch (0 bis 50, leer = Wert aus der Config). Deckel und „No Flop, No Drop“ gelten immer aus der Config.
* **Berechnung:** Prozent vom gesamten Pot, abgerundet auf ganze Beträge, höchstens der Deckel. Abgezogen wird vom Hauptpot.
* **Firmenkonto:** Mit ESX geht der Rake an das Gemeinschaftskonto von `esx_addonaccount` (z. B. `'society_casino'`). Mit QBCore/Qbox an `Renewed-Banking`, sonst an `qb-banking`. Läuft keine dieser Ressourcen, verfällt der Betrag.

#### Grenzen und Vorgaben für den Editor

| Option                                | Standard                                             | Bedeutung                                     |
| ------------------------------------- | ---------------------------------------------------- | --------------------------------------------- |
| `Config.Limits.MinSeats` / `MaxSeats` | `2` / `8`                                            | Plätze pro Tisch                              |
| `Config.Limits.MinBlind` / `MaxBlind` | `1` / `1000000`                                      | erlaubter Bereich für Small und Big Blind     |
| `Config.Limits.MinBuyinBB`            | `10`                                                 | kleinstes Buy-in in Big Blinds                |
| `Config.Limits.MaxBuyinBB`            | `500`                                                | größtes Buy-in in Big Blinds                  |
| `Config.Limits.MaxTables`             | `40`                                                 | Tische pro Server                             |
| `Config.TableDefaults`                | 6 Plätze, Blinds 50/100, Buy-in 2.000–10.000, `cash` | Vorgaben für neue Tische (im Editor änderbar) |

Der Big Blind muss größer als der Small Blind sein. Der Name braucht 2 bis 40 Zeichen, die PIN 4 bis 8 Ziffern.

#### Tisch in der Welt

| Option                            | Standard                                          | Bedeutung                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| --------------------------------- | ------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Config.Table.Models`             | 6 Einträge, zuerst `vw_prop_casino_3cardpoker_01` | Tisch-Modelle. Je Tisch wird der erste Eintrag benutzt, dessen Modell im Spiel existiert und der genug Plätze hat. Standard: 2–4 Plätze = Casino-Tisch mit 4 eingebauten Hockern, 5–8 Plätze = großer Tisch mit Stühlen rundherum. Ein Eintrag ist ein Modellname oder eine Tabelle: `model`, `maxSeats` = bis zu so vielen Plätzen wird das Modell benutzt, `chairs` = Anzahl fest eingebauter Stühle (dann erzeugt das Script keine eigenen), `arc` = Bogen der Sitze in Grad (halbrunder Tisch: 180), `heading` = Drehung des Modells, `radius` = Abstand Sitz ↔ Tischmitte, `seatZ` = Sitzhöhe, `chair` = Stuhl-Modell nur für diesen Tisch |
| `Config.Table.ChairModels`        | 3 Modelle, zuerst `vw_prop_casino_chair_01a`      | Stuhl-Modelle, gleiche Regel                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| `Config.Table.SeatRadius`         | `1.35`                                            | Abstand Sitz ↔ Tischmitte (Meter)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| `Config.Table.SeatArc`            | `360.0`                                           | Grad, über die sich die Sitze verteilen, wenn das Modell keinen eigenen Wert hat: `360` = rund um den Tisch, `180` = Halbkreis                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| `Config.Table.SeatSpacing`        | `0.68`                                            | Mindestabstand zwischen zwei Stühlen auf einem Bogen (Meter) – bei vielen Plätzen rücken die Stühle nach außen                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| `Config.Table.ChairGap`           | `0.55`                                            | Tische ohne eingebaute Stühle: Abstand Stuhlmitte ↔ Tischkante (Meter). Die Stühle stehen anhand der Maße des Tisch-Modells rund um die Tischplatte – größer = weiter weg                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| `Config.Table.SeatZ`              | `0.5`                                             | Sitzhöhe über dem Boden (für die Sitz-Animation)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| `Config.Table.TableZ`             | `0.0`                                             | Höhenkorrektur des Tisch-Modells                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| `Config.Table.ChairZ`             | `0.0`                                             | Höhenkorrektur der Stuhl-Modelle                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| `Config.Table.ChairHeadingOffset` | `180.0`                                           | Drehung der Stuhl-Modelle (stehen sie verkehrt herum: `0.0`)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| `Config.Table.StreamDistance`     | `60.0`                                            | Meter: ab hier werden Tisch und Stühle erzeugt                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| `Config.Table.Scenario`           | `'PROP_HUMAN_SEAT_CHAIR_MP_PLAYER'`               | Sitz-Szenario des Charakters                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |

Diese Werte gelten für alle Tische. Ob ein Tisch überhaupt Modelle erzeugt, stellst du je Tisch im Editor ein (**Tisch erzeugen**, **Stühle erzeugen**).

#### Interaktion, Text und Blips

| Option                                   | Standard            | Bedeutung                                                            |
| ---------------------------------------- | ------------------- | -------------------------------------------------------------------- |
| `Config.Interact.Mode`                   | `'auto'`            | `auto` = ox\_target, falls gestartet, sonst Taste · `target` · `key` |
| `Config.Interact.Key`                    | `38`                | GTA-Control-ID der Taste (38 = E)                                    |
| `Config.Interact.Distance`               | `2.4`               | Meter bis zur Tischmitte                                             |
| `Config.Label.Enabled`                   | `true`              | schwebender Text über dem Tisch (Name, Blinds, Spieler)              |
| `Config.Label.Distance`                  | `8.0`               | Sichtweite des Textes in Metern                                      |
| `Config.Label.Height`                    | `1.45`              | Höhe des Textes über dem Boden                                       |
| `Config.Blip.Enabled`                    | `true`              | Karten-Blip je aktivem Tisch                                         |
| `Config.Blip.Sprite` / `Color` / `Scale` | `680` / `1` / `0.7` | Aussehen des Blips                                                   |

Läuft ox\_target nicht, nutzt das Script auch im Modus `target` die Taste.

#### Reaktionen, Statistik, Oberfläche

| Option                    | Standard                                                    | Bedeutung                                                                              |
| ------------------------- | ----------------------------------------------------------- | -------------------------------------------------------------------------------------- |
| `Config.Reactions`        | `nice_hand`, `good_game`, `thanks`, `wow`, `bluff`, `hurry` | Schnell-Reaktionen – Texte in `locales/<sprache>/ui.json` unter `ui.react_<schlüssel>` |
| `Config.Stats.Enabled`    | `true`                                                      | Statistik und Bestenliste an/aus                                                       |
| `Config.Stats.TopSize`    | `20`                                                        | Plätze in der Bestenliste (höchstens 100)                                              |
| `Config.UI.FourColorDeck` | `false`                                                     | `true` = Vier-Farben-Blatt (Kreuz grün, Karo blau)                                     |
| `Config.UI.Sounds`        | `true`                                                      | Töne in der Oberfläche                                                                 |
| `Config.UI.ShowHandHint`  | `true`                                                      | eigene Handstärke anzeigen („Zwei Paare“)                                              |

#### Bots (zum Testen)

Computergesteuerte Mitspieler, damit du Hände allein testen kannst. Standardmäßig **aus**.

{% hint style="warning" %}
Bots spielen mit Chips, die aus dem Nichts kommen. Chips, die ein echter Spieler von einem Bot gewinnt, werden beim Aufstehen als **echtes Spielgeld** ausgezahlt; Chips, die er an einen Bot verliert, verschwinden. Auch der Rake aus solchen Händen geht an `ServerConfig.RakeAccount`. Lass Bots auf Live-Servern ausgeschaltet – außer du willst genau das.
{% endhint %}

| Option                    | Standard                 | Bedeutung                                                                           |
| ------------------------- | ------------------------ | ----------------------------------------------------------------------------------- |
| `Config.Bots.Enabled`     | `false`                  | Bots erlauben. Hinzufügen können sie nur Admins (Tisch-Verwaltung oder `/pokerbot`) |
| `Config.Bots.MaxPerTable` | `7`                      | höchstens so viele Bots pro Tisch                                                   |
| `Config.Bots.ThinkMin`    | `1200`                   | kürzeste Bedenkzeit eines Bots in Millisekunden                                     |
| `Config.Bots.ThinkMax`    | `3200`                   | längste Bedenkzeit eines Bots in Millisekunden                                      |
| `Config.Bots.Names`       | `Bot Anna`, `Bot Ben`, … | Anzeigenamen (je Tisch wird jeder Name nur einmal vergeben)                         |

Bots starten mit 100 Big Blinds (innerhalb des Buy-in-Bereichs des Tisches) und bekommen neue Chips, sobald sie pleite sind. Eine Hand startet nur, wenn mindestens ein echter Spieler mitspielt; steht der letzte echte Spieler auf, verschwinden die Bots. Bots tauchen weder in der Statistik noch in der Bestenliste auf.

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

| Option                          | Standard         | Bedeutung                                                                       |
| ------------------------------- | ---------------- | ------------------------------------------------------------------------------- |
| `ServerConfig.Webhooks.bigPots` | `''`             | Discord-Webhook für große Pots (`''` = aus)                                     |
| `ServerConfig.Webhooks.admin`   | `''`             | Discord-Webhook: Tisch angelegt, geändert, gelöscht                             |
| `ServerConfig.WebhookName`      | `'Pepper Poker'` | Absendername im Discord                                                         |
| `ServerConfig.BigPot`           | `50000`          | ab diesem Pot geht eine Meldung an `bigPots`                                    |
| `ServerConfig.HandLogDays`      | `14`             | Hand-Protokoll: Tage, nach denen Einträge gelöscht werden (`0` = nie speichern) |
| `ServerConfig.VersionCheck`     | `true`           | Update-Hinweis in der Server-Konsole – lädt nie Code nach                       |

Webhooks enthalten nur Anzeigenamen, keine Spieler-Identifier. Webhook-URLs nie öffentlich teilen.

Das **Hand-Protokoll** liegt in der Tabelle `pepper_poker_hands`: Tisch, Hand-Nummer, Pot, Rake, Board und Gewinner. Es ist für Streitfälle gedacht. Alte Einträge werden beim Start der Ressource gelöscht.

{% hint style="info" %}
In Version 1.0.0 ist für `VersionCheck` noch keine Prüf-Adresse hinterlegt – die Option hat derzeit keine Wirkung.
{% endhint %}

#### Texte anpassen

Alle Texte stehen in `locales/de/*.json` und `locales/en/*.json` (`core`, `game`, `ui`). Für eine neue Sprache den Ordner `en` kopieren, übersetzen und `Config.Locale` setzen.

### Spielablauf

#### Zum Tisch kommen

Jeder aktive Tisch hat einen Blip auf der Karte und einen schwebenden Text mit Name, Blinds und Spielerzahl (z. B. „Spieler 3/6“). Private Tische zeigen zusätzlich „Privater Tisch (PIN)“.

{% stepper %}
{% step %}
**Tisch öffnen**

Am Tisch **Pokertisch öffnen** wählen – per ox\_target oder mit `[E]`, je nach `Config.Interact`.
{% endstep %}

{% step %}
**Zuschauen**

Die Tischansicht öffnet sich, du bist zuerst **Zuschauer**. Du siehst Board, Pot, Einsätze und das Protokoll – aber keine verdeckten Karten. Pro Tisch können 12 Spieler zuschauen.
{% endstep %}

{% step %}
**Platz nehmen**

Auf einen freien Platz klicken (**Platz nehmen**). Dafür musst du höchstens 6 m von der Tischmitte entfernt stehen.
{% endstep %}

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

Im Dialog den Betrag wählen – per Schieberegler, Eingabefeld oder **Min**/**Max**. Erlaubt ist der Bereich zwischen Mindest- und Höchst-Buy-in des Tisches, höchstens dein Guthaben auf dem Tisch-Konto. Der Betrag wird sofort abgebucht.
{% endstep %}

{% step %}
**Mitspielen**

Dein Charakter setzt sich an den Tisch. Du spielst ab der nächsten Hand mit. Eine Hand startet, sobald 2 Spieler mit Chips am Tisch sitzen.
{% endstep %}
{% endstepper %}

Ein Charakter kann nur an einem Tisch gleichzeitig sitzen. Solange du sitzt, sind Waffen und Angriffe gesperrt.

#### Die Tischansicht

| Bereich                | Inhalt                                                                                                                                  |
| ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
| **Plätze**             | Name, Stack, zwei Karten (eigene offen, fremde verdeckt), aktueller Einsatz, letzte Aktion, Dealer-Button, Small/Big Blind, „Setzt aus“ |
| **Tischmitte**         | Board mit 5 Kartenplätzen, Pot, Side-Pots, am Showdown Gewinner und Handname                                                            |
| **Zug-Timer**          | läuft am Platz des Spielers, der am Zug ist (Standard 25 s)                                                                             |
| **Aktionsleiste**      | **Fold**, **Check**/**Call** mit Betrag, **Bet**/**Raise** – nur aktiv, wenn du am Zug bist                                             |
| **Raise**              | Schieberegler, Eingabefeld, Plus/Minus (je 1 Big Blind), Schnellwahl **½ Pot**, **Pot**, **All-in**                                     |
| **Deine Hand**         | deine aktuelle Handstärke, z. B. „Zwei Paare“ (abschaltbar mit `Config.UI.ShowHandHint`)                                                |
| **Protokoll**          | die letzten 30 Einträge: Blinds, Aktionen, Flop/Turn/River, Gewinner                                                                    |
| **Reaktionen**         | 6 Schnell-Reaktionen („Schöne Hand“, „Gutes Spiel“, „Danke“, „Wow!“, „Bluff?“, „Beeil dich“) – erscheinen an deinem Platz               |
| **Kopfzeile**          | Tischname, Hand-Nummer, Blinds, Buy-in, Konto, Zahl der Zuschauer                                                                       |
| **Knöpfe oben rechts** | Ton an/aus, **Aussetzen**/**Weiterspielen**, **Nachkaufen**, **Aufstehen**, Schließen                                                   |

Reaktionen können nur sitzende Spieler senden. Freien Text gibt es am Tisch bewusst nicht.

#### Tasten

Die Tasten gelten in der Tischansicht, wenn du am Zug bist:

| Taste   | Funktion                                                   |
| ------- | ---------------------------------------------------------- |
| `F`     | Fold                                                       |
| `C`     | Check bzw. Call                                            |
| `R`     | springt ins Raise-Eingabefeld                              |
| `Enter` | bestätigt den Raise (im Eingabefeld oder am Schieberegler) |
| `ESC`   | verlässt das Raise-Feld, sonst: Tischansicht schließen     |

**Schließen und ESC:** Als Zuschauer verlässt du damit den Tisch. Sitzt du am Tisch, fragt das Script, ob du aufstehen und dich auszahlen lassen willst.

#### Private Tische

Hat ein Tisch eine PIN (4–8 Ziffern), fragt das Script sie beim Öffnen ab – auch fürs Zuschauen. Nach 5 falschen Eingaben ist die Eingabe 60 Sekunden gesperrt. Die PIN legt der Admin im Editor fest; ein leeres Feld macht den Tisch öffentlich.

#### Regeln

Gespielt wird **No-Limit Texas Hold'em**. Der Server mischt, gibt und rechnet alles.

* **Button und Blinds:** Der Dealer-Button rückt jede Hand weiter. Der Spieler links davon setzt den Small Blind, der nächste den Big Blind. Reicht der Stack nicht für den Blind, ist der Spieler All-in.
* **Heads-up (2 Spieler):** Der Button setzt den Small Blind, handelt vor dem Flop zuerst und danach zuletzt.
* **Setzrunden:** Preflop → Flop (3 Karten) → Turn (1) → River (1) → Showdown. Der Big Blind hat vor dem Flop die Option.
* **Mindest-Raise:** Eine Erhöhung muss mindestens so groß sein wie die letzte, mindestens ein Big Blind. Ein All-in unter dem Mindest-Raise eröffnet die Runde nicht neu für Spieler, die schon gehandelt haben.
* **All-in und Side-Pots:** Wer All-in geht, spielt um den Teil des Pots, den er mitbezahlt hat. Für den Rest entstehen Side-Pots. Nicht gecallte Einsätze gehen zurück.
* **Automatisches Aufdecken:** Sind alle bis auf höchstens einen Spieler All-in, werden die restlichen Karten sofort aufgedeckt.
* **Gewinn ohne Showdown:** Bleibt nur ein Spieler übrig, gewinnt er den Pot. Seine Karten bleiben verdeckt.
* **Showdown:** Gewinner zeigen ihre Karten. Verlierer zeigen sie nicht (`Config.Game.AutoMuck`).
* **Split-Pot:** Gleich starke Hände teilen den Pot. Ein nicht teilbarer Rest geht an den ersten Gewinner links vom Button.
* **Handwertung:** Höchste Karte, Ein Paar, Zwei Paare, Drilling, Straße, Flush, Full House, Vierling, Straight Flush, Royal Flush. A-2-3-4-5 ist die niedrigste Straße.
* **Rake:** Der Hausanteil wird am Ende der Hand vom Pot abgezogen (siehe **Konfiguration**).

#### Zeit, Aussetzen und Nachkaufen

* **Zeit abgelaufen:** Das Script checkt für dich, wenn das möglich ist – sonst foldet es.
* **Automatisches Aussetzen:** Nach 2 Zeitüberschreitungen in Folge setzt du aus. Machst du in derselben Hand noch selbst eine Aktion oder drückst **Weiterspielen**, bist du wieder dabei.
* **Aussetzen:** Mit **Aussetzen** bekommst du ab der nächsten Hand keine Karten mehr. Die laufende Hand spielst du zu Ende. Nach 180 Sekunden Aussetzen wird dein Platz frei – der Stack wird ausgezahlt.
* **Nachkaufen:** Mit **Nachkaufen** stockst du deinen Stack bis zum Höchst-Buy-in des Tisches auf. Das Geld wird sofort abgebucht, die Chips kommen vor der nächsten Hand auf deinen Stack.
* **Ohne Chips:** Hast du keine Chips mehr, bleiben dir 45 Sekunden zum Nachkaufen. Danach wird der Platz frei.
* **Aufstehen:** Du bekommst deinen Stack sofort zurück. Läuft gerade eine Hand, werden deine Karten gefoldet – gesetzte Chips bleiben im Pot.

Alle Zeiten stehen in `Config.Game`.

#### Geld-Sicherheit

Jeder Stack steht zusätzlich in der Datenbank. Kann das Script nicht direkt auszahlen, merkt es sich eine offene Auszahlung – sie kommt automatisch, sobald der Charakter das nächste Mal geladen ist.

| Situation                                                    | Was passiert                                                                                                                                                                      |
| ------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Aufstehen**                                                | Stack wird sofort ausgezahlt                                                                                                                                                      |
| **Disconnect oder Absturz des Spiels**                       | Karten werden gefoldet, der Stack wird beim nächsten Einloggen ausgezahlt. Ausnahme: Wer schon All-in ist, bleibt bis zum Ende der Hand im Spiel und bekommt seinen Gewinn danach |
| **Charakterwechsel**                                         | wie Disconnect – das Geld bekommt der Charakter, der am Tisch saß                                                                                                                 |
| **Neustart der Ressource / Server-Neustart über txAdmin**    | Laufende Hände werden abgebrochen, alle Einsätze gehen zurück, die Stacks werden direkt ausgezahlt                                                                                |
| **Server-Absturz**                                           | Beim nächsten Start werden alle gesicherten Stacks zu offenen Auszahlungen (Stand vom Beginn der Hand)                                                                            |
| **Tisch geändert, versetzt oder gelöscht**                   | Hand wird abgebrochen, Einsätze gehen zurück, alle werden ausgezahlt und stehen auf                                                                                               |
| **Auszahlung nicht möglich** (z. B. Inventar voll bei Chips) | Der Betrag bleibt offen – Platz schaffen und neu einloggen                                                                                                                        |

{% hint style="info" %}
Ausgezahlt wird immer auf das Konto des Tisches: Bargeld-Tisch → Bargeld, Chips-Tisch → Chips-Items.
{% endhint %}

#### Tisch-Verwaltung

`/pokeradmin` öffnet die Tisch-Verwaltung (nur Admins). Sie zeigt alle Tische mit Name, Blinds, Buy-in, Konto, Spielerzahl und Status.

| Aktion                       | Wirkung                                                                                   |
| ---------------------------- | ----------------------------------------------------------------------------------------- |
| **Neuer Tisch hier**         | legt einen Tisch an deiner Position an – du schaust dorthin, wo die Spieler sitzen sollen |
| **Tisch bearbeiten**         | Name, Plätze, Blinds, Buy-in, Konto, Rake, PIN, Tisch/Stühle erzeugen, Aktiv              |
| **Hierher versetzen**        | speichert die Änderungen und setzt den Tisch an deine Position                            |
| **Aktiv** aus                | der Tisch verschwindet für alle (Modelle, Blip, Text), bleibt aber gespeichert            |
| **Spieler vom Tisch nehmen** | der Spieler auf dem gewählten Platz steht auf und bekommt seinen Stack                    |
| **Löschen**                  | entfernt den Tisch endgültig                                                              |

{% hint style="warning" %}
Speichern, Versetzen und Löschen brechen eine laufende Hand an diesem Tisch ab. Alle Einsätze gehen zurück, alle Spieler werden ausgezahlt und stehen auf.
{% endhint %}

Felder im Editor:

| Feld                                 | Regel                                              |
| ------------------------------------ | -------------------------------------------------- |
| **Name**                             | 2 bis 40 Zeichen                                   |
| **Plätze**                           | 2 bis 8                                            |
| **Small Blind / Big Blind**          | der Big Blind muss größer als der Small Blind sein |
| **Buy-in mindestens / höchstens**    | 10 bis 500 Big Blinds (`Config.Limits`)            |
| **Konto für Buy-ins**                | eines aus `Config.Accounts`                        |
| **Rake in %**                        | leer = Wert aus der Config                         |
| **PIN**                              | leer = öffentlicher Tisch, sonst 4 bis 8 Ziffern   |
| **Tisch erzeugen / Stühle erzeugen** | aus, wenn dort schon Möbel stehen                  |

#### Statistik und Bestenliste

`/pokerstats` zeigt deine Werte und die Bestenliste. Gezählt wird pro Charakter.

* **Eigene Werte:** Netto (Gewinne minus Verluste), gespielte Hände, gewonnene Hände mit Gewinnquote, größter Pot, gewonnen, verloren, beste Hand
* **Bestenliste:** umschaltbar nach **Netto**, **Gewonnen**, **Größter Pot** und **Hände** – Standard 20 Plätze

Die Bestenliste wird höchstens einmal pro Minute neu berechnet. Mit `Config.Stats.Enabled = false` schaltest du beides ab.

### Befehle & Exports

#### Befehle

Die Namen stehen in `Config.Commands` – ein leerer Text (`''`) schaltet den Befehl ab.

| Befehl               | Wer    | Funktion                                                                                                                                                                                                                                            |
| -------------------- | ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `/pokeradmin`        | Admins | öffnet die Tisch-Verwaltung: Tische anlegen, ändern, versetzen, löschen, Spieler vom Tisch nehmen                                                                                                                                                   |
| `/pokerstats`        | alle   | eigene Statistik und Bestenliste                                                                                                                                                                                                                    |
| `/pokerleave`        | alle   | Notfall: Tisch verlassen, falls die Oberfläche hängt – der Stack wird ausgezahlt                                                                                                                                                                    |
| `/pokerbot [anzahl]` | Admins | nur mit `Config.Bots.Enabled`: setzt Bots an den Tisch, an dem du sitzt oder zuschaust (ohne Zahl: einen); `/pokerbot 0` entfernt alle Bots. Bei offener Tischansicht über die F8-Konsole eingeben – oder die Knöpfe in der Tisch-Verwaltung nutzen |

Zum Spielen selbst braucht niemand einen Befehl: Der Tisch öffnet sich über die Interaktion am Tisch.

#### Tasten

| Wo              | Taste   | Funktion                                                                 |
| --------------- | ------- | ------------------------------------------------------------------------ |
| Am Tisch (Welt) | `E`     | Pokertisch öffnen (ohne ox\_target) – änderbar mit `Config.Interact.Key` |
| Tischansicht    | `F`     | Fold                                                                     |
| Tischansicht    | `C`     | Check bzw. Call                                                          |
| Tischansicht    | `R`     | ins Raise-Eingabefeld springen                                           |
| Tischansicht    | `Enter` | Raise bestätigen                                                         |
| Tischansicht    | `ESC`   | Raise-Feld verlassen bzw. Tischansicht schließen                         |

`F`, `C` und `R` wirken nur, wenn du am Zug bist.

#### Rechte

Pepper Poker kennt genau ein Recht: **Admin**. Admins dürfen die Tisch-Verwaltung nutzen.

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

Admin ist außerdem, wer in einer Gruppe aus `Config.AdminGroups` ist (`admin`, `superadmin`, `god`):

| Framework | Geprüft wird                 |
| --------- | ---------------------------- |
| ESX       | die Gruppe des Spielers      |
| QBCore    | die QBCore-Berechtigung      |
| Qbox      | das ACE-Recht `group.<name>` |

Der Server prüft das Recht bei **jedem** Aufruf der Tisch-Verwaltung neu. Ob `/pokeradmin` die Verwaltung überhaupt öffnet, liest der Client beim Laden des Charakters – nach einer neuen Rechtevergabe also einmal neu einloggen.

#### Exports (Server)

Beide Exports sind **nur lesend** – es gibt bewusst keinen Export, mit dem andere Ressourcen Geld, Stacks oder Karten ändern.

| Export                                | Rückgabe                                                                   |
| ------------------------------------- | -------------------------------------------------------------------------- |
| `exports.pepper_poker:isPlaying(src)` | `true`, wenn der Spieler an einem Pokertisch sitzt (Zuschauen zählt nicht) |
| `exports.pepper_poker:getTables()`    | Liste aller Tische                                                         |

Beispiel – eine Aktion sperren, solange jemand am Tisch sitzt:

```lua
if exports.pepper_poker:isPlaying(source) then
    return -- Spieler sitzt gerade am Pokertisch
end
```

Beispiel – alle Tische mit Spielerzahl ausgeben:

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

Felder je Tisch aus `getTables()`:

| Feld                                   | Inhalt                                                                 |
| -------------------------------------- | ---------------------------------------------------------------------- |
| `id`, `name`                           | Tisch-ID und Name                                                      |
| `coords`, `heading`                    | Position (`x`, `y`, `z`) und Ausrichtung                               |
| `seats`, `players`                     | Plätze und aktuell besetzte Plätze                                     |
| `sb`, `bb`                             | Small und Big Blind                                                    |
| `minBuyin`, `maxBuyin`                 | Buy-in-Bereich                                                         |
| `account`                              | `cash`, `bank`, `black_money` oder `chips`                             |
| `private`                              | `true`, wenn der Tisch eine PIN hat (die PIN selbst ist nie enthalten) |
| `spawnTable`, `spawnChairs`, `enabled` | Schalter aus dem Editor                                                |

Solange Pepper Poker noch startet, liefert `getTables()` eine leere Liste.

#### Webhooks

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

| Schlüssel | Inhalt                                                                                                    |
| --------- | --------------------------------------------------------------------------------------------------------- |
| `bigPots` | Pots ab `ServerConfig.BigPot` (Standard 50.000): Tisch, Pot, Gewinner mit Hand, Hand-Nummer, Blinds, Rake |
| `admin`   | Tisch angelegt, geändert oder gelöscht: Admin, Blinds, Buy-in, Plätze, Konto                              |

Webhooks enthalten nur Anzeigenamen, nie Spieler-Identifier. Webhook-URLs nie öffentlich teilen.

#### Bridges (offen)

| Datei                                                               | Aufgabe                                                                     |
| ------------------------------------------------------------------- | --------------------------------------------------------------------------- |
| `bridge/detect.lua`                                                 | Framework-Erkennung                                                         |
| `bridge/server/esx.lua`, `qbcore.lua`, `qbox.lua`, `standalone.lua` | Geld, Gruppen, Identifier, Charakterwechsel                                 |
| `bridge/server/inventory.lua`                                       | Chips-Item prüfen, geben, nehmen (ox\_inventory, qb-/ps-/lj-inventory, ESX) |
| `bridge/client/frameworks.lua`                                      | Benachrichtigungen im Client                                                |

### FAQ

{% hint style="warning" %}
**Nur für Spielgeld.** Pepper Poker ist für Ingame-Geld gedacht. Verbinde es nicht mit echtem Geld oder mit Währungen, die man für echtes Geld kaufen kann – die Regeln von Rockstar und Cfx.re verbieten Glücksspiel um echtes Geld.
{% endhint %}

#### Fehlerbehebung

| Problem                                                       | Lösung                                                                                                                                                                                                             |
| ------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Kein Tisch zu sehen                                           | Es sind keine Tische vorinstalliert – mit `/pokeradmin` → **Neuer Tisch hier** anlegen. Ist der Tisch im Editor auf **Aktiv**?                                                                                     |
| „Dafür hast du keine Berechtigung“ bei `/pokeradmin`          | `add_ace group.admin pepper_poker.admin allow` setzen oder eine Gruppe aus `Config.AdminGroups` vergeben. Danach neu einloggen. Die Meldung kommt auch, wenn Pepper Poker nicht gestartet ist – Konsole prüfen.    |
| „Pepper Poker startet noch“                                   | Datenbank nicht erreichbar – `oxmysql` vor `pepper_poker` starten, Konsole prüfen. Ohne CREATE-Recht `install/pepper_poker.sql` importieren.                                                                       |
| Konsole: „Config.Framework = 'auto', aber keines von … läuft“ | Das Framework in der `server.cfg` **vor** `pepper_poker` starten.                                                                                                                                                  |
| Blip und Text sind da, aber kein Tisch und keine Stühle       | **Tisch erzeugen** / **Stühle erzeugen** im Editor einschalten. Existiert keines der Modelle aus `Config.Table.Models` bzw. `ChairModels` in deinem Spiel, wird nichts erzeugt – ein vorhandenes Modell eintragen. |
| Spieler schweben oder sinken in den Stuhl                     | `Config.Table.SeatZ` anpassen (siehe **Installation**).                                                                                                                                                            |
| Stühle stehen verkehrt herum                                  | `Config.Table.ChairHeadingOffset` von `180.0` auf `0.0` stellen.                                                                                                                                                   |
| Stühle stehen im Tisch oder zu weit weg                       | `Config.Table.ChairGap` anpassen (Abstand Stuhl ↔ Tischkante). Ohne erzeugten Tisch gilt `Config.Table.SeatRadius`. `/pokerdebug` in der F8-Konsole zeigt Modell und Sitzpositionen.                               |
| Am Casino-Tisch können nur 4 Spieler sitzen                   | Das Modell hat 4 eingebaute Hocker. Tische mit 5–8 Plätzen bekommen automatisch den großen Tisch mit Stühlen rundherum (`Config.Table.Models`).                                                                    |
| „Du bist zu weit vom Tisch entfernt“                          | Näher an die Tischmitte gehen oder `Config.Game.MaxDistance` erhöhen.                                                                                                                                              |
| „Du hast nicht genug dabei“                                   | Das Geld muss auf dem Konto des Tisches liegen (Bargeld, Bank, Schwarzgeld oder Chips). Bei Chips-Tischen muss das Item eingetragen sein.                                                                          |
| „Der Betrag muss ein Vielfaches von … sein“                   | Chips-Tisch mit `Config.Chips.Value` größer als 1 – Buy-in passend wählen.                                                                                                                                         |
| Chips-Item zeigt nur den internen Namen                       | Item-Datei aus `install/` in dein Inventar eintragen (siehe **Installation**).                                                                                                                                     |
| Oberfläche hängt, Spieler kommt nicht vom Tisch               | `/pokerleave` – der Spieler steht auf und bekommt seinen Stack.                                                                                                                                                    |
| „… warten noch auf dich – schaff Platz im Inventar“           | Offene Auszahlung in Chips konnte nicht gegeben werden. Platz schaffen und neu einloggen.                                                                                                                          |
| Rake kommt nicht auf dem Firmenkonto an                       | `ServerConfig.RakeAccount` gesetzt? ESX braucht `esx_addonaccount` und ein vorhandenes Gemeinschaftskonto, QBCore/Qbox `Renewed-Banking` oder `qb-banking`.                                                        |
| Kein Target am Tisch                                          | `ox_target` läuft nicht oder `Config.Interact.Mode = 'key'` – dann gilt die Taste `E`.                                                                                                                             |

#### Fragen

<details>

<summary>Sind Tische dabei?</summary>

Nein, es sind keine Tische vorinstalliert. Ein Admin stellt sie im Spiel auf: an die Stelle gehen, `/pokeradmin`, **Neuer Tisch hier**. Das dauert etwa eine Minute pro Tisch und braucht keine Koordinaten in einer Config. Tisch- und Stuhl-Modell erzeugt das Script auf Wunsch selbst.

</details>

<details>

<summary>Welches Geld kann man einsetzen?</summary>

Jeder Tisch nutzt genau ein Konto: Bargeld, Bankkonto, Schwarzgeld oder Chips als Item. Welche Konten im Editor zur Auswahl stehen, legst du in `Config.Accounts` fest. Auf QBCore und Qbox zeigt Schwarzgeld in der Vorgabe auf Bargeld – das änderst du in `Config.DirtyMoney`.

</details>

<details>

<summary>Was passiert mit meinen Chips, wenn ich die Verbindung verliere oder der Server neu startet?</summary>

Nichts geht verloren. Jeder Stack ist zusätzlich in der Datenbank gesichert. Bei einem Disconnect werden deine Karten gefoldet, und du bekommst deinen Stack beim nächsten Einloggen automatisch ausgezahlt. Bei einem Neustart der Ressource werden laufende Hände abgebrochen, alle Einsätze gehen zurück und die Stacks werden ausgezahlt. Nach einem Absturz macht der Server beim nächsten Start aus allen gesicherten Stacks offene Auszahlungen.

</details>

<details>

<summary>Wie funktioniert der Rake und wohin geht er?</summary>

Der Rake ist ein Prozentsatz vom Pot (Standard 5 %), höchstens der Deckel (Standard 5.000). Endet die Hand vor dem Flop, fällt in der Vorgabe kein Rake an („No Flop, No Drop“). Den Prozentsatz kannst du je Tisch überschreiben. Ohne `ServerConfig.RakeAccount` verlässt das Geld den Umlauf. Mit einem Konto geht es an `esx_addonaccount` (ESX) bzw. `Renewed-Banking` oder `qb-banking` (QBCore/Qbox).

</details>

<details>

<summary>Können Spieler die Karten der anderen sehen? Ist das cheat-sicher?</summary>

Der Server mischt, gibt und rechnet alles. Fremde Karten werden vor dem Showdown gar nicht an andere Spieler oder Zuschauer geschickt – es gibt auf dem Client also nichts, was man auslesen könnte. Jede Aktion, jeder Betrag und jedes Recht wird am Server geprüft, alle Aufrufe sind in der Häufigkeit begrenzt.

</details>

<details>

<summary>Kann ich vorhandene Casino-Möbel oder MLOs nutzen?</summary>

Ja. Stell dich beim Anlegen in die Mitte des vorhandenen Tisches und schalte im Editor **Tisch erzeugen** und – wenn dort Stühle stehen – **Stühle erzeugen** aus. Die Sitzpositionen berechnet das Script als Kreis um die Tischmitte. Mit `Config.Table.SeatRadius` und `SeatZ` passt du sie an die vorhandenen Stühle an. Diese Werte gelten für alle Tische.

</details>

<details>

<summary>Die Stühle stehen falsch herum oder die Spieler schweben – was ändere ich?</summary>

Alles in `Config.Table`: `ChairHeadingOffset` dreht die Stuhl-Modelle (`180.0` oder `0.0`), `SeatZ` ist die Sitzhöhe des Charakters, `ChairZ` und `TableZ` korrigieren die Höhe der Modelle, `SeatRadius` den Abstand zur Tischmitte. Die ganze Tabelle steht in der **Installation**.

</details>

<details>

<summary>ox_target oder Taste?</summary>

Beides geht. Mit `Config.Interact.Mode = 'auto'` nutzt das Script ox\_target, wenn es läuft, sonst die Taste `E` mit einem Hinweis am Bildschirm. Mit `'key'` erzwingst du die Taste.

</details>

<details>

<summary>Ist Poker ein Glücksspiel-Problem für meinen Server?</summary>

Pepper Poker ist nur für Spielgeld gedacht. Solange um Ingame-Geld gespielt wird, das man nicht für echtes Geld kaufen oder in echtes Geld tauschen kann, ist es eine Roleplay-Aktivität. Verbinde es nicht mit echtem Geld oder bezahlten Währungen – das verbieten die Regeln von Rockstar und Cfx.re. Für die Regeln auf deinem Server bist du selbst verantwortlich.

</details>

<details>

<summary>Wie viele Tische und Spieler sind möglich?</summary>

2 bis 8 Plätze pro Tisch, dazu bis zu 12 Zuschauer. In der Vorgabe sind 40 Tische pro Server erlaubt (`Config.Limits.MaxTables`). Ein Charakter kann nur an einem Tisch gleichzeitig sitzen.

</details>

<details>

<summary>Gibt es Turniere?</summary>

Nein, nicht in Version 1.0.0. Gespielt wird an Cash-Tischen: Man kauft sich ein, kann nachkaufen und jederzeit aufstehen.

</details>

<details>

<summary>Kann ich Pepper Poker übersetzen?</summary>

Ja. Alle Texte stehen in `locales/de/` und `locales/en/` (`core.json`, `game.json`, `ui.json`) und sind offen. Für eine neue Sprache den Ordner `en` kopieren, übersetzen und `Config.Locale` setzen. Fehlt ein Text, nimmt das Script den englischen.

</details>

<details>

<summary>Kann ich die Bedenkzeit oder die Blinds ändern?</summary>

Die Bedenkzeit steht in `Config.Game.TurnTime` und gilt für alle Tische. Blinds, Buy-in, Konto, Rake und PIN stellst du je Tisch im Editor ein (`/pokeradmin`).

</details>

<details>

<summary>Kann ein Admin einen Spieler vom Tisch nehmen?</summary>

Ja. In der Tisch-Verwaltung den Tisch öffnen, **Spieler vom Tisch nehmen** und den Platz wählen. Der Spieler steht auf und bekommt seinen Stack ausgezahlt.

</details>

<details>

<summary>Wie funktionieren Updates?</summary>

Neue Version im [Cfx.re-Portal](https://portal.cfx.re/assets/granted-assets) herunterladen und den Ordner ersetzen – `config/` und angepasste `locales/` vorher sichern. Tische, Statistik und offene Auszahlungen liegen in der Datenbank und bleiben erhalten. Mehr dazu: **Updates**.

</details>

### Changelog

#### 1.1.0 – 2026-10-04

**Neu**

* Bots zum Testen (`Config.Bots`, standardmäßig aus): Admins setzen computergesteuerte Mitspieler an einen Tisch – über die Tisch-Verwaltung oder `/pokerbot [anzahl]`

**Behoben**

* Doppelte Stühle am Casino-Tisch: Das Modell hat 4 eingebaute Hocker – das Script erzeugt dort keine eigenen Stühle mehr, die Spieler sitzen auf den Hockern des Tischs
* Stühle früherer Tisch-Einstellungen blieben stehen: beim Umbau, Löschen und Start werden alte Tisch- und Stuhl-Modelle zuverlässig entfernt
* Stühle standen bei länglichen Tischen halb in der Tischplatte: Sie stehen jetzt anhand der Maße des Tisch-Modells rund um die Tischkante
* Halbrunder Casino-Tisch: Spieler sitzen im Halbkreis auf der Spielerseite statt rund um den Tisch

**Geändert**

* Das Tisch-Modell richtet sich nach der Sitzanzahl: 2–4 Plätze = Casino-Tisch mit eingebauten Hockern, 5–8 Plätze = großer Tisch mit Stühlen rundherum
* `Config.Table.Models` nimmt je Modell `maxSeats`, `chairs`, `arc`, `heading`, `radius`, `seatZ` und `chair`; neu `Config.Table.ChairGap` und `Config.Table.SeatSpacing`
* `/pokerdebug` (F8-Konsole) listet Tisch-Modell, Sitzpositionen und Props am nächsten Tisch

#### 1.0.1 – 2026-10-04

**Behoben**

* Schwarzer Bildschirm für alle Spieler nach dem Start der Ressource

#### 1.0.0 – 2026-10-04

**Erste Version**

* Texas Hold'em (No-Limit) an frei platzierbaren Tischen für 2–8 Spieler – ESX Legacy, QBCore und Qbox
* Tisch-Editor im Spiel (`/pokeradmin`): Tisch an der eigenen Position anlegen, versetzen, ändern, ein-/ausschalten, löschen; Spieler vom Tisch nehmen
* Je Tisch einstellbar: Name, Plätze, Small/Big Blind, Mindest- und Höchst-Buy-in, Konto (Bargeld, Bank, Schwarzgeld oder Chips-Item), Rake, PIN für private Runden, Tisch und Stühle erzeugen
* Vollständige Regeln: Blinds, Mindest-Raise, All-in, Side-Pots, Split-Pots, Heads-up-Reihenfolge, automatisches Aufdecken bei All-in, Rückgabe nicht gecallter Einsätze
* Der Server mischt, gibt und rechnet alles – fremde Karten verlassen den Server erst am Showdown
* Zug-Timer mit automatischem Check/Fold, automatisches Aussetzen nach Zeitüberschreitungen; Plätze werden bei langem Aussetzen oder ohne Chips frei
* Nachkaufen am Tisch, Aussetzen, Schnell-Reaktionen, Protokoll der letzten Aktionen
* Zuschauen an jedem Tisch (begrenzt je Tisch), private Tische nur mit PIN
* Rake mit Prozentsatz, Deckel und „No Flop, No Drop“; optional Überweisung an ein Firmenkonto (esx\_addonaccount, qb-banking, Renewed-Banking)
* Geld-Sicherheit: Jeder Stack ist in der Datenbank gesichert; bei Disconnect, Charakterwechsel, Neustart oder Absturz wird automatisch ausgezahlt bzw. beim nächsten Laden des Charakters nachgezahlt
* Statistik je Charakter (Hände, gewonnene Hände, größter Pot, Gewinn/Verlust, beste Hand) und Bestenliste (`/pokerstats`)
* Hand-Protokoll in der Datenbank für Streitfälle (Aufbewahrung einstellbar)
* Discord-Webhooks für große Pots und Änderungen an Tischen
* Optionales Chips-Item `poker_chips` (ox\_inventory, qb-inventory, ESX-Inventar)
* Server-Exports `isPlaying(src)` und `getTables()`
* Deutsch und Englisch, alle Texte in `locales/` anpassbar
