BSD 4_3 development
authorCSRG <csrg@ucbvax.Berkeley.EDU>
Sat, 11 Jan 1986 04:47:27 +0000 (20:47 -0800)
committerCSRG <csrg@ucbvax.Berkeley.EDU>
Sat, 11 Jan 1986 04:47:27 +0000 (20:47 -0800)
Work on file usr/src/games/hunt/draw.c
Work on file usr/src/games/hunt/driver.c
Work on file usr/src/games/hunt/expl.c
Work on file usr/src/games/hunt/hunt.c
Work on file usr/src/games/hunt/hunt.h
Work on file usr/src/games/hunt/playit.c
Work on file usr/src/games/hunt/shots.c

Synthesized-from: CSRG/cd1/4.3

usr/src/games/hunt/draw.c [new file with mode: 0644]
usr/src/games/hunt/driver.c [new file with mode: 0644]
usr/src/games/hunt/expl.c [new file with mode: 0644]
usr/src/games/hunt/hunt.c [new file with mode: 0644]
usr/src/games/hunt/hunt.h [new file with mode: 0644]
usr/src/games/hunt/playit.c [new file with mode: 0644]
usr/src/games/hunt/shots.c [new file with mode: 0644]

diff --git a/usr/src/games/hunt/draw.c b/usr/src/games/hunt/draw.c
new file mode 100644 (file)
index 0000000..796c514
--- /dev/null
@@ -0,0 +1,388 @@
+/*
+ *  Hunt
+ *  Copyright (c) 1985 Conrad C. Huang, Gregory S. Couch, Kenneth C.R.C. Arnold
+ *  San Francisco, California
+ *
+ *  Copyright (c) 1985 Regents of the University of California.
+ *  All rights reserved.  The Berkeley software License Agreement
+ *  specifies the terms and conditions for redistribution.
+ */
+
+# include      "hunt.h"
+
+drawmaze(pp)
+register PLAYER        *pp;
+{
+       register int    x;
+       register char   *sp;
+       register int    y;
+       register char   *endp;
+
+       clrscr(pp);
+       outstr(pp, pp->p_maze[0], WIDTH);
+       for (y = 1; y < HEIGHT - 1; y++) {
+               endp = &pp->p_maze[y][WIDTH];
+               for (x = 0, sp = pp->p_maze[y]; sp < endp; x++, sp++)
+                       if (*sp != SPACE) {
+                               cgoto(pp, y, x);
+                               if (pp->p_x == x && pp->p_y == y)
+                                       outch(pp, translate(*sp));
+                               else
+                                       outch(pp, *sp);
+                       }
+       }
+       cgoto(pp, HEIGHT - 1, 0);
+       outstr(pp, pp->p_maze[HEIGHT - 1], WIDTH);
+       drawstatus(pp);
+}
+
+/*
+ * drawstatus - put up the status lines (this assumes the screen
+ *             size is 80x24 with the maze being 64x24)
+ */
+drawstatus(pp)
+register PLAYER        *pp;
+{
+       register int    i;
+       register PLAYER *np;
+
+       (void) sprintf(Buf, "%-13.13s", pp->p_ident->i_name);
+       cgoto(pp, STAT_NAME_ROW, STAT_LABEL_COL);
+       outstr(pp, Buf, 13);
+
+       cgoto(pp, STAT_AMMO_ROW, STAT_LABEL_COL);
+       outstr(pp, "Ammo:", 5);
+       (void) sprintf(Buf, "%3d", pp->p_ammo);
+       cgoto(pp, STAT_AMMO_ROW, STAT_VALUE_COL);
+       outstr(pp, Buf, 3);
+
+       cgoto(pp, STAT_CLOAK_ROW, STAT_LABEL_COL);
+       outstr(pp, "Cloak:", 6);
+       cgoto(pp, STAT_CLOAK_ROW, STAT_VALUE_COL);
+       outstr(pp, (pp->p_cloak < 0) ? "   " : " on", 3);
+
+       cgoto(pp, STAT_SCAN_ROW, STAT_LABEL_COL);
+       outstr(pp, "Scan:", 5);
+       cgoto(pp, STAT_SCAN_ROW, STAT_VALUE_COL);
+       outstr(pp, (pp->p_scan < 0) ? "   " : " on", 3);
+
+       cgoto(pp, STAT_GUN_ROW, STAT_LABEL_COL);
+       outstr(pp, "Gun:", 4);
+       cgoto(pp, STAT_GUN_ROW, STAT_VALUE_COL);
+       outstr(pp, (pp->p_ncshot < MAXNCSHOT) ? " ok" : "   ", 3);
+
+       cgoto(pp, STAT_DAM_ROW, STAT_LABEL_COL);
+       outstr(pp, "Damage:", 7);
+       (void) sprintf(Buf, "%2d/%2d", pp->p_damage, pp->p_damcap);
+       cgoto(pp, STAT_DAM_ROW, STAT_VALUE_COL);
+       outstr(pp, Buf, 5);
+
+       cgoto(pp, STAT_KILL_ROW, STAT_LABEL_COL);
+       outstr(pp, "Kills:", 6);
+       (void) sprintf(Buf, "%3d", (pp->p_damcap - MAXDAM) / 2);
+       cgoto(pp, STAT_KILL_ROW, STAT_VALUE_COL);
+       outstr(pp, Buf, 3);
+
+       cgoto(pp, STAT_PLAY_ROW, STAT_LABEL_COL);
+       outstr(pp, "Player:", 7);
+       for (i = STAT_PLAY_ROW + 1, np = Player; np < End_player; np++) {
+               (void) sprintf(Buf, "%5.2f%c%-10.10s", np->p_ident->i_score,
+                       stat_char(np), np->p_ident->i_name);
+               cgoto(pp, i++, STAT_NAME_COL);
+               outstr(pp, Buf, STAT_NAME_LEN);
+       }
+
+# ifdef MONITOR
+       cgoto(pp, STAT_MON_ROW, STAT_LABEL_COL);
+       outstr(pp, "Monitor:", 8);
+       for (i = STAT_MON_ROW + 1, np = Monitor; np < End_monitor; np++) {
+               (void) sprintf(Buf, "%5.5s %-10.10s", " ", np->p_ident->i_name);
+               cgoto(pp, i++, STAT_NAME_COL);
+               outstr(pp, Buf, STAT_NAME_LEN);
+       }
+# endif MONITOR
+}
+
+# ifndef CPUHOG
+look(pp)
+register PLAYER        *pp;
+{
+       register int    x, y;
+
+       x = pp->p_x;
+       y = pp->p_y;
+
+       check(pp, y - 1, x - 1);
+       check(pp, y - 1, x    );
+       check(pp, y - 1, x + 1);
+       check(pp, y    , x - 1);
+       check(pp, y    , x    );
+       check(pp, y    , x + 1);
+       check(pp, y + 1, x - 1);
+       check(pp, y + 1, x    );
+       check(pp, y + 1, x + 1);
+
+       switch (pp->p_face) {
+         case LEFTS:
+               see(pp, LEFTS);
+               see(pp, ABOVE);
+               see(pp, BELOW);
+               break;
+         case RIGHT:
+               see(pp, RIGHT);
+               see(pp, ABOVE);
+               see(pp, BELOW);
+               break;
+         case ABOVE:
+               see(pp, ABOVE);
+               see(pp, LEFTS);
+               see(pp, RIGHT);
+               break;
+         case BELOW:
+               see(pp, BELOW);
+               see(pp, LEFTS);
+               see(pp, RIGHT);
+               break;
+# ifdef FLY
+         case FLYER:
+               break;
+# endif FLY
+       }
+       cgoto(pp, y, x);
+}
+
+see(pp, face)
+register PLAYER        *pp;
+int            face;
+{
+       register char   *sp;
+       register int    y, x, i, cnt;
+
+       x = pp->p_x;
+       y = pp->p_y;
+
+       switch (face) {
+         case LEFTS:
+               sp = &Maze[y][x];
+               for (i = 0; See_over[*--sp]; i++)
+                       continue;
+
+               if (i == 0)
+                       break;
+
+               cnt = i;
+               x = pp->p_x - 1;
+               --y;
+               while (i--)
+                       check(pp, y, --x);
+               i = cnt;
+               x = pp->p_x - 1;
+               ++y;
+               while (i--)
+                       check(pp, y, --x);
+               i = cnt;
+               x = pp->p_x - 1;
+               ++y;
+               while (i--)
+                       check(pp, y, --x);
+               break;
+         case RIGHT:
+               sp = &Maze[y][++x];
+               for (i = 0; See_over[*sp++]; i++)
+                       continue;
+
+               if (i == 0)
+                       break;
+
+               cnt = i;
+               x = pp->p_x + 1;
+               --y;
+               while (i--)
+                       check(pp, y, ++x);
+               i = cnt;
+               x = pp->p_x + 1;
+               ++y;
+               while (i--)
+                       check(pp, y, ++x);
+               i = cnt;
+               x = pp->p_x + 1;
+               ++y;
+               while (i--)
+                       check(pp, y, ++x);
+               break;
+         case ABOVE:
+               sp = &Maze[--y][x];
+               if (!See_over[*sp])
+                       break;
+               do {
+                       --y;
+                       sp -= sizeof Maze[0];
+                       check(pp, y, x - 1);
+                       check(pp, y, x    );
+                       check(pp, y, x + 1);
+               } while (See_over[*sp]);
+               break;
+         case BELOW:
+               sp = &Maze[++y][x];
+               if (!See_over[*sp])
+                       break;
+               do {
+                       y++;
+                       sp += sizeof Maze[0];
+                       check(pp, y, x - 1);
+                       check(pp, y, x    );
+                       check(pp, y, x + 1);
+               } while (See_over[*sp]);
+               break;
+       }
+}
+
+# else CPUHOG
+
+look(pp)
+register PLAYER        *pp;
+{
+       switch (pp->p_face) {
+         case LEFTS:
+               lookquad2(pp, pp->p_y, pp->p_x);
+               lookquad3(pp, pp->p_y, pp->p_x);
+               break;
+         case RIGHT:
+               lookquad1(pp, pp->p_y, pp->p_x);
+               lookquad4(pp, pp->p_y, pp->p_x);
+               break;
+         case ABOVE:
+               lookquad3(pp, pp->p_y, pp->p_x);
+               lookquad4(pp, pp->p_y, pp->p_x);
+               break;
+         case BELOW:
+               lookquad1(pp, pp->p_y, pp->p_x);
+               lookquad2(pp, pp->p_y, pp->p_x);
+               break;
+       }
+       cgoto(pp, pp->p_y, pp->p_x);
+}
+# endif CPUHOG
+
+check(pp, y, x)
+PLAYER *pp;
+int    y, x;
+{
+       register int    index;
+       register int    ch;
+       register PLAYER *rpp;
+
+       index = y * sizeof Maze[0] + x;
+       ch = ((char *) Maze)[index];
+       if (ch != ((char *) pp->p_maze)[index]) {
+               rpp = pp;
+               cgoto(rpp, y, x);
+               if (x == rpp->p_x && y == rpp->p_y)
+                       outch(rpp, translate(ch));
+               else
+                       outch(rpp, ch);
+               ((char *) rpp->p_maze)[index] = ch;
+       }
+}
+
+/*
+ * showstat
+ *     Update the status of players
+ */
+showstat(pp)
+register PLAYER        *pp;
+{
+       register PLAYER *np;
+       register int    y;
+       register char   c;
+
+       y = STAT_PLAY_ROW + 1 + (pp - Player);
+       c = stat_char(pp);
+# ifdef MONITOR
+       for (np = Monitor; np < End_monitor; np++) {
+               cgoto(np, y, STAT_SCAN_COL);
+               outch(np, c);
+       }
+# endif MONITOR
+       for (np = Player; np < End_player; np++) {
+               cgoto(np, y, STAT_SCAN_COL);
+               outch(np, c);
+       }
+}
+
+/*
+ * drawplayer:
+ *     Draw the player on the screen and show him to everyone who's scanning
+ *     unless he is cloaked.
+ */
+drawplayer(pp, draw)
+PLAYER *pp;
+FLAG   draw;
+{
+       register PLAYER *newp;
+       register int    x, y;
+
+       x = pp->p_x;
+       y = pp->p_y;
+       Maze[y][x] = draw ? pp->p_face : pp->p_over;
+
+# ifdef MONITOR
+       for (newp = Monitor; newp < End_monitor; newp++)
+               check(newp, y, x);
+# endif MONITOR
+
+       for (newp = Player; newp < End_player; newp++) {
+               if (!draw || newp == pp) {
+                       check(newp, y, x);
+                       continue;
+               }
+               if (newp->p_scan == 0) {
+                       cgoto(newp, STAT_SCAN_ROW, STAT_VALUE_COL);
+                       outstr(newp, "   ", 3);
+                       newp->p_scan--;
+                       showstat(newp);
+               }
+               else if (newp->p_scan > 0) {
+                       if (pp->p_cloak < 0)
+                               check(newp, y, x);
+                       newp->p_scan--;
+               }
+       }
+       if (!draw || pp->p_cloak < 0)
+               return;
+       if (pp->p_cloak-- == 0) {
+               cgoto(pp, STAT_CLOAK_ROW, STAT_VALUE_COL);
+               outstr(pp, "   ", 3);
+               showstat(pp);
+       }
+}
+
+message(pp, s)
+register PLAYER        *pp;
+char           *s;
+{
+       cgoto(pp, HEIGHT, 0);
+       outstr(pp, s, strlen(s));
+       ce(pp);
+}
+
+/*
+ * translate:
+ *     Turn a charcter into the right direction character if we are
+ *     looking at the current player.
+ */
+translate(ch)
+char   ch;
+{
+       switch (ch) {
+         case LEFTS:
+               return '<';
+         case RIGHT:
+               return '>';
+         case ABOVE:
+               return '^';
+         case BELOW:
+               return 'v';
+       }
+       return ch;
+}
diff --git a/usr/src/games/hunt/driver.c b/usr/src/games/hunt/driver.c
new file mode 100644 (file)
index 0000000..250aa16
--- /dev/null
@@ -0,0 +1,668 @@
+/*
+ *  Hunt
+ *  Copyright (c) 1985 Conrad C. Huang, Gregory S. Couch, Kenneth C.R.C. Arnold
+ *  San Francisco, California
+ *
+ *  Copyright (c) 1985 Regents of the University of California.
+ *  All rights reserved.  The Berkeley software License Agreement
+ *  specifies the terms and conditions for redistribution.
+ */
+
+# include      "hunt.h"
+# include      <signal.h>
+# include      <errno.h>
+# include      <sys/ioctl.h>
+# include      <sys/time.h>
+
+# ifndef pdp11
+# define       RN      (((Seed = Seed * 11109 + 13849) >> 16) & 0xffff)
+# else pdp11
+# define       RN      ((Seed = Seed * 11109 + 13849) & 0x7fff)
+# endif pdp11
+
+int    Seed = 0;
+
+# ifdef CONSTANT_MOVE
+static struct itimerval        Timing;
+# endif CONSTANT_MOVE
+
+SOCKET Daemon;
+# ifdef        INTERNET
+int    Test_socket;            /* test socket to answer datagrams */
+# define       DAEMON_SIZE     (sizeof Daemon)
+# else INTERNET
+# define       DAEMON_SIZE     (sizeof Daemon - 1)
+# endif        INTERNET
+
+/*
+ * main:
+ *     The main program.
+ */
+main()
+{
+       register PLAYER *pp;
+       register int    had_char;
+# ifdef INTERNET
+       register long   test_mask;
+       int             msg;
+       int             namelen;
+       SOCKET          test;
+# endif INTERNET
+# ifdef CONSTANT_MOVE
+       register int    enable_alarm, disable_alarm;
+# endif CONSTANT_MOVE
+       static long     read_fds;
+
+       init();
+       Sock_mask = (1 << Socket);
+# ifdef INTERNET
+       test_mask = (1 << Test_socket);
+# endif INTERNET
+
+# ifdef CONSTANT_MOVE
+       enable_alarm = sigblock(0);
+       disable_alarm = enable_alarm | (1 << (SIGALRM - 1));
+       (void) sigsetmask(disable_alarm);
+       (void) signal(SIGALRM, moveshots);
+# endif CONSTANT_MOVE
+
+       while (Nplayer > 0) {
+# ifdef CONSTANT_MOVE
+               (void) sigsetmask(enable_alarm);
+# endif CONSTANT_MOVE
+               read_fds = Fds_mask;
+               errno = 0;
+# ifndef OLDIPC
+               while (select(Num_fds, &read_fds, (int *) NULL,
+                   (int *) NULL, (struct timeval *) NULL) < 0)
+# else OLDIPC
+               while (select(20, &read_fds, NULL, 32767) < 0)
+# endif OLDIPC
+               {
+                       if (errno != EINTR)
+                               perror("select");
+                       if (Nplayer == 0)
+                               goto out;
+                       errno = 0;
+               }
+               Have_inp = read_fds;
+# ifdef CONSTANT_MOVE
+               (void) sigsetmask(disable_alarm);
+# endif CONSTANT_MOVE
+# ifdef INTERNET
+               if (read_fds & test_mask) {
+                       namelen = DAEMON_SIZE;
+# ifndef OLDIPC
+                       (void) recvfrom(Test_socket, (char *) &msg, sizeof msg,
+                               0, (struct sockaddr *) &test, &namelen);
+                       (void) sendto(Test_socket, (char *) &msg, sizeof msg,
+                               0, (struct sockaddr *) &test, DAEMON_SIZE);
+# else OLDIPC
+                       (void) receive(Test_socket, (struct sockaddr *) &test,
+                               (char *) &msg, sizeof msg);
+                       (void) send(Test_socket, (struct sockaddr *) &test,
+                               (char *) &msg, sizeof msg);
+# endif OLDIPC
+               }
+# endif INTERNET
+               for (;;) {
+                       had_char = FALSE;
+                       for (pp = Player; pp < End_player; pp++)
+                               if (havechar(pp)) {
+                                       execute(pp);
+                                       pp->p_nexec++;
+                                       had_char++;
+                               }
+# ifdef MONITOR
+                       for (pp = Monitor; pp < End_monitor; pp++)
+                               if (havechar(pp)) {
+                                       mon_execute(pp);
+                                       pp->p_nexec++;
+                                       had_char++;
+                               }
+# endif MONITOR
+                       if (!had_char)
+                               break;
+# ifdef CONSTANT_MOVE
+                       for (pp = Player; pp < End_player; pp++) {
+                               look(pp);
+                               sendcom(pp, REFRESH);
+                       }
+# ifdef MONITOR
+                       for (pp = Monitor; pp < End_monitor; pp++)
+                               sendcom(pp, REFRESH);
+# endif MONITOR
+# else CONSTANT_MOVE
+                       moveshots();
+# endif CONSTANT_MOVE
+                       for (pp = Player; pp < End_player; )
+                               if (pp->p_death[0] != '\0')
+                                       zap(pp, TRUE);
+                               else
+                                       pp++;
+# ifdef MONITOR
+                       for (pp = Monitor; pp < End_monitor; )
+                               if (pp->p_death[0] != '\0')
+                                       zap(pp, FALSE);
+                               else
+                                       pp++;
+# endif MONITOR
+               }
+               if (read_fds & Sock_mask)
+                       answer();
+               for (pp = Player; pp < End_player; pp++) {
+                       if (read_fds & pp->p_mask)
+                               sendcom(pp, READY, pp->p_nexec);
+                       pp->p_nexec = 0;
+                       (void) fflush(pp->p_output);
+               }
+# ifdef MONITOR
+               for (pp = Monitor; pp < End_monitor; pp++) {
+                       if (read_fds & pp->p_mask)
+                               sendcom(pp, READY, pp->p_nexec);
+                       pp->p_nexec = 0;
+                       (void) fflush(pp->p_output);
+               }
+# endif MONITOR
+       }
+out:
+# ifdef        CONSTANT_MOVE
+       bul_alarm(0);
+# endif        CONSTANT_MOVE
+
+# ifdef MONITOR
+       for (pp = Monitor; pp < End_monitor; )
+               zap(pp, FALSE);
+# endif MONITOR
+       cleanup(0);
+}
+
+/*
+ * init:
+ *     Initialize the global parameters.
+ */
+init()
+{
+       register int    i;
+# ifdef        INTERNET
+       SOCKET          test_port;
+       auto int        msg;
+# endif        INTERNET
+
+# ifndef DEBUG
+       (void) ioctl(fileno(stdout), TIOCNOTTY, NULL);
+       (void) setpgrp(getpid(), getpid());
+       (void) signal(SIGHUP, SIG_IGN);
+       (void) signal(SIGINT, SIG_IGN);
+       (void) signal(SIGQUIT, SIG_IGN);
+       (void) signal(SIGTERM, cleanup);
+# endif DEBUG
+
+       (void) chdir("/usr/tmp");       /* just in case it core dumps */
+       (void) signal(SIGPIPE, SIG_IGN);
+
+# ifdef        INTERNET
+       Daemon.sin_family = SOCK_FAMILY;
+# ifdef OLD
+       if (gethostname(local_name, sizeof local_name) < 0) {
+               perror("gethostname");
+               exit(1);
+       }
+       if ((hp = gethostbyname(local_name)) == NULL) {
+               fprintf(stderr, "Unknown host %s\n", local_name);
+               exit(1);
+       }
+       bcopy(hp->h_addr, &(Daemon.sin_addr.s_addr), hp->h_length);
+# else
+       Daemon.sin_addr.s_addr = INADDR_ANY;
+# endif OLD
+       Daemon.sin_port = htons(Sock_port);
+# else INTERNET
+       Daemon.sun_family = SOCK_FAMILY;
+       (void) strcpy(Daemon.sun_path, Sock_name);
+# endif INTERNET
+
+# ifndef OLDIPC
+       Socket = socket(SOCK_FAMILY, SOCK_STREAM, 0);
+# else OLDIPC
+       Socket = socket(SOCK_STREAM, 0, (struct sockaddr *) &Daemon,
+               SO_ACCEPTCONN);
+# endif OLDIPC
+# if defined(INTERNET) && !defined(OLDIPC)
+       if (setsockopt(Socket, SOL_SOCKET, SO_USELOOPBACK, &msg, sizeof msg)<0)
+               perror("setsockopt loopback");
+# endif INTERNET
+# ifndef OLDIPC
+       if (bind(Socket, (struct sockaddr *) &Daemon, DAEMON_SIZE) < 0) {
+               if (errno == EADDRINUSE)
+                       exit(0);
+               else {
+                       perror("bind");
+                       cleanup(1);
+               }
+       }
+       (void) listen(Socket, 5);
+# endif OLDIPC
+       Fds_mask = (1 << Socket);
+       Num_fds = Socket + 1;
+
+# ifdef INTERNET
+       test_port = Daemon;
+       test_port.sin_port = htons(Test_port);
+
+# ifndef OLDIPC
+       Test_socket = socket(SOCK_FAMILY, SOCK_DGRAM, 0);
+       if (bind(Test_socket, (struct sockaddr *) &test_port,
+           DAEMON_SIZE) < 0) {
+               perror("bind");
+               exit(1);
+       }
+       (void) listen(Test_socket, 5);
+# else OLDIPC
+       Test_socket = socket(SOCK_DGRAM, 0, (struct sockaddr *) &test_port, 0);
+# endif OLDIPC
+       Fds_mask |= (1 << Test_socket);
+       if (Test_socket > Socket)
+               Num_fds = Test_socket + 1;
+# endif        INTERNET
+
+       Seed = getpid() + time((time_t *) NULL);
+       makemaze();
+
+       for (i = 0; i < NASCII; i++)
+               See_over[i] = TRUE;
+       See_over[DOOR] = FALSE;
+       See_over[WALL1] = FALSE;
+       See_over[WALL2] = FALSE;
+       See_over[WALL3] = FALSE;
+# ifdef REFLECT
+       See_over[WALL4] = FALSE;
+       See_over[WALL5] = FALSE;
+# endif REFLECT
+
+# ifdef CONSTANT_MOVE
+       getitimer(ITIMER_REAL, &Timing);
+       Timing.it_interval.tv_sec = 0;
+       Timing.it_interval.tv_usec = 500;
+       Timing.it_value.tv_sec = 0;
+       Timing.it_value.tv_usec = 0;
+       setitimer(ITIMER_REAL, &Timing, NULL);
+# endif CONSTANT_MOVE
+
+       answer();
+}
+
+# ifdef CONSTANT_MOVE
+/*
+ * bul_alarm:
+ *     Set up the alarm for the bullets
+ */
+bul_alarm(val)
+int    val;
+{
+       Timing.it_value.tv_usec = val * Timing.it_interval.tv_usec;
+       setitimer(ITIMER_REAL, &Timing, NULL);
+}
+# endif CONSTANT_MOVE
+
+/*
+ * checkdam:
+ *     Check the damage to the given player, and see if s/he is killed
+ */
+checkdam(ouch, gotcha, credit, amt, shot_type)
+register PLAYER        *ouch, *gotcha;
+register IDENT *credit;
+int            amt;
+char           shot_type;
+{
+       register char   *cp;
+
+       if (ouch->p_death[0] != '\0')
+               return;
+       if (rand_num(100) < 5) {
+               message(ouch, "Missed you by a hair");
+               if (gotcha != NULL)
+                       message(gotcha, "Missed him");
+               return;
+       }
+       ouch->p_damage += amt;
+       if (ouch->p_damage <= ouch->p_damcap) {
+               (void) sprintf(Buf, "%2d", ouch->p_damage);
+               cgoto(ouch, STAT_DAM_ROW, STAT_VALUE_COL);
+               outstr(ouch, Buf, 2);
+               return;
+       }
+
+       /* Someone DIED */
+       switch (shot_type) {
+         default:
+               cp = "Killed";
+               break;
+# ifdef FLY
+         case FALL:
+               cp = "Killed on impact";
+               break;
+# endif FLY
+         case KNIFE:
+               cp = "Stabbed to death";
+               break;
+         case SHOT:
+               cp = "Shot to death";
+               break;
+         case GRENADE:
+         case SATCHEL:
+         case BOMB:
+               cp = "Bombed";
+               break;
+         case MINE:
+         case GMINE:
+               cp = "Blown apart";
+               break;
+# ifdef        OOZE
+         case SLIME:
+               cp = "Slimed";
+               break;
+# endif OOZE
+# ifdef        VOLCANO
+         case LAVA:
+               cp = "Baked";
+               break;
+# endif VOLCANO
+       }
+       if (credit == NULL) {
+               (void) sprintf(ouch->p_death, "| %s by %s |", cp,
+                       (shot_type == MINE || shot_type == GMINE) ?
+                       "a mine" : "act of God");
+               return;
+       }
+
+       (void) sprintf(ouch->p_death, "| %s by %s |", cp, credit->i_name);
+
+       credit->i_kills++;
+       credit->i_score = credit->i_kills / (double) credit->i_entries;
+       if (gotcha == NULL)
+               return;
+       gotcha->p_damcap += STABDAM;
+       gotcha->p_damage -= STABDAM;
+       if (gotcha->p_damage < 0)
+               gotcha->p_damage = 0;
+       (void) sprintf(Buf, "%2d/%2d", gotcha->p_damage, gotcha->p_damcap);
+       cgoto(gotcha, STAT_DAM_ROW, STAT_VALUE_COL);
+       outstr(gotcha, Buf, 5);
+       (void) sprintf(Buf, "%3d", (gotcha->p_damcap - MAXDAM) / 2);
+       cgoto(gotcha, STAT_KILL_ROW, STAT_VALUE_COL);
+       outstr(gotcha, Buf, 3);
+       (void) sprintf(Buf, "%5.2f", gotcha->p_ident->i_score);
+       for (ouch = Player; ouch < End_player; ouch++) {
+               cgoto(ouch, STAT_PLAY_ROW + 1 + (gotcha - Player),
+                       STAT_NAME_COL);
+               outstr(ouch, Buf, 5);
+       }
+}
+
+/*
+ * zap:
+ *     Kill off a player and take him out of the game.
+ */
+zap(pp, was_player)
+register PLAYER        *pp;
+FLAG           was_player;
+{
+       register int    i, len;
+       register BULLET *bp;
+       register PLAYER *np;
+       register int    x, y;
+       int             savefd, savemask;
+
+       if (was_player) {
+               drawplayer(pp, FALSE);
+               Nplayer--;
+       }
+
+       len = strlen(pp->p_death);      /* Display the cause of death */
+       x = (WIDTH - len) / 2;
+       cgoto(pp, HEIGHT / 2, x);
+       outstr(pp, pp->p_death, len);
+       for (i = 1; i < len; i++)
+               pp->p_death[i] = '-';
+       pp->p_death[0] = '+';
+       pp->p_death[len - 1] = '+';
+       cgoto(pp, HEIGHT / 2 - 1, x);
+       outstr(pp, pp->p_death, len);
+       cgoto(pp, HEIGHT / 2 + 1, x);
+       outstr(pp, pp->p_death, len);
+       cgoto(pp, HEIGHT, 0);
+
+       if (Nplayer == 0) {
+# ifdef CONSTANT_MOVE
+               bul_alarm(0);
+# endif CONSTANT_MOVE
+               cleanup(0);
+               /* NOTREACHED */
+       }
+
+       savefd = pp->p_fd;
+       savemask = pp->p_mask;
+
+# ifdef MONITOR
+       if (was_player) {
+# endif MONITOR
+               for (bp = Bullets; bp != NULL; bp = bp->b_next) {
+                       if (bp->b_owner == pp)
+                               bp->b_owner = NULL;
+                       if (bp->b_x == pp->p_x && bp->b_y == pp->p_y)
+                               bp->b_over = SPACE;
+               }
+
+               i = rand_num(pp->p_ammo);
+               if (i == pp->p_ammo - 1) {
+                       x = pp->p_ammo;
+                       len = SLIME;
+               }
+               else if (i >= BOMBREQ) {
+                       x = BOMBREQ;
+                       len = BOMB;
+               }
+               else if (i >= SSLIMEREQ) {
+                       x = SSLIMEREQ;
+                       len = SLIME;
+               }
+               else if (i >= SATREQ) {
+                       x = SATREQ;
+                       len = SATCHEL;
+               }
+               else if (i >= SLIMEREQ) {
+                       x = SLIMEREQ;
+                       len = SLIME;
+               }
+               else if (i >= GRENREQ) {
+                       x = GRENREQ;
+                       len = GRENADE;
+               }
+               else
+                       x = 0;
+               if (x > 0) {
+                       add_shot(len, pp->p_y, pp->p_x, pp->p_face, x,
+                               (PLAYER *) NULL, TRUE, SPACE);
+                       (void) sprintf(Buf, "%s detonated.",
+                               pp->p_ident->i_name);
+                       for (np = Player; np < End_player; np++)
+                               message(np, Buf);
+# ifdef MONITOR
+                       for (np = Monitor; np < End_monitor; np++)
+                               message(np, Buf);
+# endif MONITOR
+               }
+
+# ifdef VOLCANO
+               volcano += pp->p_ammo - x;
+               if (rand_num(100) < volcano / 50) {
+                       do {
+                               x = rand_num(WIDTH / 2) + WIDTH / 4;
+                               y = rand_num(HEIGHT / 2) + HEIGHT / 4;
+                       } while (Maze[y][x] != SPACE);
+                       add_shot(LAVA, y, x, LEFTS, volcano,
+                               (PLAYER *) NULL, TRUE, SPACE);
+                       for (np = Player; np < End_player; np++)
+                               message(np, "Volcano eruption.");
+                       volcano = 0;
+               }
+# endif VOLCANO
+
+               sendcom(pp, ENDWIN);
+               (void) fclose(pp->p_output);
+
+               End_player--;
+               if (pp != End_player) {
+                       bcopy((char *) End_player, (char *) pp,
+                               sizeof (PLAYER));
+                       (void) sprintf(Buf, "%5.2f%c%-10.10s",
+                               pp->p_ident->i_score, stat_char(pp),
+                               pp->p_ident->i_name);
+                       i = STAT_PLAY_ROW + 1 + (pp - Player);
+                       for (np = Player; np < End_player; np++) {
+                               cgoto(np, i, STAT_NAME_COL);
+                               outstr(np, Buf, STAT_NAME_LEN);
+                       }
+# ifdef MONITOR
+                       for (np = Monitor; np < End_monitor; np++) {
+                               cgoto(np, i, STAT_NAME_COL);
+                               outstr(np, Buf, STAT_NAME_LEN);
+                       }
+# endif MONITOR
+               }
+
+               /* Erase the last player */
+               i = STAT_PLAY_ROW + 1 + Nplayer;
+               for (np = Player; np < End_player; np++) {
+                       cgoto(np, i, STAT_NAME_COL);
+                       ce(np);
+               }
+# ifdef MONITOR
+               for (np = Monitor; np < End_monitor; np++) {
+                       cgoto(np, i, STAT_NAME_COL);
+                       ce(np);
+               }
+       }
+       else {
+               sendcom(pp, ENDWIN);
+               (void) putc(LAST_PLAYER, pp->p_output);
+               (void) fclose(pp->p_output);
+
+               End_monitor--;
+               if (pp != End_monitor) {
+                       bcopy((char *) End_monitor, (char *) pp,
+                               sizeof (PLAYER));
+                       (void) sprintf(Buf, "%5.5s %-10.10s", " ",
+                               pp->p_ident->i_name);
+                       i = STAT_MON_ROW + 1 + (pp - Player);
+                       for (np = Player; np < End_player; np++) {
+                               cgoto(np, i, STAT_NAME_COL);
+                               outstr(np, Buf, STAT_NAME_LEN);
+                       }
+                       for (np = Monitor; np < End_monitor; np++) {
+                               cgoto(np, i, STAT_NAME_COL);
+                               outstr(np, Buf, STAT_NAME_LEN);
+                       }
+               }
+
+               /* Erase the last monitor */
+               i = STAT_MON_ROW + 1 + (End_monitor - Monitor);
+               for (np = Player; np < End_player; np++) {
+                       cgoto(np, i, STAT_NAME_COL);
+                       ce(np);
+               }
+               for (np = Monitor; np < End_monitor; np++) {
+                       cgoto(np, i, STAT_NAME_COL);
+                       ce(np);
+               }
+
+       }
+# endif MONITOR
+
+       Fds_mask &= ~savemask;
+       if (Num_fds == savefd + 1) {
+               Num_fds = Socket;
+# ifdef INTERNET
+               if (Test_socket > Socket)
+                       Num_fds = Test_socket;
+# endif INTERNET
+               for (np = Player; np < End_player; np++)
+                       if (np->p_fd > Num_fds)
+                               Num_fds = np->p_fd;
+# ifdef MONITOR
+               for (np = Monitor; np < End_monitor; np++)
+                       if (np->p_fd > Num_fds)
+                               Num_fds = np->p_fd;
+# endif MONITOR
+               Num_fds++;
+       }
+}
+
+/*
+ * rand_num:
+ *     Return a random number in a given range.
+ */
+rand_num(range)
+int    range;
+{
+       return (range == 0 ? 0 : RN % range);
+}
+
+/*
+ * havechar:
+ *     Check to see if we have any characters in the input queue; if
+ *     we do, read them, stash them away, and return TRUE; else return
+ *     FALSE.
+ */
+havechar(pp)
+register PLAYER        *pp;
+{
+       extern int      errno;
+
+       if (pp->p_ncount < pp->p_nchar)
+               return TRUE;
+       if (!(Have_inp & pp->p_mask))
+               return FALSE;
+       Have_inp &= ~pp->p_mask;
+check_again:
+       errno = 0;
+       if ((pp->p_nchar = read(pp->p_fd, pp->p_cbuf, sizeof pp->p_cbuf)) <= 0)
+       {
+               if (errno == EINTR)
+                       goto check_again;
+               pp->p_cbuf[0] = 'q';
+       }
+       pp->p_ncount = 0;
+       return TRUE;
+}
+
+/*
+ * cleanup:
+ *     Exit with the given value, cleaning up any droppings lying around
+ */
+cleanup(eval)
+int    eval;
+{
+       register PLAYER *pp;
+
+       for (pp = Player; pp < End_player; pp++) {
+               cgoto(pp, HEIGHT, 0);
+               sendcom(pp, ENDWIN);
+               (void) putc(LAST_PLAYER, pp->p_output);
+               (void) fclose(pp->p_output);
+       }
+# ifdef MONITOR
+       for (pp = Monitor; pp < End_monitor; pp++) {
+               cgoto(pp, HEIGHT, 0);
+               sendcom(pp, ENDWIN);
+               (void) putc(LAST_PLAYER, pp->p_output);
+               (void) fclose(pp->p_output);
+       }
+# endif MONITOR
+       (void) close(Socket);
+# ifdef AF_UNIX_HACK
+       (void) unlink(Sock_name);
+# endif AF_UNIX_HACK
+       exit(eval);
+}
diff --git a/usr/src/games/hunt/expl.c b/usr/src/games/hunt/expl.c
new file mode 100644 (file)
index 0000000..0f579ee
--- /dev/null
@@ -0,0 +1,198 @@
+/*
+ *  Hunt
+ *  Copyright (c) 1985 Conrad C. Huang, Gregory S. Couch, Kenneth C.R.C. Arnold
+ *  San Francisco, California
+ *
+ *  Copyright (c) 1985 Regents of the University of California.
+ *  All rights reserved.  The Berkeley software License Agreement
+ *  specifies the terms and conditions for redistribution.
+ */
+
+# include      "hunt.h"
+
+/*
+ * showexpl:
+ *     Show the explosions as they currently are
+ */
+showexpl(y, x, type)
+register int   y, x;
+char           type;
+{
+       register PLAYER *pp;
+       register EXPL   *ep;
+
+       if (y < 0 || y >= HEIGHT)
+               return;
+       if (x < 0 || x >= WIDTH)
+               return;
+       ep = (EXPL *) malloc(sizeof (EXPL));    /* NOSTRICT */
+       ep->e_y = y;
+       ep->e_x = x;
+       ep->e_char = type;
+       ep->e_next = Expl[0];
+       Expl[0] = ep;
+       for (pp = Player; pp < End_player; pp++) {
+               if (pp->p_maze[y][x] == type)
+                       continue;
+               pp->p_maze[y][x] = type;
+               cgoto(pp, y, x);
+               outch(pp, type);
+       }
+# ifdef MONITOR
+       for (pp = Monitor; pp < End_monitor; pp++) {
+               if (pp->p_maze[y][x] == type)
+                       continue;
+               pp->p_maze[y][x] = type;
+               cgoto(pp, y, x);
+               outch(pp, type);
+       }
+# endif MONITOR
+       switch (Maze[y][x]) {
+         case WALL1:
+         case WALL2:
+         case WALL3:
+# ifdef RANDOM
+         case DOOR:
+# endif RANDOM
+# ifdef REFLECT
+         case WALL4:
+         case WALL5:
+# endif REFLECT
+               if (y >= UBOUND && y < DBOUND && x >= LBOUND && x < RBOUND)
+                       remove_wall(y, x);
+               break;
+       }
+}
+
+/*
+ * rollexpl:
+ *     Roll the explosions over, so the next one in the list is at the
+ *     top
+ */
+rollexpl()
+{
+       register EXPL   *ep;
+       register PLAYER *pp;
+       register int    y, x;
+       register char   c;
+       register EXPL   *nextep;
+
+       for (ep = Expl[EXPLEN - 1]; ep != NULL; ep = nextep) {
+               nextep = ep->e_next;
+               y = ep->e_y;
+               x = ep->e_x;
+               if (y < UBOUND || y >= DBOUND || x < LBOUND || x >= RBOUND)
+                       c = Maze[y][x];
+               else
+                       c = SPACE;
+               for (pp = Player; pp < End_player; pp++)
+                       if (pp->p_maze[y][x] == ep->e_char) {
+                               pp->p_maze[y][x] = c;
+                               cgoto(pp, y, x);
+                               outch(pp, c);
+                       }
+# ifdef MONITOR
+               for (pp = Monitor; pp < End_monitor; pp++)
+                       check(pp, y, x);
+# endif MONITOR
+               free((char *) ep);
+       }
+       for (x = EXPLEN - 1; x > 0; x--)
+               Expl[x] = Expl[x - 1];
+       Expl[0] = NULL;
+}
+
+/* There's about 700 walls in the initial maze.  So we pick a number
+ * that keeps the maze relatively full. */
+# define MAXREMOVE     40
+
+static REGEN   removed[MAXREMOVE];
+static REGEN   *rem_index = removed;
+
+/*
+ * remove_wall - add a location where the wall was blown away.
+ *              if there is no space left over, put the a wall at
+ *              the location currently pointed at.
+ */
+remove_wall(y, x)
+int    y, x;
+{
+       register REGEN  *r;
+# if defined(MONITOR) || defined(FLY)
+       register PLAYER *pp;
+# endif MONITOR || FLY
+# ifdef        FLY
+       register char   save_char;
+# endif        FLY
+
+       r = rem_index;
+       while (r->r_y != 0) {
+# ifdef FLY
+               switch (Maze[r->r_y][r->r_x]) {
+                 case SPACE:
+                 case LEFTS:
+                 case RIGHT:
+                 case ABOVE:
+                 case BELOW:
+                 case FLYER:
+                       save_char = Maze[r->r_y][r->r_x];
+                       goto found;
+               }
+# else FLY
+               if (Maze[r->r_y][r->r_x] == SPACE)
+                       break;
+# endif FLY
+               if (++r >= &removed[MAXREMOVE])
+                       r = removed;
+       }
+
+found:
+       if (r->r_y != 0) {
+               /* Slot being used, put back this wall */
+# ifdef FLY
+               if (save_char == SPACE)
+                       Maze[r->r_y][r->r_x] = Orig_maze[r->r_y][r->r_x];
+               else {
+                       pp = play_at(r->r_y, r->r_x);
+                       if (pp->p_flying >= 0)
+                               pp->p_flying += rand_num(10);
+                       else {
+                               pp->p_flying = rand_num(20);
+                               pp->p_flyx = 2 * rand_num(6) - 5;
+                               pp->p_flyy = 2 * rand_num(6) - 5;
+                       }
+                       pp->p_over = Orig_maze[r->r_y][r->r_x];
+                       pp->p_face = FLYER;
+                       Maze[r->r_y][r->r_x] = FLYER;
+                       showexpl(r->r_y, r->r_x, FLYER);
+               }
+# else FLY
+               Maze[r->r_y][r->r_x] = Orig_maze[r->r_y][r->r_x];
+# endif FLY
+# ifdef RANDOM
+               if (rand_num(100) == 0)
+                       Maze[r->r_y][r->r_x] = DOOR;
+# endif RANDOM
+# ifdef REFLECT
+               if (rand_num(100) == 0)         /* one percent of the time */
+                       Maze[r->r_y][r->r_x] = WALL4;
+# endif REFLECT
+# ifdef MONITOR
+               for (pp = Monitor; pp < End_monitor; pp++)
+                       check(pp, r->r_y, r->r_x);
+# endif MONITOR
+       }
+
+       r->r_y = y;
+       r->r_x = x;
+       if (++r >= &removed[MAXREMOVE])
+               rem_index = removed;
+       else
+               rem_index = r;
+
+       Maze[y][x] = SPACE;
+# ifdef MONITOR
+       for (pp = Monitor; pp < End_monitor; pp++)
+               check(pp, y, x);
+# endif MONITOR
+}
diff --git a/usr/src/games/hunt/hunt.c b/usr/src/games/hunt/hunt.c
new file mode 100644 (file)
index 0000000..d8e050b
--- /dev/null
@@ -0,0 +1,717 @@
+/*
+ *  Hunt
+ *  Copyright (c) 1985 Conrad C. Huang, Gregory S. Couch, Kenneth C.R.C. Arnold
+ *  San Francisco, California
+ *
+ *  Copyright (c) 1985 Regents of the University of California.
+ *  All rights reserved.  The Berkeley software License Agreement
+ *  specifies the terms and conditions for redistribution.
+ */
+
+# include      <errno.h>
+# include      <curses.h>
+# include      "hunt.h"
+# include      <signal.h>
+# include      <ctype.h>
+# include      <sys/stat.h>
+
+FLAG   Last_player = FALSE;
+# ifdef MONITOR
+FLAG   Am_monitor = FALSE;
+# endif MONITOR
+FLAG   Query_driver = FALSE;
+
+char   Buf[BUFSIZ];
+
+int    Master_pid;
+int    Socket;
+# ifdef INTERNET
+char   *Sock_host;
+# endif INTERNET
+
+SOCKET Daemon;
+# ifdef        INTERNET
+# define       DAEMON_SIZE     (sizeof Daemon)
+# else INTERNET
+# define       DAEMON_SIZE     (sizeof Daemon - 1)
+# endif        INTERNET
+
+char   map_key[256];                   /* what to map keys to */
+
+static char    name[NAMELEN];
+
+extern int     cur_row, cur_col, _putchar();
+extern char    *tgoto();
+
+/*
+ * main:
+ *     Main program for local process
+ */
+main(ac, av)
+int    ac;
+char   **av;
+{
+       char            *term;
+       extern int      errno;
+       extern int      Otto_mode;
+       int             dumpit(), intr(), sigterm(), sigemt(), tstp();
+
+       for (ac--, av++; ac > 0 && av[0][0] == '-'; ac--, av++) {
+               switch (av[0][1]) {
+
+               case 'l':       /* rsh compatibility */
+               case 'n':
+                       if (ac <= 1)
+                               goto usage;
+                       ac--, av++;
+                       (void) strcpy(name, av[0]);
+                       break;
+               case 'o':
+# ifndef OTTO
+                       fputs("The -o flag is reserved for future use.\n",
+                               stderr);
+                       goto usage;
+# else OTTO
+                       Otto_mode = TRUE;
+                       break;
+# endif OTTO
+# ifdef MONITOR
+               case 'm':
+                       Am_monitor = TRUE;
+                       break;
+# endif MONITOR
+# ifdef INTERNET
+               case 'q':       /* query whether hunt is running */
+                       Query_driver = TRUE;
+                       break;
+               case 'h':
+                       if (ac <= 1)
+                               goto usage;
+                       ac--, av++;
+                       Sock_host = av[0];
+                       break;
+# endif INTERNET
+               default:
+               usage:
+# ifdef INTERNET
+#  ifdef MONITOR
+#   define     USAGE   "usage: hunt [-q] [-n name] [-h host] [-m]\n"
+#  else MONITOR
+#   define     USAGE   "usage: hunt [-q] [-n name] [-h host]\n"
+#  endif MONITOR
+# else INTERNET
+#  ifdef MONITOR
+#   define     USAGE   "usage: hunt [-n name] [-m]\n"
+#  else MONITOR
+#   define     USAGE   "usage: hunt [-n name]\n"
+#  endif MONITOR
+# endif INTERNET
+                       fputs(USAGE, stderr);
+# undef USAGE
+                       exit(1);
+               }
+       }
+# ifdef INTERNET
+       if (ac > 1)
+               goto usage;
+       else if (ac > 0)
+               Sock_host = av[0];
+# else INTERNET
+       if (ac > 0)
+               goto usage;
+# endif INTERNET       
+
+# ifdef INTERNET
+       if (Query_driver) {
+               find_driver(FALSE);
+               if (Daemon.sin_port != 0) {
+                       struct  hostent *hp;
+
+                       hp = gethostbyaddr(&Daemon.sin_addr,
+                               sizeof Daemon.sin_addr, AF_INET);
+                       fprintf(stderr, "HUNT!! found on %s\n", hp != NULL
+                               ? hp->h_name : inet_ntoa(Daemon.sin_addr));
+               }
+               exit(Daemon.sin_port == 0);
+       }
+# endif INTERNET
+# ifdef OTTO
+       if (Otto_mode)
+               (void) strcpy(name, "otto");
+       else
+# endif OTTO
+       env_init();
+
+       (void) fflush(stdout);
+       if (!isatty(0) || (term = getenv("TERM")) == NULL) {
+               fprintf(stderr, "no terminal type\n");
+               exit(1);
+       }
+       _tty_ch = 0;
+       gettmode();
+       setterm(term);
+       noecho();
+       cbreak();
+       _puts(TI);
+       _puts(VS);
+       clear_screen();
+       (void) signal(SIGINT, intr);
+       (void) signal(SIGTERM, sigterm);
+       (void) signal(SIGEMT, sigemt);
+       (void) signal(SIGQUIT, dumpit);
+       (void) signal(SIGPIPE, SIG_IGN);
+       (void) signal(SIGTSTP, tstp);
+
+       do {
+# ifdef        INTERNET
+               find_driver(TRUE);
+
+               do {
+                       int     msg;
+
+# ifndef OLDIPC
+                       Socket = socket(SOCK_FAMILY, SOCK_STREAM, 0);
+# else OLDIPC
+                       Socket = socket(SOCK_STREAM, 0, 0, 0);
+# endif OLDIPC
+                       if (Socket < 0) {
+                               perror("socket");
+                               exit(1);
+                       }
+# ifndef OLDIPC
+                       msg = 1;
+                       if (setsockopt(Socket, SOL_SOCKET, SO_USELOOPBACK,
+                           &msg, sizeof msg) < 0)
+                               perror("setsockopt loopback");
+# endif OLDIPC
+                       errno = 0;
+                       if (connect(Socket, (struct sockaddr *) &Daemon,
+                           DAEMON_SIZE) < 0) {
+                               if (errno != ECONNREFUSED) {
+                                       perror("connect");
+                                       leave(1, "connect");
+                               }
+                       }
+                       else
+                               break;
+                       sleep(1);
+               } while (close(Socket) == 0);
+# else INTERNET
+               /*
+                * set up a socket
+                */
+
+               if ((Socket = socket(SOCK_FAMILY, SOCK_STREAM, 0)) < 0) {
+                       perror("socket");
+                       exit(1);
+               }
+
+               /*
+                * attempt to connect the socket to a name; if it fails that
+                * usually means that the driver isn't running, so we start
+                * up the driver.
+                */
+
+               Daemon.sun_family = SOCK_FAMILY;
+               (void) strcpy(Daemon.sun_path, Sock_name);
+               if (connect(Socket, &Daemon, DAEMON_SIZE) < 0) {
+                       if (errno != ENOENT) {
+                               perror("connect");
+                               leave(1, "connect2");
+                       }
+                       start_driver();
+
+                       do {
+                               (void) close(Socket);
+                               if ((Socket = socket(SOCK_FAMILY, SOCK_STREAM, 0)) < 0) {
+                                       perror("socket");
+                                       exit(1);
+                               }
+                               sleep(2);
+                       } while (connect(Socket, &Daemon, DAEMON_SIZE) < 0);
+               }
+# endif INTERNET
+
+               do_connect(name);
+               playit();
+       } while (!quit());
+       leave(0, NULL);
+       /* NOTREACHED */
+}
+
+# ifdef INTERNET
+# ifdef BROADCAST
+broadcast_vec(s, vector)
+       int                     s;              /* socket */
+       struct  sockaddr        **vector;
+{
+       char                    if_buf[BUFSIZ];
+       struct  ifconf          ifc;
+       struct  ifreq           *ifr;
+       int                     n;
+       int                     vec_cnt;
+
+       *vector = NULL;
+       ifc.ifc_len = sizeof if_buf;
+       ifc.ifc_buf = if_buf;
+       if (ioctl(s, SIOCGIFCONF, (char *) &ifc) < 0)
+               return 0;
+       vec_cnt = 0;
+       n = ifc.ifc_len / sizeof (struct ifreq);
+       *vector = (struct sockaddr *) malloc(n * sizeof (struct sockaddr));
+       for (ifr = ifc.ifc_req; n > 0; n--, ifr++)
+               if (ioctl(s, SIOCGIFBRDADDR, ifr) >= 0)
+                       bcopy(&ifr->ifr_addr, &(*vector)[vec_cnt++],
+                                               sizeof (struct sockaddr));
+       return vec_cnt;
+}
+# endif BROADCAST
+
+find_driver(do_startup)
+FLAG   do_startup;
+{
+       int                     msg;
+       static SOCKET           test;
+       int                     test_socket;
+       int                     namelen;
+       char                    local_name[80];
+       static                  initial = TRUE;
+       static struct in_addr   local_address;
+       register struct hostent *hp;
+       int                     (*oldsigalrm)(), sigalrm();
+       extern int              errno;
+# ifdef BROADCAST
+       static  int             brdc;
+       static  SOCKET          *brdv;
+       int                     i;
+# endif BROADCAST
+
+       if (Sock_host != NULL) {
+               if (!initial)
+                       return;         /* Daemon address already valid */
+               initial = FALSE;
+               if ((hp = gethostbyname(Sock_host)) == NULL) {
+                       leave(1, "Unknown host");
+                       /* NOTREACHED */
+               }
+               Daemon.sin_family = SOCK_FAMILY;
+               Daemon.sin_port = htons(Sock_port);
+               Daemon.sin_addr = *((struct in_addr *) hp->h_addr);
+               if (!Query_driver)
+                       return;
+       }
+
+
+       if (initial) {                  /* do one time initialization */
+# ifndef BROADCAST
+               sethostent(1);          /* don't bother to close host file */
+# endif BROADCAST
+               if (gethostname(local_name, sizeof local_name) < 0) {
+                       leave(1, "Sorry, I have no name.");
+                       /* NOTREACHED */
+               }
+               if ((hp = gethostbyname(local_name)) == NULL) {
+                       leave(1, "Can't find myself.");
+                       /* NOTREACHED */
+               }
+               local_address = * ((struct in_addr *) hp->h_addr);
+
+               test.sin_family = SOCK_FAMILY;
+               test.sin_addr = local_address;
+               test.sin_port = htons(Test_port);
+       }
+
+# ifndef OLDIPC
+       test_socket = socket(SOCK_FAMILY, SOCK_DGRAM, 0);
+# else OLDIPC
+       test_socket = socket(SOCK_DGRAM, 0, 0, 0);
+# endif OLCIPC
+       if (test_socket < 0) {
+               perror("socket");
+               leave(1, "socket system call failed");
+               /* NOTREACHED */
+       }
+
+       msg = 1;
+       if (Query_driver && Sock_host != NULL) {
+               test.sin_family = SOCK_FAMILY;
+               test.sin_addr = Daemon.sin_addr;
+               test.sin_port = htons(Test_port);
+# ifndef OLDIPC
+               (void) sendto(test_socket, (char *) &msg, sizeof msg, 0,
+                   (struct sockaddr *) &test, DAEMON_SIZE);
+# else OLDIPC
+               (void) send(test_socket, (struct sockaddr *) &test,
+                       (char *) &msg, sizeof msg);
+# endif OLDIPC
+               goto get_response;
+       }
+
+       if (!initial) {
+               /* favor host of previous session by broadcasting to it first */
+               test.sin_addr = Daemon.sin_addr;
+               test.sin_port = htons(Test_port);
+               (void) sendto(test_socket, (char *) &msg, sizeof msg, 0,
+                   (struct sockaddr *) &test, DAEMON_SIZE);
+       }
+
+
+# ifdef BROADCAST
+       if (initial)
+               brdc = broadcast_vec(test_socket, &brdv);
+
+       if (brdc <= 0) {
+               Daemon.sin_family = SOCK_FAMILY;
+               Daemon.sin_addr = local_address;
+               Daemon.sin_port = htons(Sock_port);
+               initial = FALSE;
+               return;
+       }
+
+       if (setsockopt(test_socket, SOL_SOCKET, SO_BROADCAST,
+           (int) &msg, sizeof msg) < 0) {
+               perror("setsockopt broadcast");
+               leave(1, "setsockopt broadcast");
+               /* NOTREACHED */
+       }
+
+       /* send broadcast packets on all interfaces */
+       for (i = 0; i < brdc; i++) {
+               bcopy(&brdv[i], &test, sizeof (SOCKET));
+               test.sin_port = htons(Test_port);
+               if (sendto(test_socket, (char *) &msg, sizeof msg, 0,
+                   (struct sockaddr *) &test, DAEMON_SIZE) < 0) {
+                       perror("sendto");
+                       leave(1, "sendto");
+                       /* NOTREACHED */
+               }
+       }
+# else BROADCAST
+       /* loop thru all hosts on local net and send msg to them. */
+       sethostent(0);          /* rewind host file */
+       while (hp = gethostent()) {
+               if (inet_netof(test.sin_addr)
+               == inet_netof(* ((struct in_addr *) hp->h_addr))) {
+                       test.sin_addr = * ((struct in_addr *) hp->h_addr);
+# ifndef OLDIPC
+                       (void) sendto(test_socket, (char *) &msg, sizeof msg, 0,
+                           (struct sockaddr *) &test, DAEMON_SIZE);
+# else OLDIPC
+                       (void) send(test_socket, (struct sockaddr *) &test,
+                               (char *) &msg, sizeof msg);
+# endif OLDIPC
+               }
+       }
+# endif BROADCAST
+
+get_response:
+       namelen = DAEMON_SIZE;
+       oldsigalrm = signal(SIGALRM, sigalrm);
+       errno = 0;
+       (void) alarm(1);
+# ifndef OLDIPC
+       if (recvfrom(test_socket, (char *) &msg, sizeof msg, 0,
+           (struct sockaddr *) &Daemon, &namelen) < 0)
+# else OLDIPC
+       if (receive(test_socket, (struct sockaddr *) &Daemon, &msg,
+           sizeof msg) < 0)
+# endif OLDIPC
+       {
+               if (errno != EINTR) {
+                       perror("recvfrom");
+                       leave(1, "recvfrom");
+                       /* NOTREACHED */
+               }
+               (void) alarm(0);
+               (void) signal(SIGALRM, oldsigalrm);
+               Daemon.sin_family = SOCK_FAMILY;
+               Daemon.sin_port = htons(Sock_port);
+               Daemon.sin_addr = local_address;
+               if (!do_startup)
+                       Daemon.sin_port = 0;
+               else
+                       start_driver();
+       }
+       else {
+               (void) alarm(0);
+               (void) signal(SIGALRM, oldsigalrm);
+               Daemon.sin_port = htons(Sock_port);
+       }
+       (void) close(test_socket);
+       initial = FALSE;
+}
+# endif INTERNET
+
+start_driver()
+{
+       register int    procid;
+
+# ifdef MONITOR
+       if (Am_monitor) {
+               leave(1, "No one playing.");
+               /* NOTREACHED */
+       }
+# endif MONITOR
+
+# ifdef INTERNET
+       if (Sock_host != NULL) {
+               sleep(3);
+               return 0;
+       }
+# endif INTERNET
+
+       mvcur(cur_row, cur_col, 23, 0);
+       cur_row = 23;
+       cur_col = 0;
+       put_str("Starting...");
+       fflush(stdout);
+       procid = vfork();
+       if (procid == -1) {
+               perror("fork");
+               leave(1, "fork failed.");
+       }
+       if (procid == 0) {
+               (void) signal(SIGINT, SIG_IGN);
+               (void) close(Socket);
+               execl(Driver, "HUNT", NULL);
+               /* only get here if exec failed */
+               kill(getppid(), SIGEMT);        /* tell mom */
+               _exit(1);
+       }
+       mvcur(cur_row, cur_col, 23, 0);
+       cur_row = 23;
+       cur_col = 0;
+       put_str("Connecting...");
+       fflush(stdout);
+       return 0;
+}
+
+/*
+ * bad_con:
+ *     We had a bad connection.  For the moment we assume that this
+ *     means the game is full.
+ */
+bad_con()
+{
+       leave(1, "The game is full.  Sorry.");
+       /* NOTREACHED */
+}
+
+/*
+ * dumpit:
+ *     Handle a core dump signal by not dumping core, just leaving,
+ *     so we end up with a core dump from the driver
+ */
+dumpit()
+{
+       (void) kill(Master_pid, SIGQUIT);
+       (void) chdir("coredump");
+       abort();
+}
+
+/*
+ * sigterm:
+ *     Handle a terminate signal
+ */
+sigterm()
+{
+       leave(0, NULL);
+       /* NOTREACHED */
+}
+
+
+/*
+ * sigemt:
+ *     Handle a emt signal - shouldn't happen on vaxes(?)
+ */
+sigemt()
+{
+       leave(1, "Unable to start driver.  Try again.");
+       /* NOTREACHED */
+}
+
+# ifdef INTERNET
+/*
+ * sigalrm:
+ *     Handle an alarm signal
+ */
+sigalrm()
+{
+       return;
+}
+# endif INTERNET
+
+/*
+ * rmnl:
+ *     Remove a '\n' at the end of a string if there is one
+ */
+rmnl(s)
+char   *s;
+{
+       register char   *cp;
+       char            *rindex();
+
+       cp = rindex(s, '\n');
+       if (cp != NULL)
+               *cp = '\0';
+}
+
+/*
+ * intr:
+ *     Handle a interrupt signal
+ */
+intr()
+{
+       register int    ch;
+       register int    explained;
+       register int    y, x;
+
+       (void) signal(SIGINT, SIG_IGN);
+       y = cur_row;
+       x = cur_col;
+       mvcur(cur_row, cur_col, 23, 0);
+       cur_row = 23;
+       cur_col = 0;
+       put_str("Really quit? ");
+       clear_eol();
+       fflush(stdout);
+       explained = FALSE;
+       for (;;) {
+               ch = getchar();
+               if (isupper(ch))
+                       ch = tolower(ch);
+               if (ch == 'y') {
+                       (void) write(Socket, "q", 1);
+                       (void) close(Socket);
+                       leave(0, NULL);
+               }
+               else if (ch == 'n') {
+                       (void) signal(SIGINT, intr);
+                       mvcur(cur_row, cur_col, y, x);
+                       cur_row = y;
+                       cur_col = x;
+                       fflush(stdout);
+                       return;
+               }
+               if (!explained) {
+                       put_str("(Y or N) ");
+                       fflush(stdout);
+                       explained = TRUE;
+               }
+               (void) putchar(CTRL(G));
+               (void) fflush(stdout);
+       }
+}
+
+/*
+ * leave:
+ *     Leave the game somewhat gracefully, restoring all current
+ *     tty stats.
+ */
+leave(eval, mesg)
+int    eval;
+char   *mesg;
+{
+       mvcur(cur_row, cur_col, 23, 0);
+       if (mesg == NULL)
+               clear_eol();
+       else {
+               put_str(mesg);
+               clear_eol();
+               putchar('\n');
+               fflush(stdout);         /* flush in case VE changes pages */
+       } 
+       resetty();
+       _puts(VE);
+       _puts(TE);
+       exit(eval);
+}
+
+/*
+ * tstp:
+ *     Handle stop and start signals
+ */
+tstp()
+{
+       static struct sgttyb    tty;
+       int     y, x;
+
+       tty = _tty;
+       y = cur_row;
+       x = cur_col;
+       mvcur(cur_row, cur_col, 23, 0);
+       cur_row = 23;
+       cur_col = 0;
+       _puts(VE);
+       _puts(TE);
+       (void) fflush(stdout);
+       resetty();
+       (void) kill(getpid(), SIGSTOP);
+       (void) signal(SIGTSTP, tstp);
+       _tty = tty;
+       (void) stty(_tty_ch, &_tty);
+       _puts(TI);
+       _puts(VS);
+       cur_row = y;
+       cur_col = x;
+       _puts(tgoto(CM, cur_row, cur_col));
+       redraw_screen();
+       fflush(stdout);
+}
+
+env_init()
+{
+       register int    i;
+       char    *envp, *envname, *s, *index();
+
+       for (i = 0; i < 256; i++)
+               map_key[i] = (char) i;
+
+       envname = NULL;
+       if ((envp = getenv("HUNT")) != NULL) {
+               while ((s = index(envp, '=')) != NULL) {
+                       if (strncmp(envp, "name=", s - envp + 1) == 0) {
+                               envname = s + 1;
+                               if ((s = index(envp, ',')) == NULL) {
+                                       *envp = '\0';
+                                       break;
+                               }
+                               *s = '\0';
+                               envp = s + 1;
+                       }                       /* must be last option */
+                       else if (strncmp(envp, "mapkey=", s - envp + 1) == 0) {
+                               for (s = s + 1; *s != '\0'; s += 2) {
+                                       map_key[(unsigned int) *s] = *(s + 1);
+                                       if (*(s + 1) == '\0') {
+                                               break;
+                                       }
+                               }
+                               *envp = '\0';
+                               break;
+                       } else {
+                               *s = '\0';
+                               printf("unknown option %s\n", envp);
+                               if ((s = index(envp, ',')) == NULL) {
+                                       *envp = '\0';
+                                       break;
+                               }
+                               envp = s + 1;
+                       }
+               }
+               if (*envp != '\0')
+                       if (envname == NULL)
+                               envname = envp;
+                       else
+                               printf("unknown option %s\n", envp);
+       }
+       if (envname != NULL) {
+               (void) strcpy(name, envname);
+               printf("Entering as '%s'\n", envname);
+       }
+       else if (name[0] == '\0') {
+               printf("Enter your code name: ");
+               if (fgets(name, sizeof name, stdin) == NULL)
+                       exit(1);
+       }
+       rmnl(name);
+}
diff --git a/usr/src/games/hunt/hunt.h b/usr/src/games/hunt/hunt.h
new file mode 100644 (file)
index 0000000..aa78ea8
--- /dev/null
@@ -0,0 +1,307 @@
+/*
+ *  Hunt
+ *  Copyright (c) 1985 Conrad C. Huang, Gregory S. Couch, Kenneth C.R.C. Arnold
+ *  San Francisco, California
+ *
+ *  Copyright (c) 1985 Regents of the University of California.
+ *  All rights reserved.  The Berkeley software License Agreement
+ *  specifies the terms and conditions for redistribution.
+ */
+
+# include      <stdio.h>
+# ifndef OLDIPC
+# include      <sgtty.h>
+# include      <sys/types.h>
+# include      <sys/uio.h>
+# else OLDIPC
+# include      <sys/localopts.h>
+# include      <sys/types.h>
+# include      <sys/netltoshort.h>
+# endif OLDIPC
+# include      <sys/socket.h>
+# ifdef        INTERNET
+# include      <netinet/in.h>
+# include      <netdb.h>
+# ifndef OLDIPC
+# include      <arpa/inet.h>
+# endif !OLDIPC
+# ifdef BROADCAST
+# include      <net/if.h>
+# endif BROADCAST
+# else INTERNET
+# include      <sys/un.h>
+# endif        INTERNET
+
+# ifdef        INTERNET
+# define       SOCK_FAMILY     AF_INET
+# else INTERNET
+# define       SOCK_FAMILY     AF_UNIX
+# define       AF_UNIX_HACK            /* 4.2 hack; leaves files around */
+# endif        INTERNET
+
+# define       ADDCH           ('a' | 0200)
+# define       MOVE            ('m' | 0200)
+# define       REFRESH         ('r' | 0200)
+# define       CLRTOEOL        ('c' | 0200)
+# define       ENDWIN          ('e' | 0200)
+# define       CLEAR           ('C' | 0200)
+# define       REDRAW          ('R' | 0200)
+# define       LAST_PLAYER     ('l' | 0200)
+# define       BELL            ('b' | 0200)
+# define       READY           ('g' | 0200)
+
+/*
+ * Choose MAXPL and MAXMON carefully.  The screen is assumed to be
+ * 23 lines high and will only tolerate (MAXPL == 12 && MAXMON == 0)
+ * or (MAXPL + MAXMON <= 10).
+ */
+# define       MAXPL           9
+# ifdef MONITOR
+# define       MAXMON          1
+# endif MONITOR
+# define       NAMELEN         20
+# define       MSGLEN          80
+# define       DECAY           50.0
+
+# define       NASCII          128
+
+# ifndef REFLECT
+# ifndef RANDOM
+# define RANDOM
+# endif RANDOM
+# endif REFLECT
+
+# define       WIDTH   59
+# define       WIDTH2  64      /* Next power of 2 >= WIDTH (for fast access) */
+# define       HEIGHT  23
+# define       UBOUND  1
+# define       DBOUND  22
+# define       LBOUND  1
+# define       RBOUND  (WIDTH - 1)
+
+# define       STAT_LABEL_COL  60
+# define       STAT_VALUE_COL  74
+# define       STAT_NAME_COL   61
+# define       STAT_SCAN_COL   (STAT_NAME_COL + 5)
+# define       STAT_NAME_ROW   0
+# define       STAT_AMMO_ROW   2
+# define       STAT_SCAN_ROW   3
+# define       STAT_CLOAK_ROW  4
+# define       STAT_GUN_ROW    5
+# define       STAT_DAM_ROW    7
+# define       STAT_KILL_ROW   8
+# define       STAT_PLAY_ROW   10
+# ifdef MONITOR
+# define       STAT_MON_ROW    (STAT_PLAY_ROW + MAXPL + 1)
+# endif MONITOR
+# define       STAT_NAME_LEN   16
+
+# define       DOOR    '#'
+# define       WALL1   '-'
+# define       WALL2   '|'
+# define       WALL3   '+'
+# ifdef REFLECT
+# define       WALL4   '/'
+# define       WALL5   '\\'
+# endif REFLECT
+# define       KNIFE   'K'
+# define       SHOT    ':'
+# define       GRENADE 'o'
+# define       SATCHEL 'O'
+# define       BOMB    '@'
+# define       MINE    ';'
+# define       GMINE   'g'
+# ifdef        OOZE
+# define       SLIME   '$'
+# endif        OOZE
+# ifdef        VOLCANO
+# define       LAVA    '~'
+# endif        VOLCANO
+# ifdef FLY
+# define       FALL    'F'
+# endif FLY
+# define       SPACE   ' '
+
+# define       ABOVE   'i'
+# define       BELOW   '!'
+# define       RIGHT   '}'
+# define       LEFTS   '{'
+# ifdef FLY
+# define       FLYER   '&'
+# endif FLY
+
+# define       NORTH   01
+# define       SOUTH   02
+# define       EAST    010
+# define       WEST    020
+
+# ifndef TRUE
+# define       TRUE    1
+# define       FALSE   0
+# endif TRUE
+# ifndef CTRL
+# define       CTRL(x) ('x' & 037)
+# endif CTRL
+
+# define       BULSPD          5               /* bullets movement speed */
+# define       ISHOTS          15
+# define       NSHOTS          5
+# define       MAXNCSHOT       2
+# define       MAXDAM          10
+# define       MINDAM          5
+# define       STABDAM         2
+
+# define       BULREQ          1
+# define       GRENREQ         9
+# define       SATREQ          25
+# define       BOMBREQ         49
+# ifdef        OOZE
+# define       SLIMEREQ        15
+# define       SSLIMEREQ       30
+# define       SLIMESPEED      5
+# endif        OOZE
+# ifdef        VOLCANO
+# define       LAVASPEED       2
+# endif VOLCANO
+
+# define       CLOAKLEN        20
+# define       SCANLEN         (Nplayer * 20)
+# define       EXPLEN          4
+
+# ifdef FLY
+# define       _cloak_char(pp) (((pp)->p_cloak < 0) ? ' ' : '+')
+# define       _scan_char(pp)  (((pp)->p_scan < 0) ? _cloak_char(pp) : '*')
+# define       stat_char(pp)   (((pp)->p_flying < 0) ? _scan_char(pp) : FLYER)
+# else FLY
+# define       _cloak_char(pp) (((pp)->p_cloak < 0) ? ' ' : '+')
+# define       stat_char(pp)   (((pp)->p_scan < 0) ? _cloak_char(pp) : '*')
+# endif FLY
+
+typedef int                    FLAG;
+typedef struct bullet_def      BULLET;
+typedef struct expl_def                EXPL;
+typedef struct player_def      PLAYER;
+typedef struct ident_def       IDENT;
+typedef struct regen_def       REGEN;
+# ifdef        INTERNET
+typedef struct sockaddr_in     SOCKET;
+# else INTERNET
+typedef struct sockaddr_un     SOCKET;
+# endif        INTERNET
+typedef struct sgttyb          TTYB;
+
+struct ident_def {
+       char    i_name[NAMELEN];
+       long    i_machine;
+       long    i_uid;
+       int     i_kills;
+       int     i_entries;
+       float   i_score;
+       IDENT   *i_next;
+};
+
+struct player_def {
+       IDENT   *p_ident;
+       int     p_face;
+       char    p_over;
+       int     p_undershot;
+# ifdef        FLY
+       int     p_flying;
+       int     p_flyx, p_flyy;
+# endif FLY
+       FILE    *p_output;
+       int     p_fd;
+       int     p_mask;
+       int     p_damage;
+       int     p_damcap;
+       int     p_ammo;
+       int     p_ncshot;
+       int     p_scan;
+       int     p_cloak;
+       int     p_x, p_y;
+       int     p_ncount;
+       int     p_nexec;
+       long    p_nchar;
+       char    p_death[MSGLEN];
+       char    p_maze[HEIGHT][WIDTH2];
+       int     p_curx, p_cury;
+       int     p_lastx, p_lasty;
+       int     p_changed;
+       char    p_cbuf[BUFSIZ];
+};
+
+struct bullet_def {
+       int     b_x, b_y;
+       int     b_face;
+       int     b_charge;
+       char    b_type;
+       char    b_over;
+       PLAYER  *b_owner;
+       IDENT   *b_score;
+       FLAG    b_expl;
+       BULLET  *b_next;
+};
+
+struct expl_def {
+       int     e_x, e_y;
+       char    e_char;
+       EXPL    *e_next;
+};
+
+struct regen_def {
+       int     r_x, r_y;
+       REGEN   *r_next;
+};
+
+/*
+ * external variables
+ */
+
+extern FLAG    Last_player;
+
+extern char    Buf[BUFSIZ], Maze[HEIGHT][WIDTH2], Orig_maze[HEIGHT][WIDTH2];
+
+extern char    *Sock_name, *Driver;
+
+extern int     errno, Have_inp, Nplayer, Num_fds, Socket;
+extern long    Fds_mask, Sock_mask;
+
+# ifdef INTERNET
+extern int     Test_port;
+extern int     Sock_port;
+# else INTERNET
+extern char    *Sock_name;
+# endif INTERNET
+
+# ifdef VOLCANO
+extern int     volcano;
+# endif        VOLCANO
+
+extern int     See_over[NASCII];
+
+extern BULLET  *Bullets;
+
+extern EXPL    *Expl[EXPLEN];
+
+extern IDENT   *Scores;
+
+extern PLAYER  Player[MAXPL], *End_player;
+
+# ifdef MONITOR
+extern FLAG    Am_monitor;
+extern PLAYER  Monitor[MAXMON], *End_monitor;
+# endif MONITOR
+
+/*
+ * function types
+ */
+
+char   *getenv(), *malloc(), *sprintf(), *strcpy(), *strncpy();
+
+IDENT  *get_ident();
+
+int    moveshots();
+
+BULLET *is_bullet(), *create_shot();
+
+PLAYER *play_at();
diff --git a/usr/src/games/hunt/playit.c b/usr/src/games/hunt/playit.c
new file mode 100644 (file)
index 0000000..87a9497
--- /dev/null
@@ -0,0 +1,383 @@
+/*
+ *  Hunt
+ *  Copyright (c) 1985 Conrad C. Huang, Gregory S. Couch, Kenneth C.R.C. Arnold
+ *  San Francisco, California
+ *
+ *  Copyright (c) 1985 Regents of the University of California.
+ *  All rights reserved.  The Berkeley software License Agreement
+ *  specifies the terms and conditions for redistribution.
+ */
+
+# include      <curses.h>
+# include      <ctype.h>
+# include      <signal.h>
+# include      <errno.h>
+# include      "hunt.h"
+# include      <sys/file.h>
+
+# undef  CTRL
+# define CTRL(x)       ('x' & 037)
+
+int            input();
+static int     nchar_send;
+static int     in      = FREAD;
+char           screen[24][80], blanks[80];
+int            cur_row, cur_col;
+# ifdef OTTO
+int            Otto_count;
+int            Otto_mode;
+static int     otto_y, otto_x;
+static char    otto_face;
+# endif OTTO
+
+# define       MAX_SEND        5
+
+/*
+ * ibuf is the input buffer used for the stream from the driver.
+ * It is small because we do not check for user input when there
+ * are characters in the input buffer.
+ */
+static char    ibuf[20];
+
+#define        GETCHR(fd)      (--(fd)->_cnt >= 0 ? *(fd)->_ptr++&0377 : getchr(fd))
+
+/*
+ * playit:
+ *     Play a given game, handling all the curses commands from
+ *     the driver.
+ */
+playit()
+{
+       register FILE           *inf;
+       register int            ch;
+       register unsigned int   y, x;
+       extern int              Master_pid;
+       extern int              errno;
+       extern int              _putchar();
+
+       errno = 0;
+       while ((inf = fdopen(Socket, "r")) == NULL)
+               if (errno == EINTR)
+                       errno = 0;
+               else {
+                       perror("fdopen of socket");
+                       exit(1);
+               }
+       setbuffer(inf, ibuf, sizeof ibuf);
+       Master_pid = getw(inf);
+       if (Master_pid == 0 || Master_pid == EOF) {
+               bad_con();
+               /* NOTREACHED */
+       }
+# ifdef OTTO
+       Otto_count = 0;
+# endif OTTO
+       nchar_send = MAX_SEND;
+       while ((ch = GETCHR(inf)) != EOF) {
+# ifdef DEBUG
+               fputc(ch, stderr);
+# endif DEBUG
+               switch (ch & 0377) {
+                 case MOVE:
+                       y = GETCHR(inf);
+                       x = GETCHR(inf);
+                       mvcur(cur_row, cur_col, y, x);
+                       cur_row = y;
+                       cur_col = x;
+                       break;
+                 case ADDCH:
+                       ch = GETCHR(inf);
+# ifdef OTTO
+                       switch (ch) {
+
+                       case '<':
+                       case '>':
+                       case '^':
+                       case 'v':
+                               otto_face = ch;
+                               getyx(stdscr, otto_y, otto_x);
+                               break;
+                       }
+# endif OTTO
+                       put_ch(ch);
+                       break;
+                 case CLRTOEOL:
+                       clear_eol();
+                       break;
+                 case CLEAR:
+                       clear_screen();
+                       break;
+                 case REFRESH:
+                       fflush(stdout);
+                       break;
+                 case REDRAW:
+                       redraw_screen();
+                       fflush(stdout);
+                       break;
+                 case ENDWIN:
+                       fflush(stdout);
+                       if ((ch = GETCHR(inf)) == LAST_PLAYER)
+                               Last_player = TRUE;
+                       ch = EOF;
+                       goto out;
+                 case BELL:
+                       putchar(CTRL(G));
+                       break;
+                 case READY:
+                       (void) fflush(stdout);
+                       if (nchar_send < 0)
+                               (void) ioctl(fileno(stdin), TIOCFLUSH, &in);
+                       nchar_send = MAX_SEND;
+# ifndef OTTO
+                       (void) GETCHR(inf);
+# else OTTO
+                       Otto_count -= (GETCHR(inf) & 255);
+                       if (!Am_monitor) {
+# ifdef DEBUG
+                               fputc('0' + Otto_count, stderr);
+# endif DEBUG
+                               if (Otto_count == 0 && Otto_mode)
+                                       otto(otto_y, otto_x, otto_face);
+                       }
+# endif OTTO
+                       break;
+                 default:
+# ifdef OTTO
+                       switch (ch) {
+
+                       case '<':
+                       case '>':
+                       case '^':
+                       case 'v':
+                               otto_face = ch;
+                               getyx(stdscr, otto_y, otto_x);
+                               break;
+                       }
+# endif OTTO
+                       put_ch(ch);
+                       break;
+               }
+       }
+out:
+       (void) fclose(inf);
+}
+
+/*
+ * getchr:
+ *     Grab input and pass it along to the driver
+ *     Return any characters from the driver
+ *     When this routine is called by GETCHR, we already know there are
+ *     no characters in the input buffer.
+ */
+getchr(fd)
+register FILE  *fd;
+{
+       long    nchar;
+       long    readfds, s_readfds;
+       int     driver_mask, stdin_mask;
+       int     nfds, s_nfds;
+
+       driver_mask = 1L << fileno(fd);
+       stdin_mask = 1L << fileno(stdin);
+       s_readfds = driver_mask | stdin_mask;
+       s_nfds = (driver_mask > stdin_mask) ? driver_mask : stdin_mask;
+       s_nfds++;
+
+one_more_time:
+       do {
+               errno = 0;
+               readfds = s_readfds;
+               nfds = s_nfds;
+# ifndef OLDIPC
+               nfds = select(nfds, &readfds, NULL, NULL, NULL);
+# else OLDIPC
+               nfds = select(nfds, &readfds, (int *) NULL, 32767);
+# endif OLDIPC
+       } while (nfds <= 0 && errno == EINTR);
+
+       if (readfds & stdin_mask)
+               send_stuff();
+       if ((readfds & driver_mask) == 0)
+               goto one_more_time;
+       return _filbuf(fd);
+}
+
+/*
+ * send_stuff:
+ *     Send standard input characters to the driver
+ */
+send_stuff()
+{
+       register int    count;
+       register char   *sp, *nsp;
+       static char     inp[sizeof Buf];
+       extern char     map_key[256];
+
+       count = read(fileno(stdin), Buf, sizeof Buf);
+       if (count <= 0)
+               return;
+       if (nchar_send <= 0) {
+               (void) write(1, "\7", 1);
+               return;
+       }
+
+       /*
+        * look for 'q'uit commands; if we find one,
+        * confirm it.  If it is not confirmed, strip
+        * it out of the input
+        */
+       Buf[count] = '\0';
+       nsp = inp;
+       for (sp = Buf; *sp != '\0'; sp++)
+               if ((*nsp = map_key[*sp]) == 'q')
+                       intr();
+# ifdef OTTO
+               else if (*nsp == CTRL(O))
+                       Otto_mode = !Otto_mode;
+# endif OTTO
+               else
+                       nsp++;
+       count = nsp - inp;
+       if (count) {
+# ifdef OTTO
+               Otto_count += count;
+# endif OTTO
+               nchar_send -= count;
+               if (nchar_send < 0)
+                       count += nchar_send;
+               (void) write(Socket, inp, count);
+       }
+}
+
+/*
+ * quit:
+ *     Handle the end of the game when the player dies
+ */
+quit()
+{
+       register int    explain, ch;
+
+       if (Last_player)
+               return TRUE;
+# ifdef OTTO
+       if (Otto_mode)
+               return FALSE;
+# endif OTTO
+       mvcur(cur_row, cur_col, HEIGHT, 0);
+       cur_row = HEIGHT;
+       cur_col = 0;
+       put_str("Re-enter game? ");
+       clear_eol();
+       fflush(stdout);
+       explain = FALSE;
+       for (;;) {
+               if (isupper(ch = getchar()))
+                       ch = tolower(ch);
+               if (ch == 'y') {
+                       sleep(2);
+                       return FALSE;
+               }
+               else if (ch == 'n')
+                       return TRUE;
+               (void) putchar(CTRL(G));
+               if (!explain) {
+                       put_str("(Y or N) ");
+                       explain = TRUE;
+               }
+               fflush(stdout);
+       }
+}
+
+put_ch(ch)
+       char    ch;
+{
+       if (!isprint(ch)) {
+               fprintf(stderr, "r,c,ch: %d,%d,%d", cur_row, cur_col, ch);
+               return;
+       }
+       screen[cur_row][cur_col] = ch;
+       putchar(ch);
+       if (++cur_col >= COLS) {
+               if (!AM || XN)
+                       putchar('\n');
+               cur_col = 0;
+               if (++cur_row >= LINES)
+                       cur_row = LINES;
+       }
+}
+
+put_str(s)
+       char    *s;
+{
+       while (*s)
+               put_ch(*s++);
+}
+
+clear_screen()
+{
+       register int    i;
+
+       if (blanks[0] == '\0')
+               for (i = 0; i < 80; i++)
+                       blanks[i] = ' ';
+
+       if (CL != NULL) {
+               tputs(CL, LINES, _putchar);
+               for (i = 0; i < 24; i++)
+                       bcopy(blanks, screen[i], 80);
+       } else {
+               for (i = 0; i < 24; i++) {
+                       mvcur(cur_row, cur_col, i, 0);
+                       cur_row = i;
+                       cur_col = 0;
+                       clear_eol();
+               }
+               mvcur(cur_row, cur_col, 0, 0);
+       }
+       cur_row = cur_col = 0;
+}
+
+clear_eol()
+{
+       if (CE != NULL)
+               tputs(CE, 1, _putchar);
+       else {
+               fwrite(blanks, sizeof (char), 80 - cur_col, stdout);
+               if (COLS != 80)
+                       mvcur(cur_row, 80, cur_row, cur_col);
+               else if (AM)
+                       mvcur(cur_row + 1, 0, cur_row, cur_col);
+               else
+                       mvcur(cur_row, 79, cur_row, cur_col);
+       }
+       bcopy(blanks, &screen[cur_row][cur_col], 80 - cur_col);
+}
+
+redraw_screen()
+{
+       register int    i;
+       static int      first = 1;
+
+       if (first) {
+               if ((curscr = newwin(24, 80, 0, 0)) == NULL) {
+                       fprintf(stderr, "Can't create curscr\n");
+                       exit(1);
+               }
+               for (i = 0; i < 24; i++)
+                       curscr->_y[i] = screen[i];
+               first = 0;
+       }
+       curscr->_cury = cur_row;
+       curscr->_curx = cur_col;
+       wrefresh(curscr);
+#ifdef NOCURSES
+       mvcur(cur_row, cur_col, 0, 0);
+       for (i = 0; i < 23; i++) {
+               fwrite(screen[i], sizeof (char), 80, stdout);
+               if (COLS > 80 || (COLS == 80 && !AM))
+                       putchar('\n');
+       }
+       fwrite(screen[23], sizeof (char), 79, stdout);
+       mvcur(23, 79, cur_row, cur_col);
+#endif
+}
diff --git a/usr/src/games/hunt/shots.c b/usr/src/games/hunt/shots.c
new file mode 100644 (file)
index 0000000..a99ba5f
--- /dev/null
@@ -0,0 +1,823 @@
+/*
+ *  Hunt
+ *  Copyright (c) 1985 Conrad C. Huang, Gregory S. Couch, Kenneth C.R.C. Arnold
+ *  San Francisco, California
+ *
+ *  Copyright (c) 1985 Regents of the University of California.
+ *  All rights reserved.  The Berkeley software License Agreement
+ *  specifies the terms and conditions for redistribution.
+ */
+
+# include      "hunt.h"
+# include      <signal.h>
+
+# define       PLUS_DELTA(x, max)      if (x < max) x++; else x--
+# define       MINUS_DELTA(x, min)     if (x > min) x--; else x++
+
+/*
+ * moveshots:
+ *     Move the shots already in the air, taking explosions into account
+ */
+moveshots()
+{
+       register BULLET *bp, *next;
+       register PLAYER *pp;
+       register int    x, y;
+       register BULLET *blist;
+       register int    i;
+
+       rollexpl();
+       if (Bullets == NULL)
+               goto ret;
+
+       /*
+        * First we move through the bullet list BULSPD times, looking
+        * for things we may have run into.  If we do run into
+        * something, we set up the explosion and disappear, checking
+        * for damage to any player who got in the way.
+        */
+
+       blist = Bullets;
+       Bullets = NULL;
+       for (bp = blist; bp != NULL; bp = next) {
+               next = bp->b_next;
+               x = bp->b_x;
+               y = bp->b_y;
+               Maze[y][x] = bp->b_over;
+               for (pp = Player; pp < End_player; pp++)
+                       check(pp, y, x);
+# ifdef MONITOR
+               for (pp = Monitor; pp < End_monitor; pp++)
+                       check(pp, y, x);
+# endif MONITOR
+
+               for (i = 0; i < BULSPD; i++) {
+                       if (bp->b_expl)
+                               break;
+
+                       x = bp->b_x;
+                       y = bp->b_y;
+
+                       switch (bp->b_face) {
+                         case LEFTS:
+                               x--;
+                               break;
+                         case RIGHT:
+                               x++;
+                               break;
+                         case ABOVE:
+                               y--;
+                               break;
+                         case BELOW:
+                               y++;
+                               break;
+                       }
+
+                       switch (Maze[y][x]) {
+                         case SHOT:
+                               if (rand_num(100) < 5) {
+                                       zapshot(Bullets, bp);
+                                       zapshot(next, bp);
+                               }
+                               break;
+                         case GRENADE:
+                               if (rand_num(100) < 10) {
+                                       zapshot(Bullets, bp);
+                                       zapshot(next, bp);
+                               }
+                               break;
+# ifdef        REFLECT
+                         case WALL4:   /* reflecting walls */
+                               switch (bp->b_face) {
+                                 case LEFTS:
+                                       bp->b_face = BELOW;
+                                       break;
+                                 case RIGHT:
+                                       bp->b_face = ABOVE;
+                                       break;
+                                 case ABOVE:
+                                       bp->b_face = RIGHT;
+                                       break;
+                                 case BELOW:
+                                       bp->b_face = LEFTS;
+                                       break;
+                               }
+                               Maze[y][x] = WALL5;
+# ifdef MONITOR
+                               for (pp = Monitor; pp < End_monitor; pp++)
+                                       check(pp, y, x);
+# endif MONITOR
+                               break;
+                         case WALL5:
+                               switch (bp->b_face) {
+                                 case LEFTS:
+                                       bp->b_face = ABOVE;
+                                       break;
+                                 case RIGHT:
+                                       bp->b_face = BELOW;
+                                       break;
+                                 case ABOVE:
+                                       bp->b_face = LEFTS;
+                                       break;
+                                 case BELOW:
+                                       bp->b_face = RIGHT;
+                                       break;
+                               }
+                               Maze[y][x] = WALL4;
+# ifdef MONITOR
+                               for (pp = Monitor; pp < End_monitor; pp++)
+                                       check(pp, y, x);
+# endif MONITOR
+                               break;
+# endif REFLECT
+# ifdef RANDOM
+                         case DOOR:
+                               switch (rand_num(4)) {
+                                 case 0:
+                                       bp->b_face = ABOVE;
+                                       break;
+                                 case 1:
+                                       bp->b_face = BELOW;
+                                       break;
+                                 case 2:
+                                       bp->b_face = LEFTS;
+                                       break;
+                                 case 3:
+                                       bp->b_face = RIGHT;
+                                       break;
+                               }
+                               break;
+# endif RANDOM
+                         case LEFTS:
+                         case RIGHT:
+                         case BELOW:
+                         case ABOVE:
+# ifdef FLY
+                         case FLYER:
+# endif FLY
+                               /*
+                                * give the person a chance to catch a
+                                * grenade if s/he is facing it
+                                */
+                               if (rand_num(100) < 10
+                                   && opposite(bp->b_face, Maze[y][x])) {
+                                       if (bp->b_owner != NULL)
+                                               message(bp->b_owner,
+                                               "Your charge was absorbed!");
+                                       pp = play_at(y, x);
+                                       pp->p_ammo += bp->b_charge;
+                                       (void) sprintf(Buf,
+                                               "Absorbed charge (good shield!)");
+                                       message(pp, Buf);
+                                       free((char *) bp);
+                                       (void) sprintf(Buf, "%3d", pp->p_ammo);
+                                       cgoto(pp, STAT_AMMO_ROW, STAT_VALUE_COL);
+                                       outstr(pp, Buf, 3);
+                                       goto next_bullet;
+                               }
+                               /* FALLTHROUGH */
+# ifndef RANDOM
+                         case DOOR:
+# endif RANDOM
+                         case WALL1:
+                         case WALL2:
+                         case WALL3:
+                               bp->b_expl = TRUE;
+                               break;
+                       }
+
+                       bp->b_x = x;
+                       bp->b_y = y;
+               }
+
+               bp->b_next = Bullets;
+               Bullets = bp;
+next_bullet:
+               ;
+       }
+
+       blist = Bullets;
+       Bullets = NULL;
+       for (bp = blist; bp != NULL; bp = next) {
+               next = bp->b_next;
+               if (!bp->b_expl) {
+                       save_bullet(bp);
+# ifdef MONITOR
+                       for (pp = Monitor; pp < End_monitor; pp++)
+                               check(pp, bp->b_y, bp->b_x);
+# endif MONITOR
+                       continue;
+               }
+
+               chkshot(bp);
+               free((char *) bp);
+       }
+       for (pp = Player; pp < End_player; pp++)
+               Maze[pp->p_y][pp->p_x] = pp->p_face;
+ret:
+       for (pp = Player; pp < End_player; pp++) {
+# ifdef FLY
+               if (pp->p_flying >= 0) {
+                       Maze[pp->p_y][pp->p_x] = pp->p_over;
+                       x = pp->p_x + pp->p_flyx;
+                       y = pp->p_y + pp->p_flyy;
+                       if (x < 1) {
+                               x = 1 - x;
+                               pp->p_flyx = -pp->p_flyx;
+                       }
+                       else if (x > WIDTH - 2) {
+                               x = (WIDTH - 2) - (x - (WIDTH - 2));
+                               pp->p_flyx = -pp->p_flyx;
+                       }
+                       if (y < 1) {
+                               y = 1 - y;
+                               pp->p_flyy = -pp->p_flyy;
+                       }
+                       else if (y > HEIGHT - 2) {
+                               y = (HEIGHT - 2) - (y - (HEIGHT - 2));
+                               pp->p_flyy = -pp->p_flyy;
+                       }
+again:                 switch (Maze[y][x]) {
+                         case LEFTS:
+                         case RIGHT:
+                         case ABOVE:
+                         case BELOW:
+                         case FLYER:
+                               switch (rand_num(4)) {
+                                 case 0:
+                                       PLUS_DELTA(x, WIDTH - 2);
+                                       break;
+                                 case 1:
+                                       MINUS_DELTA(x, 1);
+                                       break;
+                                 case 2:
+                                       PLUS_DELTA(y, HEIGHT - 2);
+                                       break;
+                                 case 3:
+                                       MINUS_DELTA(y, 1);
+                                       break;
+                               }
+                               goto again;
+                         case WALL1:
+                         case WALL2:
+                         case WALL3:
+# ifdef        REFLECT
+                         case WALL4:
+                         case WALL5:
+# endif REFLECT
+# ifdef        RANDOM
+                         case DOOR:
+# endif        RANDOM
+                               if (pp->p_flying == 0)
+                                       pp->p_flying++;
+                               break;
+                         case MINE:
+                               checkdam(pp, NULL, NULL, MINDAM, MINE);
+                               Maze[y][x] = SPACE;
+                               break;
+                         case GMINE:
+                               checkdam(pp, NULL, NULL, MINDAM, GMINE);
+                               checkdam(pp, NULL, NULL, MINDAM, GMINE);
+                               Maze[y][x] = SPACE;
+                               break;
+                       }
+                       pp->p_y = y;
+                       pp->p_x = x;
+                       pp->p_over = Maze[y][x];
+                       if (pp->p_flying-- == 0) {
+                               checkdam(pp, NULL, NULL,
+                                       rand_num(pp->p_damage / 5), FALL);
+                               rand_face(pp);
+                               showstat(pp);
+                       }
+                       Maze[y][x] = pp->p_face;
+                       showexpl(y, x, pp->p_face);
+               }
+# endif FLY
+               sendcom(pp, REFRESH);   /* Flush out the explosions */
+               look(pp);
+               sendcom(pp, REFRESH);
+       }
+# ifdef MONITOR
+       for (pp = Monitor; pp < End_monitor; pp++)
+               sendcom(pp, REFRESH);
+# endif MONITOR
+
+# ifdef CONSTANT_MOVE
+       if (Bullets != NULL) {
+               bul_alarm(1);
+               return;
+       }
+       for (i = 0; i < EXPLEN; i++)
+               if (Expl[i] != NULL) {
+                       bul_alarm(1);
+                       return;
+               }
+       bul_alarm(0);
+# endif CONSTANT_MOVE
+
+       return;
+}
+
+save_bullet(bp)
+register BULLET        *bp;
+{
+       bp->b_over = Maze[bp->b_y][bp->b_x];
+       switch (bp->b_over) {
+         case SHOT:
+         case GRENADE:
+         case SATCHEL:
+         case BOMB:
+# ifdef OOZE
+         case SLIME:
+# ifdef VOLCANO
+         case LAVA:
+# endif VOLCANO
+# endif OOZE
+               find_under(Bullets, bp);
+               break;
+       }
+
+       switch (bp->b_over) {
+         case LEFTS:
+         case RIGHT:
+         case ABOVE:
+         case BELOW:
+# ifdef FLY
+         case FLYER:
+# endif FLY
+               mark_player(bp);
+               break;
+               
+         default:
+               Maze[bp->b_y][bp->b_x] = bp->b_type;
+               break;
+       }
+
+       bp->b_next = Bullets;
+       Bullets = bp;
+}
+
+/*
+ * chkshot
+ *     Handle explosions
+ */
+chkshot(bp)
+register BULLET        *bp;
+{
+       register int    y, x;
+       register int    dy, dx, absdy;
+       register int    delta, damage;
+       register char   expl;
+       register PLAYER *pp;
+
+       switch (bp->b_type) {
+         case SHOT:
+         case MINE:
+               delta = 0;
+               break;
+         case GRENADE:
+         case GMINE:
+               delta = 1;
+               break;
+         case SATCHEL:
+               delta = 2;
+               break;
+         case BOMB:
+               delta = 3;
+               break;
+# ifdef        OOZE
+         case SLIME:
+# ifdef VOLCANO
+         case LAVA:
+# endif VOLCANO
+               chkslime(bp);
+               return;
+# endif        OOZE
+       }
+       for (y = bp->b_y - delta; y <= bp->b_y + delta; y++) {
+               if (y < 0 || y >= HEIGHT)
+                       continue;
+               dy = y - bp->b_y;
+               absdy = (dy < 0) ? -dy : dy;
+               for (x = bp->b_x - delta; x <= bp->b_x + delta; x++) {
+                       if (x < 0 || x >= WIDTH)
+                               continue;
+                       dx = x - bp->b_x;
+                       if (dx == 0)
+                               expl = (dy == 0) ? '*' : '|';
+                       else if (dy == 0)
+                               expl = '-';
+                       else if (dx == dy)
+                               expl = '\\';
+                       else if (dx == -dy)
+                               expl = '/';
+                       else
+                               expl = '*';
+                       showexpl(y, x, expl);
+                       switch (Maze[y][x]) {
+                         case LEFTS:
+                         case RIGHT:
+                         case ABOVE:
+                         case BELOW:
+# ifdef FLY
+                         case FLYER:
+# endif FLY
+                               if (dx < 0)
+                                       dx = -dx;
+                               if (absdy > dx)
+                                       damage = delta - absdy + 1;
+                               else
+                                       damage = delta - dx + 1;
+                               pp = play_at(y, x);
+                               while (damage-- > 0)
+                                       checkdam(pp, bp->b_owner, bp->b_score,
+                                               MINDAM, bp->b_type);
+                               break;
+                         case GMINE:
+                         case MINE:
+                               add_shot((Maze[y][x] == GMINE) ?
+                                       GRENADE : SHOT,
+                                       y, x, LEFTS,
+                                       (Maze[y][x] == GMINE) ?
+                                       GRENREQ : BULREQ,
+                                       (PLAYER *) NULL, TRUE, SPACE);
+                               Maze[y][x] = SPACE;
+                               break;
+                       }
+               }
+       }
+}
+
+# ifdef        OOZE
+/*
+ * chkslime:
+ *     handle slime shot exploding
+ */
+chkslime(bp)
+register BULLET        *bp;
+{
+       register BULLET *nbp;
+
+       switch (Maze[bp->b_y][bp->b_x]) {
+         case WALL1:
+         case WALL2:
+         case WALL3:
+# ifdef        REFLECT
+         case WALL4:
+         case WALL5:
+# endif REFLECT
+# ifdef        RANDOM
+         case DOOR:
+# endif        RANDOM
+               switch (bp->b_face) {
+                 case LEFTS:
+                       bp->b_x++;
+                       break;
+                 case RIGHT:
+                       bp->b_x--;
+                       break;
+                 case ABOVE:
+                       bp->b_y++;
+                       break;
+                 case BELOW:
+                       bp->b_y--;
+                       break;
+               }
+               break;
+       }
+       nbp = (BULLET *) malloc(sizeof (BULLET));
+       *nbp = *bp;
+# ifdef VOLCANO
+       moveslime(nbp, nbp->b_type == SLIME ? SLIMESPEED : LAVASPEED);
+# else VOLCANO
+       moveslime(nbp, SLIMESPEED);
+# endif VOLCANO
+}
+
+/*
+ * moveslime:
+ *     move the given slime shot speed times and add it back if
+ *     it hasn't fizzled yet
+ */
+moveslime(bp, speed)
+register BULLET        *bp;
+register int   speed;
+{
+       register int    i, j, dirmask, count;
+       register PLAYER *pp;
+       register BULLET *nbp;
+
+       if (speed == 0) {
+               if (bp->b_charge <= 0)
+                       free((char *) bp);
+               else
+                       save_bullet(bp);
+               return;
+       }
+
+# ifdef VOLCANO
+       showexpl(bp->b_y, bp->b_x, bp->b_type == LAVA ? LAVA : '*');
+# else VOLCANO
+       showexpl(bp->b_y, bp->b_x, '*');
+# endif VOLCANO
+       switch (Maze[bp->b_y][bp->b_x]) {
+         case LEFTS:
+         case RIGHT:
+         case ABOVE:
+         case BELOW:
+# ifdef FLY
+         case FLYER:
+# endif FLY
+               pp = play_at(bp->b_y, bp->b_x);
+               message(pp, "You've been slimed.");
+               checkdam(pp, bp->b_owner, bp->b_score, MINDAM, bp->b_type);
+               break;
+       }
+
+       if (--bp->b_charge <= 0) {
+               free((char *) bp);
+               return;
+       }
+
+       dirmask = 0;
+       count = 0;
+       switch (bp->b_face) {
+         case LEFTS:
+               if (!iswall(bp->b_y, bp->b_x - 1))
+                       dirmask |= WEST, count++;
+               if (!iswall(bp->b_y - 1, bp->b_x))
+                       dirmask |= NORTH, count++;
+               if (!iswall(bp->b_y + 1, bp->b_x))
+                       dirmask |= SOUTH, count++;
+               if (dirmask == 0)
+                       if (!iswall(bp->b_y, bp->b_x + 1))
+                               dirmask |= EAST, count++;
+               break;
+         case RIGHT:
+               if (!iswall(bp->b_y, bp->b_x + 1))
+                       dirmask |= EAST, count++;
+               if (!iswall(bp->b_y - 1, bp->b_x))
+                       dirmask |= NORTH, count++;
+               if (!iswall(bp->b_y + 1, bp->b_x))
+                       dirmask |= SOUTH, count++;
+               if (dirmask == 0)
+                       if (!iswall(bp->b_y, bp->b_x - 1))
+                               dirmask |= WEST, count++;
+               break;
+         case ABOVE:
+               if (!iswall(bp->b_y - 1, bp->b_x))
+                       dirmask |= NORTH, count++;
+               if (!iswall(bp->b_y, bp->b_x - 1))
+                       dirmask |= WEST, count++;
+               if (!iswall(bp->b_y, bp->b_x + 1))
+                       dirmask |= EAST, count++;
+               if (dirmask == 0)
+                       if (!iswall(bp->b_y + 1, bp->b_x))
+                               dirmask |= SOUTH, count++;
+               break;
+         case BELOW:
+               if (!iswall(bp->b_y + 1, bp->b_x))
+                       dirmask |= SOUTH, count++;
+               if (!iswall(bp->b_y, bp->b_x - 1))
+                       dirmask |= WEST, count++;
+               if (!iswall(bp->b_y, bp->b_x + 1))
+                       dirmask |= EAST, count++;
+               if (dirmask == 0)
+                       if (!iswall(bp->b_y - 1, bp->b_x))
+                               dirmask |= NORTH, count++;
+               break;
+       }
+       if (count == 0) {
+               /*
+                * No place to go.  Just sit here for a while and wait
+                * for adjacent squares to clear out.
+                */
+               save_bullet(bp);
+               return;
+       }
+       if (bp->b_charge < count) {
+               /* Only bp->b_charge paths may be taken */
+               while (count > bp->b_charge) {
+                       if (dirmask & WEST)
+                               dirmask &= ~WEST;
+                       else if (dirmask & EAST)
+                               dirmask &= ~EAST;
+                       else if (dirmask & NORTH)
+                               dirmask &= ~NORTH;
+                       else if (dirmask & SOUTH)
+                               dirmask &= ~SOUTH;
+                       count--;
+               }
+       }
+
+       i = bp->b_charge / count;
+       j = bp->b_charge % count;
+       if (dirmask & WEST) {
+               count--;
+               nbp = create_shot(bp->b_type, bp->b_y, bp->b_x - 1, LEFTS,
+                       i, bp->b_owner, bp->b_score, TRUE, SPACE);
+               moveslime(nbp, speed - 1);
+       }
+       if (dirmask & EAST) {
+               count--;
+               nbp = create_shot(bp->b_type, bp->b_y, bp->b_x + 1, RIGHT,
+                       (count < j) ? i + 1 : i, bp->b_owner, bp->b_score,
+                       TRUE, SPACE);
+               moveslime(nbp, speed - 1);
+       }
+       if (dirmask & NORTH) {
+               count--;
+               nbp = create_shot(bp->b_type, bp->b_y - 1, bp->b_x, ABOVE,
+                       (count < j) ? i + 1 : i, bp->b_owner, bp->b_score,
+                       TRUE, SPACE);
+               moveslime(nbp, speed - 1);
+       }
+       if (dirmask & SOUTH) {
+               count--;
+               nbp = create_shot(bp->b_type, bp->b_y + 1, bp->b_x, BELOW,
+                       (count < j) ? i + 1 : i, bp->b_owner, bp->b_score,
+                       TRUE, SPACE);
+               moveslime(nbp, speed - 1);
+       }
+
+       free((char *) bp);
+}
+
+/*
+ * iswall:
+ *     returns whether the given location is a wall
+ */
+iswall(y, x)
+register int   y, x;
+{
+       if (y < 0 || x < 0 || y >= HEIGHT || x >= WIDTH)
+               return TRUE;
+       switch (Maze[y][x]) {
+         case WALL1:
+         case WALL2:
+         case WALL3:
+# ifdef        REFLECT
+         case WALL4:
+         case WALL5:
+# endif        REFLECT
+# ifdef        RANDOM
+         case DOOR:
+# endif        RANDOM
+# ifdef VOLCANO
+         case LAVA:
+# endif VOLCANO
+               return TRUE;
+       }
+       return FALSE;
+}
+# endif        OOZE
+
+/*
+ * zapshot:
+ *     Take a shot out of the air.
+ */
+zapshot(blist, obp)
+register BULLET        *blist, *obp;
+{
+       register BULLET *bp;
+       register FLAG   explode;
+
+       explode = FALSE;
+       for (bp = blist; bp != NULL; bp = bp->b_next) {
+               if (bp->b_x != obp->b_x || bp->b_y != obp->b_y)
+                       continue;
+               if (bp->b_face == obp->b_face)
+                       continue;
+               explode = TRUE;
+               break;
+       }
+       if (!explode)
+               return;
+       explshot(blist, obp->b_y, obp->b_x);
+}
+
+/*
+ * explshot -
+ *     Make all shots at this location blow up
+ */
+explshot(blist, y, x)
+register BULLET        *blist;
+register int   y, x;
+{
+       register BULLET *bp;
+
+       for (bp = blist; bp != NULL; bp = bp->b_next)
+               if (bp->b_x == x && bp->b_y == y) {
+                       bp->b_expl = TRUE;
+                       if (bp->b_owner != NULL)
+                               message(bp->b_owner, "Shot intercepted");
+               }
+}
+
+/*
+ * play_at:
+ *     Return a pointer to the player at the given location
+ */
+PLAYER *
+play_at(y, x)
+register int   y, x;
+{
+       register PLAYER *pp;
+
+       for (pp = Player; pp < End_player; pp++)
+               if (pp->p_x == x && pp->p_y == y)
+                       return pp;
+       fprintf(stderr, "driver: couldn't find player at (%d,%d)\n", x, y);
+       abort();
+       /* NOTREACHED */
+}
+
+/*
+ * opposite:
+ *     Return TRUE if the bullet direction faces the opposite direction
+ *     of the player in the maze
+ */
+opposite(face, dir)
+int    face;
+char   dir;
+{
+       switch (face) {
+         case LEFTS:
+               return (dir == RIGHT);
+         case RIGHT:
+               return (dir == LEFTS);
+         case ABOVE:
+               return (dir == BELOW);
+         case BELOW:
+               return (dir == ABOVE);
+         default:
+               return FALSE;
+       }
+}
+
+/*
+ * is_bullet:
+ *     Is there a bullet at the given coordinates?  If so, return
+ *     a pointer to the bullet, otherwise return NULL
+ */
+BULLET *
+is_bullet(y, x)
+register int   y, x;
+{
+       register BULLET *bp;
+
+       for (bp = Bullets; bp != NULL; bp = bp->b_next)
+               if (bp->b_y == y && bp->b_x == x)
+                       return bp;
+       return NULL;
+}
+
+/*
+ * fixshots:
+ *     change the underlying character of the shots at a location
+ *     to the given character.
+ */
+fixshots(y, x, over)
+register int   y, x;
+char           over;
+{
+       register BULLET *bp;
+
+       for (bp = Bullets; bp != NULL; bp = bp->b_next)
+               if (bp->b_y == y && bp->b_x == x)
+                       bp->b_over = over;
+}
+
+/*
+ * find_under:
+ *     find the underlying character for a bullet when it lands
+ *     on another bullet.
+ */
+find_under(blist, bp)
+register BULLET        *blist, *bp;
+{
+       register BULLET *nbp;
+
+       for (nbp = blist; nbp != NULL; nbp = nbp->b_next)
+               if (bp->b_y == nbp->b_y && bp->b_x == nbp->b_x) {
+                       bp->b_over = nbp->b_over;
+                       break;
+               }
+}
+
+/*
+ * mark_player:
+ *     mark a player as under a shot
+ */
+mark_player(bp)
+register BULLET        *bp;
+{
+       register PLAYER *pp;
+
+       for (pp = Player; pp < End_player; pp++)
+               if (pp->p_y == bp->b_y && pp->p_x == bp->b_x) {
+                       pp->p_undershot = TRUE;
+                       break;
+               }
+}