/** * Biomes: Meadow, Freshwater, Ocean, Forest, Mountain. * Each cell has a biome and a temperature; display uses optional interpolation for smooth transitions. */ export const BIOMES = ["Meadow", "Freshwater", "Ocean", "Forest", "Mountain"]; /** * Base biome from grid position (5 zones by column). * @param {number} width * @param {number} _height * @param {number} x 1-based column * @param {number} _y 1-based row * @returns {string} */ export function getCellBiome(width, _height, x, _y) { const w = Math.max(1, width); const col = Math.max(1, Math.min(w, Math.floor(x))); const t = Math.floor((col - 1) / (w / 5)); const index = Math.min(4, Math.max(0, t)); return BIOMES[index] ?? "Meadow"; } /** * Backward-compat: getCellBiome with 2 args (width, x) returns Meadow/Ocean/Mountain by column thirds. * @param {number} width * @param {number} x * @returns {string} */ export function getCellBiomeLegacy(width, x) { const third = Math.max(1, Math.floor(width / 3)); if (x <= third) return "Meadow"; if (x <= third * 2) return "Ocean"; return "Mountain"; } /** * Base temperature at cell (smooth gradient by position). Range about 10–28. * @param {number} width * @param {number} height * @param {number} x 1-based * @param {number} y 1-based * @returns {number} */ export function getCellTemperature(width, height, x, y) { const w = Math.max(1, width); const h = Math.max(1, height); const nx = (Math.max(1, Math.min(w, Math.floor(x))) - 0.5) / w; const ny = (Math.max(1, Math.min(h, Math.floor(y))) - 0.5) / h; return 10 + ny * 14 + nx * 4; } /** * Display biome at (x, y) — for now the cell's own biome (no string interpolation). * @param {number} x 1-based * @param {number} y 1-based * @param {{ width: number, height: number }} grid * @returns {string} */ export function getDisplayBiome(x, y, grid) { return getCellBiome(grid.width, grid.height, x, y); } /** * Display temperature at (x, y) with smooth interpolation from neighbours. * @param {number} x 1-based * @param {number} y 1-based * @param {{ width: number, height: number }} grid * @returns {number} */ export function getDisplayTemperature(x, y, grid) { const w = grid.width; const h = grid.height; let sum = 0; let count = 0; for (let dy = -1; dy <= 1; dy++) { for (let dx = -1; dx <= 1; dx++) { const nx = x + dx; const ny = y + dy; if (nx >= 1 && nx <= w && ny >= 1 && ny <= h) { sum += getCellTemperature(w, h, nx, ny); count += 1; } } } return count > 0 ? sum / count : getCellTemperature(w, h, x, y); } /** * Temperature band for CSS class: low (< 16), mid (16–22), high (> 22). * @param {number} temp * @returns {"low"|"mid"|"high"} */ export function getTemperatureBand(temp) { if (temp < 16) return "low"; if (temp <= 22) return "mid"; return "high"; } /** * @param {string} animalBiome * @param {string} cellBiome * @returns {boolean} */ export function isAnimalAllowedOnBiome(animalBiome, cellBiome) { if (animalBiome === cellBiome) return true; if (animalBiome === "Meadow" && cellBiome === "Forest") return true; if (animalBiome === "Ocean" && cellBiome === "Freshwater") return true; return false; } /** * Biomes that are compatible with this cell for loot/placement (cell biome + compatible animal biomes). * @param {string} cellBiome * @returns {string[]} */ export function getBiomesCompatibleWithCell(cellBiome) { const set = [cellBiome]; if (cellBiome === "Forest") set.push("Meadow"); if (cellBiome === "Freshwater") set.push("Ocean"); return set; }