fix(game): restore effect-seven multiball

Arm effect 7 after the wheel-reset target, select it on the next effect line,
and spawn a second visible live ball when record 149 is consumed. Advance the
second ball through recovered line, circle, ball-ball, magnetic, and scoring
collisions independently.

During multiball, draining one ball leaves the other active without consuming a
remaining player ball. Include secondary state in deterministic traces and
finite-state validation.

Test Plan:
- `cargo test --all-targets` -- 52 passed
- `cargo clippy --all-targets -- -D warnings` -- passed
- production build plus Windows GNU and macOS checks -- passed
- effect-seven spawn, movement, and single-drain lifecycle test -- passed
- `git diff --cached --check` -- passed
This commit is contained in:
2026-08-22 22:02:50 +02:00
parent 25e32b2c06
commit f2560ee2f7
5 changed files with 190 additions and 6 deletions
+14
View File
@@ -152,6 +152,7 @@ pub struct Snapshot {
pub step: u64,
pub seconds: f64,
pub ball: BallSnapshot,
pub secondary_ball: Option<BallSnapshot>,
pub claw: ClawSnapshot,
pub flippers: FlipperSnapshot,
pub launcher_charge: f32,
@@ -254,6 +255,13 @@ impl Simulation {
velocity_y: self.game.ball.velocity.y,
in_launcher: self.game.ball.in_launcher,
},
secondary_ball: self.game.secondary_ball.map(|ball| BallSnapshot {
x: ball.position.x,
y: ball.position.y,
velocity_x: ball.velocity.x,
velocity_y: ball.velocity.y,
in_launcher: ball.in_launcher,
}),
claw: ClawSnapshot {
active: self.game.claw.active,
frame: self.game.claw.frame,
@@ -389,6 +397,12 @@ mod tests {
&& snapshot.ball.y.is_finite()
&& snapshot.ball.velocity_x.is_finite()
&& snapshot.ball.velocity_y.is_finite()
&& snapshot.secondary_ball.as_ref().is_none_or(|ball| {
ball.x.is_finite()
&& ball.y.is_finite()
&& ball.velocity_x.is_finite()
&& ball.velocity_y.is_finite()
})
}));
}