From 39aa1f25e26f1a1f7dfc2eb119cf224c2543fa60 Mon Sep 17 00:00:00 2001 From: autocommit Date: Tue, 19 May 2026 21:24:52 -0700 Subject: [PATCH] =?UTF-8?q?feat(mc-turn):=20=E2=9C=A8=20Update=20turn-base?= =?UTF-8?q?d=20event=20processing=20logic=20and=20adjust=20test=20wiring?= =?UTF-8?q?=20for=20event=20collection?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Lilith Autocommit --- src/simulator/crates/mc-turn/src/processor.rs | 32 ++++++++++++++++++- .../mc-turn/tests/event_collector_wiring.rs | 7 ++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/src/simulator/crates/mc-turn/src/processor.rs b/src/simulator/crates/mc-turn/src/processor.rs index 9384eedf..377abef9 100644 --- a/src/simulator/crates/mc-turn/src/processor.rs +++ b/src/simulator/crates/mc-turn/src/processor.rs @@ -3459,9 +3459,39 @@ impl TurnProcessor { // last city is captured. Matches the // `eliminated_player_skipped_in_domination` test's manual // setup at `victory.rs:798` (`p1.capital_position = None`). - if defender.capital_position == Some(pos) { + // + // Communications Phase 6 wiring: when the defender's + // capital is lost (and they still have surviving cities), + // begin a comms blackout. Drops in-flight outbound + // envelopes, penalises comm-tier, accelerates last-seen + // decay. Emits `CapitalBlackoutBegan` for the replay + // viewer; the next-turn handler enforces the 1-turn UX + // gate per `project_capital_blackout_design.md`. + let lost_capital = defender.capital_position == Some(pos); + if lost_capital { defender.capital_position = None; } + let defender_cities_remaining = !defender.cities.is_empty(); + // End the &mut state.players[defender_pi] borrow before + // touching state.comms (also a child of state). + let _ = defender; + if lost_capital && defender_cities_remaining { + let turn_now = state.turn; + mc_comms::blackout::begin_blackout( + &mut state.comms, + defender_pi as u8, + turn_now, + ); + result.events_emitted.push( + mc_replay::TurnEvent::CapitalBlackoutBegan { + turn: turn_now, + player: mc_replay::ClanId(defender_pi as u32), + lost_capital_hex: mc_replay::TileCoord::new( + pos.0, pos.1, + ), + }, + ); + } // Transfer to attacker. let attacker = &mut state.players[attacker_pi]; diff --git a/src/simulator/crates/mc-turn/tests/event_collector_wiring.rs b/src/simulator/crates/mc-turn/tests/event_collector_wiring.rs index c8e424c0..1446d661 100644 --- a/src/simulator/crates/mc-turn/tests/event_collector_wiring.rs +++ b/src/simulator/crates/mc-turn/tests/event_collector_wiring.rs @@ -232,6 +232,13 @@ fn ten_turn_run_emits_each_wired_variant() { TurnEvent::HeartbeatMissed { .. } => "HeartbeatMissed", TurnEvent::VisionShareCollapsed { .. } => "VisionShareCollapsed", TurnEvent::VisionShareRestored { .. } => "VisionShareRestored", + // Communications Phase 6 (envelope-flow + link-flow) — labelled + // for exhaustiveness; the 10-turn fixture does not exercise them. + TurnEvent::EnvelopeDispatched { .. } => "EnvelopeDispatched", + TurnEvent::EnvelopeDelivered { .. } => "EnvelopeDelivered", + TurnEvent::EnvelopeIntercepted { .. } => "EnvelopeIntercepted", + TurnEvent::LinkSevered { .. } => "LinkSevered", + TurnEvent::LinkRestored { .. } => "LinkRestored", }) .collect();