From e7f17db83500cb4ad6945912e655daa479891a8d Mon Sep 17 00:00:00 2001 From: Claude Code Date: Thu, 26 Mar 2026 02:22:25 -0700 Subject: [PATCH] =?UTF-8?q?feat(climate):=20=E2=9C=A8=20Implement=20new=20?= =?UTF-8?q?weather=20effects=20and=20temperature=20modeling=20in=20climate?= =?UTF-8?q?=20simulation=20logic?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Lilith Autocommit --- engine/src/modules/climate/climate.gd | 17 +++++++++++++++-- engine/src/modules/climate/climate_base.gd | 4 ++-- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/engine/src/modules/climate/climate.gd b/engine/src/modules/climate/climate.gd index bcce6153..c04c5fd8 100644 --- a/engine/src/modules/climate/climate.gd +++ b/engine/src/modules/climate/climate.gd @@ -93,7 +93,7 @@ func _apply_orbital_forcing(game_map: RefCounted, turn: int) -> void: func _apply_aerosol_forcing(game_map: RefCounted) -> void: - ## Apply stratospheric sulfate aerosol effects accumulated from volcanic/impact events. + ## Phase 0: Natural aerosol generation — desert dust, volcanic outgassing, baseline. ## Phase 1: apply cooling and drying to magic deltas (solar blocking + evaporation loss). ## Phase 2: transport aerosol downwind (double-buffered snapshot). ## Phase 3: decay aerosol each turn. @@ -101,7 +101,20 @@ func _apply_aerosol_forcing(game_map: RefCounted) -> void: if aerosol_cfg.is_empty(): return - # Short-circuit: skip turn if no aerosol exists anywhere + # Phase 0: Natural sources inject small aerosol each turn + var bg: float = _params.get("aerosol_background", 0.002) + var desert_rate: float = _params.get("aerosol_desert_dust", 0.005) + var volcano_rate: float = _params.get("aerosol_volcanic_outgas", 0.015) + for axial: Vector2i in game_map.tiles: + var tile: Variant = game_map.tiles[axial] + var inject: float = bg + if tile.biome_id == "desert": + inject += desert_rate + elif tile.biome_id == "volcano": + inject += volcano_rate + tile.sulfate_aerosol = maxf(0.0, tile.get("sulfate_aerosol", 0.0) + inject) + + # Short-circuit: skip processing if no aerosol exists anywhere var any_aerosol: bool = false for axial: Vector2i in game_map.tiles: if (game_map.tiles[axial] as Object).get("sulfate_aerosol") > 0.001: diff --git a/engine/src/modules/climate/climate_base.gd b/engine/src/modules/climate/climate_base.gd index 191dfb2f..93e8599e 100644 --- a/engine/src/modules/climate/climate_base.gd +++ b/engine/src/modules/climate/climate_base.gd @@ -34,7 +34,7 @@ const _DEFAULTS: Dictionary = { "lake_thermal_conductivity": 0.05, "river_moisture_transport": 0.075, "mountain_rain_shadow_block": 0.9, - "solar_min": 0.15, + "solar_min": 0.05, "solar_max": 0.70, } @@ -290,7 +290,7 @@ func _solar_by_latitude(row: int, center_row: float) -> float: ## Mapped via solar_min/solar_max params to produce stable equilibrium ## temperatures that support reef survival and biome diversity. var raw: float = 1.0 - absf((float(row) - center_row) / center_row) - var solar_min: float = _params.get("solar_min", _DEFAULTS.get("solar_min", 0.15)) + var solar_min: float = _params.get("solar_min", _DEFAULTS.get("solar_min", 0.05)) var solar_max: float = _params.get("solar_max", _DEFAULTS.get("solar_max", 0.70)) return solar_min + (solar_max - solar_min) * raw