Add openable doors to generated rooms

This commit is contained in:
Peter Stockings
2026-01-05 21:48:19 +11:00
parent a01d4abdf7
commit b35cf5a964
2 changed files with 54 additions and 2 deletions

View File

@@ -6,7 +6,9 @@ export const TileType = {
EMPTY_DECO: 24, EMPTY_DECO: 24,
WALL_DECO: 12, WALL_DECO: 12,
EXIT: 8, EXIT: 8,
WATER: 63 // Unused but kept for safety/legacy WATER: 63, // Unused but kept for safety/legacy
DOOR_CLOSED: 5,
DOOR_OPEN: 6
} as const; } as const;
export type TileType = typeof TileType[keyof typeof TileType]; export type TileType = typeof TileType[keyof typeof TileType];
@@ -28,7 +30,9 @@ export const TILE_DEFINITIONS: Record<number, TileBehavior> = {
[TileType.EMPTY_DECO]: { id: TileType.EMPTY_DECO, isBlocking: false, isDestructible: false }, [TileType.EMPTY_DECO]: { id: TileType.EMPTY_DECO, isBlocking: false, isDestructible: false },
[TileType.WALL_DECO]: { id: TileType.WALL_DECO, isBlocking: true, isDestructible: false }, [TileType.WALL_DECO]: { id: TileType.WALL_DECO, isBlocking: true, isDestructible: false },
[TileType.EXIT]: { id: TileType.EXIT, isBlocking: false, isDestructible: false }, [TileType.EXIT]: { id: TileType.EXIT, isBlocking: false, isDestructible: false },
[TileType.WATER]: { id: TileType.WATER, isBlocking: true, isDestructible: false } [TileType.WATER]: { id: TileType.WATER, isBlocking: true, isDestructible: false },
[TileType.DOOR_CLOSED]: { id: TileType.DOOR_CLOSED, isBlocking: false, isDestructible: true, isDestructibleByWalk: true, blocksVision: true, destructsTo: TileType.DOOR_OPEN },
[TileType.DOOR_OPEN]: { id: TileType.DOOR_OPEN, isBlocking: false, isDestructible: false }
}; };
export function isBlocking(tile: number): boolean { export function isBlocking(tile: number): boolean {

View File

@@ -57,8 +57,19 @@ export function generateWorld(floor: number, runState: RunState): { world: World
}; };
placeEnemies(floor, rooms, actors, random); placeEnemies(floor, rooms, actors, random);
// Place doors for dungeon levels (Uniform/Digger)
// Caves (Floors 10+) shouldn't have manufactured doors
if (floor <= 9) {
placeDoors(width, height, tiles, rooms, random);
}
decorate(width, height, tiles, random, exit); decorate(width, height, tiles, random, exit);
// CRITICAL FIX: Ensure player start position is always clear!
// Otherwise spawning in Grass (which blocks vision) makes the player blind.
tiles[playerY * width + playerX] = TileType.EMPTY;
return { return {
world: { width, height, tiles, actors, exit }, world: { width, height, tiles, actors, exit },
playerId playerId
@@ -347,3 +358,40 @@ function placeEnemies(floor: number, rooms: Room[], actors: Map<EntityId, Actor>
export const makeTestWorld = generateWorld; export const makeTestWorld = generateWorld;
function placeDoors(width: number, height: number, tiles: Tile[], rooms: Room[], random: () => number): void {
const checkAndPlaceDoor = (x: number, y: number) => {
const i = idx({ width, height } as any, x, y);
if (tiles[i] === TileType.EMPTY) {
// Found a connection (floor tile on perimeter)
// 50% chance to place a door
if (random() < 0.5) {
// 90% chance for closed door, 10% for open
tiles[i] = random() < 0.9 ? TileType.DOOR_CLOSED : TileType.DOOR_OPEN;
}
}
};
for (const room of rooms) {
// Scan top and bottom walls
const topY = room.y - 1;
const bottomY = room.y + room.height;
// Scan horizontal perimeters (iterate x from left-1 to right+1 to cover corners too if needed,
// but usually doors are in the middle segments. Let's cover the full range adjacent to room.)
for (let x = room.x; x < room.x + room.width; x++) {
if (topY >= 0) checkAndPlaceDoor(x, topY);
if (bottomY < height) checkAndPlaceDoor(x, bottomY);
}
// Scan left and right walls
const leftX = room.x - 1;
const rightX = room.x + room.width;
for (let y = room.y; y < room.y + room.height; y++) {
if (leftX >= 0) checkAndPlaceDoor(leftX, y);
if (rightX < width) checkAndPlaceDoor(rightX, y);
}
}
}