fix(ui): restore original attract animation

Advance idle mode on the selected detail callback and reproduce the reconstructed target, word-quad, magnetic, record-strip, point-chase, item, and BITMAP500 marquee phases from original assets. Add a deterministic attract screenshot scenario and correct DAT801-809 item placement to y=300.

Test Plan:
- cargo test --all-targets
- cargo clippy --all-targets --all-features -- -D warnings
- rumdl check CHANGELOG.md RECONSTRUCTION.md README.md
- cargo run --quiet -- --simulate attract --step 24 --screenshot /tmp/tdkpin-attract-24.png
- cargo run --quiet -- --simulate attract --step 192 --screenshot /tmp/tdkpin-attract-192.png
- cargo run --quiet -- --simulate attract --step 4608 --screenshot /tmp/tdkpin-attract-4608.png
- git diff --check
This commit is contained in:
2026-08-23 18:59:19 +02:00
parent 2936c69c5c
commit 8168d9dc23
6 changed files with 319 additions and 10 deletions
+17 -4
View File
@@ -13,6 +13,7 @@ const MAX_SIMULATION_STEPS: u64 = 72_000;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Scenario {
Attract,
Autoplay,
Launcher,
Flippers,
@@ -27,6 +28,7 @@ pub enum Scenario {
impl Scenario {
pub const fn name(self) -> &'static str {
match self {
Self::Attract => "attract",
Self::Autoplay => "autoplay",
Self::Launcher => "launcher",
Self::Flippers => "flippers",
@@ -45,7 +47,12 @@ impl Scenario {
Self::Claw6 => Some(6),
Self::Claw7 => Some(7),
Self::Claw18 => Some(18),
Self::Autoplay | Self::Launcher | Self::Flippers | Self::Panel | Self::Targets => None,
Self::Attract
| Self::Autoplay
| Self::Launcher
| Self::Flippers
| Self::Panel
| Self::Targets => None,
}
}
}
@@ -55,6 +62,7 @@ impl FromStr for Scenario {
fn from_str(value: &str) -> Result<Self, Self::Err> {
match value {
"attract" => Ok(Self::Attract),
"autoplay" => Ok(Self::Autoplay),
"launcher" => Ok(Self::Launcher),
"flippers" => Ok(Self::Flippers),
@@ -65,7 +73,7 @@ impl FromStr for Scenario {
"claw-7" => Ok(Self::Claw7),
"claw-18" => Ok(Self::Claw18),
_ => Err(format!(
"unknown scenario {value:?}; expected autoplay, launcher, flippers, panel, targets, claw-1, claw-6, claw-7, or claw-18"
"unknown scenario {value:?}; expected attract, autoplay, launcher, flippers, panel, targets, claw-1, claw-6, claw-7, or claw-18"
)),
}
}
@@ -149,7 +157,7 @@ fn seconds_to_step(value: &str) -> Result<u64, String> {
}
pub const fn usage() -> &'static str {
"Usage:\n tdkpin-rs\n tdkpin-rs --simulate SCENARIO [--at SECONDS | --step N] [--screenshot FILE.png] [--trace FILE.json] [--seed N]\n\nScenarios: autoplay, launcher, flippers, panel, targets, claw-1, claw-6, claw-7, claw-18"
"Usage:\n tdkpin-rs\n tdkpin-rs --simulate SCENARIO [--at SECONDS | --step N] [--screenshot FILE.png] [--trace FILE.json] [--seed N]\n\nScenarios: attract, autoplay, launcher, flippers, panel, targets, claw-1, claw-6, claw-7, claw-18"
}
#[derive(Debug, Serialize, PartialEq)]
@@ -230,7 +238,11 @@ impl Simulation {
} else {
controls_for(self.scenario, self.step)
};
let events = self.game.update(SIMULATION_DT, 3, controls);
let events = if self.scenario == Scenario::Attract {
Vec::new()
} else {
self.game.update(SIMULATION_DT, 3, controls)
};
self.step += 1;
self.record(events);
}
@@ -320,6 +332,7 @@ impl Simulation {
fn controls_for(scenario: Scenario, step: u64) -> Controls {
match scenario {
Scenario::Attract => Controls::default(),
Scenario::Autoplay => unreachable!("autoplay controls need mutable simulation state"),
Scenario::Launcher => Controls {
launch_down: step < u64::from(SIMULATION_HZ),