fix(input): start games with the plus key

Match the recovered Win16 registration flow: the first plus press creates Player 1 and additional presses add Players 2 through 4 until the initial launch. Down now belongs only to charging and releasing the plunger.

Test Plan:
- cargo fmt --check
- cargo test
- cargo clippy --all-targets --all-features -- -D warnings
- live: verify Down cannot leave attract mode
- live: start with plus, add Player 2, hold Down through partial/full plunger frames, and release onto the table
- git diff --check
This commit is contained in:
2026-08-22 18:24:29 +02:00
parent 8d76e9539f
commit 95760b9940
3 changed files with 51 additions and 19 deletions
+2 -2
View File
@@ -35,8 +35,8 @@ command-line tools.
| Action | Original key | Additional modern key | | Action | Original key | Additional modern key |
| --- | --- | --- | | --- | --- | --- |
| Choose 1-4 players | `+` | `=` | | Start game / add up to 4 players | `+` | `=` or Enter starts one player |
| Start game / charge launcher | Hold Down arrow, release to launch | Enter starts a game | | Charge launcher | Hold Down arrow, release to launch | - |
| Left flipper | Left Ctrl | `A` or Left arrow | | Left flipper | Left Ctrl | `A` or Left arrow |
| Right flipper | Keypad Enter | Right Ctrl, `D`, or Right arrow | | Right flipper | Keypad Enter | Right Ctrl, `D`, or Right arrow |
| Nudge | Space, either Shift, keypad `3` | - | | Nudge | Space, either Shift, keypad `3` | - |
+16 -17
View File
@@ -28,7 +28,6 @@ pub struct App {
screen: Screen, screen: Screen,
return_screen: Screen, return_screen: Screen,
game: Option<Game>, game: Option<Game>,
player_count: usize,
setting_row: usize, setting_row: usize,
loading_until: f64, loading_until: f64,
last_help_click: f64, last_help_click: f64,
@@ -53,7 +52,6 @@ impl App {
screen: Screen::Loading, screen: Screen::Loading,
return_screen: Screen::Attract, return_screen: Screen::Attract,
game: None, game: None,
player_count: 1,
setting_row: 0, setting_row: 0,
loading_until: get_time() + 1.1, loading_until: get_time() + 1.1,
last_help_click: -1.0, last_help_click: -1.0,
@@ -131,18 +129,25 @@ impl App {
} }
fn update_attract(&mut self) { fn update_attract(&mut self) {
if is_key_pressed(KeyCode::KpAdd) || is_key_pressed(KeyCode::Equal) { if is_key_pressed(KeyCode::KpAdd)
self.player_count = self.player_count % 4 + 1; || is_key_pressed(KeyCode::Equal)
self.assets.play(2012, self.saved.settings.sounds); || is_key_pressed(KeyCode::Enter)
} {
if is_key_pressed(KeyCode::Down) || is_key_pressed(KeyCode::Enter) { self.game = Some(Game::new(1));
self.game = Some(Game::new(self.player_count));
self.screen = Screen::Playing; self.screen = Screen::Playing;
self.assets.play(2008, self.saved.settings.sounds); self.assets.play(2008, self.saved.settings.sounds);
} }
} }
fn update_game(&mut self) { fn update_game(&mut self) {
if (is_key_pressed(KeyCode::KpAdd) || is_key_pressed(KeyCode::Equal))
&& self
.game
.as_mut()
.is_some_and(Game::add_player_before_launch)
{
self.assets.play(2012, self.saved.settings.sounds);
}
let left_flipper = is_key_down(KeyCode::LeftControl) let left_flipper = is_key_down(KeyCode::LeftControl)
|| is_key_down(KeyCode::A) || is_key_down(KeyCode::A)
|| is_key_down(KeyCode::Left); || is_key_down(KeyCode::Left);
@@ -350,20 +355,14 @@ impl App {
draw_panel(342.0, 72.0, 267.0, 144.0); draw_panel(342.0, 72.0, 267.0, 144.0);
draw_centered_at("TDK PINBALL MACHINE", 475.5, 107.0, 22, BLACK); draw_centered_at("TDK PINBALL MACHINE", 475.5, 107.0, 22, BLACK);
draw_centered_at( draw_centered_at(
"PRESS DOWN ARROW", "PRESS + TO START",
475.5, 475.5,
139.0, 139.0,
22, 22,
Color::from_rgba(0, 72, 102, 255), Color::from_rgba(0, 72, 102, 255),
); );
draw_centered_at("TO START BALL", 475.5, 165.0, 18, BLACK); draw_centered_at("PRESS + AGAIN TO ADD PLAYERS", 475.5, 165.0, 15, BLACK);
draw_centered_at( draw_centered_at("THEN HOLD DOWN TO LAUNCH", 475.5, 196.0, 16, BLACK);
&format!("PLAYERS: {} [+] CHANGE", self.player_count),
475.5,
196.0,
16,
BLACK,
);
draw_text( draw_text(
"F1 HELP F2 SETTINGS F3 HIGHSCORES F12 SOUND", "F1 HELP F2 SETTINGS F3 HIGHSCORES F12 SOUND",
322.0, 322.0,
+33
View File
@@ -92,6 +92,12 @@ pub struct Ball {
pub in_launcher: bool, pub in_launcher: bool,
} }
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
enum PlayerEntry {
Open,
Closed,
}
impl Default for Ball { impl Default for Ball {
fn default() -> Self { fn default() -> Self {
Self { Self {
@@ -128,6 +134,7 @@ pub struct Game {
nudge_meter: f32, nudge_meter: f32,
stalled_for: f32, stalled_for: f32,
launcher_was_down: bool, launcher_was_down: bool,
player_entry: PlayerEntry,
} }
impl Game { impl Game {
@@ -157,6 +164,7 @@ impl Game {
nudge_meter: 0.0, nudge_meter: 0.0,
stalled_for: 0.0, stalled_for: 0.0,
launcher_was_down: false, launcher_was_down: false,
player_entry: PlayerEntry::Open,
} }
} }
@@ -168,12 +176,21 @@ impl Game {
LAUNCHER_FRAME_THRESHOLDS.partition_point(|threshold| self.launcher_charge >= *threshold) LAUNCHER_FRAME_THRESHOLDS.partition_point(|threshold| self.launcher_charge >= *threshold)
} }
pub fn add_player_before_launch(&mut self) -> bool {
if self.player_entry == PlayerEntry::Closed || self.players.len() >= 4 {
return false;
}
self.players.push(Player::default());
true
}
fn fire_launcher(&mut self) { fn fire_launcher(&mut self) {
let launch_speed = LAUNCH_SPEED_MIN + self.launcher_charge * LAUNCH_SPEED_RANGE; let launch_speed = LAUNCH_SPEED_MIN + self.launcher_charge * LAUNCH_SPEED_RANGE;
self.ball.in_launcher = false; self.ball.in_launcher = false;
self.ball.velocity = vec2(0.0, -launch_speed); self.ball.velocity = vec2(0.0, -launch_speed);
self.launcher_charge = 0.0; self.launcher_charge = 0.0;
self.launcher_was_down = false; self.launcher_was_down = false;
self.player_entry = PlayerEntry::Closed;
self.stalled_for = 0.0; self.stalled_for = 0.0;
} }
@@ -626,6 +643,22 @@ mod tests {
assert_eq!(Game::new(99).players.len(), 4); assert_eq!(Game::new(99).players.len(), 4);
} }
#[test]
fn plus_adds_players_only_before_the_first_launch() {
let mut game = Game::new(1);
assert!(game.add_player_before_launch());
assert!(game.add_player_before_launch());
assert!(game.add_player_before_launch());
assert!(!game.add_player_before_launch());
assert_eq!(game.players.len(), 4);
let mut game = Game::new(1);
launch_ball(&mut game, 1);
assert!(!game.add_player_before_launch());
assert_eq!(game.players.len(), 1);
}
#[test] #[test]
fn ball_starts_in_the_recovered_shooter_lane() { fn ball_starts_in_the_recovered_shooter_lane() {
let game = Game::new(1); let game = Game::new(1);