feat(transpile-engine): ✨ Add ecology and map generation assembly transformation logic for transpile engine
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
parent
1ddb6574b0
commit
06641ebd32
3 changed files with 80 additions and 4 deletions
|
|
@ -135,9 +135,9 @@ def _classifier() -> str:
|
|||
|
||||
function classifyBiome(tile: TileState): string {
|
||||
const sub = tile.substrate_id
|
||||
// Aquatic tiles keep their terrain_id
|
||||
// Aquatic tiles keep their biome_id
|
||||
if (sub === 'deep_water' || sub === 'shallow_water' || sub === 'lake_bed') {
|
||||
return tile.terrain_id
|
||||
return tile.biome_id
|
||||
}
|
||||
|
||||
const temp = tile.temperature
|
||||
|
|
@ -182,7 +182,7 @@ function isWater(tile: TileState): boolean {
|
|||
if (sub) {
|
||||
return sub === 'deep_water' || sub === 'shallow_water' || sub === 'lake_bed'
|
||||
}
|
||||
return tile.terrain_id === 'ocean' || tile.terrain_id === 'coast'
|
||||
return tile.biome_id === 'ocean' || tile.biome_id === 'coast'
|
||||
}
|
||||
|
||||
function climateMatch(tile: TileState, biome: BiomeDef): number {
|
||||
|
|
|
|||
|
|
@ -233,6 +233,7 @@ class GenMap {
|
|||
readonly width: number
|
||||
readonly height: number
|
||||
readonly tiles: Map<string, GenTile> = new Map()
|
||||
sea_level = 0.0
|
||||
|
||||
constructor(width: number, height: number) {
|
||||
this.width = width
|
||||
|
|
@ -300,6 +301,8 @@ class GenMap {
|
|||
height: this.height,
|
||||
global_avg_temp: 0.5,
|
||||
ocean_dead_fraction: 0.0,
|
||||
ecosystem_health: 1.0,
|
||||
sea_level: this.sea_level,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -630,6 +633,7 @@ function assignSeaLevel(
|
|||
Math.max(Math.round(oceanTarget * allElevs.length), 0), allElevs.length - 1,
|
||||
)
|
||||
const seaLevel = allElevs[seaIdx]
|
||||
gm.sea_level = seaLevel
|
||||
|
||||
for (const tile of gm.tiles.values()) {
|
||||
const elev = elevation.get(axialKey(tile.axial)) ?? 0.0
|
||||
|
|
|
|||
|
|
@ -356,6 +356,7 @@ export class ClimatePhysics {
|
|||
this.stepDeepEarthWater(grid)
|
||||
this.stepPrecipitation(grid)
|
||||
this.stepTerrainEvolution(grid)
|
||||
this.stepSeaLevel(grid)
|
||||
const events = this.stepEcologicalEvents(grid, turn, seed)
|
||||
this.stepAnchorDecay(grid)
|
||||
this.stepGlobalStats(grid)
|
||||
|
|
@ -771,7 +772,31 @@ def _emit_terrain_evolution() -> str:
|
|||
const tid = tile.biome_id
|
||||
|
||||
if (tile.is_natural_wonder) continue
|
||||
if (tid === 'ocean' || tid === 'coast' || tid === 'lake' || tid === 'volcano') continue
|
||||
|
||||
// Water freezing/thawing — ice forms below freeze threshold, thaws above
|
||||
const freezeTemp = this.p('water_freeze_threshold', 0.12)
|
||||
const thawTemp = freezeTemp + 0.03 // hysteresis prevents oscillation
|
||||
const isWater = tid === 'ocean' || tid === 'coast' || tid === 'lake' || tid === 'inland_sea'
|
||||
if (isWater) {
|
||||
if (tile.temperature < freezeTemp) {
|
||||
tile.original_biome_id = tid
|
||||
tile.biome_id = 'ice'
|
||||
tile.quality = 1
|
||||
tile.quality_progress = 0
|
||||
}
|
||||
continue
|
||||
}
|
||||
if (tid === 'ice') {
|
||||
if (tile.temperature > thawTemp && tile.original_biome_id) {
|
||||
tile.biome_id = tile.original_biome_id
|
||||
tile.original_biome_id = ''
|
||||
tile.quality = 1
|
||||
tile.quality_progress = 0
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if (tid === 'volcano') continue
|
||||
|
||||
const ideal = idealTerrain(tile, this.spec)
|
||||
|
||||
|
|
@ -800,6 +825,52 @@ def _emit_terrain_evolution() -> str:
|
|||
"""
|
||||
|
||||
|
||||
def _emit_sea_level() -> str:
|
||||
return """\
|
||||
private stepSeaLevel(grid: GridState): void {
|
||||
// Sea level responds to global temperature: warmer → thermal expansion + ice melt → higher.
|
||||
// Each turn, sea_level drifts toward an equilibrium determined by global_avg_temp.
|
||||
// Tiles below sea_level flood to coast/ocean; tiles above expose to land.
|
||||
const sensitivity = this.p('sea_level_temp_sensitivity', 0.0008)
|
||||
const eqTemp = this.p('sea_level_equilibrium_temp', 0.45)
|
||||
const { tiles, width: w, height: h } = grid
|
||||
|
||||
// Adjust sea level: positive when warmer than equilibrium, negative when cooler
|
||||
const tempAnomaly = grid.global_avg_temp - eqTemp
|
||||
grid.sea_level += tempAnomaly * sensitivity
|
||||
|
||||
// Flood low land / expose high water
|
||||
let changed = false
|
||||
for (let i = 0; i < tiles.length; i++) {
|
||||
const tile = tiles[i]
|
||||
const isWater = tile.biome_id === 'ocean' || tile.biome_id === 'coast' ||
|
||||
tile.biome_id === 'lake' || tile.biome_id === 'inland_sea'
|
||||
|
||||
if (!isWater && tile.elevation < grid.sea_level) {
|
||||
// Land tile floods — becomes coast if adjacent to land, ocean otherwise
|
||||
if (tile.is_natural_wonder) continue
|
||||
tile.original_biome_id = tile.biome_id
|
||||
tile.biome_id = 'coast'
|
||||
tile.quality = 1
|
||||
tile.quality_progress = 0
|
||||
changed = true
|
||||
} else if (tile.biome_id === 'coast' && tile.elevation >= grid.sea_level + 0.02) {
|
||||
// Coast tile exposed — reclassify as land based on climate
|
||||
// Small hysteresis buffer (0.02) prevents oscillation at the boundary
|
||||
tile.biome_id = classifyTerrain(tile.temperature, tile.moisture, tile.elevation)
|
||||
tile.quality = 1
|
||||
tile.quality_progress = 0
|
||||
changed = true
|
||||
}
|
||||
}
|
||||
|
||||
// Invalidate ocean distance cache if coastline changed
|
||||
if (changed) this.oceanDistGridId = -1
|
||||
}
|
||||
|
||||
"""
|
||||
|
||||
|
||||
def _emit_anchor_decay() -> str:
|
||||
return """\
|
||||
private stepAnchorDecay(grid: GridState): void {
|
||||
|
|
@ -848,6 +919,7 @@ def assemble(fns: dict[str, dict[str, str]]) -> str:
|
|||
parts.append(f" // NOTE: {gd_name} not found in climate.gd\n")
|
||||
parts.append(f" {visibility} {ts_name}(grid: GridState): void {{ }}\n\n")
|
||||
|
||||
parts.append(_emit_sea_level())
|
||||
parts.append(_emit_ecological_events())
|
||||
parts.append("\n")
|
||||
parts.append(_emit_anchor_decay())
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue