Use the original computer drivers, car collisions and towing

Decoded from SKIDMARKS_CD32:

- Computer drivers: the path of nodes laid 2 game units apart along
  the middle of the road, with side points 1 unit in from each wall.
  Drivers aim four nodes past where they'll be in four frames, or cut
  to the other side two nodes on at 70% throttle when running wide.
  Replaces the pure-pursuit AI; laps are quicker on every track.
- Collisions: six points on the player's car (corners and sides, from
  .set words 6 and 7, now known to be half-length and half-width) are
  tested against the other car's box. Hits push the cars apart with a
  strength that grows with their speed difference, and spin the car.
  As in the original, only human players' cars collide; cars at
  different heights don't.
- Towing: the hitch is at the car's back, the caravan sits 0.656 units
  behind it, and past 90 degrees both car and caravan bend back.

The reconstructed collision weight (`mass`) is gone; old asset files
with it still load.
This commit is contained in:
2026-10-20 10:15:33 +00:00
parent 54e146ce36
commit a4445d521f
18 changed files with 511 additions and 253 deletions
+74 -11
View File
@@ -194,12 +194,13 @@ with these shifts. Word `k` is the `k`th `u16`, counting from 0:
| 3 | `$c0` | −w / 64 | stored but never read |
| 4 | `$106` | w / 8 | gravity, pixels per frame² |
| 5 | `$b8` | w / 512 | power (computer drivers) |
| 6 | (towing) | w / 32 | tow hitch distance behind the car, in game units |
| 6 | (collisions, towing) | w / 32 | half the car's length, in game units; the tow hitch is at the back |
| 7 | (collisions) | w / 32 | half the car's width |
| 8 | `$bc` | w / 64 | drag (human drivers) |
| 9 | `$e2` | w / 512 | grip (human drivers) |
| 10 | `$b8` | w / 512 | power (human drivers) |
Words 7 and 11–15 aren't read. [Game logic](#game-logic) shows how drag,
Words 11–15 aren't read. [Game logic](#game-logic) shows how drag,
grip and power work together. In short, top speed is
`power × drag / (1 − drag)` game units per frame. For the Camaro that is
271 of this port's units a second for human drivers and 186 for computer
@@ -226,6 +227,7 @@ For a preset `(a, t, g)`:
- p = t/16 × (1/drag − 1), and power = p/8
- grip = g/256 / p / drag / 8
- steering = byte 6 / 32, gravity = 0.5
- The car's size (words 6 and 7) still comes from its own settings.
So top speed is simply t/128 game units per frame.
@@ -300,6 +302,7 @@ Each car is a 266-byte (`$10a`) record:
| `$a6` | engine speed |
| `$aa` | forward speed |
| `$b8`, `$bc`, `$e2`, `$e6`, `$106` | handling (above) |
| `$86` | active (negative) |
| `$d2`, `$d6` | links to the car towing this one, and the one it tows |
| `$ea` | zone (half-gate) progress |
@@ -341,14 +344,77 @@ fits in one field. Then `$247ac` integrates every car.
A warping car (state 1) instead flies straight at a point on the track:
its velocity is the distance to it / 16.
Note that the heading vector points to the car's *rear*: pushing the
joystick forward gives a throttle of −1. This document flips that round
and talks about forward throttle as positive.
### Computer drivers
Computer cars use words 0, 1 and 5 for handling rather than 8, 9 and 10.
They steer with the sign of the cross product between their heading and
the direction to a target point, as if holding a joystick hard over. The
targets come from a table of points built along the road. The driver
picks one side of the road or the other depending on which way the road
bends, and the throttle comes from fixed values.
**The path.** At set-up (`$1ea82` onwards) the game walks the middle of
the road, the average of the two edge curves. It drops a node every 2
game units, adjusting each step by bisection until the gap squared is
between 3.8 and 4.2. Each 36-byte node (array `-$7e68(a5)`) holds:
- the centre point
- the unit vector across the road
- a point 1 unit in from each wall
- its position along the spline
A second table maps each zone to its first node.
**Each frame:**
1. The driver predicts its position four frames ahead, `pos + 4 ×
velocity`. It finds the first node that point hasn't passed: only
nodes within −2 to +8 zones of the car count, and a node is passed
once the point is beyond the line across the road there.
2. Its default target is the centre of the node 4 on, at full throttle.
3. If the predicted point is beyond the line joining one side's inset
points at that node and the one before, it's running wide. It aims
at the other side's point 2 nodes on instead, at 0.7 throttle. The
constants are Motorola fast floating point values set at `$14886`:
1.0 (negated), and that times `$b333`.
4. Steering is the sign of the cross product of its heading with the
direction from where it is now to the target, as if holding a
joystick hard over.
### Collisions between cars
Routine `$1b324` tests only the human players' cars. Each is tested
against every other active car and caravan except the caravan it tows.
So computer cars pass through each other and through caravans.
For a pair (A = the player's car, B = the other):
1. **Proximity** (`$260ba`): skip unless |dx| ≤ 2 and |dy| ≤ 2 game units
and |dz| < 17 pixels. So cars on a bridge don't hit cars under it.
2. **Strength:** k = 64 × |velocity A − velocity B|² + 20, in game units
per frame.
3. **Points:** six points on A, rotated with A, come from a table built
for every heading out of words 6 and 7: the four corners, then one on
each side at 0.58 of the half-width. Each is tested against B's box,
which is the same for every vehicle: ±0.375 across and ±0.75 along
B's heading (`$25f3c`).
4. **Push:** for each point inside the box, B's velocity gains the
point's offset from A's centre × k / 256 and A's loses the same. The
side points use 2.5 k.
5. **Spin:** each corner inside the box also turns A by k / 16 (64ths of
a turn) on its turn rate, and twice that on its heading. The sign is
the one that swings that corner away from B.
6. **Sound:** any hit plays the crash sound for both cars.
### Towing
A caravan is a car record linked from its car (`$d6`), and it's dragged
in the per-car loop at `$1cf64`:
- **Hitch:** at the back of the car, half its length (word 6) behind the
centre. The game uses the car's position after this frame's move.
- **Swing:** the caravan turns to point at the hitch, and is placed 0.656
game units behind it, by setting its velocity to the gap.
- **Jack-knife:** if the caravan ends up more than 90° from the car, both
are set to 45° either side of the angle halfway between them. So the
caravan steers the car too.
- **Warps:** when the car warps, its caravan is parked off the map until
it lands.
## Executables
@@ -360,10 +426,7 @@ bends, and the throttle comes from fixed values.
## Gaps
- **Game logic still to decode:**
- car-to-car collisions
- exactly how computer drivers pick target points and throttle
- the warp rules
- the towing physics, beyond the hitch distance
- the warp rules (when a car is warped back to the track)
- the race rules and scoring
- **Unknown data:**
- the six per-track words after each track file's palette