Aucbarpa.1050 net.sources utcsrgv!utzoo!decvax!ucbvax!G:ARPAVAX:mark Sun Apr 4 15:21:03 1982 pacman/util.c #include "pacdefs.h" #include #include extern char *mktemp(); extern int delay, errno, wmonst, boardcount, rounds, monsthere, potintvl, treascnt, goldcnt; extern long time(); extern struct pac *pacptr; extern struct pac monst[]; extern char monst_names[]; extern char *full_names[]; /* * initbrd is used to re-initialize the display * array once a new game is started. */ char initbrd[BRDY][BRDX] = { "#######################################", "# . . . * . . . . ### . . . . * . . . #", "# O ### . ##### . ### . ##### . ### O #", "# * . . * . * . * . . * . * . * . . * #", "# . ### . # . ########### . # . ### . #", "# . . . * # . . . ### . . . # * . . . #", "####### . ##### . ### . ##### . #######", " # . # . . * . . * . . # . # ", " # . # . ### - - ### . # . # ", "####### . # . # # . # . #######", " * . * # # * . * ", "####### . # . # # . # . #######", " # . # . ########### . # . # ", " # . # * . . . . . . * # . # ", "####### . # . ########### . # . #######", "# . . . * . * . . ### . . * . * . . . #", "# O ### . ##### . ### . ##### . ### O #", "# . . # * . * . * . . * . * . * # . . #", "### . # . # . ########### . # . # . ###", "# . * . . # . . . ### . . . # . . * . #", "# . ########### . ### . ########### . #", "# . . . . . . . * . . * . . . . . . . #", "#######################################", }; /* * brd is kept for historical reasons. * It should only be used in the routine "which" * to determine the next move for a monster or * in the routine "monster" to determine if it * was a valid move. Admittedly this is redundant * and could be replaced by initbrd, but it is kept * so that someday additional intelligence or * optimization could be added to the choice of * the monster's next move. Hence, note the symbol * CHOICE at most points that a move decision * logically HAS to be made. */ char brd[BRDY][BRDX] = { "#######################################", "# . . . * . . . . ### . . . . * . . . #", "# O ### . ##### . ### . ##### . ### O #", "# * . . * . * . * . . * . * . * . . * #", "# . ### . # . ########### . # . ### . #", "# . . . * # . . . ### . . . # * . . . #", "####### . ##### . ### . ##### . #######", " # . # . . * . . * . . # . # ", " # . # . ### - - ### . # . # ", "####### . # . # # . # . #######", " * . * # # * . * ", "####### . # . # # . # . #######", " # . # . ########### . # . # ", " # . # * . . . . . . * # . # ", "####### . # . ########### . # . #######", "# . . . * . * . . ### . . * . * . . . #", "# O ### . ##### . ### . ##### . ### O #", "# . . # * . * . * . . * . * . * # . . #", "### . # . # . ########### . # . # . ###", "# . * . . # . . . ### . . . # . . * . #", "# . ########### . ### . ########### . #", "# . . . . . . . * . . * . . . . . . . #", "#######################################", }; /* * display reflects the screen on the player's * terminal at any point in time. */ char display[BRDY][BRDX] = { "#######################################", "# . . . . . . . . ### . . . . . . . . #", "# O ### . ##### . ### . ##### . ### O #", "# . . . . . . . . . . . . . . . . . . #", "# . ### . # . ########### . # . ### . #", "# . . . . # . . . ### . . . # . . . . #", "####### . ##### . ### . ##### . #######", " # . # . . . . . . . . # . # ", " # . # . ### - - ### . # . # ", "####### . # . # # . # . #######", " . . . # # . . . ", "####### . # . # # . # . #######", " # . # . ########### . # . # ", " # . # . . . . . . . . # . # ", "####### . # . ########### . # . #######", "# . . . . . . . . ### . . . . . . . . #", "# O ### . ##### . ### . ##### . ### O #", "# . . # . . . . . . . . . . . . # . . #", "### . # . # . ########### . # . # . ###", "# . . . . # . . . ### . . . # . . . . #", "# . ########### . ### . ########### . #", "# . . . . . . . . . . . . . . . . . . #", "#######################################", }; char combuf[BUFSIZ], message[81], /* temporary message buffer */ inbuf[2]; int ppid, cpid, game, killcnt = 0, vs_rows, vs_cols; unsigned pscore; long timein; struct uscore { unsigned score; /* same type as pscore */ int uid; /* uid of player */ }; struct scorebrd { struct uscore entry[MSSAVE]; } scoresave[MGTYPE] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; update() { char str[10]; sprintf(str, "%6d", pscore); SPLOT(0, 52, str); sprintf(str, "%6d", goldcnt); SPLOT(21, 57, str); } reinit() { register int locx, locy; register char tmp; if (boardcount % 2 == 0) movie(); for (locy = 0; locy ypos = MSTARTY; mptr->xpos = MSTARTX + (2 * mnum); mptr->danger = TRUE; mptr->stat = START; PLOT(mptr->ypos, mptr->xpos, monst_names[mnum]); monsthere++; rounds = 1; /* force it to be a while before he comes out */ switch (monsthere) { case 1: pscore += KILLSCORE; break; case 2: pscore += 2 * KILLSCORE; break; case 3: pscore += 4 * KILLSCORE; break; case 4: pscore += 8 * KILLSCORE; break; } sprintf(msgbuf, "You got %s!\n", full_names[mnum]); SPLOT(4, 45, msgbuf); return(GOTONE); }; wmonst = mnum; return(TURKEY); } /* /* clr -- issues an escape sequence to clear the display */ clr() { clear(); } printw(fmt, p1, p2, p3, p4) char *fmt; int p1, p2, p3, p4; { static char buf[100]; sprintf(buf, fmt, p1, p2, p3, p4); addstr(buf); } /* * display initial instructions */ instruct() { clr(); POS(0, 0); printw("Attention: you are in a maze, being chased by monsters!\n\n"); printw("There is food scattered uniformly in the maze, marked by \".\".\n"); printw("One magic potion is available at each spot marked \"O\". Each potion will\n"); printw("enable you to eat monsters for a limited duration. It will also\n"); printw("scare them away. When you eat a monster it is regenerated, but this takes\n"); printw("time. You can also regenerate yourself %d times. Eating all the monsters\n", MAXPAC); printw("results in further treasure appearing magically somewhere in the dungeon,\n"); printw("marked by \"$\". There is a magic tunnel connecting the center left and\n"); printw("center right parts of the dungeon. The monsters know about it!\n\n"); printw(" Type: h or s to move left\n"); printw(" l or f to move right\n"); printw(" k or e to move up\n"); printw(" j or c to move down\n"); printw(" to halt \n"); printw(" q to quit\n\n"); printw(" Type: 1 easy game\n"); printw(" 2 intelligent monsters\n"); printw(" 3 very intelligent monsters\n"); refresh(); } /* * over -- game over processing */ over() { register int i; register int line, col; int scorefile = 0; struct passwd *getpwuid(), *p; refresh(); signal(SIGINT, SIG_IGN); /* clr(); */ /* high score to date processing */ if (game != 0) { col = 45; line = 10; POS(line++, col); (void) printw(" ___________________________ "); POS(line++, col); (void) printw("| G A M E O V E R |"); POS(line++, col); (void) printw("| |"); POS(line++, col); (void) printw("| Game type: %6.6s |",game==1?"easy":game==2?"medium":"smart"); if ((scorefile = open(MAXSCORE, 2)) != -1) { read(scorefile, (char *)scoresave, sizeof(scoresave)); for (i = MSSAVE - 1; i >= 0; i--) { if (scoresave[game - 1].entry[i].score pw_name, scoresave[game - 1].entry[i].score); }; } else { /* clr(); */ POS(line++, col); (void) printw("| |"); POS(line++, col); (void) printw("| Please create a 'paclog' |"); POS(line++, col); (void) printw("| file. See 'MAXSCORE' in |"); POS(line++, col); (void) printw("| 'pacdefs.h'. |"); }; POS(line, col); (void) printw("|___________________________|"); }; refresh(); leave(); } /* * leave -- flush buffers,kill the Child, reset tty, and delete tempfile */ leave() { POS(23, 0); refresh(); endwin(); exit(0); } /* * init -- does global initialization and spawns a child process to read * the input terminal. */ init() { register int tries = 0; static int lastchar = DELETE; extern short ospeed; /* baud rate for crt (for tputs()) */ int over(); #ifdef USG struct termio t; #endif errno = 0; (void) time(&timein); /* get start time */ srand((unsigned)timein); /* start rand randomly */ signal(SIGINT, over); signal(SIGQUIT, over); /* Curses init - could probably eliminate much of stuff below */ initscr(); noecho(); crmode(); nonl(); leaveok(stdscr, TRUE); vs_rows = LINES; vs_cols = COLS; #ifdef USG ioctl(0, TCGETA, &t); t.c_cc[VTIME] = 0; t.c_cc[VMIN] = 0; ioctl(0, TCSETA, &t); #endif if (delay == 0) delay = 500; /* number of ticks per turn */ /* * New game starts here */ if (game == 0) instruct(); while ((game == 0) && (tries++ = 300) { /* I give up. Let's call it quits. */ leave(); }; goldcnt = GOLDCNT; pscore = 0; clr(); } /* * poll -- read characters sent by input subprocess and set global flags */ poll(sltime) { int stop; register int charcnt; int junk; stop = 0; readin: refresh(); /* Check for input we've seen but not processed */ if (combuf[1] == FULL) charcnt = 1; else charcnt = 0; #ifdef FIONREAD /* Check for typeahead on 4BSD systems. */ if (charcnt <= #ELSE GOTO &JUNK); & (CHARCNT /* <="0)" TRY A (JUNK) }; 0) ELSE 0: { } (COMBUF[1]="=" READIN; COMBUF, ERRGEN("READ RETURN; CASE SWITCH(COMBUF[0] NOTHING CHARCNT="read(0," DEFAULT: TO HAVE ERROR READ POLL"); COMBUF[0]="combuf[charcnt-1];" LEFT: #ENDIF (STOP) PACPTR- BREAK; ABORT(); COMBUF[1]="EMPTY;" EMPTY) WORKED. IOCTL(0, */ IF (CHARCNT) IN SWITCH FIONREAD, 1); -1: 0177)>dirn = DLEFT; break; case RIGHT: pacptr->dirn = DRIGHT; break; case NORTH: case NNORTH: pacptr->dirn = DUP; break; case DOWN: case NDOWN: pacptr->dirn = DDOWN; break; case HALT: pacptr->dirn = DNULL; break; case REDRAW: clearok(curscr, TRUE); break; case ABORT: case DELETE: case QUIT: over(); break; case CNTLS: stop = 1; goto readin; case GAME1: game = 1; break; case GAME2: game = 2; break; case GAME3: game = 3; break; default: goto readin; } } getrand(range) int range; { register unsigned int q; q = rand(); return(q % range); } /* * This function is convenient for debugging pacman. It isn't used elsewhere. * It's like printf and prints in a window on the right hand side of the screen. */ msgf(fmt, arg1, arg2, arg3, arg4) char *fmt; int arg1, arg2, arg3, arg4; { char msgbuf[100]; static char msgline = 13; sprintf(msgbuf, fmt, arg1, arg2, arg3, arg4); SPLOT(msgline, 45, msgbuf); if (msgline++ > 20) msgline = 13; } /* * napms. Sleep for ms milliseconds. We don't expect a particularly good * resolution - 60ths of a second is normal, 10ths might even be good enough, * but the rest of the program thinks in ms because the unit of resolution * varies from system to system. (In some countries, it's 50ths, for example.) * * If you're thinking of replacing this with a call to sleep, or by outputting * some pad characters, forget it. You won't get a decent game. You absolutely * HAVE to have a fraction-of-a-second sleep. Sleeping for a full second will * make the game seem really slow. Outputting pad characters will cause the * keyboard to be ahead of the display by whatever buffering the tty driver * does, typically about one second. This causes you to have to anticipate * your moves and also makes response dependent on system load - in general * the game will be crummy. * * Here are some reasonable ways to get a good nap. * * (1) Use the select (dselect?) system call in Berkeley 4.2BSD. * * (2) Use the 1/10th second resolution wait in the UNIX 3.0 tty driver. * (This is untested - rumor has it that this feature does not work * as advertised, and there might also be problems with the user hitting * a key too soon.) * * (3) Install the ft (fast timer) device in your kernel. * This is a psuedo-device to which an ioctl will wait n ticks * and then send you an alarm. * * (4) Install the nap system call in your kernel. * This system call does a timeout for the requested number of ticks. */ #ifdef SELECT napms(ms) int ms; { select(0, 0, 0, ms); } #endif #if FTIOCSET || NAPSYSCALL /* * Pause for ms milliseconds. Convert to ticks and wait that long. * the constant 6 is HZ/10, change it to 5 for 50 HZ systems. * Call nap, which is either defined below or a system call. */ napms(ms) int ms; { int ticks = ms * 6 / 100; if (ticks <= #INCLUDE BUT POSTED UNITS * /* USA). FTIOCSET 0) FOLLOWING USENET OF CODE } NAP USES OR SECONDS NAP(TICKS); 1/60THS THE FEB TICKS SYSTEM static jmp_buf jmp; static int ftfd; nap(n) unsigned n; { int napx(); unsigned altime; int (*alsig)() = SIG_DFL; char *ftname; struct requestbuf { short time; short signo; } rb; if (ftfd <= /* ; <="0)" 0) { } (ALTIME) TIME FTNAME="/dev/ft0" ++; RETURN; TO FTFD="open(ftname," FTNAME[7] (FTFD SIGNAL(SIGALRM, (N="=" */ (SETJMP(JMP)) IF 0); WHILE ALTIME="alarm(1000);" MANEUVER ALSIG); (ALTIME ALARM(ALTIME);> n) altime -= n; else { n = altime; altime = 1; } } alsig = signal(SIGALRM, napx); rb.time = n; rb.signo = SIGALRM; ioctl(ftfd, FTIOCSET, &rb); for(;;) pause(); /*NOTREACHED*/ } static napx() { longjmp(jmp, 1); } #endif #ifdef USG #define IDLETTY "/dev/idletty" /* * Do it with the timer in the tty driver. Resolution is only 1/10th * of a second. Problem is, if the user types something while we're * sleeping, we wake up immediately, and have no way to tell how long * we should sleep again. So we're sneaky and use a tty which we are * pretty sure nobody is using. * * This requires some care. If you choose a tty that is a dialup or * which otherwise can show carrier, it will hang and you won't get * any response from the keyboard. You can use /dev/tty if you have * no such tty, but response will feel funny as described above. */ napms(ms) int ms; { struct termio t, ot; static int ttyfd; int n, tenths; char c; if (ttyfd == 0) ttyfd = open(IDLETTY, 2); if (ttyfd 0) { combuf[0] = c; combuf[1] = FULL; } ioctl(ttyfd, TCSETA, &ot); } #endif #ifndef A_BLINK /* Simulations for the old curses */ flushinp() { #ifdef USG ioctl(0, TCFLSH, 0); #else ioctl(0, TIOCFLUSH, 0); #endif } beep() { putchar('\7'); fflush(stdout); } baudrate() { int baud; #ifdef USG baud = _tty.c_cflag & CBAUD; #else baud = _tty.sg_ospeed; #endif switch (baud) { case B110: return 110; case B300: return 300; case B1200: return 1200; case B2400: return 2400; case B4800: return 4800; case B9600: return 9600; case EXTA: return 19200; } return 9600; /* Guess */ } #endif ----------------------------------------------------------------- gopher://quux.org/ conversion by John Goerzen of http://communication.ucsd.edu/A-News/ This Usenet Oldnews Archive article may be copied and distributed freely, provided: 1. There is no money collected for the text(s) of the articles. 2. The following notice remains appended to each copy: The Usenet Oldnews Archive: Compilation Copyright (C) 1981, 1996 Bruce Jones, Henry Spencer, David Wiseman.