#491: PlayerAction::TeleportToHub — moves player to hub spawn, clears dialogue/monologue/interaction buffer, Gauntlet-only with log warning. #520: ConfrontationDelivered event — Tier 2 animation shift, relationship state decrement (D-033), monologue spike emission. #519: Walk-away Phase 2 — NPC animation shift + routine deviation on dialogue exit (D-064). #498: Four new Gauntlet rooms — Interaction Gallery, Fog Theater, Crowd Plaza, Dialogue Room with constants and wiring. #514: blocked_entities Vec<u64> on ObserverSnapshot, protocol v9. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
86 lines
2.9 KiB
Rust
86 lines
2.9 KiB
Rust
//! Crowd Plaza — Room 7 (32x32)
|
|
//!
|
|
//! Density stress test room. 15 NPCs in a 5x3 grid to test perception,
|
|
//! snapshot, and tick-budget performance under high entity density.
|
|
//! Validates D-026 tick budget holds with many visible entities.
|
|
//!
|
|
//! Observer position: (16, 16) relative = (96, 94) absolute, facing West.
|
|
//!
|
|
//! Entities (StableId 34-48):
|
|
//! crowd_npc_00..crowd_npc_14 — 15 NPCs in a 5-column x 3-row grid
|
|
//! Grid starts at rel (4, 4) = abs (84, 82), spacing: 5x cols, 8y rows.
|
|
|
|
use bevy_app::prelude::*;
|
|
|
|
use crate::knowledge::registry::{EntityRegistry, StableEntityId};
|
|
use crate::npc::{Contentment, Npc, ToleranceThreshold, Want, WantKind};
|
|
use crate::simulation::interaction::Interactable;
|
|
use crate::simulation::movement::TilePosition;
|
|
use crate::simulation::path_follow::MovementSpeed;
|
|
|
|
/// Room origin (top-left corner including walls).
|
|
const ORIGIN_X: i32 = 80;
|
|
const ORIGIN_Y: i32 = 78;
|
|
|
|
/// Grid layout constants.
|
|
const GRID_COLS: usize = 5;
|
|
const GRID_ROWS: usize = 3;
|
|
const GRID_START_X: i32 = 4;
|
|
const GRID_START_Y: i32 = 4;
|
|
const GRID_SPACING_X: i32 = 5;
|
|
const GRID_SPACING_Y: i32 = 8;
|
|
|
|
/// WantKind cycle for variety across 15 NPCs.
|
|
const WANT_CYCLE: &[WantKind] = &[
|
|
WantKind::Wealth,
|
|
WantKind::Safety,
|
|
WantKind::Knowledge,
|
|
WantKind::Connection,
|
|
WantKind::Power,
|
|
WantKind::Freedom,
|
|
WantKind::Justice,
|
|
WantKind::Revenge,
|
|
WantKind::Happiness,
|
|
];
|
|
|
|
/// Spawn Crowd Plaza entities in canonical order (StableId 34-48).
|
|
pub fn spawn_entities(app: &mut App, registry: &mut EntityRegistry) {
|
|
let mut index = 0usize;
|
|
for row in 0..GRID_ROWS {
|
|
for col in 0..GRID_COLS {
|
|
let rx = GRID_START_X + col as i32 * GRID_SPACING_X;
|
|
let ry = GRID_START_Y + row as i32 * GRID_SPACING_Y;
|
|
let pos = TilePosition::new(ORIGIN_X + rx, ORIGIN_Y + ry, 0);
|
|
let want_kind = WANT_CYCLE[index % WANT_CYCLE.len()];
|
|
|
|
let entity = app
|
|
.world_mut()
|
|
.spawn((
|
|
Npc,
|
|
Interactable,
|
|
pos,
|
|
Want {
|
|
primary: want_kind,
|
|
intensity: ((index % 8) + 2) as u8, // 2-9 range
|
|
description: format!("Crowd Plaza NPC #{:02}", index),
|
|
},
|
|
Contentment {
|
|
level: (index as i16 * 7 - 50).clamp(-100, 100),
|
|
},
|
|
ToleranceThreshold {
|
|
current_stress: (index as i16 * 5) % 80,
|
|
threshold: 40 + (index as i16 % 4) * 10,
|
|
},
|
|
MovementSpeed::default(),
|
|
))
|
|
.id();
|
|
let sid = registry.register(entity);
|
|
app.world_mut()
|
|
.entity_mut(entity)
|
|
.insert(StableEntityId(sid));
|
|
|
|
index += 1;
|
|
}
|
|
}
|
|
}
|