3D Golf Simulation

An MSX cartridge without a single Z80 instruction: inside is a 246-line BASIC program the interpreter runs straight out of the ROM. The whole course — nine holes with their bunkers, lakes and trees — fits in 4,000 bytes of coordinates, and the game has no terrain map: it asks the screen what colour the ground under the ball is painted.

T&E Soft · © 1983 · A 16 KB cartridge · MSX1 · page 2 · Dump 95d4e9dd…

There is not one illustration or screen capture of the game here. The nine holes — the plan and the perspective view — are drawn from the cartridge's own bytes, by running in Python the program's own subroutines on an emulation of the SCREEN 2 display with its colour attributes, and compared against openMSX's VRAM: 15,737 of 15,744 pixels identical on the plan — the one the game reads to know what the terrain is — and 18,011 of 18,432 on the 3D view. The only image that does not come wholly from the cartridge is the title screen, and why is spelled out: the cartridge does not carry a single drawn letter.

The cartridge in numbers

100%of the binary accounted for
0Z80 instructions
100%of the lines explained
246BASIC lines, 718 statements
9 holespar 36, 2,990 m
4,000bytes of course

What turned up when we took it apart

An MSX cartridge without a single Z80 instruction

The first thing you do with a cartridge is disassemble it. Here you get nonsense: the entry point is nop / dec h / add a,b / ld bc,09700h / illegal sequence. It is not that the disassembler is failing: there is no code there.

The header says so if you read all of it. INIT, STATEMENT and DEVICE all zero, and the only thing declared is TEXT=0x8010: 'there is a BASIC program here'. The interpreter runs it from the ROM itself, without copying it to RAM. The game's only call to machine code, USR(0) in line 30000, points at address 0: pressing STOP resets the machine.

The game asks the screen what the terrain is

There is no logical map, no grid of cells. Line 380 takes the ball's position over to the plan view in the right-hand panel and reads with POINT the colour painted there. That colour is the terrain: 2 the fairway, 3 the green, 4 water, 6 out of bounds, 13 a tree, 14 a bunker, and 0 — the unpainted background — the rough.

Out of it come the golfer's stance, the penalties and how the ball bounces. The plan is not decoration: it is the game's data structure, and that is why the order of the colour markers matters so much.

The whole course in 4,000 bytes

The nine holes take exactly 4,000 bytes, from 0xB000 to 0xBF9F, one behind the other. Each is a list of 16-bit values running three at a time — x, height, depth — and a lone value between 30001 and 30015 is a marker: it changes the colour of what follows and, along the way, shifts the grouping by one.

The colour is not decoration: it says what the next stretch is made of, and it fills in the previous one. And the order is the same in all nine: outline, fairway, green, flagstick, bunkers, water and trees.

The flagstick is drawn in the data, and that pins the reading down

Each hole's colour-1 stretch is four points: an 8-high vertical mast and a pennant at the top. And it is planted exactly where that hole's DATA declares the flag to be, in all nine.

That matters because the DATA's order is not obvious — the flag is the last two values of the line, not the first. We know because three separate counts agree at once: the pars add up to 36 and match the PQ$ string; the fill seeds subroutine 4000 uses up are exactly the ones left over in each DATA; and the flagstick lands on its flag.

The cartridge carries a real round inside it

The 3,231 bytes between the program and the course data are the interpreter's variable table, frozen exactly as it was left in a real session of the game. That is the trick that boots a BASIC cartridge with no INIT routine: the ROM carries the program and its state already set up.

It reads in full, and it tells a story: hole 2, twelve strokes in all, eleven of them spent on hole 1. The course read pointer holds 0xB37A, which is where hole 3 begins — with hole 2 in play, its outline had already been read — and HX, HZ and P are hole 2's flag and par. Four figures that agree with the course data without using the program at all.

The 30006 does not end the hole: it ends the plan

It looked like the end of the run, and it is not. It is where subroutine 4000 stops drawing. What comes after still belongs to the hole, and the 3D view draws it: two or three stretches with coordinates up to 20,000, which are the vanishing lines out to the horizon, and on hole 3 a 2,000×400 wall at depth 1,200: the mountain in the background.

And in that view the colour is never used: line 5166 works it out and nobody looks at it, because the trace is always white. The colours only matter for the plan.

A test that can never fire, and two pieces nobody reads

Line 440 checks whether the terrain is colour 12 and slows the ball if so. That condition cannot happen: no hole paints colour 12, in any of the nine. It is dead code — most likely the rough of an earlier version, before the rough became the background colour.

And there is more of the same: D2(240) is reserved in the DIM and appears in no other line — 482 bytes of RAM set aside for nothing — and ZL$ is assigned "0000" with nobody ever reading it.

The round is played once, and the putter in sand costs a stroke

The program never issues a RESTORE, and the pointer that reads the course does not rewind either. After hole 9, line 720 is a GOTO 720: an infinite loop. Playing again means resetting, and that is not an oversight — there would be no way to rewind even if it jumped back to the start.

And a rule that is in no manual: if the ball is in a bunker and you pick the putter, line 280 sends the turn back to the start... which is line 225, the one that adds a stroke. Trying it costs a stroke every time, with the ball never moving.

What the cartridge draws

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

<b>The course's nine holes</b>, drawn one by one with the same subroutine 4000 the interpreter runs, from the 4,000 bytes of coordinates that begin at 0xB000. Red is out of bounds, black the rough, green the fairway, light green the green with the hole in it, grey the bunkers and blue the water
The course's nine holes, drawn one by one with the same subroutine 4000 the interpreter runs, from the 4,000 bytes of coordinates that begin at 0xB000. Red is out of bounds, black the rough, green the fairway, light green the green with the hole in it, grey the bunkers and blue the water
Hole 1's full screen exactly as it stands at the start: the perspective view on the left, the plan on the right. This is the image compared against the emulator's VRAM — <b>15,737 of 15,744 pixels identical</b> on the plan, which is the one the game reads with POINT. The gap at the bottom left is the panel, written with the machine's font and not with cartridge data
Hole 1's full screen exactly as it stands at the start: the perspective view on the left, the plan on the right. This is the image compared against the emulator's VRAM — 15,737 of 15,744 pixels identical on the plan, which is the one the game reads with POINT. The gap at the bottom left is the panel, written with the machine's font and not with cartridge data
Hole 1's tee view. It is all wireframe segments translated by the camera, rotated with a matrix that turns on one axis only, clipped against the four walls of the view frustum and projected by dividing by the depth. The two lines running off to the horizon are not on the plan: they are stretches that begin after the 30006 marker
Hole 1's tee view. It is all wireframe segments translated by the camera, rotated with a matrix that turns on one axis only, clipped against the four walls of the view frustum and projected by dividing by the depth. The two lines running off to the horizon are not on the plan: they are stretches that begin after the 30006 marker
Hole 2, a 155-metre par 3: <b>the only one with no fairway</b>. Its data goes straight from the outer outline to the green, without the colour-2 marker the other eight carry
Hole 2, a 155-metre par 3: the only one with no fairway. Its data goes straight from the outer outline to the green, without the colour-2 marker the other eight carry
Hole 5, with the lake crossing the course from side to side. The blue spills to the frame because the water polygon reaches the edge of the course: the interpreter's fill stops at the border colour, and there is none there
Hole 5, with the lake crossing the course from side to side. The blue spills to the frame because the water polygon reaches the edge of the course: the interpreter's fill stops at the border colour, and there is none there
Hole 9, the longest: par 5 and 482 metres, and the one that takes the most bytes of the nine (474)
Hole 9, the longest: par 5 and 482 metres, and the one that takes the most bytes of the nine (474)
The tee at hole 4, a 441-metre par 5. The further away a point is, the closer together it comes out: the perspective is a division by the depth and nothing else
The tee at hole 4, a 441-metre par 5. The further away a point is, the closer together it comes out: the perspective is a division by the depth and nothing else
The title screen. <b>This is the only image that does not come wholly from the cartridge, and it cannot</b>: the position and the text come from the program (lines 2 and 3, three LOCATEs and three PRINTs), but the letters are drawn by the character set in the machine's ROM, which is not here. The shapes come from a VRAM dump of the emulator
The title screen. This is the only image that does not come wholly from the cartridge, and it cannot: the position and the text come from the program (lines 2 and 3, three LOCATEs and three PRINTs), but the letters are drawn by the character set in the machine's ROM, which is not here. The shapes come from a VRAM dump of the emulator