home *** CD-ROM | disk | FTP | other *** search
/ PC-Online 1996 May / PCOnline_05_1996.bin / linux / source / y / bsdgames / bsd-game.000 / bsd-game / games / hunt / driver.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-09-21  |  19.8 KB  |  962 lines

  1. /*
  2.  *  Hunt
  3.  *  Copyright (c) 1985 Conrad C. Huang, Gregory S. Couch, Kenneth C.R.C. Arnold
  4.  *  San Francisco, California
  5.  */
  6.  
  7. # include    "hunt.h"
  8. # include    <signal.h>
  9. # include    <errno.h>
  10. # include    <sys/ioctl.h>
  11. # include    <sys/time.h>
  12.  
  13. # ifndef pdp11
  14. # define    RN    (((Seed = Seed * 11109 + 13849) >> 16) & 0xffff)
  15. # else
  16. # define    RN    ((Seed = Seed * 11109 + 13849) & 0x7fff)
  17. # endif
  18.  
  19. int    Seed = 0;
  20.  
  21.  
  22. SOCKET    Daemon;
  23. char    *First_arg;        /* pointer to argv[0] */
  24. char    *Last_arg;        /* pointer to end of argv/environ */
  25. # ifdef    INTERNET
  26. int    Test_socket;        /* test socket to answer datagrams */
  27. FLAG    inetd_spawned;        /* invoked via inetd */
  28. FLAG    standard_port = TRUE;    /* true if listening on standard port */
  29. u_short    sock_port;        /* port # of tcp listen socket */
  30. u_short    stat_port;        /* port # of statistics tcp socket */
  31. # define    DAEMON_SIZE    (sizeof Daemon)
  32. # else
  33. # define    DAEMON_SIZE    (sizeof Daemon - 1)
  34. # endif
  35.  
  36. extern SIGNAL_TYPE    cleanup();
  37.  
  38. /*
  39.  * main:
  40.  *    The main program.
  41.  */
  42. main(ac, av, ep)
  43. int    ac;
  44. char    **av, **ep;
  45. {
  46.     register PLAYER    *pp;
  47.     register int    had_char;
  48. # ifdef INTERNET
  49.     register long    test_mask;
  50.     u_short        msg;
  51.     short        port_num, reply;
  52.     int        namelen;
  53.     SOCKET        test;
  54. # endif
  55.     static long    read_fds;
  56.     static FLAG    first = TRUE;
  57.     static FLAG    server = FALSE;
  58.     extern int    optind;
  59.     extern char    *optarg;
  60.     int        c;
  61.     static struct timeval    linger = {    90, 0    };
  62.  
  63.     First_arg = av[0];
  64.     if (ep == NULL || *ep == NULL)
  65.         ep = av + ac;
  66.     while (*ep)
  67.         ep++;
  68.     Last_arg = ep[-1] + strlen(ep[-1]);
  69.  
  70.     while ((c = getopt(ac, av, "sp:")) != EOF) {
  71.         switch (c) {
  72.           case 's':
  73.             server = TRUE;
  74.             break;
  75. # ifdef INTERNET
  76.           case 'p':
  77.             standard_port = FALSE;
  78.             Test_port = atoi(optarg);
  79.             break;
  80. # endif
  81.           default:
  82. erred:
  83.             fprintf(stderr, "Usage: %s [-s] [-p port]\n", av[0]);
  84.             exit(1);
  85.         }
  86.     }
  87.     if (optind < ac)
  88.         goto erred;
  89.  
  90.     init();
  91.     Sock_mask = (1 << Socket);
  92.     Stat_mask = (1 << Status);
  93. # ifdef INTERNET
  94.     test_mask = (1 << Test_socket);
  95. # endif
  96.  
  97.  
  98. again:
  99.     do {
  100.         read_fds = Fds_mask;
  101.         errno = 0;
  102.         while (select(Num_fds, &read_fds, (int *) NULL,
  103.             (int *) NULL, (struct timeval *) NULL) < 0)
  104.         {
  105.             if (errno != EINTR)
  106. # ifdef LOG
  107.                 syslog(LOG_WARNING, "select: %m");
  108. # else
  109.                 perror("select");
  110. # endif
  111.             errno = 0;
  112.         }
  113.         Have_inp = read_fds;
  114. # ifdef INTERNET
  115.         if (read_fds & test_mask) {
  116.             namelen = DAEMON_SIZE;
  117.             port_num = htons(sock_port);
  118.             (void) recvfrom(Test_socket, (char *) &msg, sizeof msg,
  119.                 0, (struct sockaddr *) &test, &namelen);
  120.             switch (ntohs(msg)) {
  121.               case C_MESSAGE:
  122.                 if (Nplayer <= 0)
  123.                     break;
  124.                 reply = htons((u_short) Nplayer);
  125.                 (void) sendto(Test_socket, (char *) &reply,
  126.                     sizeof reply, 0,
  127.                     (struct sockaddr *) &test, DAEMON_SIZE);
  128.                 break;
  129.               case C_SCORES:
  130.                 reply = htons(stat_port);
  131.                 (void) sendto(Test_socket, (char *) &reply,
  132.                     sizeof reply, 0,
  133.                     (struct sockaddr *) &test, DAEMON_SIZE);
  134.                 break;
  135.               case C_PLAYER:
  136.               case C_MONITOR:
  137.                 if (msg == C_MONITOR && Nplayer <= 0)
  138.                     break;
  139.                 reply = htons(sock_port);
  140.                 (void) sendto(Test_socket, (char *) &reply,
  141.                     sizeof reply, 0,
  142.                     (struct sockaddr *) &test, DAEMON_SIZE);
  143.                 break;
  144.             }
  145.         }
  146. # endif
  147.         for (;;) {
  148.             had_char = FALSE;
  149.             for (pp = Player; pp < End_player; pp++)
  150.                 if (havechar(pp)) {
  151.                     execute(pp);
  152.                     pp->p_nexec++;
  153.                     had_char++;
  154.                 }
  155. # ifdef MONITOR
  156.             for (pp = Monitor; pp < End_monitor; pp++)
  157.                 if (havechar(pp)) {
  158.                     mon_execute(pp);
  159.                     pp->p_nexec++;
  160.                     had_char++;
  161.                 }
  162. # endif
  163.             if (!had_char)
  164.                 break;
  165.             moveshots();
  166.             for (pp = Player; pp < End_player; )
  167.                 if (pp->p_death[0] != '\0')
  168.                     zap(pp, TRUE);
  169.                 else
  170.                     pp++;
  171. # ifdef MONITOR
  172.             for (pp = Monitor; pp < End_monitor; )
  173.                 if (pp->p_death[0] != '\0')
  174.                     zap(pp, FALSE);
  175.                 else
  176.                     pp++;
  177. # endif
  178.         }
  179.         if (read_fds & Sock_mask)
  180.             if (answer()) {
  181. # ifdef INTERNET
  182.                 if (first && standard_port)
  183.                     faketalk();
  184. # endif
  185.                 first = FALSE;
  186.             }
  187.         if (read_fds & Stat_mask)
  188.             send_stats();
  189.         for (pp = Player; pp < End_player; pp++) {
  190.             if (read_fds & pp->p_mask)
  191.                 sendcom(pp, READY, pp->p_nexec);
  192.             pp->p_nexec = 0;
  193.             (void) fflush(pp->p_output);
  194.         }
  195. # ifdef MONITOR
  196.         for (pp = Monitor; pp < End_monitor; pp++) {
  197.             if (read_fds & pp->p_mask)
  198.                 sendcom(pp, READY, pp->p_nexec);
  199.             pp->p_nexec = 0;
  200.             (void) fflush(pp->p_output);
  201.         }
  202. # endif
  203.     } while (Nplayer > 0);
  204.  
  205.     read_fds = Fds_mask;
  206.     if (select(Num_fds, &read_fds, (int *) NULL, (int *) NULL,
  207.            &linger) > 0) {
  208.         goto again;
  209.     }
  210.     if (server) {
  211.         clear_scores();
  212.         makemaze();
  213.         clearwalls();
  214. # ifdef BOOTS
  215.         makeboots();
  216. # endif
  217.         first = TRUE;
  218.         goto again;
  219.     }
  220.  
  221. # ifdef MONITOR
  222.     for (pp = Monitor; pp < End_monitor; )
  223.         zap(pp, FALSE);
  224. # endif
  225.     cleanup(0);
  226. }
  227.  
  228. /*
  229.  * init:
  230.  *    Initialize the global parameters.
  231.  */
  232. init()
  233. {
  234.     register int    i;
  235. # ifdef    INTERNET
  236.     auto SOCKET    test_port;
  237.     auto int    msg;
  238.     auto int    len;
  239. # endif
  240.  
  241. # ifdef linux
  242.     extern char *Stat_name;
  243.     extern char *Sock_name;
  244. # endif
  245.  
  246. # ifndef DEBUG
  247. # ifdef TIOCNOTTY
  248.     (void) ioctl(fileno(stdout), TIOCNOTTY, NULL);
  249. # endif
  250.     (void) setpgrp(getpid(), getpid());
  251.     (void) signal(SIGHUP, SIG_IGN);
  252.     (void) signal(SIGINT, SIG_IGN);
  253.     (void) signal(SIGQUIT, SIG_IGN);
  254.     (void) signal(SIGTERM, cleanup);
  255. # endif
  256.  
  257.     (void) chdir("/usr/tmp");    /* just in case it core dumps */
  258.     (void) umask(0);        /* No privacy at all! */
  259.     (void) signal(SIGPIPE, SIG_IGN);
  260.  
  261. # ifdef LOG
  262. # ifdef    SYSLOG_43
  263.     openlog("HUNT", LOG_PID, LOG_DAEMON);
  264. # endif
  265. # ifdef    SYSLOG_42
  266.     openlog("HUNT", LOG_PID);
  267. # endif
  268. # endif
  269.  
  270.     /*
  271.      * Initialize statistics socket
  272.      */
  273. # ifdef    INTERNET
  274.     Daemon.sin_family = SOCK_FAMILY;
  275.     Daemon.sin_addr.s_addr = INADDR_ANY;
  276.     Daemon.sin_port = 0;
  277. # else
  278.     Daemon.sun_family = SOCK_FAMILY;
  279.     (void) strcpy(Daemon.sun_path, Stat_name);
  280. # endif
  281.  
  282.     Status = socket(SOCK_FAMILY, SOCK_STREAM, 0);
  283.     if (bind(Status, (struct sockaddr *) &Daemon, DAEMON_SIZE) < 0) {
  284.         if (errno == EADDRINUSE)
  285.             exit(0);
  286.         else {
  287. # ifdef LOG
  288.             syslog(LOG_ERR, "bind: %m");
  289. # else
  290.             perror("bind");
  291. # endif
  292.             cleanup(1);
  293.         }
  294.     }
  295.     (void) listen(Status, 5);
  296.  
  297. # ifdef INTERNET
  298.     len = sizeof (SOCKET);
  299.     if (getsockname(Status, (struct sockaddr *) &Daemon, &len) < 0)  {
  300. # ifdef LOG
  301.         syslog(LOG_ERR, "getsockname: %m");
  302. # else
  303.         perror("getsockname");
  304. # endif
  305.         exit(1);
  306.     }
  307.     stat_port = ntohs(Daemon.sin_port);
  308. # endif
  309.  
  310.     /*
  311.      * Initialize main socket
  312.      */
  313. # ifdef    INTERNET
  314.     Daemon.sin_family = SOCK_FAMILY;
  315.     Daemon.sin_addr.s_addr = INADDR_ANY;
  316.     Daemon.sin_port = 0;
  317. # else
  318.     Daemon.sun_family = SOCK_FAMILY;
  319.     (void) strcpy(Daemon.sun_path, Sock_name);
  320. # endif
  321.  
  322.     Socket = socket(SOCK_FAMILY, SOCK_STREAM, 0);
  323. # if defined(INTERNET)
  324.     msg = 1;
  325.     if (setsockopt(Socket, SOL_SOCKET, SO_USELOOPBACK, &msg, sizeof msg)<0)
  326. # ifdef LOG
  327.         syslog(LOG_WARNING, "setsockopt loopback %m");
  328. # else
  329.         perror("setsockopt loopback");
  330. # endif
  331. # endif
  332.     if (bind(Socket, (struct sockaddr *) &Daemon, DAEMON_SIZE) < 0) {
  333.         if (errno == EADDRINUSE)
  334.             exit(0);
  335.         else {
  336. # ifdef LOG
  337.             syslog(LOG_ERR, "bind: %m");
  338. # else
  339.             perror("bind");
  340. # endif
  341.             cleanup(1);
  342.         }
  343.     }
  344.     (void) listen(Socket, 5);
  345.  
  346. # ifdef INTERNET
  347.     len = sizeof (SOCKET);
  348.     if (getsockname(Socket, (struct sockaddr *) &Daemon, &len) < 0)  {
  349. # ifdef LOG
  350.         syslog(LOG_ERR, "getsockname: %m");
  351. # else
  352.         perror("getsockname");
  353. # endif
  354.         exit(1);
  355.     }
  356.     sock_port = ntohs(Daemon.sin_port);
  357. # endif
  358.  
  359.     /*
  360.      * Initialize minimal select mask
  361.      */
  362.     Fds_mask = (1 << Socket) | (1 << Status);
  363.     Num_fds = ((Socket > Status) ? Socket : Status) + 1;
  364.  
  365. # ifdef INTERNET
  366.     len = sizeof (SOCKET);
  367.     if (getsockname(0, (struct sockaddr *) &test_port, &len) >= 0
  368.     && test_port.sin_family == AF_INET) {
  369.         inetd_spawned = TRUE;
  370.         Test_socket = 0;
  371.         if (test_port.sin_port != htons((u_short) Test_port)) {
  372.             standard_port = FALSE;
  373.             Test_port = ntohs(test_port.sin_port);
  374.         }
  375.     } else {
  376.         test_port = Daemon;
  377.         test_port.sin_port = htons((u_short) Test_port);
  378.  
  379.         Test_socket = socket(SOCK_FAMILY, SOCK_DGRAM, 0);
  380.         if (bind(Test_socket, (struct sockaddr *) &test_port,
  381.             DAEMON_SIZE) < 0) {
  382. # ifdef LOG
  383.             syslog(LOG_ERR, "bind: %m");
  384. # else
  385.             perror("bind");
  386. # endif
  387.             exit(1);
  388.         }
  389.         (void) listen(Test_socket, 5);
  390.     }
  391.  
  392.     Fds_mask |= (1 << Test_socket);
  393.     if (Test_socket + 1 > Num_fds)
  394.         Num_fds = Test_socket + 1;
  395. # endif
  396.  
  397.     Seed = getpid() + time((time_t *) NULL);
  398.     makemaze();
  399. # ifdef BOOTS
  400.     makeboots();
  401. # endif
  402.  
  403.     for (i = 0; i < NASCII; i++)
  404.         See_over[i] = TRUE;
  405.     See_over[DOOR] = FALSE;
  406.     See_over[WALL1] = FALSE;
  407.     See_over[WALL2] = FALSE;
  408.     See_over[WALL3] = FALSE;
  409. # ifdef REFLECT
  410.     See_over[WALL4] = FALSE;
  411.     See_over[WALL5] = FALSE;
  412. # endif
  413.  
  414. }
  415.  
  416. # ifdef BOOTS
  417. /*
  418.  * makeboots:
  419.  *    Put the boots in the maze
  420.  */
  421. makeboots()
  422. {
  423.     register int    x, y;
  424.     register PLAYER    *pp;
  425.  
  426.     do {
  427.         x = rand_num(WIDTH - 1) + 1;
  428.         y = rand_num(HEIGHT - 1) + 1;
  429.     } while (Maze[y][x] != SPACE);
  430.     Maze[y][x] = BOOT_PAIR;
  431.     for (pp = Boot; pp < &Boot[NBOOTS]; pp++)
  432.         pp->p_flying = -1;
  433. }
  434. # endif
  435.  
  436.  
  437. /*
  438.  * checkdam:
  439.  *    Check the damage to the given player, and see if s/he is killed
  440.  */
  441. checkdam(ouch, gotcha, credit, amt, shot_type)
  442. register PLAYER    *ouch, *gotcha;
  443. register IDENT    *credit;
  444. int        amt;
  445. char        shot_type;
  446. {
  447.     register char    *cp;
  448.  
  449.     if (ouch->p_death[0] != '\0')
  450.         return;
  451. # ifdef BOOTS
  452.     if (shot_type == SLIME)
  453.         switch (ouch->p_nboots) {
  454.           default:
  455.             break;
  456.           case 1:
  457.             amt = (amt + 1) / 2;
  458.             break;
  459.           case 2:
  460.             if (gotcha != NULL)
  461.                 message(gotcha, "He has boots on!");
  462.             return;
  463.         }
  464. # endif
  465.     ouch->p_damage += amt;
  466.     if (ouch->p_damage <= ouch->p_damcap) {
  467.         (void) sprintf(Buf, "%2d", ouch->p_damage);
  468.         cgoto(ouch, STAT_DAM_ROW, STAT_VALUE_COL);
  469.         outstr(ouch, Buf, 2);
  470.         return;
  471.     }
  472.  
  473.     /* Someone DIED */
  474.     switch (shot_type) {
  475.       default:
  476.         cp = "Killed";
  477.         break;
  478. # ifdef FLY
  479.       case FALL:
  480.         cp = "Killed on impact";
  481.         break;
  482. # endif
  483.       case KNIFE:
  484.         cp = "Stabbed to death";
  485.         ouch->p_ammo = 0;        /* No exploding */
  486.         break;
  487.       case SHOT:
  488.         cp = "Shot to death";
  489.         break;
  490.       case GRENADE:
  491.       case SATCHEL:
  492.       case BOMB:
  493.         cp = "Bombed";
  494.         break;
  495.       case MINE:
  496.       case GMINE:
  497.         cp = "Blown apart";
  498.         break;
  499. # ifdef    OOZE
  500.       case SLIME:
  501.         cp = "Slimed";
  502.         if (credit != NULL)
  503.             credit->i_slime++;
  504.         break;
  505. # endif
  506. # ifdef    VOLCANO
  507.       case LAVA:
  508.         cp = "Baked";
  509.         break;
  510. # endif
  511. # ifdef DRONE
  512.       case DSHOT:
  513.         cp = "Eliminated";
  514.         break;
  515. # endif
  516.     }
  517.     if (credit == NULL) {
  518.         (void) sprintf(ouch->p_death, "| %s by %s |", cp,
  519.             (shot_type == MINE || shot_type == GMINE) ?
  520.             "a mine" : "act of God");
  521.         return;
  522.     }
  523.  
  524.     (void) sprintf(ouch->p_death, "| %s by %s |", cp, credit->i_name);
  525.  
  526.     if (ouch == gotcha) {        /* No use killing yourself */
  527.         credit->i_kills--;
  528.         credit->i_bkills++;
  529.     }
  530.     else if (ouch->p_ident->i_team == ' '
  531.     || ouch->p_ident->i_team != credit->i_team) {
  532.         credit->i_kills++;
  533.         credit->i_gkills++;
  534.     }
  535.     else {
  536.         credit->i_kills--;
  537.         credit->i_bkills++;
  538.     }
  539.     credit->i_score = credit->i_kills / (double) credit->i_entries;
  540.     ouch->p_ident->i_deaths++;
  541.     if (ouch->p_nchar == 0)
  542.         ouch->p_ident->i_stillb++;
  543.     if (gotcha == NULL)
  544.         return;
  545.     gotcha->p_damcap += STABDAM;
  546.     gotcha->p_damage -= STABDAM;
  547.     if (gotcha->p_damage < 0)
  548.         gotcha->p_damage = 0;
  549.     (void) sprintf(Buf, "%2d/%2d", gotcha->p_damage, gotcha->p_damcap);
  550.     cgoto(gotcha, STAT_DAM_ROW, STAT_VALUE_COL);
  551.     outstr(gotcha, Buf, 5);
  552.     (void) sprintf(Buf, "%3d", (gotcha->p_damcap - MAXDAM) / 2);
  553.     cgoto(gotcha, STAT_KILL_ROW, STAT_VALUE_COL);
  554.     outstr(gotcha, Buf, 3);
  555.     (void) sprintf(Buf, "%5.2f", gotcha->p_ident->i_score);
  556.     for (ouch = Player; ouch < End_player; ouch++) {
  557.         cgoto(ouch, STAT_PLAY_ROW + 1 + (gotcha - Player),
  558.             STAT_NAME_COL);
  559.         outstr(ouch, Buf, 5);
  560.     }
  561. # ifdef MONITOR
  562.     for (ouch = Monitor; ouch < End_monitor; ouch++) {
  563.         cgoto(ouch, STAT_PLAY_ROW + 1 + (gotcha - Player),
  564.             STAT_NAME_COL);
  565.         outstr(ouch, Buf, 5);
  566.     }
  567. # endif
  568. }
  569.  
  570. /*
  571.  * zap:
  572.  *    Kill off a player and take him out of the game.
  573.  */
  574. zap(pp, was_player)
  575. register PLAYER    *pp;
  576. FLAG        was_player;
  577. {
  578.     register int    i, len;
  579.     register BULLET    *bp;
  580.     register PLAYER    *np;
  581.     register int    x, y;
  582.     int        savefd, savemask;
  583.  
  584.     if (was_player) {
  585.         if (pp->p_undershot)
  586.             fixshots(pp->p_y, pp->p_x, pp->p_over);
  587.         drawplayer(pp, FALSE);
  588.         Nplayer--;
  589.     }
  590.  
  591.     len = strlen(pp->p_death);    /* Display the cause of death */
  592.     x = (WIDTH - len) / 2;
  593.     cgoto(pp, HEIGHT / 2, x);
  594.     outstr(pp, pp->p_death, len);
  595.     for (i = 1; i < len; i++)
  596.         pp->p_death[i] = '-';
  597.     pp->p_death[0] = '+';
  598.     pp->p_death[len - 1] = '+';
  599.     cgoto(pp, HEIGHT / 2 - 1, x);
  600.     outstr(pp, pp->p_death, len);
  601.     cgoto(pp, HEIGHT / 2 + 1, x);
  602.     outstr(pp, pp->p_death, len);
  603.     cgoto(pp, HEIGHT, 0);
  604.  
  605.     savefd = pp->p_fd;
  606.     savemask = pp->p_mask;
  607.  
  608. # ifdef MONITOR
  609.     if (was_player) {
  610. # endif
  611.         for (bp = Bullets; bp != NULL; bp = bp->b_next) {
  612.             if (bp->b_owner == pp)
  613.                 bp->b_owner = NULL;
  614.             if (bp->b_x == pp->p_x && bp->b_y == pp->p_y)
  615.                 bp->b_over = SPACE;
  616.         }
  617.  
  618.         i = rand_num(pp->p_ammo);
  619.         x = rand_num(pp->p_ammo);
  620.         if (x > i)
  621.             i = x;
  622.         if (pp->p_ammo == 0)
  623.             x = 0;
  624.         else if (i == pp->p_ammo - 1) {
  625.             x = pp->p_ammo;
  626.             len = SLIME;
  627.         }
  628.         else {
  629.             for (x = MAXBOMB - 1; x > 0; x--)
  630.                 if (i >= shot_req[x])
  631.                     break;
  632.             for (y = MAXSLIME - 1; y > 0; y--)
  633.                 if (i >= slime_req[y])
  634.                     break;
  635.             if (y >= 0 && slime_req[y] > shot_req[x]) {
  636.                 x = slime_req[y];
  637.                 len = SLIME;
  638.             }
  639.             else if (x != 0) {
  640.                 len = shot_type[x];
  641.                 x = shot_req[x];
  642.             }
  643.         }
  644.         if (x > 0) {
  645.             (void) add_shot(len, pp->p_y, pp->p_x, pp->p_face, x,
  646.                 (PLAYER *) NULL, TRUE, SPACE);
  647.             (void) sprintf(Buf, "%s detonated.",
  648.                 pp->p_ident->i_name);
  649.             for (np = Player; np < End_player; np++)
  650.                 message(np, Buf);
  651. # ifdef MONITOR
  652.             for (np = Monitor; np < End_monitor; np++)
  653.                 message(np, Buf);
  654. # endif
  655. # ifdef BOOTS
  656.             while (pp->p_nboots-- > 0) {
  657.                 for (np = Boot; np < &Boot[NBOOTS]; np++)
  658.                     if (np->p_flying < 0)
  659.                         break;
  660.                 if (np >= &Boot[NBOOTS])
  661.                     abort(1, "Too many boots");
  662.                 np->p_undershot = FALSE;
  663.                 np->p_x = pp->p_x;
  664.                 np->p_y = pp->p_y;
  665.                 np->p_flying = rand_num(20);
  666.                 np->p_flyx = 2 * rand_num(6) - 5;
  667.                 np->p_flyy = 2 * rand_num(6) - 5;
  668.                 np->p_over = SPACE;
  669.                 np->p_face = BOOT;
  670.                 showexpl(np->p_y, np->p_x, BOOT);
  671.             }
  672. # endif
  673.         }
  674. # ifdef BOOTS
  675.         else if (pp->p_nboots > 0) {
  676.             if (pp->p_nboots == 2)
  677.                 Maze[pp->p_y][pp->p_x] = BOOT_PAIR;
  678.             else
  679.                 Maze[pp->p_y][pp->p_x] = BOOT;
  680.             if (pp->p_undershot)
  681.                 fixshots(pp->p_y, pp->p_x,
  682.                     Maze[pp->p_y][pp->p_x]);
  683.         }
  684. # endif
  685.  
  686. # ifdef VOLCANO
  687.         volcano += pp->p_ammo - x;
  688.         if (rand_num(100) < volcano / 50) {
  689.             do {
  690.                 x = rand_num(WIDTH / 2) + WIDTH / 4;
  691.                 y = rand_num(HEIGHT / 2) + HEIGHT / 4;
  692.             } while (Maze[y][x] != SPACE);
  693.             (void) add_shot(LAVA, y, x, LEFTS, volcano,
  694.                 (PLAYER *) NULL, TRUE, SPACE);
  695.             for (np = Player; np < End_player; np++)
  696.                 message(np, "Volcano eruption.");
  697.             volcano = 0;
  698.         }
  699. # endif
  700.  
  701. # ifdef    DRONE
  702.         if (rand_num(100) < 2) {
  703.             do {
  704.                 x = rand_num(WIDTH / 2) + WIDTH / 4;
  705.                 y = rand_num(HEIGHT / 2) + HEIGHT / 4;
  706.             } while (Maze[y][x] != SPACE);
  707.             add_shot(DSHOT, y, x, rand_dir(),
  708.                 shot_req[MINDSHOT +
  709.                 rand_num(MAXBOMB - MINDSHOT)],
  710.                 (PLAYER *) NULL, FALSE, SPACE);
  711.         }
  712. # endif
  713.  
  714.         sendcom(pp, ENDWIN);
  715.         (void) putc(' ', pp->p_output);
  716.         (void) fclose(pp->p_output);
  717.  
  718.         End_player--;
  719.         if (pp != End_player) {
  720.             memcpy(pp, End_player, sizeof (PLAYER));
  721.             (void) sprintf(Buf, "%5.2f%c%-10.10s %c",
  722.                 pp->p_ident->i_score, stat_char(pp),
  723.                 pp->p_ident->i_name, pp->p_ident->i_team);
  724.             i = STAT_PLAY_ROW + 1 + (pp - Player);
  725.             for (np = Player; np < End_player; np++) {
  726.                 cgoto(np, i, STAT_NAME_COL);
  727.                 outstr(np, Buf, STAT_NAME_LEN);
  728.             }
  729. # ifdef MONITOR
  730.             for (np = Monitor; np < End_monitor; np++) {
  731.                 cgoto(np, i, STAT_NAME_COL);
  732.                 outstr(np, Buf, STAT_NAME_LEN);
  733.             }
  734. # endif
  735.         }
  736.  
  737.         /* Erase the last player */
  738.         i = STAT_PLAY_ROW + 1 + Nplayer;
  739.         for (np = Player; np < End_player; np++) {
  740.             cgoto(np, i, STAT_NAME_COL);
  741.             ce(np);
  742.         }
  743. # ifdef MONITOR
  744.         for (np = Monitor; np < End_monitor; np++) {
  745.             cgoto(np, i, STAT_NAME_COL);
  746.             ce(np);
  747.         }
  748.     }
  749.     else {
  750.         sendcom(pp, ENDWIN);
  751.         (void) putc(LAST_PLAYER, pp->p_output);
  752.         (void) fclose(pp->p_output);
  753.  
  754.         End_monitor--;
  755.         if (pp != End_monitor) {
  756.             memcpy(pp, End_monitor, sizeof (PLAYER));
  757.             (void) sprintf(Buf, "%5.5s %-10.10s %c", " ",
  758.                 pp->p_ident->i_name, pp->p_ident->i_team);
  759.             i = STAT_MON_ROW + 1 + (pp - Player);
  760.             for (np = Player; np < End_player; np++) {
  761.                 cgoto(np, i, STAT_NAME_COL);
  762.                 outstr(np, Buf, STAT_NAME_LEN);
  763.             }
  764.             for (np = Monitor; np < End_monitor; np++) {
  765.                 cgoto(np, i, STAT_NAME_COL);
  766.                 outstr(np, Buf, STAT_NAME_LEN);
  767.             }
  768.         }
  769.  
  770.         /* Erase the last monitor */
  771.         i = STAT_MON_ROW + 1 + (End_monitor - Monitor);
  772.         for (np = Player; np < End_player; np++) {
  773.             cgoto(np, i, STAT_NAME_COL);
  774.             ce(np);
  775.         }
  776.         for (np = Monitor; np < End_monitor; np++) {
  777.             cgoto(np, i, STAT_NAME_COL);
  778.             ce(np);
  779.         }
  780.  
  781.     }
  782. # endif
  783.  
  784.     Fds_mask &= ~savemask;
  785.     if (Num_fds == savefd + 1) {
  786.         Num_fds = Socket;
  787. # ifdef INTERNET
  788.         if (Test_socket > Socket)
  789.             Num_fds = Test_socket;
  790. # endif
  791.         for (np = Player; np < End_player; np++)
  792.             if (np->p_fd > Num_fds)
  793.                 Num_fds = np->p_fd;
  794. # ifdef MONITOR
  795.         for (np = Monitor; np < End_monitor; np++)
  796.             if (np->p_fd > Num_fds)
  797.                 Num_fds = np->p_fd;
  798. # endif
  799.         Num_fds++;
  800.     }
  801. }
  802.  
  803. /*
  804.  * rand_num:
  805.  *    Return a random number in a given range.
  806.  */
  807. rand_num(range)
  808. int    range;
  809. {
  810.     return (range == 0 ? 0 : RN % range);
  811. }
  812.  
  813. /*
  814.  * havechar:
  815.  *    Check to see if we have any characters in the input queue; if
  816.  *    we do, read them, stash them away, and return TRUE; else return
  817.  *    FALSE.
  818.  */
  819. havechar(pp)
  820. register PLAYER    *pp;
  821. {
  822.     extern int    errno;
  823.  
  824.     if (pp->p_ncount < pp->p_nchar)
  825.         return TRUE;
  826.     if (!(Have_inp & pp->p_mask))
  827.         return FALSE;
  828.     Have_inp &= ~pp->p_mask;
  829. check_again:
  830.     errno = 0;
  831.     if ((pp->p_nchar = read(pp->p_fd, pp->p_cbuf, sizeof pp->p_cbuf)) <= 0)
  832.     {
  833.         if (errno == EINTR)
  834.             goto check_again;
  835.         pp->p_cbuf[0] = 'q';
  836.     }
  837.     pp->p_ncount = 0;
  838.     return TRUE;
  839. }
  840.  
  841. /*
  842.  * cleanup:
  843.  *    Exit with the given value, cleaning up any droppings lying around
  844.  */
  845. SIGNAL_TYPE
  846. cleanup(eval)
  847. int    eval;
  848. {
  849.     register PLAYER    *pp;
  850.  
  851.     for (pp = Player; pp < End_player; pp++) {
  852.         cgoto(pp, HEIGHT, 0);
  853.         sendcom(pp, ENDWIN);
  854.         (void) putc(LAST_PLAYER, pp->p_output);
  855.         (void) fclose(pp->p_output);
  856.     }
  857. # ifdef MONITOR
  858.     for (pp = Monitor; pp < End_monitor; pp++) {
  859.         cgoto(pp, HEIGHT, 0);
  860.         sendcom(pp, ENDWIN);
  861.         (void) putc(LAST_PLAYER, pp->p_output);
  862.         (void) fclose(pp->p_output);
  863.     }
  864. # endif
  865.     (void) close(Socket);
  866. # ifdef AF_UNIX_HACK
  867.     (void) unlink(Sock_name);
  868. # endif
  869.  
  870.     exit(eval);
  871. }
  872.  
  873. /*
  874.  * send_stats:
  875.  *    Print stats to requestor
  876.  */
  877. send_stats()
  878. {
  879.     register IDENT    *ip;
  880.     register FILE    *fp;
  881.     int        s;
  882.     SOCKET        sockstruct;
  883.     int        socklen;
  884.  
  885.     /*
  886.      * Get the output stream ready
  887.      */
  888. # ifdef INTERNET
  889.     socklen = sizeof sockstruct;
  890. # else
  891.     socklen = sizeof sockstruct - 1;
  892. # endif
  893.     s = accept(Status, (struct sockaddr *) &sockstruct, &socklen);
  894.     if (s < 0) {
  895.         if (errno == EINTR)
  896.             return;
  897. # ifdef LOG
  898.         syslog(LOG_ERR, "accept: %m");
  899. # else
  900.         perror("accept");
  901. # endif
  902.         return;
  903.     }
  904.     fp = fdopen(s, "w");
  905.     if (fp == NULL) {
  906. # ifdef LOG
  907.         syslog(LOG_ERR, "fdopen: %m");
  908. # else
  909.         perror("fdopen");
  910. # endif
  911.         (void) close(s);
  912.         return;
  913.     }
  914.  
  915.     /*
  916.      * Send output to requestor
  917.      */
  918.     fputs("Name\t\tScore\tDucked\tAbsorb\tFaced\tShot\tRobbed\tMissed\tSlimeK\n", fp);
  919.     for (ip = Scores; ip != NULL; ip = ip->i_next) {
  920.         fprintf(fp, "%s\t", ip->i_name);
  921.         if (strlen(ip->i_name) < 8)
  922.             putc('\t', fp);
  923.         fprintf(fp, "%.2f\t%d\t%d\t%d\t%d\t%d\t%d\t%d\n",
  924.             ip->i_score, ip->i_ducked, ip->i_absorbed,
  925.             ip->i_faced, ip->i_shot, ip->i_robbed,
  926.             ip->i_missed, ip->i_slime);
  927.     }
  928.     fputs("\n\nName\t\tEnemy\tFriend\tDeaths\tStill\tSaved\n", fp);
  929.     for (ip = Scores; ip != NULL; ip = ip->i_next) {
  930.         if (ip->i_team == ' ') {
  931.             fprintf(fp, "%s\t", ip->i_name);
  932.             if (strlen(ip->i_name) < 8)
  933.                 putc('\t', fp);
  934.         }
  935.         else {
  936.             fprintf(fp, "%s[%c]\t", ip->i_name, ip->i_team);
  937.             if (strlen(ip->i_name) + 3 < 8)
  938.                 putc('\t', fp);
  939.         }
  940.         fprintf(fp, "%d\t%d\t%d\t%d\t%d\n",
  941.             ip->i_gkills, ip->i_bkills, ip->i_deaths,
  942.             ip->i_stillb, ip->i_saved);
  943.     }
  944.  
  945.     (void) fclose(fp);
  946. }
  947.  
  948. /*
  949.  * clear_scores:
  950.  *    Clear out the scores so the next session start clean
  951.  */
  952. clear_scores()
  953. {
  954.     register IDENT    *ip, *nextip;
  955.  
  956.     for (ip = Scores; ip != NULL; ip = nextip) {
  957.         nextip = ip->i_next;
  958.         (void) free((char *) ip);
  959.     }
  960.     Scores = NULL;
  961. }
  962.