|
|
1.1 root 1: #include <stdio.h>
2: #include <signal.h>
3: #ifdef BELL3.0
4: #include <fcntl.h>
5: #include <termio.h>
6: #else
7: #include <sgtty.h>
8: #endif
9: #include <pwd.h>
10: #include "pacdefs.h"
11:
12: #ifndef BELL3.0
13: #define O_RDWR 2
14: #define O_CREAT 0
15: #define O_RDONLY 0
16: #define O_NDELAY 0
17: #endif
18:
19: extern char
20: *BC,
21: *UP;
22:
23: extern int
24: putch();
25:
26: extern char
27: *tgoto(),
28: *mktemp();
29:
30: extern int
31: delay,
32: errno,
33: goldcnt;
34:
35: extern long
36: time();
37:
38: extern struct pac
39: *pacptr;
40:
41: extern struct pac
42: monst[];
43:
44: #ifndef MSG
45: int comfile;
46: #else
47: struct mstruct
48: {
49: int frompid;
50: int mtype;
51: };
52:
53: #endif
54:
55: #ifndef NODELAY
56:
57: #ifndef MSG
58: char *fnam;
59: #endif
60:
61: #endif
62:
63: /*
64: * initbrd is used to re-initialize the display
65: * array once a new game is started.
66: */
67: char initbrd[BRDY][BRDX] =
68: {
69: "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
70: "O + + + * + + + + OOO + + + + * + + + O",
71: "O X OOO + OOOOO + OOO + OOOOO + OOO X O",
72: "O * + + * + * + * + + * + * + * + + * O",
73: "O + OOO + O + OOOOOOOOOOO + O + OOO + O",
74: "O + + + * O + + + OOO + + + O * + + + O",
75: "OOOOOOO + OOOOO + OOO + OOOOO + OOOOOOO",
76: " O + O + + * + + * + + O + O ",
77: " O + O + OOO - - OOO + O + O ",
78: "OOOOOOO + O + O O + O + OOOOOOO",
79: " * + * O O * + * ",
80: "OOOOOOO + O + O O + O + OOOOOOO",
81: " O + O + OOOOOOOOOOO + O + O ",
82: " O + O * + + + + + + * O + O ",
83: "OOOOOOO + O + OOOOOOOOOOO + O + OOOOOOO",
84: "O + + + * + * + + OOO + + * + * + + + O",
85: "O X OOO + OOOOO + OOO + OOOOO + OOO X O",
86: "O + + O * + * + * + + * + * + * O + + O",
87: "OOO + O + O + OOOOOOOOOOO + O + O + OOO",
88: "O + * + + O + + + OOO + + + O + + * + O",
89: "O + OOOOOOOOOOO + OOO + OOOOOOOOOOO + O",
90: "O + + + + + + + * + + * + + + + + + + O",
91: "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
92: };
93:
94: /*
95: * brd is kept for historical reasons.
96: * It should only be used in the routine "which"
97: * to determine the next move for a monster or
98: * in the routine "monster" to determine if it
99: * was a valid move. Admittedly this is redundant
100: * and could be replaced by initbrd, but it is kept
101: * so that someday additional intelligence or
102: * optimization could be added to the choice of
103: * the monster's next move. Hence, note the symbol
104: * CHOICE at most points that a move decision
105: * logically HAS to be made.
106: */
107: char brd[BRDY][BRDX] =
108: {
109: "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
110: "O + + + * + + + + OOO + + + + * + + + O",
111: "O X OOO + OOOOO + OOO + OOOOO + OOO X O",
112: "O * + + * + * + * + + * + * + * + + * O",
113: "O + OOO + O + OOOOOOOOOOO + O + OOO + O",
114: "O + + + * O + + + OOO + + + O * + + + O",
115: "OOOOOOO + OOOOO + OOO + OOOOO + OOOOOOO",
116: " O + O + + * + + * + + O + O ",
117: " O + O + OOO - - OOO + O + O ",
118: "OOOOOOO + O + O O + O + OOOOOOO",
119: " * + * O O * + * ",
120: "OOOOOOO + O + O O + O + OOOOOOO",
121: " O + O + OOOOOOOOOOO + O + O ",
122: " O + O * + + + + + + * O + O ",
123: "OOOOOOO + O + OOOOOOOOOOO + O + OOOOOOO",
124: "O + + + * + * + + OOO + + * + * + + + O",
125: "O X OOO + OOOOO + OOO + OOOOO + OOO X O",
126: "O + + O * + * + * + + * + * + * O + + O",
127: "OOO + O + O + OOOOOOOOOOO + O + O + OOO",
128: "O + * + + O + + + OOO + + + O + + * + O",
129: "O + OOOOOOOOOOO + OOO + OOOOOOOOOOO + O",
130: "O + + + + + + + * + + * + + + + + + + O",
131: "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
132: };
133:
134: /*
135: * display reflects the screen on the player's
136: * terminal at any point in time.
137: */
138: char display[BRDY][BRDX] =
139: {
140: "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
141: "O + + + + + + + + OOO + + + + + + + + O",
142: "O X OOO + OOOOO + OOO + OOOOO + OOO X O",
143: "O + + + + + + + + + + + + + + + + + + O",
144: "O + OOO + O + OOOOOOOOOOO + O + OOO + O",
145: "O + + + + O + + + OOO + + + O + + + + O",
146: "OOOOOOO + OOOOO + OOO + OOOOO + OOOOOOO",
147: " O + O + + + + + + + + O + O ",
148: " O + O + OOO - - OOO + O + O ",
149: "OOOOOOO + O + O O + O + OOOOOOO",
150: " + + + O O + + + ",
151: "OOOOOOO + O + O O + O + OOOOOOO",
152: " O + O + OOOOOOOOOOO + O + O ",
153: " O + O + + + + + + + + O + O ",
154: "OOOOOOO + O + OOOOOOOOOOO + O + OOOOOOO",
155: "O + + + + + + + + OOO + + + + + + + + O",
156: "O X OOO + OOOOO + OOO + OOOOO + OOO X O",
157: "O + + O + + + + + + + + + + + + O + + O",
158: "OOO + O + O + OOOOOOOOOOO + O + O + OOO",
159: "O + + + + O + + + OOO + + + O + + + + O",
160: "O + OOOOOOOOOOO + OOO + OOOOOOOOOOO + O",
161: "O + + + + + + + + + + + + + + + + + + O",
162: "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
163: };
164:
165: /* terminal type from environment and /etc/termcap ala ex & vi */
166: char *vs_cl = "", /* clear screen sequence */
167: *vs_cm = "", /* cursor positioning sequence */
168: *vs_vb = "";
169:
170: char combuf[BUFSIZ],
171: message[81], /* temporary message buffer */
172: inbuf[2];
173:
174: int ppid,
175: cpid,
176: game,
177: killcnt = 0,
178: vs_rows,
179: vs_cols;
180:
181: unsigned
182: pscore;
183:
184: long timein;
185:
186: #ifdef BELL3.0
187: struct termio
188: savetty,
189: newtty;
190: #else
191: struct sgttyb
192: savetty, newtty;
193: #endif
194:
195: struct uscore
196: {
197: unsigned score; /* same type as pscore */
198: int uid; /* uid of player */
199: };
200:
201: struct scorebrd
202: {
203: struct uscore entry[MSSAVE];
204: } scoresave[MGTYPE] =
205: {
206: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
207: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
208: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
209: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
210: };
211:
212: update()
213: {
214: char str[10];
215:
216: (void) sprintf(str, "%6d", pscore);
217: SPLOT(0, 52, str);
218: (void) sprintf(str, "%6d", goldcnt);
219: SPLOT(21, 57, str);
220: }
221:
222: reinit()
223: {
224: register int locx, locy;
225: register char tmp;
226:
227: for (locy = 0; locy < BRDY; locy++)
228: {
229: for (locx = 0; locx < BRDX; locx++)
230: {
231: tmp = initbrd[locy][locx];
232: brd[locy][locx] = tmp;
233: if ((display[locy][locx] = tmp) == CHOICE)
234: {
235: display[locy][locx] = GOLD;
236: };
237: };
238: };
239: goldcnt = GOLDCNT;
240: delay -= (delay / 10); /* hot it up */
241: }
242:
243: errgen(string)
244: char *string;
245: {
246: SPLOT(23,45,string);
247: }
248:
249: dokill(mnum)
250: int mnum;
251: {
252: register struct pac *mptr;
253:
254: PLOT(0, 0, BEEP);
255: if (pacptr->danger == TRUE)
256: {
257: if (++killcnt == MAXMONSTER)
258: {
259: if (display[TRYPOS][TRXPOS] == GOLD)
260: {
261: goldcnt--;
262: };
263: display[TRYPOS][TRXPOS] = TREASURE;
264: PLOT(TRYPOS, TRXPOS, TREASURE);
265: killcnt = 0;
266: };
267: SPLOT(5, 45, "MONSTERS KILLED: ");
268: (void) sprintf(message, "%1d", killcnt);
269: SPLOT(5, 62, message);
270: mptr = (&monst[mnum]);
271: mptr->ypos = MSTARTY;
272: mptr->xpos = MSTARTX + (2 * mnum);
273: mptr->stat = START;
274: PLOT(mptr->ypos, mptr->xpos, MONSTER);
275: pscore += KILLSCORE;
276: return(GOTONE);
277: };
278: return(TURKEY);
279: }
280:
281: /*
282: /* clr -- issues an escape sequence to clear the display
283: */
284:
285: clr()
286: {
287: (void) fprintf(stdout, "%s", vs_cl);
288: fflush(stdout);
289: nap(2);
290: }
291:
292: /*
293: * display initial instructions
294: */
295:
296: instruct()
297: {
298: clr();
299: POS(0, 0);
300: (void) fprintf(stdout, "Attention: you are in a dungeon, being chased by monsters!\r\n\n");
301: (void) fprintf(stdout, "There are gold coins scattered uniformly in the dungeon, marked by \"+\".\r\n");
302: (void) fprintf(stdout, "One magic potion is available at each spot marked \"X\". Each potion will\r\n");
303: (void) fprintf(stdout, "enable you to kill monsters by touch for a limited duration. It will also\r\n");
304: (void) fprintf(stdout, "scare them away. When you kill a monster it is regenerated, but this takes\r\n");
305: (void) fprintf(stdout, "time. You can also regenerate yourself %d times. Killing all the monsters\r\n", MAXPAC);
306: (void) fprintf(stdout, "results in further treasure appearing magically somewhere in the dungeon,\r\n");
307: (void) fprintf(stdout, "marked by \"$\". There is a magic tunnel connecting the center left and\r\n");
308: (void) fprintf(stdout, "center right parts of the dungeon. The monsters know about it!\r\n\n");
309: (void) fprintf(stdout, " Type: h to move left\r\n");
310: (void) fprintf(stdout, " l to move right\r\n");
311: (void) fprintf(stdout, " k or w to move up\r\n");
312: (void) fprintf(stdout, " j or x to move down\r\n");
313: (void) fprintf(stdout, " <space> to halt \r\n");
314: (void) fprintf(stdout, " q to quit\r\n\n");
315: (void) fprintf(stdout, " Type: 1 normal game\r\n");
316: (void) fprintf(stdout, " 2 blinking monsters\r\n");
317: (void) fprintf(stdout, " 3 intelligent monsters\r\n");
318: (void) fprintf(stdout, " 4 blinking intelligent monsters\r\n");
319: }
320:
321: /*
322: * over -- game over processing
323: */
324:
325: over()
326: {
327: register int i;
328: register int line;
329: int scorefile = 0;
330: struct passwd *getpwuid(), *p;
331:
332: fflush(stdout);
333: sleep(5); /* for slow readers */
334: poll(0); /* flush and discard input from player */
335: clr();
336: /* high score to date processing */
337: if (game != 0)
338: {
339: line = 7;
340: POS(line++, 20);
341: (void) fprintf(stdout, " ___________________________ ");
342: POS(line++, 20);
343: (void) fprintf(stdout, "| |");
344: POS(line++, 20);
345: (void) fprintf(stdout, "| G A M E O V E R |");
346: POS(line++, 20);
347: (void) fprintf(stdout, "| |");
348: POS(line++, 20);
349: (void) fprintf(stdout, "| Game type: %1d |",game);
350: if ((scorefile = open(MAXSCORE, O_RDWR | O_CREAT, 0666)) != -1)
351: {
352: read(scorefile, (char *)scoresave, sizeof(scoresave));
353: for (i = MSSAVE - 1; i >= 0; i--) {
354: if (scoresave[game - 1].entry[i].score < pscore)
355: {
356: if (i < MSSAVE - 1)
357: {
358: scoresave[game - 1].entry[i + 1].score =
359: scoresave[game - 1].entry[i].score;
360: scoresave[game - 1].entry[i + 1].uid =
361: scoresave[game - 1].entry[i].uid;
362: };
363: scoresave[game - 1].entry[i].score = pscore;
364: scoresave[game - 1].entry[i].uid = getuid();
365: };
366: };
367: lseek(scorefile, 0l, 0);
368: write(scorefile, (char *)scoresave, sizeof(scoresave));
369: close(scorefile);
370: POS(line++, 20);
371: (void) fprintf(stdout, "| High Scores to date: |");
372: for (i = 0; i < MSSAVE; i++)
373: {
374: setpwent();
375: p = getpwuid(scoresave[game - 1].entry[i].uid);
376: POS(line++, 20);
377: (void) fprintf(stdout, "| Player : %-8s %5u |", p->pw_name,
378: scoresave[game - 1].entry[i].score);
379: };
380: }
381: else
382: {
383: POS(line++, 20);
384: (void) fprintf(stdout, "| |");
385: POS(line++, 20);
386: (void) fprintf(stdout, "| Please create a 'paclog' |");
387: POS(line++, 20);
388: (void) fprintf(stdout, "| file. See 'MAXSCORE' in |");
389: POS(line++, 20);
390: (void) fprintf(stdout, "| 'pacdefs.h'. |");
391: };
392: POS(line++, 20);
393: (void) fprintf(stdout, "| |");
394: POS(line++, 20);
395: (void) fprintf(stdout, "| Your score: %-5u |", pscore);
396: POS(line, 20);
397: (void) fprintf(stdout, "|___________________________|");
398: };
399: leave();
400: }
401:
402: /*
403: * leave -- flush buffers,kill the Child, reset tty, and delete tempfile
404: */
405:
406: leave()
407: {
408: POS(23, 0);
409: (void) fflush(stdout);
410: sleep(1);
411:
412: #ifndef NODELAY
413: kill(cpid, SIGKILL);
414: #endif
415:
416: #ifdef BELL3.0
417: ioctl(0, TCSETAW, &savetty);
418: #else
419: ioctl(0, TIOCSETP, &savetty);
420: #endif
421:
422: #ifndef NODELAY
423:
424: #ifndef MSG
425: close(comfile);
426: unlink(fnam);
427: #endif
428:
429: #endif
430: exit(0);
431: }
432:
433: /*
434: * init -- does global initialization and spawns a child process to read
435: * the input terminal.
436: */
437:
438: init()
439: {
440: register int tries = 0;
441: static int lastchar = DELETE;
442: extern short ospeed; /* baud rate for crt (for tputs()) */
443:
444: errno = 0;
445: (void) time(&timein); /* get start time */
446: srand((unsigned)timein); /* start rand randomly */
447: /*
448: * verify CRT and get proper cursor control sequence.
449: */
450:
451: #ifdef NODELAY
452:
453: #ifndef BELL3.0
454: close(0);
455: if (open("/dev/tty", O_RDONLY | O_NDELAY) != 0)
456: {
457: perror("Unable to open /dev/tty");
458: exit(1);
459: };
460: #endif
461:
462: #endif
463: vsinit();
464: /*
465: * setup raw mode, no echo
466: */
467: #ifdef BELL3.0
468: ioctl(0, TCGETA, &savetty);
469: newtty = savetty;
470: if ((savetty.c_cflag & CBAUD) == B9600)
471: {
472: delay = 1000 * (nrand(10) + 5);
473: }
474: else
475: {
476: delay = 1000;
477: };
478: ospeed = savetty.c_cflag & CBAUD; /* for tputs() */
479: #ifdef NODELAY
480: newtty.c_cc[VTIME] = 7;
481: newtty.c_cc[VMIN] = 0;
482: #else
483: newtty.c_cc[VMIN] = 1;
484: #endif
485: newtty.c_iflag = 0;
486: newtty.c_oflag &= ~OPOST;
487: newtty.c_cflag &= ~(PARENB | CSIZE);
488: newtty.c_cflag |= CS8;
489: newtty.c_lflag &= ~(ECHO | ECHOE | ISIG | ICANON | XCASE);
490: ioctl(0, TCSETAW, &newtty);
491: #else
492: ioctl(0, TIOCGETP, &savetty);
493: newtty = savetty;
494: if (savetty.sg_ospeed >= B9600)
495: delay = 1000 * (nrand(10) + 5);
496: else
497: delay = 1000;
498: ospeed = savetty.sg_ospeed; /* for tputs() */
499: newtty.sg_flags |= CBREAK;
500: newtty.sg_flags &= ~ECHO;
501: ioctl(0, TIOCSETP, &newtty);
502: #endif
503:
504: /*
505: * set up communications
506: */
507:
508: #ifndef NODELAY
509:
510: #ifndef MSG
511: fnam = mktemp(TMPF);
512: if ((comfile = creat(fnam, 0666)) == -1)
513: {
514: (void) sprintf(message, "Cannot create %s", fnam);
515: perror(message);
516: leave();
517: };
518: /*
519: * initialize semaphore
520: */
521: lseek(comfile, 0l, 0);
522: combuf[1] = EMPTY;
523: write(comfile, combuf, 2);
524: close(comfile);
525: #endif
526: #endif
527:
528: #ifndef NODELAY
529: /*
530: * fork off a child to read the input
531: */
532: ppid = getpid();
533: if ((cpid = fork()) == 0)
534: {
535: #ifndef MSG
536: comfile = open(fnam, O_RDWR);
537: #endif
538: for (;;)
539: {
540: read(0, inbuf, 1);
541: if (lastchar != inbuf[0])
542: {
543: #ifdef MSG
544: if (inbuf[0] == DELETE || inbuf[0] == ABORT)
545: leave();
546: send(inbuf, 1, ppid, 64);
547: #else
548: lseek(comfile, 0l, 0);
549: read(comfile, combuf, 2);
550: if (combuf[1] == EMPTY)
551: {
552: lseek(comfile, 0l, 0);
553: combuf[0] = inbuf[0];
554: combuf[1] = FULL;
555: write(comfile, combuf, 2);
556: };
557: #endif
558: };
559: lastchar = DELETE;
560: };
561: };
562:
563: #ifndef MSG
564: comfile = open(fnam, O_RDWR);
565: #else
566: msgenab();
567: #endif
568:
569: #endif
570: /*
571: * New game starts here
572: */
573: game = 0;
574: instruct();
575: while ((game == 0) && (tries++ < 300))
576: {
577: poll(1);
578: };
579: if (tries >= 300)
580: {
581: /* I give up. Let's call it quits. */
582: leave();
583: };
584: goldcnt = GOLDCNT;
585: pscore = 0;
586: clr();
587: }
588:
589: /*
590: * poll -- read characters sent by input subprocess and set global flags
591: */
592:
593: poll(sltime)
594: {
595: int stop;
596: register int charcnt;
597: int junk;
598:
599: #ifndef NODELAY
600: #ifdef MSG
601: struct mstruct msghead;
602: #endif
603: #endif
604:
605: stop = 0;
606: readin:
607:
608: #ifdef NODELAY
609: fflush(stdout);
610: charcnt = 0;
611: nap(12);
612: #ifndef BELL3.0
613: ioctl(0, FIONREAD, &junk);
614: if (junk)
615: #endif
616: charcnt = read(0, combuf, 1);
617: switch (charcnt)
618: {
619:
620: case 0:
621: combuf[1] = EMPTY;
622: break;
623:
624: case -1:
625: errgen("READ ERROR IN POLL");
626: abort();
627:
628: default:
629: combuf[0] = combuf[charcnt-1];
630: combuf[1] = FULL;
631: break;
632: };
633: #else
634:
635: #ifdef MSG
636: combuf[1] = (recv(combuf, 1, &msghead, 0) == -1) ? EMPTY : FULL;
637: #else
638: lseek(comfile, 0l, 0); /* rewind */
639: read(comfile, combuf, 2); /* read 2 chars */
640: #endif
641:
642: #endif
643: if (combuf[1] == EMPTY)
644: {
645: #ifndef BELL3.0
646:
647: #ifndef NODELAY
648: if (sltime > 0)
649: {
650: sleep(sltime);
651: };
652: #endif
653:
654: #endif
655: if (stop)
656: {
657: goto readin;
658: };
659: return;
660: };
661: combuf[1] = EMPTY;
662:
663: #ifndef NODELAY
664:
665: #ifndef MSG
666: lseek(comfile, 0l, 0); /* another rewind */
667: write(comfile, combuf, 2);
668: #endif
669: #endif
670:
671: switch(combuf[0] & 0177)
672: {
673: case LEFT:
674: pacptr->dirn = DLEFT;
675: break;
676:
677: case RIGHT:
678: pacptr->dirn = DRIGHT;
679: break;
680:
681: case NORTH:
682: case NNORTH:
683: pacptr->dirn = DUP;
684: break;
685:
686: case DOWN:
687: case NDOWN:
688: pacptr->dirn = DDOWN;
689: break;
690:
691: case HALT:
692: pacptr->dirn = DNULL;
693: break;
694:
695: case ABORT:
696: case DELETE:
697: case QUIT:
698: over();
699: break;
700:
701: case CNTLS:
702: stop = 1;
703: goto readin;
704:
705: case GAME1:
706: game = 1;
707: break;
708:
709: case GAME2:
710: game = 2;
711: break;
712:
713: case GAME3:
714: game = 3;
715: break;
716:
717: case GAME4:
718: game = 4;
719: break;
720:
721: default:
722: goto readin;
723: }
724: }
725:
726: vsinit()
727: {
728: char buf[1024];
729: char tspace[256], *aoftspace;
730: char *tgetstr();
731: extern char *UP, *BC; /* defined in tgoto.c (from ex's termlib */
732: extern char PC; /* defined in tputs.c (from termlib) */
733:
734: tgetent(buf, getenv("TERM"));
735: aoftspace = tspace;
736: vs_cl = tgetstr("cl", &aoftspace);
737: vs_cm = tgetstr("cm", &aoftspace);
738: BC = tgetstr("bc", &aoftspace);
739: UP = tgetstr("up", &aoftspace);
740: PC = *tgetstr("pc", &aoftspace);
741: vs_vb = tgetstr("vb", &aoftspace);
742: vs_rows = tgetnum("li");
743: vs_cols = tgetnum("co");
744: if ((vs_vb == 0) || (*vs_vb == '\0'))
745: {
746: vs_vb = aoftspace;
747: *vs_vb++ = '';
748: *vs_vb++ = '\0';
749: aoftspace += 2;
750: };
751: if ((vs_cl == 0) || (*vs_cl == '\0') ||
752: (vs_cm == 0) || (*vs_cm == '\0'))
753: {
754: (void) fprintf(stderr, "\nPacman is designed for CRT's with addressable cursors.\n");
755: (void) fprintf(stderr, "Verify that the TERM environment variable is a proper\n");
756: (void) fprintf(stderr, "type and is export-ed, and try it again...\n\n");
757: exit(2);
758: };
759: }
760:
761: /* dfp - real function for tputs function to use */
762: putch( ch )
763: register int ch;
764: {
765: putchar( ch );
766: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.