Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Posting-Version: version B 2.10.2 9/18/84; site ucdavis.UUCP Path: utzoo!watmath!clyde!burl!ulysses!ucbvax!ucdavis!deneb!ccohesh001 From: ccohesh001@ucdavis.UUCP (Peter Costantinidis, Jr.) Newsgroups: net.sources.games Subject: Pm - UNIX version of PacMan (Src part 2 of 2) Message-ID: <479@ucdavis.UUCP> Date: Fri, 13-Dec-85 18:20:28 EST Article-I.D.: ucdavis.479 Posted: Fri Dec 13 18:20:28 1985 Date-Received: Sun, 15-Dec-85 00:01:10 EST Distribution: net Organization: University of California, Davis Lines: 2047 #!/bin/sh : "This is a shell archive, meaning: " : "1. Remove everything above the #! /bin/sh line. " : "2. Save the resulting test in a file. " : "3. Execute the file with /bin/sh (not csh) to create the files:" : " config.c" : " flsbuf.c" : " init.c" : " make_moves.c" : " misc.c" : " monsters.c" : " msg.c" : "This archive created: Fri Dec 13 13:05:41 PST 1985 " echo file: config.c sed 's/^X//' >config.c << 'END-of-config.c' X/* X** config.c - installation dependent parameters X** X** PM_ROLL: full pathname of score file X** X** PM_USER: full pathname of user log file. used to keep X** track of who has played X** X** WIZARD_UID: if argv[0] == "tester" and getuid() = WIZARD_UID X** then game runs in diagnostic mode where special X** commands take effect X** X** [pm by Peter Costantinidis, Jr. @ University of California at Davis] X*/ Xchar *pm_roll = PM_ROLL, /* score file */ X#ifdef PM_USER X *pm_user = PM_USER; /* user file */ X#else X *pm_user = NULL; /* no user file */ X#endif X#ifdef NOFULLPATH Xint wizard_uid = WIZARD_UID; X#endif END-of-config.c echo file: flsbuf.c sed 's/^X//' >flsbuf.c << 'END-of-flsbuf.c' X/*LINTLIBRARY*/ X#include X X/* X** It is necessary to count the number of characters that are printed. X** It was decided that the easiest way to do this would be to increment X** a counter variable in _flsbuf(). X** X** [pm by Peter Costantinidis, Jr. @ University of California at Davis] X*/ Xextern char *malloc(); Xextern long chcnt; /* counter */ X Xint X_flsbuf(c, iop) X unsigned c; X register FILE *iop; X{ X register char *base; X register n = 1, rn; X extern char _sobuf[]; X X if (iop->_flag & _IORW) { X iop->_flag |= _IOWRT; X iop->_flag &= ~_IOEOF; X } X Xtryagain: X if (iop->_flag & _IONBF) { X iop->_cnt = 0; X if (1 != write(fileno(iop), (char *) &c, 1)) X { X iop->_flag |= _IOERR; X return(EOF); X } X chcnt++; /* counter incremented */ X return(c); X } X if ((base = iop->_base) == NULL) { X if (iop == stdout) { X if (isatty(fileno(stdout))) { X iop->_flag |= _IONBF; X goto tryagain; X } X iop->_base = _sobuf; X iop->_ptr = _sobuf; X goto tryagain; X } X if ((iop->_base = base = malloc(BUFSIZ)) == NULL) { X iop->_flag |= _IONBF; X goto tryagain; X } X iop->_flag |= _IOMYBUF; X rn = n = 0; X } else if((rn = n = iop->_ptr - base) > 0) { X iop->_ptr = base; X n = write(fileno(iop), base, n); X chcnt += (long) n; /* counter incremented */ X } X iop->_cnt = BUFSIZ - 1; X *base++ = c; X iop->_ptr = base; X if (rn != n) { X iop->_flag |= _IOERR; X return(EOF); X } X return(c); X} X X#ifndef LINT Xint Xfflush(iop) X register FILE *iop; X{ X register char *base; X register n; X X if ((iop->_flag & (_IONBF|_IOWRT)) == _IOWRT X && (base = iop->_base) != NULL && (n = iop->_ptr - base) > 0) { X iop->_ptr = base; X iop->_cnt = BUFSIZ; X if (write(fileno(iop), base, n) != n) { X iop->_flag |= _IOERR; X return(EOF); X } X } X return(0); X} X X/* X * Flush buffers on exit X */ X X#ifndef BSD43 X_cleanup() X{ X register FILE *iop; X extern FILE *_lastbuf; X X for(iop = _iob; iop < _lastbuf; iop++) X fclose(iop); X} X#endif X Xint Xfclose(iop) X register FILE *iop; X{ X register r; X X r = EOF; X if (iop->_flag & (_IOREAD|_IOWRT|_IORW) X && (iop->_flag & _IOSTRG) == 0) { X r = fflush(iop); X if (close(fileno(iop)) < 0) X r = EOF; X if (iop->_flag & _IOMYBUF) X free(iop->_base); X if (iop->_flag & (_IOMYBUF|_IONBF)) X iop->_base = NULL; X } X iop->_flag &= X ~(_IOREAD|_IOWRT|_IONBF|_IOMYBUF|_IOERR|_IOEOF|_IOSTRG|_IORW); X iop->_cnt = 0; X return(r); X} X#endif END-of-flsbuf.c echo file: init.c sed 's/^X//' >init.c << 'END-of-init.c' X/* X** init.c - game initializations X** X** [pm by Peter Costantinidis, Jr. @ University of California at Davis] X*/ X#include "pm.h" X Xcoord pm_pos; Xstruct timeb _tp; /* used for timing */ Xlong thescore = 0L, /* player's score */ X hi_score = 0L, /* high score so far */ X move_cntr = 0L, /* # of moves made by player */ X chcnt = 0L, /* character count */ X demon = 0L; /* # of loops game made (psuedo time) */ Xchar fr_ch, /* fruit character */ X ch = ' ', /* current move of pm */ X oldch = '\0', /* old (temporary) move */ X newch = '\0', /* new move (future) */ X baud = '\0', /* output baud rate of terminal */ X *argv0, /* argv[0] */ X *mesg; /* pointer to last message */ Xint timeit = FALSE, /* printing loop/move counter? */ X quiet = TRUE, /* bells and whistles */ X fast = FALSE, /* skip senseless looping */ X timer = 0, /* duration timer for energizers */ X level = 0, /* level (board) number */ X seed, /* rnd num seed */ X fr_val, /* fruit value */ X d_left = MAX_DOTS, /* number of dots left on board */ X e_left = MAX_ENERGY, /* number of energizers left on board */ X mons_eaten = -1, /* number of monsters eaten (<= 4) */ X pm_eaten = FALSE, /* got eaten */ X pms_left = 3, /* pm's left (you start with three) */ X pm_bonus = TRUE, /* can get a bonus pm */ X pm_run = TRUE, /* TRUE if eatable */ X pm_tunn = FALSE, /* " if in tunnel */ X pm_extunn, /* how long left in tunnel */ X is_wiz = FALSE, /* TRUE if currently wizard */ X was_wiz = FALSE, /* TRUE if ever was wizard */ X uid; /* user's uid */ Xmons ghosts[MAX_MONS], /* array of monsters */ X *h, *g, *c, *z; /* pointers into array of monsters */ Xchar fruit[] = "%&00++$$~~^^_", X fruit_eaten[15] = " ", X moves[] = "hjkl"; Xint fruit_val[] = /* the values of each succeeding fruit */ X{ X 100, 300, 500, 500, 700, 700, 1000, 1000, 2000, 2000, 3000, 3000, 5000 X}; Xint mons_val[] = /* the values of the monsters when eaten */ X{ X 200, 400, 800, 1600 X}; Xint eat_times[] = /* the duration of the power pill */ X{ X 130, 130, 120, 115, 110, 100, 95, 85, 75, 70, 65, 55, 45 X}; Xint bauds[] = X{ X/* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15*/ X/* 0 50 75 110 134 150 200 300 600 1200 1800 2400 4800 9600 EXTA EXTB*/ X 0, 0, 0, 0, 0, 0, 0, 0, 0, 1200, 1800, 2400, 4800, 9600, 19200, 0 X}; X X/* X** init() - perform necessary intializations X*/ Xvoid init () X{ X if ((uid = getuid()) < 0) X { X fprintf(stderr, "Who the hell are you???\n"); X exit(1); X } X randomize(SEED); X#ifdef PM_USER X if (chk_pm_user()) /* check user log file */ X fprintf(stderr, "%s: Can not make entry into user log file\n", X argv0); X#endif X hi_score = get_hi_scr(); X if (initscr() == ERR) X { X fprintf(stderr, "initscr() error\n"); X perror(argv0); X exit(1); X } X if (!baud) /* if baud, then we are trying to simulate another */ X { X if (!bauds[_tty.sg_ospeed]) X { X fprintf(stderr, "pm: baud rate must be at least %d(%d)\n", MIN_BAUD, _tty.sg_ospeed); X endwin(); X exit(1); X } X baud = _tty.sg_ospeed; X } X trap(0); X h = &ghosts[0]; X g = &ghosts[1]; X c = &ghosts[2]; X z = &ghosts[3]; X mons_init(); X crmode(); X noecho(); X mesg = NULL; X draw_screen(); X} X X/* X** mons_init() - initialize the monsters X** - MUST be called before monsters()!!! X** Note: I am sure that there was a reason why I did not statically X** initialize these structures. When I remember the reason X** I will mention it here at a later date. X*/ Xvoid mons_init () X{ X reg int i; X X h->mo_attrib = SMART | SLOW; X g->mo_attrib = SMART | FAST; X c->mo_attrib = NORMAL | FAST; X z->mo_attrib = DUMB | MED; X h->mo_name = HARPO; X g->mo_name = GROUCHO; X c->mo_name = CHICO; X z->mo_name = ZEPPO; X for (i = 0; i < 4; i++) X m_init(&ghosts[i]); X g->mo_inside = FALSE; X} X X/* X** m_init() - initialize a single monster X** - this function is called from p_monsters() (every time a X** new screen is entered) X*/ Xm_init (m) Xreg mons *m; X{ X m->mo_inch = EMPTY; X m->mo_run = FALSE; X m->mo_tunn = FALSE; X m->mo_eaten = FALSE; X m->mo_inside = TRUE; X m->mo_ch = ' '; X m->mo_cnt = 0; X m->mo_extunn = 0; X} END-of-init.c echo file: make_moves.c sed 's/^X//' >make_moves.c << 'END-of-make_moves.c' X/* X** make_moves - code relating to player movement X** X** [pm by Peter Costantinidis, Jr. @ University of California at Davis] X*/ X#include "pm.h" X X/* X** make_moves - `ch' is the global variable designating the move of the X** player. perhaps it would have been better to pass this X** character to this function instead of using a global. X*/ Xint make_moves () X{ X reg char what; X reg int quit = FALSE; X auto coord tmp_pos; X X if (pm_tunn) X { /* in tunnel */ X if (pm_extunn--) X { /* still in tunnel, move over a square */ X switch (ch) X { X when MLEFT: X if (--pm_pos.x < LEFT) X pm_pos.x = RIGHT; X when MRIGHT: X if (++pm_pos.x > RIGHT) X pm_pos.x = LEFT; X otherwise: X msg("case error in tunnel"); X } X /* X ** check for monsters here!!!! X ** to see if they have run into any in the tunnel X */ XAbove: /* sorry about this! */ X switch (what = tunn_look(&pm_pos)) X { X case EMPTY: X return(msg("In and out of tunn"),quit); X case TUNNEL: X return(quit); X case PM: /* nothing here but me! */ X return(quit); X } X if (!is_mons(what)) X return(msg("found: %s in tunn", punctrl(what)),quit); X if (islower(what)) /* we have caught a monster */ X return(pm_eat_m(what), quit); X if (isupper(what)) X { X pm_eaten = TRUE; X m_eat_pm(wh_mons(what)); X return(quit); X } X msg("What was that???"); X } X else X { X pm_tunn = FALSE; X tmp_pos.x = pm_pos.x; X tmp_pos.y = pm_pos.y; X newch = ch; X goto here; X } X } X else X mvaddch(pm_pos.y, pm_pos.x, ' '); X if (pending()) X { X if (isupper(newch = getchar())) X newch = tolower(newch); X else if (isdigit(newch)) X newch = toletter(newch); X move_cntr++; X } X if (newch) X { X oldch = ch; X ch = newch; X } X if (!ch) X return(quit); Xtop: X tmp_pos.x = pm_pos.x; X tmp_pos.y = pm_pos.y; X switch (moveit(ch, &tmp_pos)) X { X when FINE: X when ERROR: X ch = oldch; X oldch = '\0'; X newch = '\0'; X goto top; X when QUIT: X quit = TRUE; X } Xhere: X if (is_safe(&tmp_pos)) X pm_pos.x = tmp_pos.x, pm_pos.y = tmp_pos.y; X else if (pm_eaten) X return(0); X else if (pm_tunn) X goto Above; X else X { X#ifdef USELESS X/* X** maybe the next `if' statement should have been an `else if', X** but until that has been ascertained, this one is useless X*/ X if ((newch == ch) && oldch) X { X ch = oldch; X oldch = '\0'; X goto top; X } X#endif X if (oldch) X { X ch = oldch; X oldch = '\0'; X goto top; X } X } X /* X ** redraw pm and leave cursor there if not in tunnel X */ X if (!pm_tunn) X { X move(pm_pos.y, pm_pos.x); X addch(PM); X move(pm_pos.y, pm_pos.x); X } X draw(); X return(quit); X} X X/* X** pending() - return TRUE if the user wants service, else return FALSE X** - i realize that this function could be simpler (ex. just X** return((int) l)), but i wanted to minimize lint's complaints X*/ Xint pending () X{ X#ifdef FIONREAD X auto long l; X X if (ioctl(0, FIONREAD, &l) == -1) X return(FALSE); X return(l > 0 ? TRUE : FALSE); X#else X return(1); X#endif X} X X/* X** is_safe() - returns TRUE if location is safe X** - also assumes that move will be made regardless X** of safeness X*/ Xint is_safe (where) Xreg coord *where; X{ X reg char what; X X move(where->y, where->x); X what = INCH(); X move(pm_pos.y, pm_pos.x); X switch (what) X { X case BLOCK: X case DOOR: X return(FALSE); X case TUNNEL: X pm_tunn = TRUE; X pm_extunn = TUNN_TIME; X return(TRUE); X case DOT: X thescore += V_DOT; X d_left--; X if (!quiet) X beep(); X return(TRUE); X case ENERGY: X thescore += V_ENERGY; X e_left--; X if (!quiet) X beep(); X submissive(); X return(TRUE); X case EMPTY: X return(TRUE); X case PM: X msg("I'm going skitzo"); X return(FALSE); X } X if (IS_FRUIT(what)) /* check to see if it is a fruit */ X { X thescore += fr_val; X if (!quiet) X beep(); X fr_val = 0; /* shows fruit has been eaten */ X add_fruit(fr_ch); X return(TRUE); X } X#ifdef DEBUG X if (!is_mons(what)) X return(msg("found a %s in @ 226", punctrl(what)), FALSE); X#endif X if (islower(what)) /* we have caught a monster */ X { X#ifdef DEBUG X if (pm_run) /* remove message later on### */ X msg("Eatable, but not running"); X /* X ** may need this X pm_pos.x = where->x; X pm_pos.y = where->y; X */ X#endif X return(pm_eat_m(what), TRUE); X } X pm_eaten = TRUE; X pm_pos.x = where->x; X pm_pos.y = where->y; X m_eat_pm(wh_mons(what)); X return(FALSE); X} X X/* X** pm_eat_m() - the pm ate the m!!! X** - the variable flag is used to indicate that the X** monsters (including the one eaten) must become X** submissive (after the eaten one has been initialized) X*/ Xvoid pm_eat_m (who) Xreg char who; X{ X reg mons *m; X reg int flag = FALSE; X X thescore += mons_val[++mons_eaten]; X if (mons_eaten == 3) X { /* all the monsters are eaten, reset the timer */ X timer = 0; X mons_eaten = -1; X } X if (!(m = wh_mons(who))) X { X msg("Lost monster in pm_eat_m()"); X return; X } X switch (m->mo_inch) /* check what was underneath him*/ X { X when DOT: X thescore += V_DOT; X d_left--; X if (!quiet) X beep(); X when ENERGY: X flag = TRUE; X thescore += V_ENERGY; X e_left--; X if (!quiet) X beep(); X } X m->mo_name = toupper(who); X m_init(m); X place_m(m); X m->mo_eaten = TRUE; X if (flag) X submissive(); X} X X/* X** moveit() - evaluate move and return status X*/ Xmoveit (what, where) Xreg char what; Xreg coord *where; X{ X switch (what) X { X case MUP: X return(where->y--, FINE); X case MDOWN: X return(where->y++, FINE); X case MLEFT: X return(where->x--, FINE); X case MRIGHT: X return(where->x++, FINE); X case MSTOP: X return(STOP); X case MQUIT: X return(QUIT); X case MREDRAW: X return(redraw(), ERROR); X case MSHELL: X return(shell(), ERROR); X case MHELP: X return(commands(), ERROR); X case MFAST: X return(fast = !fast, ERROR); X case MQUIET: X return(quiet = !quiet, ERROR); X case MPAUSE: X /* X ** they are not allowed to pause to examine X ** the board (for potential moves), so clear X ** the screen (and go to the bottom) while X ** they are paused X */ X if (is_wiz) /* wizard is an exception! */ X return(trash(getchar()), ERROR); X _puts(CL); X move(LINES - 1, 0); X draw(); X printf("[Hit return when ready] "); X trash(getchar()); X redraw(); X return(ERROR); X case MHUH: X return(re_msg(), ERROR); X case MWIZARD: X if (is_wiz) X { X msg(""); X is_wiz = FALSE; X return(ERROR); X } X msg("Wizard's Password: "); X if (!strcmp(W_PASSWD, crypt(get_pass(), SALT))) X { X was_wiz = TRUE; X is_wiz = TRUE; X if (getuid() != WIZARD_UID) X msg("Are you trying to cheat?"); X else X msg("Hi wiz!"); X } X else X msg("Who are you kidding?"); X return(ERROR); X default: X if (!is_wiz) X return(ERROR); X } X /* X ** since they are wizard, lets try some of these X */ X switch (what) X { X when MPM: X pms_left++, p_pms(); X when MSLOW: X slowness(); X when MSTATUS: X status(); X when MMONS: X p_info(getchar()); X when MUP_LVL: X chg_lvl(1); X when MDN_LVL: X chg_lvl(-1); X when MEAT: X submissive(); X when MMEAN: X aggressive(); X } X return(ERROR); X} X X/* X** commands() - print a list of the users commands X** - erase the screen by hand X*/ Xvoid commands () X{ X static char *cmds[] = X { "---------------------------------------------------", X "| Movement: | Misc: |", X "---------------------------------------------------", X "| | |", X "| k | ! shell |", X "| ^ | q quit |", X "| ^ | stop |", X "| ^ | f faster |", X "| ^ | b quiet |", X "| h < < < < * > > > > l | p pause |", X "| v | |", X "| v | |", X "| v | |", X "| v | |", X "| j | |", X "| | |", X "---------------------------------------------------", X "\nHit return to continue", X 0 X }; X reg char **s = cmds; X X _puts(CL); X while (*s) X printf("%s\n", *s++); X trash(getchar()); X chcnt = 0l; X redraw(); X} X X/* X** status() - print out a bunch of debugging info X*/ Xvoid status () X{ X alarm(0); X _puts(CL); X move(0, 0); X printf(" Diagnostics\n\n"); X printf("Fruit: %c\n", fr_ch); X printf("Fruit value: %d\n", fr_val); X printf("Level: %d\n", level); X printf("Moves: %ld\n", move_cntr); X printf("Time: %ld\n", demon); X printf("Timeit: %s\n", (timeit ? "Yes" : "No")); X printf("Fast: %s\n", (fast ? "Yes" : "No")); X printf("Beeping: %s\n", (quiet ? "No" : "Yes")); X printf("Dots left: %d\n", d_left); X printf("Energizers left: %d\n", e_left); X printf("Pm's left: %d\n", pms_left); X printf("Time left: %d\n", timer); X printf("Score: %ld\n", thescore); X printf("Pos.: (%d, %d)\n", pm_pos.x, pm_pos.y); X printf("Tunn.: %s\n",TF(pm_tunn)); X printf("Baud: %d\n", bauds[baud]); X printf("Screen dimension %d x %d\n", LINES, COLS); X printf("High score: %ld\n", hi_score); X printf("Max's: %d,%d\n", stdscr->_maxy, stdscr->_maxx); X printf("\n"); X printf("\nHit return to continue\n"); X trash(getchar()); X chcnt = 0L; X redraw(); X} END-of-make_moves.c echo file: misc.c sed 's/^X//' >misc.c << 'END-of-misc.c' X/* X** misc.c - miscellaneous functions X** X** [pm by Peter Costantinidis, Jr. @ University of California at Davis] X*/ X#include X#include "pm.h" X X X/* X** chg_lvl() - change the level by the desired ammount X*/ Xvoid chg_lvl (delta) Xreg int delta; X{ X level += delta; X if (level < 0) X level = 0; X ch = ' '; X oldch = ' '; X newch = ' '; X pm_run = TRUE; X sleep(1); X new_screen(); X} X X/* X** scrcpy() - copy score structures X** - there are more efficient ways todo this, but lint doesn't X** like any of the ones i came up with X*/ Xvoid scrcpy (to, from) Xreg score *to, *from; X{ X to->sc_uid = from->sc_uid; X to->sc_score = from->sc_score; X to->sc_level = from->sc_level; X to->sc_flags = from->sc_flags; X to->sc_mons = from->sc_mons; X strncpy(to->sc_name, from->sc_name, sizeof(from->sc_name)); X return; X} X X/* X** dir_int() - changes a char direction indicator to a int X*/ Xint dir_int (dir) Xreg char dir; X{ X switch (dir) X { X case MUP: X return(0); X case MDOWN: X return(1); X case MLEFT: X return(2); X case MRIGHT: X return(3); X default: X return(-1); X } X /*NOTREACHED*/ X} X Xstatic char *dirs[] = X{ X "\n\n\t\tWelcome to the game of pm\n", X "Just a few words of information and caution to", X "beginning pm players. This game is very expensive!!!", X "It is so expensive that your usercode may not last", X "more than a few medium length games. The arcade", X "equivalent of this costs a quarter per game, no", X "matter how long it lasts. With pm it is the other way", X "around, the longer you play the more expensive it gets!", X "If you are unfamilar with the commands for movement, I", X "suggest that you try getting the hang of them by playing", X "other games (such as rogue, snake, or tank) that use", X "similar commands. It could get very expensive getting", X "the hang of moving around by learning on pm.", X "The higher your baud rate, the better the game performs.", X "9600 is a pretty good speed to run at.", X "For a summary of valid commands, type in a '?'.", X "\nHappy packing!!!", X "\n[Hit return to continue] ", X 0 X}; X X/* X** directions() - print out any opening messages to beginners X*/ Xvoid directions () X{ X reg char **s = dirs; X X while (*s) X printf("%s\n", *s++); X trash(getchar()); X} X X/* X** get_pass() - read in the password X** - only read in 8 characters! X*/ Xchar *get_pass () X{ X static char buf[9]; X reg int i; X X nocrmode(); X for (i = 0; i < 9; i++) X buf[i] = '\0'; X for (i = 0; i < 8; i++) X { X reg char in; X X if ((in = getchar()) == '\n') X break; X buf[i] = in; X } X crmode(); X return(buf); X} X X/* X** int_dir() - changes an int to a char direction indicator X** - the % insures that it is in range X*/ Xchar int_dir (dir) Xreg int dir; X{ X static char _dirs[] = X { X MUP, MDOWN, MLEFT, MRIGHT, 0 X }; X X return(_dirs[dir % MAX_DIRS]); X} X X/* X** lturn() - return the direction to the left, relative to X** the given direction X*/ Xchar lturn (dir) Xreg char dir; X{ X switch (dir) X { X case MUP: X return(MLEFT); X case MDOWN: X return(MRIGHT); X case MLEFT: X return(MDOWN); X case MRIGHT: X return(MUP); X default: X return(MSTOP); X } X /*NOTREACHED*/ X} X X/* X** mons_str() - return the (full) name of the given monster X*/ Xchar *mons_str (mon) Xreg char mon; X{ X switch (mon) X { case HARPO: X return("Harpo"); X case GROUCHO: X return("Groucho"); X case CHICO: X return("Chico"); X case ZEPPO: X return("Zeppo"); X default: X return("Anonymous"); X } X /*NOTREACHED*/ X} X X/* X** opposite() - return the direction opposite to that specified X*/ Xchar opposite (dir) Xreg char dir; X{ X switch (dir) X { X case MUP: X return(MDOWN); X case MDOWN: X return(MUP); X case MLEFT: X return(MRIGHT); X case MRIGHT: X return(MLEFT); X default: X return(MSTOP); X } X} X X/* X** rturn() - return the direction to the right, relative to X** the given direction X*/ Xchar rturn (dir) Xreg char dir; X{ X switch (dir) X { X case MUP: X return(MRIGHT); X case MDOWN: X return(MLEFT); X case MLEFT: X return(MUP); X case MRIGHT: X return(MDOWN); X default: X return(MSTOP); X } X} X X/* X** quit_it() - stop the game X*/ Xvoid quit_it () X{ X echo(); X nocrmode(); X endwin(); X exit(0); X} X X/* X** shell() - set thier uid to thier realuid and give them a shell X*/ Xvoid shell () X{ X reg char *sh; X reg int pid; X extern char *getenv(); X X echo(); X nocrmode(); X _puts(CL); /* clear screen */ X move(LINES - 1, 0); /* and go to the bottom */ X draw(); X if ((sh = getenv("SHELL")) == NULL) /* check for a preferred shell */ X sh = DEFAULT_SH; X if ((pid = fork()) == -1) X { X fprintf(stderr, "fork failed, by by!\n"); X quit_it(); X } X if (!pid) /* if child */ X { X if (setuid(uid) == -1) /* incase we are running setuid */ X exit((fprintf(stderr, "Can't setuid(%d)\n", uid), 1)); X if (setgid(getgid()) == -1) /* incase we are running setgid */ X exit((fprintf(stderr,"Can't setgid(%d)\n",getgid()),1)); X#ifndef LINT X signal(SIGINT, SIG_DFL); X signal(SIGQUIT, SIG_DFL); X#endif X execle(sh, "shell", "-i", 0, environ); X perror("pm"); X exit(1); X } X#ifndef LINT X signal(SIGINT, SIG_IGN); X signal(SIGQUIT, SIG_IGN); X#endif X wait(0); X trap(0); /* reset signals */ X noecho(); X crmode(); X printf("[Press return to continue]"); X trash(getchar()); X redraw(); X} X X/* X** toletter() - translate the numeric move (key pad) to a letter move X** - this is to facilitate the use of keypads if the X** terminal is so equipped X** - return NULL for invalid X*/ Xchar toletter (in) Xreg char in; X{ X static char mvs[] = X { X NULL, NULL, MDOWN, NULL, MLEFT, MSTOP, MRIGHT, NULL, MUP, NULL X }; X X return(mvs[(in - '0') % 9]); X} X X/* X** trap() - catches signals X** - flag is zero for the initial call, non-zero X** when an interrupt is recieved X*/ Xvoid trap (flag) Xreg int flag; X{ X if (!flag) X { X#ifndef LINT X signal(SIGINT, trap); X signal(SIGHUP, trap); X#endif X return; X } X#ifndef LINT X signal(SIGINT, SIG_IGN); X signal(SIGHUP, SIG_IGN); X#endif X clear(); X draw(); X quit_it(); X} X X/* X** tunn_look() - return what is at the given location in the tunnel X*/ Xchar tunn_look (pos) Xreg coord *pos; X{ X reg int i; X X for (i = 0; i < MAX_MONS; i++) X if (AT(pos, &ghosts[i].mo_pos)) X return(ghosts[i].mo_name); X if (AT(pos, &pm_pos)) X return(PM); X move(pos->y, pos->x); X return(INCH()); X} X X#ifdef BAD_OVERLAY X/* X** overlay() - a bug exist[s,ed] in the curses function overlay() on the X** 4.2 machine on which this program was updated. this file X** is included in case this bug is not just local to this X** system. X** X*/ X X/* X** In the outer `for' loop the "<" should have been a "<=". X*/ X# define min(a,b) (a < b ? a : b) X# define max(a,b) (a > b ? a : b) X X/* X * This routine writes win1 on win2 non-destructively. X * X * 11/5/82 (Berkeley) @(#)overlay.c 1.4 X */ Xoverlay(win1, win2) Xreg WINDOW *win1, *win2; { X X reg char *sp, *end; X reg int x, y, endy, endx, starty, startx; X X# ifdef DEBUG X fprintf(outf, "OVERLAY(%0.2o, %0.2o);\n", win1, win2); X# endif X starty = max(win1->_begy, win2->_begy) - win1->_begy; X startx = max(win1->_begx, win2->_begx) - win1->_begx; X endy = min(win1->_maxy, win2->_maxy) - win1->_begy - 1; X endx = min(win1->_maxx, win2->_maxx) - win1->_begx - 1; X/* X** this is what was erroneously here: X** X** for (y = starty; y < endy; y++) { X** X** below you will find the correct code (s/_y[y][endx]; X x = startx + win1->_begx; X for (sp = &win1->_y[y][startx]; sp <= end; sp++) { X if (!isspace(*sp)) X mvwaddch(win2, y + win1->_begy, x, *sp); X x++; X } X } X} X#endif END-of-misc.c echo file: monsters.c sed 's/^X//' >monsters.c << 'END-of-monsters.c' X/* X** monsters.c - X** This file contains the necessary functions X** to deal with the monsters and how they move. X** If the flag variable is TRUE, then they are after X** you, else you are after them. X** X** X** [pm by Peter Costantinidis, Jr. @ University of California at Davis] X*/ X#include "pm.h" X X/* X** harpo - will try his best to get you, but is slow X** - smart, slow X** X** groucho - is always behind you, it is hard to shake him X** - smart, fast X** X** chico - he's fast X** - fast X** X** zeppo - terribly shy and will actually run away from you X** - medium, dumb X*/ X X/* X** p_monsters() - place and initialize the monsters for new screens X*/ Xvoid p_monsters () X{ X reg int i; X X for (i = 0; i < MAX_MONS; i++) X m_init(&ghosts[i]); X h->mo_pos.x = 26; X h->mo_pos.y = 11; X g->mo_pos.x = 26; X g->mo_pos.y = 9; X c->mo_pos.x = 28; X c->mo_pos.y = 11; X z->mo_pos.x = 24; X z->mo_pos.y = 11; X h->mo_name = HARPO; X g->mo_name = GROUCHO; X c->mo_name = CHICO; X z->mo_name = ZEPPO; X g->mo_inside = FALSE; X for (i = 0; i < MAX_MONS; i++) X { X move(ghosts[i].mo_pos.y, ghosts[i].mo_pos.x); X addch(ghosts[i].mo_name); X } X} X X/* X** m_move() - move the monsters X** - if they are eatable, then skip them half the time X** - if they are inside, skip them a third of the time X*/ Xvoid m_move () X{ X reg int i; X X for (i = 0; i < MAX_MONS; i++) X { X if (ghosts[i].mo_run && (demon % 3l)) X continue; X mv_mon(&ghosts[i]); X if (pm_eaten) X return; X } X} X X/* X** mv_mon() - make the given monster move X** - maybe change the "mod 5"'s to randomness X** - intelligence is simulated by choosing the best X** possible move, and then occasionally doing some- X** thing random. occasionally is defined relative X** to the intelligence of the monster! X** - when a monster is in the tunnel, it continues X** moving in its original direction X** - returns FALSE if pm is eaten (everything must stop!) X*/ Xvoid mv_mon (m) Xreg mons *m; X{ X#ifdef FASTER X reg int once = FALSE; X#endif X X#ifdef FASTER Xtop: X#endif X if (!get_move(m)) X { X m->mo_ch = moves[rnd(0, 3)]; X m->mo_cnt = 0; X } X /* X ** take care of slow monsters X */ X if ((!(demon % SPEED)) && X (m->mo_attrib & SLOW) && X !m->mo_run && !m->mo_tunn) X return; X#ifdef FASTER X /* X ** take care of fast monsters X */ X if (!(demon % SPEED) && X (m->mo_attrib & FAST) && X !once && !m->mo_run && !m->mo_tunn) X once = TRUE; X else if (once) X once = FALSE; X#endif X /* X ** take care of dumb monsters X ** - 25% of time they move randomly, and if they are inside, X ** then 50% of the time they move wrong X */ X if ((m->mo_attrib & DUMB) && !m->mo_tunn) X { X if (rnd(1,100) < 25) X { X if ((m->mo_ch = gen_mv(m)) != MSTOP) X m->mo_cnt = DIST(); X else X m->mo_cnt = 0; X } X else if (m->mo_inside && (rnd(1, 100) < 45)) X { X m->mo_ch = opposite(m->mo_ch); X m->mo_cnt = 2; X } X } X /* X ** take care of medium monsters X */ X else if ((m->mo_attrib & NORMAL) && !m->mo_tunn) X { X if (rnd(1,100) < 10) X { X if ((m->mo_ch = gen_mv(m)) != MSTOP) X m->mo_cnt = DIST(); X else X m->mo_cnt = 0; X } X else if (m->mo_inside && (rnd(1, 100) < 37)) X { X m->mo_ch = opposite(m->mo_ch); X m->mo_cnt = 2; X } X else if ((rnd(1, 100) < 15) && (m->mo_ch != MSTOP)) X m->mo_cnt = rnd(2, 4); X } X else if (m->mo_attrib & SMART) X { X if (m->mo_inside && (rnd(1, 100) < 27)) X { X m->mo_ch = opposite(m->mo_ch); X m->mo_cnt = 2; X } X } X if (!_mv_mon(m)) X return; X#ifdef FASTER X if (once) X goto top; X#endif X} X X/* X** p_info() - prints information about the given monster X*/ Xvoid p_info (name) Xreg char name; X{ X reg mons *m; X X m = wh_mons(name); X if (m == NULL) X msg("No such monster: %s", punctrl(name)); X _puts(CL); X fprintf(stderr, "Name: %c\n", m->mo_name); X fprintf(stderr, "Place: (%d,%d)\n", m->mo_pos.x, m->mo_pos.y); X fprintf(stderr, "Inch: %c\n", m->mo_inch); X fprintf(stderr, "Run: %s\n", TF(m->mo_run)); X fprintf(stderr, "Tunn: %s\n", TF(m->mo_tunn)); X fprintf(stderr, "Eaten: %s\n", TF(m->mo_eaten)); X fprintf(stderr, "Inside: %s\n", TF(m->mo_inside)); X fprintf(stderr, "Move: %c\n", m->mo_ch); X fprintf(stderr, "Count: %d\n", m->mo_cnt); X fprintf(stderr, "Attrib: %o\n\n", m->mo_attrib); X trash(getchar()); X redraw(); X} X X/* X** _mv_mon() - lower level routine to move a monster X** - checks for barriers and stuff... X** - returns FALSE if pm is eaten (everything must stop!) X** - if in tunnel, it will only move half as fast X*/ X_mv_mon (m) Xreg mons *m; X{ X reg char what; X auto coord pos; XAbove: X if (m->mo_tunn) X { X if (!(demon % 4)) X { X pos.x = m->mo_pos.x; X pos.y = m->mo_pos.y; X switch (m->mo_ch) X { X when MLEFT: X if (--pos.x < LEFT) X pos.x = RIGHT; X when MRIGHT: X if (++pos.x > RIGHT) X pos.x = LEFT; X otherwise: X msg("Bad move in tunn"); X } X } X else /* not moving this time around */ X return(TRUE); X switch (what = tunn_look(&pos)) X { X case PM: X m->mo_pos.x = pos.x; X m->mo_pos.y = pos.y; X if (OUTOFTUNN(&m->mo_pos)) X m->mo_tunn = FALSE; X if (m->mo_run) X { X pm_eat_m(m->mo_name); X return(FALSE); X } X m_eat_pm(m); X return(FALSE); X case EMPTY: X if (!OUTOFTUNN(&pos)) X msg("Lost out of tunn"); X m->mo_tunn = FALSE; X goto ok; X case TUNNEL: X m->mo_pos.x = pos.x; X m->mo_pos.y = pos.y; X m->mo_inch = what; X return(TRUE); X default: X /* X ** ran into another monster? X */ X m->mo_ch = opposite(m->mo_ch); X msg("Ran into another monster"); X return(TRUE); X } X } X else X { X if (move_to(m->mo_ch, &m->mo_pos, &pos) == -1) X return(-1); X move(pos.y, pos.x); X what = INCH(); X } X switch (what) X { X when PM: X mvaddch(m->mo_pos.y, m->mo_pos.x, m->mo_inch); X draw(); X m->mo_pos.x = pos.x; X m->mo_pos.y = pos.y; X if (m->mo_run) X return(pm_eat_m(m->mo_name), FALSE); X mvaddch(pos.y, pos.x, m->mo_name); X draw(); X m->mo_inch = EMPTY; X m_eat_pm(m); X return(FALSE); X when BLOCK: X m->mo_cnt = 0; X when DOT: X case ENERGY: X case EMPTY: Xok: X mvaddch(m->mo_pos.y, m->mo_pos.x, m->mo_inch); X#ifdef MAX_UPDATE X draw(); X#endif X mvaddch(pos.y, pos.x, m->mo_name); X m->mo_pos.x = pos.x; X m->mo_pos.y = pos.y; X m->mo_inch = what; X when DOOR: X if (!m->mo_inside) /* can only exit, not enter */ X { X m->mo_cnt = 0; X break; X } X mvaddch(m->mo_pos.y, m->mo_pos.x, m->mo_inch); X#ifdef MAX_UPDATE X draw(); X#endif X mvaddch(pos.y, pos.x, m->mo_name); X m->mo_pos.x = pos.x; X m->mo_pos.y = pos.y; X m->mo_inch = what; X m->mo_inside = FALSE; X when TUNNEL: X if (tunn_look(&pos) != TUNNEL) X break; X mvaddch(m->mo_pos.y, m->mo_pos.x, m->mo_inch); X m->mo_inch = TUNNEL; X m->mo_tunn = TRUE; X m->mo_pos.x = pos.x; X m->mo_pos.y = pos.y; X goto Above; X otherwise: X if (IS_FRUIT(what)) X goto ok; X if (!is_mons(what)) X { X msg("_mv_mon(): default"); X break; X } X m->mo_cnt = 0; X } X draw(); X return(TRUE); X} X X/* X** get_move() - find a smart move for the given monster X** - return FALSE if none was determined X*/ Xint get_move (m) Xreg mons *m; X{ X reg int i, dist = 0; X auto char tmp; X X if (m->mo_cnt > 0) X m->mo_cnt--; X /* X ** must always move up when on the door!!! X */ X if (m->mo_inch == DOOR) X { X m->mo_ch = MUP; X m->mo_cnt = 0; X return(TRUE); X } X if (m->mo_tunn) X { /* if in tunnel, keep moving */ X#ifdef DEBUG X if (!m->mo_ch) X msg("m's in tunn, & mo_ch is null"); X#endif X return(TRUE); X } X if (m->mo_inside) X { X /* X ** still inside thier little cave (box) X ** make them move to space under the door if they X ** are not there already X */ X if (m->mo_pos.x > DOOR_COL) X { X m->mo_ch = MLEFT; X m->mo_cnt = 1; X return(TRUE); X } X if (m->mo_pos.x < DOOR_COL) X { X m->mo_ch = MRIGHT; X m->mo_cnt = 1; X return(TRUE); X } X /* X ** they're under the door, try to move up! X */ X m->mo_ch = MUP; X m->mo_cnt = 1; X return(TRUE); X } X tmp = m->mo_ch; X for (i = 0; i < 4; i++) X { X m->mo_ch = int_dir(i); X if (dist = can_see(m, &pm_pos)) X break; X } X if (m->mo_run && dist) /* running away from him */ X { X m->mo_cnt = 0; X if (m_is_safe(m, opposite(m->mo_ch))) X return(m->mo_ch = opposite(m->mo_ch), TRUE); X m->mo_ch = tmp; X if ((m->mo_ch = gen_mv(m)) != MSTOP) X return(TRUE); X m->mo_ch = (rnd(0, 1) ? lturn(m->mo_ch) : rturn(m->mo_ch)); X return(FALSE); X } X if (dist) X return(m->mo_cnt = dist, TRUE); X m->mo_ch = tmp; X if (m->mo_cnt) /* check for predetermination */ X return(TRUE); X m->mo_cnt = 0; X if ((m->mo_ch = gen_mv(m)) != MSTOP) X return(TRUE); X m->mo_ch = tmp; X if (m_is_safe(m, m->mo_ch)) X return(TRUE); X return(FALSE); X} X X/* X** gen_mv() - generate a move when no hueristics are available X** - turn 80% of the time, 50% of that left, 50% right X** - 20% of the time just keep going X*/ Xchar gen_mv (m) Xreg mons *m; X{ X if (rnd(0, 99)<40) X { X if (m_is_safe(m, rturn(m->mo_ch))) X return(rturn(m->mo_ch)); X if (m_is_safe(m, lturn(m->mo_ch))) X return(lturn(m->mo_ch)); X return(MSTOP); X } X if (rnd(0, 59) < 40) X { X if (m_is_safe(m, lturn(m->mo_ch))) X return(lturn(m->mo_ch)); X if (m_is_safe(m, rturn(m->mo_ch))) X return(rturn(m->mo_ch)); X return(MSTOP); X } X if (m_is_safe(m, m->mo_ch)) X return(m->mo_ch); X if (rnd(0, 1)) X { X if (m_is_safe(m, rturn(m->mo_ch))) X return(rturn(m->mo_ch)); X if (m_is_safe(m, lturn(m->mo_ch))) X return(lturn(m->mo_ch)); X return(MSTOP); X } X if (m_is_safe(m, lturn(m->mo_ch))) X return(lturn(m->mo_ch)); X if (m_is_safe(m, rturn(m->mo_ch))) X return(rturn(m->mo_ch)); X return(MSTOP); X} X X/* X** m_is_safe() - return TRUE if monster can move in the indicated X** direction X*/ Xint m_is_safe (m, dir) Xreg mons *m; Xreg char dir; X{ X reg char what; X auto coord pos; X X if (move_to(dir, &m->mo_pos, &pos)) X return(FALSE); X move(pos.y, pos.x); X switch (what = INCH()) X { X case HARPO: X case _HARPO: X case GROUCHO: X case _GROUCHO: X case CHICO: X case _CHICO: X case ZEPPO: X case _ZEPPO: X case BLOCK: X case DOOR: X return(FALSE); X case DOT: X case ENERGY: X case EMPTY: X case TUNNEL: X return(TRUE); X case PM: X if (m->mo_run) X return(FALSE); X return(TRUE); X default: X if (IS_FRUIT(what)) X return(TRUE); X msg("m_is_safe default"); X return(FALSE); X } X} X X/* X** can_see() - returns distance the monster is from the pm if X** the pm can be seen X** - look in the direction the monster is facing X** - special case for when pm is in tunnel, then the X** monster must be facing the tunnel X*/ Xint can_see (m, pos) Xreg mons *m; Xreg coord *pos; X{ X auto int dist = 0; X auto coord mv; X X switch (m->mo_ch) X { X when MUP: X if (m->mo_pos.x != pos->x) /* not in line */ X return(FALSE); X if ((m->mo_pos.y == TUNN_ROW) && pm_tunn) X break; X if (m->mo_pos.y < pos->y) /* not facing */ X return(FALSE); X when MDOWN: X if (m->mo_pos.x != pos->x) /* not in line */ X return(FALSE); X if ((m->mo_pos.y == TUNN_ROW) && pm_tunn) X break; X if (m->mo_pos.y > pos->y) /* not facing */ X return(FALSE); X when MLEFT: X if (m->mo_pos.y != pos->y) /* not in line */ X return(FALSE); X if ((m->mo_pos.y == TUNN_ROW) && pm_tunn) X break; X if (m->mo_pos.x < pos->x) /* not facing */ X return(FALSE); X when MRIGHT: X if (m->mo_pos.y != pos->y) /* not in line */ X return(FALSE); X if ((m->mo_pos.y == TUNN_ROW) && pm_tunn) X break; X if (m->mo_pos.x > pos->x) /* not facing */ X return(FALSE); X otherwise: X msg("default in can_see: \%03o", m->mo_ch); X return(FALSE); X } X /* X ** at this point, they are in direct line and X ** facing in the right direction, we need to X ** see if anything is in the way X */ X mv.x = m->mo_pos.x; X mv.y = m->mo_pos.y; X do X { X reg char what; X X if (move_to(m->mo_ch, &mv, &mv) == -1) X return(msg("move_to=-1"), FALSE); X move(mv.y, mv.x); X switch (what = INCH()) X { X case PM: X case HARPO: X case _HARPO: X case GROUCHO: X case _GROUCHO: X case CHICO: X case _CHICO: X case ZEPPO: X case _ZEPPO: X case DOT: X case ENERGY: X case DOOR: X case EMPTY: X break; X case TUNNEL: X if (pm_tunn) X return(dist); X else X msg("can_see(): what???"); X case BLOCK: X return(0); X default: X if (IS_FRUIT(what)) /* its the fruit */ X break; X msg("can_see(): case (2)"); X return(0); X } X dist++; X } while ((mv.x != pos->x) || (mv.y != pos->y)); X return(dist); X} X X/* X** move_to() - X*/ Xint move_to (dir, pos1, pos2) Xreg int dir; /* declared int to pacify lint */ Xreg coord *pos1, *pos2; X{ X static int offset[2][4] = X { {0, 0, -1, 1}, X {-1, 1, 0, 0} X }; X X if ((dir = dir_int((char) dir)) == -1) X return(-1); X pos2->x = pos1->x + offset[0][dir]; X pos2->y = pos1->y + offset[1][dir]; X return(0); X} X X/* X** wh_mons() - return pointer to ch's monster struct X*/ Xmons *wh_mons (mch) Xreg char mch; X{ X switch (mch) X { X case HARPO: X case _HARPO: X return(h); X case GROUCHO: X case _GROUCHO: X return(g); X case CHICO: X case _CHICO: X return(c); X case ZEPPO: X case _ZEPPO: X return(z); X default: X msg("Unknown monster!!!"); X return((mons *) NULL); X } X} X X/* X** m_eat_pm() - a monster has eaten the pm X*/ Xvoid m_eat_pm (m) Xreg mons *m; X{ X eat_pm(); X sleep(1); X if (!--pms_left) /* if no more pm's then quit immediately */ X die(m->mo_name); X flush(); X old_screen(); X pm_eaten = FALSE; X ch = ' '; X oldch = '\0'; X newch = '\0'; X} X X/* X** eat_pm() - make the pm look eaten X*/ Xvoid eat_pm () X{ X reg int i; X X if (pm_tunn) X return; X for (i = 0; i < 5; i++) X { X mvaddch(pm_pos.y, pm_pos.x, 'O'); X draw(); X msleep(EAT_PAUSE); X mvaddch(pm_pos.y, pm_pos.x, '='); X draw(); X msleep(EAT_PAUSE); X mvaddch(pm_pos.y, pm_pos.x, 'O'); X draw(); X msleep(EAT_PAUSE); X mvaddch(pm_pos.y, pm_pos.x, '='); X draw(); X msleep(EAT_PAUSE); X } X mvaddch(pm_pos.y, pm_pos.x, EMPTY); X draw(); X sleep(2); X} X X/* X** is_mons() - return TRUE if ch is a monster X*/ Xint is_mons (whoru) Xreg char whoru; X{ X switch (whoru) X { X case HARPO: X case _HARPO: X case GROUCHO: X case _GROUCHO: X case CHICO: X case _CHICO: X case ZEPPO: X case _ZEPPO: X return(TRUE); X } X return(FALSE); X} X X/* X** place_m() - put a monster back in its box X** - an infinite loop can occur if the box is full! X** - the box should never be full!!! X*/ Xvoid place_m (m) Xreg mons *m; X{ X reg int xx; X X m->mo_pos.y = 11; X while (TRUE) X { X move(m->mo_pos.y, (xx = rnd(19, 33))); X if (INCH() == EMPTY) X break; X } X m->mo_pos.x = xx; X move(m->mo_pos.y, m->mo_pos.x); X addch(m->mo_name); X} END-of-monsters.c echo file: msg.c sed 's/^X//' >msg.c << 'END-of-msg.c' X/* X** msg.c - code dealing with the printing of messages X** X** [pm by Peter Costantinidis, Jr. @ University of California at Davis] X*/ X#include X#include "pm.h" X X/* X** strucpy() - copy string using punctrl for things X** - ctrl chars count double X*/ Xvoid strucpy (s1, s2, len) Xreg char *s1, *s2; Xreg int len; X{ X reg char *sp; X X while (len-- && *s2) X { X if ((*s2 < ' ') && !len--) /* if len = 0, then no room */ X return; X strcpy(s1, sp = punctrl(*s2++)); X s1 += strlen(sp); X } X *s1 = '\0'; X} X X/* X** msg: X** Display a message on the screen. X*/ Xstatic char msgbuf[BUFSIZ]; X X/*VARARGS1*/ Xvoid msg (fmt, args) Xchar *fmt; Xint args; X{ X alarm(0); X /* X ** if the string is "", just clear the line X */ X if (*fmt == '\0') X { X move(5, 55); X clrtoeol(); X return; X } X /* X ** otherwise print the message and flush it out X */ X doadd(fmt, &args); X move(5, 55); X addstr(msgbuf); X clrtoeol(); X refresh(); X /* X ** set off an alarm to erase it X */ X#ifndef LINT X signal(SIGALRM, msg_erase); X#endif X alarm(ALARM_TIME); X} X X/* X** msg_erase() - erase the msg line X*/ Xvoid msg_erase () X{ X alarm(0); X move(5, 55); X addstr(" "); X} X Xvoid doadd (fmt, args) Xchar **fmt; Xint ***args; X{ X static FILE junk; X X /* X ** Do the printf into buf X */ X junk._flag = _IOWRT + _IOSTRG; X junk._ptr = &msgbuf[0]; X junk._cnt = 32767; X _doprnt(fmt, args, &junk); X putc('\0', &junk); X} X X/* X** re_msg() - reprint the last message X*/ Xvoid re_msg () X{ X msg(msgbuf); X} X X/* X** punctrl() - print a readable version of a certain character X** X** Note: Due to the inconsistent availability of a function to perform X** this, my own version has been built in and used in place of X** any pre-existing function. I believe that this particular X** version suts down on data space considerably from the versions X** I have found on the Berkley systems. X*/ Xchar *punctrl (chr) Xchar chr; X{ X static char *str = "^ "; X X chr &= 0177; X if (chr >= ' ' && chr <= '~') X { X static char *str1 = " "; X X *str1 = chr; X return(str1); X } X if (chr == CTRL(?)) X return("^?"); X *(str+1) = chr + '@'; X return(str); X} END-of-msg.c exit -- -- Peter Costantinidis, Jr. -- ucdavis!deneb!ccohesh001@ucb-vax.arpa (ARPA) -- ...!{ucbvax,lll-crg,dual}!ucdavis!deneb!ccohesh001 (UUCP)