From 8c51094b3187c9d9a27768331565f168e0ed50d0 Mon Sep 17 00:00:00 2001 From: ddidderr Date: Sun, 23 Aug 2026 18:17:29 +0200 Subject: [PATCH] fix(timing): decay tilt on detail callbacks Remove the independent 30 ms tilt accumulator and decrement the wrapping 16-bit counter once at the end of each selected multimedia detail callback. This restores the original 50/40/30/20/10 ms decay cadence across all five settings. Test Plan: - cargo test --all-targets - cargo clippy --all-targets --all-features -- -D warnings - rumdl check CHANGELOG.md RECONSTRUCTION.md README.md - git diff --check --- tdkpin-rs/CHANGELOG.md | 2 ++ tdkpin-rs/src/game.rs | 36 ++++++++++++++++++++++-------------- 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/tdkpin-rs/CHANGELOG.md b/tdkpin-rs/CHANGELOG.md index f14108f..e9b3553 100644 --- a/tdkpin-rs/CHANGELOG.md +++ b/tdkpin-rs/CHANGELOG.md @@ -10,6 +10,8 @@ and this project adheres to ### Fixed +- Decay the 16-bit tilt counter once per selected 50/40/30/20/10 ms detail + callback, replacing an invented independent 30 ms accumulator. - Match the multiball nudge path's saved-slot behavior: consume the active formula's random draws, then add one shared fixed/random impulse to both slot velocity records instead of applying different formulas to each ball. diff --git a/tdkpin-rs/src/game.rs b/tdkpin-rs/src/game.rs index 56eb9e9..7371526 100644 --- a/tdkpin-rs/src/game.rs +++ b/tdkpin-rs/src/game.rs @@ -286,7 +286,6 @@ pub struct Game { accumulator: f32, record_countdowns: [u8; 176], tilt_counter: u16, - tilt_counter_accumulator: f32, launcher_was_down: bool, launcher_hold_seconds: f32, launcher_next_repeat: f32, @@ -328,7 +327,6 @@ impl Game { accumulator: 0.0, record_countdowns: [0; 176], tilt_counter: 0, - tilt_counter_accumulator: 0.0, launcher_was_down: false, launcher_hold_seconds: 0.0, launcher_next_repeat: LAUNCHER_REPEAT_DELAY_SECONDS, @@ -415,7 +413,6 @@ impl Game { } self.last_collision_id = None; self.claw_frame_seconds = DETAIL_TIMER_SECONDS[usize::from(detail.clamp(1, 5) - 1)]; - self.advance_tilt_counter(frame_time.min(0.05)); let mut events = Vec::new(); self.flipper_inputs.left_raised = controls.left_flipper && !self.tilted; self.flipper_inputs.right_raised = controls.right_flipper && !self.tilted; @@ -524,6 +521,9 @@ impl Game { } } self.apply_flipper_kicks(); + if self.tilt_counter != 0 { + self.tilt_counter -= 1; + } } fn update_record_countdowns(&mut self) { @@ -586,16 +586,6 @@ impl Game { true } - fn advance_tilt_counter(&mut self, elapsed: f32) { - self.tilt_counter_accumulator += elapsed; - while self.tilt_counter_accumulator >= self.claw_frame_seconds { - self.tilt_counter_accumulator -= self.claw_frame_seconds; - if self.tilt_counter != 0 { - self.tilt_counter -= 1; - } - } - } - #[allow(clippy::cast_possible_truncation)] fn apply_nudge(&mut self, nudge: Nudge, events: &mut Vec) { const SCALAR: i32 = 15; @@ -1617,7 +1607,6 @@ impl Game { } self.tilted = false; self.tilt_counter = 0; - self.tilt_counter_accumulator = 0.0; self.target_rotation_state = None; self.panel_frame = None; self.claw = Claw::default(); @@ -2700,6 +2689,25 @@ mod tests { assert_eq!(game.tilt_counter, 24); } + #[test] + fn tilt_counter_decays_once_per_selected_detail_callback() { + for (detail, interval) in [ + (1, 0.050), + (2, 0.040), + (3, 0.030), + (4, 0.020), + (5, 0.010), + ] { + let mut game = Game::new(1); + game.tilt_counter = 2; + + game.update(interval - 0.001, detail, Controls::default()); + assert_eq!(game.tilt_counter, 2, "detail {detail} decayed before its callback"); + game.update(0.001_1, detail, Controls::default()); + assert_eq!(game.tilt_counter, 1, "detail {detail} did not decay at its callback"); + } + } + #[test] fn multiball_nudge_consumes_active_draws_then_updates_both_saved_slots() { let mut game = Game::new_with_seed(1, 7);