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

# Configuration

Every option in config/shared.lua.

All settings are in one file, `config/shared.lua`, loaded on the client and the server. Restart the resource after changing it.

## General

```lua
Config.Language = nil
Config.AdminGroup = 'group.admin'
Config.Target = 'auto'
Config.Notify = 'ox_lib'
```

| Option              | Default         | Description                                                                                                                                                                                       |
| ------------------- | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Config.Language`   | `nil`           | Language of all texts. `nil` follows your server's ox\_lib language (`setr ox:locale pl` in `server.cfg`). `'en'` or `'pl'` forces one.                                                           |
| `Config.AdminGroup` | `'group.admin'` | Ace group that may use `/squashcourt`.                                                                                                                                                            |
| `Config.Target`     | `'auto'`        | How players open the squash panel in the middle of the court: `'auto'`, `'ox_target'`, `'qb_target'` or `'helptext'`. See [Frameworks & Targets](/docs/scripts/squash/frameworks-and-targets.md). |
| `Config.Notify`     | `'ox_lib'`      | `'ox_lib'` notifications, or `'gta'` for the game's own above the minimap.                                                                                                                        |

### The E prompt

Used when no target resource shows the spot.

```lua
Config.Prompt = {
    style = 'ox_lib',
    marker = {
        enabled = true,
        type = 1,
        size = 1.0,
        color = { 60, 200, 90, 200 },
    },
}
```

| Option           | Default                | Description                                                                                    |
| ---------------- | ---------------------- | ---------------------------------------------------------------------------------------------- |
| `style`          | `'ox_lib'`             | `'ox_lib'` shows the ox\_lib text UI, `'gta'` the game's own help text in the top left corner. |
| `marker.enabled` | `true`                 | A marker on the floor in the middle of the court. It is hidden while the court is in play.     |
| `marker.type`    | `1`                    | Marker type, see the [marker list](https://docs.fivem.net/docs/game-references/markers/).      |
| `marker.size`    | `1.0`                  | Size in metres across.                                                                         |
| `marker.color`   | `{ 60, 200, 90, 200 }` | Red, green, blue and opacity, each 0 to 255.                                                   |

### Debug mode

Debug mode draws the outline of every court, logs each swing and referee decision, and adds the `/squashprop` command. It is not switched on in the config. Put this in `server.cfg`:

```cfg
setr kossek_squash_debug true
```

{% hint style="warning" %}
Use `setr`, not `set`. The value is also read on the client, and a convar created with `set` never reaches it.
{% endhint %}

## Courts

`Config.Courts` holds one line per court. The options of a line and the commands that write it for you are explained in [Courts & Scoreboards](/docs/scripts/squash/courts-and-scoreboards.md).

## Match rules

```lua
Config.Match = {
    pointsToWin = 11,
    winBy = 2,
    gamesToWin = 1,
    joinDistance = 3.0,
    introDelay = 2500,
    pointDelay = 2500,
    finishDelay = 6000,
    serveTimeout = 30000,
    serveBoxMargin = 0.3,
    idleTimeout = 120000,
    outsideGrace = 5000,
}
```

| Option           | Default  | Description                                                               |
| ---------------- | -------- | ------------------------------------------------------------------------- |
| `pointsToWin`    | `11`     | Points needed to win a game. Every rally scores a point.                  |
| `winBy`          | `2`      | Lead needed to finish a game: at 10-10 play goes on to 12-10.             |
| `gamesToWin`     | `1`      | `1` is a single game, `2` best of three, `3` best of five.                |
| `joinDistance`   | `3.0`    | Metres from the middle of the court within which the panel opens.         |
| `introDelay`     | `2500`   | Time in ms between the opponent joining and the first serve.              |
| `pointDelay`     | `2500`   | Time in ms the result of a rally stays up before the next serve.          |
| `finishDelay`    | `6000`   | Time in ms the final result stays up before the court is free again.      |
| `serveTimeout`   | `30000`  | Time in ms to serve. After that the server loses the point.               |
| `serveBoxMargin` | `0.3`    | Metres a server may stand outside the service box. One foot in is enough. |
| `idleTimeout`    | `120000` | Time in ms without a serve after which solo practice ends.                |
| `outsideGrace`   | `5000`   | Time in ms a player may be off the court before they forfeit the match.   |

## Wagers

Needs ESX, QBCore or QBX.

```lua
Config.Wager = {
    enabled = true,
    account = 'money',
    min = 100,
    max = 100000,
    fee = 0.0,
}
```

| Option    | Default   | Description                                                                          |
| --------- | --------- | ------------------------------------------------------------------------------------ |
| `enabled` | `true`    | Let the player who opens a match set a stake.                                        |
| `account` | `'money'` | `'money'` is cash (the `cash` account on QBCore and QBX), `'bank'` the bank account. |
| `min`     | `100`     | Smallest stake.                                                                      |
| `max`     | `100000`  | Largest stake.                                                                       |
| `fee`     | `0.0`     | Share of the pot the server keeps: `0.05` is 5%.                                     |

How stakes are taken and paid is described in [Gameplay](/docs/scripts/squash/gameplay.md).

## Stats and rankings

```lua
Config.Stats = {
    enabled = true,
    table = 'squash_stats',
    elo = {
        start = 1000,
        floor = 100,
        k = { { below = 10, k = 48 }, { below = 50, k = 32 }, { k = 16 } },
    },
    leaderboardSize = 10,
    minMatches = 1,
}
```

| Option            | Default          | Description                                                                                                |
| ----------------- | ---------------- | ---------------------------------------------------------------------------------------------------------- |
| `enabled`         | `true`           | Save stats and show the stats and ranking tabs.                                                            |
| `table`           | `'squash_stats'` | Database table, created on the first start.                                                                |
| `elo.start`       | `1000`           | Rating of a new player.                                                                                    |
| `elo.floor`       | `100`            | Nobody drops below this.                                                                                   |
| `elo.k`           | 48 / 32 / 16     | How much one match can move a rating, by matches played so far: 48 for the first 10, 32 up to 50, then 16. |
| `leaderboardSize` | `10`             | Players shown in the ranking.                                                                              |
| `minMatches`      | `1`              | Matches a player needs before they appear in the ranking.                                                  |

## Controls

```lua
Config.Keys = {
    hard = { mapper = 'MOUSE_BUTTON', key = 'MOUSE_LEFT' },
    soft = { mapper = 'MOUSE_BUTTON', key = 'MOUSE_RIGHT' },
    let = { mapper = 'keyboard', key = 'E' },
    leave = { mapper = 'keyboard', key = 'BACK', hold = 1.0 },
}
```

| Option       | Default     | Description                                                         |
| ------------ | ----------- | ------------------------------------------------------------------- |
| `hard`       | Left mouse  | Hard shot (drive, kill).                                            |
| `soft`       | Right mouse | Touch shot (drop, lob).                                             |
| `let`        | E           | Ask the referee for a let, in matches only.                         |
| `leave`      | Backspace   | Leave the court: cancels a lobby, ends practice, forfeits a match.  |
| `leave.hold` | `1.0`       | Seconds the leave key has to be held, so nobody leaves by accident. |

Key names are listed in the [FiveM input reference](https://docs.fivem.net/docs/game-references/input-mapper-parameter-ids/).

{% hint style="info" %}
These are defaults. Players can rebind every key in the GTA settings (Key Bindings, FiveM), and a default changed here does not reach players who already have the old one saved.
{% endhint %}

## HUD and visuals

```lua
Config.Ui = {
    grid = 2.5,
    layout = {
        scoreboard = { x = 50.0, y = 5.0 },
        banner = { x = 50.0, y = 20.0 },
        shot = { x = 50.0, y = 84.0 },
        meter = { x = 65.0, y = 50.0 },
        leave = { x = 50.0, y = 92.5 },
    },
    meterVertical = true,
    spectateDistance = 15.0,
    spectateWithBoard = false,
}
```

| Option              | Default   | Description                                                                                                                                                                                                                            |
| ------------------- | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `layout`            | see above | Where each HUD element sits: its centre in % of the screen, x from the left and y from the top. The elements are the scoreboard, the result banner, the readout of your last shot, the serve power meter and the bar of the leave key. |
| `grid`              | `2.5`     | Step in % the `/squashhud` editor snaps to.                                                                                                                                                                                            |
| `meterVertical`     | `true`    | Serve meter as an upright bar. Players can switch it in `/squashhud`.                                                                                                                                                                  |
| `spectateDistance`  | `15.0`    | Metres from the middle of a court within which bystanders get its scoreboard and results on their screen. `0` switches that off.                                                                                                       |
| `spectateWithBoard` | `false`   | A court with a scoreboard in the world shows the score to everybody who stands there, so bystanders get nothing on their screen at such a court. `true` puts the scoreboard on their screen at every court, with or without a board.   |

The layout is the server's default. Every player can move the elements with `/squashhud`, and that is saved on their own PC.

| Option                    | Default | Description                                                                                                                |
| ------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------- |
| `Config.RenderDistance`   | `50.0`  | Metres within which a court's ball, rackets and lines are drawn.                                                           |
| `Config.LandingMarker`    | `true`  | Ring on the floor where the ball will bounce, for the player who has to return it.                                         |
| `Config.AimMarker`        | `true`  | Dot on the wall where you are aiming, on your turn.                                                                        |
| `Config.Trail.enabled`    | `true`  | Streak behind the flying ball.                                                                                             |
| `Config.Trail.color`      | yellow  | Colour of the streak as `r`, `g`, `b`.                                                                                     |
| `Config.Trail.scale`      | `1.0`   | Size of the streak.                                                                                                        |
| `Config.Trail.minSpeed`   | `2.0`   | Speed in m/s below which the ball has no streak.                                                                           |
| `Config.Stance.enabled`   | `true`  | Tennis footwork on the court: the player keeps facing the front wall and sidesteps. `false` is normal walking and running. |
| `Config.Stance.speed`     | `1.0`   | How fast the player moves in the stance: `1.1` is 10% faster.                                                              |
| `Config.Board.enabled`    | `true`  | Scoreboards in the world, see [Courts & Scoreboards](/docs/scripts/squash/courts-and-scoreboards.md).                      |
| `Config.Board.resultTime` | `20`    | Seconds the result of a match stays on a scoreboard once the court is free again. A new game replaces it at once.          |

### Ball and racket models

```lua
Config.Props = {
    ball = 'ksq_ball',
    racket = 'ksq_racket',
    racketOffset = { pos = vec3(0.0, 0.0, 0.0), rot = vec3(0.0, 0.0, 0.0) },
    ballOffset = { pos = vec3(0.0, 0.0, 0.0), rot = vec3(0.0, 0.0, 0.0) },
}
```

| Option         | Default        | Description                                                                 |
| -------------- | -------------- | --------------------------------------------------------------------------- |
| `ball`         | `'ksq_ball'`   | Model of the ball. Comes with `kossek_squash_assets`.                       |
| `racket`       | `'ksq_racket'` | Model of the racket. Comes with `kossek_squash_assets`.                     |
| `racketOffset` | zero           | Where the racket sits in the hand: position in metres, rotation in degrees. |
| `ballOffset`   | zero           | The same for the ball held before a serve.                                  |

A model named here that the game does not have, also a name typed wrong, is replaced by the game's tennis ball (`prop_tennis_ball`) or tennis racket (`prop_tennis_rack_01b`). So there is nothing to change when the assets resource is not started. Zero offsets fit both pairs. For other models, debug mode has `/squashprop`, which moves them live and prints the line to paste here.

## Gameplay tuning

The game is balanced around these values. Change one at a time and test it on a court.

### Serving

The first press of a shot key starts a marker moving up the bar and back down, the second press stops it. Stopped in the sweet spot it is a perfect serve.

| Option                      | Default | Description                                                      |
| --------------------------- | ------- | ---------------------------------------------------------------- |
| `Config.Serve.meter`        | `true`  | `false` means one press serves, always at `fixedQuality`.        |
| `Config.Serve.fixedQuality` | `0.7`   | Serve quality without the meter, from 0 (worst) to 1 (perfect).  |
| `Config.Serve.period`       | `1600`  | Time in ms for the marker to go up and come back down.           |
| `Config.Serve.target`       | `0.8`   | Middle of the sweet spot on the bar, from 0 (bottom) to 1 (top). |
| `Config.Serve.zone`         | `0.08`  | Width of the sweet spot: `0.08` is 8% of the bar.                |
| `Config.Serve.falloff`      | `0.35`  | Distance from the sweet spot at which a serve is at its worst.   |
| `Config.Serve.minQuality`   | `0.2`   | Quality of that worst serve.                                     |

### Shots and swings

```lua
Config.Shots = {
    hard = { minSpeed = 13.0, maxSpeed = 18.0, spread = 1.6 },
    soft = { minSpeed = 7.0, maxSpeed = 15.0, shortDepth = 1.0, longDepth = 7.8, spread = 1.0 },
}
```

| Option                               | Default         | Description                                                                                                                                |
| ------------------------------------ | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
| `hard.minSpeed` / `hard.maxSpeed`    | `13.0` / `18.0` | Speed in m/s of a hard shot, from the poorest contact to a perfect one.                                                                    |
| `soft.minSpeed` / `soft.maxSpeed`    | `7.0` / `15.0`  | Speed range of a touch shot. The script works out the speed for the length the player aims for.                                            |
| `soft.shortDepth` / `soft.longDepth` | `1.0` / `7.8`   | Where a touch shot lands, in metres from the front wall: aimed just above the tin, and aimed near the top line.                            |
| `spread`                             | `1.6` / `1.0`   | How far the ball can stray from the aim point, in degrees.                                                                                 |
| `Config.Swing.reach`                 | `0.8`           | Metres the ball may be to the side of the racket and still be hit.                                                                         |
| `Config.Swing.heightReach`           | `0.55`          | The same in height.                                                                                                                        |
| `Config.Swing.missSpread`            | `2.5`           | Extra spread in degrees of the poorest contact.                                                                                            |
| `Config.Swing.power`                 | see config      | Speed of a hard shot by the kind of swing (`1.0` is unchanged): close to the body, normal or a dive, a low, middle or high ball, a volley. |
| `Config.Swing.diveSpread`            | `1.8`           | A dive is this many times less accurate.                                                                                                   |

### The referee

`Config.Interference` sets how strict the referee is. All distances are in metres. The rulings themselves are explained in [Gameplay](/docs/scripts/squash/gameplay.md).

| Option        | Default | Description                                                                                                                                  |
| ------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| `reach`       | `1.5`   | A player this close to the ball can play it without moving.                                                                                  |
| `runSpeed`    | `5.0`   | Speed in m/s a player is assumed to run. Decides whether the ball was in reach.                                                              |
| `path`        | `0.6`   | Opponent within this of the player's way to the ball: let.                                                                                   |
| `swing`       | `1.0`   | Opponent within this of the spot where the ball would be played: stroke.                                                                     |
| `frontLine`   | `0.5`   | Opponent within this of the straight line from that spot to the front wall: stroke.                                                          |
| `turnSide`    | `0.15`  | How far to one side the ball must pass a player to count as passing on that side.                                                            |
| `wrongFooted` | `0.3`   | A player who took a detour still gets a let if they ended up this much further from the ball than they were when it came off the front wall. |
| `body`        | `0.25`  | Size of a player's body for the ball hitting them.                                                                                           |

## Court and ball physics

{% hint style="danger" %}
Leave `Config.Court` and `Config.Physics` alone. The server and every player's game work out the flight of the ball on their own from these numbers, so all of them must use the same ones, and everything above is tuned for exactly these values.
{% endhint %}

`Config.Court` is the official singles court (9.75 x 6.40 m) with its lines. `Config.Physics` holds gravity, air resistance, how the ball bounces off the walls and the floor, and `pace`: the game speed in %, where `90` makes every ball fly 10% slower. `pace` is the one value here that is safe to change if the game feels too fast or too slow on your server.
