Emergency Response Simulator for FiveM

Emergency Response Simulator for FiveM

A guide to install Emergency Response Simulator for FiveM


📋 Table of Contents

  1. 🎥 Installation Tutorial
  2. 🛒 Purchase Information
  3. ⚠️ Important Pre-Installation Notes
  4. 🔧 System Requirements & Compatibility
    1. fxServer (Artifacts) & Gamebuild version
    2. OneSync Requirements
    3. Framework Compatibility
      1. ESX Integration
      2. QBCore Integration
    4. Known Incompatibilities
  5. 📦 Installation Process
    1. Step 1: Download Required Resources
      1. Core Resources (Required)
      2. Optional Resources
      3. Add-on DLCs
    2. Step 2: File Placement
    3. Step 3: Server Configuration
  6. ⚙️ Configuration Setup
    1. Required Tools
    2. Configuration Files
    3. Configuration Process
  7. 🎯 Creating Custom Callouts
    1. Overview
    2. Callout Creator Pack
    3. Development Process
  8. 🔧 Open Source Functions / Events
    1. Client Functions / Events (night_ers/client/c_functions.lua)
    2. Server Functions / Events (night_ers/server/s_functions.lua)
  9. 🔗 night_shifts_mdt Integration — Field Ownership
    1. NPC payload (pedData)
    2. Vehicle payload (vehicleData)
    3. Debug printing
  10. 🛠️ ERS Functions Reference
    1. Client Functions
    2. Server Functions
  11. 📤 Exports
    1. Client Exports (night_ers/client/exports_client.lua)
      1. Start pursuit (callouts & other integrations)
      2. NPC backup — pursuit & service (other resources)
    2. Server Exports (night_ers/server/exports_server.lua)
      1. createCallout vs SendCalloutOfferToPlayer (server scripts)
      2. Spawning Smart Fires (server)
  12. 🎨 Props by NovelaxNeko
    1. 10 Free Included Props
  13. 🔧 Troubleshooting
    1. Common Issues
      1. MDT Integration Issues
      2. Hosting-Specific Issues
    2. Compatibility Checklist
  14. 💬 Support & Community
    1. Getting Help
    2. Feedback & Reviews

🎥 Installation Tutorial

Watch our comprehensive installation guide:

Installation Tutorial by Skull


🛒 Purchase Information

Get Emergency Response Simulator:

Purchase on Nights Software Store


⚠️ Important Pre-Installation Notes

Critical Installation Order: Always follow this exact sequence to avoid parsing errors in the F8 console:

  1. Set FTP Transfer Type to Binary
  2. Download ZIP Package from CFX Portal
  3. Unpack in a local folder
  4. Set File Transfer Protocol (FTP) to binary
  5. Drag files from local machine to server resources folder
  6. Add to server.cfg (ensure script)
  7. Boot up the server

Support Policy: Follow this guide step by step. If you’re stuck, ask for support in our Discord and provide the specific step name. Do not skip steps.


🔧 System Requirements & Compatibility

fxServer (Artifacts) & Gamebuild version

  • ✅ Recommended Gamebuild: 3323
  • ✅ Recommended Artifacts: 21703(+)
  • ❌ Considered Not Compatible: Other Gamebuilds below 2944 and above 3323 and Artifacts.

Important: If you are using different Gamebuilds or Artifacts, trial and error this. Please inform us of (in)compatibility.

OneSync Requirements

  • ✅ Required: OneSync Legacy or Infinity
  • ⚠️ Note: Some hosting companies require setting Enable Beyond to 1 in dashboard

Framework Compatibility

Standalone Mode

  • ✅ Works without any framework
  • ✅ Compatible with most known frameworks

ESX Integration

  • Permissions: Configure job-based access in night_ers/config/config.lua
  • Weapons: Configure in night_ers/config/gear-config.lua
  • Code: Adjust item distribution in night_ers/client/c_functions.lua

QBCore Integration

  • Permissions: Configure job-based or QB permissions in night_ers/config/config.lua
  • Weapons: Configure in night_ers/config/gear-config.lua
  • Code: Adjust item distribution in night_ers/client/c_functions.lua

Known Incompatibilities

Incompatible Resources:

  • RemoveCops-AI
  • Andrew’s Advanced AI
  • Realistic Euphoria Physics
  • RedSaints Stretcher/Ambulance
  • Improved-Seat-Shuffle-FiveM by Dalrae1
  • Clear world commands / Anti-cheat (resolve with your provider)

📦 Installation Process

Step 1: Download Required Resources

Download these packages from the CFX Portal in the exact order listed:

Core Resources (Required)

  1. SmartHoseLite (Required)
    • Provided by London Studios
    • Enables water hose functionality for fire extinguishing
    • *Must start before SmartFiresLite*SmartFiresLite consumes SmartHose exports at runtime.
  2. SmartFiresLite (Required)
    • Provided by London Studios
    • Enables fire spawning functionality
    • Note: Keep Lite named SmartFiresLite. If you use full Smart Fires instead, rename the folder to exactly SmartFires (case sensitive), per London Studios. This also goes for SmartFires v2: SmartFires.
  3. Emergency Response Simulator (Required)
    • Main gamemode with 100+ callouts
    • Supports Police, Fire, Medic, and Tow services

Optional Resources

  1. Night Discord API (Optional - Included with ERS Essential, Plus and Ultimate)
  2. Night Subtitles (Optional - Included with ERS Essential, Plus and Ultimate)
    • Movie-style subtitle display
    • View Features
    • Drag-and-drop installation
  3. Nearest Postal & Map (Optional - Free)
  4. Night Shifts MDT (Optional - Included with ERS Plus and Ultimate)
  5. Theebu Flatbeds Lite (Optional - Included with ERS Essential, Plus and Ultimate)

Add-on DLCs

  1. World Events Add-on (Optional)
  2. Dynamic Weighing Stations (Optional)
  3. K9 Dog Handler (Optional)

Step 2: File Placement

Critical: Place all resources in your resources folder and DO NOT RENAME them. Use exact names as specified in this documentation.

Step 3: Server Configuration

Add to your server.cfg in exact order:

# Optional Resources
ensure night_discordapi
ensure night_subtitles
ensure nearest-postal
ensure map

# Required Resources
ensure SmartHoseLite   # or SmartHose if you have full version (must start before SmartFiresLite)
ensure SmartFiresLite  # or SmartFires if you have full version

# Core ERS
ensure night_shifts_mdt
ensure night_ers

# Optional Add-ons
ensure ebu_flatbeds_ers
ensure night_ers_worldevents
ensure night_ers_weighstation
ensure night_ers_k9

# Optional Callout Packs
ensure night_ers_cp1

⚙️ Configuration Setup

Required Tools

Visual Studio Code: We strongly recommend downloading VS Code for editing Lua files.

Configuration Files

File Purpose
night_ers/config/config.lua Main configuration
night_ers/config/gear-config.lua Weapons and clothing
night_ers/config/impound-config.lua Impound settings
night_ers/config/leaderboard-config.lua Leaderboard settings
night_ers/config/npcbackup-config.lua NPC Backup settings
night_ers/config/persistententity-config.lua NPC personal data settings
night_ers/config/pullover-config.lua Traffic stop settings
night_ers/config/pursuit-config.lua Pursuit settings
night_ers/config/questioning-config.lua NPC questioning settings
night_ers/config/sound-config.lua Sound & Voice over settings
night_ers/config/spikestrip-config.lua Spikestrip settings
night_ers/config/stretcher-config.lua Stretcher settings
night_ers/config/vehinteractions-config.lua Vehicle search settings
night_ers/client/c_functions.lua Client-side functions / events
night_ers/server/s_functions.lua Server-side functions / events

Configuration Process

  1. Open VS Code and navigate to the config files Download Visual Studio Code
  2. Read thoroughly - each line has explanatory comments
  3. Configure in order - work from top to bottom
  4. Watch for notes - important warnings are clearly marked
  5. Test frequently - use F8 console and server console for error checking

Time Investment: Plan adequate time for configuration. Each variable is named descriptively to help you understand its purpose.


🎯 Creating Custom Callouts

Overview

ERS includes open-source callout scripts in night_ers/callouts/plugins/*.lua. You can add, remove, or edit callouts using built-in ERS functions.

Callout Creator Pack

Free Resource: Download our Callout Creator Pack for examples and documentation.

Development Process

  1. Copy Template: Use existing callout file from night_ers/callouts/plugins/
  2. Rename File: Use your desired callout name
  3. Modify Code: Adjust config, client, and server sections
  4. Test Thoroughly: Restart script and test with /requestcallout

Support Notice: Nights Software does not provide custom callout creation support beyond this documentation. Ask the community for help!


🔧 Open Source Functions / Events

Client Functions / Events (night_ers/client/c_functions.lua)

Event Triggers

--- Handles when a callout is offered to the player.
-- @param calloutData table The data of the callout.
function OnIsOfferedCallout(calloutData)
    -- Add your code here. Keep in mind they are offered a callout. It is possible they will not accept the callout.
    -- local jsonReady = CloneWithoutFunctions(calloutData)
    TriggerServerEvent('ErsIntegration::OnIsOfferedCallout', calloutData)
end

--- Handles when a callout is accepted by the player.
-- @param calloutData table The data of the callout.
function OnAcceptedCalloutOffer(calloutData)
    -- Add your code here. Keep in mind they have accepted a callout. It is possible they will cancel before arrival (and spawn of entities).
    TriggerServerEvent('ErsIntegration::OnAcceptedCalloutOffer', calloutData)
end

--- Handles when the player arrives at a callout.
-- @param calloutData table The data of the callout.
function OnArrivedAtCallout(calloutData)
    -- Add your code here. This is triggered right before the entities are built for a callout. This code will execute first.
    TriggerServerEvent('ErsIntegration::OnArrivedAtCallout', calloutData)
end

--- Handles when a callout is ended (as the host). This does not mean the callout is completed.
-- @param calloutData table The data of the callout.
function OnEndedACallout(calloutData)
    -- Add your code here. This is triggered right before the entities are deleted or callout is cancelled serverside. This code will execute first.
    TriggerServerEvent('ErsIntegration::OnEndedACallout', calloutData)
end

--- Handles when a callout is completed successfully.
-- @param calloutData table The data of the callout.
function OnCalloutCompletedSuccesfully(calloutData)
    -- Add your code here. This is triggered right after the entire callout task list is completed.
    TriggerServerEvent('ErsIntegration::OnCalloutCompletedSuccesfully', calloutData)
end

--- Handles when a pullover is initiated.
-- @param pedData table The data of the ped.
-- @param vehicleData table The data of the vehicle.
function OnPullover(pedData, vehicleData)
    -- Add your custom pullover logic here or trigger (and build) a server event to handle it.
    TriggerServerEvent('ErsIntegration::OnPullover', pedData, vehicleData)
end

--- Handles when a pullover is ended.
-- @param pedData table The data of the ped.
-- @param vehicleData table The data of the vehicle.
function OnPulloverEnded(pedData, vehicleData)
    -- Add your custom pullover ended logic here or trigger (and build) a server event to handle it.
    TriggerServerEvent('ErsIntegration::OnPulloverEnded', pedData, vehicleData)
end

--- Handles when a pursuit is started.
-- @param pedData table The data of the ped.
function OnPursuitStarted(pedData)
    -- Add your custom pursuit started logic here or trigger (and build) a server event to handle it.
    TriggerServerEvent('ErsIntegration::OnPursuitStarted', pedData)
end

--- Handles when a pursuit is ended.
-- @param pedData table The data of the ped.
function OnPursuitEnded(pedData)
    -- Add your custom pursuit ended logic here or trigger (and build) a server event to handle it.
    TriggerServerEvent('ErsIntegration::OnPursuitEnded', pedData)
end
  • Explore the file for more…

Server Functions / Events (night_ers/server/s_functions.lua)

--- Handles user shift toggle events.
-- @param src number The source ID of the user who toggled shift.
-- @param isOnShift boolean Whether the user is now on shift or off shift.
-- @param serviceType string The service type of the shift (police, fire, ambulance, tow).
RegisterServerEvent("ErsIntegration::OnToggleShift")
AddEventHandler("ErsIntegration::OnToggleShift", function(source, isOnShift, serviceType)
    -- Add your custom shift toggle logic here
    -- print(source, isOnShift, serviceType)
end)

--- Handles first-time NPC interaction events.
-- @param src number The source ID of the user who interacted with the NPC.
-- @param pedData table The complete data table of the NPC being interacted with.
-- @param context string The interaction context:
--
-- Timing & data source:
--   * Without night_shifts_mdt, this event fires immediately with ERS-generated
--     random identity data — legacy behaviour.
--   * With night_shifts_mdt running, this event fires ONCE per first interaction,
--     AFTER the MDT identity lookup has merged into pedData. Identity fields come
--     from the MDT's persistent civilian record — the same values the officer sees
--     in the MDT UI.
--   * License_* and FlagsOrMarkers will be nil when the MDT is active. Query the
--     MDT exports for warrants/flags/licenses instead.
--   * If the MDT identity never resolves within ~5s, the event still fires
--     once with the partial pedData and identity fields stay nil.
RegisterServerEvent("ErsIntegration::OnFirstNPCInteraction")
AddEventHandler("ErsIntegration::OnFirstNPCInteraction", function(source, pedData, context)
    -- Add your custom NPC interaction logic here
    --[[
        Context frequency analysis:
        - "on_interaction": Very common (normal ped interactions)
        - "on_aiming_at_ped": Common (when aiming at peds and ordering them to kneel)
        - "on_pullover": Common (traffic stops)
        - "on_pursuit_start": Uncommon (callout/world event peds fleeing, regular peds are usually interacted with first)
        - "on_pursuit_end": Very rare (edge cases only)
        - "on_pullover_end": Very rare (edge cases only)
    ]]
    -- print(source, json.encode(pedData, { indent = true }), context)
end)

-- Handles first vehicle interaction events.
-- @param src number The source ID of the user who interacted with the vehicle.
-- @param vehicleData table The complete data table of the vehicle being interacted with.
-- @param context string The interaction context:
--
-- Timing & data source:
--   * Without night_shifts_mdt, this event fires immediately with ERS-rolled
--     random compliance data — legacy behaviour.
--   * With night_shifts_mdt running, this event fires ONCE per first interaction,
--     AFTER the MDT vehicle lookup has merged into vehicleData. Compliance fields
--     and owner_name come from the MDT's persistent vehicle record. For stolen
--     vehicles, owner_name is the victim's name (taken from identity.owner)
--     rather than the driver.
--   * If the MDT identity never resolves within ~5s, the event still fires
--     once with the partial vehicleData (compliance fields stay nil).
RegisterServerEvent("ErsIntegration::OnFirstVehicleInteraction")
AddEventHandler("ErsIntegration::OnFirstVehicleInteraction", function(source, vehicleData, context)
    -- Add your custom vehicle interaction logic here
    --[[
        Context frequency analysis:
        -- Explained: "First interaction with this specific vehicle instance in current session, unless the network ID was replaced. Then it can be an other instance for the same vehicle."

        - "on_pullover": Very common (traffic stops)
        - "on_vehicle_search": Common (when searching for vehicles)
        - "on_pursuit_start": Uncommon (callout/world event peds fleeing whilst in a vehicle and not interacted with yet)
        - "on_pullover_end": Very rare (edge cases only)
    ]]
    -- print(source, json.encode(vehicleData, { indent = true }), context)
end)

--- Handles when a callout is offered.
-- @param calloutData table The data of the callout.
RegisterServerEvent("ErsIntegration::OnIsOfferedCallout")
AddEventHandler("ErsIntegration::OnIsOfferedCallout", function(calloutData)
    local src = source
    -- Add your custom callout offered logic here
    -- print(src, calloutData)
end)

--- Handles when a callout is accepted.
-- @param calloutData table The data of the callout.
RegisterServerEvent("ErsIntegration::OnAcceptedCalloutOffer")
AddEventHandler("ErsIntegration::OnAcceptedCalloutOffer", function(calloutData)
    local src = source
    -- Add your custom callout accepted logic here
    -- print(src, calloutData)
end)

--- Handles when a callout is arrived at.
-- @param calloutData table The data of the callout.
RegisterServerEvent("ErsIntegration::OnArrivedAtCallout")
AddEventHandler("ErsIntegration::OnArrivedAtCallout", function(calloutData)
    local src = source
    -- Add your custom callout arrived at logic here
    -- print(src, calloutData)
end)

--- Handles when a callout is ended.
RegisterServerEvent("ErsIntegration::OnEndedACallout")
AddEventHandler("ErsIntegration::OnEndedACallout", function()
    local src = source
    -- Add your custom callout ended logic here
    -- print(src)
end)

--- Handles when a callout is completed successfully.
-- @param calloutData table The data of the callout.
RegisterServerEvent("ErsIntegration::OnCalloutCompletedSuccesfully")
AddEventHandler("ErsIntegration::OnCalloutCompletedSuccesfully", function(calloutData)
    local src = source
    -- Add your custom callout completed successfully logic here
    -- print(src, calloutData)
end)

--- Handles when a pullover is initiated.
-- @param pedData table The data of the ped.
-- @param vehicleData table The data of the vehicle.
RegisterServerEvent("ErsIntegration::OnPullover")
AddEventHandler("ErsIntegration::OnPullover", function(pedData, vehicleData)
    local src = source
    -- Add your custom pullover logic here
    -- print(src, pedData, vehicleData)
end)

--- Handles when a pullover is ended.
-- @param pedData table The data of the ped.
-- @param vehicleData table The data of the vehicle.
RegisterServerEvent("ErsIntegration::OnPulloverEnded")
AddEventHandler("ErsIntegration::OnPulloverEnded", function(pedData, vehicleData)
    local src = source
    -- Add your custom pullover ended logic here
    -- print(src, pedData, vehicleData)
end)

--- Handles when a pursuit is started.
-- @param pedNetId number The network ID of the ped.
RegisterServerEvent("ErsIntegration::OnPursuitStarted")
AddEventHandler("ErsIntegration::OnPursuitStarted", function(pedData)
    local src = source
    -- Add your custom pursuit started logic here
    -- print(src, pedData)
end)

--- Handles when a pursuit is ended.
-- @param pedData table The data of the ped.
RegisterServerEvent("ErsIntegration::OnPursuitEnded")
AddEventHandler("ErsIntegration::OnPursuitEnded", function(pedData)
    local src = source
    -- Add your custom pursuit ended logic here, note that it's possible that the ped is being deleted on losing the target.
    -- print(src, pedData)
end)
  • Explore the file for more…

🔗 night_shifts_mdt Integration — Field Ownership

When the optional night_shifts_mdt resource is running, the MDT becomes the single source of truth for identity and vehicle compliance data. ERS resolves the MDT identity on the client, BEFORE asking the server for pedData / vehicleData, then forwards the resolved identity inline so the server can merge it synchronously. The OnFirstNPCInteraction / OnFirstVehicleInteraction events fire once, in the same tick as the underlying request, with MDT-authoritative values already overlaid into the existing ERS field shape — external integrations that subscribe to these events keep working without any code changes and never see an unmerged placeholder payload.

NPC payload (pedData)

Field With night_shifts_mdt Without night_shifts_mdt
FirstName, LastName, DOB, Gender MDT (persistent civilian record) ERS (random rolls)
Address, City, PostalCode, State, Country MDT ERS
Email, PhoneNumber, Nationality MDT ERS
ProfilePicture MDT (pictureUrl) ERS (model-derived)
License_Car, License_Bike, License_Boat, License_Truck, License_Pilot (+ _Is_Valid / _Colour / _Icon per line, e.g. License_Car_Is_Valid) Same shape as plain ERS — same pedData keys. With MDT, each line is filled from the civilian’s PNC licence row for that fixed type id: License_Cardriver_license, License_Bikemotorcycle_license, License_Boatboat_license, License_Truckcommercial_driver_license, License_Pilotpilot_license. Those ids are not configurable (only the labels in admin). If there is no row for a type, the card still shows the slot, usually as no licence. Without MDT, ERS random rolls. ERS (random rolls)
FlagsOrMarkers Use it like vanilla ERS. Keep reading pedData.FlagsOrMarkers on your existing server events (OnFirstNPCInteraction, pullover, etc.). With the MDT on, that object reflects the civilian’s Important Notices from the MDT instead of a random roll. You do not need a different field or a second integration path. ERS (random rolls)
mdtCivilianId, mdtPersonalId Set on **mdt-merged** payloads — MDT civilian PK and dossier id for integrations (n/a — MDT not running)
AddressType ERS (always — situational) ERS
Inventory, isDrunk, isDrugged, BehaviourState ERS (always — situational) ERS
MassiveBleeding, Airway, Breathing, Circulation, Hypothermia, CPR ERS (always — medical) ERS

Vehicle payload (vehicleData)

Field With night_shifts_mdt Without night_shifts_mdt
tax, mot, insurance, stolen, bolo, bolo_description MDT (persistent vehicle record) ERS (random rolls)
owner_name MDT (identity.owner.firstName + lastName — falls back to driver name) ERS (driver / random)
build_year MDT if known (vehicle.buildYear), else ERS roll ERS (random roll)
make, model, color, vehicle_class, license_plate, vehicle_picture_url ERS (vehicle attributes) ERS
inventory ERS (always — situational) ERS

Debug printing

When Config.Debug = true, every OnFirst* event payload is pretty-printed to the server console with a mode tag indicating how the data was sourced:

Mode Meaning
mdt-merged MDT identity resolved on the client and merged into the payload before firing. The common path when night_shifts_mdt is running.
mdt-disabled night_shifts_mdt is not running. ERS data fired immediately (legacy behaviour).
mdt-no-civilian Ped data was requested without an MDT-merged civilian id (non-standard integration path).
mdt-no-vehicle Vehicle data was requested without MDT-backed vehicle identity (non-standard integration path).

Use these tags when debugging server-side integrations to confirm which sourcing path fired for each OnFirst* event.


🛠️ ERS Functions Reference

Client Functions

Function Description
ERS_SetMovementAnimClipSetToPed(ped, clipset) Apply movement style
ERS_SpawnConfiguredWeaponForPed(ped, calloutDataClient) Spawn weapon by chance
ERS_RequestNetControlForEntity(entityId) Request entity control
ERS_PerformTimedActionOnPed(calloutDataClient, pedList) Execute pre-configured ped behaviors
ERS_CreateTemporaryBlipForEntities(entityList, timeoutInMs) Create temporary blips
ERS_SpawnParticlesWithinRange(coords, diameter, particleDict, particleName, particleSize, particleAmount, timeout, chanceToExplode) Spawn particles with explosion chance
ERS_GetRandomCoordinateWithinRangeOfCoordinate(coords, diameter) Get random coordinates
ERS_SetPedToFleeFromPlayer(ped) Make ped flee
ERS_SetPedToAttackPlayer(ped) Make ped attack
ERS_SetPedToSurrender(ped) Make ped surrender
ERS_ApplyBloodToPed(ped) Apply blood to ped
ERS_CreateBloodPuddleAtPed(ped) Create blood puddle
ERS_SetPedToPassout(ped) Make ped pass out
ERS_ClearPedTasksAndBlockEvents(ped) Clear ped tasks
ERS_SetPedAsDrunkPed(ped) Apply drunk movement
ERS_GetIsPedADrunkPed(ped) Check if ped is drunk
ERS_CheckIfPedIsAlive(ped) Check ped health status
ERS_IsPedAnAnimalPed(ped) Check if ped is animal
ERS_SetRandomDamageToVehicle(veh) Apply vehicle damage
ERS_CreateFlareAtCoordinate(coords) Create red flare
ERS_GetSafeSpawnPointForNPCVehicle() Find safe spawn point
ERS_SelectRandomMovementClipSet() Get random movement style
ERS_SelectMentalHealthPersonScenario() Get mental health scenario
ERS_SelectRandomBystanderScenario() Get bystander scenario
ERS_SelectRandomProtesterScenario() Get protester scenario
ERS_SelectRandomWoundedPersonScenario() Get wounded person scenario
ERS_SelectStandingByFireScenario() Get fire scenario
ERS_PedEquipWeapon(ped, weaponModel) Equip weapon to ped
ERS_DeleteEntityFromCallout(entityId) Delete entity

Server Functions

Function Description
ERS_CreatePed(model, coords, heading) Create synchronized ped
ERS_CreateObject(model, coords, heading) Create synchronized object
ERS_CreateVehicle(model, vehType, coords, vehHeading) Create synchronized vehicle
ERS_GetRandomCoordinateWithinRangeOfCoordinate(coords, diameter) Get random coordinates
ERS_GetRandomModel(modelList) Select random model

📤 Exports

Client Exports (night_ers/client/exports_client.lua)

-- Get player status
local isOnShift = exports['night_ers']:getIsPlayerOnShift()
local getPlayerActiveServiceType = exports['night_ers']:getPlayerActiveServiceType()
local isPlayerAttachedToCallout = exports['night_ers']:getIsPlayerAttachedToCallout()
local isPlayerTrackingUnit = exports['night_ers']:getIsPlayerTrackingUnit()

-- Other
exports['night_ers']:playRadioAnimation()
exports['night_ers']:toggleDispatchMessages()
exports['night_ers']:toggleHints()
exports['night_ers']:toggleShift()
exports['night_ers']:trackPlayerCallout(targetSource)
exports['night_ers']:ERS_PedEquipWeapon(pedEntityId, weaponModelName, ammo)
exports['night_ers']:SetERSVehicleInfoDisplay(display) -- Sets the display for vehicle information on traffic stops to true or false.
exports['night_ers']:SetERSIDCardInfoDisplay(display) -- Sets the display for ID cards to true or false.

Start pursuit (callouts & other integrations)

Use from client Lua in resources that ensure / dependency on night_ers. There is no server export for this; if your logic runs on the server, trigger the officer’s client (e.g. your own event) and call the export there.

Export Notes
StartPursuit(pedNetId) pedNetId is the suspect’s network id (e.g. NetworkGetNetworkIdFromEntity(suspectPed)). Returns **true** if ERS entered pursuit mode, **false** if it refused (pursuit disabled in config, player not on police service, invalid net id, already in a pursuit or cancel-in-progress, or ped / vehicle data could not be resolved for pursuit init).

After a successful start, the player is in pursuit mode and you can use **RequestNPCPursuitBackup** / **CancelNPCPursuitBackup** as documented below.

local netId = NetworkGetNetworkIdFromEntity(suspectPed)
local started = exports['night_ers']:StartPursuit(netId)

NPC backup — pursuit & service (other resources)

Use these from client scripts in resources that ensure / dependency on night_ers. Pursuit backup exports only work while the player is in pursuit mode (including after a successful **StartPursuit** from another resource).

Export Notes
RequestNPCPursuitBackup(unitType) Request pursuit NPC backup, or toggle-cancel by calling again with the same unitType while pending. Returns dispatched, reason.
CancelNPCPursuitBackup(serverDeleteDelayMs?) Cancels active pursuit NPC backup without a unitType. Optional delay (ms) for server-side cleanup; omit or 0 for immediate.
RequestNPCBackup(backupType) Service / road NPC backup. Returns dispatched, reason; when dispatched is false, reason is "unknown_backup_type".
CancelNPCBackup(backupType, mustNotify) Cancels matching service backup. mustNotify controls in-game notification behaviour (bool).

Pursuit unitType must match night_ers/config/pursuit-config.luaConfig.PursuitBackupTypes[].PursuitType (stock values, all lowercase):

"light", "medium", "heavy", "air", "army"

Service backupType identifiers:

"ambulance", "police", "taxi", "tow", "roadservice", "coroner", "animalrescue", "mechanic", "fire"

Service backup casing: You can pass any casing (e.g. "Tow" or "TOW"). night_ers normalizes backupType internally for both request and cancel. Pursuit unitType still must match config exactly unless you customize PursuitType strings.

Toggle cancel (pursuit): Calling RequestNPCPursuitBackup again with the same unitType while a pursuit backup is already pending cancels that request (returns dispatched, reason). Use CancelNPCPursuitBackup when you want to cancel without knowing the pending type.

-- Pursuit NPC backup — only during pursuit mode; returns dispatched, reason
local dispatched, reason = exports['night_ers']:RequestNPCPursuitBackup('light')

-- Toggle-cancel: call again with same unitType while pending
-- local dispatched2, reason2 = exports['night_ers']:RequestNPCPursuitBackup('light')

-- Explicit pursuit cancel (optional server purge delay in ms)
exports['night_ers']:CancelNPCPursuitBackup()
-- exports['night_ers']:CancelNPCPursuitBackup(5000)

-- Service NPC backup — returns dispatched, reason (second value set when not dispatched, e.g. "unknown_backup_type")
local dispatched, reason = exports['night_ers']:RequestNPCBackup('tow')

exports['night_ers']:CancelNPCBackup('tow', true)

Server Exports (night_ers/server/exports_server.lua)

-- Shift management
exports['night_ers']:toggleShift(source, shiftType) -- "police", "ambulance", "fire", "tow"
exports['night_ers']:trackPlayerCallout(source, targetSource)
exports['night_ers']:setPlayerCalloutOffersEnabled(source, enabled)

-- Advanced programming exports:
exports['night_ers']:getCallouts() -- Returns a json ready table of all callouts in the callouts/plugins/*.lua folder. (Without functions!)
exports['night_ers']:createCallout(callout) -- Only use if you know what you are doing, this allows you to adjust some variables to when spawning callouts via an external program.

-- Custom callouts / pack server Lua — see **Spawning Smart Fires (server)** for the safe exports.

-- Scripted callout *offer* (recommended for integrations — returns whether the prompt was shown):
local ok, reason = exports['night_ers']:SendCalloutOfferToPlayer(source, optionalCalloutId, optionalTimeoutMs)

createCallout vs SendCalloutOfferToPlayer (server scripts)

createCallout makes a new callout preset in memory by copying an existing definition. It merges things like CalloutLocations, PedWeaponData, and AI / loot rolls. You only get { calloutId = "<new-key>" }. It never checks the player — not shift, job, distance, “already busy”, or whether callouts are on. Nobody gets a popup; you spawn or drive the scenario from your own script.

Use SendCalloutOfferToPlayer when you want the same thing as /requestcallout: eligibility runs on server + client (shift, cooldown, blocks, passenger, valid spots, …) and the player sees the normal accept / decline dispatch prompt.

Argument Meaning
source Player’s server id.
optionalCalloutId Leave off or use nil / "" for a random callout (same idea as typing /requestcallout with no id). Or pass a callout id string (same loose matching as /requestcallout).
optionalTimeoutMs How many milliseconds to wait for that player’s client to answer. Default is 5000 if you skip this argument.

Waiting on the player

This export talks to their client. Your server script pauses until the client answers or the wait time runs out.

  1. Omit the third argument → wait 5000 ms (5 seconds) at most.
  2. Pass a positive number → wait that many milliseconds (e.g. 15000 = 15 seconds).
  3. If time runs out with no reply → you get ok = false and reason = "client_response_timeout" (crash, disconnect, extreme lag).

Returns

  • oktrue if the offer went through.
  • reason — only when ok is false; log it to see what blocked the offer.

Spawn spots (matches /requestcallout)

  • Random offer (nil / "") → spawn must be within range of the player (see OfferCalloutsWithinRangeOf in config).
  • You pass a specific id → any spawn listed for that callout can be used (range filter off).

When ok is false — common reason values

Server: invalid_player, player_not_on_shift, no_active_service, player_busy_on_callout, no_callouts_enabled_on_server, callout_service_mismatch, callout_not_found:..., no_eligible_callouts_for_service, offer_unavailable, client_response_timeout

Client / player-side: callouts_disabled_by_player, callouts_temporarily_blocked, callout_request_cooldown, not_on_shift, passenger_not_allowed, already_offered_or_attached, no_valid_locations

Example:

local ok, err = exports['night_ers']:SendCalloutOfferToPlayer(src)
if not ok then
    print(('Could not offer callout: %s'):format(err or '?'))
else
    -- Player has the accepting / declining timed prompt exactly like `/requestcallout`.
end

local ok2, err2 = exports['night_ers']:SendCalloutOfferToPlayer(src, 'callout_vehicle_theft', 6000)

Spawning Smart Fires (server)

This is mainly for custom callouts: if you write your own Lua (in night_ers callout plugins, a separate callout pack resource, or any other server script that participates in building a callout) and you need to start a Smart Fires fire or smoke.

If you use Smart Fires or Smart Fires Lite with ERS, stock callouts already handle setup and cleanup—you do not need these exports unless your script creates the flame or smoke.

From that server Lua, call night_ers rather than Smart Fires directly. Fires you create this way behave like stock ERS callouts on your server—the same cleanup when the incident ends and the same integration with whichever Smart Fires product you run with ERS.

GetFireConfig(): In custom callouts, call exports['night_ers']:GetFireConfig() on the server when you need size/type values. It exposes the same tables core fire callouts draw from so your random sizes and fire types stay consistent. The example below uses the returned booleans only to distinguish full Smart Fires from Lite sizing (you can paste that pattern verbatim).

Export What you pass in What you get back
ERS_CreateSmartFireAtCoords World position, size (radius number), fire type (string) Fire / incident id to store on your callout, or nothing if Smart Fires is turned off in ERS or the fire resource is not running.
ERS_CreateSmartSmokeAtCoords World position, size, smoke type (string) Smoke id (or equivalent), or nothing if unavailable.
ERS_StopSmartFire Id you received when creating the fire Removes that fire the same way ERS would when cleaning up.
ERS_StopSmartSmoke Id you received when creating the smoke Removes that smoke the same way ERS would.
-- Example pattern for custom callouts (your coordinates and lists).
local fireCfg = exports['night_ers']:GetFireConfig()
if fireCfg.UsingSmartFiresV2 or fireCfg.UsingSmartFires then
    local fireSize = fireCfg.RandomMediumFireOrSmokeSize[math.random(#fireCfg.RandomMediumFireOrSmokeSize)]
    local fireType = fireCfg.NormalFireTypes[math.random(#fireCfg.NormalFireTypes)]
    local fireId = exports['night_ers']:ERS_CreateSmartFireAtCoords(vector3(x, y, z), fireSize, fireType)
    if fireId ~= nil then table.insert(fireList, fireId) end
else
    local fireSize = fireCfg.RandomSmallFireOrSmokeSize[math.random(#fireCfg.RandomSmallFireOrSmokeSize)]
    local fireId = exports['night_ers']:ERS_CreateSmartFireAtCoords(vector3(x, y, z), fireSize, "normal")
    if fireId ~= nil then table.insert(fireList, fireId) end
end

Auto cleanup: The example table.insert(fireList, fireId) is how you register “this incident owns that fire”. When your callout is torn down normally, ERS walks fireList / smokeList and stops anything still listed.

Manual stop: Use ERS_StopSmartFire / ERS_StopSmartSmoke only when you extinguish or remove smoke in the middle of the callout (your script clears it early). Otherwise you don’t need those calls—the end-of-callout cleanup handles it if the id stays in fireList / smokeList.


🎨 Props by NovelaxNeko

10 Free Included Props

Name Prop Model
Cone neko_night_cone_00
Barrier neko_night_water_barrier_00
Warning triangle neko_night_warning_tri_00
Rubber barrier neko_night_rubber_barrier_00
Barrier neko_night_barrier_00
Barrier 1 neko_night_barrier_01
Barrier 2 neko_night_barrier_02
Arrow board cross neko_night_arrow_board_00
Arrow board left neko_night_arrow_board_00_l
Arrow board right neko_night_arrow_board_00_r

Artist Credit: Check out NovelaxNeko!


🔧 Troubleshooting

Common Issues

Fire & Smoke Problems

Resource Naming: SmartFires and SmartHose must be named exactly SmartFires and SmartHose (case sensitive). Same applies to Lite versions. A common issue is that callouts can no longer be cancelled or will no longer spawn after encountering issues due to faulty naming of the resources.

MDT Integration Issues

Solution: Enable ERS in night_shifts_mdt config and enable Night Shifts in night_ers config. Duty can (optionally) toggled through the MDT

Hosting-Specific Issues

  • Iceline Hosting: Set Enable Beyond to 1 in server dashboard
  • Entity Spawning: Ensure OneSync is properly configured in the host dashboard

Compatibility Checklist

  • Recommended Gamebuild: 3323
  • Recommended Artifacts: 21703(+)
  • QBox important note; NPC Backup doesn’t spawn: Remove blocked ped & vehicle model names, like s_m_y_cop_01 or FIRETRUK from qbx_smallresources/qbx_entitiesblacklist/config.lua and your backup peds will spawn again.
  • Considered Not Compatible: Other Gamebuilds below 2944 and above 3323 and Artifacts.
  • RemoveCops-AI: We recommend to disable this resource when using ERS.
  • Andrew’s Advanced AI: We recommend to disable this resource when using ERS.
  • Realistic Euphoria Physics: We recommend to disable this resource when using ERS.
  • RedSaints Stretcher/Ambulance: We recommend to disable this resource when using ERS.
  • Improved-Seat-Shuffle-FiveM by Dalrae1: We recommend to disable this resource when using ERS.
  • ⚠️ Anti-cheat: May cause entity deletion issues. This can be prevented via your anti-cheat settings. Contact your provider.

💬 Support & Community

Getting Help

  1. Read Documentation: Review this guide thoroughly
  2. Check Console: Use F8 and txAdmin (sserver) console for error messages
  3. Discord Support: Create a ticket in our Discord

Feedback & Reviews

We welcome your feedback! Visit our Discord for:

  • Support
  • Product reviews
  • Feature suggestions
  • Documentation improvements

Nights Software Discord



Back to top

Copyright © 2025 Nights Software

Page last modified: May 4, 2026 at 12:00 AM.

This site uses Just the Docs, a documentation theme for Jekyll.