From bcb464f1d4e4b4560c262d2d4d619b46033d0739 Mon Sep 17 00:00:00 2001 From: autocommit Date: Thu, 30 Apr 2026 00:14:46 -0700 Subject: [PATCH] =?UTF-8?q?feat(city):=20=E2=9C=A8=20Implement=20bridge=20?= =?UTF-8?q?occupation=20multiplier=20and=20capture=20marking=20in=20City?= =?UTF-8?q?=20struct?= 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 | 25 ++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/simulator/crates/mc-city/src/city.rs b/src/simulator/crates/mc-city/src/city.rs index 168d00a7..e9df2071 100644 --- a/src/simulator/crates/mc-city/src/city.rs +++ b/src/simulator/crates/mc-city/src/city.rs @@ -276,6 +276,11 @@ pub struct City { /// a city under sustained siege cannot out-regen incoming damage. #[serde(default)] pub last_attacked_turn: Option, + + /// Turn this city was most recently captured. `None` = never captured. + /// Used to apply an occupation production penalty for OCCUPATION_TURNS after capture. + #[serde(default)] + pub captured_turn: Option, } impl Default for City { @@ -300,6 +305,7 @@ impl Default for City { queues: HashMap::new(), building_yields: HashMap::new(), last_attacked_turn: None, + captured_turn: None, } } } @@ -361,6 +367,7 @@ impl City { queues: HashMap::new(), building_yields: HashMap::new(), last_attacked_turn: None, + captured_turn: None, } } @@ -664,6 +671,24 @@ impl City { self.hp == 0 } + /// Record that this city was captured on `turn`. + /// Enables `occupation_production_mult` to apply the penalty. + pub fn mark_captured(&mut self, turn: u32) { + self.captured_turn = Some(turn); + } + + /// Returns the production multiplier for `current_turn`. + /// Captured cities produce at 50% for `OCCUPATION_TURNS` turns + /// after capture to slow the attacker's production snowball. + pub fn occupation_production_mult(&self, current_turn: u32) -> f64 { + const OCCUPATION_TURNS: u32 = 5; + const OCCUPATION_PENALTY: f64 = 0.5; + match self.captured_turn { + Some(ct) if current_turn.saturating_sub(ct) < OCCUPATION_TURNS => OCCUPATION_PENALTY, + _ => 1.0, + } + } + // ── Production queue (carried from production.rs, unchanged) ── /// Validate, charge, and enqueue an item into its producer building's queue.