Monster is a platform-style maze game in which the player navigates a character around a multi-level screen, collecting jewels, eliminating monsters, and reaching a door before a countdown timer expires. The screen layout is built procedurally each level using UDGs (user-defined graphics) loaded via a DATA/POKE USR loop that defines eight custom characters (codes 144–151). Movement is handled with keys 5, 6, 7, and 8, and the ATTR function is used extensively to detect collisions with colored screen objects, distinguishing platforms, monsters, jewels, and the exit door by their ink and paper attribute bytes. Killing a monster triggers an “invisible gas” mechanic that doubles the rate of timer decay, tracked with a flag variable. A high-score variable persists across games within the same session.
Program Structure
The program is organized into clearly delineated functional blocks:
- Lines 1–6: Initialization, high-score reset, and instructions prompt.
- Line 7: Level selection and validation.
- Lines 8–120: Level setup — drawing platforms, monster positions, jewels, and the exit door, plus an intro beep sweep.
- Lines 195–300: Main game loop — player movement, collision detection, scoring, and timer management.
- Lines 1000–1010: Death-by-falling routine.
- Lines 2000–2090: UDG definition subroutine via DATA and POKE USR.
- Lines 5000–5040: End-of-game screen with high-score comparison and replay prompt.
- Lines 6000–6030: Instructions display (note: called as
GO SUB 5500in line 5, but defined at line 6000 — see Bugs section).
UDG Definitions
Eight UDGs are defined at startup by the subroutine at line 2000, using a nested FOR loop that reads eight bytes per character from DATA lines 2010–2080 and POKEs them into memory with POKE USR CHR$ z+x, a for z running from 144 to 151. The characters and their roles are:
| UDG | Code | Role |
|---|---|---|
| [UDG-A] | 144 | Player character |
| [UDG-B] | 145 | Player death sprite |
| [UDG-C] | 146 | Jewel / collectible |
| [UDG-D] | 147 | Monster (placed on platforms) |
| [UDG-E] | 148 | Platform block |
| [UDG-F] | 149 | Killable monster (row 1) |
| [UDG-G] | 150 | Door left half |
| [UDG-H] | 151 | Door right half |
Level Generation
Platforms are drawn in a loop (lines 10–30) that prints INK 5 platform blocks across each row, stepping up three rows at a time from row 21 down to row 3. Monster sprites are scattered at random column positions using RND *29+1 (line 45), printed in INK 6 pairs two cells tall. Jewels (line 100) are placed at six positions spaced three rows apart, printed BRIGHT 1 INK 7. The exit door (line 110) is fixed at row 20, column 29 in INK 2.
ATTR-Based Collision Detection
The game makes heavy use of ATTR to identify objects by their color attributes rather than tracking sprite positions in variables. Key checks in the main loop include:
ATTR (a-1,b)=6— detects a monster above the player (INK 6 = yellow), used for jumping onto platforms with monsters (line 275) and for the downward move (line 281).ATTR (a-1,b)=4— detects a killable monster at row 1 in INK 4 (green), awards 100 points (line 280).ATTR (a,b)=71— detects a jewel (attribute byte 71 = BRIGHT 1 + INK 7 + PAPER 0), awards 50 points (line 285).ATTR (a,b)=2— detects the exit door in INK 2 (red), triggering level advance (line 291).SCREEN$ (a-1,b)=" "— checks for empty space above before a simple upward step (line 270).
Movement and Physics
The player position is stored in row a and column b. Movement keys are 5 (left), 8 (right), 7 (up), and 6 (down). Upward movement on a plain space (line 270) is a short one-cell hop that immediately returns the player to their original row — effectively a cosmetic jump with no sustained elevation. The jump onto a monster platform (line 275) moves the player up three rows at once, matching the three-row platform spacing. The downward move through a monster (line 281) similarly shifts three rows and is gated by k >= 16, meaning the player must have collected at least 16 kills. Boundary detection (line 290) triggers the fall subroutine when b=0 or b=31.
Timer and Gas Mechanic
The timer t starts at 1000 and is decremented by l (the current level) each iteration of the main loop (line 282). When a monster is killed, flag n is set to 1 (line 280), and line 287 subtracts an additional 2*l per loop while n=1, effectively tripling the timer drain. The flag is cleared when the player descends through a monster (line 281, LET n=0). Timer display is updated each loop at line 288, and exhaustion at line 289 routes to the end-game subroutine.
Falling Death Routine
Lines 1000–1010 implement a falling animation: the player sprite is printed one row lower on each iteration with an accompanying descending BEEP, and the previous position is erased. When row 21 is reached, the death sprite (UDG-B) is displayed with FLASH 1 in INK 2, a long low beep plays, and the routine falls through to the end-game screen at line 5000.
Notable Techniques
- The OVER 1 mode in lines 250 and 260 XORs the player sprite onto the screen when erasing the previous position, a common sprite-movement technique to avoid explicit background redrawing.
- The intro music (line 120) is a simple
FORsweep from -10 to 20 semitones, producing a rising glide. - The high-score
hsis initialized once at line 1 and persists for the session, compared at line 5000. - Platform row spacing of 3 is hardcoded throughout and must be consistent between generation (lines 10–30) and movement (lines 275, 281) for gameplay to work correctly.
Bugs and Anomalies
- Missing subroutine target: Line 5 calls
GO SUB 5500, but the instructions routine begins at line 6000. There is no line 5500, so requesting instructions would cause a BASIC error. The instructions are never reachable in normal play. - Level validation error: Line 7 checks
IF l<1 OR 1>9— the second operand should bel>9not1>9. Since1>9is always false, any value oflthat is not less than 1 (i.e., any positive number) bypasses the FOOL message, allowing levels above 9. - Variable reuse of
b: The variablebis used both as a platform-drawing row counter (lines 8–95) and as the player’s column position (lines 195 onward). This is resolved by the explicit reset at line 195 (LET b=1), but the dual use is a potential source of confusion. - Line 270 jump behavior: The upward hop immediately restores
ato its original value withLET a=a+1, so the jump has no lasting effect on position — it is purely cosmetic. - Line 95 loop variable conflict: The loop at line 95 uses
bas both itsFORvariable and increments it manually withLET b=b+1inside the loop body, which interferes with theNEXT bcounter and will cause non-standard stepping behavior.
Source Code
1 LET hs=0
2 INK 3:BORDER 0:PAPER 0:CLS :GO SUB 2000
3 CLS :PRINT AT 10,0; INK 7;"Do you need instructions ? (y/n)"
4 IF INKEY$ ="n" THEN GO TO 7
5 IF INKEY$ ="y" THEN GO SUB 5500
6 GO TO 4
7 CLS :PRINT INK 7;"START LEVEL ? (1-9)":INPUT l:LET sc=0:LET k=0:IF l<1 OR 1>9 THEN CLS :PRINT AT 10,13; FLASH 1; INK 7;"FOOL":PAUSE 100:GO TO 3
8 LET b=21:LET t=1000
9 CLS :PRINT AT 0,0; INK 7;"SCORE=";sc; AT 0,13;"TIME=";t; AT 0,25;"LEVEL=";l
10 FOR a=1 TO 30
11 PRINT AT b,a; INK 5;"[UDG-E]"
20 NEXT a
30 IF b>3 THEN LET b=b-3:GO TO 10
40 FOR m=1 TO 2
45 LET r= RND *29+1
50 FOR s=1 TO 2:PRINT AT b,r; INK 6;"[UDG-D]":LET b=b+1:NEXT s
70 IF b<19 THEN LET b=b+1: GO TO 45
80 LET b=3:NEXT m
90 LET z=5
95 FOR b=1 TO 14:PRINT AT 1,b; INK 4;"[UDG-F]":LET b=b+1:NEXT b:PRINT AT 1,15; INK 4;"[UDG-F][UDG-F]":FOR b=18 TO 30:PRINT AT 1,b; INK 4;"[UDG-F]":LET b=b+1:NEXT b
100 FOR n=0 TO 5:PRINT AT z, RND *29+1; INK 7; BRIGHT 1;"[UDG-C]":LET z=z+3:NEXT n
110 PRINT AT 20,29; INK 2;"[UDG-G][UDG-H]"
120 FOR m=-10 TO 20:BEEP .05,m:NEXT m
195 LET a=20:LET b=1
200 PRINT AT a,b;"[UDG-A]"
201 BEEP .002,0:BEEP .002,10
205 PRINT AT 0,6; INK 7;sc
250 IF INKEY$ ="5" AND b>0 THEN LET b=b-1:PRINT AT a,b+1; OVER 1;"[UDG-A]"
260 IF INKEY$ ="8" AND b<31 THEN LET b=b+1:PRINT AT a,b-1; OVER 1; "[UDG-A]"
270 IF SCREEN$ (a-1,b)=" " AND INKEY$ ="7" THEN PRINT AT a,b;;" ":LET a=a-1:PRINT AT a,b;"[UDG-A]":BEEP .1,2:LET a=a+1:PRINT AT a-1,b;" "
275 IF ATTR (a-1,b)=6 AND INKEY$ ="7" AND a>3 THEN PRINT AT a,b;" ":LET a=a-3:BEEP .01,10:BEEP .01,5
280 IF ATTR (a-1,b) =4 AND INKEY$ ="7" AND a<3 THEN PRINT AT a,b;" ":PRINT AT a-1,b;"[UDG-A]":BEEP .1,-20:PRINT AT a-1,b;" ":LET sc=sc+100:LET n=1:LET k=k+1
281 IF ATTR (a+1,b) =6 AND INKEY$ ="6" AND k >= 16 THEN LET a=a+3:PRINT AT a-3,b;" ":BEEP .01,10:BEEP .01,0:LET n=0
282 LET t=t-l
285 IF ATTR (a,b)=71 THEN BEEP .1,40:LET sc=sc+50
287 IF n=1 THEN LET t=t-(2*l)
288 PRINT AT 0,18;" "; AT 0,18; INK 7;t
289 IF t<0 THEN LET t=0:PRINT AT 0,18;" "; AT 0,18; INK 7;"0":IF t=0 THEN GO SUB 5000
290 IF b=0 OR b=31 THEN GO SUB 1000
291 IF ATTR (a,b)=2 THEN LET l=l+1:GO TO 8
300 GO TO 200
1000 LET a=a+1:PRINT AT a,b;"[UDG-A]":BEEP .1,-a:PRINT AT a,b;" ":IF a <> 21 THEN GO TO 1000
1010 PRINT AT a,b; FLASH 1; INK 2;"[UDG-B]":BEEP 2,-40:GO TO 5000
2000 FOR z=144 TO 151:FOR x=0 TO 7:READ a:POKE USR CHR$ z+x,a:NEXT x:NEXT z
2010 DATA 24,36,24,60,90,24,36,66
2020 DATA 60,92,191,251,190,255,86,24
2030 DATA 0,16,56,84,254,84,56,16
2040 DATA 195,255,255,195,195,255,255,195
2050 DATA 255,255,129,66,36,24,255,255
2060 DATA 102,153,60,90,60,102,255,126
2070 DATA 63,33,33,33,33,33,33,63
2080 DATA 248,248,248,248,232,248,248,248
2090 RETURN
5000 CLS :IF sc>hs THEN PRINT AT 5,8; INK 7; FLASH 1;"CONGRATULATIONS"; AT 7,3;"YOU HAVE BEATEN THE HI-SCORE"; AT 9,10;"of ";hs; AT 11,8;"with a score of ";sc:LET hs=sc:GO TO 5010
5005 PRINT AT 10,7; INK 7;"Your score was ";sc
5010 PRINT AT 15,1; INK 7;"Do you want another go ? (y/n)"
5020 IF INKEY$ ="n" THEN CLS :PRINT AT 10,11; INK 7; FLASH 1;"GOODBYE":STOP
5030 IF INKEY$ ="y" THEN GO TO 3
5040 GO TO 5020
6000 CLS :PRINT INK 7;"Your task is to steer yourself ([UDG-A]) around the screen without falling to your death or runningout of time.You must attempt to collect the jewels ([UDG-C]) and kill all the monsters ([UDG-F]) before moving on to the next level through the door ([UDG-G][UDG-H])."
6005 PRINT INK 7''"Press any key to continue.":PAUSE 0
6010 CLS :PRINT INK 7'"Once you have killed a monster an invisible gas is released and your time decreases more rapidly."''"You score 50 points for each jewel and 100 for each monster."
6020 PRINT AT 10,10; INK 7;"INSTRUCTIONS"; AT 12,5;"5...............left"; AT 14,5;"6...............down"; AT 16,5;"7...............up"; AT 18,5;"8...............right"
6025 PRINT INK 7''"Press any key to continue.":PAUSE 0
6030 GO TO 7Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.

