diff --git a/src/game/engine/scenes/tests/auto_play.gd b/src/game/engine/scenes/tests/auto_play.gd index c882be96..bf48840c 100644 --- a/src/game/engine/scenes/tests/auto_play.gd +++ b/src/game/engine/scenes/tests/auto_play.gd @@ -1014,14 +1014,15 @@ func _next_building(city: Variant, player: Variant, city_count: int, has_founder ## 14 factors — priorities emerge from circumstances, not prescriptive order. var tech_req: Dictionary = { "library": "scholarship", "barracks": "military_doctrine", - "castle": "fortification", + "castle": "fortification", "spearmen": "war", + "cavalry": "animal_husbandry", } var candidates: Array[String] = [ "warrior", "forge", "walls", "marketplace", "temple", "colosseum", "ale_hall", "bathhouse", "library", "barracks", "monument", - "castle", "founder", "worker", + "castle", "founder", "worker", "spearmen", "cavalry", ] - var units_set: Array[String] = ["warrior", "founder", "worker"] + var units_set: Array[String] = ["warrior", "founder", "worker", "spearmen", "cavalry"] var scores: Dictionary = {} for cid: String in candidates: if not (cid in units_set) and city.has_building(cid): @@ -1035,6 +1036,13 @@ func _next_building(city: Variant, player: Variant, city_count: int, has_founder if not BuildableHelperScript.player_owns_resource( player, req_res ): + _append_event({ + "type": "resource_gate_rejected", + "player": player.index, + "city": city.city_name, + "unit": cid, + "resource": req_res, + }) continue scores[cid] = 0.0 diff --git a/src/simulator/crates/mc-city/src/city.rs b/src/simulator/crates/mc-city/src/city.rs index 2bd20d0a..db923c84 100644 --- a/src/simulator/crates/mc-city/src/city.rs +++ b/src/simulator/crates/mc-city/src/city.rs @@ -107,10 +107,10 @@ impl TileYield { pub const FOOD_PER_POP: f64 = 1.2; /// Base city HP before population scaling. Tuned up from 200 to extend TTV: -/// prior batches showed capitals falling at T99/T116 because a pop-3 capital -/// (230 HP) could be melted in ~15 siege turns even with walls. At 260 base, -/// pop-3 walled capital = 290+50 = 340 HP, pushing capture to T200+. -pub const BASE_CITY_HP: u32 = 260; +/// after a first pass to 260 seed1 still fell at T106, so bumped to 320. +/// Pop-3 walled capital = 350+50 = 400 HP, forcing attackers to sustain +/// siege for 30+ turns (target: median TTV ≥ 200). +pub const BASE_CITY_HP: u32 = 320; /// HP gained per population point. pub const HP_PER_POP: u32 = 10; @@ -514,13 +514,13 @@ impl City { self.hp = (self.hp + amount).min(self.max_hp); } - /// Heal the city by the standard per-turn amount (20 HP). - /// Raised from 10 to 20 to extend siege duration: at 10/turn regen a - /// 2-warrior assault could chain captures in ~15 turns, giving T99/T116 - /// fast wins. 20/turn forces attackers to commit more force or siege. + /// Heal the city by the standard per-turn amount (30 HP). + /// Second pass (was 10, then 20, now 30): at 20/turn seed1 still fell at + /// T106. 30/turn forces attackers to deal >30 avg siege damage per turn + /// or walls outlast any 1-2-unit rush. /// Skips destroyed cities (HP == 0). pub fn heal_per_turn(&mut self) { - const HEAL_PER_TURN: u32 = 20; + const HEAL_PER_TURN: u32 = 30; if self.hp > 0 && self.hp < self.max_hp { self.heal(HEAL_PER_TURN); } diff --git a/src/simulator/crates/mc-combat/src/siege.rs b/src/simulator/crates/mc-combat/src/siege.rs index 7db55408..b998ecd9 100644 --- a/src/simulator/crates/mc-combat/src/siege.rs +++ b/src/simulator/crates/mc-combat/src/siege.rs @@ -23,13 +23,13 @@ const RANGED_CITY_HP_FRACTION: f32 = 0.75; /// Compute the penalty multiplier for melee attacks against a walled city. /// Returns a value < 1.0 that the attacker's effective strength is multiplied by. -/// Scales by tier: 0=1.0, 1=0.70 (walls), 2=0.55 (castle). -/// Tightened from 0.80/0.65 to slow sieges after fast-win regressions (T99/T116). +/// Scales by tier: 0=1.0, 1=0.60 (walls), 2=0.45 (castle). +/// Second pass from 0.70/0.55; first pass slowed but seed1 still fell T106. pub fn melee_wall_penalty(wall_tier: i32) -> f32 { match wall_tier { 0 => 1.0, - 1 => 0.70, - _ => 0.55, + 1 => 0.60, + _ => 0.45, } } @@ -91,9 +91,9 @@ mod tests { #[test] fn melee_penalty_scales_by_tier() { assert!((melee_wall_penalty(0) - 1.0).abs() < 0.001); - assert!((melee_wall_penalty(1) - 0.70).abs() < 0.001); - assert!((melee_wall_penalty(2) - 0.55).abs() < 0.001); - assert!((melee_wall_penalty(3) - 0.55).abs() < 0.001); + assert!((melee_wall_penalty(1) - 0.60).abs() < 0.001); + assert!((melee_wall_penalty(2) - 0.45).abs() < 0.001); + assert!((melee_wall_penalty(3) - 0.45).abs() < 0.001); } #[test]