fix(physics): port the Borland Real48 collision core
Add a bit-exact six-byte Real48 implementation for integer conversion, rounding, comparison, add/subtract, multiply/divide, and Newton square root. Use the normalized Borland random-register result and route speed clamps, segment/circle detection, moving flippers, captures, triggers, and magnetic fields through the recovered arithmetic instead of host floating formulas. Preserve Real48 spin per ball and feed it through the original tangent/spin response, separating zero-spin C fixtures from retained-spin Wine traces. Replace path-progress selection with surface-distance ordering and implement dynamic records 174/175, including impulse transfer to the other slot, normal_velocity-1000 response, and the second post-collision speed clamp. Test Plan: - `cargo test --all-targets` -- passed, 69 tests - `cargo clippy --all-targets -- -D warnings` -- passed - `rumdl check tdkpin-rs/CHANGELOG.md tdkpin-rs/RECONSTRUCTION.md` -- passed - `git diff --cached --check` -- passed
This commit is contained in:
@@ -1,6 +1,9 @@
|
||||
//! Borland Win16 random-number stream used by the original executable.
|
||||
|
||||
use crate::real48::Real48;
|
||||
|
||||
const MULTIPLIER: u32 = 0x0808_8405;
|
||||
#[cfg(test)]
|
||||
const TWO_TO_32: f64 = 4_294_967_296.0;
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
|
||||
@@ -24,7 +27,30 @@ impl BorlandRandom {
|
||||
(product >> 32) as u16
|
||||
}
|
||||
|
||||
#[allow(clippy::cast_possible_truncation)]
|
||||
pub fn real48(&mut self) -> Real48 {
|
||||
let mut random = self.next_u32();
|
||||
if random == 0 {
|
||||
return Real48::ZERO;
|
||||
}
|
||||
let mut exponent = 0x80_u8;
|
||||
while random & 0x8000_0000 == 0 {
|
||||
random <<= 1;
|
||||
exponent = exponent.wrapping_sub(1);
|
||||
}
|
||||
random &= 0x7fff_ffff;
|
||||
Real48::from_bytes([
|
||||
exponent,
|
||||
0,
|
||||
random as u8,
|
||||
(random >> 8) as u8,
|
||||
(random >> 16) as u8,
|
||||
(random >> 24) as u8,
|
||||
])
|
||||
}
|
||||
|
||||
/// Exact host representation of the x87 `Random` result in `[0, 1)`.
|
||||
#[cfg(test)]
|
||||
pub fn unit_interval(&mut self) -> f64 {
|
||||
f64::from(self.next_u32()) / TWO_TO_32
|
||||
}
|
||||
@@ -66,4 +92,13 @@ mod tests {
|
||||
(f64::from(expected_seed) / TWO_TO_32).to_bits()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn real48_register_result_matches_the_reconstructed_normalization() {
|
||||
let mut random = BorlandRandom::new(7);
|
||||
assert_eq!(
|
||||
random.real48(),
|
||||
Real48::from_bytes([0x7e, 0, 0x90, 0x70, 0xee, 0x60])
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user