Skip to main content

Danger Zones

Danger zones are rectangular ring areas surrounding each chunk's baseplate. They serve as the spawnable region for enemies and trigger insanity effects for players.

Ring Creation

For each baseplate, 4 rectangular parts are created by subtracting the inner rect (baseplate) from the outer rect (baseplate + 300 stud padding):

┌──────────────────────┐
│ Danger Zone │
│ ┌──────────────┐ │
│ │ Baseplate │ │
│ │ (inner) │ │
│ └──────────────┘ │
│ │
└──────────────────────┘
(outer)

subtractRect(outer, inner) from quadtree.ts returns up to 4 non-overlapping rectangles.

Spatial Indexing

  • Octree stores all danger zone parts for fast radius queries
  • Region3 computed per zone for world.store atom integration
  • Baseplate mapping tracks which zones belong to which chunk (for cleanup on unload)

Player Detection

Server-Side

ChunkService checks player positions against danger zones every 0.25s:

  1. Query octree for nearby danger zones
  2. Check if player position is within zone's Region3
  3. Update dangerZonePlayers atom
  4. Apply insanity increment on client

Client-Side

The dangerZonePlayers atom syncs to clients, driving:

  • Insanity increase rate
  • Vignette intensity
  • Audio distortion (future)

Distributed Creation

For performance, danger zone creation is deferred:

Chunk created
→ task.defer() → createDangerZoneDistributed()
→ Create ring parts (4 rectangles)
→ Register in octree
→ Define Region3 per zone
→ Map zones to baseplate

Cleanup

When a chunk unloads:

  1. Remove all danger zone parts for that baseplate
  2. Clean up octree nodes
  3. Remove from baseplate mapping
  4. Remove Region3 entries

Key Files

FilePurpose
danger-zone-manager.tsRing creation, octree, Region3, cleanup
quadtree.tssubtractRect() for ring computation
chunk-service.tsPlayer detection in heartbeat