Admin menu
/dispatchadmin opens the admin menu in game. Everything you change there is saved in the database (koja_dispatch_settings) and applies live, without a restart. The values in config.lua are the defaults.
Access
A player can open the menu when one of these is true:
- their framework group is in
Config.Admin.groups(admin,god,superadmin), - they have the ACE
koja-dispatcher.admin(Config.Admin.ace).
add_ace group.admin koja-dispatcher.admin allowThe command is Config.Admin.command. It does nothing from the server console; use dispatchcheck there. Every admin change is printed in the server console and, with Discord logs on, posted to the admin webhook.
Pages
| Page | What it is for |
|---|---|
| Overview | Live state, current setup, statistics and quick actions |
| Modes | Call sources, units, and what happens when nobody is on shift |
| Stations | Dispatch stations in the world |
| Access & jobs | Jobs allowed to dispatch, creating a job, hiring, dispatcher ranks |
| Calls & limits | Dispatcher seats, remote CAD, generated call rate and limits |
| Pay | Shift pay |
| Features | Intro camera, AI callers, sensors, map layers, field units |
| Integrations | koja-mdt and the client alert API |
| Modules | Settings of every optional module |
| Scenarios | Scenario editor |
| AI fleet | Fleet editor |
Every setting has a reset button that shows the default value. Reset all settings puts every setting back to the config.lua value; stations, allowed jobs and created jobs are kept.
Overview
Refreshes every few seconds. It shows the dispatchers on shift (station and since when), units on duty per department with AI on and off duty and players, active incidents and open calls, the current setup (modes, stations, allowed jobs) and the incident statistics.
Quick actions affect everyone on the server at once:
| Action | What it does |
|---|---|
| Test call | Rings a random generated 911 call in every CAD. Needs a dispatcher on shift. |
| Test incident | Creates a test incident about 120 m from you with one police unit and auto-assigns it. |
| Clear calls | Ends every ringing and active call. |
| Clear incidents | Closes all incidents and frees their units. |
| End all shifts | Clocks every dispatcher out. They see their shift report. |
Modes
Three choices decide how the whole dispatch works. The page shows a live How calls flow diagram that changes with the modes.
Call sources (mode.calls)
| Value | Meaning |
|---|---|
generated | Only AI 911 calls. The server makes up emergencies while dispatchers are on shift. Real calls (/911, phones, sensors, API, koja-mdt) are not rung at the console; they follow the "nobody on shift" rule below. |
real | Only real calls: player /911, phones, sensors, other scripts through the API and koja-mdt. No generated calls. |
mixed | Both. Real calls come in between generated ones. |
Generated calls only come while at least one dispatcher is on shift.
Units (mode.units)
| Value | Meaning |
|---|---|
ai | Only AI units drive to incidents. Good for small or new servers. |
players | Only on-duty players with a police, EMS or fire job appear as units and get dispatched. |
mixed | Players and AI together. AI units of a department go off duty while units.disableWhenPlayers players of that department are on duty. |
When nobody is on shift (mode.noDispatcher)
What happens to a real call (/911, phone, API, client alert) when no dispatcher can take it.
| Value | Meaning |
|---|---|
reject | The caller is told nobody is answering. Nothing is created. |
auto | An incident is created at the caller and the nearest free units are assigned automatically. The incident follows the caller until units arrive. |
mdt | The call is sent to koja-mdt as a dispatch call for officers to pick up. Needs koja-mdt running with the integration on; otherwise it acts like reject. |
Stations
Dispatch stations (consoles) in the world. A player whose job may dispatch walks up to one to start a shift. There can be up to 40 stations.
| Action | What it does |
|---|---|
| Place a station | Opens the placing mode at your position. |
| Rename | Click the name. 2 to 48 characters. |
| Stand / Sit | Pose the dispatcher takes during the shift. |
| Blip | Show the station on the map. |
| Adjust position | Opens the placing mode for this station with a live preview. |
| Teleport | Moves you to the station. |
| Set waypoint | GPS to the station. |
| Delete | Removes the station for good. A dispatcher on shift there is clocked out. |
Placing a station with the gizmo
The admin menu hides, a camera orbits a see-through copy of your character that plays the exact sit or stand pose, and you place it with a 3D gizmo. The spot must stay within 25 m of where you stand.
| Input | Action |
|---|---|
| Drag the arrows | Move |
| Drag the ring | Rotate |
| Tab | Switch between move and rotate mode |
| Q / E | Turn 5° (Shift 1°, Ctrl 15°) |
| G | Sit / stand |
| R | Snap to the floor |
| S | Snap 5 cm / 5° on or off |
| F | Refocus the camera |
| Right-drag / wheel | Orbit / zoom the camera |
| X, Y, Z and heading fields | Exact values; arrow keys in a field nudge it (Shift x10) |
| Enter | Save |
| Esc | Cancel, nothing changes |
Access & jobs
Jobs allowed to dispatch. A player needs one of these jobs at the minimum grade or higher. Only those players see the start prompt at a station. A job that the framework does not know is marked. With no job in the list nobody can start a shift. Removing a job does not end shifts that are running.
Create job (ESX and QBCore only). Name (lowercase, no spaces), label, grades (name, label, salary, up to 20) and the lowest grade that can dispatch. The job is created in the framework and added to the allowed list. On ESX it is created with ESX.CreateJob, on QBCore with exports['qb-core']:AddJob. On other frameworks add the job yourself.
Hire. Search online players by name, ID or job and set their job and grade. The list shows who is on shift and whether the grade can dispatch.
Dispatcher ranks. With the career module on, set the rank of online players. Setting a rank moves their XP to that rank's threshold.
Calls & limits
| Setting | Default | What it does |
|---|---|---|
Dispatchers at once (access.maxDispatchers) | 0 | Seats. 0 = no limit. |
Remote CAD (access.remote) | off | Allowed jobs open the CAD anywhere with /cad. |
Shortest / longest gap between calls (calls.intervalMin / calls.intervalMax) | 35 / 80 s | Time between generated calls. |
Faster with more dispatchers (calls.perDispatcherSpeedup) | 0.15 | Per extra dispatcher on shift. |
Ringing calls at once (calls.maxRinging) | 4 | No new generated call while this many ring. |
Active incidents limit (calls.maxActiveIncidents) | 10 | No new generated call while this many incidents are open. |
Caller patience (calls.patience) | 45 s | Before a generated caller hangs up. |
Player reply window (calls.playerReplyWindow) | 180 s | How long a player's 911 text line stays open. |
Replace AI with players (units.disableWhenPlayers) | 3 | Only used when units are mixed. 0 = never. |
The generated call settings are greyed out when call sources are real.
Pay
Paid when the shift ends: minutes worked plus a bonus per score point, scaled by the star rating, up to the maximum payout (0 = no cap). See Config.Pay.
Features
Dispatcher experience (intro camera, AI callers), automatic alerts (shots, crashes, downed players; only used when call sources include real calls; the switches apply live), map layers (civilians, NPC peds) and field units (scenes, auto waypoint).
Integrations
koja-mdt status (not installed, running, not started) and its five settings, the Client alerts switch for the client export SendAlert, and a copyable list of the developer exports. See Integrations.
Modules
Settings of the optional modules, one group per module: career, compat, discord, dynamics, fleet, hospitals, mdt_status, mdt_tools, patrol, phones, pursuit, stats, training, voice. They save and apply live like everything else. Settings that other resources add with the RegisterSetting export appear here too, grouped by the part of the key before the first dot. The full list is in All settings.
Scenarios
Create, edit, duplicate and disable the 911 scenarios generated calls are drawn from.
- Built-in scenarios can be switched off and given another weight (how often they are drawn,
0never). They cannot be deleted. Reset restores the default weight. - Custom scenarios (up to 100) are created from scratch or by duplicating a built-in one. Fields: name, category, priority, caller (any, male, female), distress, scene (none, crowd, fight, fire, injured, crash), 1 to 5 opening lines, answers per question with an optional chance and the extra units the answer reveals, base needs, correct instruction, respond, fail and work time, points, weight, needs transport, prank call, and where it happens (location tags, or up to 10 own places picked on the map or at your position;
{location}inserts the place name). - Test call now rings the scenario at once.
Custom scenarios have no recorded voice lines, so their calls are text only unless AI callers are on. They are stored in koja_dispatch_scenarios.
AI fleet
Add, remove and disable AI units and stations. At first the fleet comes from Config.AiUnits. Press Copy config and edit to copy it into the editor; from then on the editor overrides Config.AiUnits.fleet and Config.AiUnits.stations.
- Units: callsign, unit type and station (the type must match the station's department). Disabled units on an incident finish the job first; removed units are released at once. Up to 80 units.
- Stations: name, department and position (click the map or use your position). A station with units cannot be removed. Up to 30 stations.
- Reset to config deletes the edited fleet and respawns the units from
Config.AiUnits.
If Config.AiUnits.enabled is false, no AI unit spawns even when listed here. The edited fleet is stored in koja_dispatch_ai_stations and koja_dispatch_ai_fleet.
All settings
Every key below can be changed in the menu, read with GetSetting and changed with SetSetting. Other resources can add their own keys with RegisterSetting (see Server exports). Defaults come from the config option named in the last column.
Core
| Key | Type | Range or values | Default | What it does |
|---|---|---|---|---|
mode.calls | enum | generated, real, mixed | mixed | Where 911 calls come from. Config.Modes.calls |
mode.units | enum | ai, players, mixed | mixed | Which units appear on the map and can be dispatched. Config.Modes.units |
mode.noDispatcher | enum | reject, auto, mdt | reject | What happens to a player's /911 when no dispatcher is working. Config.Modes.noDispatcher |
access.maxDispatchers | int | 0-32 | 0 | Dispatchers on shift at once, 0 no limit. Config.Dispatcher.maxDispatchers |
access.remote | bool | false | Allowed jobs can open the CAD anywhere with /cad. Config.Dispatcher.remote | |
calls.intervalMin | int | 10-600 | 35 | Minimum seconds before the next generated call. |
calls.intervalMax | int | 10-900 | 80 | Maximum seconds before the next generated call. |
calls.maxRinging | int | 1-12 | 4 | No new generated call while this many are waiting. |
calls.maxActiveIncidents | int | 1-50 | 10 | No new generated call while this many incidents are open. |
calls.patience | int | 15-300 | 45 | Seconds a generated caller waits before hanging up. |
calls.playerReplyWindow | int | 30-900 | 180 | Seconds a player's 911 chat stays open for replies. |
calls.perDispatcherSpeedup | number | 0-1, step 0.05 | 0.15 | Calls come this much faster for every extra dispatcher. |
units.disableWhenPlayers | int | 0-32 | 3 | AI of a department go off duty at this many players of it on duty, 0 never. Config.AiUnits.disableWhenPlayers |
pay.enabled | bool | true | Pay out when a shift ends. | |
pay.perMinute | int | 0-1000 | 6 | Money per minute worked. |
pay.perPoint | int | 0-100 | 2 | Bonus per score point. |
pay.minimumMinutes | int | 0-120 | 3 | Shorter shifts get nothing. |
pay.maximum | int | 0-1000000 | 15000 | Cap per shift. 0 = no cap. |
features.cinematic | bool | true | Camera fly-in when a dispatcher clocks in. | |
features.aiCallers | bool | false | Live AI callers via OpenAI / ElevenLabs. Needs the API keys. Config.AI.enabled | |
features.sensorDowned | bool | true | A call when a player stays down. | |
features.sensorShots | bool | true | A call when someone shoots in the city. Applies live on every client. | |
features.sensorCrash | bool | true | A call after a heavy vehicle crash. Applies live on every client. | |
features.showCivilians | bool | true | Players without a service job appear as dots on the map. | |
features.showNpcPeds | bool | false | NPC peds on the map. Costs performance on busy servers. | |
features.fieldScenes | bool | true | Units sent to an incident see props and peds at the scene. | |
features.fieldWaypoint | bool | true | Set the GPS when a unit gets assigned. | |
mdt.enabled | bool | true | Use koja-mdt. Config.Mdt.enabled | |
mdt.pushIncidents | enum | off, real, all | real | Send incidents to the MDT. Real = from players, API, manual and MDT; all = also generated calls. |
mdt.pullCalls | enum | off, calls, incidents | calls | MDT calls (911, panic, ALPR...) ring in the CAD or open straight as an incident. |
mdt.syncStatus | bool | true | Status and assignments sync both ways. | |
mdt.useCallsigns | bool | true | Player units show their MDT callsign. | |
api.clientAlerts | bool | false | Allow the client export SendAlert. Rate limited. Config.Api.clientAlerts |
Modules
| Key | Type | Range or values | Default | What it does |
|---|---|---|---|---|
career.enabled | bool | true | XP, rank badge, simultaneous lines, call gates and supervisor powers. | |
career.xpMultiplier | number | 0.1-5, step 0.1 | 1.0 | Scales XP from score, incidents, codes and instructions. |
career.xpTimeMultiplier | number | 0-5, step 0.1 | 1.0 | Scales XP per minute on shift. |
career.xpPenaltyMultiplier | number | 0-5, step 0.1 | 1.0 | Scales XP lost for missed calls and failed incidents. |
career.gateCalls | bool | true | Low ranks cannot answer pursuit, hostage and mass casualty calls. | |
career.gateOwnership | bool | true | Only supervisors can reassign units, cancel or reprioritise incidents another dispatcher owns. | |
compat.enabled | bool | true | Accept alerts from other dispatch scripts. | |
compat.mode | enum | call, incident | call | Call rings at the console, incident goes straight to the map. |
compat.autoAssign | bool | true | Incidents only: send the nearest free units at once. | |
discord.enabled | bool | true | Discord logging. Webhooks are read from server convars only. | |
discord.shifts | bool | true | Log shifts. | |
discord.incidents | bool | true | Log ended incidents. | |
discord.calls | bool | true | Log missed and dropped calls. | |
discord.admin | bool | true | Log admin changes. | |
discord.events | bool | true | Log pursuits and MCI. | |
discord.minPriority | int | 1-3 | 3 | Lowest incident priority logged. 3 logs every incident, 1 only priority 1. |
dynamics.events | bool | true | Scenarios with events can escalate while the caller is on the line or after dispatch. | |
dynamics.stages | bool | true | Scenarios with stages continue with a new stage when the current one is done. | |
dynamics.weather | bool | true | Generated calls depend on the in-game hour and weather. | |
dynamics.strength | number | 0-2, step 0.1 | 1.0 | 0 turns weighting off, 1 is normal, 2 doubles the effect. |
fleet.enabled | bool | true | AI units tire out and can be damaged on violent calls, then rest or repair at their station. | |
fleet.fatigueRate | number | 0-30, step 0.5 | 6.0 | Fatigue (0-100) per minute on scene. Travel counts at about a third. |
fleet.restSeconds | int | 15-1800 | 180 | Seconds a tired unit rests at its station. |
fleet.repairSeconds | int | 15-1800 | 240 | Seconds a damaged unit spends in repair. |
fleet.damageChance | number | 0-1, step 0.05 | 0.25 | Damage chance on shooting, hostage, pursuit and assault calls (police full, EMS and fire less). |
hospitals.enabled | bool | true | Transports fill hospital beds. Full or diverted hospitals are skipped. | |
hospitals.turnoverSeconds | int | 30-7200 | 600 | Seconds until an occupied bed frees up. |
mdt_status.enabled | bool | true | Field units set 10-codes with key mappings, /tencode and the quick menu. | |
mdt_status.hud | bool | true | Small HUD chip with the current code for field units. | |
mdt_status.backupUnits | int | 1-6 | 2 | Extra units auto-assigned when an officer requests backup. |
mdt_status.cooldown | int | 5-600 | 45 | Seconds per officer between backup requests and panic fallbacks. |
mdt_status.panicFallback | bool | true | Without koja-mdt, 10-99 creates a priority 1 incident here. | |
mdt_tools.monitor | bool | true | MDT workspace drawer in the CAD (key B). | |
mdt_tools.boloSource | enum | auto, mdt, internal | auto | Auto uses koja-mdt when it runs and the internal list otherwise. MDT only refuses new BOLOs while it is down. |
mdt_tools.alpr | bool | true | Alert dispatchers when an ALPR read hits a BOLO plate. | |
mdt_tools.notifyUnits | bool | true | Send internal BOLOs to on-duty police field units. | |
patrol.enabled | bool | true | Dispatchers can draw zones that idle AI units patrol. Turning it off recalls patrolling units. | |
patrol.maxZones | int | 1-32 | 8 | Zones at once. |
patrol.speedFactor | number | 0.2-1, step 0.05 | 0.6 | AI speed while patrolling. |
phones.enabled | bool | true | Calls and texts to the service number reach the dispatcher like /911. | |
phones.resource | enum | auto, lb-phone, qs-smartphone-pro, gksphone, npwd, yseries | auto | auto uses the first supported phone that is running. |
phones.number | int | 1-99999 | 911 | Number players dial or text. |
pursuit.enabled | bool | true | Pursuit incidents get a moving suspect vehicle. | |
pursuit.maxActive | int | 0-10 | 2 | More pursuit incidents stay normal incidents. |
pursuit.loseSeconds | int | 10-300 | 40 | Suspect lost when no unit or helicopter sees it for this long. |
pursuit.spikes | int | 0-10 | 3 | Spike strips per pursuit. |
pursuit.roadblocks | int | 0-10 | 2 | Roadblocks per pursuit. |
pursuit.spikeChance | number | 0-1, step 0.05 | 0.65 | Chance a spike strip slows the suspect. |
pursuit.roadblockChance | number | 0-1, step 0.05 | 0.5 | Chance the suspect stops at a roadblock. |
pursuit.speedFactor | number | 0.5-2, step 0.05 | 1.15 | Suspect speed relative to a patrol car. |
pursuit.escalationChance | number | 0-1, step 0.05 | 0.3 | Chance a suspect flees in a vehicle when a robbery, assault or shooting escalates. |
stats.enabled | bool | true | Store every closed incident for the heatmap and the statistics. | |
stats.retentionDays | int | 1-365 | 30 | Older incidents are deleted automatically. |
training.enabled | bool | true | Dispatchers can run the guided tutorial from the top bar. | |
training.offerFirstShift | bool | true | Offer the tutorial to dispatchers with no finished shifts. | |
training.practiceCalls | bool | true | Easy practice calls that only the trainee sees. No effect on score, pay or other dispatchers. | |
voice.enabled | bool | true | Private voice channel between dispatcher and player caller when a 911 call is answered. | |
voice.provider | enum | auto, pma-voice, mumble-voip | auto | Auto picks pma-voice first, then mumble-voip. |
voice.channelBase | int | 1000-9000000 | 91100 | First call channel. Calls use the next 900 ids. |
voice.endOnDispatch | bool | true | Off: the caller stays on the line after dispatch until you end the voice call. | |
voice.allowTransfer | bool | true | Dispatchers can hand the voice call to an on-duty player unit. |
Module defaults come from the matching Config block (for example pursuit.maxActive from Config.Pursuit.maxActive). career.xp*, career.gate*, mdt_status.*, mdt_tools.* and training.* have their defaults in code.