Paqman

Developer(s): S. N. Deary
Date: 1985
Type: Diskette
Platform(s): QL
Tags: Arcade

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.

Image Gallery

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 DEFine

Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.