# Configuration

The options live in `shared/config.lua` and in the files of `shared/config/`. Call scenarios are in `shared/scenarios.lua` and `shared/scenarios/*.lua`, call locations in `shared/locations.lua`. These files, `server/bridge.lua`, `locales/` and `compat/` are not escrowed, so you can edit them freely. Restart the resource after changes.

| File | Purpose |
|---|---|
| `shared/config.lua` | Core options: access, modes, stations, departments, units, AI fleet, calls, pay, AI callers, koja-mdt, 3D map |
| `shared/config/career.lua` | `Config.Career`: ranks, XP and unlocks |
| `shared/config/dynamics.lua` | `Config.Dynamics`: call events, stages, weather and time weighting |
| `shared/config/editors.lua` | `Config.Editors`: limits of the scenario and fleet editors |
| `shared/config/fleet.lua` | `Config.Fleet`, `Config.Mci`, `Config.HospitalBeds` |
| `shared/config/integrations.lua` | `Config.Phones`, `Config.Compat`, `Config.Discord` |
| `shared/config/mdt.lua` | `Config.MdtStatus`, `Config.MdtTools` |
| `shared/config/pursuit.lua` | `Config.Pursuit`, `Config.Patrol` |
| `shared/config/stats.lua` | `Config.Stats` |
| `shared/config/training.lua` | `Config.Training` |
| `shared/config/voice.lua` | `Config.Voice` |
| `shared/scenarios.lua`, `shared/scenarios/*.lua` | Call scenarios: lines, answers, hidden needs, correct instruction, timings, escalation, scene |
| `shared/locations.lua` | Places where generated calls happen, with tags (store, bank, residential...) |
| `server/custom/*.lua`, `client/custom/*.lua` | Your own code. Loaded after the built-in files, with access to the same `KOJA`, `Config` and exports. |

:::hint{type="info" title="Config and the admin menu"}
Many options can also be changed in game with `/dispatchadmin`. The config value is the default. Once a value is saved in the admin menu, the database value wins until you press **Reset to default** for it, or **Reset all settings**. The admin key of each option is listed in [Admin menu](/new/dispatcher/admin-menu#all-settings).
:::

:::hint{type="warning" title="No secrets in config files"}
`shared/` is sent to every player. API keys and webhook URLs go in `server.cfg` as convars with `set`. See [Installation](/new/dispatcher/installation).
:::

## General

| Option | Default | Description |
|---|---|---|
| `Config.Debug` | `false` | Prints extra debug lines in the server console. |
| `Config.Locale` | `'en'` | Language file from `locales/`. See [Translations](/new/dispatcher/translations). |
| `Config.VersionCheck.enabled` | `true` | Runs the version check through koja-lib after start and prints the result. |

### Config.Admin

| Option | Default | Description |
|---|---|---|
| `command` | `'dispatchadmin'` | Command that opens the admin menu. |
| `groups` | `{ 'admin', 'god', 'superadmin' }` | Framework groups that may open it. |
| `ace` | `'koja-dispatcher.admin'` | ACE that also grants access. |

### Config.Modes

Defaults of the three modes. Explained in [Admin menu](/new/dispatcher/admin-menu#modes).

| Option | Default | Values |
|---|---|---|
| `calls` | `'mixed'` | `'generated'`, `'real'`, `'mixed'` |
| `units` | `'mixed'` | `'ai'`, `'players'`, `'mixed'` |
| `noDispatcher` | `'reject'` | `'reject'`, `'auto'`, `'mdt'` |

### Config.Dispatcher

| Option | Default | Description |
|---|---|---|
| `jobs` | `{ dispatch = 0, police = 4, ambulance = 4 }` | Jobs allowed to work as dispatcher, with the lowest grade. Replaced by the list saved in the admin menu. Only these players see the start prompt at a station. |
| `setDuty` | `true` | Sets the framework job duty on when a shift starts and off when it ends. |
| `maxDispatchers` | `0` | Dispatchers on shift at the same time. `0` means no limit. |
| `remote` | `false` | Allows the remote CAD: allowed jobs open the CAD anywhere with `remoteCommand`, without a station. |
| `remoteCommand` | `'cad'` | Remote CAD command. Empty string removes the command. |
| `consoleRange` | `3.0` | Distance in metres to a station to start a shift. Walking more than `consoleRange + 4` away ends the shift. |

### Config.Keys

Default keys. Players can rebind them in the FiveM key bindings. See [Commands and keybinds](/new/dispatcher/commands-and-keybinds).

| Option | Default | Description |
|---|---|---|
| `console` | `'F7'` | Reopen the CAD while on shift. |
| `acknowledge` | `'Y'` | Field unit: acknowledge the assignment and set the GPS. |
| `code4` | `''` | Field unit: report code 4. Unbound by default, `/code4` works. |

### Config.Consoles

Default dispatch stations, used until a station is saved in the admin menu. Each entry:

| Field | Example | Description |
|---|---|---|
| `id` | `'mrpd'` | Unique id. |
| `label` | `'Mission Row Communications'` | Name shown on the station screen and in the CAD. |
| `coords` | `vector4(441.09, -978.86, 30.69, 180.0)` | Position and heading of the dispatcher. |
| `pose` | `'stand'` | `'stand'` or `'sit'`. |
| `blip` | `{ enabled = true, sprite = 459, color = 3, scale = 0.75 }` | Map blip. |

### Config.StationPanel

The in-world screen over each station that shows whether it is free, who is on shift and how to start.

| Option | Default | Description |
|---|---|---|
| `enabled` | `true` | Show the screen. |
| `distance` | `12.0` | Distance in metres at which the screen is drawn for the nearest station. |
| `height` | `1.3` | Height of the screen above the station position. |
| `width` | `640` | Width of the screen page in pixels. |
| `pixels` | `360` | Height of the screen page in pixels. |

### Config.Cinematic

The camera fly-in when a shift starts.

| Option | Default | Description |
|---|---|---|
| `enabled` | `true` | Play the intro. Also the admin setting `features.cinematic`. Players can skip it for themselves in the CAD settings. |
| `skippable` | `true` | Space or Enter skips it. |
| `approachDuration` | `4500` | Milliseconds of the flight from the establishing shot to the shoulder. |
| `settleDuration` | `1500` | Milliseconds of the shoulder shot. |
| `screenDuration` | `1300` | Milliseconds of the move onto the monitor. |

## Departments and units

### Config.Departments

The three departments. A player is a field unit when their job is in `jobs` and they are on duty.

| Key | Label | Color | Jobs | Callsign prefix | Blip color |
|---|---|---|---|---|---|
| `police` | `'Police'` | `'#3d8bff'` | `police`, `sheriff` | `'ADAM'` | `3` |
| `ems` | `'EMS'` | `'#ff5d6c'` | `ambulance` | `'MEDIC'` | `1` |
| `fire` | `'Fire'` | `'#ff9f2e'` | `fire` | `'ENGINE'` | `17` |

Fields: `label`, `color` (CAD color), `jobs` (framework jobs), `prefix` (default player callsign is `<prefix>-<server id>`), `blipColor`.

### Config.UnitTypes

| Type | Department | Label | Speed | Power | Notes |
|---|---|---|---|---|---|
| `patrol` | police | Patrol | `24.0` | `1` | |
| `k9` | police | K9 | `22.0` | `1` | |
| `swat` | police | SWAT | `18.0` | `2` | |
| `air` | police | Air | `55.0` | `1` | `direct = true`, flies straight |
| `ambulance` | ems | Ambulance | `22.0` | `1` | |
| `medic_air` | ems | Air ambulance | `50.0` | `1` | `direct = true` |
| `engine` | fire | Engine | `17.0` | `1` | |
| `ladder` | fire | Ladder | `15.0` | `2` | |
| `player` | any | Field unit | `0.0` | `1` | Real players |

`speed` is the travel speed of AI units in metres per second. `power` is how much a unit counts toward an incident's needs: a SWAT van counts as two police units. `direct` units ignore the road network.

### Config.Units

| Option | Default | Description |
|---|---|---|
| `arriveRadius` | `35.0` | Metres from the incident at which a unit is on scene. |
| `searchRadius` | `350.0` | Radius units search when the exact location was never asked. |
| `searchSeconds` | `12` | Seconds units search the area before they find an unlocated scene. |
| `roadFactor` | `1.35` | Without road routing, AI speed is divided by this to imitate road distance. |
| `trackInterval` | `1000` | Milliseconds between reads of player unit positions. |
| `membershipInterval` | `5000` | Milliseconds between checks of who is an on-duty field unit. |

### Config.Roads

AI ground units drive along the game's road network (`data/roads.json`, loaded on the server only).

| Option | Default | Description |
|---|---|---|
| `enabled` | `true` | Use road routing. `false` makes units drive in a straight line. |
| `file` | `'data/roads.json'` | Road graph file. |
| `cellSize` | `150.0` | Grid cell size for finding the nearest road. |
| `maxSnapRings` | `12` | How many grid rings are searched for the nearest road. |
| `zWeight` | `0.5` | Weight of the height difference when snapping (keeps units off bridges above them). |
| `speedFactor` | `{ [0] = 0.6, 0.9, 1.15, 1.45 }` | Speed multiplier per road class, from small roads to freeways. |
| `maxExpansions` | `20000` | Search limit of one route. |
| `cacheSize` | `64` | Routes kept in the cache. |

### Config.AiUnits

| Option | Default | Description |
|---|---|---|
| `enabled` | `true` | Spawn the AI fleet. |
| `disableWhenPlayers` | `3` | AI units of a department go off duty while this many players of that department are on duty. `0` never. Only used when units are `mixed`. |
| `stations` | 11 stations | `id = { label, coords }`: `mrpd`, `vespucci`, `sandy`, `paleto` (police), `pillbox`, `zonah`, `sandy_med` (EMS), `fs7`, `davis_fire`, `sandy_fire`, `paleto_fire` (fire). |
| `fleet` | 19 units | `{ callsign, type, station }`. Five units at Mission Row (two patrols, K9, SWAT, AIR-1), two patrols in Vespucci, one in Sandy and one in Paleto, five ambulances and LIFEFLIGHT, two engines and a ladder at Station 7, and one engine each in Davis, Sandy and Paleto. |

The fleet can also be edited in game. Once the **AI fleet** page of the admin menu takes over, `stations` and `fleet` from this file are no longer used. See [Admin menu](/new/dispatcher/admin-menu#ai-fleet).

### Config.Hospitals

List of `vector3` hospital positions where ambulances take patients: Pillbox, Mount Zonah, Central Los Santos, Sandy Shores and Paleto Bay. With hospital beds on, `Config.HospitalBeds.list` is used as well.

## Calls and incidents

### Config.Calls

| Option | Default | Description |
|---|---|---|
| `generate` | `true` | Master switch for generated AI calls. |
| `intervalMin` | `35` | Shortest gap in seconds between generated calls. |
| `intervalMax` | `80` | Longest gap in seconds. |
| `perDispatcherSpeedup` | `0.15` | Calls come this much faster for every extra dispatcher on shift. |
| `maxRinging` | `4` | No new generated call while this many are ringing. |
| `maxActiveIncidents` | `10` | No new generated call while this many incidents are open. |
| `patience` | `45` | Seconds a generated caller waits before hanging up (a missed call). |
| `approximateRadius` | `300.0` | Size of the approximate area shown before the dispatcher asks for the location. |
| `playerCommand` | `'911'` | Command players use to call 911. |
| `playerReplyWindow` | `180` | Seconds a player's 911 text line stays open. Another `/911` in that window is added to the same call. |

Generated calls only come while at least one dispatcher is on shift.

### Config.Incidents

| Option | Default | Description |
|---|---|---|
| `lifetimeAfterEnd` | `20` | Seconds a closed incident stays visible before it is removed. |
| `maxLog` | `40` | Radio log lines kept. |

### Config.Field

What field units (players) get when they are dispatched.

| Option | Default | Description |
|---|---|---|
| `notify` | `true` | Play a sound with the assignment toast. |
| `waypoint` | `true` | Draw a GPS route to the incident blip. Also the admin setting `features.fieldWaypoint`. |
| `scenes` | `true` | Spawn the scene (injured, brawlers, crowd, fire, wrecks) when a player unit gets close. Also `features.fieldScenes`. |
| `sceneRadius` | `140.0` | Distance at which the scene spawns. |

### Config.Sensors

Witness calls from what happens in the world. A sensor only creates a call when a dispatcher can take it (someone on shift and call sources are not `generated`). Each sensor has a cooldown per player. The `enabled` values are the defaults of the admin switches `features.sensorDowned`, `features.sensorShots` and `features.sensorCrash`, which apply live.

| Option | Default | Description |
|---|---|---|
| `downed.enabled` | `true` | A player down for `delay` seconds triggers a call. |
| `downed.delay` | `25` | Seconds down before the call. |
| `downed.chance` | `0.7` | Chance that a witness calls. |
| `downed.cooldown` | `300` | Seconds between calls for one player. |
| `downed.ignoreDepartments` | `false` | `true` ignores on-duty police, EMS and fire. |
| `shots.enabled` | `true` | Gunfire triggers a call. |
| `shots.chance` | `0.45` | Chance that a witness calls. |
| `shots.cooldown` | `90` | Seconds between calls for one player. |
| `shots.ignoreDepartments` | `true` | Ignore on-duty police, EMS and fire. |
| `shots.ignoreSuppressed` | `true` | Silenced weapons do not trigger calls. |
| `crash.enabled` | `true` | A hard vehicle crash triggers a call. |
| `crash.chance` | `0.35` | Chance that a witness calls. |
| `crash.cooldown` | `120` | Seconds between calls for one player. |
| `crash.minSpeedLoss` | `55.0` | Speed loss in km/h that counts as a crash. |

### Config.Map

| Option | Default | Description |
|---|---|---|
| `showCivilians` | `true` | Players without a service job appear as dots. Admin `features.showCivilians`. |
| `showNpcPeds` | `false` | Show networked NPC peds. Costs performance. Admin `features.showNpcPeds`. |
| `npcLimit` | `250` | Maximum NPC peds sent to the map. |
| `npcInterval` | `3000` | Milliseconds between NPC updates. |

### Config.Score

Points for the dispatcher's shift score.

| Option | Default | Description |
|---|---|---|
| `resolved` | `1.0` | Multiplier of the incident's points when it is resolved. |
| `fastBonusSeconds` | `90` | First unit on scene within this many seconds gives the fast bonus. |
| `fastBonus` | `0.5` | Fast bonus: +50 % points. |
| `failed` | `-1.0` | Multiplier of the incident's points when it fails. |
| `missedCall` | `-25` | A generated call that rang out or was hung up. Pressing **Prank** on a generated call that is not a prank costs double. |
| `correctCode` | `20` | The call was classified with the right category. |
| `wrongCode` | `-10` | Wrong category. |
| `prankCaught` | `30` | A prank call caught with the prank button. |
| `prankDispatched` | `-40` | A prank call dispatched anyway. |
| `goodInstruction` | `15` | The right pre-arrival instruction. |
| `badInstruction` | `-10` | A wrong instruction. |

### Config.Pay

Paid when the shift ends: `(perMinute × minutes + perPoint × score)`, multiplied by `0.6 + 0.1 × star rating`, capped at `maximum`.

| Option | Default | Description |
|---|---|---|
| `enabled` | `true` | Pay dispatchers. |
| `account` | `'bank'` | Account that receives the money. |
| `perMinute` | `6` | Money per minute on shift. |
| `perPoint` | `2` | Money per score point (negative scores pay nothing extra). |
| `minimumMinutes` | `3` | Shorter shifts are not paid. |
| `maximum` | `15000` | Highest payout per shift. `0` means no cap. |

### Config.Security

Every request from the CAD is rate limited per player with a token bucket.

| Option | Default | Description |
|---|---|---|
| `burst` | `10` | Bucket size. |
| `perSecond` | `6` | Refill per second. |
| `limits` | per request | Stricter `{ burst, perSecond }` per request name, for example `['field:911'] = { 2, 0.05 }` (one `/911` every 20 seconds after the burst). The files in `shared/config/` add limits for their own requests. |

### Config.Avatars

Character headshots shown in the CAD and on the station screen.

| Option | Default | Description |
|---|---|---|
| `enabled` | `true` | Take and store headshots. |
| `transparent` | `true` | Transparent background. |
| `size` | `128` | Image size in pixels. |
| `format` | `'image/webp'` | Image format. |
| `quality` | `0.85` | Image quality. |
| `captureDelaySeconds` | `3` | Delay before the capture. |
| `refreshMinutes` | `60` | A stored headshot older than this is taken again. |
| `sweepSeconds` | `60` | How often the server looks for units and dispatchers without a headshot. |
| `minUploadSeconds` | `60` | Minimum seconds between uploads from one player. |
| `maxLength` | `150000` | Largest accepted image in characters. |
| `batch` | `24` | Headshots sent to the CAD per request. |

### Config.Voices

Recorded caller voices.

| Option | Default | Description |
|---|---|---|
| `perScenario` | `4` | Voices a scenario can use. Picked from the lists by the scenario name, so a scenario always sounds like the same set of people. |
| `female` | 10 voices | `jessica`, `sarah`, `matilda`, `laura`, `bella`, `alice`, `lily`, `carol`, `rachel`, `cassidy`. |
| `male` | 10 voices | `liam`, `chris`, `bill`, `roger`, `callum`, `will`, `brian`, `adam`, `eric`, `charlie`. |

### Config.AI

Live AI callers. Off by default. Keys are read from the convars `koja_dispatch_openai_key` and `koja_dispatch_elevenlabs_key`.

| Option | Default | Description |
|---|---|---|
| `enabled` | `false` | Turn AI callers on. Also the admin setting `features.aiCallers`. |
| `chance` | `1.0` | Share of generated calls that become AI calls. |
| `model` | `'gpt-4.1-mini'` | OpenAI Chat Completions model. For reasoning models (`gpt-5*`, `o*`) the temperature is not sent; set `reasoningEffort` and raise `maxTokens`. |
| `temperature` | `0.9` | Model temperature. |
| `maxTokens` | `160` | Reply length limit. |
| `maxTurns` | `24` | AI replies per call. After that the call continues with the scripted answers. |
| `timeout` | `7000` | Request timeout in ms (max 9000). On a timeout or error the scripted answer is used. |
| `generateOpening` | `false` | `true` lets the model phrase the opening line as well (one more request when the call is answered). |
| `language` | `'en'` | Language the caller speaks and the transcription language. |
| `tts` | `'elevenlabs'` | `'elevenlabs'`, `'openai'` or `'none'` (silent AI callers). |
| `elevenlabs.model` | `'eleven_flash_v2_5'` | ElevenLabs model. |
| `elevenlabs.format` | `'mp3_22050_32'` | Audio format. |
| `elevenlabs.stability`, `similarity`, `style` | `0.35`, `0.75`, `0.45` | Voice settings. |
| `elevenlabs.voices` | 20 entries | Map of the caller voices (`Config.Voices`) to ElevenLabs voice ids. Replace them with voices from your account if the defaults are not available. |
| `openaiTts.model` | `'gpt-4o-mini-tts'` | OpenAI speech model. |
| `openaiTts.voices` | 20 entries | Map of the caller voices to OpenAI voices. |
| `speech` | `true` | **Hold to talk** button: the dispatcher's microphone is recorded and transcribed. Hidden when the microphone is not available. |
| `transcribeModel` | `'gpt-4o-mini-transcribe'` | Transcription model. |
| `maxRecordSeconds` | `15` | Longest recording. |
| `maxAudioBytes` | `600000` | Largest accepted recording. |

### Config.Api

| Option | Default | Description |
|---|---|---|
| `clientAlerts` | `false` | Allow the client export `SendAlert`. Admin `api.clientAlerts`. See [Client exports](/new/dispatcher/api/client-exports). |

### Config.Mdt

Link to koja-mdt. See [Integrations](/new/dispatcher/integrations).

| Option | Default | Description |
|---|---|---|
| `resource` | `'koja-mdt'` | MDT resource name. |
| `enabled` | `true` | Use the MDT when it runs. Admin `mdt.enabled`. |
| `code` | `'911'` | Call code of calls created in the MDT. |
| `pushIncidents` | `'real'` | `'off'`, `'real'` (from players, API, manual, sensors and the MDT) or `'all'` (also generated calls). |
| `pullCalls` | `'calls'` | `'off'`, `'calls'` (ring at the console) or `'incidents'` (open straight as an incident). |
| `syncStatus` | `true` | Sync unit status and assignments both ways. |
| `useCallsigns` | `true` | Player units use their MDT callsign. |

### Config.Map3D

The 3D terrain scan (`/dispatchscan`). The release already ships a scanned heightmap; scan again only after big map changes.

| Option | Default | Description |
|---|---|---|
| `scanCommand` | `'dispatchscan'` | Command that starts the scan. |
| `cellSize` | `16.0` | Sample spacing in metres. |
| `bounds` | `minX = -4096, maxX = 4608, minY = -4352, maxY = 8448` | Area that is scanned. |
| `samplesPerFrame` | `2500` | Height samples taken per frame on the client. |
| `rowsPerChunk` | `16` | Rows sent to the server per message. |
| `uploadBps` | `250000` | Upload speed limit in bytes per second. |
| `exaggeration` | `1.15` | Terrain height scale in the 3D view (written into `height.json` by a scan). |

## Module files

### Config.Career (career.lua)

| Option | Default | Description |
|---|---|---|
| `enabled` | `true` | Ranks, XP and unlocks. Admin `career.enabled`. |
| `xp.perScore` | `0.25` | XP per positive score point. |
| `xp.perResolved` | `12` | XP per resolved incident. |
| `xp.perCoded` | `4` | XP per correctly classified call. |
| `xp.perGoodInstruction` | `6` | XP per correct instruction. |
| `xp.perMinute` | `1.5` | XP per minute on shift. |
| `xp.perMissed` | `-15` | XP per missed or dropped call. |
| `xp.perFailed` | `-10` | XP per failed incident. |
| `xp.maxLossPerShift` | `120` | Most XP a shift can take away. |
| `seed.perScore`, `seed.perResolved` | `0.5`, `10` | Starting XP for dispatchers who already have shifts in `koja_dispatch_shifts` when career is first used. |
| `ranks` | 5 ranks | See below. |
| `gates` | 3 gates | Perk needed to answer calls of these categories. |

| Rank | XP | Lines | Pay | Perks |
|---|---|---|---|---|
| Trainee | 0 | 1 | x1.0 | |
| Dispatcher | 400 | 2 | x1.1 | `pursuits` |
| Senior Dispatcher | 1800 | 3 | x1.25 | `hostage`, `mci` |
| Supervisor | 5000 | 3 | x1.4 | `supervise` |
| Chief | 12000 | 4 | x1.6 | |

`lines` is the number of calls a dispatcher can hold at once. `pay` multiplies the shift pay. Perks carry over to higher ranks. Gates: `pursuits` for `pursuit`, `hostage` for `hostage` and `officer_down`, `mci` for `mci` and `mass_casualty`. `supervise` lets the dispatcher take over calls and incidents of others.

### Config.Dynamics (dynamics.lua)

| Option | Default | Description |
|---|---|---|
| `events` | `true` | Scenario events during calls. Admin `dynamics.events`. |
| `stages` | `true` | Multi-stage incidents. Admin `dynamics.stages`. |
| `weather` | `true` | Weather and time weighting of generated calls. Admin `dynamics.weather`. |
| `strength` | `1.0` | How strongly weather and time change the weights (0 to 2). Admin `dynamics.strength`. |
| `reportInterval` | `30` | Seconds between hour and weather reports from dispatcher clients. |
| `reportTtl` | `120` | Seconds a report stays valid. |
| `boost` | `1.8` | Weight multiplier when a scenario's `time` or `weather` list matches. |
| `unmatched` | `0.6` | Weight multiplier when it does not match. |
| `eventDelay` | `2` | Default delay in seconds of events triggered by a question or instruction. |
| `periods` | `day` 7-17, `evening` 18-21 | Hours of each period. Other hours are `night`. |
| `weatherGroups` | GTA weather types | Maps `CLEAR`, `RAIN`, `THUNDER`, `FOGGY`, `SNOW`... to `clear`, `sunny`, `clouds`, `rain`, `storm`, `fog`, `snow`. |
| `weatherAliases` | per group | Words a scenario's `weather` can use for each group (`storm` also matches `rain` and `wet`). |
| `categories` | 13 categories | Multipliers per category, for example `traffic` x2.0 in rain and x2.6 in snow, `burglary` x1.9 at night. |
| `scenarios` | 21 scenarios | Time or weather lists for built-in scenarios, for example `drunk_driver` only at night, `brush_fire` in sunny or clear weather by day. |

The weather comes from `GlobalState.weather` or `GlobalState.currentWeather` when a weather sync sets it, otherwise from the dispatchers' clients.

### Config.Editors (editors.lua)

| Option | Default | Description |
|---|---|---|
| `maxCustom` | `100` | Custom scenarios. |
| `maxText` | `240` | Characters per scenario line. |
| `maxLocations` | `10` | Custom locations per scenario. |
| `maxUnits` | `80` | AI units in the fleet editor. |
| `maxStations` | `30` | AI stations in the fleet editor. |

### Config.Fleet (fleet.lua)

Fatigue and damage of AI units.

| Option | Default | Description |
|---|---|---|
| `enabled` | `true` | Admin `fleet.enabled`. |
| `fatigueRate` | `6.0` | Fatigue (0-100) gained per minute on scene. Admin `fleet.fatigueRate`. |
| `travelFactor` | `0.35` | Share of `fatigueRate` gained while driving. |
| `idleRecovery` | `4.0` | Fatigue lost per minute while idle. |
| `restThreshold` | `80` | At this fatigue the unit returns to its station to rest after the job. |
| `exhaustedAt` | `100` | At this fatigue the unit leaves the job at once. |
| `slowAt` | `60` | From this fatigue the unit drives slower. |
| `slowPenalty` | `0.25` | Speed lost when tired (25 %). |
| `restSeconds` | `180` | Rest time at the station. Admin `fleet.restSeconds`. |
| `repairSeconds` | `240` | Repair time at the station. Admin `fleet.repairSeconds`. |
| `damageChance` | `0.25` | Chance of damage on a violent call. Admin `fleet.damageChance`. |
| `damageDelay` | `{ 6, 30 }` | Seconds on scene before the damage happens. |
| `damageAmount` | `{ 35, 100 }` | Damage range. |
| `damageCategories` | `shooting`, `hostage`, `pursuit`, `assault` | Violent categories. |
| `damageDepartments` | `police = 1.0`, `ems = 0.4`, `fire = 0.4` | Damage chance multiplier per department. |
| `homeRadius` | `25.0` | Distance at which a unit counts as back at its station. |
| `broadcastStep` | `5` | Fatigue and damage are sent to the CAD in steps of this size. |

### Config.Mci (fleet.lua)

Mass casualty incidents.

| Option | Default | Description |
|---|---|---|
| `enabled` | `true` | Turn MCI on. |
| `category` | `'mci'` | Category of MCI incidents. |
| `patients` | `{ 4, 12 }` | Number of patients. |
| `mix` | `red = 0.25`, `yellow = 0.35` | Share of red and yellow patients. The rest are green. |
| `stabiliseSeconds` | `20` | Seconds an ambulance crew needs to stabilise a red or yellow patient. |
| `airStabiliseSeconds` | `14` | The same for the air ambulance. |
| `treatSeconds` | `25` | Seconds to treat a green patient on scene. |
| `deteriorateSeconds` | `150` | Untreated patients get worse after this time. |
| `exposureFactor` | `0.5` | Danger builds at this rate compared to a normal incident. |
| `minFail` | `900` | An MCI fails after at least this many seconds. |

### Config.HospitalBeds (fleet.lua)

| Option | Default | Description |
|---|---|---|
| `enabled` | `true` | Track beds. Admin `hospitals.enabled`. |
| `turnoverSeconds` | `600` | Seconds until an occupied bed is free. Admin `hospitals.turnoverSeconds`. |
| `turnoverJitter` | `0.3` | Random spread of the turnover time. |
| `handoverSeconds` | `8` | Patient handover at a hospital with a free bed. |
| `overflowSeconds` | `45` | Handover when every hospital is full. |
| `defaultBeds` | `8` | Beds of a hospital without its own count. |
| `nearlyFull` | `0.75` | Occupancy shown as nearly full. |
| `list` | 5 hospitals | `{ id, label, coords, beds }`: Pillbox 14, Mount Zonah 10, Central Los Santos 8, Sandy Shores 4, Paleto Bay 4. |

### Config.Phones (integrations.lua)

| Option | Default | Description |
|---|---|---|
| `enabled` | `true` | Phone 911. Admin `phones.enabled`. |
| `resource` | `'auto'` | `'auto'` or a phone name. Admin `phones.resource`. |
| `number` | `911` | Service number. Admin `phones.number`. |
| `order` | `lb-phone`, `qs-smartphone-pro`, `gksphone`, `npwd`, `yseries` | Order in which `auto` looks for a running phone. |
| `companies` | `police`, `sheriff`, `ambulance`, `ems`, `fire`, `lspd`, `bcso`, `safd` | lb-phone company apps that count as 911. |
| `endCall` | `true` | End the phone call and continue as a text thread. |
| `threadMinutes` | `20` | Dispatcher replies are sent as phone messages for this long. |
| `cooldown` | `2` | Seconds between phone calls from one player. |

### Config.Compat (integrations.lua)

| Option | Default | Description |
|---|---|---|
| `enabled` | `true` | Accept alerts from other dispatch scripts. Admin `compat.enabled`. |
| `mode` | `'call'` | `'call'` rings at the console, `'incident'` opens an incident. Admin `compat.mode`. |
| `autoAssign` | `true` | Incidents only: send the nearest free units. Admin `compat.autoAssign`. |
| `maxDistance` | `600.0` | Alert positions further than this from the sending player are moved to the player. |
| `dedupeSeconds` | `20` | The same alert at the same place within this time is dropped. |
| `rate` | `{ 8, 10 }` | Alerts per player: 8 per 10 seconds. |

### Config.Discord (integrations.lua)

| Option | Default | Description |
|---|---|---|
| `enabled` | `true` | Admin `discord.enabled`. Nothing is sent without a webhook convar. |
| `shifts`, `incidents`, `calls`, `admin`, `events` | `true` | What is logged. Admin `discord.*`. |
| `minPriority` | `3` | Lowest incident priority logged. `3` logs all, `1` only priority 1. |
| `interval` | `2000` | Milliseconds between sends per webhook. |
| `maxQueue` | `200` | Embeds queued per channel. |
| `username` | `'Koja Dispatcher'` | Webhook user name. |
| `colors` | per kind | Embed colors for `shift`, `resolved`, `failed`, `cancelled`, `missed`, `admin`, `event`. |

### Config.MdtStatus (mdt.lua)

Field status codes for players. See [Commands and keybinds](/new/dispatcher/commands-and-keybinds#field-status-codes).

| Option | Default | Description |
|---|---|---|
| `bindSuggested` | `false` | `true` binds the suggested keys (Numpad 1-9, F10 for the menu) by default. |
| `menuKey` | `''` | Default key of the quick menu. |
| `suggestedMenuKey` | `'F10'` | Menu key used when `bindSuggested` is on. |
| `command` | `'tencode'` | Command: `/tencode <code>`, or no argument for the menu. Empty removes it. |
| `codes` | 8 codes | `{ id, action, status, mdt, key, suggested }`. `action` is `status`, `backup` or `panic`; `status` is the CAD unit status; `mdt` is the koja-mdt status; `key` is a fixed default key for that code; `suggested` is the key used with `bindSuggested`. |
| `backup.category`, `priority`, `mdtCode` | `'officer_down'`, `1`, `'10-78'` | Incident created by a backup request, and the MDT call code. |
| `panic.category`, `priority`, `units` | `'officer_down'`, `1`, `4` | Incident created by a panic without koja-mdt, and how many extra units it asks for. |

| Code | Action | Unit status | MDT status | Suggested key |
|---|---|---|---|---|
| `10-8` | status | available | available | Numpad 1 |
| `10-6` | status | busy | busy | Numpad 2 |
| `10-97` | status | en route | enroute | Numpad 3 |
| `10-23` | status | on scene | onscene | Numpad 4 |
| `10-7` | status | unavailable | break | Numpad 5 |
| `10-15` | status | transport | busy | Numpad 6 |
| `backup` | backup | | | Numpad 8 |
| `10-99` | panic | | | Numpad 9 |

### Config.MdtTools (mdt.lua)

| Option | Default | Description |
|---|---|---|
| `department` | `nil` | Department id sent with BOLOs and mail created in koja-mdt. |
| `boloLimit` | `100` | BOLOs read from the MDT. |
| `searchLimit` | `20` | Results of a person search. |
| `alertSeconds` | `12` | Not read by the current code. |
| `flags` | `{ 'stolen', 'wanted' }` | Vehicle flags the dispatcher can set from the workspace. |

### Config.Pursuit (pursuit.lua)

| Option | Default | Description |
|---|---|---|
| `enabled` | `true` | Admin `pursuit.enabled`. |
| `maxActive` | `2` | Pursuits at once. Admin `pursuit.maxActive`. |
| `loseSeconds` | `40` | Suspect lost after this long without a visual. Admin `pursuit.loseSeconds`. |
| `reportedSeconds` | `240` | Suspect lost when no unit spots it within this time. |
| `speedFactor` | `1.15` | Suspect speed compared to a patrol car. Admin `pursuit.speedFactor`. |
| `unitSpeedFactor` | `1.1` | Speed of chasing units. |
| `visualRange` | `180.0` | Distance at which a ground unit sees the suspect. |
| `airVisualRange` | `480.0` | The same for helicopters. |
| `catchRange` | `30.0` | Distance at which units box in a slowed or stopped suspect. |
| `catchSeconds` | `5` | Seconds of boxing in to catch the suspect. |
| `chaseReroute` | `3.0` | Seconds between route updates of chasing AI units. |
| `playerUpdate` | `2.0` | Seconds between updates for chasing player units. |
| `broadcastInterval` | `1.0` | Seconds between map updates. |
| `destinationMin`, `destinationMax` | `500.0`, `1400.0` | Distance of the suspect's escape target. |
| `trailPoints`, `trailEvery` | `14`, `2.0` | Trail drawn behind the suspect. |
| `spikes`, `roadblocks` | `3`, `2` | Tools per pursuit. Admin `pursuit.spikes`, `pursuit.roadblocks`. |
| `spikeChance` | `0.65` | Chance a spike strip hits. Admin `pursuit.spikeChance`. |
| `roadblockChance` | `0.5` | Chance a roadblock stops the suspect. Admin `pursuit.roadblockChance`. |
| `triggerRadius` | `22.0` | Distance at which the suspect reaches a tool. |
| `snapRadius` | `45.0` | A tool must be placed within this distance of a road. |
| `roadblockSeconds` | `150` | Lifetime of a roadblock. |
| `roadblockCooldown` | `25` | Seconds before the same roadblock can try again. |
| `spikedFactor` | `0.3` | Speed of a spiked suspect. |
| `stopSeconds` | `14` | Seconds a stopped suspect stays stopped. |
| `crashChance` | `0.004` | Chance per second that a suspect in sight crashes. |
| `escalationChance` | `0.3` | Chance that an escalating incident turns into a pursuit. Admin `pursuit.escalationChance`. |
| `escalationCategories` | robbery, burglary, assault, shooting, hostage, domestic | Categories that can turn into a pursuit. |
| `need` | `{ police = 2 }` | Needs of a pursuit. |

### Config.Patrol (pursuit.lua)

| Option | Default | Description |
|---|---|---|
| `enabled` | `true` | Admin `patrol.enabled`. |
| `maxZones` | `8` | Zones at once. Admin `patrol.maxZones`. |
| `speedFactor` | `0.6` | AI speed while patrolling. Admin `patrol.speedFactor`. |
| `maxVertices` | `24` | Points per polygon zone. |
| `minRadius`, `maxRadius` | `60.0`, `1500.0` | Circle zone radius limits. |
| `pickAttempts` | `12` | Tries to find a patrol point on a road inside the zone. |
| `nameLength` | `32` | Zone name length. |

### Config.Stats (stats.lua)

| Option | Default | Description |
|---|---|---|
| `enabled` | `true` | Store closed incidents. Admin `stats.enabled`. |
| `retentionDays` | `30` | Days kept. Admin `stats.retentionDays`. |
| `binSize` | `80.0` | Heatmap cell size in metres. |
| `heatCap` | `1200` | Heatmap cells sent at most. |
| `cacheSeconds` | `20` | Statistics cache. |
| `topStreets` | `8` | Busiest streets listed. |
| `topDispatchers` | `8` | Dispatchers on the leaderboard. |
| `pruneMinutes` | `60` | How often old rows are deleted. |

### Config.Training (training.lua)

| Option | Default | Description |
|---|---|---|
| `scenario` | `'training_practice'` | Scenario used for practice calls. |
| `maxPracticeCalls` | `3` | Practice calls a trainee can have open at once. |

### Config.Voice (voice.lua)

| Option | Default | Description |
|---|---|---|
| `enabled` | `true` | Voice 911 calls. Admin `voice.enabled`. |
| `provider` | `'auto'` | `'auto'`, `'pma-voice'` or `'mumble-voip'`. Admin `voice.provider`. |
| `channelBase` | `91100` | First call channel. Admin `voice.channelBase`. |
| `channelRange` | `900` | Channels used from `channelBase`. |
| `endOnDispatch` | `true` | End the voice call when the call is dispatched. Admin `voice.endOnDispatch`. |
| `allowTransfer` | `true` | Dispatchers can hand the voice call to a field unit. Admin `voice.allowTransfer`. |
| `talkingPollMs` | `150` | How often the talking indicator is checked. |
| `keepAliveSeconds` | `5` | Keeps a call with an open voice line from timing out. |
| `hangupCommand` | `'hangup911'` | Command callers and units use to leave the voice call. |
| `indicator` | `x = 0.5, y = 0.045, width = 0.118, height = 0.03` | Position and size of the on-screen call indicator for the caller and the unit. |
