fix(multiball): defer fifth-lock panel for survivor
The fifth type-three lock always pays and transfers its accumulated award, but the original starts the DAT600 panel only when no multiball is active. Rust started the panel unconditionally and suspended the surviving ball. A later capture with all five contacts already set could also shift the award to 320,000 instead of retaining the binary's 160,000 cap. Derive each lock award from the post-capture filled count capped at five. Keep the transfer, multiplier increment, and extra ball during multiball, but defer the panel until a single-ball completion. Cover the fifth multiball capture and its survivor recapture end to end. Test Plan: - `cargo test --workspace --all-targets --all-features` -- 120 passed - `cargo clippy --workspace --all-targets --all-features -- -D warnings` -- passed - `rumdl check --flavor commonmark RECONSTRUCTION.md CHANGELOG.md` -- passed - `git diff --cached --check` -- passed
This commit is contained in:
+60
-20
@@ -1683,30 +1683,42 @@ impl Game {
|
||||
CaptureStep::Outside | CaptureStep::Holding => continue,
|
||||
CaptureStep::Complete => {}
|
||||
}
|
||||
let filled_before = self.wheel_holes.iter().filter(|filled| **filled).count();
|
||||
self.wheel_holes[index] = true;
|
||||
let award = 10_000_u32 << u32::try_from(filled_before).unwrap_or_default();
|
||||
let player = &mut self.players[self.current_player];
|
||||
player.secondary_score = player.secondary_score.wrapping_add(award);
|
||||
if self.wheel_holes.iter().all(|filled| *filled) {
|
||||
let transfer = self.secondary_score_display();
|
||||
self.add_score(transfer, events);
|
||||
let player = &mut self.players[self.current_player];
|
||||
player.secondary_score = 0;
|
||||
player.score_multiplier = player.score_multiplier.wrapping_add(1);
|
||||
player.extra_balls = player.extra_balls.wrapping_add(1);
|
||||
self.panel_frame = Some(0);
|
||||
}
|
||||
events.push(Event::Lock);
|
||||
return Some(if ball_count == 1 {
|
||||
BallAction::Reset
|
||||
} else {
|
||||
BallAction::Remove
|
||||
});
|
||||
return Some(self.complete_lock_hole(index, ball_count, events));
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn complete_lock_hole(
|
||||
&mut self,
|
||||
index: usize,
|
||||
ball_count: u16,
|
||||
events: &mut Vec<Event>,
|
||||
) -> BallAction {
|
||||
self.wheel_holes[index] = true;
|
||||
let filled = self.wheel_holes.iter().filter(|filled| **filled).count();
|
||||
let shift = u32::try_from(filled.min(5)).unwrap_or(5);
|
||||
let award = 5_000_u32 << shift;
|
||||
let player = &mut self.players[self.current_player];
|
||||
player.secondary_score = player.secondary_score.wrapping_add(award);
|
||||
if filled == 5 {
|
||||
let transfer = self.secondary_score_display();
|
||||
self.add_score(transfer, events);
|
||||
let player = &mut self.players[self.current_player];
|
||||
player.secondary_score = 0;
|
||||
player.score_multiplier = player.score_multiplier.wrapping_add(1);
|
||||
player.extra_balls = player.extra_balls.wrapping_add(1);
|
||||
if ball_count == 1 {
|
||||
self.panel_frame = Some(0);
|
||||
}
|
||||
}
|
||||
events.push(Event::Lock);
|
||||
if ball_count == 1 {
|
||||
BallAction::Reset
|
||||
} else {
|
||||
BallAction::Remove
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn check_wheel_reset(
|
||||
&mut self,
|
||||
@@ -3903,6 +3915,34 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fifth_multiball_lock_defers_panel_and_caps_survivor_reaward() {
|
||||
let mut game = Game::new(1);
|
||||
game.wheel_holes = [true, true, true, true, false];
|
||||
game.players[0].secondary_score = 150_000;
|
||||
game.score_mode = ScoreMode::Multiball;
|
||||
let mut events = Vec::new();
|
||||
|
||||
assert_eq!(
|
||||
game.complete_lock_hole(4, 2, &mut events),
|
||||
BallAction::Remove
|
||||
);
|
||||
assert_eq!(game.player().score, 620_000);
|
||||
assert_eq!(game.player().secondary_score, 0);
|
||||
assert_eq!(game.player().score_multiplier, 2);
|
||||
assert_eq!(game.panel_frame, None);
|
||||
|
||||
game.score_mode = ScoreMode::Normal;
|
||||
assert_eq!(
|
||||
game.complete_lock_hole(4, 1, &mut events),
|
||||
BallAction::Reset
|
||||
);
|
||||
assert_eq!(game.player().score, 940_000);
|
||||
assert_eq!(game.player().secondary_score, 0);
|
||||
assert_eq!(game.player().score_multiplier, 3);
|
||||
assert_eq!(game.panel_frame, Some(0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn type_three_capture_pulls_holds_and_publishes_contact_sentinels() {
|
||||
let sensor = LOCK_HOLES[0];
|
||||
|
||||
Reference in New Issue
Block a user