100 lines
3 KiB
TypeScript
100 lines
3 KiB
TypeScript
import { BEACH, ICECAP, LIGHT_FOREST, MOUNTAIN, WATER } from "./data";
|
|
import { IslandGrid } from "./grid";
|
|
|
|
export type IsDone = boolean;
|
|
export type LobeGenerator = () => IsDone;
|
|
export type LobeGeneratorConstructor = (
|
|
islands: IslandGrid,
|
|
basePos: number
|
|
) => LobeGenerator;
|
|
|
|
/** form mountain with icecap */
|
|
export const BIG_MOUNTAIN: LobeGeneratorConstructor =
|
|
(islands: IslandGrid, basePos: number) => () => {
|
|
const mountainTiles = islands.floodSearch(
|
|
basePos,
|
|
(tile) => tile > MOUNTAIN
|
|
);
|
|
islands.dropWithin(mountainTiles);
|
|
|
|
return mountainTiles.some((pos) => islands.data[pos] == ICECAP);
|
|
};
|
|
|
|
/** form low-lying beach */
|
|
export const SMALL_BEACH: LobeGeneratorConstructor =
|
|
(islands: IslandGrid, basePos: number) => () => {
|
|
const islandTiles = islands.floodSearch(basePos, (tile) => tile > WATER);
|
|
|
|
const shoreTiles = islandTiles.filter((pos) => islands.data[pos] == WATER);
|
|
islands.dropWithin(shoreTiles);
|
|
|
|
return true;
|
|
};
|
|
|
|
/** form low-lying beach that meets another island */
|
|
export const BIG_BEACH: LobeGeneratorConstructor = (
|
|
islands: IslandGrid,
|
|
basePos: number
|
|
) => {
|
|
let dropped = 0;
|
|
return () => {
|
|
const islandTiles = islands.floodSearch(basePos, (tile) => tile > WATER);
|
|
|
|
const shoreTiles = islandTiles.filter((pos) => islands.data[pos] == WATER);
|
|
islands.dropWithin(shoreTiles);
|
|
dropped++;
|
|
|
|
const landTiles = islandTiles.filter((pos) => islands.data[pos] > WATER);
|
|
return landTiles.length > dropped;
|
|
};
|
|
};
|
|
|
|
/** form forested zone */
|
|
export const FOREST_LOBE: LobeGeneratorConstructor =
|
|
(islands: IslandGrid, basePos: number) => () => {
|
|
const islandTiles = islands.floodSearch(basePos, (tile) => tile > WATER);
|
|
|
|
// grow shore
|
|
const shoreTiles = islandTiles.filter((pos) => islands.data[pos] == WATER);
|
|
islands.dropWithin(shoreTiles);
|
|
|
|
// seed beach
|
|
const beachTiles = islandTiles.filter((pos) => islands.data[pos] == BEACH);
|
|
islands.dropWithin(beachTiles);
|
|
|
|
// expand forest
|
|
const forestLobe = islands.floodSearch(basePos, (tile) => tile > BEACH);
|
|
const forestTiles = forestLobe.filter(
|
|
(pos) => islands.data[pos] == LIGHT_FOREST
|
|
);
|
|
islands.dropWithin(forestTiles);
|
|
islands.dropWithin(forestTiles);
|
|
islands.dropWithin(forestTiles);
|
|
|
|
return true;
|
|
};
|
|
|
|
/** form low-lying beach with eroded sections */
|
|
export const ERODED_LOBE: LobeGeneratorConstructor =
|
|
(islands: IslandGrid, basePos: number) => () => {
|
|
const islandTiles = islands.floodSearch(basePos, (tile) => tile > WATER);
|
|
|
|
const shoreTiles = islandTiles.filter((pos) => islands.data[pos] == WATER);
|
|
islands.dropWithin(shoreTiles);
|
|
|
|
// erode
|
|
if (islandTiles.length > 1) {
|
|
const erodePos = islandTiles[islands.rng() % islandTiles.length];
|
|
islands.data[erodePos] = Math.max(islands.data[erodePos] - 1, WATER);
|
|
}
|
|
|
|
return true;
|
|
};
|
|
|
|
export const BIG_ISLANDS = [BIG_BEACH, BIG_MOUNTAIN];
|
|
export const ALL_ISLANDS = [
|
|
BIG_MOUNTAIN,
|
|
SMALL_BEACH,
|
|
FOREST_LOBE,
|
|
ERODED_LOBE,
|
|
];
|