> For the complete documentation index, see [llms.txt](https://galaxis-studios.gitbook.io/galaxis-studios/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://galaxis-studios.gitbook.io/galaxis-studios/getting-started/dispatch-system.md).

# Dispatch System

{% embed url="<https://www.youtube.com/watch?v=wNeDd112zAA>" %}

\
\
This page explains how to configure and use the Dispatch System.

***

***

#### &#x20;🔊 Sound Cooldown

**Config.SoundCooldown**\
Prevent the same alert sound from repeating too quickly.

```lua
Config.SoundCooldown = {
  enabled = true,
  duration = 60000
}
```

💡 `60000` = 60 seconds minimum between identical sounds.

## 📋 Configuration Files

**cfg\_main.lua**\
Main system settings, UI defaults, and feature toggles.

**cfg\_alerts.lua**\
Alert types, grouping rules, and automatic event detection.

**cfg\_utils.lua**\
Postal zones and custom utility functions.

***

### ⚙️ Main Configuration

#### 🌐 Language Settings

**Config.Locale**\
Sets the default language for the dispatch system.

```lua
Config.Locale = 'en'
```

**Supported Languages:**

* `'en'` — English
* `'tr'` — Turkish
* `'de'` — German
* `'fr'` — French
* `'es'` — Spanish
* `'pl'` — Polish
* `'pt'` — Portuguese
* `'cz'` — Czech

💡 Add more languages by creating locale files in the `/locales/` folder.

***

#### 🧑‍✈️ Unit Display Format

**Config.UnitDisplay.mode**\
Determines how officer names and callsigns appear in alerts.

```lua
Config.UnitDisplay = {
    mode = 'name'
}
```

**Options:**

* `'name'` — Show only officer name/initials
  * Example: `J.Doe`
* `'callsign'` — Show only callsign (falls back to name if no callsign)
* `'callsign_name'` — Show both
  * Example: `23A | J.Doe`

***

#### 🧑‍✈️ Custom Callsigns (Server Export)

External scripts can assign a **custom callsign** per player, overriding the default callsign from player metadata.

**🔧 Export Syntax**

```lua
exports['glxs-dispatch']:SetCustomCallsign(source, callsign)
```

**Parameters:**

* `source` *(number)*\
  The server ID of the player.
* `callsign` *(string | nil)*
  * Pass a **string** to set a custom callsign.
  * Pass **nil** to clear/reset and revert to the default callsign.

**💻 Example: `/callsign` Command (Server-Side)**

Add this to any **server-side** script:

```lua
RegisterCommand('callsign', function(source, args)
    local callsign = args[1]

    if not callsign then
        return
    end

    -- Set the custom callsign for the player
    exports['glxs-dispatch']:SetCustomCallsign(source, callsign)
end, false)
```

Usage in-game:

```
/callsign 23A
```

This sets the player’s callsign to `23A` in the dispatch UI.

To reset back to default:

```lua
exports['glxs-dispatch']:SetCustomCallsign(source, nil)
```

***

#### 🚨 Job Restrictions

**Config.TargetJobs**\
Limit dispatch alerts to specific jobs only.

```lua
Config.TargetJobs = {
    enabled = false,
    jobs = { 'police', 'sheriff', 'lspd', 'bcso', 'ems' }
}
```

✅ **Allowed Jobs Examples:**

* `police`, `sheriff`, `lspd`, `bcso`
* `ems`, `ambulance`, `fire`

💡 Set `enabled = true` to activate job filtering.

***

#### 🚗 License Plate Obfuscation

**Config.PlateObfuscation**\
Partially hide license plates in vehicle-related alerts.

```lua
Config.PlateObfuscation = {
    enabled = true,
    chanceToHideChar = 0.5
}
```

**How it works:**

* Each character in the plate has a **50% chance** of being replaced with `*`.
* Example:
  * `ABC123` → `A*C1*3`

💡 Set `chanceToHideChar = 0.0` for full plates, `1.0` for fully hidden plates.

***

#### 🔇 Smart Mute

**Config.SmartMute**\
Automatically mute alerts during combat/shooting.

```lua
Config.SmartMute = {
    enabled = false,
    duration = 10000,
    checkInterval = 1000
}
```

* `duration` — Keep muted for **X milliseconds** after combat ends.
* `checkInterval` — How often to check combat state (ms).

⚠️ Recommended: Keep **disabled on production** servers to prevent missed alerts.

***

#### 🔊 Sound Cooldown

**Config.SoundCooldown**\
Prevents the same alert sound from repeating too quickly.

```lua
Config.SoundCooldown = {
    enabled = true,
    duration = 60000
}
```

💡 `60000` = **60 seconds** minimum between identical sounds.

***

#### 🎯 Detection Mode *(NEW in v1.0.3)*

**Config.DetectionMode**\
Controls how sensitive alert detection is for automatic events.

```lua
Config.DetectionMode = {
    mode = 'easy'  -- 'easy' or 'hard'
}
```

**Modes:**

* `'easy'` — Alerts trigger more easily (**recommended**)
  * ✅ Gunshot alerts: **No witness** check required – triggers immediately
  * ✅ Reckless driving: Manual speed check every 2 seconds – **100% reliable**
* `'hard'` — More realistic detection (requires witnesses)
  * ⚠️ Gunshot alerts: **Requires witnesses** to trigger
  * ⚠️ Reckless driving: Uses native GTA events – **less reliable** but more realistic

💡 Recommended: Use `'easy'` mode for **consistent** alert detection.

***

#### 📍 Location Display Format

**Config.LocationFormat**\
Controls how locations appear in alerts.

```lua
Config.LocationFormat = 1
```

**Options:**

1. Street name only
   * Example: `Power St`
2. Area/District only
   * Example: `Vespucci`
3. Both street and area
   * Example: `Power St, Vespucci`

***

#### 💡 Alert Suggestions

**Config.Suggest**\
Recommends nearby alerts to units.

```lua
Config.Suggest = {
    enabled = true,
    radius = 50.0,
    cooldownSec = 15,
    pulseUI = true
}
```

* `radius` — Maximum distance (meters) to suggest alerts
* `cooldownSec` — Wait X seconds before re-suggesting the same alert
* `pulseUI` — Highlight the **"Attach"** button for suggested alerts

***

#### ⏱️ Dispatch Settings

**Config.Dispatch**\
Alert timing and weapon filtering.

```lua
Config.Dispatch = {
    DefaultDelaySec = 5,
    WeaponIgnore = { 'WEAPON_STUNGUN', 'WEAPON_FIREEXTINGUISHER' }
}
```

* `DefaultDelaySec` — Delay (seconds) before alerts are sent
* `WeaponIgnore` — Weapons that **won't** trigger shooting alerts

***

### 🚨 Alert Configuration

#### 📊 Alert Grouping

**Config.AlertGrouping**\
Prevents spam by grouping similar alerts.

```lua
Config.AlertGrouping = {
    enabled = true,
    radius = 50.0,
    timeout = 30000,
    activeThreshold = 10,
    excludedCodes = { '10-99' }
}
```

**How it works:**

* Alerts within **50.0 meters** are grouped together
* Group expires after **30000 ms (30 seconds)**
* Shows **"ACTIVE"** badge after **10 grouped alerts**
* Critical codes like `'10-99'` (Officer Down) **bypass** grouping

***

#### 🎯 Automatic Event Detection

**Config.Events**\
Auto-trigger alerts when certain events occur.

```lua
Config.Events = {
    Shooting        = { enabled = true,  type = 'shooting',          cooldown = 8000 },
    VehicleShooting = { enabled = true,  type = 'vehicle_shooting',  cooldown = 8000 },
    RecklessDriving = { 
        enabled = true,  
        type = 'reckless_driving', 
        thresholdKmh = { 180.0, 200.0 },
        speedUnit = 'kmh',  -- NEW in v1.0.3: 'kmh' or 'mph'
        cooldown = 15000 
    },
    VehicleTheft    = { enabled = true,  type = 'vehicle_theft',     cooldown = 10000 },
    Fight           = { enabled = true,  type = 'fight',             cooldown = 15000 },
    Explosion       = { enabled = true,  type = 'explosion',         cooldown = 10000 },
    PlayerDown      = { enabled = false, type = 'player_down',       cooldown = 5000 },
    OfficerDown     = { enabled = false, type = 'officer_down',      cooldown = 5000 },
    EmsDown         = { enabled = false, type = 'ems_down',          cooldown = 5000 }
}
```

⚠️ **Note:** Officer/EMS/Civilian down alerts should be triggered **manually** by scripts for accuracy.

***

#### 🚗 Reckless Driving Speed Unit *(NEW in v1.0.3)*

**speedUnit**\
Choose between **KM/H** or **MPH** for speed thresholds.

**KM/H example:**

```lua
RecklessDriving = { 
    thresholdKmh = { 180.0, 200.0 },
    speedUnit = 'kmh'
}
```

**MPH example:**

```lua
RecklessDriving = { 
    thresholdKmh = { 112.0, 124.0 },  -- 112 mph ≈ 180 km/h
    speedUnit = 'mph'
}
```

💡 The system automatically converts **MPH to KM/H** internally.

***

### 🔧 Exported Functions

All exports are **client-side** (except the custom callsign export which is server-side) and automatically collect alert data such as location, vehicle, weapon, etc.

#### 📞 Standard Exports

**🔫 Shooting Alerts**

```lua
exports['glxs-dispatch']:Shooting()
exports['glxs-dispatch']:VehicleShooting()
```

**🚗 Traffic & Vehicle**

```lua
exports['glxs-dispatch']:RecklessDriving()
exports['glxs-dispatch']:VehicleTheft()
exports['glxs-dispatch']:Carjacking()
exports['glxs-dispatch']:CarBoosting()
exports['glxs-dispatch']:StreetRacing()
```

**🕵️ Criminal Activity**

```lua
exports['glxs-dispatch']:Fight()
exports['glxs-dispatch']:SuspiciousActivity(message)
exports['glxs-dispatch']:DrugSale()
exports['glxs-dispatch']:Explosion()
```

**💰 Robberies**

```lua
exports['glxs-dispatch']:StoreRobbery()
exports['glxs-dispatch']:HouseRobbery()
exports['glxs-dispatch']:BankRobbery(message)
exports['glxs-dispatch']:PacificBankRobbery()
exports['glxs-dispatch']:PaletoBankRobbery()
exports['glxs-dispatch']:BobcatRobbery()
exports['glxs-dispatch']:ArtGalleryRobbery()
exports['glxs-dispatch']:HumaneLabsRobbery()
exports['glxs-dispatch']:UnionRobbery()
exports['glxs-dispatch']:VangelicoRobbery()
exports['glxs-dispatch']:YachtRobbery()
exports['glxs-dispatch']:TrainRobbery()
exports['glxs-dispatch']:VanRobbery()
exports['glxs-dispatch']:UndergroundRobbery()
exports['glxs-dispatch']:DrugBoatRobbery()
exports['glxs-dispatch']:SignRobbery()
```

**🚑 Emergency Services**

```lua
exports['glxs-dispatch']:OfficerDown()
exports['glxs-dispatch']:OfficerBackup()
exports['glxs-dispatch']:OfficerDistress()
exports['glxs-dispatch']:EmsDown()
exports['glxs-dispatch']:PlayerDown()
exports['glxs-dispatch']:CivilianDead()
```

**☎️ 911/311 Calls**

```lua
exports['glxs-dispatch']:Call911()
exports['glxs-dispatch']:Call911Anonymous()
exports['glxs-dispatch']:Call311()
```

***

### 💻 Usage Examples

#### Example 1: Trigger Store Robbery

```lua
-- In your robbery script (client-side)
RegisterNetEvent('myStore:startRobbery', function()
    exports['glxs-dispatch']:StoreRobbery()
end)
```

***

#### Example 2: Bank Robbery with Custom Message

```lua
-- Pacific Bank with custom description
RegisterNetEvent('pacificBank:alarm', function()
    exports['glxs-dispatch']:BankRobbery("Vault breach detected - Multiple suspects")
end)
```

***

#### Example 3: Officer Down Alert

```lua
-- When officer health drops below threshold
CreateThread(function()
    while true do
        Wait(1000)
        if IsPedDeadOrDying(PlayerPedId()) and isPoliceJob then
            exports['glxs-dispatch']:OfficerDown()
            break
        end
    end
end)
```

***

#### Example 4: Suspicious Activity with Custom Message

```lua
-- Report suspicious behavior
RegisterCommand('report', function()
    exports['glxs-dispatch']:SuspiciousActivity("Suspicious individual near ATM")
end)
```

***

### 🛠️ Custom Alerts

Create your own alert types in **3 simple steps**.

#### Step 1: Define Alert Type in Config

Add your alert to `config/cfg_alerts.lua`:

```lua
Config.AlertTypes = {
    ['my_custom_robbery'] = {
        code = '10-99',                       -- Radio code (shown in UI)
        title = 'Custom Alert',               -- Alert title
        message = 'Custom event reported',    -- Default message
        icon = 'fas fa-exclamation-triangle', -- FontAwesome icon
        priority = 1,                         -- 1=Critical, 2=High, 3=Normal
        soundFile = 'dp_generic.ogg',         -- Sound file from /web/sounds/
        fields = { 
            'location',
            'gender',
            'name',
            'weapon',
            'vehicle',
            'plate',
            'color',
            'vehicleClass',
            'doorCount',
            'heading',
            'message'
        },
        targetJobs = { 'police' },
        locationAccuracy = {
            enabled = false,       -- Location uncertainty enabled
            chanceForExact = 0.0,  -- Chance for exact location (0.0-1.0)
            offsetRange = 50.0,    -- Random offset +/- X meters
            radiusSize = 75.0      -- Radius circle size (meters)
        },    
        blip = {
            sprite = 161,          -- Blip icon ID
            color = 1,             -- 1=Red, 2=Green, 3=Blue, 5=Yellow...
            scale = 1.0,           -- Size (0.5-2.0)
            duration = 60000,      -- Duration on map (ms)
            flash = true,          -- Flash effect
            showRadius = true,     -- Show radius circle
        }
    }
}
```

***

#### Step 2: Create Export Function

Open `client/cl_exports.lua` and scroll to the bottom where you'll find templates.

**Simple Alert (No Parameters):**

```lua
local function MyCustomRobbery()
    local galaxis = CollectAlertContext()
    TriggerServerEvent('glxs-dispatch:server:SendAlert', 'my_custom_robbery', galaxis.coords, galaxis)
end

exports('MyCustomRobbery', MyCustomRobbery)
```

**Alert with Message:**

```lua
local function MyCustomRobbery(message)
    local galaxis = CollectAlertContext()
    galaxis.message = message
    TriggerServerEvent('glxs-dispatch:server:SendAlert', 'my_custom_robbery', galaxis.coords, galaxis)
end

exports('MyCustomRobbery', MyCustomRobbery)
```

***

#### Step 3: Use Your Export

```lua
-- In your script
exports['glxs-dispatch']:MyCustomRobbery("Vault breach in progress!")
```

***

#### 📋 Available Templates in `cl_exports.lua`

The file includes ready-to-use templates:

* **EXAMPLE 1:** Simple alert (no parameters)
* **EXAMPLE 2:** Alert with message parameter
* **EXAMPLE 3:** Alert with extra custom data

Simply **uncomment and modify** the template that fits your needs!

***

### 📊 Available Alert Data

All exports automatically collect:

* `coords` — Player coordinates (automatic)
* `vehicle` — Vehicle model name (automatic, if in vehicle)
* `plate` — License plate (automatic, if in vehicle)
* `color` — Vehicle color (automatic, if in vehicle)
* `weapon` — Current weapon name (automatic, if equipped)
* `message` — Custom description (parameter)
* `gender` — Player gender (server-side, automatic)
* `name` — Player name (server-side, automatic)
* `location` — Street / Area name (server-side, automatic)

💡 Use the `fields` array in each alert config to control **which data displays** in the UI.

***

### 📊 Discord Webhook Logging

Automatically log dispatch alerts to Discord with detailed player and alert information.

#### Setup

Get your Discord webhook URL and add to `config/cfg_main.lua`:

```lua
Config.Logging = {
    enabled = true,
    webhook = 'YOUR_WEBHOOK_URL_HERE',
    
    -- Choose which alert types to log
    alertTypes = {
        ['shooting']         = true,  -- Gunfire/Shots Fired
        ['shooting_vehicle'] = true,  -- Shots from Vehicle
        ['vehicle_theft']    = true,  -- Vehicle Theft
        ['reckless_driving'] = false, -- Speeding/Reckless Driving
        ['explosion']        = true,  -- Explosions
        ['911']              = true,  -- 911 Emergency Calls
        ['911a']             = true,  -- 311 Non-Emergency Calls (alias)
        ['311']              = true,
    },
    
    -- Privacy settings
    includePlayerName   = true,
    includePlayerId     = true,
    includeSteamId      = true,
    includeDiscordId    = true,
    includeLicense      = true,
    includeIP           = false, -- Recommended: false
    includeCoords       = true,
    includeAlertData    = true,
    
    -- Appearance
    embedColor = 15158332,       -- Decimal color code
    embedFooter = 'GLXS Dispatch',
}
```

**Logged Information:**

* Player identifiers (Steam, Discord, License)
* Alert type, message, and coordinates
* Vehicle info, weapons, caller data
* Timestamp

***

### 🧭 Quick Reference

#### Main Settings

| Key                               | Description                | Default  |
| --------------------------------- | -------------------------- | -------- |
| `Config.Locale`                   | Language                   | `'en'`   |
| `Config.UnitDisplay.mode`         | Name / callsign format     | `'name'` |
| `Config.TargetJobs.enabled`       | Job filtering              | `true`   |
| `Config.PlateObfuscation.enabled` | Hide plate characters      | `true`   |
| `Config.SmartMute.enabled`        | Auto-mute in combat        | `false`  |
| `Config.LocationFormat`           | Location display format    | `1`      |
| `Config.DetectionMode.mode`       | Auto-detection sensitivity | `'hard'` |

#### Alert Settings

| Key                               | Description           | Default |
| --------------------------------- | --------------------- | ------- |
| `Config.AlertGrouping.enabled`    | Group similar alerts  | `true`  |
| `Config.AlertGrouping.radius`     | Group radius (meters) | `50.0`  |
| `Config.AlertGrouping.timeout`    | Group timeout (ms)    | `30000` |
| `Config.Dispatch.DefaultDelaySec` | Alert delay (seconds) | `5`     |

***

### 🧰 Troubleshooting

* **Alerts not showing**
  * Check `Config.TargetJobs.enabled` and `jobs` list.
* **Wrong language**
  * Verify `Config.Locale` and locale file in `/locales/`.
* **Too many alerts / spam**
  * Ensure `Config.AlertGrouping.enabled = true`.
* **Duplicate sounds**
  * Enable `Config.SoundCooldown.enabled`.
* **Missing officer names / callsigns**
  * Units might not be attached – use the **“Join Call”** button.
  * For custom codes, verify `SetCustomCallsign` usage.
* **Plates fully visible**
  * Check `Config.PlateObfuscation.enabled` and `chanceToHideChar`.
* **Alerts during combat**
  * Enable `Config.SmartMute` (use with caution).

***

### 📚 Additional Resources

#### Adding New Locale

1. Create `/locales/xx.json` (replace `xx` with language code).
2. Copy structure from `en.json`.
3. Translate all keys.
4. Set `Config.Locale = 'xx'`.

#### Framework Support

* ✅ ESX Legacy (auto-detected)
* ✅ QBCore (auto-detected)
* ✅ QBox (auto-detected)

💡 No manual framework configuration needed.

***

**Version:** `1.0.4`\
**Support:** Discord / Forum Thread
