fix(game): restore six-state target rotation
Replace the free-running 68x60 wheel animation with the original six-callback 91x90 DAT600 mechanism. Start WAVE 2011 at state one, advance once per selected detail timer, and rotate the five per-player lock contact/item values exactly at state six. Decode the 17x17 DAT600 target image/mask pair and render all six recovered position sets over the correct atlas or overlay-B base. Preserve filled targets in their resting state after rotation and add a deterministic `targets` scenario for trace and framebuffer validation. Test Plan: - `cargo test --all-targets` -- passed, 74 tests - `cargo clippy --all-targets -- -D warnings` -- passed - `rumdl check CHANGELOG.md README.md RECONSTRUCTION.md` -- passed - rendered all six target-rotation states -- visually verified - `git diff --cached --check` -- passed
This commit is contained in:
+50
-20
@@ -11,6 +11,14 @@ use std::path::Path;
|
||||
|
||||
const WIDTH: f32 = 640.0;
|
||||
const HEIGHT: f32 = 460.0;
|
||||
const TARGET_POSITIONS: [[(f32, f32); 5]; 6] = [
|
||||
[(9.0, 41.0), (23.0, 11.0), (56.0, 14.0), (63.0, 47.0), (35.0, 63.0)],
|
||||
[(11.0, 45.0), (18.0, 13.0), (52.0, 11.0), (63.0, 42.0), (39.0, 64.0)],
|
||||
[(13.0, 50.0), (15.0, 17.0), (46.0, 9.0), (64.0, 37.0), (44.0, 62.0)],
|
||||
[(17.0, 55.0), (11.0, 23.0), (39.0, 7.0), (64.0, 30.0), (50.0, 59.0)],
|
||||
[(21.0, 60.0), (9.0, 28.0), (35.0, 7.0), (62.0, 25.0), (54.0, 56.0)],
|
||||
[(8.0, 35.0), (26.0, 8.0), (59.0, 18.0), (59.0, 50.0), (27.0, 61.0)],
|
||||
];
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
enum Screen {
|
||||
@@ -369,21 +377,11 @@ impl App {
|
||||
|
||||
if let Some(frame) = game.panel_frame {
|
||||
self.draw_panel_animation(frame);
|
||||
}
|
||||
|
||||
if game.wheel_animation > 0.0 {
|
||||
let frame = animation_frame(f64::from(0.65 - game.wheel_animation), 18.0, 5);
|
||||
draw_texture_ex(
|
||||
&self.assets.wheel,
|
||||
80.0,
|
||||
49.0,
|
||||
WHITE,
|
||||
DrawTextureParams {
|
||||
dest_size: Some(vec2(68.0, 60.0)),
|
||||
source: Some(Rect::new(frame as f32 * 68.0, 0.0, 68.0, 60.0)),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
} else if let Some(state) = game
|
||||
.target_rotation_state
|
||||
.or_else(|| game.wheel_holes.iter().any(|filled| *filled).then_some(6))
|
||||
{
|
||||
self.draw_target_rotation(game, state);
|
||||
}
|
||||
for (index, bumper) in BUMPERS.into_iter().enumerate() {
|
||||
if game.bumper_flash[index] > 0.0 {
|
||||
@@ -630,6 +628,43 @@ impl App {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::cast_precision_loss)]
|
||||
fn draw_target_rotation(&self, game: &Game, state: u8) {
|
||||
if state == 0 || state > 6 {
|
||||
return;
|
||||
}
|
||||
if state < 6 {
|
||||
draw_texture_region(
|
||||
&self.assets.wheel,
|
||||
79.0,
|
||||
33.0,
|
||||
91.0,
|
||||
90.0,
|
||||
f32::from(state - 1) * 91.0,
|
||||
0.0,
|
||||
);
|
||||
} else {
|
||||
draw_texture_region(
|
||||
&self.assets.inactive_table,
|
||||
79.0,
|
||||
33.0,
|
||||
91.0,
|
||||
90.0,
|
||||
79.0,
|
||||
33.0,
|
||||
);
|
||||
}
|
||||
for (active, (x, y)) in game
|
||||
.wheel_holes
|
||||
.iter()
|
||||
.zip(TARGET_POSITIONS[usize::from(state - 1)])
|
||||
{
|
||||
if *active {
|
||||
draw_texture(&self.assets.panel_target, 79.0 + x, 33.0 + y, WHITE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::cast_precision_loss)]
|
||||
fn draw_displays(&self, game: &Game) {
|
||||
for region in [
|
||||
@@ -898,11 +933,6 @@ fn draw_texture_region(
|
||||
);
|
||||
}
|
||||
|
||||
#[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
|
||||
fn animation_frame(elapsed: f64, frames_per_second: f64, frame_count: usize) -> usize {
|
||||
((elapsed.max(0.0) * frames_per_second) as usize) % frame_count
|
||||
}
|
||||
|
||||
fn draw_centered(text: &str, baseline: f32, font_size: u16, color: Color) {
|
||||
draw_centered_at(text, WIDTH * 0.5, baseline, font_size, color);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user