fix(physics): preserve record layer and kick fields

Carry the recovered +0x49 layer mask through every static line/circle and select the original upper/lower scan layer from the previous Y coordinate. Restore negative auxiliary thresholds and kick coefficients for bumpers and records 55, 74, and 107, including weak-hit scoring, rail sound, and tilt suppression.

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
This commit is contained in:
2026-08-23 18:13:35 +02:00
parent 692e0087f9
commit 3d5a105c10
5 changed files with 247 additions and 22 deletions
+47
View File
@@ -18,9 +18,12 @@ pub struct TableSegment {
pub segment: Segment,
pub normal_rebound: f32,
pub tangent_coupling: f32,
pub response_auxiliary: f32,
pub response_kick: f32,
pub score: u32,
pub flags: u16,
pub contact_group: u8,
pub layer_mask: u8,
}
impl TableSegment {
@@ -69,14 +72,22 @@ impl TableSegment {
118..=120 => 118,
_ => 0,
};
let (response_auxiliary, response_kick) = match id {
55 | 74 => (-0.40, 0.40),
107 => (-0.40, 0.30),
_ => (0.0, 0.0),
};
Self {
id,
segment: Segment::new(start, end, normal_rebound),
normal_rebound,
tangent_coupling,
response_auxiliary,
response_kick,
score,
flags,
contact_group,
layer_mask: layer_mask_for_record(id),
}
}
}
@@ -89,6 +100,7 @@ pub struct StaticCircle {
pub normal_rebound: f32,
pub tangent_coupling: f32,
pub normal_kick: f32,
pub layer_mask: u8,
}
#[derive(Clone, Copy, Debug)]
@@ -139,10 +151,19 @@ impl StaticCircle {
normal_rebound,
tangent_coupling,
normal_kick,
layer_mask: layer_mask_for_record(id),
}
}
}
const fn layer_mask_for_record(id: u8) -> u8 {
match id {
11 | 24 | 49 | 84..=120 | 167..=175 => 0x03,
1..=10 | 25 | 50 | 54..=83 | 153 | 154 => 0x02,
_ => 0x01,
}
}
/// Active type-2 objects after later registrations overwrite objects 169 and
/// 170. Object 2 is the drain sensor and object 25 is the shooter stop; callers
/// apply their special behavior after detecting contact.
@@ -347,6 +368,32 @@ mod tests {
assert_eq!(BUMPERS.len(), 3);
}
#[test]
fn recovered_layer_masks_cover_upper_lower_and_shared_records() {
assert_eq!(layer_mask_for_record(48), 0x01);
assert_eq!(layer_mask_for_record(50), 0x02);
assert_eq!(layer_mask_for_record(49), 0x03);
assert_eq!(layer_mask_for_record(89), 0x03);
assert_eq!(layer_mask_for_record(140), 0x01);
assert_eq!(layer_mask_for_record(153), 0x02);
assert_eq!(layer_mask_for_record(174), 0x03);
}
#[test]
fn recovered_auxiliary_kick_records_keep_both_coefficients() {
for (id, expected_kick) in [(55, 0.40_f32), (74, 0.40), (107, 0.30)] {
let wall = WALLS
.iter()
.find(|wall| wall.id == id)
.expect("the kicked line record must be present");
assert_eq!(wall.response_auxiliary.to_bits(), (-0.40_f32).to_bits());
assert_eq!(wall.response_kick.to_bits(), expected_kick.to_bits());
}
for bumper in BUMPERS {
assert_eq!(bumper.normal_kick.to_bits(), 0.40_f32.to_bits());
}
}
#[test]
fn recovered_landmarks_match_the_visible_table() {
let left_flipper_post = PASSIVE_CIRCLES