From owner-freebsd-hackers Sun Mar 19 22:00:50 1995 Return-Path: hackers-owner Received: (from majordom@localhost) by freefall.cdrom.com (8.6.10/8.6.6) id WAA03047 for hackers-outgoing; Sun, 19 Mar 1995 22:00:50 -0800 Received: from coyote.rain.org (dcasba@coyote.rain.org [198.68.144.2]) by freefall.cdrom.com (8.6.10/8.6.6) with ESMTP id WAA03021 for ; Sun, 19 Mar 1995 22:00:47 -0800 Received: by coyote.rain.org(8.6.10/RAIN-1.0) with id VAA25783 for Hackers@FreeBSD.org on Sun, 19 Mar 1995 21:56:20 -0800 From: Tom Gray - DCA Message-Id: <199503200556.VAA25783@coyote.rain.org> Subject: pacman To: Hackers@FreeBSD.org Date: Sun, 19 Mar 1995 21:56:18 -0800 (PST) X-Mailer: ELM [version 2.4 PL23] MIME-Version: 1.0 Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 7bit Content-Length: 39474 Sender: hackers-owner@FreeBSD.org Precedence: bulk Here's a terminal-based pacman for FreeBSD. The source is quite dated but the code compiles and runs okay. John John Poplett dcasba@pacrain.com # This is a shell archive. Save it in a file, remove anything before # this line, and then unpack it by entering "sh file". Note, it may # create directories; files and directories will be owned by you and # have default permissions. # # This archive contains: # # . # ./Makefile # ./monster.c # ./pacdefs.h # ./pacman.c # ./rain.c # ./util.c # ./pacman.6 # echo c - . mkdir -p . > /dev/null 2>&1 echo x - ./Makefile sed 's/^X//' >./Makefile << 'END-of-./Makefile' X# @(#)Makefile 8.1 (Berkeley) 5/31/93 X XPROG= pacman XSRCS= pacman.c monster.c util.c XMAN6= pacman.6 XCFLAGS += -DNODELAY -DHAVE_TERMIOS -DHAVE_USLEEP XDPADD= ${LIBTERMLIB} XLDADD= -ltermlib X#HIDEGAME=hidegame X X.include END-of-./Makefile echo x - ./monster.c sed 's/^X//' >./monster.c << 'END-of-./monster.c' X#include X#include "pacdefs.h" X Xextern char X *vs_cm; X Xextern char X brd[BRDY][BRDX], X display[BRDY][BRDX]; X Xextern int X putch(); X Xextern char X *tgoto(); X Xextern int X delay, X game, X killflg, X potion, X rounds; X Xextern unsigned X pscore; X Xextern struct pac X *pacptr; X Xint rscore[MAXMONSTER]; X Xstruct pac X monst[MAXMONSTER]; X Xstartmonst() X{ X register struct pac *mptr; X register int monstnum; X X if (potion == TRUE) X { X /* don't start if potion active */ X return; X }; X X for (mptr = &monst[0], monstnum = 0; monstnum < MAXMONSTER; mptr++, monstnum++) X { X if (mptr->stat == START) X { X rscore[monstnum] = 1; X X /* clear home */ X PLOT(mptr->ypos, mptr->xpos, VACANT); X X /* initialize moving monster */ X mptr->ypos = MBEGINY; X mptr->xpos = MBEGINX; X mptr->speed = SLOW; X mptr->danger = TRUE; X mptr->stat = RUN; X PLOT(MBEGINY, MBEGINX, MONSTER); X X /* DRIGHT or DLEFT? */ X mptr->dirn = getrand(2) + DLEFT; X break; X }; X }; X} X Xmonster(mnum) X int mnum; X{ X register int newx,newy; X register int tmpx, tmpy; X struct pac *mptr; X int gmod2; X X mptr = &monst[mnum]; X X /* remember monster's current position */ X tmpx = mptr->xpos; X tmpy = mptr->ypos; X X /* if we can, let's move a monster */ X if (mptr->stat == RUN) X { X gmod2 = game % 2; X /* if a monster was displayed ... */ X if ((gmod2 == 1) || X ((gmod2 == 0) && X (( (rounds - 1) % rscore[mnum]) == 0))) X { X /* replace display character */ X PLOT(tmpy, tmpx, display[tmpy][tmpx]); X }; X X /* get a new direction */ X mptr->dirn = which(mptr, tmpx, tmpy); X switch (mptr->dirn) X { X case DUP: X newy = tmpy + UPINT; X newx = tmpx; X break; X X case DDOWN: X newy = tmpy + DOWNINT; X newx = tmpx; X break; X X case DLEFT: X newx = tmpx + LEFTINT; X newy = tmpy; X if (newx <= 0) X newx = XWRAP; /* wrap around */ X break; X X case DRIGHT: X newx = tmpx + RIGHTINT; X newy = tmpy; X if (newx >= XWRAP) X newx = 0; /* wrap around */ X break; X } X X /* use brd to determine if this was a valid direction */ X switch (brd[newy][newx]) X { X case GOLD: X case VACANT: X case POTION: X case TREASURE: X case CHOICE: X /* set new position */ X mptr->xpos = newx; X mptr->ypos = newy; X X /* run into a pacman? */ X if ((newy == pacptr->ypos) && X (newx == pacptr->xpos)) X { X killflg = dokill(mnum); X }; X rscore[mnum] = pscore / 100 + 1; X if ((gmod2 == 1) || (killflg == TURKEY) || X ( (gmod2 == 0) && X ((rounds % rscore[mnum]) == 0))) X { X X if (mptr->danger == TRUE) X { X PLOT(newy, newx, MONSTER); X } X else if (killflg != GOTONE) X { X PLOT(newy, newx, RUNNER); X }; X }; X break; X X default: X errgen("bad direction"); X break; X }; X } X} X Xwhich(mptr, x, y) /* which directions are available ? */ X struct pac *mptr; X int x, y; X{ X register int movecnt; X register int submovecnt; X register int next; X int moves[4]; X int submoves[4]; X int nydirn, nxdirn; X int goodmoves; X int offx, offy; X int tmpdirn; X char *brdptr; X X /* X * As a general rule: determine the set of all X * possible moves, but select only those moves X * that don't require a monster to backtrack. X */ X movecnt = 0; X brdptr = &(brd[y][x]); X if (((tmpdirn = mptr->dirn) != DDOWN) && X ((next = *(brdptr + (BRDX * UPINT))) != WALL) && X (next != GATE)) X { X moves[movecnt++] = DUP; X }; X if ((tmpdirn != DUP) && X ((next = *(brdptr + (BRDX * DOWNINT))) != WALL) && X (next != GATE)) X { X moves[movecnt++] = DDOWN; X }; X if ((tmpdirn != DRIGHT) && X ((next = *(brdptr + LEFTINT)) != WALL) && X (next != GATE)) X { X moves[movecnt++] = DLEFT; X }; X if ((tmpdirn != DLEFT) && X ((next = *(brdptr + RIGHTINT)) != WALL) && X (next != GATE)) X { X moves[movecnt++] = DRIGHT; X }; X X /* X * If the player requested intelligent monsters and X * the player is scoring high ... X */ X if (((game == 3) || (game == 4)) && (getrand(1000) < pscore)) X { X /* make monsters intelligent */ X if (pacptr->danger == TRUE) X { X /* X * Holy Cow!! The pacman is dangerous, X * permit monsters to reverse direction X */ X switch (tmpdirn) X { X case DUP: X if ((*(brdptr + (BRDX * DOWNINT)) != WALL) && X (*(brdptr + (BRDX * DOWNINT)) != GATE)) X { X moves[movecnt++] = DDOWN; X }; X break; X X case DDOWN: X if ((*(brdptr + (BRDX * UPINT)) != WALL) && X (*(brdptr + (BRDX * UPINT)) != GATE)) X { X moves[movecnt++] = DUP; X }; X break; X X case DRIGHT: X if ((*(brdptr + LEFTINT) != WALL) && X (*(brdptr + LEFTINT) != GATE)) X { X moves[movecnt++] = DLEFT; X }; X break; X X case DLEFT: X if ((*(brdptr + RIGHTINT) != WALL) && X (*(brdptr + RIGHTINT) != GATE)) X { X moves[movecnt++] = DRIGHT; X }; X break; X }; X }; X X /* determine the offset from the pacman */ X offx = x - pacptr->xpos; X offy = y - pacptr->ypos; X if (offx > 0) X { X /*need to go left */ X nxdirn = DLEFT; X } X else X { X if (offx < 0) X { X nxdirn = DRIGHT; X } X else X { X /*need to stay here */ X nxdirn = DNULL; X }; X }; X if (offy > 0) X { X /*need to go up */ X nydirn = DUP; X } X else X { X if (offy < 0) X { X /* need to go down */ X nydirn = DDOWN; X } X else X { X /* need to stay here */ X nydirn = DNULL; X }; X }; X goodmoves = 0; X for (submovecnt = 0; submovecnt < movecnt; submovecnt++) X { X if (pacptr->danger == FALSE) X { X if ((moves[submovecnt] == nydirn) || X (moves[submovecnt] == nxdirn)) X { X submoves[goodmoves++] = moves[submovecnt]; X }; X } X else X { X if ((moves[submovecnt] != nydirn) && X (moves[submovecnt] != nxdirn)) X { X submoves[goodmoves++] = moves[submovecnt]; X }; X }; X }; X if (goodmoves > 0) X { X return(submoves[getrand(goodmoves)]); X }; X }; X return(moves[getrand(movecnt)]); X} END-of-./monster.c echo x - ./pacdefs.h sed 's/^X//' >./pacdefs.h << 'END-of-./pacdefs.h' X/* dfp #define POS(row,col) fputs(tgoto(vs_cm,(col),(row)),stdout)*/ X#define POS(row,col) tputs(tgoto(vs_cm,(col),(row)),1,putch) X/* dfp */ X#define PLOT(A,B,C) POS(A,B);putchar(C) X#define SPLOT(A,B,S) POS(A,B);(void)fprintf(stdout, "%s", S) X#define TMPF "/usr/tmp/pacmanXXXXXX" X#define GAME1 '1' X#define GAME2 '2' X#define GAME3 '3' X#define GAME4 '4' X X/* #define MAXSCORE "/usr/games/lib/paclog" */ X#define MAXSCORE "/var/games/pacman.scores" X X#define MSSAVE 5 /* maximum scores saved per game type */ X#define MGTYPE 4 /* Maximum game types */ X#define MAXPAC 3 /* maximum number of pacmen to start */ X#define MAXMONSTER 4 /* max number of monsters */ X#define EMPTY 'E' X#define FULL 'F' X#define LEFT 'h' X#define RIGHT 'l' X#define NORTH 'k' /* means UP, but UP defined in vsinit() */ X#define NNORTH 'w' X#define DOWN 'j' X#define NDOWN 'x' X#define HALT ' ' X#define DELETE '\177' X#define ABORT '\34' X#define QUIT 'q' X#define CNTLS '\23' X#define BUF_SIZE 32 X#define TRUE 1 X#define FALSE 0 X#define UPINT (-1) X#define DOWNINT 1 X#define LEFTINT (-2) X#define RIGHTINT 2 X#define PACMAN '@' X#define MONSTER 'M' X#define RUNNER 'S' X#define TREASURE '$' X#define CHOICE '*' X#define GOLD '+' X#define POTION 'X' X#define VACANT ' ' /* space */ X#define WALL 'O' X#define GATE '-' X#define START 0 X#define RUN 1 X#define FAST 1 X#define SLOW 0 X#define PSTARTX 18 X#define PSTARTY 17 X#define MSTARTX 16 /* monster starting position */ X#define MSTARTY 10 /* monster starting position */ X#define MBEGINX 18 /* monster beginning position */ X#define MBEGINY 7 /* monster beginning position */ X#define TRYPOS 13 X#define TRXPOS 20 X#define GOTONE 1 X#define TURKEY (-1) X#define DUP 1 X#define DDOWN 4 X#define DRIGHT 3 X#define DLEFT 2 X#define DNULL 0 X#define BRDX 40 X#define BRDY 23 X#define XWRAP 38 X#define TREASVAL 20 X#define KILLSCORE 10 X#define BEEP '' /* ctrl-g */ X#define MSTARTINTVL 10 X#define POTINTVL 25 X#define GOLDCNT 185 X#define PUP '^' X#define PDOWN 'v' X#define PLEFT '<' X#define PRIGHT '>' X Xstruct pac X{ X int xpos; /* horizontal position */ X int ypos; /* vertical position */ X int dirn; /* direction of travel */ X int speed; /* FAST/SLOW */ X int danger; /* TRUE if can eat */ X int stat; /* status */ X}; END-of-./pacdefs.h echo x - ./pacman.c sed 's/^X//' >./pacman.c << 'END-of-./pacman.c' X/* X/* PACMAN - written by Dave Nixon, AGS Computers Inc., July, 1981. X/* X/* Terminal handling for video games taken from aliens X/* the original version of aliens is from X/* Fall 1979 Cambridge Jude Miller X/* X/* Score keeping modified and general terminal handling (termcap routines X/* from UCB's ex) added by Rob Coben, BTL, June, 1980. X/* X/* If MSG is defined, the program uses the inter-process message facility X/* of UNIX/TS Augmented to optimize reading the tty while updating the X/* screen. Otherwise, the child process (reading the tty) writes X/* a temporary communications file, which the parent (updating the screen) X/* is constantly seeking to the beginning of and re-reading. (UGH!) X/* If your system has a non-blocking read (read-without-wait), it should X/* be implemented, and the child process could be dispensed with entirely. X*/ X#include X#include "pacdefs.h" X X/* X * global variables X */ X Xextern char X *vs_cm; X Xextern int X putch(); X Xextern char X *tgoto(); X Xextern char X message[]; X Xextern char X initbrd[BRDY][BRDX], X display[BRDY][BRDX]; X Xextern unsigned X pscore; X Xextern struct pac X monst[]; X Xint pacsymb = PACMAN, X rounds, /* time keeping mechanism */ X killflg, X delay, X potion, X goldcnt, /* no. of gold pieces remaining */ X potioncnt; X Xstruct pac X pac; X Xstruct pac X pacstart = X{ X PSTARTX, X PSTARTY, X DNULL, X SLOW, X FALSE X}; X Xstruct pac X *pacptr = &pac; X Xmain() X{ X register int tmp; /* temp variables */ X register int pac_cnt; X register int monstcnt; /* monster number */ X struct pac *mptr; X char gcnt[10]; X X init(); /* global init */ X for (pac_cnt = MAXPAC; pac_cnt > 0; pac_cnt--) X { Xredraw: X clr(); X SPLOT(0, 45, "SCORE: "); X SPLOT(21, 45, "gold left = "); X (void) sprintf(gcnt, "%6d", goldcnt); X SPLOT(21, 57, gcnt); X if (potion == TRUE) X { X SPLOT(3, 45, "COUNTDOWN: "); X }; X pacsymb = PACMAN; X killflg = FALSE; X (void) sprintf(message, "delay = %6d", delay); X SPLOT(22, 45, message); X /* X * PLOT maze X */ X for (tmp = 0; tmp < BRDY; tmp++) X { X SPLOT(tmp, 0, &(display[tmp][0])); X }; X /* initialize a pacman */ X pac = pacstart; X PLOT(pacptr->ypos, pacptr->xpos, pacsymb); X /* display remaining pacmen */ X for (tmp = 0; tmp < pac_cnt - 1; tmp++) X { X PLOT(23, (MAXPAC * tmp), PACMAN); X }; X /* X * Init. monsters X */ X for (mptr = &monst[0], monstcnt = 0; monstcnt < MAXMONSTER; mptr++, monstcnt++) X { X mptr->xpos = MSTARTX + (2 * monstcnt); X mptr->ypos = MSTARTY; X mptr->speed = SLOW; X mptr->dirn = DNULL; X mptr->danger = FALSE; X mptr->stat = START; X PLOT(mptr->ypos, mptr->xpos, MONSTER); X }; X rounds = 0; /* timing mechanism */ X X /* main game loop */ X do X { X if (rounds++ % MSTARTINTVL == 0) X { X startmonst(); X }; X pacman(); X if (killflg == TURKEY) X break; X for (monstcnt = 0; monstcnt < (MAXMONSTER / 2); monstcnt++) X { X monster(monstcnt); /* next monster */ X }; X if (killflg == TURKEY) X break; X if (pacptr->speed == FAST) X { X pacman(); X if (killflg == TURKEY) X break; X }; X for (monstcnt = (MAXMONSTER / 2); monstcnt < MAXMONSTER; monstcnt++) X { X monster(monstcnt); /* next monster */ X }; X if (killflg == TURKEY) X break; X if (potion == TRUE) X { X (void) sprintf(message, "%2d%c", potioncnt, X ((potioncnt == 10) ? BEEP : ' ')); X SPLOT(3, 60, message); X if (--potioncnt <= 0) X { X SPLOT(3, 45, "   "); X potion = FALSE; X pacptr->speed = SLOW; X pacptr->danger = FALSE; X for (monstcnt = 0; monstcnt < MAXMONSTER; monstcnt++) X { X monst[monstcnt].danger = TRUE; X }; X }; X }; X update(); /* score display etc */ X if (goldcnt <= 0) X { X reinit(); X goto redraw; X }; X } while (killflg != TURKEY); X SPLOT(5, 45, "YOU ARE BEING EATEN"); X SPLOT(6, 45, "THIS TAKES ABOUT 2 SECONDS"); X sleep(2); X }; X SPLOT(8, 45, "THE MONSTERS ALWAYS TRIUMPH"); X SPLOT(9, 45, "IN THE END!"); X over(); X} X Xpacman() X{ X register int sqtype; X register int mcnt; X register int tmpx, tmpy; X int deltat; X struct pac *mptr; X X /* pause; wait for the player to hit a key */ X for (deltat = delay; deltat > 0; deltat--); X X /* get instructions from player, but don't wait */ X poll(0); X X /* remember current pacman position */ X tmpx = pacptr->xpos; X tmpy = pacptr->ypos; X X /* "eat" any gold */ X /* update display array to reflect what is on terminal */ X display[tmpy][tmpx] = VACANT; X X /* what next? */ X switch (pacptr->dirn) X { X case DUP: X pacsymb = PUP; X switch (sqtype = display[tmpy + UPINT][tmpx]) X { X case GOLD: X case VACANT: X case CHOICE: X case POTION: X case TREASURE: X X /* erase where the pacman went */ X PLOT(tmpy, tmpx, VACANT); X pacptr->ypos += UPINT; X break; X X default: X pacptr->dirn = DNULL; X break; X }; X break; X case DDOWN: X pacsymb = PDOWN; X switch (sqtype = display[tmpy + DOWNINT][tmpx]) X { X case GOLD: X case VACANT: X case CHOICE: X case POTION: X case TREASURE: X X /* erase where the pacman went */ X PLOT(tmpy, tmpx, VACANT); X pacptr->ypos += DOWNINT; X break; X X default: X pacptr->dirn = DNULL; X break; X }; X break; X case DLEFT: X if(tmpx == 0) X { X /* erase where the pacman went */ X PLOT(tmpy, tmpx, VACANT); X pacptr->xpos = XWRAP; X sqtype = VACANT; X break; X }; X pacsymb = PLEFT; X switch (sqtype = display[tmpy][tmpx + LEFTINT]) X { X case GOLD: X case VACANT: X case CHOICE: X case POTION: X case TREASURE: X X /* erase where the pacman went */ X PLOT(tmpy, tmpx, VACANT); X pacptr->xpos += LEFTINT; X break; X X default: X pacptr->dirn = DNULL; X break; X }; X break; X case DRIGHT: X if(tmpx == XWRAP) X { X /* erase where the pacman went */ X PLOT(tmpy, tmpx, VACANT); X pacptr->xpos = 0; X sqtype = VACANT; X break; X }; X pacsymb = PRIGHT; X switch (sqtype = display[tmpy][tmpx + RIGHTINT]) X { X case GOLD: X case VACANT: X case CHOICE: X case POTION: X case TREASURE: X X /* erase where the pacman went */ X PLOT(tmpy, tmpx, VACANT); X pacptr->xpos += RIGHTINT; X break; X X default: X pacptr->dirn = DNULL; X break; X }; X break; X }; X X /* did the pacman get any points or eat a potion? */ X switch (sqtype) X { X case CHOICE: X case GOLD: X pscore++; X goldcnt--; X break; X X case TREASURE: X pscore += TREASVAL; X break; X X case POTION: X SPLOT(3, 45, "COUNTDOWN: "); X potion = TRUE; X potioncnt = POTINTVL; X pacptr->speed = FAST; X pacptr->danger = TRUE; X X /* slow down monsters and make them harmless */ X mptr = &monst[0]; X for (mcnt = 0; mcnt < MAXMONSTER; mcnt++) X { X if (mptr->stat == RUN) X { X mptr->speed = SLOW; X mptr->danger = FALSE; X }; X mptr++; X }; X break; X }; X X /* did the pacman run into a monster? */ X for (mptr = &monst[0], mcnt = 0; mcnt < MAXMONSTER; mptr++, mcnt++) X { X if ((mptr->xpos == pacptr->xpos) && X (mptr->ypos == pacptr->ypos)) X { X X killflg = dokill(mcnt); X } X else X { X killflg = FALSE; X }; X }; X if (killflg != TURKEY) X { X PLOT(pacptr->ypos, pacptr->xpos, pacsymb); X }; X} END-of-./pacman.c echo x - ./rain.c sed 's/^X//' >./rain.c << 'END-of-./rain.c' X Xstatic char sccsid[] = " rain.c 4.1 82/10/24 "; X X#include X#include X#include X/* rain 11/3/1980 EPS/CITHEP */ X/* cc rain.c -o rain -O -ltermlib */ X#define cursor(col,row) tputs(tgoto(CM,col,row),1,outc) Xoutc(c) X{ X putchar(c); X} Xextern char *UP; Xextern short ospeed; Xstruct sgttyb old_tty; Xchar *LL, *TE, *TI; Xmain(argc,argv) Xint argc; Xchar *argv[]; X{ X extern fputchar(); X char *malloc(); X char *getenv(); X char *tgetstr(), *tgoto(); X float ranf(); X int onsig(); X register int x, y, j; X static int xpos[5], ypos[5]; X register char *CM, *BC, *DN, *ND; X char *tcp; X register char *term; X char tcb[100]; X struct sgttyb sg; X setbuf(stdout,malloc(BUFSIZ)); X if (!(term=getenv("TERM"))) { X fprintf(stderr,"%s: TERM: parameter not set\n",*argv); X exit(1); X } X if (tgetent(malloc(1024),term)<=0) { X fprintf(stderr,"%s: %s: unknown terminal type\n",*argv,term); X exit(1); X } X tcp=tcb; X if (!(CM=tgetstr("cm",&tcp))) { X fprintf(stderr,"%s: terminal not capable of cursor motion\n",*argv); X exit(1); X } X if (!(BC=tgetstr("bc",&tcp))) BC="\b"; X if (!(DN=tgetstr("dn",&tcp))) DN="\n"; X if (!(ND=tgetstr("nd",&tcp))) ND=" "; X TE=tgetstr("te",&tcp); X TI=tgetstr("ti",&tcp); X UP=tgetstr("up",&tcp); X if (!(LL=tgetstr("ll",&tcp))) strcpy(LL=malloc(10),tgoto(CM,0,23)); X gtty(1, &sg); X ospeed=sg.sg_ospeed; X for (j=SIGHUP;j<=SIGTERM;j++) X if (signal(j,SIG_IGN)!=SIG_IGN) signal(j,onsig); X gtty(1, &old_tty); /* save tty bits for exit */ X gtty(1, &sg); X sg.sg_flags&=~(CRMOD|ECHO); X stty(1, &sg); X if (TI) fputs(TI,stdout); X tputs(tgetstr("cl",&tcp),1,fputchar); X fflush(stdout); X for (j=5;--j>=0;) { X xpos[j]=(int)(76.*ranf())+2; X ypos[j]=(int)(20.*ranf())+2; X } X for (j=0;;) { X x=(int)(76.*ranf())+2; X y=(int)(20.*ranf())+2; X cursor(x,y); fputchar('.'); X cursor(xpos[j],ypos[j]); fputchar('o'); X if (j==0) j=4; else --j; X cursor(xpos[j],ypos[j]); fputchar('O'); X if (j==0) j=4; else --j; X cursor(xpos[j],ypos[j]-1); X fputchar('-'); X fputs(DN,stdout); fputs(BC,stdout); fputs(BC,stdout); X fputs("|.|",stdout); X fputs(DN,stdout); fputs(BC,stdout); fputs(BC,stdout); X fputchar('-'); X if (j==0) j=4; else --j; X cursor(xpos[j],ypos[j]-2); fputchar('-'); X fputs(DN,stdout); fputs(BC,stdout); fputs(BC,stdout); X fputs("/ \\",stdout); X cursor(xpos[j]-2,ypos[j]); X fputs("| O |",stdout); X cursor(xpos[j]-1,ypos[j]+1); X fputs("\\ /",stdout); X fputs(DN,stdout); fputs(BC,stdout); fputs(BC,stdout); X fputchar('-'); X if (j==0) j=4; else --j; X cursor(xpos[j],ypos[j]-2); fputchar(' '); X fputs(DN,stdout); fputs(BC,stdout); fputs(BC,stdout); X fputchar(' '); fputs(ND,stdout); fputchar(' '); X cursor(xpos[j]-2,ypos[j]); X fputchar(' '); fputs(ND,stdout); fputchar(' '); X fputs(ND,stdout); fputchar(' '); X cursor(xpos[j]-1,ypos[j]+1); X fputchar(' '); fputs(ND,stdout); fputchar(' '); X fputs(DN,stdout); fputs(BC,stdout); fputs(BC,stdout); X fputchar(' '); X xpos[j]=x; ypos[j]=y; X fflush(stdout); X } X} Xonsig(n) Xint n; X{ X struct sgttyb sg; X fputs(LL, stdout); X if (TE) fputs(TE, stdout); X fflush(stdout); X stty(1, &old_tty); X kill(getpid(),n); X _exit(0); X} Xfputchar(c) Xchar c; X{ X putchar(c); X} Xfloat ranf() { X return((float)rand()/2147483647.); X} END-of-./rain.c echo x - ./util.c sed 's/^X//' >./util.c << 'END-of-./util.c' X#include X#include X#ifdef HAVE_TERMIOS X#include X#include X#else X#include X#endif X#include X#include "pacdefs.h" X X#ifndef O_RDWR X#define O_RDWR 2 X#define O_CREAT 0 X#define O_RDONLY 0 X#define O_NDELAY 0 X#endif X X#if !HAVE_SIGSET X#define sigset signal X#endif X Xextern char X *BC, X *UP; X Xextern int X putch(); X Xextern char X *tgoto(), X *mktemp(); X Xextern int X delay, X errno, X goldcnt; X Xextern long X time(); X Xextern void X leave(); X Xextern struct pac X *pacptr; X Xextern struct pac X monst[]; X X#ifndef MSG Xint comfile; X#else Xstruct mstruct X{ X int frompid; X int mtype; X}; X X#endif X X#ifndef NODELAY X X#ifndef MSG Xchar *fnam; X#endif X X#endif X X/* X * initbrd is used to re-initialize the display X * array once a new game is started. X */ Xchar initbrd[BRDY][BRDX] = X{ X"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", X"O + + + * + + + + OOO + + + + * + + + O", X"O X OOO + OOOOO + OOO + OOOOO + OOO X O", X"O * + + * + * + * + + * + * + * + + * O", X"O + OOO + O + OOOOOOOOOOO + O + OOO + O", X"O + + + * O + + + OOO + + + O * + + + O", X"OOOOOOO + OOOOO + OOO + OOOOO + OOOOOOO", X" O + O + + * + + * + + O + O ", X" O + O + OOO - - OOO + O + O ", X"OOOOOOO + O + O O + O + OOOOOOO", X" * + * O O * + * ", X"OOOOOOO + O + O O + O + OOOOOOO", X" O + O + OOOOOOOOOOO + O + O ", X" O + O * + + + + + + * O + O ", X"OOOOOOO + O + OOOOOOOOOOO + O + OOOOOOO", X"O + + + * + * + + OOO + + * + * + + + O", X"O X OOO + OOOOO + OOO + OOOOO + OOO X O", X"O + + O * + * + * + + * + * + * O + + O", X"OOO + O + O + OOOOOOOOOOO + O + O + OOO", X"O + * + + O + + + OOO + + + O + + * + O", X"O + OOOOOOOOOOO + OOO + OOOOOOOOOOO + O", X"O + + + + + + + * + + * + + + + + + + O", X"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", X}; X X/* X * brd is kept for historical reasons. X * It should only be used in the routine "which" X * to determine the next move for a monster or X * in the routine "monster" to determine if it X * was a valid move. Admittedly this is redundant X * and could be replaced by initbrd, but it is kept X * so that someday additional intelligence or X * optimization could be added to the choice of X * the monster's next move. Hence, note the symbol X * CHOICE at most points that a move decision X * logically HAS to be made. X */ Xchar brd[BRDY][BRDX] = X{ X"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", X"O + + + * + + + + OOO + + + + * + + + O", X"O X OOO + OOOOO + OOO + OOOOO + OOO X O", X"O * + + * + * + * + + * + * + * + + * O", X"O + OOO + O + OOOOOOOOOOO + O + OOO + O", X"O + + + * O + + + OOO + + + O * + + + O", X"OOOOOOO + OOOOO + OOO + OOOOO + OOOOOOO", X" O + O + + * + + * + + O + O ", X" O + O + OOO - - OOO + O + O ", X"OOOOOOO + O + O O + O + OOOOOOO", X" * + * O O * + * ", X"OOOOOOO + O + O O + O + OOOOOOO", X" O + O + OOOOOOOOOOO + O + O ", X" O + O * + + + + + + * O + O ", X"OOOOOOO + O + OOOOOOOOOOO + O + OOOOOOO", X"O + + + * + * + + OOO + + * + * + + + O", X"O X OOO + OOOOO + OOO + OOOOO + OOO X O", X"O + + O * + * + * + + * + * + * O + + O", X"OOO + O + O + OOOOOOOOOOO + O + O + OOO", X"O + * + + O + + + OOO + + + O + + * + O", X"O + OOOOOOOOOOO + OOO + OOOOOOOOOOO + O", X"O + + + + + + + * + + * + + + + + + + O", X"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", X}; X X/* X * display reflects the screen on the player's X * terminal at any point in time. X */ Xchar display[BRDY][BRDX] = X{ X"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", X"O + + + + + + + + OOO + + + + + + + + O", X"O X OOO + OOOOO + OOO + OOOOO + OOO X O", X"O + + + + + + + + + + + + + + + + + + O", X"O + OOO + O + OOOOOOOOOOO + O + OOO + O", X"O + + + + O + + + OOO + + + O + + + + O", X"OOOOOOO + OOOOO + OOO + OOOOO + OOOOOOO", X" O + O + + + + + + + + O + O ", X" O + O + OOO - - OOO + O + O ", X"OOOOOOO + O + O O + O + OOOOOOO", X" + + + O O + + + ", X"OOOOOOO + O + O O + O + OOOOOOO", X" O + O + OOOOOOOOOOO + O + O ", X" O + O + + + + + + + + O + O ", X"OOOOOOO + O + OOOOOOOOOOO + O + OOOOOOO", X"O + + + + + + + + OOO + + + + + + + + O", X"O X OOO + OOOOO + OOO + OOOOO + OOO X O", X"O + + O + + + + + + + + + + + + O + + O", X"OOO + O + O + OOOOOOOOOOO + O + O + OOO", X"O + + + + O + + + OOO + + + O + + + + O", X"O + OOOOOOOOOOO + OOO + OOOOOOOOOOO + O", X"O + + + + + + + + + + + + + + + + + + O", X"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", X}; X X/* terminal type from environment and /etc/termcap ala ex & vi */ Xchar *vs_cl = "", /* clear screen sequence */ X *vs_cm = "", /* cursor positioning sequence */ X *vs_vb = ""; X Xchar combuf[BUFSIZ], X message[81], /* temporary message buffer */ X inbuf[2]; X Xint ppid, X cpid, X game, X killcnt = 0, X vs_rows, X vs_cols; X Xunsigned X pscore; X Xlong timein; X X#ifdef HAVE_TERMIOS Xstruct termios X savetty, X newtty; X#else Xstruct sgttyb X savetty, newtty; X#endif X Xstruct uscore X{ X unsigned score; /* same type as pscore */ X int uid; /* uid of player */ X}; X Xstruct scorebrd X{ X struct uscore entry[MSSAVE]; X} scoresave[MGTYPE] = X { X 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, X 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, X 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, X 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 X }; X Xvoid nap (int naptime) X{ X#ifdef HAVE_USLEEP X usleep (naptime * 18000); X#else X register int i = naptime * 5000; X while (i--); X#endif X} X Xupdate() X{ X char str[10]; X X (void) sprintf(str, "%6d", pscore); X SPLOT(0, 52, str); X (void) sprintf(str, "%6d", goldcnt); X SPLOT(21, 57, str); X} X Xreinit() X{ X register int locx, locy; X register char tmp; X X for (locy = 0; locy < BRDY; locy++) X { X for (locx = 0; locx < BRDX; locx++) X { X tmp = initbrd[locy][locx]; X brd[locy][locx] = tmp; X if ((display[locy][locx] = tmp) == CHOICE) X { X display[locy][locx] = GOLD; X }; X }; X }; X goldcnt = GOLDCNT; X delay -= (delay / 10); /* hot it up */ X} X Xerrgen(string) Xchar *string; X{ X SPLOT(23,45,string); X} X Xdokill(mnum) X int mnum; X{ X register struct pac *mptr; X X PLOT(0, 0, BEEP); X if (pacptr->danger == TRUE) X { X if (++killcnt == MAXMONSTER) X { X if (display[TRYPOS][TRXPOS] == GOLD) X { X goldcnt--; X }; X display[TRYPOS][TRXPOS] = TREASURE; X PLOT(TRYPOS, TRXPOS, TREASURE); X killcnt = 0; X }; X SPLOT(5, 45, "MONSTERS KILLED: "); X (void) sprintf(message, "%1d", killcnt); X SPLOT(5, 62, message); X mptr = (&monst[mnum]); X mptr->ypos = MSTARTY; X mptr->xpos = MSTARTX + (2 * mnum); X mptr->stat = START; X PLOT(mptr->ypos, mptr->xpos, MONSTER); X pscore += KILLSCORE; X return(GOTONE); X }; X return(TURKEY); X} X X/* X/* clr -- issues an escape sequence to clear the display X*/ X Xclr() X{ X /* ... kre X (void) fprintf(stdout, "%s", vs_cl); X fflush(stdout); X nap(2); X */ X tputs(vs_cl, vs_rows, putch); X fflush(stdout); X} X X/* X * display initial instructions X */ X Xinstruct() X{ X clr(); X POS(0, 0); X (void) fprintf(stdout, "Attention: you are in a dungeon, being chased by monsters!\r\n\n"); X (void) fprintf(stdout, "There are gold coins scattered uniformly in the dungeon, marked by \"+\".\r\n"); X (void) fprintf(stdout, "One magic potion is available at each spot marked \"X\". Each potion will\r\n"); X (void) fprintf(stdout, "enable you to kill monsters by touch for a limited duration. It will also\r\n"); X (void) fprintf(stdout, "scare them away. When you kill a monster it is regenerated, but this takes\r\n"); X (void) fprintf(stdout, "time. You can also regenerate yourself %d times. Killing all the monsters\r\n", MAXPAC); X (void) fprintf(stdout, "results in further treasure appearing magically somewhere in the dungeon,\r\n"); X (void) fprintf(stdout, "marked by \"$\". There is a magic tunnel connecting the center left and\r\n"); X (void) fprintf(stdout, "center right parts of the dungeon. The monsters know about it!\r\n\n"); X (void) fprintf(stdout, " Type: h to move left\r\n"); X (void) fprintf(stdout, " l to move right\r\n"); X (void) fprintf(stdout, " k or w to move up\r\n"); X (void) fprintf(stdout, " j or x to move down\r\n"); X (void) fprintf(stdout, " to halt \r\n"); X (void) fprintf(stdout, " q to quit\r\n\n"); X (void) fprintf(stdout, " Type: 1 normal game\r\n"); X (void) fprintf(stdout, " 2 blinking monsters\r\n"); X (void) fprintf(stdout, " 3 intelligent monsters\r\n"); X (void) fprintf(stdout, " 4 blinking intelligent monsters\r\n"); X} X X/* X * over -- game over processing X */ X Xover() X{ X register int i; X register int line; X int scorefile = 0; X struct passwd *getpwuid(), *p; X X fflush(stdout); X sleep(5); /* for slow readers */ X poll(0); /* flush and discard input from player */ X clr(); X /* high score to date processing */ X if (game != 0) X { X line = 7; X POS(line++, 20); X (void) fprintf(stdout, " ___________________________ "); X POS(line++, 20); X (void) fprintf(stdout, "| |"); X POS(line++, 20); X (void) fprintf(stdout, "| G A M E O V E R |"); X POS(line++, 20); X (void) fprintf(stdout, "| |"); X POS(line++, 20); X (void) fprintf(stdout, "| Game type: %1d |",game); X if ((scorefile = open(MAXSCORE, O_RDWR | O_CREAT, 0666)) != -1) X { X read(scorefile, (char *)scoresave, sizeof(scoresave)); X for (i = MSSAVE - 1; i >= 0; i--) { X if (scoresave[game - 1].entry[i].score < pscore) X { X if (i < MSSAVE - 1) X { X scoresave[game - 1].entry[i + 1].score = X scoresave[game - 1].entry[i].score; X scoresave[game - 1].entry[i + 1].uid = X scoresave[game - 1].entry[i].uid; X }; X scoresave[game - 1].entry[i].score = pscore; X scoresave[game - 1].entry[i].uid = getuid(); X }; X }; X lseek(scorefile, 0l, 0); X write(scorefile, (char *)scoresave, sizeof(scoresave)); X close(scorefile); X POS(line++, 20); X (void) fprintf(stdout, "| High Scores to date: |"); X for (i = 0; i < MSSAVE; i++) X { X setpwent(); X p = getpwuid(scoresave[game - 1].entry[i].uid); X POS(line++, 20); X (void) fprintf(stdout, "| Player : %-8s %5u |", p->pw_name, X scoresave[game - 1].entry[i].score); X }; X } X else X { X POS(line++, 20); X (void) fprintf(stdout, "| |"); X POS(line++, 20); X (void) fprintf(stdout, "| Please create a 'paclog' |"); X POS(line++, 20); X (void) fprintf(stdout, "| file. See 'MAXSCORE' in |"); X POS(line++, 20); X (void) fprintf(stdout, "| 'pacdefs.h'. |"); X }; X POS(line++, 20); X (void) fprintf(stdout, "| |"); X POS(line++, 20); X (void) fprintf(stdout, "| Your score: %-5u |", pscore); X POS(line, 20); X (void) fprintf(stdout, "|___________________________|"); X }; X leave(); X} X X/* X * leave -- flush buffers,kill the Child, reset tty, and delete tempfile X */ X Xvoid leave() X{ X POS(23, 0); X (void) fflush(stdout); X sleep(1); X X#ifndef NODELAY X kill(cpid, SIGKILL); X#endif X X#ifdef HAVE_TERMIOS X tcsetattr (0, TCSANOW, &savetty); X#else X ioctl(0, TIOCSETP, &savetty); X#endif X X#ifndef NODELAY X X#ifndef MSG X close(comfile); X unlink(fnam); X#endif X X#endif X exit(0); X} X X/* X * init -- does global initialization and spawns a child process to read X * the input terminal. X */ X Xinit() X{ X register int tries = 0; X static int lastchar = DELETE; X extern short ospeed; /* baud rate for crt (for tputs()) */ X X errno = 0; X (void) time(&timein); /* get start time */ X srand((unsigned)timein); /* start rand randomly */ X /* X * verify CRT and get proper cursor control sequence. X */ X X#ifdef NODELAY X X#ifndef BELL30 X close(0); X if (open("/dev/tty", O_RDONLY | O_NDELAY) != 0) X { X perror("Unable to open /dev/tty"); X exit(1); X }; X#endif X X#endif X vsinit(); X /* X * setup raw mode, no echo X */ X#ifdef SIGTSTP X sigset(SIGTSTP, SIG_IGN); /* ignore ^Z (too hard just now) .. kre */ X#endif X#ifdef SIG_HOLD X sigset(SIGINT, SIG_HOLD); /* keep ints till we are ready .. kre */ X#endif X#ifdef HAVE_TERMIOS X tcgetattr (0, &savetty); X newtty = savetty; X if (savetty.c_ospeed >= B9600) X delay = 1000 * (getrand(10) + 5); X else X delay = 1000; X ospeed = savetty.c_ospeed; /* for tputs() */ X#ifdef NODELAY X newtty.c_cc[VTIME] = 7; X newtty.c_cc[VMIN] = 0; X#else X newtty.c_cc[VMIN] = 1; X#endif X newtty.c_iflag = 0; X newtty.c_oflag &= ~OPOST; X newtty.c_cflag &= ~(PARENB | CSIZE); X newtty.c_cflag |= CS8; X /* newtty.c_lflag &= ~(ECHO | ECHOE | ISIG | ICANON); */ X newtty.c_lflag &= ~(ECHO | ECHOE | ICANON); X tcsetattr (0, TCSANOW, &newtty); X#else X ioctl(0, TIOCGETP, &savetty); X newtty = savetty; X if (savetty.sg_ospeed >= B9600) X delay = 1000 * (getrand(10) + 5); X else X delay = 1000; X ospeed = savetty.sg_ospeed; /* for tputs() */ X newtty.sg_flags |= CBREAK; X newtty.sg_flags &= ~ECHO; X ioctl(0, TIOCSETP, &newtty); X#endif X X /* X * set up communications X */ X X#ifndef NODELAY X X#ifndef MSG X fnam = mktemp(TMPF); X if ((comfile = creat(fnam, 0666)) == -1) X { X (void) sprintf(message, "Cannot create %s", fnam); X perror(message); X leave(); X }; X /* X * initialize semaphore X */ X lseek(comfile, 0l, 0); X combuf[1] = EMPTY; X write(comfile, combuf, 2); X close(comfile); X#endif X#endif X X#ifndef NODELAY X /* X * fork off a child to read the input X */ X ppid = getpid(); X if ((cpid = fork()) == 0) X { X#ifndef MSG X comfile = open(fnam, O_RDWR); X#endif X for (;;) X { X read(0, inbuf, 1); X if (lastchar != inbuf[0]) X { X#ifdef MSG X if (inbuf[0] == DELETE || inbuf[0] == ABORT) X leave(); X send(inbuf, 1, ppid, 64); X#else X lseek(comfile, 0l, 0); X read(comfile, combuf, 2); X if (combuf[1] == EMPTY) X { X lseek(comfile, 0l, 0); X combuf[0] = inbuf[0]; X combuf[1] = FULL; X write(comfile, combuf, 2); X }; X#endif X }; X lastchar = DELETE; X }; X }; X X#ifndef MSG X comfile = open(fnam, O_RDWR); X#else X msgenab(); X#endif X X#endif X sigset(SIGINT, leave); X /* X * New game starts here X */ X game = 0; X instruct(); X while ((game == 0) && (tries++ < 300)) X { X poll(1); X }; X if (tries >= 300) X { X /* I give up. Let's call it quits. */ X leave(); X }; X goldcnt = GOLDCNT; X pscore = 0; X clr(); X} X X/* X * poll -- read characters sent by input subprocess and set global flags X */ X Xpoll(sltime) X{ X int stop; X register int charcnt; X int junk; X X#ifndef NODELAY X#ifdef MSG X struct mstruct msghead; X#endif X#endif X X stop = 0; Xreadin: X X#ifdef NODELAY X fflush(stdout); X charcnt = 0; X nap(12); X#ifdef FIONREAD X ioctl(0, FIONREAD, &junk); X if (junk) X#endif X charcnt = read(0, combuf, 1); X switch (charcnt) X { X X case 0: X combuf[1] = EMPTY; X break; X X case -1: X errgen("READ ERROR IN POLL"); X abort(); X X default: X combuf[0] = combuf[charcnt-1]; X combuf[1] = FULL; X break; X }; X#else X X#ifdef MSG X combuf[1] = (recv(combuf, 1, &msghead, 0) == -1) ? EMPTY : FULL; X#else X lseek(comfile, 0l, 0); /* rewind */ X read(comfile, combuf, 2); /* read 2 chars */ X#endif X X#endif X if (combuf[1] == EMPTY) X { X#ifndef BELL30 X X#ifndef NODELAY X if (sltime > 0) X { X sleep(sltime); X }; X#endif X X#endif X if (stop) X { X goto readin; X }; X return; X }; X combuf[1] = EMPTY; X X#ifndef NODELAY X X#ifndef MSG X lseek(comfile, 0l, 0); /* another rewind */ X write(comfile, combuf, 2); X#endif X#endif X X switch(combuf[0] & 0177) X { X case LEFT: X pacptr->dirn = DLEFT; X break; X X case RIGHT: X pacptr->dirn = DRIGHT; X break; X X case NORTH: X case NNORTH: X pacptr->dirn = DUP; X break; X X case DOWN: X case NDOWN: X pacptr->dirn = DDOWN; X break; X X case HALT: X pacptr->dirn = DNULL; X break; X X case ABORT: X case DELETE: X case QUIT: X over(); X break; X X case CNTLS: X stop = 1; X goto readin; X X case GAME1: X game = 1; X break; X X case GAME2: X game = 2; X break; X X case GAME3: X game = 3; X break; X X case GAME4: X game = 4; X break; X X default: X goto readin; X } X} X Xvsinit() X{ X char buf[1024], *tp; X static char tspace[512]; X char *aoftspace; X char *tgetstr(); X extern char *UP, *BC; /* defined in tgoto.c (from ex's termlib */ X extern char PC; /* defined in tputs.c (from termlib) */ X X tgetent(buf, getenv("TERM")); X aoftspace = tspace; X vs_cl = tgetstr("cl", &aoftspace); X vs_cm = tgetstr("cm", &aoftspace); X BC = tgetstr("bc", &aoftspace); X UP = tgetstr("up", &aoftspace); X if ((tp = tgetstr("pc", &aoftspace)) != NULL) X PC = *tp; X vs_rows = tgetnum("li"); X vs_cols = tgetnum("co"); X/* what total crap .. kre X vs_vb = tgetstr("vb", &aoftspace); X if ((vs_vb == 0) || (*vs_vb == '\0')) X { X vs_vb = aoftspace; X *vs_vb++ = ''; X *vs_vb++ = '\0'; X aoftspace += 2; X }; X*/ X if ((vs_cl == 0) || (*vs_cl == '\0') || X (vs_cm == 0) || (*vs_cm == '\0')) X { X (void) fprintf(stderr, "\nPacman is designed for CRT's with addressable cursors.\n"); X (void) fprintf(stderr, "Verify that the TERM environment variable is a proper\n"); X (void) fprintf(stderr, "type and is export-ed, and try it again...\n\n"); X exit(2); X }; X} X Xgetrand(range) X int range; X{ X register unsigned int q; X X q = rand(); X return(q % range); X} X X X/* dfp - real function for tputs function to use */ Xputch( ch ) X register int ch; X{ X putchar( ch ); X} END-of-./util.c echo x - ./pacman.6 sed 's/^X//' >./pacman.6 << 'END-of-./pacman.6' X.\" X.\" @(#)pacman.6 X.\" X.Dd "March 18, 1995" X.Dt PACMAN 6 X.Os X.Sh NAME X.Nm pacman X.Nd the game of pacman X.Sh SYNOPSIS X.Nm X.Sh DESCRIPTION XThe X.Nm Xcommand runs display-based game which must be played on a CRT terminal. XThe object is to eat and not get eaten. X.Pp XThe default control keys are as follows: X.Bl -tag -width "" -compact -offset indent X.It l Xmove right X.It h Xmove left X.It j Xmove down X.It k Xmove up X.It Xpause X.It q Xquit X.El X.Sh PLAY XUse the direction keys to move your critter about the maze. Eat Xas many gold coins as you can. Aim for treasure and eat them for extra Xpoints. Avoid the monsters. X.Sh SCORING XYou score a point each time your critter eats a gold coin. You score Xtwenty points for eating treasure and ten points for eating monsters. X.Sh FILES X.Bl -tag -width indent X.It /var/games/pacman.scores Xhigh score file X.El X.Sh BUGS XThis man page does not completely describe the game. X.Sh AUTHORS XOriginally written by Dave Nixon, AGS Computers Inc., July, 1981. X.Pp XTerminal handling for video games taken from aliens, written by Jude XMiller, fall 1979. X.Pp XScore keeping modified and general terminal handling from UCB's ex Xadded by Rob Coben, BTL, June, 1980. END-of-./pacman.6 exit