import { createNoise2D } from 'simplex-noise' import { WORLD_TILES } from '../config' import { TileType } from '../types' /** Simple seeded PRNG (mulberry32) */ function mulberry32(seed: number): () => number { return () => { seed |= 0 seed = (seed + 0x6D2B79F5) | 0 let t = Math.imul(seed ^ (seed >>> 15), 1 | seed) t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t return ((t ^ (t >>> 14)) >>> 0) / 4294967296 } } function classify(e: number, m: number): TileType { if (e < 0.22) return TileType.DEEP_WATER if (e < 0.30) return TileType.SHALLOW_WATER if (e < 0.38) return TileType.SAND if (e > 0.82) return TileType.ROCK // land – split by moisture if (m > 0.62 && e > 0.48) return TileType.FOREST if (m > 0.38) return TileType.DARK_GRASS return TileType.GRASS } export function generateTerrain(seed: number): number[] { const prng1 = mulberry32(seed) const prng2 = mulberry32(seed ^ 0xDEADBEEF) const elevNoise = createNoise2D(prng1) const moistNoise = createNoise2D(prng2) const size = WORLD_TILES const tiles = new Array(size * size) for (let y = 0; y < size; y++) { for (let x = 0; x < size; x++) { // Multi-octave elevation const nx = x / size const ny = y / size const e = (elevNoise(nx * 4, ny * 4) * 1.0 + elevNoise(nx * 8, ny * 8) * 0.5 + elevNoise(nx * 16, ny * 16) * 0.25) / 1.75 const eNorm = (e + 1) / 2 // -1..1 → 0..1 const m = moistNoise(nx * 6 + 10, ny * 6 + 10) const mNorm = (m + 1) / 2 tiles[y * size + x] = classify(eNorm, mNorm) } } return tiles } /** Find a walkable spawn tile near the world center */ export function findSpawn(tiles: number[]): { tileX: number; tileY: number } { const center = Math.floor(WORLD_TILES / 2) const walkable = new Set([TileType.GRASS, TileType.DARK_GRASS, TileType.SAND]) for (let r = 0; r < center; r++) { for (let dy = -r; dy <= r; dy++) { for (let dx = -r; dx <= r; dx++) { if (Math.abs(dx) !== r && Math.abs(dy) !== r) continue const tx = center + dx const ty = center + dy if (tx < 0 || ty < 0 || tx >= WORLD_TILES || ty >= WORLD_TILES) continue if (walkable.has(tiles[ty * WORLD_TILES + tx])) { return { tileX: tx, tileY: ty } } } } } return { tileX: center, tileY: center } }