[PAID] srz_npc_witness — Advanced NPC Witness & AI Dispatch System
You shot a guy. You thought nobody saw. But that grandma across the street? She’s already on the phone describing your car to the police. And she got the color wrong because she’s drunk.
NPCs actually notice your crimes, freak out, pull out a phone, and call the cops. Each caller has their own personality — some panic, some lie, some are just vibing. Reports stack when multiple witnesses call about the same thing.
Showcase
Purchase
Price: €24.99
Buy on Tebex
Documentation
Join the Discord for support, updates, and feature requests.
Features
Core System
- Heat-based detection — Criminal actions accumulate “heat”. When heat exceeds a threshold, nearby NPCs initiate a 911 call with a phone animation. Continued crime escalates into multiple simultaneous calls (up to 12 concurrent)
- 17 crime types — Shooting, carjacking, fistfights, hit & run, explosions, aiming, car alarm, visible weapon, dead body, weapon threat, and more. Each individually toggleable
- Immediate report events — Critical crimes (murder, explosion, dead body) bypass the heat system entirely and trigger instant NPC calls
- NPC phone animation — Witnesses pull out a phone prop and play a call animation. The report is only sent when the call finishes
- NPC reaction phase — Before calling, NPCs stop, turn toward the crime scene, and play a reaction animation (shock, disgust, facepalm). Gives players a visual cue and a short window to intervene
- Intimidation system — Aim a weapon at a calling NPC to interrupt the call. They panic and flee. Kill them to cancel it permanently
- Coward NPCs — Configurable per-event chance that an NPC flees instead of calling
- Background calls — If an NPC goes out of range or despawns mid-call, the call continues in the background and cannot be stopped. Should’ve been faster
Witness Detection
- Scanner-based detection — Dedicated client-side scanners for reliable detection, independent of GTA’s unreliable native events
- Multi-method vehicle hit detection — 4 parallel methods ensure hits are always detected
- Line of sight + hearing — NPCs with direct LOS contribute to heat. NPCs within 40m without LOS can hear events
- Vehicle witnesses — NPCs in passing vehicles can witness crimes
- Aiming detection — NPCs that see you free-aiming a weapon in public contribute to heat — no need to aim directly at them
- Carjacking victims — The driver being pulled from a vehicle becomes a guaranteed witness with an immediate call
- Player-only attribution — Only events where the player is directly involved are processed. NPC-vs-NPC crimes don’t falsely implicate the player
- No-suspect calls — Distant events (random explosion, far car alarm) generate calls without suspect descriptions
Caller AI — 5 Personalities, 160+ Templates
- 5 caller profiles —
Calm,Panic,Angry,Elderly,Drunk— each with unique speech patterns, accuracy levels, and behavioral traits - ~160 unique call templates — Per profile + event type, with 4-5 variants each. No two reports sound the same
- Realistic confusion — Callers make mistakes based on their personality. The drunk caller will describe your red car as blue. An elderly caller confuses your pistol for a rifle. Not a bug — it’s a feature
- Guaranteed useful data — Every caller provides at least 1 correct detail
- Snapshot at crime time — Suspect appearance is captured instantly, not when the call finishes
Corroboration & Consensus
- Report merging — Multiple calls for the same crime merge into a single report
- Weighted consensus — Each caller’s vote is weighted by accuracy × distance × environment. Plate holders get bonus weight
- VERIFIED / DISPUTED / UNCONFIRMED tags — Indicates consensus quality with confidence bars
- Stacked transcripts — All call transcripts display in a single scrollable section
Environment & Disguise
- Night vision reduction — NPCs see 50% as far at night (configurable hours)
- Weather impact — Rain (65%), fog/smog (40%) reduce NPC vision range
- Mask/disguise system — Masks reduce heat accumulation (65%) and fuzz the reported location by up to 100m. Crime responsibly
Built-in Dispatch UI
- Full dispatch panel — Central map + sidebar layout with scrollable call list, severity badges, timestamps, caller profile, reliability score
- Real-time interactive map — Leaflet map with GTA satellite image. Each report gets a unique color with markers for every witness position, connected with dashed lines
- Unified transcripts — Primary + corroborating call transcripts merged in one section
- Mini-HUD — Always-visible widget showing the latest report
- Filter system — By severity (CODE 1/2/3) or crime type. Applies to sidebar and map
- GPS integration — One-click waypoint from any report
- Audio alerts — Distinct tones for CODE 2 and CODE 3. Optional auto-open on CODE 3
- Report expiry — Configurable auto-cleanup (default 180s)
- Reduced UI mode — Item-based access shows a limited view without debug data
Access Control
| Mode | Description |
|---|---|
all |
Everyone can access the full dispatch |
job |
Restrict to specific jobs (police, ambulance, sheriff, etc.) |
ace |
ACE permission: srz_witness.dispatch |
export |
External scripts control access via exports |
| Item-based | Players with a specific item (e.g. radio) get reduced access |
Full Export API
Plug it into whatever dispatch you already use, or use ours.
Server Exports
-- Query reports
exports.srz_npc_witness:GetRecentReports(10)
exports.srz_npc_witness:GetReportsByType('shooting', 20)
exports.srz_npc_witness:GetReportsBySeverity(3, 10)
exports.srz_npc_witness:GetReportById(42)
exports.srz_npc_witness:GetReportsByPlayer(serverId, 10)
exports.srz_npc_witness:GetReportsSince(600)
exports.srz_npc_witness:GetReportsByZone('Vinewood', 10)
exports.srz_npc_witness:GetReportsByStreet('Innocence Blvd', 10)
exports.srz_npc_witness:GetReportsInRadius(x, y, z, 200.0, 20)
-- Statistics
exports.srz_npc_witness:GetStats()
exports.srz_npc_witness:GetReportCount()
-- Inject custom reports from other scripts
exports.srz_npc_witness:PushReport({ ... })
-- Admin
exports.srz_npc_witness:ClearReports()
exports.srz_npc_witness:IsEventEnabled('shooting')
exports.srz_npc_witness:GetEnabledEvents()
Client Exports
exports.srz_npc_witness:GetCurrentHeat()
exports.srz_npc_witness:SetHeat(150)
exports.srz_npc_witness:ResetHeat()
exports.srz_npc_witness:GetWitnessCount()
exports.srz_npc_witness:GetActiveCallers()
exports.srz_npc_witness:IsPlayerDisguised()
exports.srz_npc_witness:OpenDispatchUI()
exports.srz_npc_witness:CloseDispatchUI()
exports.srz_npc_witness:ToggleDispatchUI()
exports.srz_npc_witness:IsDispatchOpen()
exports.srz_npc_witness:CanAccessDispatch()
exports.srz_npc_witness:SendWitnessReport('shooting', vector3(100, 200, 30))
Server Events
AddEventHandler('srz_npc_witness:onReport', function(report) end)
AddEventHandler('srz_npc_witness:onReport:shooting', function(report) end)
AddEventHandler('srz_npc_witness:onSeverity:3', function(report) end)
AddEventHandler('srz_npc_witness:onCorroborate', function(updatedReport) end)
Client Events
RegisterNetEvent('srz_npc_witness:dispatch', function(report) end)
RegisterNetEvent('srz_npc_witness:personalAlert', function(report) end)
RegisterNetEvent('srz_npc_witness:corroborate', function(updatedReport) end)
Integration Examples
MDT Integration
AddEventHandler('srz_npc_witness:onReport', function(report)
exports.your_mdt:AddDispatchCall({
id = report.id,
title = report.label,
message = report.callerData and report.callerData.callText or '',
coords = report.coords,
severity = report.callerData and report.callerData.severity or 1,
})
end)
Discord Webhook (CODE 3 only)
AddEventHandler('srz_npc_witness:onSeverity:3', function(report)
PerformHttpRequest('https://discord.com/api/webhooks/...', function() end, 'POST',
json.encode({
embeds = {{
title = 'CODE 3 — ' .. (report.label or '?'),
description = report.callerData and report.callerData.callText or '',
color = 16711680,
}},
}),
{ ['Content-Type'] = 'application/json' })
end)
Disable Built-in UI (External Dispatch Only)
Config.UI.enabled = false
-- Reports still flow through events and exports
Configuration
80+ configurable options in config.lua. If you can think of it, you can probably toggle it.
| Section | What it controls |
|---|---|
| Heat System | Threshold, decay, per-crime values, witness multipliers |
| NPC Behavior | Call duration, max simultaneous calls, flee chance, intimidation range, reaction phase |
| Per-Event Overrides | Custom call duration + flee chance per crime type |
| Environment | Night hours, weather vision multipliers |
| Disguise | Heat reduction, position fuzzing distance |
| Corroboration | Merge window, reliability boost, max witnesses |
| Caller AI | Profile weight overrides, raw data toggle |
| Dispatch UI | Command, keybind, access mode, sounds, report expiry, auto-open |
| Events | Toggle each of 17 crime types on/off |
| Zone Blacklist | Disable witness system in specific zones |
| Locale | EN/IT included, add your own |
Installation
- Copy
srz_npc_witnessinto your resources folder - Add
ensure srz_npc_witnessto yourserver.cfg - Configure
config.lua - Set
EnableClientDebug = falseandshowDebugInfo = falsefor production
Framework Support
Works standalone out of the box. QBX/QBCore/ESX auto-detected if you want job-restricted dispatch access.
| Dependency | Required | Notes |
|---|---|---|
| QBX Core / QBCore / ESX | Optional | Only needed if accessMode = 'job' |
| ox_inventory | Optional | Only needed if itemAccess.enabled = true |
Languages
English and Italian included. Add your own by copying locales/en.lua.
| Code is accessible | No (config, framework bridge, locales, full web UI are open) |
| Subscription-based | No |
| Lines (approximately) | ~6,400 |
| Requirements | None (standalone). Optional: QBX/QBCore/ESX, ox_inventory |
| Support | Yes |
This post was written with the help of AI.
