feat(simulation): add Zone Gate gauntlet room and zone crossing detection (#512)
New test_world room with two zones (Terminal/Corridor) separated by a door. Adds ZoneCrossEventQueue resource and detect_zone_crossings system to fire events when the player crosses zone boundaries. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -255,6 +255,49 @@ pub const SHIFT_CHANGE: GauntletRoom = GauntletRoom {
|
||||
reset_plate: Some(TilePosition { x: 72, y: 78, z: 0 }),
|
||||
};
|
||||
|
||||
/// Zone Gate — Room 15 (16x22)
|
||||
/// Tests D-077 zone assignment and zone-crossing detection (#512).
|
||||
///
|
||||
/// Room is split at x=72 (absolute) into two zones:
|
||||
/// Terminal side (x=64-71): ZONE_GATE_TERMINAL_ZONE_ID (zone_id=100)
|
||||
/// Corridor side (x=72-79): ZONE_GATE_CORRIDOR_ZONE_ID (zone_id=101)
|
||||
///
|
||||
/// A door entity sits on the boundary at (72, 112, 0). Moving from the
|
||||
/// Terminal side to the Corridor side (or vice versa) fires ZoneCrossEvent.
|
||||
///
|
||||
/// Observer starts on the Terminal side at (70, 112, 0), facing East.
|
||||
pub const ZONE_GATE: GauntletRoom = GauntletRoom {
|
||||
name: "zone_gate",
|
||||
origin: TilePosition {
|
||||
x: 64,
|
||||
y: 102,
|
||||
z: 0,
|
||||
},
|
||||
size: (16, 22),
|
||||
spawn: TilePosition {
|
||||
x: 70,
|
||||
y: 112,
|
||||
z: 0,
|
||||
},
|
||||
observer: TilePosition {
|
||||
x: 70,
|
||||
y: 112,
|
||||
z: 0,
|
||||
},
|
||||
observer_facing: Facing(FacingDirection::East),
|
||||
reset_plate: Some(TilePosition {
|
||||
x: 72,
|
||||
y: 102,
|
||||
z: 0,
|
||||
}),
|
||||
};
|
||||
|
||||
/// Zone ID for the Terminal (left/west) half of the Zone Gate room.
|
||||
pub const ZONE_GATE_TERMINAL_ZONE_ID: u16 = 100;
|
||||
|
||||
/// Zone ID for the Corridor (right/east) half of the Zone Gate room.
|
||||
pub const ZONE_GATE_CORRIDOR_ZONE_ID: u16 = 101;
|
||||
|
||||
/// All rooms in canonical spawn order.
|
||||
/// THIS ORDER DETERMINES STABLEID ASSIGNMENT.
|
||||
/// Do not reorder existing entries. Append new rooms at the end.
|
||||
@@ -273,6 +316,7 @@ pub const ROOMS: &[GauntletRoom] = &[
|
||||
SOUND_LAB,
|
||||
DECAY_OBSERVATORY,
|
||||
SHIFT_CHANGE,
|
||||
ZONE_GATE,
|
||||
];
|
||||
|
||||
/// Look up which room a position falls in.
|
||||
@@ -323,6 +367,11 @@ pub const DECAY_OBSERVATORY_STABLE_IDS: (u64, u64) = (69, 69);
|
||||
pub const SHIFT_CHANGE_STABLE_IDS: (u64, u64) = (70, 71);
|
||||
/// Reset plates for Sprint 13 rooms (sound_lab, decay_observatory, shift_change).
|
||||
pub const SPRINT13_RESET_PLATE_STABLE_IDS: (u64, u64) = (72, 74);
|
||||
// Sprint 22 rooms — appended after SPRINT13_RESET_PLATE_STABLE_IDS per additive-only rule.
|
||||
/// Zone Gate room: door entity at the zone boundary.
|
||||
pub const ZONE_GATE_STABLE_IDS: (u64, u64) = (75, 75);
|
||||
/// Reset plate for Sprint 22 rooms (zone_gate).
|
||||
pub const SPRINT22_RESET_PLATE_STABLE_IDS: (u64, u64) = (76, 76);
|
||||
|
||||
/// Number of actively-spawned entities in the current Gauntlet build.
|
||||
/// Derived from StableId ranges of all rooms + player + reset plates.
|
||||
@@ -343,7 +392,9 @@ pub const EXPECTED_ENTITY_COUNT: usize = 1 // player (StableId 0)
|
||||
+ (SOUND_LAB_STABLE_IDS.1 - SOUND_LAB_STABLE_IDS.0 + 1) as usize
|
||||
+ (DECAY_OBSERVATORY_STABLE_IDS.1 - DECAY_OBSERVATORY_STABLE_IDS.0 + 1) as usize
|
||||
+ (SHIFT_CHANGE_STABLE_IDS.1 - SHIFT_CHANGE_STABLE_IDS.0 + 1) as usize
|
||||
+ (SPRINT13_RESET_PLATE_STABLE_IDS.1 - SPRINT13_RESET_PLATE_STABLE_IDS.0 + 1) as usize;
|
||||
+ (SPRINT13_RESET_PLATE_STABLE_IDS.1 - SPRINT13_RESET_PLATE_STABLE_IDS.0 + 1) as usize
|
||||
+ (ZONE_GATE_STABLE_IDS.1 - ZONE_GATE_STABLE_IDS.0 + 1) as usize
|
||||
+ (SPRINT22_RESET_PLATE_STABLE_IDS.1 - SPRINT22_RESET_PLATE_STABLE_IDS.0 + 1) as usize;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
@@ -452,7 +503,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn all_rooms_in_correct_order() {
|
||||
assert_eq!(ROOMS.len(), 14);
|
||||
assert_eq!(ROOMS.len(), 15);
|
||||
assert_eq!(ROOMS[0].name, "central_hub");
|
||||
assert_eq!(ROOMS[1].name, "fog_theater");
|
||||
assert_eq!(ROOMS[2].name, "occlusion_corridor");
|
||||
@@ -467,6 +518,7 @@ mod tests {
|
||||
assert_eq!(ROOMS[11].name, "sound_lab");
|
||||
assert_eq!(ROOMS[12].name, "decay_observatory");
|
||||
assert_eq!(ROOMS[13].name, "shift_change");
|
||||
assert_eq!(ROOMS[14].name, "zone_gate");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -533,6 +585,8 @@ mod tests {
|
||||
DECAY_OBSERVATORY_STABLE_IDS,
|
||||
SHIFT_CHANGE_STABLE_IDS,
|
||||
SPRINT13_RESET_PLATE_STABLE_IDS,
|
||||
ZONE_GATE_STABLE_IDS,
|
||||
SPRINT22_RESET_PLATE_STABLE_IDS,
|
||||
];
|
||||
for (i, a) in ranges.iter().enumerate() {
|
||||
for (j, b) in ranges.iter().enumerate() {
|
||||
|
||||
Reference in New Issue
Block a user