V10/games/pacman/util.c

Compare this file to the similar file:
Show the results in this format:

#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 );
}