phase 9: biome expansion — 3 biomes, 40 elements, 119 reactions, 9 species
Expand beyond vertical slice with two new biomes and massive chemistry expansion: Chemistry: +20 real elements (Li→U), +39 compounds (acids/salts/oxides/organics), +85 reactions (Haber process, thermite variants, smelting, fermentation, etc.) Biomes: Kinetic Mountains (physics/mechanics themed) and Verdant Forests (biology/ecology themed), each with 8 tile types and unique generation rules. Creatures: 6 new species — Pendulums/Mechanoids/Resonators (mountains), Symbiotes/Mimics/Spore-bearers (forests). Species filtered by biome. Infrastructure: CradleScene biome selector UI, generic world generator (tile lookup by property instead of hardcoded names), actinide element category. 487 tests passing (32 new). Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -4,8 +4,9 @@ import { createSeededNoise, sampleNoise } from '../src/world/noise';
|
||||
import { generateWorld } from '../src/world/generator';
|
||||
import type { BiomeData } from '../src/world/types';
|
||||
|
||||
const allBiomes = biomeDataArray as BiomeData[];
|
||||
// Load the first biome — structural compatibility with BiomeData
|
||||
const biome = biomeDataArray[0] as BiomeData;
|
||||
const biome = allBiomes[0];
|
||||
|
||||
// ─── Noise ──────────────────────────────────────────────────────
|
||||
|
||||
@@ -181,3 +182,139 @@ describe('World Generation', () => {
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// ─── Multi-Biome Support (Phase 9) ──────────────────────────────
|
||||
|
||||
describe('Multi-Biome Data', () => {
|
||||
it('has 3 biomes loaded', () => {
|
||||
expect(allBiomes).toHaveLength(3);
|
||||
});
|
||||
|
||||
it('each biome has a unique id', () => {
|
||||
const ids = allBiomes.map(b => b.id);
|
||||
expect(new Set(ids).size).toBe(3);
|
||||
expect(ids).toContain('catalytic-wastes');
|
||||
expect(ids).toContain('kinetic-mountains');
|
||||
expect(ids).toContain('verdant-forests');
|
||||
});
|
||||
|
||||
it('each biome has 8 tile types with sequential IDs', () => {
|
||||
for (const b of allBiomes) {
|
||||
expect(b.tiles).toHaveLength(8);
|
||||
b.tiles.forEach((tile, index) => {
|
||||
expect(tile.id, `${b.id}: tile ${index}`).toBe(index);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
it('each biome has an interactive tile and a resource tile', () => {
|
||||
for (const b of allBiomes) {
|
||||
const interactive = b.tiles.find(t => t.interactive);
|
||||
const resource = b.tiles.find(t => t.resource);
|
||||
expect(interactive, `${b.id}: no interactive tile`).toBeDefined();
|
||||
expect(resource, `${b.id}: no resource tile`).toBeDefined();
|
||||
}
|
||||
});
|
||||
|
||||
it('each biome has valid elevation rules covering [0, 1]', () => {
|
||||
for (const b of allBiomes) {
|
||||
const rules = b.generation.elevationRules;
|
||||
expect(rules.length).toBeGreaterThan(0);
|
||||
expect(rules[rules.length - 1].below).toBe(1);
|
||||
const validIds = new Set(b.tiles.map(t => t.id));
|
||||
for (const rule of rules) {
|
||||
expect(validIds.has(rule.tileId), `${b.id}: invalid tileId ${rule.tileId}`).toBe(true);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('Kinetic Mountains Generation', () => {
|
||||
const mtns = allBiomes.find(b => b.id === 'kinetic-mountains')!;
|
||||
|
||||
it('generates correct-size grid', () => {
|
||||
const world = generateWorld(mtns, 42);
|
||||
expect(world.grid).toHaveLength(mtns.mapHeight);
|
||||
expect(world.grid[0]).toHaveLength(mtns.mapWidth);
|
||||
});
|
||||
|
||||
it('all tile IDs are valid', () => {
|
||||
const world = generateWorld(mtns, 42);
|
||||
const validIds = new Set(mtns.tiles.map(t => t.id));
|
||||
for (const row of world.grid) {
|
||||
for (const tileId of row) {
|
||||
expect(validIds.has(tileId)).toBe(true);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it('has diverse tiles with no single type > 60%', () => {
|
||||
const world = generateWorld(mtns, 42);
|
||||
const counts = new Map<number, number>();
|
||||
for (const row of world.grid) {
|
||||
for (const t of row) counts.set(t, (counts.get(t) ?? 0) + 1);
|
||||
}
|
||||
const total = mtns.mapWidth * mtns.mapHeight;
|
||||
expect(counts.size).toBeGreaterThanOrEqual(4);
|
||||
for (const count of counts.values()) {
|
||||
expect(count / total).toBeLessThan(0.6);
|
||||
}
|
||||
});
|
||||
|
||||
it('generates chasms (low elevation)', () => {
|
||||
const world = generateWorld(mtns, 42);
|
||||
const chasmId = mtns.tiles.find(t => t.name === 'chasm')?.id;
|
||||
expect(world.grid.some(row => row.includes(chasmId!))).toBe(true);
|
||||
});
|
||||
|
||||
it('generates ore deposits (resources)', () => {
|
||||
const world = generateWorld(mtns, 42);
|
||||
const oreId = mtns.tiles.find(t => t.resource)?.id;
|
||||
expect(world.grid.some(row => row.includes(oreId!))).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Verdant Forests Generation', () => {
|
||||
const forest = allBiomes.find(b => b.id === 'verdant-forests')!;
|
||||
|
||||
it('generates correct-size grid', () => {
|
||||
const world = generateWorld(forest, 42);
|
||||
expect(world.grid).toHaveLength(forest.mapHeight);
|
||||
expect(world.grid[0]).toHaveLength(forest.mapWidth);
|
||||
});
|
||||
|
||||
it('all tile IDs are valid', () => {
|
||||
const world = generateWorld(forest, 42);
|
||||
const validIds = new Set(forest.tiles.map(t => t.id));
|
||||
for (const row of world.grid) {
|
||||
for (const tileId of row) {
|
||||
expect(validIds.has(tileId)).toBe(true);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it('has diverse tiles with no single type > 60%', () => {
|
||||
const world = generateWorld(forest, 42);
|
||||
const counts = new Map<number, number>();
|
||||
for (const row of world.grid) {
|
||||
for (const t of row) counts.set(t, (counts.get(t) ?? 0) + 1);
|
||||
}
|
||||
const total = forest.mapWidth * forest.mapHeight;
|
||||
expect(counts.size).toBeGreaterThanOrEqual(4);
|
||||
for (const count of counts.values()) {
|
||||
expect(count / total).toBeLessThan(0.6);
|
||||
}
|
||||
});
|
||||
|
||||
it('generates bogs (low elevation)', () => {
|
||||
const world = generateWorld(forest, 42);
|
||||
const bogId = forest.tiles.find(t => t.name === 'bog')?.id;
|
||||
expect(world.grid.some(row => row.includes(bogId!))).toBe(true);
|
||||
});
|
||||
|
||||
it('generates herb patches (resources)', () => {
|
||||
const world = generateWorld(forest, 42);
|
||||
const herbId = forest.tiles.find(t => t.resource)?.id;
|
||||
expect(world.grid.some(row => row.includes(herbId!))).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user