King's Valley

A game that stores nowhere where the road is -it READS it off the screen-, a routine hidden inside its own pointer table, and two builds that differ by a single byte.

Konami - (c) Konami 1985 - An RC-730 16 KB cartridge - MSX1 - page 1 - Dump 6d36c9e9...

Not one capture here. Every picture is drawn from the bytes of the ROM, by running in Python the same two script interpreters the Z80 runs. The listing and the numbers are reproducible with make, and reassembling gives back the ROM byte for byte.

The cartridge in numbers

100%of the binary explained
482named routines
55.1%of the listing commented
7,797bytes of code
8,587bytes of data
0bytes unidentified

What turned up when we took it apart

The collision map is the screen itself

This cartridge stores nowhere where the road actually is. To find out whether the car has touched the verge it reads the screen: the routine at 0x6D8B works out the cell the car is in, asks the VDP for it with SETRD and pulls back, with a single in a,(c), whatever tile is drawn there.

Then it sorts it into bands: below 0xCF it is a certain crash, 0xCF to 0xD8 is clear, and 0xD9 to 0xE8 is the verge and needs pixel-level checking. It is the cheapest way to make the car hit what you can see, whatever the road happened to paint there.

The road does not exist: it is manufactured, row by row

There are no track maps. There is a ring of RAM, twenty-four rows by twenty-two columns at 0xE186, and every time the road moves the pointer steps back one row and a new row goes into the gap it leaves. Not one byte of scenery moves: what moves is where you start reading.

And the new row is built by an engine with one branch per stage: stage 2 pastes four columns from a cyclic list, stage 3 pulls the whole row out of a single sixteen-bit word, stage 4 stores seven columns and computes the mirror by adding 0x0D to each tile, stage 5 does the same with four, and stage 6 is like 3 but also redraws the lane markings on top.

The six roads on this page are drawn by running that engine in Python, routine by routine. The check is not that they look right: it is that across 264 steps compared against openMSX -44 per stage- the entire 528-byte ring and every generator variable came out identical to the machine's.

A routine hidden inside its own pointer table

0x5540 does call 05716h, and 0x5716 lands inside the scenery pointer table at 0x570C: it is its last two bytes. Konami uses them for two things at once. Read as a word they are the table's sixth entry; executed they are the ld hl,(0e046h) that starts the routine which advances the ring.

The giveaway is that the sixth entry points at 0x462A - a jr inside the RLE decompressor, which is no scenery artwork at all. The table has five entries, and what follows is already code. These thirty-six bytes spent the whole disassembly classified as data nobody reads.

The two builds differ by ONE byte

Two dumps of this cartridge are in circulation. They differ by a single byte, 0x53CB: one has 0x05, the other 0xFF.

That byte is the fifteenth segment in the stage 5 row of the plan at 0x537D, six rows of sixteen bytes each closed with 0xFF. Measured in the emulator by placing the pointer at the end of that row: the 0x05 version plays fifteen segments per cycle and the 0xFF one, fourteen. The one that vanishes is segment 5.

Which of the two plays harder is not claimed here, because it has not been measured. The "Easy" and "Hard" labels they circulate under come from the dump, not from the ROM.

The car has a dead band of speed

Under acceleration the car moves up the screen by 0x48 of 256 of a pixel per frame. But not always: the routine at 0x6C93 only lets it move while the speed is between 0x18 and 0x50, or above 0x7E. Between 0x50 and 0x7E it stays put.

This is measured, not inferred: across 900 frames of the attract mode the car's Y sits still at 0x8FC0 while the speed climbs from 0x51 to 0x7D, and starts moving again the moment it passes 0x7E. 57 of the 58 comparable frames match the prediction, and the one that does not falls exactly on the boundary between two samples.

CHECK POINT, and GOAL only on the last one

The end of a stage has three marks nine apart, which is nine ring rows: at 0x0F00 of distance the rival car is released, at 0x0F09 the finish sign is painted and at 0x0F12 it is crossed.

And the sign is not always the same: the first five stages get the eleven tiles of CHECK POINT, and the sixth the five of GOAL, three columns further right. They read with the same rule as every other text in the cartridge -the pattern index is the ASCII code minus 0x20- and were confirmed by drawing them out of the emulator's VRAM.

The symmetrical road comes free

Stage 3 draws the whole row from a single sixteen-bit word: each bit picks one of two tiles. Twelve columns are asked for and then ten more, but the second call reloads the same word from the start, because the pointer has not moved.

The upshot is that columns 12 to 21 repeat the pattern of the first ten: the road comes out symmetrical without spending one extra byte or one extra instruction. It is not an oversight, it is the saving.

Colours sit below patterns, the wrong way round

In SCREEN 2 the usual layout is patterns at 0x0000 and colours at 0x2000. Here it is the other way round, and the eight bytes the cartridge loads into the VDP registers say so - the table at 0x46A9, which reads 02 E2 0E 7F 07 76 03 E4: R3=0x7F puts colours at 0x0000 and R4=0x07 patterns at 0x2000.

R3 and R4 are not addresses, they are a base and a mask, and reading them as if they were gives a result that looks right: the shapes come out fine and the colours come out in stripes. The cartridge itself confirms it, filling the area at 0x0080 with 0xF0 at 0x477F, and 0xF0 only makes sense as a colour.

The level does not just change the difficulty: it changes the cartridge

LEVEL A and LEVEL B are not a multiplier. The level, which lives at (0xE03B), gets involved in four separate places: it doubles or does not double the sideways push objects come out with (0x706D), it changes the fuel-burn step - 0x0180 against 0x01FF, at 0x7374 -, it changes the object spawn delay between seven and twelve (0x6F72), and it removes an entire segment: on the first level segment 0x0A is swapped for 9 (0x7044).

Konami's hidden mark

The last fifteen bytes of the cartridge are read by nobody: they are RC-730 and the title in katakana, ロードファイター, written backwards and closed with the length, the two RC digits in BCD and an 0xAA.

The format of that signature was discovered by Manuel Pazos, and without his find these fifteen bytes would have stayed filed under "data nobody reads". Our thanks.

What the cartridge draws

Under each picture is where it comes from and what is on it.

<b>The title screen</b>, built by running the cartridge's own steps. The big wordmark slides in from both sides, which is why the word ROAD is stored <b>backwards</b> in the ROM, with its 0xFF in front
The title screen, built by running the cartridge's own steps. The big wordmark slides in from both sides, which is why the word ROAD is stored backwards in the ROM, with its 0xFF in front
The <b>start line</b>, with the finish arch and the START sign. This screen comes from no list: the routine at 0x77C8 builds it by hand, pasting eight patches one after another, each call inheriting the destination the previous one left behind
The start line, with the finish arch and the START sign. This screen comes from no list: the routine at 0x77C8 builds it by hand, pasting eight patches one after another, each call inheriting the destination the previous one left behind
<b>Stage 1</b>, a hundred and twenty rows in a row. Not a capture and not a map: it is the cartridge's road engine run in Python. You can pick out the houses with their hedges, the swimming pool, the parked cars, the tennis courts and a <b>Konami</b> billboard near the top
Stage 1, a hundred and twenty rows in a row. Not a capture and not a map: it is the cartridge's road engine run in Python. You can pick out the houses with their hedges, the swimming pool, the parked cars, the tennis courts and a Konami billboard near the top
<b>Stage 2</b>: the beach. The road narrows towards the end of the stretch, and the four columns on the left come from this stage's own cyclic list, the one at 0x7DC5
Stage 2: the beach. The road narrows towards the end of the stretch, and the four columns on the left come from this stage's own cyclic list, the one at 0x7DC5
<b>Stage 3</b>: the only one that draws the whole row from a word of bits, and the only one with its own road tiles - 0x9B and 0x04 instead of 0x80 and 0x0F - which is what gives it that different edge
Stage 3: the only one that draws the whole row from a word of bits, and the only one with its own road tiles - 0x9B and 0x04 instead of 0x80 and 0x0F - which is what gives it that different edge
<b>Stage 4</b>: the S-bend. Only the seven columns on one side are stored; the ones on the other are computed by adding 0x0D to each tile, which is the jump from a drawing to its mirrored version
Stage 4: the S-bend. Only the seven columns on one side are stored; the ones on the other are computed by adding 0x0D to each tile, which is the jump from a drawing to its mirrored version
<b>Stage 5</b>, the one that tells the two builds apart. Byte 0x53CB, the only difference between them, is the fifteenth segment of this row of the plan
Stage 5, the one that tells the two builds apart. Byte 0x53CB, the only difference between them, is the fifteenth segment of this row of the plan
<b>Stage 6</b>: the last one, the one that ends with GOAL instead of CHECK POINT. It brings its own set of scripts - shared with none of the others - and another <b>KONAMI</b> billboard, this one in capitals
Stage 6: the last one, the one that ends with GOAL instead of CHECK POINT. It brings its own set of scripts - shared with none of the others - and another KONAMI billboard, this one in capitals
The <b>stage 1 tiles</b> with their colour, exactly as they end up in VRAM. At the top the complete font, ordered like ASCII from the space onwards; that is why the cartridge's text reads by subtracting 0x20 from the pattern index. SPEED and FUEL are in there too, and the Konami billboard
The stage 1 tiles with their colour, exactly as they end up in VRAM. At the top the complete font, ordered like ASCII from the space onwards; that is why the cartridge's text reads by subtracting 0x20 from the pattern index. SPEED and FUEL are in there too, and the Konami billboard
The <b>sprite patterns</b>, in white because on the MSX1 a sprite's colour lives in its attribute and not in the pattern. The cars in their poses are all there, the explosions, the flags and the score pop-ups: <b>300, 500, 800 and 1000</b>
The sprite patterns, in white because on the MSX1 a sprite's colour lives in its attribute and not in the pattern. The cars in their poses are all there, the explosions, the flags and the score pop-ups: 300, 500, 800 and 1000