From 95760b9940b6462c80ed4e146bf6f1a55d959add Mon Sep 17 00:00:00 2001 From: ddidderr Date: Sat, 22 Aug 2026 18:24:29 +0200 Subject: [PATCH] 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 --- tdkpin-rs/README.md | 4 ++-- tdkpin-rs/src/app.rs | 33 ++++++++++++++++----------------- tdkpin-rs/src/game.rs | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+), 19 deletions(-) diff --git a/tdkpin-rs/README.md b/tdkpin-rs/README.md index c7ced5d..c254c98 100644 --- a/tdkpin-rs/README.md +++ b/tdkpin-rs/README.md @@ -35,8 +35,8 @@ command-line tools. | Action | Original key | Additional modern key | | --- | --- | --- | -| Choose 1-4 players | `+` | `=` | -| Start game / charge launcher | Hold Down arrow, release to launch | Enter starts a game | +| Start game / add up to 4 players | `+` | `=` or Enter starts one player | +| Charge launcher | Hold Down arrow, release to launch | - | | Left flipper | Left Ctrl | `A` or Left arrow | | Right flipper | Keypad Enter | Right Ctrl, `D`, or Right arrow | | Nudge | Space, either Shift, keypad `3` | - | diff --git a/tdkpin-rs/src/app.rs b/tdkpin-rs/src/app.rs index 846fc58..e9520f7 100644 --- a/tdkpin-rs/src/app.rs +++ b/tdkpin-rs/src/app.rs @@ -28,7 +28,6 @@ pub struct App { screen: Screen, return_screen: Screen, game: Option, - player_count: usize, setting_row: usize, loading_until: f64, last_help_click: f64, @@ -53,7 +52,6 @@ impl App { screen: Screen::Loading, return_screen: Screen::Attract, game: None, - player_count: 1, setting_row: 0, loading_until: get_time() + 1.1, last_help_click: -1.0, @@ -131,18 +129,25 @@ impl App { } fn update_attract(&mut self) { - if is_key_pressed(KeyCode::KpAdd) || is_key_pressed(KeyCode::Equal) { - self.player_count = self.player_count % 4 + 1; - self.assets.play(2012, self.saved.settings.sounds); - } - if is_key_pressed(KeyCode::Down) || is_key_pressed(KeyCode::Enter) { - self.game = Some(Game::new(self.player_count)); + if is_key_pressed(KeyCode::KpAdd) + || is_key_pressed(KeyCode::Equal) + || is_key_pressed(KeyCode::Enter) + { + self.game = Some(Game::new(1)); self.screen = Screen::Playing; self.assets.play(2008, self.saved.settings.sounds); } } 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) || is_key_down(KeyCode::A) || is_key_down(KeyCode::Left); @@ -350,20 +355,14 @@ impl App { 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( - "PRESS DOWN ARROW", + "PRESS + TO START", 475.5, 139.0, 22, Color::from_rgba(0, 72, 102, 255), ); - draw_centered_at("TO START BALL", 475.5, 165.0, 18, BLACK); - draw_centered_at( - &format!("PLAYERS: {} [+] CHANGE", self.player_count), - 475.5, - 196.0, - 16, - BLACK, - ); + draw_centered_at("PRESS + AGAIN TO ADD PLAYERS", 475.5, 165.0, 15, BLACK); + draw_centered_at("THEN HOLD DOWN TO LAUNCH", 475.5, 196.0, 16, BLACK); draw_text( "F1 HELP F2 SETTINGS F3 HIGHSCORES F12 SOUND", 322.0, diff --git a/tdkpin-rs/src/game.rs b/tdkpin-rs/src/game.rs index fd62fcf..5487cdf 100644 --- a/tdkpin-rs/src/game.rs +++ b/tdkpin-rs/src/game.rs @@ -92,6 +92,12 @@ pub struct Ball { pub in_launcher: bool, } +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +enum PlayerEntry { + Open, + Closed, +} + impl Default for Ball { fn default() -> Self { Self { @@ -128,6 +134,7 @@ pub struct Game { nudge_meter: f32, stalled_for: f32, launcher_was_down: bool, + player_entry: PlayerEntry, } impl Game { @@ -157,6 +164,7 @@ impl Game { nudge_meter: 0.0, stalled_for: 0.0, launcher_was_down: false, + player_entry: PlayerEntry::Open, } } @@ -168,12 +176,21 @@ impl Game { 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) { let launch_speed = LAUNCH_SPEED_MIN + self.launcher_charge * LAUNCH_SPEED_RANGE; self.ball.in_launcher = false; self.ball.velocity = vec2(0.0, -launch_speed); self.launcher_charge = 0.0; self.launcher_was_down = false; + self.player_entry = PlayerEntry::Closed; self.stalled_for = 0.0; } @@ -626,6 +643,22 @@ mod tests { 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] fn ball_starts_in_the_recovered_shooter_lane() { let game = Game::new(1);