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

# Configuration

Every option of Cuxial Multichar: slots, Discord, registration, minors, spawn, scene and loading screen.

Everything is set in `shared/config.lua`. Locations, loading screen content and nationalities live in the `data` folder. Restart the resource after any change.

## General

| Option      | Type     | Default      | What it does                                                                                                                                    |
| ----------- | -------- | ------------ | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| `debug`     | boolean  | `false`      | Prints debug messages in the console                                                                                                            |
| `ui.accent` | string   | configurable | Accent colour of the interface and the loading screen, as a hex colour                                                                          |
| `hud`       | function | empty        | Called with `false` when the selection opens and with `true` when it closes. Use it to hide and show your HUD. The minimap is hidden without it |

{% code title="shared/config.lua" %}

```lua
hud = function(visible)
    exports.my_hud:setVisible(visible)
end,
```

{% endcode %}

## Characters

| Option                   | Type    | Default | What it does                                    |
| ------------------------ | ------- | ------- | ----------------------------------------------- |
| `characters.slots`       | number  | `3`     | Characters any player can have                  |
| `characters.maxSlots`    | number  | `10`    | Absolute cap. No role or user ID goes above it  |
| `characters.allowDelete` | boolean | `true`  | `true` lets players delete their own characters |

## Discord slots

Gives more characters to specific Discord roles or users.

| Option                      | Type    | Default | What it does                                                                      |
| --------------------------- | ------- | ------- | --------------------------------------------------------------------------------- |
| `discordSlots.enabled`      | boolean | `false` | `true` enables extra slots by role and by user ID                                 |
| `discordSlots.roles`        | list    | empty   | `{ id = 'ROLE_ID', slots = N }` entries. Needs the bot convars                    |
| `discordSlots.users`        | table   | empty   | `['DISCORD_USER_ID'] = N` entries. Works without the bot                          |
| `discordSlots.cacheMinutes` | number  | `10`    | Minutes the roles of a player are remembered before asking Discord again          |
| `discordSlots.timeoutMs`    | number  | `4000`  | Milliseconds to wait for Discord. With no answer, the player keeps the base slots |

How the final number is calculated:

* `slots` in a role or a user is the **total** number of characters, not an addition.
* If a player matches several entries, the highest number wins.
* The result is never lower than `characters.slots` and never higher than `characters.maxSlots`.
* The player needs Discord linked to FiveM. Without it, they get the base slots.

{% hint style="info" %}
The bot token and the server ID are convars, not config options. See [Installation](/scripts/core/cuxial-multichar/installation.md).
{% endhint %}

## Registration

| Option                           | Type    | Default        | What it does                                            |
| -------------------------------- | ------- | -------------- | ------------------------------------------------------- |
| `register.name.min` / `max`      | number  | `2` / `32`     | Length allowed for first name and last name             |
| `register.dob.format`            | string  | `"DD-MM-YYYY"` | Date format: `DD-MM-YYYY`, `YYYY-MM-DD` or `MM-DD-YYYY` |
| `register.dob.minYear`           | number  | `1950`         | Oldest year of birth accepted                           |
| `register.minAge`                | number  | `18`           | Minimum age of an adult character                       |
| `register.height.enabled`        | boolean | `true`         | Shows the height field                                  |
| `register.height.min` / `max`    | number  | `150` / `200`  | Height range in cm                                      |
| `register.backstory.enabled`     | boolean | `true`         | Shows the backstory field                               |
| `register.backstory.min` / `max` | number  | `10` / `300`   | Length allowed for the backstory                        |

The nationality list is in `data/nationalities.lua`.

## Minor characters

A minor is created as a request. The player picks the parents and writes a motivation, and staff approve or reject it. Until it is approved, the character cannot be played.

| Option                          | Type    | Default                      | What it does                                                                        |
| ------------------------------- | ------- | ---------------------------- | ----------------------------------------------------------------------------------- |
| `family.enabled`                | boolean | `true`                       | Enables minor characters                                                            |
| `family.minAge` / `maxAge`      | number  | `6` / `17`                   | Age range of a minor                                                                |
| `family.motivation.min` / `max` | number  | `30` / `600`                 | Length allowed for the motivation                                                   |
| `family.height.min`             | number  | `100`                        | Minimum height of a minor in cm                                                     |
| `family.height.max`             | table   | `male = 168`, `female = 158` | Maximum height by gender                                                            |
| `family.adultHeight`            | table   | `male = 182`, `female = 170` | Reference adult height. The character is scaled as its height divided by this value |
| `family.growthCommand`          | string  | `"height"`                   | Command the minor uses to change height. `false` removes it                         |
| `family.scaleRadius`            | number  | `60.0`                       | Distance in metres within which other players are shown scaled                      |
| `family.rejectCooldownHours`    | number  | `24`                         | Hours to wait after a rejection before sending a new request. `0` disables it       |
| `family.allowOwnParent`         | boolean | `false`                      | `true` lets a player choose their own characters as parents                         |
| `family.maxPending`             | number  | `1`                          | Pending requests allowed per player                                                 |

Requests are reviewed through the [exports](/scripts/core/cuxial-multichar/developers.md).

## Spawn

| Option                    | Type             | Default  | What it does                                                                                                                                                                                                       |
| ------------------------- | ---------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `spawn.newCharacter`      | vec4             | —        | Where a new character is placed while the appearance creator opens                                                                                                                                                 |
| `spawn.birth`             | vec4             | —        | Where a new character appears after the creator. `false` skips this move                                                                                                                                           |
| `spawn.registerPreview`   | vec4             | —        | Where the character stands during creation                                                                                                                                                                         |
| `spawn.registerReference` | vec4             | —        | Where the adult reference stands when setting a minor's height                                                                                                                                                     |
| `spawn.fallback`          | vec4             | —        | Used when a character has no saved position or no location is available                                                                                                                                            |
| `spawn.apartments`        | string / boolean | `"auto"` | `"auto"` uses starting apartments if `qbx_properties` is running and the framework has them enabled. `true` / `false` forces it. With apartments, the appearance creator and the move to `spawn.birth` are skipped |

Existing characters always spawn at their last saved position.

## Scene

| Option                   | Type    | Default                      | What it does                                                                                       |
| ------------------------ | ------- | ---------------------------- | -------------------------------------------------------------------------------------------------- |
| `scene.randomLocation`   | boolean | `true`                       | `true` picks a random location each time. `false` always uses the first one in the list            |
| `scene.emotes`           | list    | `texting`, `idle3`, `smoke2` | Emote commands played at random when the location has no `emote` of its own. Needs `cuxial_emotes` |
| `scene.fallbackScenario` | string  | `"WORLD_HUMAN_STAND_MOBILE"` | Scenario used when `cuxial_emotes` is not running                                                  |
| `scene.posture`          | string  | `"side"`                     | `"side"` keeps the heading of the location. `"front"` turns the character towards the camera       |
| `scene.depthOfField`     | boolean | `true`                       | Background blur. The player can turn it off with FPS mode                                          |
| `scene.cameraDistance`   | number  | `2`                          | Default camera distance: `1` near, `2` far                                                         |

### Locations

`data/locations.lua` holds the places where characters are shown.

{% code title="data/locations.lua" %}

```lua
{ label = 'Rockford Hills', coords = vec4(-852.73, -226.99, 61.02, 354.04) },

{
    label = 'Police station',
    coords = vec4(444.37, -984.33, 30.69, 71.35),
    groups = { 'police' },
    emote = { scenario = 'WORLD_HUMAN_COP_IDLES' },
},
```

{% endcode %}

| Field                                        | What it does                                                                                                                       |
| -------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| `label`                                      | Name of the location                                                                                                               |
| `coords`                                     | Position and heading of the character                                                                                              |
| `groups`                                     | Job or gang names. The location is only used for characters in one of them, and those characters only get locations of their group |
| `emote`                                      | `{ command = '...' }` for an emote or `{ scenario = '...' }` for a GTA scenario                                                    |
| `camera`                                     | `front` (default), `back`, `close` or `free`                                                                                       |
| `cameraCoords`, `fov`, `focusOffset`, `blur` | Camera position and lens, only with `camera = 'free'`. `cameraCoords` is required in that mode                                     |
| `scene`                                      | `'bar'` plays the leaning animation with props defined in `data/scenes.lua`                                                        |

`data/vehicle_locations.lua` holds the spots used when the character poses with a vehicle. `data/scenes.lua` holds the animations for the bar, couple, best friend and vehicle scenes.

## ID card, vehicles and partner

| Option                     | Type             | Default                       | What it does                                                                                        |
| -------------------------- | ---------------- | ----------------------------- | --------------------------------------------------------------------------------------------------- |
| `idCard.enabled`           | boolean          | `true`                        | Shows the real ID card while creating a character                                                   |
| `idCard.resource`          | string           | `"cuxial_license"`            | Resource that provides the card                                                                     |
| `idCard.item`              | string           | `"id_card"`                   | Item whose card is used                                                                             |
| `idCard.cardId`            | string           | `nil`                         | Specific card ID. `nil` picks it from the item                                                      |
| `vehicles.enabled`         | boolean          | `true`                        | Lets players pick an owned vehicle for the scene                                                    |
| `vehicles.resource`        | string           | `"cuxial_garages"`            | Resource that must be running for this feature                                                      |
| `vehicles.spotCommand`     | string / boolean | `false`                       | Command name that copies your current `vec4` to the clipboard, to fill `data/vehicle_locations.lua` |
| `partner.enabled`          | boolean          | `true`                        | Enables couple and best friend scenes                                                               |
| `partner.maxDistance`      | number           | `10.0`                        | Maximum distance in metres to invite someone                                                        |
| `partner.inviteSeconds`    | number           | `60`                          | Seconds an invitation stays open                                                                    |
| `partner.invitesPerMinute` | number           | `3`                           | Invitations a player can send per minute                                                            |
| `partner.commands.invite`  | string           | `"partnerinvite"`             | Name of the invite command                                                                          |
| `partner.commands.force`   | table            | `forcepartner`, `group.admin` | `name` and `restricted` (permission) of the staff command                                           |

## World

Weather and time shown in the selection. Each player can change them in their settings.

| Option                  | Type    | Default     | What it does                                         |
| ----------------------- | ------- | ----------- | ---------------------------------------------------- |
| `world.enabled`         | boolean | `true`      | `false` leaves the server weather and time untouched |
| `world.weather`         | string  | `"XMAS"`    | GTA weather type                                     |
| `world.hour` / `minute` | number  | `23` / `30` | Time of day                                          |

## Loading screen and music

| Option              | Type    | Default | What it does                                                                            |
| ------------------- | ------- | ------- | --------------------------------------------------------------------------------------- |
| `loading.enabled`   | boolean | `true`  | `false` closes the loading screen right away                                            |
| `loading.autoEnter` | boolean | `false` | `true` enters the selection without the start button                                    |
| `loading.handoffMs` | number  | `2400`  | Duration of the transition to the selection, in milliseconds                            |
| `loading.timeoutMs` | number  | `60000` | Safety limit in milliseconds. The loading screen closes if the transition never arrives |
| `loading.debug`     | boolean | `false` | Debug output of the loading screen                                                      |
| `music.enabled`     | boolean | `true`  | Music in the loading screen and the selection                                           |
| `music.file`        | string  | `""`    | Path inside `web/build` of the track used when `data/loading.lua` has no track list     |
| `music.scale`       | number  | `0.35`  | Volume multiplier applied over the player's volume                                      |
| `music.analyse`     | boolean | `true`  | Makes the interface react to the beat                                                   |

Content is edited in `data/loading.lua`:

| Field                        | What it does                                                                                          |
| ---------------------------- | ----------------------------------------------------------------------------------------------------- |
| `background.video`           | Video file inside `web/build`, or a URL. Empty by default: no video, a dark background with particles |
| `background.dim`, `blur`     | Darkening (0 to 1) and blur of the video                                                              |
| `background.loop`, `startAt` | Loop the video and second where it starts                                                             |
| `background.sound`           | `'auto'` detects whether the video has sound. `true` / `false` forces it                              |
| `background.title`, `artist` | Shown in the player when the video carries the sound                                                  |
| `tipSeconds`                 | Seconds each tip stays on screen                                                                      |
| `tracks`                     | Playlist: `{ id, url, title, artist }`. Empty by default: no music                                    |
| `tips`                       | Tips: `{ id, category, title, text }`                                                                 |
| `keys`                       | Key guide: `{ id, keys, label, category, description }`                                               |

{% hint style="info" %}
The package includes no video or music. Put your own files in `web/build/video` and `web/build/music`, creating the folders if they are missing, and list them in `data/loading.lua`. Use `.webm` video and `.ogg` audio.
{% endhint %}

## Starter items, commands and logs

| Option                  | Type    | Default                              | What it does                                                                                                                                   |
| ----------------------- | ------- | ------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| `starterItems`          | list    | `phone`, `id_card`, `driver_license` | `{ item, amount }`. `identity = true` fills the item with the character's name, date of birth and nationality. `metadata` sets custom metadata |
| `commands.logout`       | table   | `logout`, `group.admin`              | `name` and `restricted` (permission) of the command. `restricted = false` opens it to everyone                                                 |
| `commands.logoutPlayer` | table   | `logoutplayer`, `group.admin`        | `name` and `restricted` (permission) of the command                                                                                            |
| `logs.enabled`          | boolean | `true`                               | Sends logs to Discord when the webhook convar is set                                                                                           |
| `logs.convar`           | string  | `"cuxial_multichar_webhook"`         | Name of the convar that holds the webhook                                                                                                      |
| `logs.username`         | string  | `"Multicharacter"`                   | Name shown by the webhook                                                                                                                      |

## Common changes

{% tabs %}
{% tab title="More slots for a role" %}

```lua
discordSlots = {
    enabled = true,
    roles = {
        { id = '123456789012345678', slots = 5 },
    },
},
```

{% endtab %}

{% tab title="Disable minors" %}

```lua
family = {
    enabled = false,
    -- ...
},
```

{% endtab %}

{% tab title="Let players use /logout" %}

```lua
commands = {
    logout = { name = "logout", restricted = false },
    logoutPlayer = { name = "logoutplayer", restricted = "group.admin" },
},
```

{% endtab %}

{% tab title="Different starter items" %}

```lua
starterItems = {
    { item = "phone", amount = 1 },
    { item = "water", amount = 2 },
    { item = "id_card", amount = 1, identity = true },
},
```

{% endtab %}
{% endtabs %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.cuxial.com/scripts/core/cuxial-multichar/configuration.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
