Grimm’s Fairy Trails is a maze game in which the player guides “Prince Billy” through a maze, collecting 250 “B-lers” (life crystals) while being pursued by two maze dwellers named Murph and Drago. The game relies heavily on machine code routines called via USR at addresses such as 16608, 16642, 16664, 16750, 18000, 18220, and 18370, which handle sprite movement, collision detection, and screen rendering beyond what BASIC alone could achieve at playable speed. Six difficulty levels are selectable at startup, each POKEing a delay value (5 through 30) into address 18037 to control game speed. A title-screen animation routine draws the game’s name and a sponsoring label character-by-character using a DIM’d string array and a machine code character-plotting routine at USR 18370. A built-in machine code entry utility at line 9000 and a save routine at line 9200 are included for development purposes.
Program Analysis
Program Structure
The program is organized into several functional blocks:
- Line 10: A REM statement containing what appears to be embedded machine code data (the long token-heavy line is the ML payload stored in a REM).
- Lines 990–2070: Main game initialization and loop — sets up the screen, POKEs machine code parameters, and launches ML routines via
USR. - Lines 3000–3064: Game-over / replay prompt (“GO-AGAIN – PRINCE ? Y/N”).
- Lines 4000–4099: Instructions and difficulty-level selection subroutine.
- Lines 5000–5999: Animated title screen subroutine — draws the game name letter by letter.
- Lines 6000–6199: Helper subroutine for setting ML display parameters per title row.
- Lines 6200–6399: Story/introduction screen with character descriptions.
- Lines 9000–9220: Developer utilities: machine code entry tool, POKE-based hex entry, and a tape save routine.
Machine Code Integration
The game’s core logic — sprite movement, collision detection, and rendering — is implemented in machine code rather than BASIC. The ML routines are invoked repeatedly through USR calls, with results discarded into a dummy variable C1. Key addresses used include:
| Address | Purpose (inferred) |
|---|---|
16608 | Screen/display reset or CLS routine |
16642 | Maze rendering routine |
16664 | Additional screen setup |
16750 | Sprite/character movement engine |
18000 | Main game loop (movement, collision) |
18220 | Score display update |
18370 | Character-plotting routine for title animation |
Machine code parameters are passed by POKEing values directly into fixed addresses immediately before calling USR. For example, sprite row/column coordinates are written to addresses 16751, 16753, 16771, and 16773, while game speed is stored at 18037.
The machine code payload itself is almost certainly stored inside the REM statement on line 10. This is the standard technique for embedding ML in BASIC: the tokenizer stores the REM body verbatim, allowing arbitrary byte sequences to be placed at a known address (just past the line header).
Difficulty Level System
Six difficulty levels are offered at startup (lines 4040–4088). Each level POKEs a different delay constant into address 18037, which the ML game loop presumably uses as a timing parameter:
| Key | Label | POKE 18037 value |
|---|---|---|
| 1 | SUPER PRINCE | 5 (fastest) |
| 2 | SKILLED HUNTER | 10 |
| 3 | SCHOOL DAZE | 15 |
| 4 | FIRST TIME | 20 |
| 5 | LEAD FEET | 25 |
| 6 | POISON APPLE | 30 (slowest) |
Title Animation
The subroutine at line 5000 uses a DIM A$(6,7) string array to store six seven-character strings: a label row, a separator row, another label row, and three rows spelling “GRIMM S / FAIRY / TRAILS”. A nested loop iterates over each character, extracts it with A$(J,N TO N), POKEs its CODE and column index into addresses 18345 and 18346, then calls the ML plotter at USR 18370. An inner loop at lines 5032–5034 provides a brief inter-character pause. A special case at line 5036 clears the screen after row 3, and line 5037 prints a block-graphic character at a fixed position when row 4 is drawn.
Key BASIC Idioms
- Dummy USR variable: All ML calls use
LET C1=USR xxxxxto discard the return value while still invoking the routine. - Score display: Line 2070 uses
PRINT AT 18,11;PEEK 16816to read the score directly from a fixed ML variable address rather than tracking it in BASIC. - Input loop: Lines 4040–4088 use a tight
IF INKEY$="" THEN GOTO 4038spin-wait followed byLET Y=VAL INKEY$to capture a single keypress and convert it to a number. - Replay loop: Lines 3010–3025 use a three-way INKEY$ branch (Y / N / empty) to manage the “play again” prompt without blocking.
- SLOW/FAST: Line 990 sets
SLOWmode for the BASIC sections; the ML routines operate independently of this setting.
Developer Utilities
Lines 9000–9220 contain tools that were left in the final listing. Lines 9010–9060 implement a sequential POKE loop for entering ML byte by byte. Lines 9070–9150 provide a character-pair hex-entry utility that converts two-character strings to byte values using 16*CODE A$+CODE A$(2)-476. Line 9200 provides a tape save routine that calls a ML save entry point at address 8192 with a filename. These routines are unreachable during normal play and represent development scaffolding.
Notable Anomalies
- Lines 5040–5042 contain two
REM-commented-out BASIC statements (PRINT AT 20,1;"PRESS ENTER WHEN READY"andINPUT Y$), replaced by the more elaborate prompt at line 6385. The REM keyword causes the lines to be skipped entirely. POKE 16625,8at line 995 andPOKE 16625,128at line 6390 manipulate the system flags byte. Setting bit 3 (value 8) enables FAST mode within ML context; value 128 sets a high bit with a different effect, likely related to display mode control.- Address
14812is POKEd at line 1041 (POKE 14812,1), which falls well below the typical ML and system variable ranges used elsewhere — this may be a display file or attribute area address used to place a specific screen element. - The score tracking uses
POKE 16816,0andPOKE 16814,0to reset two ML variables at game start (lines 1002–1004 and 3060–3062), and reads the score back withPEEK 16816for display.
Content
Image Gallery
Source Code
10 REM A #ACS 9ACS 9ACS 9ACS 9ACS 9ACS =#- ;#; GOSUB #£RND;)▘ ;##TAN :-E£RND7)5 ▞4 GOSUB #6 COPYRNDQ█7▌TAB LIST RNDE COPYRND$TAB DIM RNDTAN [X]# ▞2:?Y.LN [▒]RND$# RETURN▘4 PRINT :?▌4 LIST TAN :~~▞1Y█LN [▒]RND$# RETURN▞4 PRINT :~~▌▌# RETURN?4 GOTO :~~▞:Y█LN [▒]RND$# RETURN▞4 PRINT :~~▌▌# RETURN 4 GOTO ▞(:~~Y█LN [▒]RND▌# RETURN:4 PRINT :▛▞(Y█LN [▒]RND▌# RETURN:4 PRINT TAN ▞1:£Y█LN [▒]RND▌LN [▒]RND▌▌# RETURN▝4 LIST ▞1:▀Y█LN [▒]RND▌LN [▒]RND▌▌# RETURN▝4 LIST TAN ▝2(,,▝2 ,,/4#▘▘ 5[5]INKEY$ #5[4]INKEY$ #YOLN [▒]RNDTAN LN USR INKEY$ 7# RETURN█COS RETURN.ATN [(]PI)[K]INKEY$ , RETURNCOS COS Y LN [▒]RND▖YOLN [▒]RND#M[5]INKEY$ TAN LN USR INKEY$ F# RETURN█COS RETURN.ATN [(]PI)[K]INKEY$ , RETURNCOS COS Y LN [▒]RND▌YOLN [▒]RND#M[5]INKEY$ TAN LN USR INKEY$ )5 GOSUB ## RETURN█COS RETURN.ATN [(]PI)[K]INKEY$ , RETURNCOS COS Y LN [▒]RND$YOLN [▒]RND#M[4]INKEY$ TAN LN USR INKEY$ )5 GOSUB ## RETURN█COS RETURN.ATN [(]PI)[K]INKEY$ , RETURNCOS COS Y LN [▒]RND£YOLN [▒]RND#M[4]INKEY$ TAN U[K]INKEY$ LEN ▘M[K]INKEY$ TAN LN RAND #LN K#U[I]INKEY$ RETURNXCOS #0# U[4]INKEY$ 5[8]INKEY$ [-] IF ##-▝#U[5]INKEY$ 5[9]INKEY$ [-] IF ##2▝##[S] IF ## PAUSE ##-▘ GOSUB ##W#2▘ GOSUB ##### RETURN▘ASN [▒]#TAB ### RETURN▘ASN [2]#TAB [O]#LN ## RETURN█""LN ""# RETURN█""LN CONT # RETURN█""LN [,]#TAN LN [,]# RETURN█""LN ""# RETURN█""LN CONT # RETURN█""LN ##TAN LN CONT # RETURN█""LN [,]# RETURN█""LN ## RETURN█""LN ""#TAN LN ""# RETURN█""LN ## RETURN█""LN [,]# RETURN█""LN CONT #TAN 7U9RND UARND#U9RND[T]TAB $#UARND[S]COS UARND#U9RND# RETURN COPYCOS 2 COPY- #?##[3] PLOT AI▌[+]▐R##3##S RUN #HI▘4 LET 5# #;#M SAVE # RETURN5ATN :PI RETURN6ATN #PI RETURN7ATN QPI RETURN8ATN NEWINKEY$ TAN RAND # 5[9]INKEY$ #5[8]INKEY$ #Y▒LN [▒]RNDTAN ##TAN [6]#TAN LN ##)5 GOSUB ##ACS #"" RETURNOATN [▒]# RETURN▒COS LN [▒]RND£Y▒LN [▒]RND#M[8]INKEY$ TAN LN ##)5 GOSUB ##ACS #"" RETURNOATN [▒]# RETURN▒COS LN [▒]RND$Y▒LN [▒]RND#M[8]INKEY$ TAN INKEY$ TAN [3]#LN ##7#ACS #"" RETURNOATN [▒]# RETURN▒COS LN [▒]RND▖Y▒LN [▒]RND#M[9]INKEY$ TAN LN ##F#ACS #"" RETURNOATN [▒]# RETURN▒COS LN [▒]RND▌Y▒LN [▒]RND#M[9]INKEY$ TAN 5[D]INKEY$ #5[C]INKEY$ #Y▒LN [▒]RNDTAN [▒]LN 8#)5 GOSUB ##ACS #"" RETURNOATN [▒]# RETURN▒COS LN [▒]RND£Y▒LN [▒]RND#M[C]INKEY$ TAN LN LN 8#)5 GOSUB ##ACS #"" RETURNOATN [▒]# RETURN▒COS LN [▒]RND$Y▒LN [▒]RND#M[C]INKEY$ TAN U[G]INKEY$ RETURN▝ASN [-]#YXM[I]INKEY$ TAN LN ##TAN LN 8#7#ACS #"" RETURNOATN [▒]# RETURN▒COS LN [▒]RND▖Y▒LN [▒]RND#M[D]INKEY$ TAN LN 8#F#ACS #"" RETURNOATN [▒]# RETURN▒COS LN [▒]RND▌Y▒LN [▒]RND#M[D]INKEY$ TAN LN RAND #U[H]INKEY$ RETURN▝TAB ##Y▘M[H]INKEY$ LN K#LN [O]#U[I]INKEY$ RETURNXCOS ###LEN ▘M[H]INKEY$ :▌▞ IF Y▘▌4 CLS$4 PLOT U[K]INKEY$ RETURN IF COS E[E]INKEY$ ## RETURNOATN ####### U[4]INKEY$ 5[C]INKEY$ [-] IF CHR$ #-▝#U[5]INKEY$ 5[D]INKEY$ [-] IF <>#2▝##[S] IF SLOW# PAUSE GOSUB #-▘ GOSUB ##""#2▘ GOSUB ##LN ## RETURN▘ASN £#TAB PLOT ## RETURN▘ASN +#TAB 2#LN N# RETURN█""LN [U]# RETURN█""LN [0]# RETURN█""LN ##TAN LN ## RETURN█"" LN [U]# RETURN█""# PLOT #LN [0]# RETURN█""# PLOT # 5[6]INKEY$ #5[7]INKEY$ #Y[*]LN [▒]RND6[E]INKEY$ TAN U[G]INKEY$ LEN ▘M[G]INKEY$ ▞(:,,Y LN [▒]RNDY(M[5]INKEY$ Y?M[4]INKEY$ YOLN USR INKEY$ TAN XM[G]INKEY$ Y(M[5]INKEY$ Y?M[4]INKEY$ YOVAL STR$ FASTLN USR INKEY$ LPRINT SGN AT Y TAN ▛ ▗▖▄▝▐▞▟▘▚▌▙▀▜▛█ E£RND7▘ LET ▘U[E]# RETURN▘TAB CHR$ # GOSUB #6:RND5[D]##[B]*****- ACS >#5 2;:▖▞▖#7#7 FAST[J]ACS >*ACS >*ACS <*ACS <*5[I]#▐##E:RND#76:RND( STOPSTR$ )1 ;6:RNDSGN LPRINT $4INT )█ COPYE:RND;6:RND#TAN
990 SLOW
995 POKE 16625,8
1000 LET C1=USR 16608
1002 POKE 16816,0
1004 POKE 16814,0
1006 GOSUB 4000
1010 LET C1=USR 16642
1011 PRINT AT 15,1;" "
1012 PRINT AT 8,15;" "
1014 PRINT AT 8,16;" "
1016 PRINT AT 9,16;" "
1018 PRINT AT 9,15;" "
1020 LET C1=USR 16664
1022 POKE 16751,30
1024 POKE 16753,14
1026 POKE 16771,30
1028 POKE 16773,5
1030 POKE 16767,0
1032 POKE 16787,0
1034 LET C1=USR 16750
1036 POKE 16751,29
1038 POKE 16753,12
1040 POKE 16771,29
1041 POKE 14812,1
1042 POKE 16773,3
1044 POKE 16767,2
1046 POKE 16787,2
1048 LET C1=USR 16750
1049 PRINT AT 8,14;"."
1050 PRINT AT 3,1;".█"
1051 PRINT AT 14,30;"."
1052 PRINT AT 12,1;".█"
1053 PRINT AT 5,30;"."
1056 PRINT AT 18,5;"[S][C][O][R][E]"
1057 POKE 16802,16
1058 POKE 16803,9
1059 LET C1=USR 18220
1060 POKE 16801,16
1062 POKE 16800,15
1064 PRINT AT 15,16;"O"
2020 PRINT AT 6,16;"[▒]"
2022 PRINT AT 6,15;"[▒]"
2024 POKE 16804,6
2028 POKE 16805,16
2030 POKE 16808,6
2032 POKE 16809,15
2035 POKE 16813,1
2055 LET C1=USR 18000
2070 PRINT AT 18,11;PEEK 16816
3000 PRINT AT 20,3;"GO-AGAIN - PRINCE ? Y/N"
3010 IF INKEY$ ="Y" THEN GOTO 3050
3015 IF INKEY$ ="N" THEN GOTO 1
3020 IF INKEY$ ="" THEN GOTO 3000
3025 GOTO 3000
3030 STOP
3050 LET C1=USR 16608
3060 POKE 16814,0
3062 POKE 16816,0
3064 GOTO 1010
4000 REM
4005 GOSUB 5000
4007 GOSUB 6200
4010 PRINT AT 2,1;"USING THE ROYAL ARROW KEYS"
4012 PRINT AT 3,1;"YOU MUST GUIDE PRINCE BILLY"
4014 PRINT AT 4,1;"THROUGH THE MAZE AND GET"
4016 PRINT AT 5,1;"ALL THE B-LERS"
4017 PRINT AT 7,1;"GOOD LUCK"
4019 PRINT AT 12,2;"WHAT LEVEL OF PLAY?"
4020 PRINT AT 14,2;"1=SUPER PRINCE"
4030 PRINT AT 15,2;"2=SKILLED HUNTER"
4032 PRINT AT 16,2;"3=SCHOOL DAZE"
4034 PRINT AT 17,2;"4=FIRST TIME"
4036 PRINT AT 18,2;"5=LEAD FEET"
4038 PRINT AT 19,2;"6=POISON APPLE"
4040 IF INKEY$ ="" THEN GOTO 4038
4080 LET Y=VAL INKEY$
4082 IF Y=1 THEN POKE 18037,5
4083 IF Y=2 THEN POKE 18037,10
4084 IF Y=3 THEN POKE 18037,15
4085 IF Y=4 THEN POKE 18037,20
4086 IF Y=5 THEN POKE 18037,25
4087 IF Y=6 THEN POKE 18037,30
4088 IF Y<1 OR Y>6 THEN GOTO 4019
4090 LET C1=USR 16608
4099 RETURN
5000 REM
5002 DIM A$(6,7)
5004 LET A$(1)=" TIMEX "
5006 LET A$(2)="*******"
5008 LET A$(3)=" TIMEX "
5010 LET A$(4)="GRIMM S"
5012 LET A$(5)=" FAIRY "
5014 LET A$(6)="TRAILS "
5016 FOR J=1 TO 6
5018 GOSUB 6000
5020 FOR N=1 TO 7
5022 LET B$=A$(J,N TO N)
5024 POKE 18345,CODE B$
5026 POKE 18346,N
5028 LET C1=USR 18370
5030 NEXT N
5032 FOR L=1 TO 3
5034 NEXT L
5036 IF J=3 THEN LET C1=USR 16608
5037 IF J=4 THEN PRINT AT 5,24;"▞"
5038 NEXT J
5040 REM PRINT AT 20,1;"PRESS ENTER WHEN READY"
5042 REM INPUT Y$
5990 POKE 16625,0
5995 LET C1=USR 16608
5999 RETURN
6000 REM
6002 IF J=1 OR J=4 THEN POKE 18375,167
6004 IF J=1 OR J=4 THEN POKE 18376,0
6006 IF J=2 OR J=5 THEN POKE 18375,76
6008 IF J=2 OR J=5 THEN POKE 18376,1
6010 IF J=3 OR J=6 THEN POKE 18375,241
6020 IF J=3 OR J=6 THEN POKE 18376,1
6199 RETURN
6200 REM
6202 PRINT AT 1,0;"ONCE UPON A TIME, IN A FAR"
6204 PRINT "AND DISTANT LAND THERE LIVED"
6206 PRINT "THE FOLLOWING PEOPLE:"
6208 PRINT
6210 PRINT "O = PRINCE BILLY"
6212 PRINT "[▒] = MAZE DWELLER MURPH"
6213 PRINT
6214 PRINT "[▒] = MAZE DWELLER DRAGO"
6216 PRINT
6218 PRINT "THE MAZE DWELLERS WOULD CHASE "
6220 PRINT "PRINCE BILLY DAY AND NIGHT"
6222 PRINT
6224 PRINT "HIS ONLY HOPE WAS TO GATHER 250"
6226 PRINT "B-LERS (...), HIS LIFE CRYSTALS."
6228 PRINT
6230 PRINT "IF PRINCE BILLY COULD TOUCH"
6232 PRINT "THE SACRED STONE OF ROSS [*] "
6234 PRINT "IN THE CENTER OF THE MAZE HE"
6236 PRINT "CAN ESCAPE CAPTURE--ONLY ONCE"
6385 PRINT AT 21,1;"[P][R][E][S][S]█[E][N][T][E][R]█[W][H][E][N]█[R][E][A][D][Y]"
6387 INPUT Y$
6390 POKE 16625,128
6392 LET C1=USR 16608
6399 RETURN
9000 STOP
9010 INPUT A
9020 INPUT B
9030 PRINT B
9040 POKE A,B
9050 LET A=A+1
9060 GOTO 9020
9070 INPUT X
9080 LET A$=""
9090 IF A$="" THEN INPUT A$
9100 IF A$="S" THEN STOP
9110 POKE X,16*CODE A$+CODE A$(2)-476
9120 PRINT X;" ";A$
9130 LET X=X+1
9140 LET A$=A$(3 TO )
9150 GOTO 9090
9200 PRINT "SET TAPE"
9205 INPUT Y$
9210 PRINT USR 8192;"SAVE:P:GRIMM:"
9212 CLS
9220 GOTO 1
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.