From aeae63aabe54622c345a1813afca00ee7f66ea09 Mon Sep 17 00:00:00 2001 From: ddidderr Date: Sat, 22 Aug 2026 18:07:12 +0200 Subject: [PATCH] fix(render): restore original game presentation Compose the running table from the recovered resting bitmap and exact active UI regions. Remove the procedural replacements that distorted lamps, flippers, player rows, and display values, and place the plunger strip at its recovered destination. Test Plan: - cargo fmt --check - cargo test - cargo clippy --all-targets --all-features -- -D warnings - launch the game and compare the initial frame and charged plunger visually --- tdkpin-rs/src/app.rs | 213 ++++++++++++++---------------------------- tdkpin-rs/src/game.rs | 7 -- 2 files changed, 70 insertions(+), 150 deletions(-) diff --git a/tdkpin-rs/src/app.rs b/tdkpin-rs/src/app.rs index 8a6fbbf..dd76719 100644 --- a/tdkpin-rs/src/app.rs +++ b/tdkpin-rs/src/app.rs @@ -375,6 +375,8 @@ impl App { #[allow(clippy::cast_precision_loss, clippy::too_many_lines)] fn draw_game(&self) { + // Resource 998 is the original game's resting playfield. Resource 997 + // contains exact lit-state patches used below for the active displays. draw_texture(&self.assets.inactive_table, 0.0, 0.0, WHITE); let Some(game) = &self.game else { return; @@ -409,53 +411,6 @@ impl App { ); } - for (index, center) in [vec2(205.0, 47.0), vec2(234.0, 50.0), vec2(262.0, 53.0)] - .into_iter() - .enumerate() - { - if game.top_targets[index] { - draw_line( - center.x - 7.0, - center.y + 9.0, - center.x + 5.0, - center.y - 10.0, - 7.0, - YELLOW, - ); - } - } - let side_colors = [RED, ORANGE, YELLOW, GREEN, SKYBLUE]; - for (index, y) in [180.0, 195.0, 210.0, 225.0, 240.0].into_iter().enumerate() { - let color = if game.side_targets[index] { - side_colors[index] - } else { - Color::from_rgba(38, 38, 38, 255) - }; - draw_circle(286.0, y, 5.0, color); - } - for (index, lit) in game.wheel_holes.iter().enumerate() { - if *lit { - let angle = index as f32 / 8.0 * std::f32::consts::TAU; - draw_circle( - 114.0 + angle.cos() * 29.0, - 79.0 + angle.sin() * 29.0, - 6.0, - YELLOW, - ); - } - } - for index in 0..4 { - draw_circle( - 155.0 + index as f32 * 14.0, - 214.0, - 5.0, - if index < usize::from(game.lock_lights) { - WHITE - } else { - DARKGRAY - }, - ); - } for (index, bumper) in BUMPERS.into_iter().enumerate() { if game.bumper_flash[index] > 0.0 { draw_circle_lines(bumper.center.x, bumper.center.y, 17.0, 3.0, WHITE); @@ -488,7 +443,7 @@ impl App { draw_texture_ex( &self.assets.plunger, 314.0, - 406.0, + 426.0, WHITE, DrawTextureParams { dest_size: Some(vec2(21.0, 18.0)), @@ -497,43 +452,6 @@ impl App { }, ); } - - for (start, end) in [ - (vec2(103.0, 397.0), vec2(58.0, 374.0)), - (vec2(210.0, 397.0), vec2(256.0, 374.0)), - ] { - draw_line(start.x, start.y, end.x, end.y, 22.0, BLACK); - draw_circle(start.x, start.y, 11.0, BLACK); - } - let (left, right) = game.flippers(); - for flipper in [left, right] { - draw_line( - flipper.start.x, - flipper.start.y, - flipper.end.x, - flipper.end.y, - 18.0, - Color::from_rgba(32, 32, 32, 255), - ); - draw_line( - flipper.start.x, - flipper.start.y - 1.0, - flipper.end.x, - flipper.end.y - 1.0, - 12.0, - LIGHTGRAY, - ); - draw_line( - flipper.start.x, - flipper.start.y - 3.0, - flipper.end.x, - flipper.end.y - 3.0, - 3.0, - WHITE, - ); - draw_circle(flipper.start.x, flipper.start.y, 9.0, DARKGRAY); - draw_circle(flipper.start.x, flipper.start.y - 1.0, 6.0, GRAY); - } draw_texture( &self.assets.ball, game.ball.position.x - 8.0, @@ -555,80 +473,89 @@ impl App { }, ); } - draw_rectangle( - 340.0, - 444.0, - 292.0, - 14.0, - Color::from_rgba(214, 214, 214, 235), - ); - draw_text("F1 HELP F2 SETUP", 347.0, 455.0, 10.0, BLACK); } #[allow(clippy::cast_precision_loss)] fn draw_displays(&self, game: &Game) { - draw_texture_ex( - &self.assets.active_table, - 371.0, - 233.0, - WHITE, - DrawTextureParams { - dest_size: Some(vec2(244.0, 34.0)), - source: Some(Rect::new(371.0, 233.0, 244.0, 34.0)), - ..Default::default() - }, - ); - self.draw_digits( - &format!("{:07}", game.bonus), - vec2(458.0, 240.0), - vec2(10.0, 18.0), - ); + for region in [ + Rect::new(383.0, 72.0, 140.0, 136.0), + Rect::new(545.0, 170.0, 9.0, 9.0), + Rect::new(372.0, 233.0, 238.0, 29.0), + ] { + draw_texture_ex( + &self.assets.active_table, + region.x, + region.y, + WHITE, + DrawTextureParams { + dest_size: Some(vec2(region.w, region.h)), + source: Some(region), + ..Default::default() + }, + ); + } + self.draw_right_aligned_digits(&game.bonus.to_string(), 610.0, 240.0); let media_level = game.player().media_level; if media_level > 0 { let index = usize::from(media_level.saturating_sub(1).min(3)); draw_texture(&self.assets.media[index], 380.0, 72.0, WHITE); } - draw_text( - format!("{:07} KBytes", game.player().score / 1_000), - 395.0, - 205.0, - 14.0, - WHITE, - ); + + let row_y = 277.0 + game.current_player as f32 * 44.0; + for region in [ + Rect::new(373.0, row_y + 4.0, 9.0, 9.0), + Rect::new(473.0, row_y, 137.0, 29.0), + ] { + draw_texture_ex( + &self.assets.active_table, + region.x, + region.y, + WHITE, + DrawTextureParams { + dest_size: Some(vec2(region.w, region.h)), + source: Some(region), + ..Default::default() + }, + ); + } + let displayed_balls = game + .player() + .balls + .saturating_sub(1) + .saturating_add(game.player().extra_balls) + .min(6); + for ball in 0..displayed_balls { + let x = 392.0 + f32::from(ball) * 8.0; + draw_texture_ex( + &self.assets.active_table, + x, + row_y + 22.0, + WHITE, + DrawTextureParams { + dest_size: Some(vec2(3.0, 3.0)), + source: Some(Rect::new(x, row_y + 22.0, 3.0, 3.0)), + ..Default::default() + }, + ); + } for (index, player) in game.players.iter().enumerate() { - let y = 274.0 + index as f32 * 44.0; - if index == game.current_player { - draw_texture_ex( - &self.assets.active_table, - 472.0, - y, - WHITE, - DrawTextureParams { - dest_size: Some(vec2(143.0, 30.0)), - source: Some(Rect::new(472.0, y, 143.0, 30.0)), - ..Default::default() - }, - ); - } - self.draw_digits( - &format!("{:09}", player.score), - vec2(480.0, y + 6.0), - vec2(10.0, 18.0), + self.draw_right_aligned_digits( + &player.score.to_string(), + 610.0, + 280.0 + index as f32 * 44.0, ); - for ball in 0..6 { - let lit = ball < usize::from(player.balls + player.extra_balls); - draw_circle( - 397.0 + ball as f32 * 8.0, - y + 27.0, - 2.4, - if lit { GREEN } else { DARKGRAY }, - ); - } } } + fn draw_right_aligned_digits(&self, digits: &str, right: f32, y: f32) { + let digit_count = u16::try_from(digits.bytes().filter(u8::is_ascii_digit).count()) + .expect("a display value has at most ten digits"); + let width = f32::from(digit_count) * 10.0; + self.draw_digits(digits, vec2(right - width, y), vec2(10.0, 18.0)); + } + fn draw_digits(&self, digits: &str, position: Vec2, digit_size: Vec2) { let mut x = position.x; for digit in digits.bytes() { diff --git a/tdkpin-rs/src/game.rs b/tdkpin-rs/src/game.rs index 9db9dce..9c610a9 100644 --- a/tdkpin-rs/src/game.rs +++ b/tdkpin-rs/src/game.rs @@ -547,13 +547,6 @@ impl Game { } self.finished = true; } - - pub fn flippers(&self) -> (Segment, Segment) { - ( - flipper_segment(vec2(103.0, 397.0), self.left_flipper_angle), - flipper_segment(vec2(210.0, 397.0), self.right_flipper_angle), - ) - } } fn flipper_segment(pivot: Vec2, angle: f32) -> Segment {