At the controls
| Steer | ←→ or AD |
|---|---|
| Speed up | ↑ or W |
| Slow down | ↓ or S |
| Fire | Space or Z |
| Game reset | Enter |
| Pause / mute | P / M |
A gamepad works too: stick or D-pad to fly, any face button to fire, Start for reset, Back to pause.
About this port
Carol Shaw's endless river, rebuilt for the browser from the cartridge's own tables and the labelled 6502 disassembly. No emulator, no external assets — and a second, high-resolution presentation, Petro Raid, that turns the same raid into a desert oil corridor.
Two graphics modes
Petro Raid is the default. It keeps the cartridge's zero-page state, block generator, collision masks, scoring, fuel and timing, but renders the world as a high-resolution desert waterway. The Petro Raid / River Raid switch on the main page swaps the presentation instantly; the simulation does not change.
The banks become desert sand with wet shorelines, foam and rocks. Collision geometry still comes from the original 160 × 199 playfield and sprite masks, so the new artwork never changes what the game counts as a hit.
Petro Raid's score readout is the price of a barrel of crude oil, starting at $200.00. The price is tracked in whole cents, so every few hits visibly removes pennies. The curve is anchored to the player-distribution figures:
| Score | Players reaching it | Barrel price |
|---|---|---|
| 0 | 100% | $200.00 |
| 5,000 | 98% | $196.00 |
| 15,000 | 39% | $78.00 |
| 35,000 | 18% | $36.00 |
| 50,000 | 14% | $28.00 |
Between anchors the price interpolates in cents. Above 50,000 points the last $28.00 drains over another 50,000 points and clamps at $0.00, so it can never go negative. The underlying point score is still tracked and shown in small type on the HUD.
| Steer | ←→ or AD |
|---|---|
| Speed up | ↑ or W |
| Slow down | ↓ or S |
| Fire | Space or Z |
| Game reset | Enter |
| Pause / mute | P / M |
A gamepad works too: stick or D-pad to fly, any face button to fire, Start for reset, Back to pause.
The river is never stored. Each 32-line block is built just before it scrolls in by the cartridge's 16-bit LFSR, which starts from $A814 every game.
A section is 16 blocks and ends at a road with a bridge. Odd sections run straight; even sections wind and split around islands. Higher levels bring more enemies and fewer fuel depots.
In Petro Raid the water is a desert channel, but the generated width, islands, object positions and section timing are the cartridge's.
You start with three jets and earn another every 10,000 points, up to nine.
Under the hood
The game state is the cartridge's zero page: a 256-byte array where every variable stays at its original address, from blockLst at $8E to sound0Id at $F8. The block generator, object spawner, enemy patrolling, collisions, scoring, fuel and sound routines are ported from the disassembly instruction by instruction. Both graphics modes read that same state.
The playfield pages at $FC00/$FD00, the object shapes at $FE00, colour tables at $FF00 and the digit glyphs at $FB00 are read straight from the 4,096-byte ROM by tools/extract_rom.py.
River Raid draws the original kernel line schedule. Petro Raid reads the same 160 × 199 masks and paints a 1280 × 796 desert scene, placing each new vehicle from the cartridge's original sprite bounds.
Collisions are evaluated at the same two points inside each block where the ROM reads the TIA latches, using per-line pixel masks. That keeps the original block-based collision quirks, including the seventh-block edge case, in both modes.
The ROM's AUDC/AUDF/AUDV writes drive a software TIA: two channels, polynomial noise, pure tones and a DC blocker, at the 31.4 kHz audio clock. Petro Raid uses the same sound registers.
From the cartridge
These are the cartridge's River Raid shapes. Petro Raid replaces them in the renderer, but the original sprite bounds still drive placement and collisions.