Skip to content

Crime System

Three services work together to track crime, coordinate NPC responses, and clear the player's wanted level.

Services at a Glance

Service Responsibility
PlayerService Owns the CrimeRecord per player and the advisories cops share
CentralService NPC-to-NPC coordination (unit caps, patrol slots, advisories)
DispatchService Spawning units, search timers, vision checks, car assignment

Crime Record

Every player has a CrimeRecord table in their runtime session (managed by PlayerService). Key fields:

Field Meaning
Score Cumulative crime score, drives the star level
Identified True once a cop has made a positive ID on the suspect
LastPosition Last confirmed world position when unidentified, used by NPCs to route to
RecognitionProgress 0–1 fill; when it reaches 1 the player is identified
ClientSearchTick Timestamp when a search order was issued; NPCs use it to switch into Search state

PlayerService:AddCrime(player, score, label) increments the score and attaches a label for the HUD. PlayerService:ClearCrimeRecord resets everything (called on respawn to suppress signals, and by the cashout/jail flow to actually clear it).


Wanted Flow

Player commits a crime
  └── PlayerService:AddCrime(player, score, label)
        └── CrimeRecord.Score += score
              └── client Score property updated → star display

Cop spots player
  └── PoliceNPCService:CanSeeTarget (line-of-sight check)
        └── PlayerService:Identify(player, true, position)
              └── CrimeRecord.Identified = true
                    └── client Identified property updated

Cop spots player carrying weapon
  └── CentralService:Advise(player, "HAS_GUN")
        └── adds "HAS_GUN" to CrimeRecord.CopAdvise

Wanted level clears
  └── player arrested  OR  cashout  OR  score decays to 0
        └── PlayerService:ClearCrimeRecord
              └── CrimeScoreClearedSignal fires

Dispatch Loop

DispatchService.dispatchNewNPCs runs every few seconds. It:

  1. Skips if the world already has more than 7 police vehicles or 10 foot NPCs
  2. For each player with Score > 0, checks how many units are already assigned
  3. If below the star-level minimum (Star.minGroundUnits), picks a spawn point:
  4. Moving suspect — tries to spawn ahead (70% of the time) or behind (30%) along the path, outside the player's vision cone
  5. Stationary / fallback — random node at least 350–500 studs away, also outside vision
  6. Spawns a police car (Ford Crown Victoria Police or Dodge Charger Police) plus two NPCs, assigns them driver + passenger seats, and attaches them to the player via CentralService.Attach
  7. At high crime scores (>400) the NPCs receive a police vest and 150/135 HP

A minimum of 2 patrol vehicles always exist in the world regardless of active crimes.


Search System

DispatchService.searchLoop tracks whether any cop currently has line-of-sight to the wanted player. If the player breaks line-of-sight and stays hidden:

  • After SEARCH_START_DELAY seconds (5 s), ClientSearchTick is set on the crime record
  • If the player was near their last-seen position, the delay extends to SEARCH_START_DELAY_NEAR_LAST_SEEN (20 s)
  • First sighting gets an extra grace period of SEARCH_FIRST_SIGHTING_GRACE (30 s)

When ClientSearchTick > 0, NPCs switch to the G_Search group. If the player stays hidden long enough for the search timer to expire, the wanted level clears.


CentralService — NPC Coordination

CentralService is the message bus between cops. It does not talk to the client.

Unit Caps

CentralService.RequestTarget(Entity, Target) returns true only if the number of already-assigned units is below Star.maxGroundUnits. NPCs check this before targeting a player.

Advisories

Advise(suspect, message) appends a message string to the player's CopAdvise set. IsAdvised(suspect, message) checks it. Current messages:

Advisory Meaning
HAS_GUN Player is or was seen with an equipped weapon
SEEN_WITH_GUN Player was spotted carrying a duffel bag (legacy name — not an actual gun sighting)

Patrol Slots

Only 2 cars can be in patrol mode at the same time (to avoid every idle car driving around). CanPatrol and RemovePatrolIfApplicable manage the PatrolUnits list.


Car Assignment

When a police NPC enters a patrol car, DispatchService:AssignCopCar transfers the car's network ownership to the pursuing player's client and adds a ReplicationFocus so the car stays in that client's replication bubble. UnassignCopCar reverses this. The client's PoliceCarController then runs the driving AI each frame.