From e75d98e53d321463a09ba66456dae72076978bc2 Mon Sep 17 00:00:00 2001 From: Claude Code Date: Sun, 29 Mar 2026 05:22:26 -0700 Subject: [PATCH] =?UTF-8?q?feat(ecology):=20=E2=9C=A8=20Add=20dynamic=20fl?= =?UTF-8?q?ora=20physics=20interactions=20and=20update=20sprite=20generati?= =?UTF-8?q?on=20pipeline?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Lilith Autocommit --- engine/src/modules/ecology/flora.gd | 8 ++++++-- .../engine-ts/src/EcologyPhysics.generated.ts | 9 +++++++-- tools/sprite-generation/spritegen.db-shm | Bin 32768 -> 32768 bytes tools/sprite-generation/spritegen.db-wal | Bin 9092872 -> 9092872 bytes tools/transpile-engine/ecology_assembly.py | 4 ++-- 5 files changed, 15 insertions(+), 6 deletions(-) diff --git a/engine/src/modules/ecology/flora.gd b/engine/src/modules/ecology/flora.gd index 11ad50ff..6232b57a 100644 --- a/engine/src/modules/ecology/flora.gd +++ b/engine/src/modules/ecology/flora.gd @@ -63,7 +63,7 @@ func process_turn(game_map: RefCounted) -> void: var tiles: Array = game_map.tiles.values() var o2: float = game_map.o2_fraction if "o2_fraction" in game_map else 0.21 - tick_pioneer(tiles, _biome_flora, _veg) + tick_pioneer(tiles, _biome_flora, _veg, o2) tick_canopy(tiles, _biome_flora, _veg, o2) tick_undergrowth(tiles, _biome_flora, _veg, o2) tick_fungi(tiles, _biome_flora, _veg) @@ -81,12 +81,16 @@ func process_turn(game_map: RefCounted) -> void: # ========================================================================= -static func tick_pioneer(tiles: Array, biome_flora: Dictionary, veg: Dictionary) -> void: +static func tick_pioneer(tiles: Array, biome_flora: Dictionary, veg: Dictionary, o2_fraction: float = 0.21) -> void: ## Pioneer colonization: seeds bare ground with initial flora using raw climate values. ## Uses temperature/moisture directly (not biome climate range) because abiotic-classified ## tiles may have narrow climate ranges that don't match their actual climate conditions ## (e.g., a temperate tile classified as polar_desert before biology establishes). ## Does NOT run for abiotic worlds (ecology is disabled when abioticWorld = true). + ## Respects the O2 minimum threshold — no pioneer seeding in anoxic atmospheres. + var o2_mult: float = _o2_growth_mult(o2_fraction) + if o2_mult <= 0.0: + return var pioneer_rate: float = veg.get("pioneer_rate", 0.002) for tile: Variant in tiles: diff --git a/packages/engine-ts/src/EcologyPhysics.generated.ts b/packages/engine-ts/src/EcologyPhysics.generated.ts index 17973a5d..47664018 100644 --- a/packages/engine-ts/src/EcologyPhysics.generated.ts +++ b/packages/engine-ts/src/EcologyPhysics.generated.ts @@ -391,12 +391,17 @@ function _getStage(stage_index: number, stages: Record[]): Recor // Flora tick functions (auto-transpiled from flora.gd) // --------------------------------------------------------------------------- -function tickPioneer(tiles: TileState[], biomeFlora: Record>, veg: Record): void { +function tickPioneer(tiles: TileState[], biomeFlora: Record>, veg: Record, o2_fraction: number = 0.21): void { // Pioneer colonization: seeds bare ground with initial flora using raw climate values. // Uses temperature/moisture directly (not biome climate range) because abiotic-classified // tiles may have narrow climate ranges that don't match their actual climate conditions // (e.g., a temperate tile classified as polar_desert before biology establishes). // Does NOT run for abiotic worlds (ecology is disabled when abioticWorld = true). + // Respects the O2 minimum threshold — no pioneer seeding in anoxic atmospheres. + let o2_mult = _o2GrowthMult(o2_fraction) + if (o2_mult <= 0.0) { + return + } let pioneer_rate = (veg as any)["pioneer_rate"] ?? 0.002 for (const tile of tiles) { @@ -1160,7 +1165,7 @@ export class EcologyPhysics { // Flora dynamics (order matches flora.gd process_turn) const o2 = grid.o2_fraction ?? 0.21 - tickPioneer(tiles, bf, veg) + tickPioneer(tiles, bf, veg, o2) // Reclassify pioneer-seeded tiles immediately so subsequent ticks use the correct biome. // A tile seeded from canopy=0 to canopy>0 may be in an abiotic biome (polar_desert, // chaparral) that won't match its actual climate, causing tick_canopy/tick_undergrowth diff --git a/tools/sprite-generation/spritegen.db-shm b/tools/sprite-generation/spritegen.db-shm index 35ce2169ab83e8fe8deee5a057ac92a025876603..e7186dc00efc8c82de1de33305c22e7c9fc6c2f1 100644 GIT binary patch delta 215 zcmZo@U}|V!s+V}A%K!p5moqRhGB60tV`5;qEYH9o;hI*YeeZXmpi`MvL9|-D#gh2v z2BsV1NL3Fu97ur7{f`8o;v4G=x%e1`fOZ2h3lOsjZT`q*V7gh);es6ZY^FItZ6NS) s@<%RF#=glHJw-R0#2?{coC{=1Zx+dTz{)spa$$u2ByO?IR(Zz+0jvN*R{#J2 delta 191 zcmZo@U}|V!s+V}A%K!pbmoqRhGB60tVq##pEYH9&F|@DOhhf_!L8mgUf@rmP=I5Dl znXBd+lBynTIFJCD`yUBF#W&U$a&2bj);66iz%9I4&*6d`kio_Ha55veC}ZE`i=LvJ bP2!JmOn%@kvsonL0qbNQZnw==dB+3+jIBM% diff --git a/tools/sprite-generation/spritegen.db-wal b/tools/sprite-generation/spritegen.db-wal index 4470d33ce40d0b38801c8593410dd3f328cb908a..f5638cd18f7ffa229f8bb15c3ac9fc833a0e6d97 100644 GIT binary patch delta 1095 zcmbW!NlX)A7{>8wskD|>3W`#}K|qm$v@>6~aTG*kakmw5VG$P;Hxy6-tzv~&Kob+d z=$D8lCYl)apb%prYC@vMg9kOP7cudOB*vpLE>COXa`58ecbm-opLe>xUDI_zkTj&F zDALh5iY7f7XgnDyhD>Cp2^32filca%NRudmCesv3Br8p&Bub`fBvJ}Zr&LO#becgk zDT8KF<}F+ANJhLy5K^AU6*OhlS7cN#k9(i-eV`^_HeM05(Sw31F?ukD>xX&w=Z?4i z8y}Ag1qay2D6Jrb8vLwY6IDYMr|*8f%v;BTdM<|8{?Nl5xlhA~16q;S4cU@;{XN@k z-cTdCc;8si$Q^fB%o(3tJCCWdM|HXF%*8y+l`ToCBniUbIj08B1=}uqon}E0v<4YD z2KkSiLcOkY3sv%OWwy&a_X7%^js_zI`!xKv?67FO{MlNkn_n7|OZca)vWu60K*Q_a z%*I4~Ur{Ay_jnaWQht8F^S|dP|Cpou^SXVnVkf6P@~UQ2Jm#c_=cM=hrx-#}4{%f? zMn($)8mb~E9lqWi2w$^Z!|lm7E6;m5OXSnWGLyM4-jStYk)!Gq=E2C`%$9J0qPm=R zk0N=P_t!!3%HRLDaa&QM|I0|W*%A>H{P%SFK)`e zdA3Ks&qvPNEWCT9)XK+tWRbrMXp?yU1zR@v^~!Gk)G#}9x+Ui7 z92K)58)ice*ueo3$iTn};b-080WT;p2UM5~^B@=UU_Ru-0w{omPzXg(3?;A#7Q+%) z3d>+Qtbmo^13#>SQdkXTum;w`I#>_oPyv-t1sk9mHo_*@3|pWEw!${3h3&8dcET>$ z4Rx>w_Ch^0KqKsf{cr%9pcz`=ARK}K9EKy%3P&Lb$Dj?`f#5iFKqqv;iO{HcQoQ&B D=9BAI-L3iwHZ0t4#yxjcWGN&yl;< zGKPQj?(G-LrjYMe!wk3OM`l&RObKf#ceCp^$K-)@k>bgCl>n<^4p!2+y0cN%ZxKgj z_21D|^8bIu2&FpvtX(uImYP(J?0gXmc=VKR81bmC*Xg?LmaJbR_PV|5dmVaZSG#D* z9c@o9OM-(GJUV@FL{+mI~2p*8ZwO9npA#9 z#-|Nw&KydnTo(3oBAIy8#cLVT zCI86!SE5BR@|RSSvaiALI}(+8BA!g7x}SsuM4 dict[str, str]: # --------------------------------------------------------------------------- FLORA_TICK_SIGS: dict[str, str] = { - "tick_pioneer": "tickPioneer(tiles: TileState[], biomeFlora: Record>, veg: Record): void", + "tick_pioneer": "tickPioneer(tiles: TileState[], biomeFlora: Record>, veg: Record, o2_fraction: number = 0.21): void", "tick_canopy": "tickCanopy(tiles: TileState[], biomeFlora: Record>, veg: Record, o2_fraction: number = 0.21): void", "tick_undergrowth": "tickUndergrowth(tiles: TileState[], biomeFlora: Record>, veg: Record, o2_fraction: number = 0.21): void", "tick_fungi": "tickFungi(tiles: TileState[], biomeFlora: Record>, veg: Record): void", @@ -657,7 +657,7 @@ export class EcologyPhysics {{ // Flora dynamics (order matches flora.gd process_turn) const o2 = grid.o2_fraction ?? 0.21 - tickPioneer(tiles, bf, veg) + tickPioneer(tiles, bf, veg, o2) // Reclassify pioneer-seeded tiles immediately so subsequent ticks use the correct biome. // A tile seeded from canopy=0 to canopy>0 may be in an abiotic biome (polar_desert, // chaparral) that won't match its actual climate, causing tick_canopy/tick_undergrowth