Konami's Billiards

Sixteen kilobytes of which the game uses eight: it boots, hooks the interrupt and settles into a jr $ forever. The whole game fits inside the video hook, split across sixteen states, and inside it there is collision physics with trigonometry, square roots and forty-five degree bounces.

Konami · ©KONAMI 1984 · Cartridge RC-706, 16 KB · MSX1 · page 1 · Dump 38741612…

There is not a single screenshot here. Every picture is reconstructed: a tool replays the cartridge's loading routines and its two drawing interpreters, instruction by instruction, onto an empty video memory, and then develops that VRAM the way the VDP would. The table coming out right is the proof that the routines have been understood. The listing and the numbers come from the binary and are reproduced with make.

The cartridge in numbers

100%of the binary explained
16game states
333routines identified
5,343bytes of code
11,041bytes of data
0bytes unidentified

What turned up when we took it apart

There are only seven balls on the table, and the eighth entry is not a ball

The table array (0xE100) holds eight sixteen-byte records, but the physics loop only walks seven: it stops at 0xE16F. The eighth, 0xE170, is the point being aimed at, and subtracting the cue ball's position from it is what gives the shot vector (0x4CA8).

It is drawn like the rest — it is that small dot to the right of the table — because the sprite refresh dumps two groups of four, that is, all eight entries.

Two balls that do not exist, placed there to reuse one routine

0xE18F and 0xE1EA hold nothing. They are positioned so that their +7 and +9 bytes land exactly on a pair of loose variables, which is where a real ball keeps the two components of its velocity.

With that, the routine that extracts a ball's slope and angle (0x5430) works without changing a single line to measure the angle of the line joining two centres, in a collision, and the angle from the cue ball to the aiming point, in the attract mode. A well-chosen pointer instead of a second routine.

The attract mode plays by pressing the button from the inside

There is no separate game code for the demonstration. What 0x5EEC does is measure the angle from the cue ball to the first ball still on the table, compare it with the angle to the aiming point and, when they match within one degree, write 0x10 into 0xE009.

0xE008 and 0xE009 are the two variables where the game keeps last frame's keys and this frame's; 0x10 is the fire button bit. The machine does not call the shooting routine: it fakes the keypress and lets the game read it as if a person had made it.

A forty-five degree bounce without a single multiplication

The pocket mouths are chamfered diagonally, and the cartridge resolves them by looking at the sum and the difference of the two coordinates: along a 45° diagonal, one of the two is always constant.

And bouncing off it is just swapping the two velocity components (0x5923), or swapping them and negating both for the other diagonal (0x593B). Reflecting in a 45° mirror is exactly that, and it costs nothing.

A square root that rounds, and not by accident

0x5376 takes the root by the method of odd numbers: subtract 1, then 0, then 2 and 2, then 4 and 4… and return how many rounds it survived. It is about a dozen bytes.

Run over all 65,536 possible inputs, it returns exactly round(sqrt(n)): the root rounded to the nearest integer, not truncated, which is what these routines usually give. It is used for the distance between ball and aiming point, and half a pixel matters when the shot direction comes out of it.

The power bar cannot be set: it swings on its own

The SPEED indicator does not respond to the keys. The very routine that draws it (0x5314) also advances it one step every time it is called, cycling 1, 2, 3, 1, 2, 3… The call comes in once every sixty-four frames.

So shot power is not chosen, it is caught: you press the button at the moment the bar sits where you want it. The machine, in attract mode, only shoots with the bar at maximum.

This cartridge does not carry Konami's hidden mark

Manuel Pazos found that Konami cartridges of this period hide their RC-7xx catalogue number and the title in katakana at the end of the ROM. It is not here: there is not a single RC-7 in ASCII anywhere in the 16 KB, and the end of the chip is 8,269 bytes of 0xFF running from 0x5FB3.

The RC-706 on this page's fact line comes from the catalogue, not from the binary.

What the cartridge draws

Under each caption is the address it comes from. They are all reconstructed: make imagenes rebuilds them and no emulator is needed.

RECONSTRUCTED — the whole table, laid out the way 0x4A39 lays it: the plan at 0x4C59 is a strip of [how many rows][compressed block] unrolled from row 7 down. On top, the eight entries from 0x461F: the cue ball, the six coloured ones in a triangle and, to the right of the cloth, the aiming point
RECONSTRUCTED — the whole table, laid out the way 0x4A39 lays it: the plan at 0x4C59 is a strip of [how many rows][compressed block] unrolled from row 7 down. On top, the eight entries from 0x461F: the cue ball, the six coloured ones in a triangle and, to the right of the cloth, the aiming point
RECONSTRUCTED — the same table with no sprites. The six pockets are visible and, at the four corners, the 45° chamfers the code resolves using the sum and the difference of the coordinates
RECONSTRUCTED — the same table with no sprites. The six pockets are visible and, at the four corners, the 45° chamfers the code resolves using the sum and the difference of the coordinates
RECONSTRUCTED from 0x4A70 — the 59 table tiles with their colour. The patterns are copied verbatim and the colours come compressed separately, at 0x4C40, in the same format as the rest of the artwork
RECONSTRUCTED from 0x4A70 — the 59 table tiles with their colour. The patterns are copied verbatim and the colours come compressed separately, at 0x4C40, in the same format as the rest of the artwork
RECONSTRUCTED from 0x4B30 — the 16×16 sprite drawings: the cue ball, the six numbered ones and the aiming dot. The ninth is not a drawing: the 288 bytes copied overrun the end and land on the table's compressed colours
RECONSTRUCTED from 0x4B30 — the 16×16 sprite drawings: the cue ball, the six numbered ones and the aiming dot. The ninth is not a drawing: the 288 bytes copied overrun the end and land on the table's compressed colours
RECONSTRUCTED from 0x5788 — the green BILLIARDS from the title screen. That is fifteen two-tile columns, not fifteen letters: the animation at 0x48B8 releases one column per call
RECONSTRUCTED from 0x5788 — the green BILLIARDS from the title screen. That is fifteen two-tile columns, not fifteen letters: the animation at 0x48B8 releases one column per call
RECONSTRUCTED from 0x4136 — the 48 glyphs the cartridge carries itself, loaded into tiles 0x30 to 0x5F. Since those numbers match ASCII, the text lists spell the words out literally
RECONSTRUCTED from 0x4136 — the 48 glyphs the cartridge carries itself, loaded into tiles 0x30 to 0x5F. Since those numbers match ASCII, the text lists spell the words out literally
RECONSTRUCTED from 0x498D — the 26 tiles of the KONAMI logo, decompressed and laid out in the rows of 3, 11 and 12 tiles that 0x491E uses as it scrolls them up the title screen
RECONSTRUCTED from 0x498D — the 26 tiles of the KONAMI logo, decompressed and laid out in the rows of 3, 11 and 12 tiles that 0x491E uses as it scrolls them up the title screen