From 8d024c7b8733cdb94e083c6cfec129065d36a23c Mon Sep 17 00:00:00 2001 From: Claude Code Date: Sun, 29 Mar 2026 05:03:43 -0700 Subject: [PATCH] =?UTF-8?q?feat(climate):=20=E2=9C=A8=20Add=20climate=20ev?= =?UTF-8?q?aluation=20logic=20and=20update=20climate=20specifications=20in?= =?UTF-8?q?=20climate=5Fspec=5Feval.gd=20and=20climate=5Fspec.json?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Lilith Autocommit --- .../src/modules/climate/climate_spec_eval.gd | 17 ++++++++++------- games/age-of-dwarves/data/climate_spec.json | 8 ++++++-- tools/sprite-generation/spritegen.db-shm | Bin 32768 -> 32768 bytes tools/sprite-generation/spritegen.db-wal | Bin 9092872 -> 9092872 bytes 4 files changed, 16 insertions(+), 9 deletions(-) diff --git a/engine/src/modules/climate/climate_spec_eval.gd b/engine/src/modules/climate/climate_spec_eval.gd index 8cd64004..4fa15f04 100644 --- a/engine/src/modules/climate/climate_spec_eval.gd +++ b/engine/src/modules/climate/climate_spec_eval.gd @@ -14,6 +14,7 @@ static func ideal_terrain(tile: Variant, spec: Dictionary) -> String: var tid: String = tile.biome_id var temp: float = tile.temperature var moist: float = tile.moisture + var canopy: float = tile.get("canopy_cover", 0.0) var transitions: Dictionary = spec.get("terrain_transitions", {}) var rules: Array = transitions.get(tid, []) @@ -23,7 +24,7 @@ static func ideal_terrain(tile: Variant, spec: Dictionary) -> String: for rule: Variant in rules: if not rule is Dictionary: continue - if eval_condition(rule.get("condition", ""), temp, moist, tile.elevation): + if eval_condition(rule.get("condition", ""), temp, moist, tile.elevation, canopy): var becomes: String = rule.get("becomes", "") if becomes == "classify": return BiomeClassifierScript.classify(tile) @@ -32,22 +33,22 @@ static func ideal_terrain(tile: Variant, spec: Dictionary) -> String: return tid -static func eval_condition(cond: String, temp: float, moist: float, elev: float) -> bool: +static func eval_condition(cond: String, temp: float, moist: float, elev: float, canopy: float = 0.0) -> bool: ## Evaluate a condition string from climate_spec.json. ## Supports: "field op value", "cond1 AND cond2", "cond1 OR cond2". - ## Fields: temperature, moisture, elevation. + ## Fields: temperature, moisture, elevation, canopy. ## Operators: <, <=, >, >=. if " OR " in cond: var parts: PackedStringArray = cond.split(" OR ") for part: String in parts: - if eval_condition(part.strip_edges(), temp, moist, elev): + if eval_condition(part.strip_edges(), temp, moist, elev, canopy): return true return false if " AND " in cond: var parts: PackedStringArray = cond.split(" AND ") for part: String in parts: - if not eval_condition(part.strip_edges(), temp, moist, elev): + if not eval_condition(part.strip_edges(), temp, moist, elev, canopy): return false return true @@ -61,7 +62,7 @@ static func eval_condition(cond: String, temp: float, moist: float, elev: float) var op: String = tokens[1] var value: float = float(tokens[2]) - var actual: float = _field_value(field, temp, moist, elev) + var actual: float = _field_value(field, temp, moist, elev, canopy) if actual == -INF: return false @@ -83,7 +84,7 @@ static func ley_channeling_mult(tile: Variant, spec: Dictionary) -> float: return ley_spec.get("on_ley_generic", 2.0) -static func _field_value(field: String, temp: float, moist: float, elev: float) -> float: +static func _field_value(field: String, temp: float, moist: float, elev: float, canopy: float = 0.0) -> float: match field: "temperature": return temp @@ -91,6 +92,8 @@ static func _field_value(field: String, temp: float, moist: float, elev: float) return moist "elevation": return elev + "canopy": + return canopy push_warning("ClimateSpecEval: unknown field '%s'" % field) return -INF diff --git a/games/age-of-dwarves/data/climate_spec.json b/games/age-of-dwarves/data/climate_spec.json index f7d28a47..960f28da 100644 --- a/games/age-of-dwarves/data/climate_spec.json +++ b/games/age-of-dwarves/data/climate_spec.json @@ -406,7 +406,7 @@ "becomes": "savanna" }, { - "condition": "temperature <= 0.25", + "condition": "temperature <= 0.25 AND canopy > 0", "becomes": "tundra" } ], @@ -443,6 +443,10 @@ } ], "tundra": [ + { + "condition": "canopy <= 0", + "becomes": "polar_desert" + }, { "condition": "canopy > 0.30 AND temperature > 0.10", "becomes": "boreal_forest" @@ -458,7 +462,7 @@ ], "polar_desert": [ { - "condition": "temperature > 0.10", + "condition": "temperature > 0.10 AND canopy > 0", "becomes": "tundra" } ], diff --git a/tools/sprite-generation/spritegen.db-shm b/tools/sprite-generation/spritegen.db-shm index 0ae3ed3275d905cd72304aa52dc186b2e9e58b5f..6f5f06248e54185eeb038dc2e1377fcd7a24fa97 100644 GIT binary patch delta 221 zcmZo@U}|V!s+V}A%K!prmNPIgGB5~CWMW{rEYHA@WvV%)IZp18pi`MvL9|-D7YoPk zSXTQdq^buS4kSS4{zn2(@s0JSTw*);85ltLqa*_Zr!)jN32Z*dm14SC&moC}qlc-D rshz2pY4Z$^HZjJ&$rn9EH=D%oV&(5=ngBEx1||X}BsPntzLo+2g)u&* delta 184 zcmZo@U}|V!s+V}A%K!q$mNPIgGB5~qGchn+mS4u4vQA54hwv>p3KGa4;~mF|`9#Z=T`NCI%E1 T+iViQi*@o9F7?f#sjsB~s{1`> diff --git a/tools/sprite-generation/spritegen.db-wal b/tools/sprite-generation/spritegen.db-wal index a5f9078b98c09ba128ab45453274b2e947ccfa2d..2effd6e03a12f006832b2aa9b0b5ef98eebe7a92 100644 GIT binary patch delta 1982 zcmdtiTWl0n7zgl~&ThNCv0dnuZrfSFc6!^n?6u3qwqRSJEiE8bfwseTwq3gHZfB>Z z<)Rc0w2}~GxqJ^k7(i-*XxIc?Bql1CH;oW9iXlb;jhY%M8skgVZ@WN1-+l1mm(0_g zbN=7|obf+T>&DR@LX#xI5FOEzWRgM*B$cF*bdo_b$sA%NS;R!Zbl(y5@Yf+>2^?^X7PxgsNQ15)I1`*ZrOQh9$zFf3m)|Z2`eDvp zp%gwo!4<&Q9w`mJnBWF;+#bngwYx=^;I0$|k06ZolV)hUVLKVSZj+jr*z^T%npyDV z8Je_(9hGM$Z)O@6JUBzzC(-tIng4wI+5g%;MJ2_e=}jjv&SX0KAWxc~jPp=eB2GNq zPVnW{v9WIo__QRQPYy&NTAQ2?-7~xyjBki~x*P`X2v)97k$c#1DB{=rp&;vzu(HN# zeF_^;d|I_v32KVU%Bmv6w|Z`#Asq4tHH;iAA2GSvtT&_v71hc%gw*)As(3Xpy;Gjc zR?Ysy+b65CH~xo6UuZDU!){SnIoKOedSIrC&&!j;VKp@D-zIBHV1$(<$EHC+*doBd z6`bNPPMqRPp@g{^9m!wsfad(Q*w6)uAi>&$}PIeY=sjwcm?d5SY1JxffruBR| zBMuuZTPKue%R_QN9bvbHhHyBn7K+CYoo{i)(0o@&*DDbXGq3B=7r@)o>8X%&KVvSG z*i(z(m5NjYs8_groy#uS;rawOoIiVVo5Si9Y?A#!)_8H&%w8PWyh2Ke-CHiz&EB5- zOvw|8Y)Hwve7>RO)5PV8ClamIGykh7D2n+#+J2wWjrEW-nmgo^BtIL58lkl)vS$iLE){%0@*4xFM z`!bVV6hqCY3>C5Z)lzjbLs4{0r0ed{`Y|tQGs9*hpLh7PnL{wXPTCQ>S}m&d(H7bS z*E+Dt;XiN_ZBtd1@Z&iFx8RWA+5|TepDyD%v=}WxOVKj)G^#~)s2(jxE6_8j0X3o~v=XgC zt5Gv*L9J*FYD4X4En0`xqi4|u)PbHu&!ZR6MzjfSMxCe&bt4&VL0;5@6y!s_s1Nzk zR@9FIXd4Qm5DKFKq@oDY&>$K@+tDx@K|9b+v L*u|EEtpk4pA6v-D delta 7632 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