shellquest
Version:
Terminal-based procedurally generated dungeon crawler
123 lines (114 loc) • 4.58 kB
text/typescript
import type {PRNG} from 'seedrandom';
import type {LevelTile} from '../types.ts';
import {getTileName} from '../types.ts';
export class HouseGenerator {
constructor(
private tiles: LevelTile[][],
private width: number,
private height: number,
) {}
generateHouse(
x: number,
y: number,
width: number,
height: number,
houseType: 'house-1' | 'house-2',
rng: PRNG,
): void {
if (x + width > this.width || y + height > this.height) return;
for (let dy = 0; dy < height; dy++) {
for (let dx = 0; dx < width; dx++) {
const tile = this.tiles[y + dy][x + dx];
tile.bottomTile = 'dirt-1';
tile.solid = false;
tile.topTile = undefined;
}
}
for (let dx = 0; dx < width; dx++) {
if (dx === 0) {
this.tiles[y][x + dx].topTile = `${houseType}-roof-top-top-left`;
} else if (dx === width - 1) {
this.tiles[y][x + dx].topTile = `${houseType}-roof-top-top-right`;
} else {
if (rng() < 0.3 && dx > 0 && dx < width - 1) {
this.tiles[y][x + dx].topTile = `${houseType}-roof-top-chimney`;
} else {
this.tiles[y][x + dx].topTile = `${houseType}-roof-top-middle`;
}
}
this.tiles[y][x + dx].solid = true;
if (y + 1 < this.height) {
if (dx === 0) {
this.tiles[y + 1][x + dx].topTile = `${houseType}-roof-bottom-left`;
} else if (dx === width - 1) {
this.tiles[y + 1][x + dx].topTile = `${houseType}-roof-bottom-right`;
} else {
if (rng() < 0.2 && dx > 0 && dx < width - 1) {
this.tiles[y + 1][x + dx].topTile = `${houseType}-roof-bottom-arch`;
} else {
this.tiles[y + 1][x + dx].topTile = `${houseType}-roof-bottom-middle`;
}
}
this.tiles[y + 1][x + dx].solid = true;
}
}
for (let dy = 2; dy < height; dy++) {
if (y + dy >= this.height) break;
for (let dx = 0; dx < width; dx++) {
if (dx === 0) {
if (rng() < 0.3 && dy > 2 && dy < height - 1) {
this.tiles[y + dy][x + dx].topTile = `${houseType}-wall-left`;
} else {
this.tiles[y + dy][x + dx].topTile = `${houseType}-wall-left`;
}
} else if (dx === width - 1) {
if (rng() < 0.3 && dy > 2 && dy < height - 1) {
this.tiles[y + dy][x + dx].topTile = `${houseType}-wall-right`;
} else {
this.tiles[y + dy][x + dx].topTile = `${houseType}-wall-right`;
}
} else {
if (dy === height - 1) {
if (width === 3 && dx === 1) {
this.tiles[y + dy][x + dx].topTile = `${houseType}-wall-door-single`;
this.tiles[y + dy][x + dx].solid = false;
} else if (width >= 4 && dx === Math.floor(width / 2) - 1) {
this.tiles[y + dy][x + dx].topTile = `${houseType}-wall-door-double-left`;
this.tiles[y + dy][x + dx].solid = false;
} else if (width >= 4 && dx === Math.floor(width / 2)) {
this.tiles[y + dy][x + dx].topTile = `${houseType}-wall-door-double-right`;
this.tiles[y + dy][x + dx].solid = false;
} else {
this.tiles[y + dy][x + dx].topTile = `${houseType}-wall-middle`;
}
} else if (dy === height - 2 && rng() < 0.5) {
if (
(width === 3 && dx === 1) ||
(width >= 4 && (dx === Math.floor(width / 2) - 1 || dx === Math.floor(width / 2)))
) {
this.tiles[y + dy][x + dx].topTile = `${houseType}-wall-door-hole`;
} else {
if (rng() < 0.3) {
this.tiles[y + dy][x + dx].topTile = `${houseType}-wall-window`;
} else {
this.tiles[y + dy][x + dx].topTile = `${houseType}-wall-middle`;
}
}
} else {
if (rng() < 0.2 && dy > 2) {
this.tiles[y + dy][x + dx].topTile = `${houseType}-wall-window`;
} else {
this.tiles[y + dy][x + dx].topTile = `${houseType}-wall-middle`;
}
}
}
const topTileName = this.tiles[y + dy][x + dx].topTile
? getTileName(this.tiles[y + dy][x + dx].topTile!)
: null;
if (!topTileName?.includes('door')) {
this.tiles[y + dy][x + dx].solid = true;
}
}
}
}
}