test(@projects/@magic-civilization): 🐛 update siege capture tests for HP-gated process_siege

process_siege was changed from "≥3 attackers within 2 hexes = instant capture" to
HP-gated siege: 15 dmg/attacker/turn against the city's persistent hp, capture at
hp<=0. A starter city has 510 hp, so 3 attackers (45/turn) capture neither in one
step (last_survivor) nor in 10 turns (event_collector). Drop each defender city's
hp below the single-turn 3-attacker total (45) so the capture fires as the tests
intend, and refresh the stale "nearby_attackers >= 3" doc comments.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Natalie 2026-06-24 20:24:02 -04:00
parent f293c31d07
commit 1bd1a29d9a
2 changed files with 16 additions and 9 deletions

View file

@ -94,8 +94,11 @@ fn fixture_state() -> GameState {
p0_city0.queue_tier = Some(1);
p0_city0.production_stored = 5_000;
// Stand 3 player-0 units on player-1's only city tile so the siege
// capture trigger (`nearby_attackers >= 3`) fires immediately.
// Stand 3 player-0 units on player-1's only city tile so the per-unit
// HP-gated siege in `process_siege` captures it. A starter city has 510 hp
// and siege deals 15/attacker/turn; drop the defender city below the
// single-turn 3-attacker total (45) so CityCaptured fires on turn 1.
state.players[1].cities[0].hp = 30;
let p1_city_pos = state.players[1].city_positions[0];
for i in 0..3 {
state.players[0].units.push(MapUnit {

View file

@ -8,9 +8,9 @@
//! && `cities.is_empty()`) stayed false forever and domination /
//! last-survivor never fired even after total annihilation.
//!
//! This test exercises the actual capture pipeline (3 attacker units
//! within 2 hexes of the defender's only city → `nearby_attackers >= 3`
//! → `process_siege` swap-removes the city), then asserts both:
//! This test exercises the actual capture pipeline (3 attacker units on the
//! defender's only city tile → the per-unit HP-gated siege in `process_siege`
//! drives the city's hp to 0 → the city is swap-removed), then asserts both:
//! • `defender.capital_position == None` after capture
//! • `TurnEvent::GameOver { reason_kind: "last_survivor", winner: 0 }`
//! emitted.
@ -78,11 +78,15 @@ fn capturing_last_city_clears_capital_and_emits_last_survivor() {
let p1_pos = (8, 0);
let mut p0 = player_with_city_at(0, p0_pos);
let p1 = player_with_city_at(1, p1_pos);
let mut p1 = player_with_city_at(1, p1_pos);
// HP-gated siege deals 15 dmg per attacker per turn (`process_siege`); a
// starter city has 510 hp. Drop the defender's lone city below the
// single-turn 3-attacker siege total (3 × 15 = 45) so the capture completes
// on the first step, as this Bug-5 regression requires.
p1.cities[0].hp = 30;
// Stack 3 p0 units on p1's only city → siege capture trigger fires
// (matches the `nearby_attackers >= 3` predicate in
// `processor::process_siege`).
// Stack 3 p0 units on p1's only city tile → the per-unit siege loop in
// `processor::process_siege` drives the city's hp to 0 and captures it.
for i in 0..3 {
p0.units.push(MapUnit {
id: 100 + i,