feat(simulator): Update city-building and siege combat mechanics with new simulation logic

Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
autocommit 2026-04-16 11:29:48 -07:00
parent 268c9303cd
commit d46862f4be
2 changed files with 17 additions and 10 deletions

View file

@ -106,8 +106,11 @@ impl TileYield {
/// with two decent food tiles. Target: median p0_pop_peak ≥ 7 at T150.
pub const FOOD_PER_POP: f64 = 1.2;
/// Base city HP before population scaling.
pub const BASE_CITY_HP: u32 = 200;
/// 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;
/// HP gained per population point.
pub const HP_PER_POP: u32 = 10;
@ -511,10 +514,13 @@ impl City {
self.hp = (self.hp + amount).min(self.max_hp);
}
/// Heal the city by the standard per-turn amount (10 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.
/// Skips destroyed cities (HP == 0).
pub fn heal_per_turn(&mut self) {
const HEAL_PER_TURN: u32 = 10;
const HEAL_PER_TURN: u32 = 20;
if self.hp > 0 && self.hp < self.max_hp {
self.heal(HEAL_PER_TURN);
}

View file

@ -23,12 +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.80 (walls), 2=0.65 (castle).
/// 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).
pub fn melee_wall_penalty(wall_tier: i32) -> f32 {
match wall_tier {
0 => 1.0,
1 => 0.80,
_ => 0.65,
1 => 0.70,
_ => 0.55,
}
}
@ -90,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.80).abs() < 0.001);
assert!((melee_wall_penalty(2) - 0.65).abs() < 0.001);
assert!((melee_wall_penalty(3) - 0.65).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);
}
#[test]