1986 · Mastertronic

Prospector Pete

This minisite was contributed by air. It’s agent-generated and needs a human editor. Clone https://github.com/gamesexplained/gamesexplained and follow kit/START.md to curate games/c16/prospector-pete with me to Gold.

What the code does that the game never tells the player. A stick laid in the right cell on level 6 boxes the first creature in, and the game stops for good.

01 · Bug

Bug: a creature with nowhere to go freezes the game

When every way round a creature is shut, it looks for a way out for ever, inside the interrupt, and the game never moves on.

Level 6 frozen: the shaft full of water, Pete standing in it, and the creature boxed in at the bottom.

Left, level 6 in plus4emu after the recipe below: the water has filled the shaft and covers Pete, who does not drown, and nothing else moves. Right, the game's move_creatures ($2778) on the kit's 6502, for a creature at the bottom of the shaft at the end of a cell. Click a cell round it to open or shut it. With all four shut, the run is stopped after 100,000 instructions, still in the loop.

At the end of each cell a creature that does not chase Pete looks for an open way, starting from a random one (move_creatures). The loop at $281E-$2827 masks the way's number to 0 to 3, looks at that way, and if it is shut adds one and goes round again. The BNE at $2827 tests the number after the add and before the mask, 1 to 4, which is never zero, so it always branches. While any way is open the loop finds it. With all four shut it goes round for ever.

move_creatures runs inside irq_play, in the raster interrupt at line $AC. Stuck there, the interrupt never returns to the main loop, so main_loop never runs again: goodies are not collected, sticks do not go off, Pete cannot die, and ESC does nothing. The interrupt's other raster lines still fire, because irq_play lets interrupts in again as soon as it starts (CLI at $1997): the screen is still drawn, Pete still walks, and the water still rises. Only a reset ends it.

A player can reach it. On level 6, walk straight down the shaft from the start, lay a stick in row 20, the cell above the big charge, and climb away. The stick goes off a few frames after the big charge, and its debris forms at frame 291 of the level, just after the flood has begun below it at 285. The first creature comes out of the bottom of the shaft at frame 300, two frames before the water rises through the debris, with debris above it, the broken floor below, and earth on either side. Live, the main loop then ran no pass in 500 frames, while the interrupt ran 2,000 times. On levels 1, 5, and 14 the same play missed: the creature came out with the bottom cell still exploding, or with the water already through.

02 · Bug

Bug: a creature chasing up or down nearly always goes up

The distance up or down to Pete is worked out from the creature's column, where its row was meant.

$27A3  A5 07     LDA $07      ; Pete's row, 4 to 21
$27A5  38        SEC
$27A6  F5 8A     SBC $8A,X    ; the creature's column; its row is at $8E,X
$27A8  85 98     STA $98      ; the distance up or down, for chase_updown

From move_creatures. Three lines before, the distance across is Pete's column less $8A,X, the same operand, which is right for that one.

When a creature chases, it tries across or up and down first, at random, and for up and down it follows the sign of the difference at $98: down when it is positive, up when negative (chase_updown). That difference is Pete's row less the creature's column. Pete's row is 4 to 21 and the creature's column 1 to 88, so whenever the creature is right of column 21 the difference is negative and it goes up, wherever Pete is. Creatures come out at the bottom of the shaft, in column 44, below Pete, so going up is usually right, and the slip seldom shows. A creature above Pete and right of column 21 that chases up or down climbs away from him.

The map on the How it works tab shows it for any place: with the game's reading, a creature right of column 21 never heads down, wherever Pete is; with the row read instead, it heads down towards every place below it.

03 · Bug

Bug: creatures stop chasing in a lattice of places

A creature wanders whenever the two distances to Pete, ANDed together, come to zero: often, and in a pattern.

$27E0  A5 98     LDA $98      ; the distance up or down
$27E2  25 97     AND $97      ; ANDed with the distance across
$27E4  F0 2B     BEQ $2811    ; zero: wander

From move_creatures.

The test is meant to catch a creature level with Pete, where a distance is 0 and there is nothing to chase. ANDing the two distances does that, and also sends the creature wandering whenever the two numbers have no bit set in common, such as 8 and 6, or 12 and 3. On the How it works tab's map these places are the grey lattice to the right of the creature; to its left the distance across is negative, its high bits all set, and nearly every AND is non-zero. Together with the column slip above, a creature left of Pete wanders far more often than one right of him.

04 · Secret

Secret: debris walls the creatures out

The debris a stick leaves stops a creature, though Pete walks through it.

$27C7  B1 84     LDA ($84),Y  ; the cell on that side
$27C9  C9 5C     CMP #$5C
$27CB  90 0E     BCC $27DB    ; below $5C kept as it is: only 0, tunnel, is open
$27CD  C9 6D     CMP #$6D
$27CF  90 08     BCC $27D9    ; water, $5C-$6C: open
$27D1  C9 6F     CMP #$6F
$27D3  F0 04     BEQ $27D9    ; a stick: open
$27D5  C9 A2     CMP #$A2
$27D7  D0 02     BNE $27DB    ; an explosion open, anything else shut, debris ($A3) too

From move_creatures: a way is open when the cell holds 0 (tunnel), water, a stick or an explosion, and shut otherwise, debris included. can_enter lets Pete into debris and clears it ($21AA).

A stick laid across a tunnel leaves a wall that only Pete can pass. Live, on level 1, with debris poked into the shaft at row 15 before the first creature came out, the creature climbed to row 16, turned back, and went on only after the water had risen through the debris at frame 445. Without the debris the same creature reached Pete at the top of the shaft by frame 613. The water flows into debris as into tunnel, so the wall lasts until the flood reaches it.

05 · Secret

Secret: water puts out a burning stick

A stick the flood covers never goes off.

$2BA8  DE 02 07  DEC $0702,X  ; one frame less on this stick
$2BAB  F0 0A     BEQ $2BB7    ; run out
...
$2BB7  B1 0D     LDA ($0D),Y  ; what is in its cell now
$2BB9  C9 6F     CMP #$6F     ; still a stick: explode
$2BBB  F0 22     BEQ $2BDF
$2BBD  C9 A2     CMP #$A2     ; an explosion: leave debris
...                           ; anything else, water: off the list

From dynamite.

When a stick's count runs out, dynamite looks at its cell again. A stick goes off and an explosion turns to debris, but a cell the water has filled in the meantime is simply taken off the list. Live, a stick put in the shaft at row 20 with 255 frames of fuse was covered by the water at frame 345 of level 1 and left the list without exploding when its fuse ran out at frame 455; the same stick with 100 frames exploded at frame 300. In the mine on the How it works tab, a stick laid low in the shaft just before the flood goes out the same way.

06 · Quirk

The room check for the bottom row reads the zero page

Where a goodie goes in the deepest row depends on the game's own variables.

$2DA7  B1 11     LDA ($11),Y  ; a cell of the 4 by 4 block round the place
$2DA9  C9 70     CMP #$70     ; a goodie there?
$2DAB  B0 94     BCS $2D41    ; then try another place

From find_space. The block starts one row above and one column left of the place and runs four rows down.

Before placing a goodie, find_space checks the four-by-four block round the place it has picked for any byte of $70 or more, so that goodies never touch. For a one-cell or two-wide goodie in row 21, the lowest it can go, the block's last row is row 23, below the map. The map ends at $3FFF, and on the C16, whose 16 KB of RAM repeats through the 64 KB, the address after it is the zero page again. Row 23 is the game's variables from $00 to $5A, and where one of them holds $70 or more, a goodie in the row above is refused and placed again elsewhere.

A player could never tell. It shows when the level builder runs on 64 KB of plain memory: from the same timer readings it made a different mine for level 16 than the game did in plus4emu, and the same mine once $4000 read the zero page, as this site's pages run it. On a Plus/4, with 64 KB of real RAM, the same tape would read whatever lies at $4000 instead (inferred from the memory map).

07 · Quirks

Smaller oddities in the code

Slips that change nothing a player sees.

  • The view asks to scroll right at its right end, every frame. scroll_view stops a move at the left end of the map by comparing with the first column, but at the right end it compares the view's edge with $77, column 119, which it never reaches. With Pete near the right end the move is asked for on every call and stopped at the start of the next, with nothing to see. Live: with Pete at column 88, $08 read 1 after every frame and the view did not move.
  • The jingle at the end of a level reads TED where it seems meant to write. At $18BB it loads 3 and then loads $FF10 over it, so voice 2's high pitch bits keep whatever they held. The lines round it all store to TED, so a STA was probably meant (inferred from the code). After Pete's climb up the shaft they hold 1, and voice 2 plays almost two octaves under voice 1, where a store would have put the two voices 9 Hz apart; the Sound section of How it works plays both.
  • The large goodies' list sits on the KERNAL's vectors. place_goodies keeps the addresses of up to ten large goodies at $0316, over the vectors for BRK and OPEN to GETIN. The game never calls the KERNAL, so nothing reads them.
  • The kill bonus is paid once for each pass of the creatures. kill_bonus adds 150 points however many creatures one explosion kills in the same pass.
  • Level 6 burns faster than level 7. level_fuse runs 120, 110, 110, 105, 100, then 90 on level 6 and 95 on level 7.