feat(engine): Update ecology/physics simulation, hex grid traversal, and procedural map generation logic with auto-generated code and new simulation runner support

Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
Claude Code 2026-03-26 04:32:37 -07:00
parent 35038780ec
commit fb6b66894c
5 changed files with 983 additions and 460 deletions

File diff suppressed because it is too large Load diff

View file

@ -99,48 +99,69 @@ export function classifyTerrain(
moisture: number,
elevation: number,
): string {
// Only the highest peaks are locked terrain — elevation interacts with
// climate for hills (cold hills→tundra, wet hills→forest).
// ── Extreme elevation ─────────────────────────────────────────────────────
if (elevation > 0.82) return 'mountains'
if (elevation > 0.70) {
if (temp < 0.25) return 'tundra'
if (moisture > 0.65 && temp > 0.55) return 'forest'
if (temp < 0.20) return 'alpine_tundra'
if (temp < 0.40 && moisture > 0.50) return 'cloud_forest'
if (moisture > 0.45 && temp > 0.35) return 'alpine_meadow'
return 'hills'
}
if (elevation > 0.55) {
if (moisture > 0.40 && temp > 0.30) return 'montane_forest'
if (moisture > 0.70 && temp > 0.30) return 'cloud_forest'
if (moisture > 0.30) return 'alpine_meadow'
return 'hills'
}
// Polar / cold zones
if (temp < 0.10) return 'snow'
if (temp < 0.20) return moisture >= 0.30 ? 'boreal_forest' : 'tundra'
if (temp < 0.35) {
if (moisture >= 0.50) return 'boreal_forest'
if (moisture >= 0.30) return 'grassland'
// ── Polar / ice (temp < 0.10) ─────────────────────────────────────────────
if (temp < 0.05) return 'ice'
if (temp < 0.10) {
if (moisture < 0.15) return 'polar_desert'
return 'snow'
}
// ── Subpolar (0.100.20) ──────────────────────────────────────────────────
if (temp < 0.20) {
if (moisture < 0.20) return 'polar_desert'
if (moisture >= 0.30) return 'boreal_forest'
return 'tundra'
}
// Temperate zone (0.350.55) — this is where most diversity should live
// ── Cool (0.200.35) ──────────────────────────────────────────────────────
if (temp < 0.35) {
if (moisture >= 0.55) return 'boreal_forest'
if (moisture >= 0.35) return 'grassland'
return 'tundra'
}
// ── Temperate (0.350.55) — most biome diversity ──────────────────────────
if (temp < 0.55) {
if (moisture < 0.25) return 'desert'
if (moisture < 0.40) return 'plains'
if (moisture < 0.20) return 'desert'
if (moisture < 0.30) return 'chaparral'
if (moisture < 0.42) return 'plains'
if (moisture < 0.55) return 'grassland'
if (moisture < 0.70) return 'forest'
if (moisture < 0.80) return 'temperate_rainforest'
return 'bog'
}
// ── Warm (0.550.75) ──────────────────────────────────────────────────────
if (temp < 0.75) {
if (moisture < 0.20) return 'desert'
if (moisture < 0.35) return 'savanna'
if (moisture < 0.50) return 'plains'
if (moisture < 0.62) return 'tropical_dry_forest'
if (moisture < 0.75) return 'jungle'
return 'swamp'
}
// Warm zone (0.550.80)
if (temp < 0.80) {
if (moisture < 0.25) return 'desert'
if (moisture < 0.40) return 'plains'
if (moisture < 0.55) return 'grassland'
if (moisture < 0.68) return 'forest'
return 'jungle'
}
// Hot zone (>0.80) — true tropics, equatorial only
if (moisture < 0.30) return 'desert'
if (moisture < 0.45) return 'plains'
if (moisture < 0.60) return 'grassland'
if (moisture < 0.68) return 'forest'
return 'jungle'
// ── Hot (>0.75) — true tropics ────────────────────────────────────────────
if (moisture < 0.20) return 'desert'
if (moisture < 0.38) return 'savanna'
if (moisture < 0.52) return 'tropical_dry_forest'
if (moisture < 0.70) return 'jungle'
return 'tropical_rainforest'
}
// ---------------------------------------------------------------------------

View file

@ -264,6 +264,29 @@ class GenMap {
wonder_anchor_schools: [],
wonder_tier: 0,
river_source_type: gt?.river_source_type || undefined,
// Classifier fields (populated by water body finder + map gen)
water_body_type: '',
is_river_mouth: false,
has_cave: false,
// Atmosphere fields (populated by ClimatePhysics atmosphere steps)
pressure: 1013.0,
pressure_anomaly: 0.0,
humidity: 0.0,
// Ecology fields (populated by EcologyPhysics)
canopy_cover: 0.0,
undergrowth: 0.0,
fungi_network: 0.0,
drought_counter: 0,
succession_progress: 0,
regrowth_stage: -1,
regrowth_turns: 0,
habitat_suitability: 0.0,
habitat_low_turns: 0,
landmark_name: '',
substrate_id: '',
water_body_id: -1,
depth_from_coast: -1,
fish_stock: 0,
}
}
}

View file

@ -50,10 +50,24 @@ function computeTileAlbedo(tile: TileState, isWater: boolean): number {
// ---------------------------------------------------------------------------
export const TERRAIN_ORDER: readonly string[] = [
'ocean', 'coast', 'lake', 'inland_sea', 'ice', 'snow', 'tundra', 'desert',
'plains', 'grassland', 'forest', 'boreal_forest', 'jungle', 'enchanted_forest',
'hills', 'mountains', 'swamp', 'volcano',
// Natural wonders (geological/biological formations)
// Water
'ocean', 'deep_ocean', 'coast', 'coral_reef', 'lake', 'inland_sea', 'estuary',
// Ice / Polar
'ice', 'snow', 'polar_desert',
// Cold
'tundra', 'alpine_tundra', 'boreal_forest',
// Temperate
'chaparral', 'plains', 'grassland', 'forest', 'temperate_rainforest',
// Warm / Tropical
'desert', 'savanna', 'tropical_dry_forest', 'tropical_rainforest', 'jungle', 'mangrove',
// Elevation
'hills', 'mountains', 'alpine_meadow', 'cloud_forest', 'montane_forest',
// Wetland
'swamp', 'bog',
// Special
'volcano',
// Magic (hidden from legend — kept for ClimatePhysics.generated.ts compat)
'enchanted_forest',
'mana_node', 'ley_nexus', 'lodestone_spire', 'crystal_cavern',
'worldroot', 'primordial_spring', 'abyssal_vortex',
] as const

View file

@ -10,6 +10,9 @@ export interface TileState {
biome_id: string // computed biome from substrate + climate + flora
wind_direction: number // [0, 5] axial direction index
wind_speed: number // [0, 1]
pressure: number // atmospheric pressure (hPa, ~995-1030)
pressure_anomaly: number // dynamic anomaly offset from baseline
humidity: number // atmospheric humidity [0, 1]
quality: number // 1-5 (Q1 prolific .. Q5 epic)
quality_progress: number // counter toward next quality change
river_edges: number[] // edge indices [0-5] where rivers flow
@ -39,7 +42,11 @@ export interface TileState {
regrowth_turns: number // turns in current regrowth stage
// Fauna fields (updated per turn by ecology system)
habitat_suitability: number // [0, 1] weighted flora average
habitat_low_turns: number // consecutive turns habitat < abandon threshold
landmark_name: string // Q4+ tile name from FlavorGenerator
water_body_type: string // pond, lake, large_lake, ocean, river (from water body finder)
is_river_mouth: boolean // true if ocean tile adjacent to river
has_cave: boolean // true if cave system present (subterranean biome)
// Optional fields written by subsystems (not present on all tiles)
river_source_type?: string // 'snowmelt' | 'spring' | 'hot_spring' | 'glacial' | undefined
fish_stock?: number // marine ecosystem fish population [0, 1]