Paqman is a Pac-Man style maze game. You steer the paqman around a red and blue maze eating dots while ghosts chase you; you have three lives, each cleared screen earns a bonus, more ghosts join as the screens go on, and clearing nineteen screens wins the title of Grand Master.
The REMs read “QL USER 1985” and credit S N Deary BSc, so it was a type-in from QL User magazine.
Program Analysis
The main loop draws the maze with user-defined characters, then repeats move_man and move_ghost; the chance of a ghost moving rises with the screen number (handicap).
Potential Issues
- The bonus is built as a string (
Screen&'000') and added to the score; SuperBASIC coerces it, so it works.
It came from a QL owner’s floppy copies of QUANTA and IQLUG library material, imaged double-stepped so that only half of each disk survived; this file read back complete. The download holds the files exactly as recovered and a QL5A floppy image, Paqman.img, with the same files and their QDOS headers. Mount the image as FLP1_ (drop it on the QLRun page, or use it as a floppy image in sQLux, QPC2 or Q-emuLator) and type lrun flp1_paqman_bas.
Tested in QLRun with the JS ROM: the maze and the start screen.
Source Code
10 REMark **** QL USER 1985 ****
20 REMark **** PAQMAN : Author SN Deary Bsc ****
100 initialise
110 REPeat forever
120 score=0 : lives=3 : Screen=1
130 REPeat screens
140 ghosts=Screen-1 : IF ghosts > 2 : ghosts=2
150 drawmaze
160 handicap=Screen+4
170 REPeat moves
180 move_man
190 IF RND(30)< handicap:move_ghost(RND(ghosts))
200 IF end_of_screen:EXIT moves
210 END REPeat moves
220 IF max = 0
230 CLS : AT 5,12 : FLASH 1
240 PRINT 'Bonus ';Screen;'000'
250 score=score+(Screen&'000')
260 FLASH 0 : FOR i=1 TO 300 : i=i : REMark delay
270 Screen=Screen+1
280 END IF
290 IF lives < 1 : EXIT screens
300 IF Screen > 19 : EXIT screens
310 END REPeat screens
320 CLS
330 IF Screen > 19
340 PRINT 'You have won the title of Grand Master'
350 PRINT 'Too good for this game. I concede!!'
360 STOP
370 END IF
380 AT 5,10 : FLASH 1
390 PRINT 'G A M E O V E R'
400 FLASH 0 : FOR i=1 TO 1000: i=i: REMark delay
410 IF score > top_score:top_score=score
420 END REPeat forever
430 :
440 DEFine PROCedure move_man
450 INK 2
460 key=KEYROW(1)
470 row=man_row : col=man_col
480 IF key && 2 : col=col-1 : IF col < 0:IF row=5:col=18:ELSE col=0
490 IF key && 16 : col=col+1 : IF col > 18 : IF row=5 : col=0:ELSE col=18
500 IF key && 4 : row=row-1 : IF row <0 : IF col=9 : row=10 : ELSE row=0
510 IF key &&128 : row=row+1 : IF row > 10 : IF col = 9 : row=0 : ELSE row=10
520 prize=maze(row,col)
530 IF (prize&&1) OR key=0:RETurn
540 IF prize&&16:gotcha:RETurn
550 AT man_row,man_col*2:PRINT " ";
560 INK 6:AT row,col*2:PRINT man$;
570 BEEP 200,max
580 maze(row,col)=0
590 IF prize
600 score=score+prize
610 max=max-1 : IF max < 1 : end_of_screen=true
620 AT #4,0,6:PRINT #4,score;
630 END IF
640 man_row=row : man_col=col
650 END DEFine
660 :
670 DEFine PROCedure move_ghost(x)
680 row=ghost_row(x):col=ghost_col(x)
690 not_moved=true
700 IF ABS(man_row-row) < ABS(man_col-col)
710 horizontal:IF not_moved:col=ghost_col(x):vertical
720 ELSE vertical: IF not_moved:row=ghost_row(x):horizontal
730 END IF
740 END DEFine
750 :
760 DEFine PROCedure vertical
770 IF row=man_row : RETurn
780 IF man_row < row
790 row=row-1 : IF row >=0 : moveit
800 ELSE
810 row=row+1: IF row <=10 : moveit
820 END IF
825 END DEFine
830 :
840 DEFine PROCedure horizontal
850 IF col=man_col:RETurn
860 IF man_col<col
870 col=col-1:IF col>=0:moveit
880 ELSE
890 col=col+1:IF col <=18:moveit
900 END IF
910 END DEFine
920 :
930 DEFine PROCedure moveit
940 IF (maze(row,col)&&17) : RETurn
950 INK 4:OVER -1
960 not_moved=false
970 AT ghost_row(x),2*ghost_col(x):PRINT ghost$
980 maze(ghost_row(x),ghost_col(x))=maze(ghost_row(x),ghost_col(x))-16
990 AT row,2*col:PRINT ghost$
1000 maze(row,col)=maze(row,col)+16
1010 ghost_row(x)=row:ghost_col(x)=col
1020 OVER 0
1030 IF row=man_row AND col=man_col:gotcha
1040 END DEFine
1050 :
1060 DEFine PROCedure gotcha
1070 end_of_screen=true
1080 lives=lives-1
1090 BEEP 30000,1,255,200,4,2
1100 END DEFine
1110 :
1120 DEFine PROCedure initialise
1130 set_up_user_defined_chars
1140 MODE 8
1150 true=1:false=0
1160 top_score=0
1170 CSIZE 2,1
1180 OPEN #3,scr_512x256a0x0
1190 PAPER #3,0:CLS #3
1200 SCALE #3,256,0,0
1210 OPEN #4,scr_456x10a32x14
1220 WINDOW 476,230,23,26
1230 BORDER 5,2
1240 BLOCK #3,24,5,248,26,1
1250 BLOCK #3,24,5,248,251,1
1260 BLOCK #3,10,20,23,131,1
1270 BLOCK #3,10,20,489,131,1
1280 DIM maze(10,18),man$(2),maze$(2,2)
1290 DIM ghost$(2),ghost_row(2),ghost_col(2)
1300 man$=CHR$(131)&CHR$(132)
1310 ghost$=CHR$(128)&CHR$(129)
1320 maze$(0)=CHR$(133)&' '
1330 maze$(1)=CHR$(134)&CHR$(134)
1340 maze$(2)=CHR$(130)&' '
1350 END DEFine
1360 :
1370 DEFine PROCedure set_up_user_defined_chars
1380 start_address=RESPR(100)
1390 register_a0=65537
1400 register_a2=start_address+6
1410 RESTORE 1440
1420 FOR i=0 TO 70: READ byte:POKE start_address+i,byte
1430 CALL start_address,0,0,255,37,0,0,0,register_a0,0,register_a2
1440 DATA 32,4,78,67,78,117
1450 DATA 128,6
1460 DATA 4,8,16,44,76,64,84,84,0
1470 DATA 64,32,16,104,100,4,84,84,0
1480 DATA 0,0,0,0,4,0,0,0,0
1490 DATA 124,60,36,60,124,24,24,56,0
1500 DATA 124,120,72,120,192,48,48,56,0
1510 DATA 0,40,16,56,124,124,124,56,0
1520 DATA 40,56,56,124,124,124,124,40,108
1530 END DEFine
1540 :
1550 DEFine PROCedure drawmaze
1560 max=139:end_of_screen=false
1570 RESTORE 1600
1580 READ man_row,man_col
1590 FOR i=0 TO 2:READ ghost_row(i),ghost_col(i)
1600 DATA 5,0,5,8,5,9,5,10
1610 IF Screen MOD 4 : PAPER 2 : ELSE PAPER 1
1620 CLS : CLS #4
1630 RESTORE 1950
1640 PAPER 1 : INK 4
1650 FOR row=0 TO 5
1660 opposite_row=10-row
1670 FOR col=0 TO 9
1680 opposite_col=18-col
1690 READ prize: maze(row,col)=prize
1700 maze(row,opposite_col)=prize
1710 maze(opposite_row,col)=prize
1720 maze(opposite_row,opposite_col)=prize
1730 IF prize > 1
1740 IF prize = 2
1750 chars$=maze$(2)
1760 ELSE IF prize =6 : chars$=maze$(0):ELSE chars$=maze$(1)
1770 END IF
1780 AT row,col*2: PRINT chars$;
1790 AT opposite_row,col*2:PRINT chars$;
1800 AT opposite_row,opposite_col*2:PRINT chars$;
1810 AT row,opposite_col*2:PRINT chars$;
1815 END IF
1820 END FOR col
1830 END FOR row
1840 AT 5,16:OVER -1:INK 4
1850 FOR i=0 TO ghosts:PRINT ghost$;:maze(5,8+i)=17
1860 AT man_row,2*man_col:OVER 0
1870 maze(man_row,man_col)=0
1880 INK 6 : PRINT man$
1890 key=KEYROW(1)
1900 PRINT #4,"Press any key to start";
1910 a$=INKEY$(-1):CLS #4
1920 AT #4,0,0:PRINT #4;'SCORE:';score;
1930 AT #4,0,13:PRINT #4;'TOP SCORE:';top_score;
1940 AT #4,0,31:PRINT #4;'LIVES:';lives
1950 DATA 2,2,2,2,2,2,2,2,1,2
1960 DATA 6,1,2,1,1,2,1,2,2,2
1970 DATA 2,1,2,2,2,2,2,2,1,1
1980 DATA 1,1,1,2,1,2,1,2,1,8
1990 DATA 1,2,2,2,1,2,2,2,2,2
2000 DATA 2,2,1,2,2,2,1,2,1,1
2010 END DEFineNote: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
