feat(reverse): isolate original physics substeps

Expose the original detail-derived integration count, active-ball count,
gravity, maximum speed, and movement flags in live traces. Allow probes to
force one physics substep so a single collision response can be observed
without the default three-step timer batch obscuring intermediate state.

Record the dynamically verified type-2 rail response: resolve velocity in the
registered line's normal/tangent basis, apply the two original Real48
coefficients, then advance from the previous position using that response.

Test Plan:
- `ruff check original/tools/trace_original_state.py original/tools/inject_original_state.py` -- passed
- one-substep probes against both vertical shooter walls -- passed
- ordinary rail responses matched 0.6 normal rebound and 0.1 tangent coupling
- `git diff --cached --check` -- passed
This commit is contained in:
2026-08-22 20:27:56 +02:00
parent 65ee3c5355
commit c50ed39a35
3 changed files with 37 additions and 1 deletions
+9
View File
@@ -18,6 +18,7 @@ from trace_original_state import (
NEXT_BALL_Y,
OBJECT_BALL_X,
OBJECT_BALL_Y,
PHYSICS_SUBSTEPS,
PREVIOUS_BALL_X,
PREVIOUS_BALL_Y,
VELOCITY_X,
@@ -49,6 +50,12 @@ def parse_args() -> argparse.Namespace:
parser.add_argument("--y", type=float, required=True, help="ball center y in logical pixels")
parser.add_argument("--vx", type=float, default=0.0, help="x velocity in pixels per timer tick")
parser.add_argument("--vy", type=float, default=0.0, help="y velocity in pixels per timer tick")
parser.add_argument(
"--substeps",
type=int,
choices=range(1, 6),
help="temporarily force the original physics substep count",
)
return parser.parse_args()
@@ -106,6 +113,8 @@ def main() -> None:
(NEXT_BALL_Y, next_y),
):
memory.write(data_base + offset, value)
if args.substeps is not None:
memory.write(data_base + PHYSICS_SUBSTEPS, struct.pack("<H", args.substeps))
for offset, value in (
(VELOCITY_X, velocity_x),
(VELOCITY_Y, velocity_y),