Loading listing…
1986 · Micro Power
Every routine, table and variable the game uses, with the names and descriptions given to them. Click an operand to follow it; the counter beside a label lists what refers to it. The reference below the fold is rendered from the game's facts file.
Current truth for this game. The workflow lives in kit/skills/; how this understanding developed lives in agent-history.md. Every fact names the routine or table it comes from. Unless marked live, a fact comes from reading the code in work/entry.vsf, the hand-over snapshot named in orientation.md.
A single packed program file (orientation.md). The depacker leaves the game at $484D with the KERNAL banked in; the game banks it out itself ($01 = $35) and banks it back only to save ($958A). A loader stub at $7F00-$7F52 that prints "PLEASE WAIT -- STILL LOADING" and jumps to $484D, and a prologue at $4800-$484C that never runs, are left over from the release the file was made from.
| Thing | Where |
|---|---|
| Zero page | every variable named in symbols.json: countdown $1B-$1D, lives $1E, battery $1F, camera $20-$2D, programmer $2F-$3B and $FF, pockets $3C-$41, markers $42-$45, throws $46-$4D, score $57-$59, oxygen $F1 |
| Glyph-merge operand pointers | $03-$16, pixel masks $17-$1A, copied from $4A4E |
| Status screen and its font | $0400, glyphs for codes $94-$FF at $04A0-$07FF |
| Splinx Programmer | font $0800, sprites $0B00, screen $0C00, colours parked at $1000 |
| Map row pointers | $0A80/$0AC0 |
| Block pointers, terrain classes | $1400/$1500, $1600 |
| Item names, lives field, digit glyphs | $1770, $1720, $1730 |
| Object tables, 80 objects | $1850-$1EFF |
| Music | $1F00-$2D3F, player $74C0-$7649 |
| Character colours | $2F00 |
| Block definitions, 256 x 4x4 characters | $3000-$3FFF |
| Play-area character set | $4000-$47FF |
| Status screen source | $4B00-$4EFF |
| Sprite images | $5000-$73FF, pointers $40-$CF |
| Play screens | $7800 and $7C00; $7800-$7D7F is also the save block |
| Code | $484D-$4A85 (start-up), $7440-$7649, $8000-$CFF5, $FC8C-$FF6E |
| Cavern map | $E000-$FBFF, under the KERNAL |
$7476) waits in $80DA for raster line $FA once per pass, so a pass is at least one PAL frame, 50 a second when nothing overruns.$80DA counts frames in $53-$55. It subtracts 1, in decimal, from the three-byte counter $1B-$1D only when $53 and $54 wrap to zero together (the BNEs at $80EA and $80EE), once every 65,536 frames, about 21.8 minutes; the AND #$3F test after them is then always true.$4996-$499C, leaving $1D,$1C,$1B = 01 08 00) and at 010805 on a later new game ($9408-$9414). No code prints it; it is added to the score at the end (below).$8F24 reads the stick in control port 2 ($DC00) and six keyboard rows, each into its own zero-page byte, and sets movement flags (traced: $8F3C-$9058):
| Input | Flag | Effect |
|---|---|---|
| stick left, Z | $CB = $81 | walk left (live) |
| stick right, X | $CB = $01 | walk right (live) |
stick up, ; | $CC = $01 | climb up |
stick down, / | $CC = $81 | climb down |
| fire, RETURN | $CD = $FF | jump |
| F1 | $D0 | move the pocket selector $3C through 0-4 (live: 0, 1, 2, 3, 4, 0) ($A530) |
| F3 | $CF | put the held item in the first free pocket, a marker in its slot, or with empty hands take the selected one out ($A575) |
| F5 | $D2 | standing still, pick up the object in front ($A6B4, $A929); use the held item ($BB28) |
| F7 | $D1 | with a direction, throw the held item ($A68A) |
| S | $D3 | the Splinx Programmer (live) |
| R | $E8 = $12 | forced regeneration (live: message, lives 5 to 4) |
| D, CTRL+D, L | $E8 = $80, $C0, $FF | the save menu, but only where the Doctor stands on tile $23: everywhere else doctor_update clears $E8 ($C902-$C909; live: D beside the TARDIS does nothing) |
Three raster bands ($8010-$80D7), checked against the emulator's picture by a frame capture (live: frame.py compare, 104,448 of 104,448 pixels):
$D018 = $11, screen $0400, characters from $0000. The status bar uses codes $94-$FF, so the video chip reads its font from $04A0-$07FF, the rows of the same screen below the status bar. Start-up copies $4B00-$4EFF there and builds the letters and digits from the character ROM ($48F5-$493E): code $DC is A, $F6 is 0. Digit 9's glyph would sit under the sprite pointers at $07F8, so 9 is drawn with code $F5 ($1730).$D018 = $E3/$F3 (screen $7800 or $7C00, characters $4800), fine scroll from $5E and $5F.$D018 = $E1/$F1, characters $4000. $7440 clears $4800-$4FFF, so the one character row of band 2 is blank.$E000-$FBFF, row r at $FB80 − $80r; each block is 4x4 characters from $3000. Two screens are drawn in turn and swapped ($52), the coarse scroll spread over three frames ($8C32) and the hardware scroll in between.$2F00 ($8EB8).$56, $AA3D, every 8 frames); a zone swaps in its own shapes for 16 characters ($ABCF) and wakes its own objects.$81DA, $8133); objects $30-$4F can also be drawn into the background as characters, composited per pixel pair into 32 spare character codes ($8310, $8652).$AE02, state $1D00-$1D10).$0C00 and on the loading picture left at $0400 in the hand-over image.A = $DC ... Z = $F5), a digit n is $F6 + n, $94 is a space and $00 ends a string.$1770 + $1720[object]: 2 SPLINX, $30-$33 MARKER 1-4, $34 PICK AXE, $35 MAT, $36 CRYSTAL, $37 PASS CARD, $38 SPANNER, $39 PLATFORM, $3A AIR MASK, $3B BOX, $3C/$48/$4C DETONATOR, $3D EXPLOSIVES, $3E CAPSULE, $3F ACTIVATOR, $40-$45 and $4A CIRCUIT, $46/$47 EGG, $49 CHEMICALS, $4B GEM, $4D-$4F SPANNER.$1B55 = 0) level with a controller and within 10 pixels in x stops it ($CDD6, controller_stop $CE78). The Doctor jumping up within 20 x 8 pixels of the PLATFORM is put in the airborne state $0A with $E7 = $FF ($C975-$C9A2). doctor_ride_platform ($CCE2) then moves him by the stick: up until he is $50 (80) pixels above it, down until level with it, which ends the ride, as does a horizontal distance of $14 or more or reaching a ladder (state 8). $A9E8 refuses to pick it up meanwhile. A free EGG within 20 x 12 pixels of the Doctor sets $E8 = $16 (death by a baby madrag) and places object $0D at the egg ($B861); the madrag returns moved eggs to the nests at $B665 and takes one from Splinx ($B752). No routine was found that tests for the BOX ($3B) by number, and no absolute operand in the code addresses its entries in the object tables ($1850-$1DF0 + $3B); only the indexed routines shared by all items touch it. The CHEMICALS ($49) are tested at $BA8D: lying at y exactly $0588 and within $50 of x $0290, they set the states of controllers $1A and $1B ($1CCA, $1CCB) to 3, which only draws them, in colour 2 ($CD92), and set the colours of characters $A1 and $3A ($2FA1, $2F3A) to $0C, recolouring the pool ($AE81). The restore after a lost life skips objects $1A and $1B ($93C7-$93CD).$95CB/$9626, printed by a scroller on status row $0450 in step with raster $C8 ($92E3).$1E = 5 at the start (live), one figure each in the item-name field at $1770 ($94AC), which the status bar shows when the Doctor holds nothing. A death decrements it ($912F); below 0 is GAME OVER.$E8 holds twice an index into the message table at $90EF ($9109):| $E8 | Cause | Set at | |---|---|---| | $06 | THE EXPLOSION | $C1F6 | | $08 | prints GAME OVER as the cause | $C0C2, when the rising level $51 passes the Doctor | | $0A | A SHOCK FROM A CONTROLLER | $CE5A | | $0C | A FALL, a drop of $60 or more | $CD8B | | $0E | FALLING ON A STALAGMITE, tiles $74/$51 | $CA67 (live) | | $10 | SUFFOCATING | $CAC2 | | $12 | FORCED REGENERATION, key R | $9051 (live) | | $14 | SUFFERING A MADRAG BITE | $B96F | | $16 | BEING ATTACKED BY A BABY MADRAG, near an egg | $B902 |
EXPOSURE TO RADIATION is a message nothing in the table points at.
$1D29, nine points in $9059-$907C); $907D makes a point current when he comes within $14 of it.$F1 is set to 50 and counts down once a pass while the Doctor's Y high byte is 2 or more (unless the tile is $39/$04) or he stands on tile $3F; holding the AIR MASK refills it; at zero he suffocates ($CA90-$CAC2). live: 0 and untouched while he walks the start cavern (Y below $0200).$A0D4).$3E-$41, four marker slots $42-$45; two thrown items can be in flight ($46-$4D).$FF: 0 shut down, 1 follow the Doctor, 2 execute the program. The program is ten steps at $30-$39; commands 1-4 go to markers 1-4, 5 returns to the Doctor, 6 waits, 7 picks up the nearest free item, 8 drops it, 9 recharges on character $5E. The battery $1F is 24 when full (live) and loses 1 every 1024 frames while Splinx follows or runs a program ($B1EA); recharging adds 1 every 8 frames. In the programmer, the stick moves the command cursor $3A (live) and the step pointer $2F; fire stores the command.$0E, $A13C) visits eight stops in turn and waits 127 frames at each; the carrier (object $0F, $A2B9) runs between two ends. The Doctor boards the carrier only at Y exactly $0450 ($A395) and the lift only at a height difference of exactly 8 ($A294).$10-$28. Waypoint walkers ($C28E), patrols on routes at $C404 ($C44D), and controllers on routes at $764A ($CD9A) whose touch kills.$0A, her legs, and $0B, her head and body, placed 21 pixels higher by $B861) guards two eggs, fetches an egg that has been moved back to its nest, takes one from Splinx, and bites; its behaviour runs twice a pass ($B680). A baby madrag ($0D) hatches when the Doctor comes near a free egg.$0C goes after the CRYSTAL, from the Doctor's hands or a pocket, and carries it off ($B48A). It is one sprite, frames $9A-$A1 ($B46F), drawn at double height ($18AC = 1). The code does not name it; players know it as the Master.$B500, $B571): taking the crystal from the Doctor sets his $1CB0 = $79 ($B544); while it is positive he is drawn in frame $55, lying down, and it counts down ($CB60). At his home point ($0DA8, $0380) the Master moves the crystal to ($06C8, $06A8) as a free item ($B587), sets switch cell 12 to block $1C for $FF counts, then back to $BC ($B477).$BACC): the pick axe digs at three sites, three hits each; the spanner works at eight points; detonators and explosives are armed; the activator at three points ends the game ($E8 = 2, the escape pod); the pass card opens a way ($16A0).$C09A): an armed charge counts down, flashes, then destroys every object within $20 ($80 sideways for the explosives) and may kill the Doctor. The explosives blown near ($0E60, $0068) start a rising level $51, one step every 128 frames.$B9B6): circuits set exactly in their slots at Y $0390 stop four moving objects ($4F). Each circuit's sprite is a letter: the five in the machine spell START ($40 S, $41 T, $42 A, $43 R, $4A T), the spares are $44 O and $45 P. Slots 1-4 must read S, T (either), O, P to stop it ($B989, slot 5 not tested) and START to restart it ($B97F); chemicals left at ($0290, $0588) recolour the pool and stop two controllers.$BD35-$BFD9): three buttons, a six-press sequence dealt from a 186-byte deck with seeds from the frame counter; a wrong press deals a new one; success sets $4E. The clue panel (F5 with empty hands at x $0A14-$0A33, y $05C6 up) shows in turn a number 1-5 ($A1-$A5), a shape and a letter W R B G Y ($F6 $F5 $F7 $F8 $F9); the shapes 0-5 are characters $FD $FA $FE $FB $FC $FF, drawn in the hand-over image's graphics set as triangle, square, circle, cross, diamond and question mark. Deck byte = 8 x colour + shape; the code is the six bytes from the (number)-th occurrence of the clue's colour and shape, so its first shape is the clue's. The deck's first seven entries match the outer band of the printed code card read from its top corner (by eye, from the contributor's photograph). Success also sets switch cell 13 to block $D5 ($BF62). The $4E test at $BB05 is overwritten by the PASS CARD test at $BB15.$CE28, $C9A5, $CF24): controller $22 is the only one whose flag $778A,X is 1 (it starts at $0C40, $0588). Touching the Doctor while $50 is not negative and his Y AND $0F = 8, it goes to state 9 and sets $50 = $79. While $50 is positive the Doctor's fire is cleared, $E0 = $FF blocks the pockets, and chase_direction steers him to ($0BBC, $0588); within $10 x $08 of it $50 = $FF ($C9D4). Controller state 9 then sets switch cell 11 to block $F1 (a column of class-1 characters) and returns to state 0 ($CF44). Start-up writes cell 11 from $1D0B = $04, open (the hand-over map holds $F1). A blast within $20 x $20 of ($0BE0, $0588) sets it to $FF, open ($C22E). While $50 is non-zero and cell 11 is not $FF, patrolling controllers do not turn to the Doctor ($CE8A). Bit 7 of $50 survives a regeneration ($937F), so with $50 negative every later touch is a shock.$BBBC): each of the eight points is switch cell 0-7, block $E0 (a clamp on a ladder); undoing it writes $E1, the clamp drawn open. Point 5 needs the Doctor below it ($BBB4).$1D00 into the map ($AECA from $4A3C); the hand-over image's map predates that for cells 0, 1, 9, 11 and 14.$9102, $E8 = 2 escape pod, 4 TARDIS): the countdown is added to the score (zeroed first if object 0's Y high byte is below 3), then a bonus of 1024 doubled once for each of the CRYSTAL, the TIRU plans (the CAPSULE, $3E) and Splinx held or pocketed, once for the TARDIS, and once if heatonite production was halted ($4F with a qualifying object, or $51). The rating: below 4100 VERY DISPLEASED, below 20000 DISPLEASED, below 40000 PLEASED, else VERY PLEASED. F1 plays again ($9282).$94FF): F1 cassette, F3 disc, F5 back. It copies zero page, the object tables and the status rows into $7800-$7D7F, sets $7800 to $FF and saves that block as "DRWHO"; the start-up restores it when $7800 is not zero ($49C6). After saving it jumps through $A000, which with the BASIC ROM in is a BASIC cold start: the game does not resume. The original disk's BASIC boot program DWMT loads the save: it POKEs $7800 to 0, asks LOAD A SAVED POSITION (Y/N)?, on Y loads "DRWHO",8,1, then loads P2 ($8000-$CFFF), P3 ($E000-$FF6F) and P1 ($0800-$77FF) and types SYS18509 ($484D) into the keyboard buffer (disk image, 3 October 2026).$74EA; five tunes chosen from the Doctor's map position, silence as tune 5. live: voice 1 plays a sawtooth note in the start cavern and $E1 stays 1 frame after frame.$C677; a lower number interrupts a higher one ($C7C7); updated every other frame ($C818), which reads the voice 3 envelope $D41C.From every instruction in the traced code with an operand in $D000- $DFFF (colour RAM aside).
| Register | Where |
|---|---|
$D000-$D007, $D010 | sprite positions: $B00F-$B059 (programmer), $FE80-$FE90 (TARDIS) |
$D011, $D012 | start-up, raster bands, $80DA; raster reads in $8D0B, $931B, $B02D, $B15D |
$D015-$D01D | sprite enables and modes: $8138-$81BE, $AF83-$AFE2, $FE7A-$FE88 |
$D018, $D016 | raster bands; programmer $AFC6; $9594 |
$D019, $D01A | start-up; $9367, $94F2, $AF88, $B140 |
$D020-$D02A | colours: start-up, $815E, $AFE7-$AFF6, $FEA2, $FF31-$FF41 |
$D400-$D40B | music, voices 1 and 2: $755D-$7631 |
$D40E-$D414, $D418, $D41C | effects on voice 3, volume: $C7CF-$C8A5 |
$DC00-$DC02 | keyboard and stick: $8F3C-$8FD2 |
$DC0E | stops CIA1 timer A at start-up |
$DD00, $DD02 | VIC bank: raster bands, $AFB2-$AFC1 |
Not named by any traced instruction: the filter, $D01E/$D01F (collisions are worked out in software), the CIA timers beyond the one stop. STA $D400,Y at $755D reaches the SID through an index.
$E8 = 8 (the rising level) prints GAME OVER as the cause of death while lives remain ($90F3).$90CC stores $64, not a BCD value, into the score's low byte on the first restart point.RTS that ends the whole controller loop for that pass ($CE77).$C2BF and $CDF7 accept only the states they were written for; another value lands mid-instruction.$16A0 value computed from $4E at $BB05 is overwritten at $BB15.$881D does not clear the drawn flag of object $4F.$8652 reads the overlay glyphs from $0000-$07FF, not $4000: is that where they are?| Test | Result |
|---|---|
| Frame capture, rebuild compared with the emulator's picture | 104,448 of 104,448 pixels |
Writes to $1B-$1D from the hand-over | $499A, $499E; 010800 |
$1E and the lives field at play start | 5; five figures |
F1 pressed six times, $3C read | 0 1 2 3 4 0 |
S, then stick down, $3A read | the programmer opens; cursor moves |
$1F at play start | 24 |
| R pressed | $E8 = $12, FORCED REGENERATION scrolls, lives 4 |
| D pressed beside the TARDIS | nothing; $E8 back to 0 |
| Walk right until a fall | FALLING ON A STALAGMITE, a life lost |
Twelve frames stepped in play, SID and $E1 read | music plays; $E1 stays 1 |
Original disk, stopped at $484D, RAM compared with the listing | equal in all bytes the listing holds except zero page and $FF70-$FFFF (3 October 2026) |
| Restart point moved to the crystal room, a life lost | the room on screen matches the Maps tab, railing gap included |
CIRCUITs $44 and $45 put at x $0208 and $0228, y $0390 | slots read S T O P T; $4F = $FF; $42/$43 put back: $4F = 0 |
| Restart beside the madrag | head and body drawn above the legs, as on Gameplay |
| Title screen, after N | SID voice 2 plays the title tune; stops when space is pressed |
Pokes that change the game within its own parameters. Each one names the variable it changes and whether it has been tested live. Untested pokes are labelled as candidates. The file is packed, so these are made in a machine code monitor or an emulator while the game runs, not before RUN.
| Effect | Poke | Status |
|---|---|---|
| Lives: n figures, n lives before GAME OVER | $1E = n (5 at the start; the field shows up to five) | live: 2 poked, one death left one figure |
| Score | $57-$59, six BCD digits, high byte first | live: 12 34 56 shows 123456 |
| Full Splinx battery | $1F = 24 | candidate (24 read live at the start) |
| Air | $F1 = 50 | candidate ($CA90) |
| Time bonus | $1B-$1D, BCD, low byte first | candidate ($91BC) |
Loading listing…