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.