V10/games/pacman/util.c
#include <stdio.h>
#include <signal.h>
#ifdef BELL3.0
#include <fcntl.h>
#include <termio.h>
#else
#include <sgtty.h>
#endif
#include <pwd.h>
#include "pacdefs.h"
#ifndef BELL3.0
#define O_RDWR 2
#define O_CREAT 0
#define O_RDONLY 0
#define O_NDELAY 0
#endif
extern char
*BC,
*UP;
extern int
putch();
extern char
*tgoto(),
*mktemp();
extern int
delay,
errno,
goldcnt;
extern long
time();
extern struct pac
*pacptr;
extern struct pac
monst[];
#ifndef MSG
int comfile;
#else
struct mstruct
{
int frompid;
int mtype;
};
#endif
#ifndef NODELAY
#ifndef MSG
char *fnam;
#endif
#endif
/*
* initbrd is used to re-initialize the display
* array once a new game is started.
*/
char initbrd[BRDY][BRDX] =
{
"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
"O + + + * + + + + OOO + + + + * + + + O",
"O X OOO + OOOOO + OOO + OOOOO + OOO X O",
"O * + + * + * + * + + * + * + * + + * O",
"O + OOO + O + OOOOOOOOOOO + O + OOO + O",
"O + + + * O + + + OOO + + + O * + + + O",
"OOOOOOO + OOOOO + OOO + OOOOO + OOOOOOO",
" O + O + + * + + * + + O + O ",
" O + O + OOO - - OOO + O + O ",
"OOOOOOO + O + O O + O + OOOOOOO",
" * + * O O * + * ",
"OOOOOOO + O + O O + O + OOOOOOO",
" O + O + OOOOOOOOOOO + O + O ",
" O + O * + + + + + + * O + O ",
"OOOOOOO + O + OOOOOOOOOOO + O + OOOOOOO",
"O + + + * + * + + OOO + + * + * + + + O",
"O X OOO + OOOOO + OOO + OOOOO + OOO X O",
"O + + O * + * + * + + * + * + * O + + O",
"OOO + O + O + OOOOOOOOOOO + O + O + OOO",
"O + * + + O + + + OOO + + + O + + * + O",
"O + OOOOOOOOOOO + OOO + OOOOOOOOOOO + O",
"O + + + + + + + * + + * + + + + + + + O",
"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
};
/*
* 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] =
{
"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
"O + + + * + + + + OOO + + + + * + + + O",
"O X OOO + OOOOO + OOO + OOOOO + OOO X O",
"O * + + * + * + * + + * + * + * + + * O",
"O + OOO + O + OOOOOOOOOOO + O + OOO + O",
"O + + + * O + + + OOO + + + O * + + + O",
"OOOOOOO + OOOOO + OOO + OOOOO + OOOOOOO",
" O + O + + * + + * + + O + O ",
" O + O + OOO - - OOO + O + O ",
"OOOOOOO + O + O O + O + OOOOOOO",
" * + * O O * + * ",
"OOOOOOO + O + O O + O + OOOOOOO",
" O + O + OOOOOOOOOOO + O + O ",
" O + O * + + + + + + * O + O ",
"OOOOOOO + O + OOOOOOOOOOO + O + OOOOOOO",
"O + + + * + * + + OOO + + * + * + + + O",
"O X OOO + OOOOO + OOO + OOOOO + OOO X O",
"O + + O * + * + * + + * + * + * O + + O",
"OOO + O + O + OOOOOOOOOOO + O + O + OOO",
"O + * + + O + + + OOO + + + O + + * + O",
"O + OOOOOOOOOOO + OOO + OOOOOOOOOOO + O",
"O + + + + + + + * + + * + + + + + + + O",
"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
};
/*
* display reflects the screen on the player's
* terminal at any point in time.
*/
char display[BRDY][BRDX] =
{
"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
"O + + + + + + + + OOO + + + + + + + + O",
"O X OOO + OOOOO + OOO + OOOOO + OOO X O",
"O + + + + + + + + + + + + + + + + + + O",
"O + OOO + O + OOOOOOOOOOO + O + OOO + O",
"O + + + + O + + + OOO + + + O + + + + O",
"OOOOOOO + OOOOO + OOO + OOOOO + OOOOOOO",
" O + O + + + + + + + + O + O ",
" O + O + OOO - - OOO + O + O ",
"OOOOOOO + O + O O + O + OOOOOOO",
" + + + O O + + + ",
"OOOOOOO + O + O O + O + OOOOOOO",
" O + O + OOOOOOOOOOO + O + O ",
" O + O + + + + + + + + O + O ",
"OOOOOOO + O + OOOOOOOOOOO + O + OOOOOOO",
"O + + + + + + + + OOO + + + + + + + + O",
"O X OOO + OOOOO + OOO + OOOOO + OOO X O",
"O + + O + + + + + + + + + + + + O + + O",
"OOO + O + O + OOOOOOOOOOO + O + O + OOO",
"O + + + + O + + + OOO + + + O + + + + O",
"O + OOOOOOOOOOO + OOO + OOOOOOOOOOO + O",
"O + + + + + + + + + + + + + + + + + + O",
"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
};
/* terminal type from environment and /etc/termcap ala ex & vi */
char *vs_cl = "", /* clear screen sequence */
*vs_cm = "", /* cursor positioning sequence */
*vs_vb = "";
char combuf[BUFSIZ],
message[81], /* temporary message buffer */
inbuf[2];
int ppid,
cpid,
game,
killcnt = 0,
vs_rows,
vs_cols;
unsigned
pscore;
long timein;
#ifdef BELL3.0
struct termio
savetty,
newtty;
#else
struct sgttyb
savetty, newtty;
#endif
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,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
update()
{
char str[10];
(void) sprintf(str, "%6d", pscore);
SPLOT(0, 52, str);
(void) sprintf(str, "%6d", goldcnt);
SPLOT(21, 57, str);
}
reinit()
{
register int locx, locy;
register char tmp;
for (locy = 0; locy < BRDY; locy++)
{
for (locx = 0; locx < BRDX; locx++)
{
tmp = initbrd[locy][locx];
brd[locy][locx] = tmp;
if ((display[locy][locx] = tmp) == CHOICE)
{
display[locy][locx] = GOLD;
};
};
};
goldcnt = GOLDCNT;
delay -= (delay / 10); /* hot it up */
}
errgen(string)
char *string;
{
SPLOT(23,45,string);
}
dokill(mnum)
int mnum;
{
register struct pac *mptr;
PLOT(0, 0, BEEP);
if (pacptr->danger == TRUE)
{
if (++killcnt == MAXMONSTER)
{
if (display[TRYPOS][TRXPOS] == GOLD)
{
goldcnt--;
};
display[TRYPOS][TRXPOS] = TREASURE;
PLOT(TRYPOS, TRXPOS, TREASURE);
killcnt = 0;
};
SPLOT(5, 45, "MONSTERS KILLED: ");
(void) sprintf(message, "%1d", killcnt);
SPLOT(5, 62, message);
mptr = (&monst[mnum]);
mptr->ypos = MSTARTY;
mptr->xpos = MSTARTX + (2 * mnum);
mptr->stat = START;
PLOT(mptr->ypos, mptr->xpos, MONSTER);
pscore += KILLSCORE;
return(GOTONE);
};
return(TURKEY);
}
/*
/* clr -- issues an escape sequence to clear the display
*/
clr()
{
(void) fprintf(stdout, "%s", vs_cl);
fflush(stdout);
nap(2);
}
/*
* display initial instructions
*/
instruct()
{
clr();
POS(0, 0);
(void) fprintf(stdout, "Attention: you are in a dungeon, being chased by monsters!\r\n\n");
(void) fprintf(stdout, "There are gold coins scattered uniformly in the dungeon, marked by \"+\".\r\n");
(void) fprintf(stdout, "One magic potion is available at each spot marked \"X\". Each potion will\r\n");
(void) fprintf(stdout, "enable you to kill monsters by touch for a limited duration. It will also\r\n");
(void) fprintf(stdout, "scare them away. When you kill a monster it is regenerated, but this takes\r\n");
(void) fprintf(stdout, "time. You can also regenerate yourself %d times. Killing all the monsters\r\n", MAXPAC);
(void) fprintf(stdout, "results in further treasure appearing magically somewhere in the dungeon,\r\n");
(void) fprintf(stdout, "marked by \"$\". There is a magic tunnel connecting the center left and\r\n");
(void) fprintf(stdout, "center right parts of the dungeon. The monsters know about it!\r\n\n");
(void) fprintf(stdout, " Type: h to move left\r\n");
(void) fprintf(stdout, " l to move right\r\n");
(void) fprintf(stdout, " k or w to move up\r\n");
(void) fprintf(stdout, " j or x to move down\r\n");
(void) fprintf(stdout, " <space> to halt \r\n");
(void) fprintf(stdout, " q to quit\r\n\n");
(void) fprintf(stdout, " Type: 1 normal game\r\n");
(void) fprintf(stdout, " 2 blinking monsters\r\n");
(void) fprintf(stdout, " 3 intelligent monsters\r\n");
(void) fprintf(stdout, " 4 blinking intelligent monsters\r\n");
}
/*
* over -- game over processing
*/
over()
{
register int i;
register int line;
int scorefile = 0;
struct passwd *getpwuid(), *p;
fflush(stdout);
sleep(5); /* for slow readers */
poll(0); /* flush and discard input from player */
clr();
/* high score to date processing */
if (game != 0)
{
line = 7;
POS(line++, 20);
(void) fprintf(stdout, " ___________________________ ");
POS(line++, 20);
(void) fprintf(stdout, "| |");
POS(line++, 20);
(void) fprintf(stdout, "| G A M E O V E R |");
POS(line++, 20);
(void) fprintf(stdout, "| |");
POS(line++, 20);
(void) fprintf(stdout, "| Game type: %1d |",game);
if ((scorefile = open(MAXSCORE, O_RDWR | O_CREAT, 0666)) != -1)
{
read(scorefile, (char *)scoresave, sizeof(scoresave));
for (i = MSSAVE - 1; i >= 0; i--) {
if (scoresave[game - 1].entry[i].score < pscore)
{
if (i < MSSAVE - 1)
{
scoresave[game - 1].entry[i + 1].score =
scoresave[game - 1].entry[i].score;
scoresave[game - 1].entry[i + 1].uid =
scoresave[game - 1].entry[i].uid;
};
scoresave[game - 1].entry[i].score = pscore;
scoresave[game - 1].entry[i].uid = getuid();
};
};
lseek(scorefile, 0l, 0);
write(scorefile, (char *)scoresave, sizeof(scoresave));
close(scorefile);
POS(line++, 20);
(void) fprintf(stdout, "| High Scores to date: |");
for (i = 0; i < MSSAVE; i++)
{
setpwent();
p = getpwuid(scoresave[game - 1].entry[i].uid);
POS(line++, 20);
(void) fprintf(stdout, "| Player : %-8s %5u |", p->pw_name,
scoresave[game - 1].entry[i].score);
};
}
else
{
POS(line++, 20);
(void) fprintf(stdout, "| |");
POS(line++, 20);
(void) fprintf(stdout, "| Please create a 'paclog' |");
POS(line++, 20);
(void) fprintf(stdout, "| file. See 'MAXSCORE' in |");
POS(line++, 20);
(void) fprintf(stdout, "| 'pacdefs.h'. |");
};
POS(line++, 20);
(void) fprintf(stdout, "| |");
POS(line++, 20);
(void) fprintf(stdout, "| Your score: %-5u |", pscore);
POS(line, 20);
(void) fprintf(stdout, "|___________________________|");
};
leave();
}
/*
* leave -- flush buffers,kill the Child, reset tty, and delete tempfile
*/
leave()
{
POS(23, 0);
(void) fflush(stdout);
sleep(1);
#ifndef NODELAY
kill(cpid, SIGKILL);
#endif
#ifdef BELL3.0
ioctl(0, TCSETAW, &savetty);
#else
ioctl(0, TIOCSETP, &savetty);
#endif
#ifndef NODELAY
#ifndef MSG
close(comfile);
unlink(fnam);
#endif
#endif
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()) */
errno = 0;
(void) time(&timein); /* get start time */
srand((unsigned)timein); /* start rand randomly */
/*
* verify CRT and get proper cursor control sequence.
*/
#ifdef NODELAY
#ifndef BELL3.0
close(0);
if (open("/dev/tty", O_RDONLY | O_NDELAY) != 0)
{
perror("Unable to open /dev/tty");
exit(1);
};
#endif
#endif
vsinit();
/*
* setup raw mode, no echo
*/
#ifdef BELL3.0
ioctl(0, TCGETA, &savetty);
newtty = savetty;
if ((savetty.c_cflag & CBAUD) == B9600)
{
delay = 1000 * (nrand(10) + 5);
}
else
{
delay = 1000;
};
ospeed = savetty.c_cflag & CBAUD; /* for tputs() */
#ifdef NODELAY
newtty.c_cc[VTIME] = 7;
newtty.c_cc[VMIN] = 0;
#else
newtty.c_cc[VMIN] = 1;
#endif
newtty.c_iflag = 0;
newtty.c_oflag &= ~OPOST;
newtty.c_cflag &= ~(PARENB | CSIZE);
newtty.c_cflag |= CS8;
newtty.c_lflag &= ~(ECHO | ECHOE | ISIG | ICANON | XCASE);
ioctl(0, TCSETAW, &newtty);
#else
ioctl(0, TIOCGETP, &savetty);
newtty = savetty;
if (savetty.sg_ospeed >= B9600)
delay = 1000 * (nrand(10) + 5);
else
delay = 1000;
ospeed = savetty.sg_ospeed; /* for tputs() */
newtty.sg_flags |= CBREAK;
newtty.sg_flags &= ~ECHO;
ioctl(0, TIOCSETP, &newtty);
#endif
/*
* set up communications
*/
#ifndef NODELAY
#ifndef MSG
fnam = mktemp(TMPF);
if ((comfile = creat(fnam, 0666)) == -1)
{
(void) sprintf(message, "Cannot create %s", fnam);
perror(message);
leave();
};
/*
* initialize semaphore
*/
lseek(comfile, 0l, 0);
combuf[1] = EMPTY;
write(comfile, combuf, 2);
close(comfile);
#endif
#endif
#ifndef NODELAY
/*
* fork off a child to read the input
*/
ppid = getpid();
if ((cpid = fork()) == 0)
{
#ifndef MSG
comfile = open(fnam, O_RDWR);
#endif
for (;;)
{
read(0, inbuf, 1);
if (lastchar != inbuf[0])
{
#ifdef MSG
if (inbuf[0] == DELETE || inbuf[0] == ABORT)
leave();
send(inbuf, 1, ppid, 64);
#else
lseek(comfile, 0l, 0);
read(comfile, combuf, 2);
if (combuf[1] == EMPTY)
{
lseek(comfile, 0l, 0);
combuf[0] = inbuf[0];
combuf[1] = FULL;
write(comfile, combuf, 2);
};
#endif
};
lastchar = DELETE;
};
};
#ifndef MSG
comfile = open(fnam, O_RDWR);
#else
msgenab();
#endif
#endif
/*
* New game starts here
*/
game = 0;
instruct();
while ((game == 0) && (tries++ < 300))
{
poll(1);
};
if (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;
#ifndef NODELAY
#ifdef MSG
struct mstruct msghead;
#endif
#endif
stop = 0;
readin:
#ifdef NODELAY
fflush(stdout);
charcnt = 0;
nap(12);
#ifndef BELL3.0
ioctl(0, FIONREAD, &junk);
if (junk)
#endif
charcnt = read(0, combuf, 1);
switch (charcnt)
{
case 0:
combuf[1] = EMPTY;
break;
case -1:
errgen("READ ERROR IN POLL");
abort();
default:
combuf[0] = combuf[charcnt-1];
combuf[1] = FULL;
break;
};
#else
#ifdef MSG
combuf[1] = (recv(combuf, 1, &msghead, 0) == -1) ? EMPTY : FULL;
#else
lseek(comfile, 0l, 0); /* rewind */
read(comfile, combuf, 2); /* read 2 chars */
#endif
#endif
if (combuf[1] == EMPTY)
{
#ifndef BELL3.0
#ifndef NODELAY
if (sltime > 0)
{
sleep(sltime);
};
#endif
#endif
if (stop)
{
goto readin;
};
return;
};
combuf[1] = EMPTY;
#ifndef NODELAY
#ifndef MSG
lseek(comfile, 0l, 0); /* another rewind */
write(comfile, combuf, 2);
#endif
#endif
switch(combuf[0] & 0177)
{
case LEFT:
pacptr->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 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;
case GAME4:
game = 4;
break;
default:
goto readin;
}
}
vsinit()
{
char buf[1024];
char tspace[256], *aoftspace;
char *tgetstr();
extern char *UP, *BC; /* defined in tgoto.c (from ex's termlib */
extern char PC; /* defined in tputs.c (from termlib) */
tgetent(buf, getenv("TERM"));
aoftspace = tspace;
vs_cl = tgetstr("cl", &aoftspace);
vs_cm = tgetstr("cm", &aoftspace);
BC = tgetstr("bc", &aoftspace);
UP = tgetstr("up", &aoftspace);
PC = *tgetstr("pc", &aoftspace);
vs_vb = tgetstr("vb", &aoftspace);
vs_rows = tgetnum("li");
vs_cols = tgetnum("co");
if ((vs_vb == 0) || (*vs_vb == '\0'))
{
vs_vb = aoftspace;
*vs_vb++ = '';
*vs_vb++ = '\0';
aoftspace += 2;
};
if ((vs_cl == 0) || (*vs_cl == '\0') ||
(vs_cm == 0) || (*vs_cm == '\0'))
{
(void) fprintf(stderr, "\nPacman is designed for CRT's with addressable cursors.\n");
(void) fprintf(stderr, "Verify that the TERM environment variable is a proper\n");
(void) fprintf(stderr, "type and is export-ed, and try it again...\n\n");
exit(2);
};
}
/* dfp - real function for tputs function to use */
putch( ch )
register int ch;
{
putchar( ch );
}