The code

246 lines of MSX-BASIC. The listing is at 100 % coverage: all 246 carry their own comment above them, and that comes to 702 lines of explanation for 718 statements of program.

How it breaks down

lineswhat they do
1-3STOP, the title screen and the DEFINT D
10-90arrays, the thirteen clubs, hole 1's course and the wait
110-130builds the hole's view and starts
200-295the turn: stance, club, and the shot formula
300-470the flight simulation
500-630where the ball came to rest, and the camera for the next shot
700-720hole finished, and the end of the round
900-1260the ball in the view, and the three selection screens
2000-2510reading the course out of the ROM
3000-3070finding somewhere to drop the ball
4000-4080the plan view
5000-5690the 3D view engine
6100-6900the five sounds and the silence
7000-9900scaling, scoreboard, text, panel and compass
10200-30000the nine holes' DATA and the STOP handler

The 3D engine

A classic conic perspective, written out by hand three times because there is no shared routine: in 370-372 for the ball, in 900-940 to mark where it came to rest, and in 5000-5690 for the terrain.

Subroutine 5000 makes four passes over the hole's data:

  1. Copies the outline into DN().
  2. Translates every point by subtracting the camera's position.
  3. Rotates with the Q1-Q9 matrix. Of its nine terms, six are constants: the camera turns on one axis only. It never tilts or rolls.
  4. Walks the segments, clipping each one before projecting it.

The clipping (5190-5590) is the classic one against a 45-degree view frustum: a point is outside on the left if its x is less than minus its depth, and so on for all four walls. If both ends are outside the same wall, the whole segment is out. If not, the outside end is replaced by the exact intersection and the whole thing starts over, because the moved point may now fall outside another wall. With four walls, the loop cannot run more than four times.

The projection is two divisions by the depth, scaled to half the window's width and height (71 and 63) and centred on (79,63).

Reading the course

Subroutine 2500 reads one 16-bit value from the ROM. Since MSX-BASIC has no 16-bit PEEK, it builds one:

F1=PEEK(ZM) : F2=PEEK(ZM+1)
F1$=HEX$(F1) : F2$=HEX$(F2) : IF LEN(F2$)=1 THEN F2$="0"+F2$
DI(I)=VAL("&H"+F1$+F2$)

Two PEEKs, two conversions to hexadecimal text, a concatenation and a VAL. The second piece is padded with a zero when needed; the first is not, because it sits in the high position where a zero does no harm. And since VAL of a four-digit hexadecimal returns a signed integer, negative coordinates come out on their own.

It is desperately slow, and it shows: drawing hole 1 in full takes the interpreter more than five minutes of machine time.

The text

There is no text console. Everything is written by opening the screen as if it were a file:

PSET(AX*8,AY*8),0 : OPEN"GRP:"FOR OUTPUT AS #1 : PRINT#1,E$ : CLOSE#1

The PSET is there to move the graphics cursor to the cell; the text comes out in COLOR's foreground, which is white. This was checked in the emulator's VRAM: the panel's cells read 0xF0, ink 15.

And the golfer is not a sprite or a drawing: it is eight strings, J$(0) to J$(7), written with that same trick using the graphic character set in the machine's own ROM. That is why a Japanese MSX is needed to see them properly.

The two sprites

There are only two, and they are the other way round from what you would guess: sprite 0, with the solid pattern, is the power meter's bar; sprite 1, with a two-pixel pattern, is the ball, and it moves across the plan view, not the 3D view. In the 3D view the ball is the shadow drawn by lines 390-393 - a filled circle whose radius shrinks with distance - and the dot left by subroutine 900.