# Kivo Multi Character

Cinematic multicharacter system for FiveM. Handles character selection, creation, and deletion with animated scene backdrops and routing bucket isolation. Supports ESX, QBCore, and QBX with auto-detection.

## Installation Steps

{% stepper %}
{% step %}

### Remove conflicting scripts

Remove or comment out any of the following from `server.cfg` before installing:

* `esx_identity` — kivo-multi-char handles identity internally
* `esx_multicharacter` — replaced by this script
* `qb-multicharacter` — replaced by this script
* Any other multicharacter resource currently running on your server
  {% endstep %}

{% step %}

### Place the resource

```
resources/
  [kivo]/
    kivo-multi-char/
```

{% endstep %}

{% step %}

### Import SQL

Run the following on your database. **The resource auto-creates this table on first start**, but you can run it manually to inspect or seed it:

```sql
CREATE TABLE IF NOT EXISTS `kivo_player_slots` (
    `license`    VARCHAR(60)      NOT NULL,
    `slots`      TINYINT UNSIGNED NOT NULL DEFAULT 3,
    `created_at` TIMESTAMP        NOT NULL DEFAULT CURRENT_TIMESTAMP,
    `updated_at` TIMESTAMP        NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    PRIMARY KEY (`license`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
```

{% endstep %}

{% step %}

### Configure

Open `config.lua` and set the following:

```lua
Config.maxChars           = 5             -- hard cap per player
Config.defaultSlots       = 3             -- default slots before any DB override
Config.spawnSelector      = 'kivo-spawn'  -- 'kivo-spawn' | 'default' | 'custom'
Config.useIdentityCreator = true          -- false = use lib.inputDialog fallback
Config.defaultScene       = 'scene_2'     -- which scene loads on connect

Config.defaultMoney = { cash = 500, bank = 5000 }
Config.defaultJob   = { name = 'unemployed', grade = 0 }
```

{% endstep %}

{% step %}

### Add to server.cfg

{% tabs %}
{% tab title="QBX" %}

```
ensure oxmysql
ensure ox_lib
ensure qbx_core
ensure kivo-multi-char
ensure kivo-identity-creator   # only if useIdentityCreator = true
ensure kivo-spawn              # only if spawnSelector = 'kivo-spawn'
```

{% endtab %}

{% tab title="QBCore" %}

```
ensure oxmysql
ensure ox_lib
ensure qb-core
ensure kivo-multi-char
ensure kivo-identity-creator
ensure kivo-spawn
```

Do **not** add `spawnmanager` for QBCore.
{% endtab %}

{% tab title="ESX" %}

```
ensure mapmanager
ensure spawnmanager
ensure oxmysql
ensure ox_lib
ensure es_extended
ensure kivo-multi-char
ensure kivo-identity-creator
ensure kivo-spawn
```

{% endtab %}
{% endtabs %}
{% endstep %}
{% endstepper %}

## Features

* Auto-detects QBX / QBCore / ESX — no manual framework config required
* Routing bucket isolation during character selection
* Configurable cinematic scenes with per-slot animated pedestals
* Per-player character slot management via `kivo_player_slots` DB table
* `addslot` / `removeslot` server console commands
* Integrates with kivo-identity-creator for the character creation NUI
* Integrates with kivo-spawn (or any custom spawn selector) after character selection
* Demo mode and demo server mode for testing without a live framework

## Config Reference

| Key                         | Default        | Description                                       |
| --------------------------- | -------------- | ------------------------------------------------- |
| `Config.maxChars`           | `5`            | Hard cap on characters per player                 |
| `Config.defaultSlots`       | `3`            | Default slot count before any DB override         |
| `Config.bucket`             | `732`          | Routing bucket used during character selection    |
| `Config.defaultScene`       | `'scene_2'`    | Scene to load on connect                          |
| `Config.spawnSelector`      | `'kivo-spawn'` | Spawn system used after character login           |
| `Config.useIdentityCreator` | `true`         | Use kivo-identity-creator NUI for char creation   |
| `Config.defaultSpawn`       | Legion Square  | Fallback spawn if character has no saved position |
| `Config.esxNewCharSpawn`    | `nil`          | ESX only — spawn during first-character creation  |
| `Config.defaultMoney.cash`  | `500`          | Starting cash for new characters                  |
| `Config.defaultMoney.bank`  | `5000`         | Starting bank balance for new characters          |
| `Config.defaultJob.name`    | `'unemployed'` | Starting job for new characters                   |

## Kivo Suite Integration

### kivo-spawn

Set `Config.spawnSelector = 'kivo-spawn'`. After a character is selected, kivo-multi-char fires:

```lua
TriggerEvent('kivo:client:readyForSpawn', spawnCoords, false, Config.demoServer)
```

kivo-spawn receives this and opens its location picker. If kivo-spawn is not running the bridge falls back to `'default'` automatically.

### kivo-identity-creator

Set `Config.useIdentityCreator = true`. On "Create Character", kivo-multi-char opens the identity creator NUI. On confirm, `kivo-multichar:identityCreated` fires back and kivo-multi-char writes the character to the DB.

Set `Config.useIdentityCreator = false` to skip this resource entirely and use `lib.inputDialog` instead.

### Custom spawn selector

Set `Config.spawnSelector = 'custom'` and edit `SpawnBridge.custom()` in `shared/spawnbridge.lua`:

```lua
function SpawnBridge.custom(spawnCoords)
    TriggerEvent('mySpawn:openSelector', spawnCoords)
end
```

## Console Commands

Server console only. Changes take effect on the player's next connection.

| Command                         | Description                             |
| ------------------------------- | --------------------------------------- |
| `addslot <license> [amount]`    | Grant extra character slots to a player |
| `removeslot <license> [amount]` | Revoke character slots (floor: 1)       |

Manual DB management:

```sql
-- Set an exact slot count
INSERT INTO kivo_player_slots (license, slots) VALUES ('license:abc123', 5)
ON DUPLICATE KEY UPDATE slots = 5;

-- Remove override (reverts to Config.defaultSlots)
DELETE FROM kivo_player_slots WHERE license = 'license:abc123';

-- View all overrides
SELECT * FROM kivo_player_slots ORDER BY slots DESC;
```

## Demo Mode

| Mode        | Config                     | Description                                                            |
| ----------- | -------------------------- | ---------------------------------------------------------------------- |
| UI Demo     | `Config.demo = true`       | Uses mock data from `config_demo.lua` — no DB or framework needed      |
| Demo Server | `Config.demoServer = true` | QBX only — shows Michael / Trevor / Franklin, direct teleport on spawn |

## Troubleshooting

1. **Player stuck on loading screen**
   * Ensure `ShutdownLoadingScreen()` is called before the multichar UI opens
   * Quick fix: add `setr loadscreen:externalShutdown "false"` to `server.cfg`
2. **`ssn NOT NULL` INSERT failure (ESX)**

   ```sql
   ALTER TABLE `users` MODIFY `ssn` VARCHAR(15) NULL DEFAULT NULL;
   ```
3. **Characters return empty on login**
   * Framework not fully started yet — ensure kivo-multi-char loads **after** your framework core in `server.cfg`
4. **Spawn fires but player never enters the world**
   * kivo-spawn is not running — set `Config.spawnSelector = 'default'` or start kivo-spawn
5. **Duplicate identity or character conflict (ESX)**
   * Remove `ensure esx_identity` from `server.cfg`

## Checklist

* [ ] Removed `esx_identity`, `esx_multicharacter`, `qb-multicharacter` from `server.cfg`
* [ ] SQL table `kivo_player_slots` created
* [ ] `Config.spawnSelector` matches the spawn resource you are running
* [ ] `Config.useIdentityCreator` matches whether kivo-identity-creator is installed
* [ ] kivo-multi-char loads after your framework core
* [ ] kivo-identity-creator loads after kivo-multi-char (if used)
* [ ] kivo-spawn loads after kivo-multi-char (if used)
* [ ] `spawnmanager` removed for QBCore / QBX
* [ ] Tested with a fresh character and a returning character


---

# Agent Instructions: Querying This Documentation

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

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.kivostudios.net/scripts/kivo-multi-character.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
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.
