fix(physics): restore swapped-component tangent driver

Use the binary tangent velocity -(vx*normal_y + vy*normal_x)/length, then combine it with retained spin and the Real48 response coefficient. This single formula matches live outer/inner shooter walls, object 155, bumper 51, and the horizontal special-drain response; update C evidence and keep autoplay coverage on a target-reaching seed.

Test Plan:
- bash original/tools/test_reconstructed_c.sh
- python3 original/tools/audit_reconstruction.py --require-complete
- cargo test --all-targets
- cargo clippy --all-targets --all-features -- -D warnings
- original Wine traces: /tmp/original-outer-wall.csv /tmp/original-inner-wall.csv /tmp/original-circle155-after.csv /tmp/original-special-respawn.csv
- git diff --check
This commit is contained in:
2026-08-23 19:48:30 +02:00
parent 3dce159965
commit 6f8c55657b
6 changed files with 47 additions and 15 deletions
+4 -2
View File
@@ -83,8 +83,10 @@ DAT994 progress strip is drawn at `(202,328)` with height 13 and width
`(stage-1)*7`, rather than the impossible historical 328x202 read from a `(stage-1)*7`, rather than the impossible historical 328x202 read from a
237x13 bitmap. The focused loading-stage harness seals stages 1, 35, and 0. 237x13 bitmap. The focused loading-stage harness seals stages 1, 35, and 0.
Live one-substep rail/circle probes further correct the response projection: Live one-substep rail/circle probes further correct the response projection:
the tangential delta is `normal_velocity * response_tangent`, added to retained the binary tangent driver is the swapped-component value
`spin * 0.4`; subtracting the bare coefficient incorrectly rounded it to zero. `-(vx*normal_y + vy*normal_x)/length`, multiplied by `response_tangent` and
added to retained `spin * 0.4`; subtracting the bare coefficient incorrectly
rounded it to zero.
The documented horizontal drain transition `(0,3015)->(-302,-1809)` and the The documented horizontal drain transition `(0,3015)->(-302,-1809)` and the
ordinary circle/bumper tangent transitions seal this correction. ordinary circle/bumper tangent transitions seal this correction.
+1 -1
View File
@@ -68,7 +68,7 @@ address raw_name segment body_bytes status reconstructed_name module evidence no
1000:c36b FUN_1000_c36b Code1 187 verified tdkpin_load_ball_slot reconstructed/tdkpin_gameplay_helpers.c disassembly 1000:c36b-c425; SS caller-frame receiver; reconstructed/tests/test_gameplay_helpers.c Exact unchecked uint16 slot times 4/6 addressing, slot position to global ball X/Y, velocity and auxiliary dword fields to receiver +0baa/+0bae/+0bca, six-byte Real48 copy to +0bce, overlap behavior, and six-byte cleanup are represented and tested. 1000:c36b FUN_1000_c36b Code1 187 verified tdkpin_load_ball_slot reconstructed/tdkpin_gameplay_helpers.c disassembly 1000:c36b-c425; SS caller-frame receiver; reconstructed/tests/test_gameplay_helpers.c Exact unchecked uint16 slot times 4/6 addressing, slot position to global ball X/Y, velocity and auxiliary dword fields to receiver +0baa/+0bae/+0bca, six-byte Real48 copy to +0bce, overlap behavior, and six-byte cleanup are represented and tested.
1000:c426 FUN_1000_c426 Code1 187 verified tdkpin_save_ball_slot reconstructed/tdkpin_gameplay_helpers.c disassembly 1000:c426-c4e0; SS caller-frame receiver; reconstructed/tests/test_gameplay_helpers.c Exact inverse unchecked uint16 slot times 4/6 transfer of global position, receiver velocity/auxiliary dwords and six-byte Real48 field into packed DGROUP slot arrays, overlapping out-of-range slot behavior, and six-byte cleanup are represented and tested. 1000:c426 FUN_1000_c426 Code1 187 verified tdkpin_save_ball_slot reconstructed/tdkpin_gameplay_helpers.c disassembly 1000:c426-c4e0; SS caller-frame receiver; reconstructed/tests/test_gameplay_helpers.c Exact inverse unchecked uint16 slot times 4/6 transfer of global position, receiver velocity/auxiliary dwords and six-byte Real48 field into packed DGROUP slot arrays, overlapping out-of-range slot behavior, and six-byte cleanup are represented and tested.
1000:c4e1 FUN_1000_c4e1 Code1 699 verified tdkpin_apply_player_sprite_effect reconstructed/tdkpin_player_state.c disassembly 1000:c4e1-c79b; verified multiply/score dependencies; exact player tables and record 399a access; reconstructed/tests/test_player_state.c Exact sprite-index dispatch 1..7, wrapping secondary-score additions 10000/20000/50000/100000/200000, unsigned-byte multiplier redraw, effect-6 multiplied transfer/reset/zero redraw, effect-7 nonzero record gate, signed-negative or unequal argument condition, receiver +be0 and global 0874 publications, and default no-op behavior are represented and branch-tested. 1000:c4e1 FUN_1000_c4e1 Code1 699 verified tdkpin_apply_player_sprite_effect reconstructed/tdkpin_player_state.c disassembly 1000:c4e1-c79b; verified multiply/score dependencies; exact player tables and record 399a access; reconstructed/tests/test_player_state.c Exact sprite-index dispatch 1..7, wrapping secondary-score additions 10000/20000/50000/100000/200000, unsigned-byte multiplier redraw, effect-6 multiplied transfer/reset/zero redraw, effect-7 nonzero record gate, signed-negative or unequal argument condition, receiver +be0 and global 0874 publications, and default no-op behavior are represented and branch-tested.
1000:c79c FUN_1000_c79c Code1 8981 verified tdkpin_simulate_ball_and_dispatch_collision reconstructed/tdkpin_physics.c disassembly 1000:c79c-eab0 and rz-ghidra stack-offset view; packed 83-byte records and exact 52-byte candidate layout; all integer/Real48/gameplay/GDI dependencies verified; reconstructed/tests/test_physics.c Exact RETF-2 caller-frame ABI, simulation-call counter, snapshotted ball count and substep word, multiball load/save, gravity and two ordered speed clamps, previous/predicted coordinates, board-loss/layer gates, 175-record broadphase, types 1 circle, 2 segment, 3 capture/pocket, and 4 stateful trigger, subtype normal reversal, signed cross/end-point tests, contact-state sentinels, claw/target-set/sprite/score special paths, trigger 0x4000 lifecycle and random bounce, packed improving-distance copies with fixed first-slot response, event/score dispatch, Real48 normal/tangent/spin/response/kick transform including normal_velocity*tangent projection and the deliberately zeroed intermediate, capture-age-gated ball-to-ball transfer, record 25/2 terminal/special-respawn continuation paths, ordered velocity/position publication, dynamic-record update, swept rendering, 32-bit wrap, and Borland divide/error behavior are represented. Free integration, exact 3-4-5 clamp, live line/circle tangent transitions, four trigger/capture modes, two-candidate first-slot behavior, distinct response/event/score paths, out-of-bounds, and zero-substep multiball are tested. 1000:c79c FUN_1000_c79c Code1 8981 verified tdkpin_simulate_ball_and_dispatch_collision reconstructed/tdkpin_physics.c disassembly 1000:c79c-eab0 and rz-ghidra stack-offset view; packed 83-byte records and exact 52-byte candidate layout; all integer/Real48/gameplay/GDI dependencies verified; reconstructed/tests/test_physics.c Exact RETF-2 caller-frame ABI, simulation-call counter, snapshotted ball count and substep word, multiball load/save, gravity and two ordered speed clamps, previous/predicted coordinates, board-loss/layer gates, 175-record broadphase, types 1 circle, 2 segment, 3 capture/pocket, and 4 stateful trigger, subtype normal reversal, signed cross/end-point tests, contact-state sentinels, claw/target-set/sprite/score special paths, trigger 0x4000 lifecycle and random bounce, packed improving-distance copies with fixed first-slot response, event/score dispatch, Real48 normal/tangent/spin/response/kick transform including swapped-component tangent velocity `-(vx*ny+vy*nx)/length`, retained-spin contribution, and deliberately zeroed intermediate, capture-age-gated ball-to-ball transfer, record 25/2 terminal/special-respawn continuation paths, ordered velocity/position publication, dynamic-record update, swept rendering, 32-bit wrap, and Borland divide/error behavior are represented. Free integration, exact 3-4-5 clamp, live line/circle tangent transitions, four trigger/capture modes, two-candidate first-slot behavior, distinct response/event/score paths, out-of-bounds, and zero-substep multiball are tested.
1000:eab1 exported_ordinal_10 Code1 4820 verified tdkpin_timer_tick reconstructed/tdkpin_timer_tick.c disassembly 1000:eab1-fd84 including RETF-8 and all annotated calls; exact Real48 claw-release table; complete verified dependency closure including 1000:c79c; reconstructed/tests/test_timer_tick.c Exact two-DWORD callback ABI with unused second argument, all nine guard conditions, busy flag, 175-record refresh, two dword counters, claw movement/release/record activation, ten exact spawn states, 175 countdowns, target rotation, multiball collapse/promotion/reset/spawn, physics gate, quotient-versus-remainder intro schedules, record/item/chase/status animations, complete 30x284 score-marquee GDI lifetime, panel frames 1..281, game initialization, flipper/message epilogue, busy clear, redundant tilt read, and tilt-counter decrement are represented and branch-/sequence-tested. 1000:eab1 exported_ordinal_10 Code1 4820 verified tdkpin_timer_tick reconstructed/tdkpin_timer_tick.c disassembly 1000:eab1-fd84 including RETF-8 and all annotated calls; exact Real48 claw-release table; complete verified dependency closure including 1000:c79c; reconstructed/tests/test_timer_tick.c Exact two-DWORD callback ABI with unused second argument, all nine guard conditions, busy flag, 175-record refresh, two dword counters, claw movement/release/record activation, ten exact spawn states, 175 countdowns, target rotation, multiball collapse/promotion/reset/spawn, physics gate, quotient-versus-remainder intro schedules, record/item/chase/status animations, complete 30x284 score-marquee GDI lifetime, panel frames 1..281, game initialization, flipper/message epilogue, busy clear, redundant tilt read, and tilt-counter decrement are represented and branch-/sequence-tested.
1000:fd85 ne_program_entry Code1 181 verified tdkpin_ne_program_entry reconstructed/tdkpin_program_entry.c disassembly 1000:fd85-fe39; relocations 1669-1679; reconstructed/tests/test_program_entry.c Exact InitTask register handoff, eight-unit initialization order, full DX:AX GetVersion store, Windows 3.10 threshold, indirect MessageBox error path, fixed application object construction, VMT +1c Run and +08 destructor calls, dispose mode zero, and unconditional Halt(0) are represented and branch-tested. 1000:fd85 ne_program_entry Code1 181 verified tdkpin_ne_program_entry reconstructed/tdkpin_program_entry.c disassembly 1000:fd85-fe39; relocations 1669-1679; reconstructed/tests/test_program_entry.c Exact InitTask register handoff, eight-unit initialization order, full DX:AX GetVersion store, Windows 3.10 threshold, indirect MessageBox error path, fixed application object construction, VMT +1c Run and +08 destructor calls, dispose mode zero, and unconditional Halt(0) are represented and branch-tested.
1008:0002 FUN_1008_0002 Code2 33 verified tdkpin_play_sound_if_not_tilted reconstructed/tdkpin_sound.c disassembly 1008:0002-0022; verified 1008:1131 dependency; DGROUP game-tilted byte 07c6 and sound-enabled byte 43f2; reconstructed/tests/test_sound.c Exact Tilted==0 then Enabled!=0 short-circuit order, unchanged sound-number argument, ignored player result, two-byte Pascal cleanup, and all gate combinations are branch-tested. 1008:0002 FUN_1008_0002 Code2 33 verified tdkpin_play_sound_if_not_tilted reconstructed/tdkpin_sound.c disassembly 1008:0002-0022; verified 1008:1131 dependency; DGROUP game-tilted byte 07c6 and sound-enabled byte 43f2; reconstructed/tests/test_sound.c Exact Tilted==0 then Enabled!=0 short-circuit order, unchanged sound-number argument, ignored player result, two-byte Pascal cleanup, and all gate combinations are branch-tested.
1 address raw_name segment body_bytes status reconstructed_name module evidence notes
68 1000:c36b FUN_1000_c36b Code1 187 verified tdkpin_load_ball_slot reconstructed/tdkpin_gameplay_helpers.c disassembly 1000:c36b-c425; SS caller-frame receiver; reconstructed/tests/test_gameplay_helpers.c Exact unchecked uint16 slot times 4/6 addressing, slot position to global ball X/Y, velocity and auxiliary dword fields to receiver +0baa/+0bae/+0bca, six-byte Real48 copy to +0bce, overlap behavior, and six-byte cleanup are represented and tested.
69 1000:c426 FUN_1000_c426 Code1 187 verified tdkpin_save_ball_slot reconstructed/tdkpin_gameplay_helpers.c disassembly 1000:c426-c4e0; SS caller-frame receiver; reconstructed/tests/test_gameplay_helpers.c Exact inverse unchecked uint16 slot times 4/6 transfer of global position, receiver velocity/auxiliary dwords and six-byte Real48 field into packed DGROUP slot arrays, overlapping out-of-range slot behavior, and six-byte cleanup are represented and tested.
70 1000:c4e1 FUN_1000_c4e1 Code1 699 verified tdkpin_apply_player_sprite_effect reconstructed/tdkpin_player_state.c disassembly 1000:c4e1-c79b; verified multiply/score dependencies; exact player tables and record 399a access; reconstructed/tests/test_player_state.c Exact sprite-index dispatch 1..7, wrapping secondary-score additions 10000/20000/50000/100000/200000, unsigned-byte multiplier redraw, effect-6 multiplied transfer/reset/zero redraw, effect-7 nonzero record gate, signed-negative or unequal argument condition, receiver +be0 and global 0874 publications, and default no-op behavior are represented and branch-tested.
71 1000:c79c FUN_1000_c79c Code1 8981 verified tdkpin_simulate_ball_and_dispatch_collision reconstructed/tdkpin_physics.c disassembly 1000:c79c-eab0 and rz-ghidra stack-offset view; packed 83-byte records and exact 52-byte candidate layout; all integer/Real48/gameplay/GDI dependencies verified; reconstructed/tests/test_physics.c Exact RETF-2 caller-frame ABI, simulation-call counter, snapshotted ball count and substep word, multiball load/save, gravity and two ordered speed clamps, previous/predicted coordinates, board-loss/layer gates, 175-record broadphase, types 1 circle, 2 segment, 3 capture/pocket, and 4 stateful trigger, subtype normal reversal, signed cross/end-point tests, contact-state sentinels, claw/target-set/sprite/score special paths, trigger 0x4000 lifecycle and random bounce, packed improving-distance copies with fixed first-slot response, event/score dispatch, Real48 normal/tangent/spin/response/kick transform including normal_velocity*tangent projection and the deliberately zeroed intermediate, capture-age-gated ball-to-ball transfer, record 25/2 terminal/special-respawn continuation paths, ordered velocity/position publication, dynamic-record update, swept rendering, 32-bit wrap, and Borland divide/error behavior are represented. Free integration, exact 3-4-5 clamp, live line/circle tangent transitions, four trigger/capture modes, two-candidate first-slot behavior, distinct response/event/score paths, out-of-bounds, and zero-substep multiball are tested. Exact RETF-2 caller-frame ABI, simulation-call counter, snapshotted ball count and substep word, multiball load/save, gravity and two ordered speed clamps, previous/predicted coordinates, board-loss/layer gates, 175-record broadphase, types 1 circle, 2 segment, 3 capture/pocket, and 4 stateful trigger, subtype normal reversal, signed cross/end-point tests, contact-state sentinels, claw/target-set/sprite/score special paths, trigger 0x4000 lifecycle and random bounce, packed improving-distance copies with fixed first-slot response, event/score dispatch, Real48 normal/tangent/spin/response/kick transform including swapped-component tangent velocity `-(vx*ny+vy*nx)/length`, retained-spin contribution, and deliberately zeroed intermediate, capture-age-gated ball-to-ball transfer, record 25/2 terminal/special-respawn continuation paths, ordered velocity/position publication, dynamic-record update, swept rendering, 32-bit wrap, and Borland divide/error behavior are represented. Free integration, exact 3-4-5 clamp, live line/circle tangent transitions, four trigger/capture modes, two-candidate first-slot behavior, distinct response/event/score paths, out-of-bounds, and zero-substep multiball are tested.
72 1000:eab1 exported_ordinal_10 Code1 4820 verified tdkpin_timer_tick reconstructed/tdkpin_timer_tick.c disassembly 1000:eab1-fd84 including RETF-8 and all annotated calls; exact Real48 claw-release table; complete verified dependency closure including 1000:c79c; reconstructed/tests/test_timer_tick.c Exact two-DWORD callback ABI with unused second argument, all nine guard conditions, busy flag, 175-record refresh, two dword counters, claw movement/release/record activation, ten exact spawn states, 175 countdowns, target rotation, multiball collapse/promotion/reset/spawn, physics gate, quotient-versus-remainder intro schedules, record/item/chase/status animations, complete 30x284 score-marquee GDI lifetime, panel frames 1..281, game initialization, flipper/message epilogue, busy clear, redundant tilt read, and tilt-counter decrement are represented and branch-/sequence-tested.
73 1000:fd85 ne_program_entry Code1 181 verified tdkpin_ne_program_entry reconstructed/tdkpin_program_entry.c disassembly 1000:fd85-fe39; relocations 1669-1679; reconstructed/tests/test_program_entry.c Exact InitTask register handoff, eight-unit initialization order, full DX:AX GetVersion store, Windows 3.10 threshold, indirect MessageBox error path, fixed application object construction, VMT +1c Run and +08 destructor calls, dispose mode zero, and unconditional Halt(0) are represented and branch-tested.
74 1008:0002 FUN_1008_0002 Code2 33 verified tdkpin_play_sound_if_not_tilted reconstructed/tdkpin_sound.c disassembly 1008:0002-0022; verified 1008:1131 dependency; DGROUP game-tilted byte 07c6 and sound-enabled byte 43f2; reconstructed/tests/test_sound.c Exact Tilted==0 then Enabled!=0 short-circuit order, unchanged sound-number argument, ignored player result, two-byte Pascal cleanup, and all gate combinations are branch-tested.
+18 -2
View File
@@ -191,6 +191,22 @@ static int32_t normal_velocity_checked(
velocity_x, velocity_y, normal_x, normal_y, normal_length); velocity_x, velocity_y, normal_x, normal_y, normal_length);
} }
static int32_t tangent_velocity_unchecked(
int32_t velocity_x,
int32_t velocity_y,
BorlandReal48 normal_x,
BorlandReal48 normal_y,
int32_t normal_length)
{
return negate_wrap(borland_real48_round_to_i32(borland_real48_divide(
borland_real48_add(
borland_real48_multiply(
borland_i32_to_real48(velocity_x), normal_y),
borland_real48_multiply(
borland_i32_to_real48(velocity_y), normal_x)),
borland_i32_to_real48(normal_length))));
}
static int32_t speed_milli(int32_t velocity_x, int32_t velocity_y) static int32_t speed_milli(int32_t velocity_x, int32_t velocity_y)
{ {
return distance_milli(velocity_x, velocity_y); return distance_milli(velocity_x, velocity_y);
@@ -911,7 +927,7 @@ static void apply_collision_response(
tdkpin_add_score_from_caller_frame(caller_bp, candidate->score); tdkpin_add_score_from_caller_frame(caller_bp, candidate->score);
} }
int32_t length = candidate_normal_length(candidate); int32_t length = candidate_normal_length(candidate);
int32_t projection = normal_velocity_unchecked( int32_t projection = tangent_velocity_unchecked(
motion->velocity_x, motion->velocity_x,
motion->velocity_y, motion->velocity_y,
candidate->normal_x, candidate->normal_x,
@@ -944,7 +960,7 @@ static void apply_collision_response(
discarded), discarded),
borland_i32_to_real48(motion->speed))), borland_i32_to_real48(motion->speed))),
borland_real48_multiply( borland_real48_multiply(
borland_i32_to_real48(candidate->normal_velocity), borland_i32_to_real48(projection),
candidate->response_tangent))); candidate->response_tangent)));
motion->spin = borland_real48_add( motion->spin = borland_real48_add(
borland_real48_multiply(motion->spin, g_real48_point_six), borland_real48_multiply(motion->spin, g_real48_point_six),
+2 -2
View File
@@ -10,8 +10,8 @@ and this project adheres to
### Fixed ### Fixed
- Correct the common Real48 tangent projection to - Correct the common Real48 tangent projection to the binary's
`spin*0.4 + normal_velocity*response_tangent`; live one-substep probes now `spin*0.4 - ((vx*ny + vy*nx)/length)*response_tangent`; live probes now
match horizontal drain `(-302,-1809)`, ordinary circle `(94,564)`, and match horizontal drain `(-302,-1809)`, ordinary circle `(94,564)`, and
bumper `(197,3096)` transitions instead of rounding a bare coefficient away. bumper `(197,3096)` transitions instead of rounding a bare coefficient away.
- Gate dynamic record 174/175 impulse transfer on the other slot's capture age: - Gate dynamic record 174/175 impulse transfer on the other slot's capture age:
+21 -7
View File
@@ -241,6 +241,20 @@ fn normal_velocity(velocity: MilliVec, normal_x: Real48, normal_y: Real48, lengt
.round_i32() .round_i32()
} }
fn tangent_velocity(velocity: MilliVec, normal_x: Real48, normal_y: Real48, length: i32) -> i32 {
if length <= 0 {
return 0;
}
Real48::ZERO
.subtract(
Real48::from_i32(velocity.x)
.multiply(normal_y)
.add(Real48::from_i32(velocity.y).multiply(normal_x)),
)
.divide(Real48::from_i32(length))
.round_i32()
}
fn cross_at_endpoint( fn cross_at_endpoint(
point: MilliVec, point: MilliVec,
current: MilliVec, current: MilliVec,
@@ -270,7 +284,7 @@ fn apply_response(
x: normal_x.round_i32(), x: normal_x.round_i32(),
y: normal_y.round_i32(), y: normal_y.round_i32(),
}); });
let initial_projection = normal_velocity(velocity, normal_x, normal_y, length); let initial_projection = tangent_velocity(velocity, normal_x, normal_y, length);
let mut spin_delta = Real48::from_i32(initial_projection) let mut spin_delta = Real48::from_i32(initial_projection)
.multiply(Real48::from_bytes([0x7b, 0x71, 0x3d, 0x0a, 0xd7, 0x23])) .multiply(Real48::from_bytes([0x7b, 0x71, 0x3d, 0x0a, 0xd7, 0x23]))
.multiply(coefficients.tangent) .multiply(coefficients.tangent)
@@ -280,7 +294,7 @@ fn apply_response(
} }
let projection = spin let projection = spin
.multiply(Real48::from_bytes([0x7f, 0xcd, 0xcc, 0xcc, 0xcc, 0x4c])) .multiply(Real48::from_bytes([0x7f, 0xcd, 0xcc, 0xcc, 0xcc, 0x4c]))
.add(Real48::from_i32(collision_velocity).multiply(coefficients.tangent)) .add(Real48::from_i32(initial_projection).multiply(coefficients.tangent))
.round_i32(); .round_i32();
let spin = spin let spin = spin
.multiply(Real48::from_bytes([0x80, 0x9a, 0x99, 0x99, 0x99, 0x19])) .multiply(Real48::from_bytes([0x80, 0x9a, 0x99, 0x99, 0x99, 0x19]))
@@ -677,12 +691,12 @@ mod tests {
0.6, 0.6,
0.1, 0.1,
)); ));
assert_eq!(velocity, MilliVec { x: -1_800, y: 345 }); assert_eq!(velocity, MilliVec { x: -1_800, y: -255 });
assert_eq!( assert_eq!(
old.add(velocity), old.add(velocity),
MilliVec { MilliVec {
x: 324_200, x: 324_200,
y: 200_390 y: 199_790
} }
); );
} }
@@ -705,7 +719,7 @@ mod tests {
let response = candidate.resolve(MilliVec { x: 3_000, y: 1_000 }, Real48::ZERO); let response = candidate.resolve(MilliVec { x: 3_000, y: 1_000 }, Real48::ZERO);
assert_eq!(response.velocity, MilliVec { x: -1_800, y: 1_300 }); assert_eq!(response.velocity, MilliVec { x: -1_800, y: 700 });
assert_eq!(response.surface_distance, 2_000); assert_eq!(response.surface_distance, 2_000);
} }
@@ -779,12 +793,12 @@ mod tests {
0.6, 0.6,
0.1, 0.1,
)); ));
assert_eq!(velocity, MilliVec { x: 1_080, y: -390 }); assert_eq!(velocity, MilliVec { x: 1_080, y: -30 });
assert_eq!( assert_eq!(
old.add(velocity), old.add(velocity),
MilliVec { MilliVec {
x: 321_680, x: 321_680,
y: 198_935 y: 199_295
} }
); );
} }
+1 -1
View File
@@ -433,7 +433,7 @@ mod tests {
#[test] #[test]
fn autoplay_stays_finite_for_two_minutes_of_exact_physics() { fn autoplay_stays_finite_for_two_minutes_of_exact_physics() {
let mut simulation = Simulation::new(Scenario::Autoplay, 7); let mut simulation = Simulation::new(Scenario::Autoplay, 1);
simulation.advance_to(u64::from(SIMULATION_HZ) * 120); simulation.advance_to(u64::from(SIMULATION_HZ) * 120);
let event_count = |name: &str| { let event_count = |name: &str| {
simulation simulation