From 2b0c1d55f5159f06f8189e16e09137e71420eb30 Mon Sep 17 00:00:00 2001 From: autocommit Date: Wed, 15 Apr 2026 01:13:36 -0700 Subject: [PATCH] =?UTF-8?q?feat(city):=20=E2=9C=A8=20Increase=20food=20con?= =?UTF-8?q?sumption=20rate=20to=201.5=20for=20improved=20biome-specific=20?= =?UTF-8?q?small=20city=20viability?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Lilith Autocommit --- src/simulator/crates/mc-city/src/city.rs | 29 ++++++++++++------------ 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/src/simulator/crates/mc-city/src/city.rs b/src/simulator/crates/mc-city/src/city.rs index b2ae4708..1065967a 100644 --- a/src/simulator/crates/mc-city/src/city.rs +++ b/src/simulator/crates/mc-city/src/city.rs @@ -99,8 +99,12 @@ impl TileYield { } } -/// Food consumed per citizen per turn (Civ5 standard). -pub const FOOD_PER_POP: f64 = 2.0; +/// Food consumed per citizen per turn. Tuned to 1.5 (below Civ5's 2.0) so +/// small cities (pop 2-3) in plains/hills-heavy biomes can still climb past +/// pop 3 on center yield + one mediocre food tile. With 4-food center: +/// pop 2 breakeven → +1.0 surplus; pop 3 deficit of −0.5 covered by any +/// 1-food tile; pop 4 needs two food tiles (still achievable). +pub const FOOD_PER_POP: f64 = 1.5; /// Base city HP before population scaling. pub const BASE_CITY_HP: u32 = 200; @@ -658,9 +662,9 @@ mod tests { let mut city = City::found("Ironhold", (5, 5), true, 1); city.population = 1; // With no tile yields, city center gives 4 food. - // Surplus = 4.0 - 2.0*1 = 2.0 + // Surplus = 4.0 - 1.5*1 = 2.5 let surplus = city.get_food_surplus(&[]); - assert!((surplus - 2.0).abs() < f64::EPSILON); + assert!((surplus - 2.5).abs() < f64::EPSILON); } #[test] @@ -673,18 +677,15 @@ mod tests { let ty = vec![ TileYield { coord: (6, 5), food: 5.0, ..TileYield::default() }, ]; - // Surplus per turn: (4 + 5) - 2*1 = 7.0 + // Surplus per turn: (4 + 5) - 1.5*1 = 7.5 // Threshold at pop 1: 15.0 - // Turn 1: food_stored = 7 + // Turn 1: food_stored = 7.5 assert_eq!(city.process_growth(&ty), 0); - assert_eq!(city.food_stored, 7.0); - // Turn 2: food_stored = 14 - assert_eq!(city.process_growth(&ty), 0); - assert_eq!(city.food_stored, 14.0); - // Turn 3: food_stored = 21 >= 15 → grow, carry 6.0 + assert_eq!(city.food_stored, 7.5); + // Turn 2: food_stored = 15.0 >= 15 → grow, carry 0 assert_eq!(city.process_growth(&ty), 1); assert_eq!(city.population, 2); - assert_eq!(city.food_stored, 6.0); // 21 - 15 = 6 + assert_eq!(city.food_stored, 0.0); // 15 - 15 = 0 } #[test] @@ -692,8 +693,8 @@ mod tests { let mut city = City::found("Ironhold", (5, 5), true, 1); city.population = 3; // No worked tiles beyond center → yields = 4 food - // Consumption = 2*3 = 6. Surplus = 4 - 6 = -2 - // food_stored starts at 0, then 0 + (-3) = -3 < 0, pop > 1 → starve + // Consumption = 1.5*3 = 4.5. Surplus = 4 - 4.5 = -0.5 + // food_stored: 0 + (-0.5) = -0.5 < 0, pop > 1 → starve let ty: Vec = vec![]; assert_eq!(city.process_growth(&ty), -1); assert_eq!(city.population, 2);