home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / games / volume15 / robothnt / part02 < prev    next >
Encoding:
Text File  |  1993-01-26  |  54.4 KB  |  2,480 lines

  1. Path: uunet!news.tek.com!master!saab!billr
  2. From: billr@saab.CNA.TEK.COM (Bill Randle)
  3. Newsgroups: comp.sources.games
  4. Subject: v15i033:  robot_hunt - original hunt with a robot, Part02/04
  5. Message-ID: <4189@master.CNA.TEK.COM>
  6. Date: 14 Jan 93 03:13:41 GMT
  7. Sender: news@master.CNA.TEK.COM
  8. Lines: 2468
  9. Approved: billr@saab.CNA.TEK.COM
  10. Xref: uunet comp.sources.games:1532
  11.  
  12. Submitted-by: whatis@ucsd.edu (Steve Boswell)
  13. Posting-number: Volume 15, Issue 33
  14. Archive-name: robot_hunt/Part02
  15. Environment: Curses, Sockets
  16.  
  17.  
  18. #! /bin/sh
  19. # This is a shell archive.  Remove anything before this line, then unpack
  20. # it by saving it into a file and typing "sh file".  To overwrite existing
  21. # files, type "sh file -c".  You can also feed this as standard input via
  22. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  23. # will see the following message at the end:
  24. #        "End of archive 2 (of 4)."
  25. # Contents:  driver.c extern.c hunt.c shots.c
  26. # Wrapped by billr@saab on Wed Jan 13 19:04:32 1993
  27. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  28. if test -f 'driver.c' -a "${1}" != "-c" ; then 
  29.   echo shar: Will not clobber existing file \"'driver.c'\"
  30. else
  31. echo shar: Extracting \"'driver.c'\" \(15418 characters\)
  32. sed "s/^X//" >'driver.c' <<'END_OF_FILE'
  33. X/*
  34. X * Copyright (c) 1985 Regents of the University of California.
  35. X * All rights reserved.
  36. X *
  37. X * Redistribution and use in source and binary forms are permitted
  38. X * provided that the above copyright notice and this paragraph are
  39. X * duplicated in all such forms and that any documentation,
  40. X * advertising materials, and other materials related to such
  41. X * distribution and use acknowledge that the software was developed
  42. X * by the University of California, Berkeley.  The name of the
  43. X * University may not be used to endorse or promote products derived
  44. X * from this software without specific prior written permission.
  45. X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  46. X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  47. X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  48. X */
  49. X
  50. X#ifndef lint
  51. Xchar copyright[] =
  52. X"@(#) Copyright (c) 1985 Regents of the University of California.\n\
  53. X All rights reserved.\n";
  54. X#endif /* not lint */
  55. X
  56. X#ifndef lint
  57. Xstatic char sccsid[] = "@(#)driver.c    5.3 (Berkeley) 6/27/88";
  58. X#endif /* not lint */
  59. X
  60. X/*
  61. X *  Hunt
  62. X *  Copyright (c) 1985 Conrad C. Huang, Gregory S. Couch, Kenneth C.R.C. Arnold
  63. X *  San Francisco, California
  64. X */
  65. X
  66. X# include    "hunt.h"
  67. X# include    <signal.h>
  68. X# include    <errno.h>
  69. X# include    <sys/ioctl.h>
  70. X# include    <sys/time.h>
  71. Xextern int Seed;
  72. X
  73. X# ifdef CONSTANT_MOVE
  74. Xstatic struct itimerval    Timing;
  75. X# endif CONSTANT_MOVE
  76. X
  77. XSOCKET    Daemon;
  78. X# ifdef    INTERNET
  79. Xint    Test_socket;        /* test socket to answer datagrams */
  80. X# define    DAEMON_SIZE    (sizeof Daemon)
  81. X# else INTERNET
  82. X# define    DAEMON_SIZE    (sizeof Daemon - 1)
  83. X# endif    INTERNET
  84. X
  85. X/*
  86. X * main:
  87. X *    The main program.
  88. X */
  89. Xmain()
  90. X{
  91. X    register PLAYER    *pp;
  92. X    register int    had_char;
  93. X# ifdef INTERNET
  94. X    register long    test_mask;
  95. X    int        msg;
  96. X    int        namelen;
  97. X    SOCKET        test;
  98. X# endif INTERNET
  99. X# ifdef CONSTANT_MOVE
  100. X    register int    enable_alarm, disable_alarm;
  101. X# endif CONSTANT_MOVE
  102. X    static long    read_fds;
  103. X
  104. X    init();
  105. X    Sock_mask = (1 << Socket);
  106. X# ifdef INTERNET
  107. X    test_mask = (1 << Test_socket);
  108. X# endif INTERNET
  109. X
  110. X# ifdef CONSTANT_MOVE
  111. X    enable_alarm = sigblock(0);
  112. X    disable_alarm = enable_alarm | (1 << (SIGALRM - 1));
  113. X    (void) sigsetmask(disable_alarm);
  114. X    (void) signal(SIGALRM, moveshots);
  115. X# endif CONSTANT_MOVE
  116. X
  117. X    while (Nplayer > 0) {
  118. X# ifdef CONSTANT_MOVE
  119. X        (void) sigsetmask(enable_alarm);
  120. X# endif CONSTANT_MOVE
  121. X        read_fds = Fds_mask;
  122. X        errno = 0;
  123. X# ifndef OLDIPC
  124. X        while (select(Num_fds, &read_fds, (int *) NULL,
  125. X            (int *) NULL, (struct timeval *) NULL) < 0)
  126. X# else OLDIPC
  127. X        while (select(20, &read_fds, NULL, 32767) < 0)
  128. X# endif OLDIPC
  129. X        {
  130. X            if (errno != EINTR)
  131. X                perror("select");
  132. X            if (Nplayer == 0)
  133. X                goto out;
  134. X            errno = 0;
  135. X        }
  136. X        Have_inp = read_fds;
  137. X# ifdef CONSTANT_MOVE
  138. X        (void) sigsetmask(disable_alarm);
  139. X# endif CONSTANT_MOVE
  140. X# ifdef INTERNET
  141. X        if (read_fds & test_mask) {
  142. X            namelen = DAEMON_SIZE;
  143. X# ifndef OLDIPC
  144. X            (void) recvfrom(Test_socket, (char *) &msg, sizeof msg,
  145. X                0, (struct sockaddr *) &test, &namelen);
  146. X            (void) sendto(Test_socket, (char *) &msg, sizeof msg,
  147. X                0, (struct sockaddr *) &test, DAEMON_SIZE);
  148. X# else OLDIPC
  149. X            (void) receive(Test_socket, (struct sockaddr *) &test,
  150. X                (char *) &msg, sizeof msg);
  151. X            (void) send(Test_socket, (struct sockaddr *) &test,
  152. X                (char *) &msg, sizeof msg);
  153. X# endif OLDIPC
  154. X        }
  155. X# endif INTERNET
  156. X        for (;;) {
  157. X            had_char = FALSE;
  158. X            for (pp = Player; pp < End_player; pp++)
  159. X                if (havechar(pp)) {
  160. X                    execute(pp);
  161. X                    pp->p_nexec++;
  162. X                    had_char++;
  163. X                }
  164. X# ifdef MONITOR
  165. X            for (pp = Monitor; pp < End_monitor; pp++)
  166. X                if (havechar(pp)) {
  167. X                    mon_execute(pp);
  168. X                    pp->p_nexec++;
  169. X                    had_char++;
  170. X                }
  171. X# endif MONITOR
  172. X            if (!had_char)
  173. X                break;
  174. X# ifdef CONSTANT_MOVE
  175. X            for (pp = Player; pp < End_player; pp++) {
  176. X                look(pp);
  177. X                sendcom(pp, REFRESH);
  178. X            }
  179. X# ifdef MONITOR
  180. X            for (pp = Monitor; pp < End_monitor; pp++)
  181. X                sendcom(pp, REFRESH);
  182. X# endif MONITOR
  183. X# else CONSTANT_MOVE
  184. X            moveshots();
  185. X# endif CONSTANT_MOVE
  186. X            for (pp = Player; pp < End_player; )
  187. X                if (pp->p_death[0] != '\0')
  188. X                    zap(pp, TRUE);
  189. X                else
  190. X                    pp++;
  191. X# ifdef MONITOR
  192. X            for (pp = Monitor; pp < End_monitor; )
  193. X                if (pp->p_death[0] != '\0')
  194. X                    zap(pp, FALSE);
  195. X                else
  196. X                    pp++;
  197. X# endif MONITOR
  198. X        }
  199. X        if (read_fds & Sock_mask)
  200. X            answer();
  201. X        for (pp = Player; pp < End_player; pp++) {
  202. X            if (read_fds & pp->p_mask)
  203. X                sendcom(pp, READY, pp->p_nexec);
  204. X            pp->p_nexec = 0;
  205. X            (void) fflush(pp->p_output);
  206. X        }
  207. X# ifdef MONITOR
  208. X        for (pp = Monitor; pp < End_monitor; pp++) {
  209. X            if (read_fds & pp->p_mask)
  210. X                sendcom(pp, READY, pp->p_nexec);
  211. X            pp->p_nexec = 0;
  212. X            (void) fflush(pp->p_output);
  213. X        }
  214. X# endif MONITOR
  215. X    }
  216. Xout:
  217. X# ifdef    CONSTANT_MOVE
  218. X    bul_alarm(0);
  219. X# endif    CONSTANT_MOVE
  220. X
  221. X# ifdef MONITOR
  222. X    for (pp = Monitor; pp < End_monitor; )
  223. X        zap(pp, FALSE);
  224. X# endif MONITOR
  225. X    cleanup(0);
  226. X}
  227. X
  228. X/*
  229. X * init:
  230. X *    Initialize the global parameters.
  231. X */
  232. Xinit()
  233. X{
  234. X    register int    i;
  235. X# ifdef    INTERNET
  236. X    SOCKET        test_port;
  237. X    auto int    msg;
  238. X# endif    INTERNET
  239. X    int        cleanup();
  240. X
  241. X# ifndef DEBUG
  242. X    (void) ioctl(fileno(stdout), TIOCNOTTY, NULL);
  243. X    (void) setpgrp(getpid(), getpid());
  244. X    (void) signal(SIGHUP, SIG_IGN);
  245. X    (void) signal(SIGINT, SIG_IGN);
  246. X    (void) signal(SIGQUIT, SIG_IGN);
  247. X    (void) signal(SIGTERM, cleanup);
  248. X# endif DEBUG
  249. X
  250. X# ifndef pdp11
  251. X    /* Seed the random number generator. */
  252. X    srandom (getpid());
  253. X# endif pdp11
  254. X
  255. X    (void) chdir("/usr/tmp");    /* just in case it core dumps */
  256. X    (void) signal(SIGPIPE, SIG_IGN);
  257. X
  258. X# ifdef    INTERNET
  259. X    Daemon.sin_family = SOCK_FAMILY;
  260. X# ifdef OLD
  261. X    if (gethostname(local_name, sizeof local_name) < 0) {
  262. X        perror("gethostname");
  263. X        exit(1);
  264. X    }
  265. X    if ((hp = gethostbyname(local_name)) == NULL) {
  266. X        fprintf(stderr, "Unknown host %s\n", local_name);
  267. X        exit(1);
  268. X    }
  269. X    bcopy(hp->h_addr, &(Daemon.sin_addr.s_addr), hp->h_length);
  270. X# else
  271. X    Daemon.sin_addr.s_addr = INADDR_ANY;
  272. X# endif OLD
  273. X    Daemon.sin_port = htons(Sock_port);
  274. X# else INTERNET
  275. X    Daemon.sun_family = SOCK_FAMILY;
  276. X    (void) strcpy(Daemon.sun_path, Sock_name);
  277. X# endif INTERNET
  278. X
  279. X# ifndef OLDIPC
  280. X    Socket = socket(SOCK_FAMILY, SOCK_STREAM, 0);
  281. X# else OLDIPC
  282. X    Socket = socket(SOCK_STREAM, 0, (struct sockaddr *) &Daemon,
  283. X        SO_ACCEPTCONN);
  284. X# endif OLDIPC
  285. X# if defined(INTERNET) && !defined(OLDIPC)
  286. X    msg = 1;
  287. X    if (setsockopt(Socket, SOL_SOCKET, SO_REUSEADDR, &msg, sizeof msg)<0)
  288. X        perror("setsockopt loopback");
  289. X# endif INTERNET
  290. X# ifndef OLDIPC
  291. X    if (bind(Socket, (struct sockaddr *) &Daemon, DAEMON_SIZE) < 0) {
  292. X        if (errno == EADDRINUSE)
  293. X            exit(0);
  294. X        else {
  295. X            perror("bind");
  296. X            cleanup(1);
  297. X        }
  298. X    }
  299. X    (void) listen(Socket, 5);
  300. X# endif OLDIPC
  301. X    Fds_mask = (1 << Socket);
  302. X    Num_fds = Socket + 1;
  303. X
  304. X# ifdef INTERNET
  305. X    test_port = Daemon;
  306. X    test_port.sin_port = htons(Test_port);
  307. X
  308. X# ifndef OLDIPC
  309. X    Test_socket = socket(SOCK_FAMILY, SOCK_DGRAM, 0);
  310. X    if (bind(Test_socket, (struct sockaddr *) &test_port,
  311. X        DAEMON_SIZE) < 0) {
  312. X        perror("bind");
  313. X        exit(1);
  314. X    }
  315. X    (void) listen(Test_socket, 5);
  316. X# else OLDIPC
  317. X    Test_socket = socket(SOCK_DGRAM, 0, (struct sockaddr *) &test_port, 0);
  318. X# endif OLDIPC
  319. X    Fds_mask |= (1 << Test_socket);
  320. X    if (Test_socket > Socket)
  321. X        Num_fds = Test_socket + 1;
  322. X# endif    INTERNET
  323. X
  324. X    Seed = getpid() + time((time_t *) NULL);
  325. X    makemaze();
  326. X
  327. X    for (i = 0; i < NASCII; i++)
  328. X        See_over[i] = TRUE;
  329. X    See_over[DOOR] = FALSE;
  330. X    See_over[WALL1] = FALSE;
  331. X    See_over[WALL2] = FALSE;
  332. X    See_over[WALL3] = FALSE;
  333. X# ifdef REFLECT
  334. X    See_over[WALL4] = FALSE;
  335. X    See_over[WALL5] = FALSE;
  336. X# endif REFLECT
  337. X
  338. X# ifdef CONSTANT_MOVE
  339. X    getitimer(ITIMER_REAL, &Timing);
  340. X    Timing.it_interval.tv_sec = 0;
  341. X    Timing.it_interval.tv_usec = 500;
  342. X    Timing.it_value.tv_sec = 0;
  343. X    Timing.it_value.tv_usec = 0;
  344. X    setitimer(ITIMER_REAL, &Timing, NULL);
  345. X# endif CONSTANT_MOVE
  346. X
  347. X    answer();
  348. X}
  349. X
  350. X# ifdef CONSTANT_MOVE
  351. X/*
  352. X * bul_alarm:
  353. X *    Set up the alarm for the bullets
  354. X */
  355. Xbul_alarm(val)
  356. Xint    val;
  357. X{
  358. X    Timing.it_value.tv_usec = val * Timing.it_interval.tv_usec;
  359. X    setitimer(ITIMER_REAL, &Timing, NULL);
  360. X}
  361. X# endif CONSTANT_MOVE
  362. X
  363. X/*
  364. X * checkdam:
  365. X *    Check the damage to the given player, and see if s/he is killed
  366. X */
  367. Xcheckdam(ouch, gotcha, credit, amt, shot_type)
  368. Xregister PLAYER    *ouch, *gotcha;
  369. Xregister IDENT    *credit;
  370. Xint        amt;
  371. Xchar        shot_type;
  372. X{
  373. X    register char    *cp;
  374. X
  375. X    if (ouch->p_death[0] != '\0')
  376. X        return;
  377. X    if (rand_num(100) < 5) {
  378. X        message(ouch, "Missed you by a hair");
  379. X        if (gotcha != NULL)
  380. X            message(gotcha, "Missed him");
  381. X        return;
  382. X    }
  383. X    ouch->p_damage += amt;
  384. X    if (ouch->p_damage <= ouch->p_damcap) {
  385. X        (void) sprintf(Buf, "%2d", ouch->p_damage);
  386. X        cgoto(ouch, STAT_DAM_ROW, STAT_VALUE_COL);
  387. X        outstr(ouch, Buf, 2);
  388. X        return;
  389. X    }
  390. X
  391. X    /* Someone DIED */
  392. X    switch (shot_type) {
  393. X      default:
  394. X        cp = "Killed";
  395. X        break;
  396. X# ifdef FLY
  397. X      case FALL:
  398. X        cp = "Killed on impact";
  399. X        break;
  400. X# endif FLY
  401. X      case KNIFE:
  402. X        cp = "Stabbed to death";
  403. X        break;
  404. X      case SHOT:
  405. X        cp = "Shot to death";
  406. X        break;
  407. X      case GRENADE:
  408. X      case SATCHEL:
  409. X      case BOMB:
  410. X        cp = "Bombed";
  411. X        break;
  412. X      case MINE:
  413. X      case GMINE:
  414. X        cp = "Blown apart";
  415. X        break;
  416. X# ifdef    OOZE
  417. X      case SLIME:
  418. X        cp = "Slimed";
  419. X        break;
  420. X# endif OOZE
  421. X# ifdef    VOLCANO
  422. X      case LAVA:
  423. X        cp = "Baked";
  424. X        break;
  425. X# endif VOLCANO
  426. X    }
  427. X    if (credit == NULL) {
  428. X        (void) sprintf(ouch->p_death, "| %s by %s |", cp,
  429. X            (shot_type == MINE || shot_type == GMINE) ?
  430. X            "a mine" : "act of God");
  431. X        return;
  432. X    }
  433. X
  434. X    (void) sprintf(ouch->p_death, "| %s by %s |", cp, credit->i_name);
  435. X
  436. X    credit->i_kills++;
  437. X    credit->i_score = credit->i_kills / (double) credit->i_entries;
  438. X    if (gotcha == NULL)
  439. X        return;
  440. X    gotcha->p_damcap += STABDAM;
  441. X    gotcha->p_damage -= STABDAM;
  442. X    if (gotcha->p_damage < 0)
  443. X        gotcha->p_damage = 0;
  444. X    (void) sprintf(Buf, "%2d/%2d", gotcha->p_damage, gotcha->p_damcap);
  445. X    cgoto(gotcha, STAT_DAM_ROW, STAT_VALUE_COL);
  446. X    outstr(gotcha, Buf, 5);
  447. X    (void) sprintf(Buf, "%3d", (gotcha->p_damcap - MAXDAM) / 2);
  448. X    cgoto(gotcha, STAT_KILL_ROW, STAT_VALUE_COL);
  449. X    outstr(gotcha, Buf, 3);
  450. X    (void) sprintf(Buf, "%5.2f", gotcha->p_ident->i_score);
  451. X    for (ouch = Player; ouch < End_player; ouch++) {
  452. X        cgoto(ouch, STAT_PLAY_ROW + 1 + (gotcha - Player),
  453. X            STAT_NAME_COL);
  454. X        outstr(ouch, Buf, 5);
  455. X    }
  456. X}
  457. X
  458. X/*
  459. X * zap:
  460. X *    Kill off a player and take him out of the game.
  461. X */
  462. Xzap(pp, was_player)
  463. Xregister PLAYER    *pp;
  464. XFLAG        was_player;
  465. X{
  466. X    register int    i, len;
  467. X    register BULLET    *bp;
  468. X    register PLAYER    *np;
  469. X    register int    x, y;
  470. X    int        savefd, savemask;
  471. X
  472. X    if (was_player) {
  473. X        drawplayer(pp, FALSE);
  474. X        Nplayer--;
  475. X    }
  476. X
  477. X    len = strlen(pp->p_death);    /* Display the cause of death */
  478. X    x = (WIDTH - len) / 2;
  479. X    cgoto(pp, HEIGHT / 2, x);
  480. X    outstr(pp, pp->p_death, len);
  481. X    for (i = 1; i < len; i++)
  482. X        pp->p_death[i] = '-';
  483. X    pp->p_death[0] = '+';
  484. X    pp->p_death[len - 1] = '+';
  485. X    cgoto(pp, HEIGHT / 2 - 1, x);
  486. X    outstr(pp, pp->p_death, len);
  487. X    cgoto(pp, HEIGHT / 2 + 1, x);
  488. X    outstr(pp, pp->p_death, len);
  489. X    cgoto(pp, HEIGHT, 0);
  490. X
  491. X    if (Nplayer == 0) {
  492. X# ifdef CONSTANT_MOVE
  493. X        bul_alarm(0);
  494. X# endif CONSTANT_MOVE
  495. X        cleanup(0);
  496. X        /* NOTREACHED */
  497. X    }
  498. X
  499. X    savefd = pp->p_fd;
  500. X    savemask = pp->p_mask;
  501. X
  502. X# ifdef MONITOR
  503. X    if (was_player) {
  504. X# endif MONITOR
  505. X        for (bp = Bullets; bp != NULL; bp = bp->b_next) {
  506. X            if (bp->b_owner == pp)
  507. X                bp->b_owner = NULL;
  508. X            if (bp->b_x == pp->p_x && bp->b_y == pp->p_y)
  509. X                bp->b_over = SPACE;
  510. X        }
  511. X
  512. X        i = rand_num(pp->p_ammo);
  513. X        if (i == pp->p_ammo - 1) {
  514. X            x = pp->p_ammo;
  515. X            len = SLIME;
  516. X        }
  517. X        else if (i >= BOMBREQ) {
  518. X            x = BOMBREQ;
  519. X            len = BOMB;
  520. X        }
  521. X        else if (i >= SSLIMEREQ) {
  522. X            x = SSLIMEREQ;
  523. X            len = SLIME;
  524. X        }
  525. X        else if (i >= SATREQ) {
  526. X            x = SATREQ;
  527. X            len = SATCHEL;
  528. X        }
  529. X        else if (i >= SLIMEREQ) {
  530. X            x = SLIMEREQ;
  531. X            len = SLIME;
  532. X        }
  533. X        else if (i >= GRENREQ) {
  534. X            x = GRENREQ;
  535. X            len = GRENADE;
  536. X        }
  537. X        else
  538. X            x = 0;
  539. X        if (x > 0) {
  540. X            add_shot(len, pp->p_y, pp->p_x, pp->p_face, x,
  541. X                (PLAYER *) NULL, TRUE, SPACE);
  542. X            (void) sprintf(Buf, "%s detonated.",
  543. X                pp->p_ident->i_name);
  544. X            for (np = Player; np < End_player; np++)
  545. X                message(np, Buf);
  546. X# ifdef MONITOR
  547. X            for (np = Monitor; np < End_monitor; np++)
  548. X                message(np, Buf);
  549. X# endif MONITOR
  550. X        }
  551. X
  552. X# ifdef VOLCANO
  553. X        volcano += pp->p_ammo - x;
  554. X        if (rand_num(100) < volcano / 50) {
  555. X            do {
  556. X                x = rand_num(WIDTH / 2) + WIDTH / 4;
  557. X                y = rand_num(HEIGHT / 2) + HEIGHT / 4;
  558. X            } while (Maze[y][x] != SPACE);
  559. X            add_shot(LAVA, y, x, LEFTS, volcano,
  560. X                (PLAYER *) NULL, TRUE, SPACE);
  561. X            for (np = Player; np < End_player; np++)
  562. X                message(np, "Volcano eruption.");
  563. X            volcano = 0;
  564. X        }
  565. X# endif VOLCANO
  566. X
  567. X        sendcom(pp, ENDWIN);
  568. X        (void) fclose(pp->p_output);
  569. X
  570. X        End_player--;
  571. X        if (pp != End_player) {
  572. X            bcopy((char *) End_player, (char *) pp,
  573. X                sizeof (PLAYER));
  574. X            (void) sprintf(Buf, "%5.2f%c%-10.10s",
  575. X                pp->p_ident->i_score, stat_char(pp),
  576. X                pp->p_ident->i_name);
  577. X            i = STAT_PLAY_ROW + 1 + (pp - Player);
  578. X            for (np = Player; np < End_player; np++) {
  579. X                cgoto(np, i, STAT_NAME_COL);
  580. X                outstr(np, Buf, STAT_NAME_LEN);
  581. X            }
  582. X# ifdef MONITOR
  583. X            for (np = Monitor; np < End_monitor; np++) {
  584. X                cgoto(np, i, STAT_NAME_COL);
  585. X                outstr(np, Buf, STAT_NAME_LEN);
  586. X            }
  587. X# endif MONITOR
  588. X        }
  589. X
  590. X        /* Erase the last player */
  591. X        i = STAT_PLAY_ROW + 1 + Nplayer;
  592. X        for (np = Player; np < End_player; np++) {
  593. X            cgoto(np, i, STAT_NAME_COL);
  594. X            ce(np);
  595. X        }
  596. X# ifdef MONITOR
  597. X        for (np = Monitor; np < End_monitor; np++) {
  598. X            cgoto(np, i, STAT_NAME_COL);
  599. X            ce(np);
  600. X        }
  601. X    }
  602. X    else {
  603. X        sendcom(pp, ENDWIN);
  604. X        (void) putc(LAST_PLAYER, pp->p_output);
  605. X        (void) fclose(pp->p_output);
  606. X
  607. X        End_monitor--;
  608. X        if (pp != End_monitor) {
  609. X            bcopy((char *) End_monitor, (char *) pp,
  610. X                sizeof (PLAYER));
  611. X            (void) sprintf(Buf, "%5.5s %-10.10s", " ",
  612. X                pp->p_ident->i_name);
  613. X            i = STAT_MON_ROW + 1 + (pp - Player);
  614. X            for (np = Player; np < End_player; np++) {
  615. X                cgoto(np, i, STAT_NAME_COL);
  616. X                outstr(np, Buf, STAT_NAME_LEN);
  617. X            }
  618. X            for (np = Monitor; np < End_monitor; np++) {
  619. X                cgoto(np, i, STAT_NAME_COL);
  620. X                outstr(np, Buf, STAT_NAME_LEN);
  621. X            }
  622. X        }
  623. X
  624. X        /* Erase the last monitor */
  625. X        i = STAT_MON_ROW + 1 + (End_monitor - Monitor);
  626. X        for (np = Player; np < End_player; np++) {
  627. X            cgoto(np, i, STAT_NAME_COL);
  628. X            ce(np);
  629. X        }
  630. X        for (np = Monitor; np < End_monitor; np++) {
  631. X            cgoto(np, i, STAT_NAME_COL);
  632. X            ce(np);
  633. X        }
  634. X
  635. X    }
  636. X# endif MONITOR
  637. X
  638. X    Fds_mask &= ~savemask;
  639. X    if (Num_fds == savefd + 1) {
  640. X        Num_fds = Socket;
  641. X# ifdef INTERNET
  642. X        if (Test_socket > Socket)
  643. X            Num_fds = Test_socket;
  644. X# endif INTERNET
  645. X        for (np = Player; np < End_player; np++)
  646. X            if (np->p_fd > Num_fds)
  647. X                Num_fds = np->p_fd;
  648. X# ifdef MONITOR
  649. X        for (np = Monitor; np < End_monitor; np++)
  650. X            if (np->p_fd > Num_fds)
  651. X                Num_fds = np->p_fd;
  652. X# endif MONITOR
  653. X        Num_fds++;
  654. X    }
  655. X}
  656. X
  657. X/*
  658. X * havechar:
  659. X *    Check to see if we have any characters in the input queue; if
  660. X *    we do, read them, stash them away, and return TRUE; else return
  661. X *    FALSE.
  662. X */
  663. Xhavechar(pp)
  664. Xregister PLAYER    *pp;
  665. X{
  666. X    extern int    errno;
  667. X
  668. X    if (pp->p_ncount < pp->p_nchar)
  669. X        return TRUE;
  670. X    if (!(Have_inp & pp->p_mask))
  671. X        return FALSE;
  672. X    Have_inp &= ~pp->p_mask;
  673. Xcheck_again:
  674. X    errno = 0;
  675. X    if ((pp->p_nchar = read(pp->p_fd, pp->p_cbuf, sizeof pp->p_cbuf)) <= 0)
  676. X    {
  677. X        if (errno == EINTR)
  678. X            goto check_again;
  679. X        pp->p_cbuf[0] = 'q';
  680. X    }
  681. X    pp->p_ncount = 0;
  682. X    return TRUE;
  683. X}
  684. X
  685. X/*
  686. X * cleanup:
  687. X *    Exit with the given value, cleaning up any droppings lying around
  688. X */
  689. Xcleanup(eval)
  690. Xint    eval;
  691. X{
  692. X    register PLAYER    *pp;
  693. X
  694. X    for (pp = Player; pp < End_player; pp++) {
  695. X        cgoto(pp, HEIGHT, 0);
  696. X        sendcom(pp, ENDWIN);
  697. X        (void) putc(LAST_PLAYER, pp->p_output);
  698. X        (void) fclose(pp->p_output);
  699. X    }
  700. X# ifdef MONITOR
  701. X    for (pp = Monitor; pp < End_monitor; pp++) {
  702. X        cgoto(pp, HEIGHT, 0);
  703. X        sendcom(pp, ENDWIN);
  704. X        (void) putc(LAST_PLAYER, pp->p_output);
  705. X        (void) fclose(pp->p_output);
  706. X    }
  707. X# endif MONITOR
  708. X    (void) close(Socket);
  709. X# ifdef AF_UNIX_HACK
  710. X    (void) unlink(Sock_name);
  711. X# endif AF_UNIX_HACK
  712. X    exit(eval);
  713. X}
  714. END_OF_FILE
  715. if test 15418 -ne `wc -c <'driver.c'`; then
  716.     echo shar: \"'driver.c'\" unpacked with wrong size!
  717. fi
  718. # end of 'driver.c'
  719. fi
  720. if test -f 'extern.c' -a "${1}" != "-c" ; then 
  721.   echo shar: Will not clobber existing file \"'extern.c'\"
  722. else
  723. echo shar: Extracting \"'extern.c'\" \(2185 characters\)
  724. sed "s/^X//" >'extern.c' <<'END_OF_FILE'
  725. X/*
  726. X * Copyright (c) 1985 Regents of the University of California.
  727. X * All rights reserved.
  728. X *
  729. X * Redistribution and use in source and binary forms are permitted
  730. X * provided that the above copyright notice and this paragraph are
  731. X * duplicated in all such forms and that any documentation,
  732. X * advertising materials, and other materials related to such
  733. X * distribution and use acknowledge that the software was developed
  734. X * by the University of California, Berkeley.  The name of the
  735. X * University may not be used to endorse or promote products derived
  736. X * from this software without specific prior written permission.
  737. X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  738. X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  739. X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  740. X */
  741. X
  742. X#ifndef lint
  743. Xstatic char sccsid[] = "@(#)extern.c    5.2 (Berkeley) 6/27/88";
  744. X#endif /* not lint */
  745. X
  746. X/*
  747. X *  Hunt
  748. X *  Copyright (c) 1985 Conrad C. Huang, Gregory S. Couch, Kenneth C.R.C. Arnold
  749. X *  San Francisco, California
  750. X */
  751. X
  752. X# include    "hunt.h"
  753. X
  754. X# ifdef MONITOR
  755. XFLAG    Am_monitor = FALSE;        /* current process is a monitor */
  756. X# endif MONITOR
  757. X
  758. Xchar    Buf[BUFSIZ];            /* general scribbling buffer */
  759. Xchar    Maze[HEIGHT][WIDTH2];        /* the maze */
  760. Xchar    Orig_maze[HEIGHT][WIDTH2];    /* the original maze */
  761. X
  762. Xlong    Fds_mask;            /* mask for the file descriptors */
  763. Xint    Have_inp;            /* which file descriptors have input */
  764. Xint    Nplayer = 0;            /* number of players */
  765. Xint    Num_fds;            /* number of maximum file descriptor */
  766. Xint    Socket;                /* main socket */
  767. Xlong    Sock_mask;            /* select mask for main socket */
  768. Xint    See_over[NASCII];        /* lookup table for determining whether
  769. X                     * character represents "transparent"
  770. X                     * item */
  771. X
  772. XBULLET    *Bullets = NULL;        /* linked list of bullets */
  773. X
  774. XEXPL    *Expl[EXPLEN];            /* explosion lists */
  775. X
  776. XPLAYER    Player[MAXPL];            /* all the players */
  777. XPLAYER    *End_player = Player;        /* last active player slot */
  778. XIDENT    *Scores;            /* score cache */
  779. X# ifdef MONITOR
  780. XPLAYER    Monitor[MAXMON];        /* all the monitors */
  781. XPLAYER    *End_monitor = Monitor;        /* last active monitor slot */
  782. X# endif MONITOR
  783. X
  784. X# ifdef VOLCANO
  785. Xint    volcano = 0;            /* Explosion size */
  786. X# endif VOLCANO
  787. END_OF_FILE
  788. if test 2185 -ne `wc -c <'extern.c'`; then
  789.     echo shar: \"'extern.c'\" unpacked with wrong size!
  790. fi
  791. # end of 'extern.c'
  792. fi
  793. if test -f 'hunt.c' -a "${1}" != "-c" ; then 
  794.   echo shar: Will not clobber existing file \"'hunt.c'\"
  795. else
  796. echo shar: Extracting \"'hunt.c'\" \(16374 characters\)
  797. sed "s/^X//" >'hunt.c' <<'END_OF_FILE'
  798. X/*
  799. X * Copyright (c) 1985 Regents of the University of California.
  800. X * All rights reserved.
  801. X *
  802. X * Redistribution and use in source and binary forms are permitted
  803. X * provided that the above copyright notice and this paragraph are
  804. X * duplicated in all such forms and that any documentation,
  805. X * advertising materials, and other materials related to such
  806. X * distribution and use acknowledge that the software was developed
  807. X * by the University of California, Berkeley.  The name of the
  808. X * University may not be used to endorse or promote products derived
  809. X * from this software without specific prior written permission.
  810. X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  811. X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  812. X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  813. X */
  814. X
  815. X#ifndef lint
  816. Xstatic char sccsid[] = "@(#)hunt.c    5.3 (Berkeley) 6/27/88";
  817. X#endif /* not lint */
  818. X
  819. X/*
  820. X *  Hunt
  821. X *  Copyright (c) 1985 Conrad C. Huang, Gregory S. Couch, Kenneth C.R.C. Arnold
  822. X *  San Francisco, California
  823. X */
  824. X
  825. X# include    <errno.h>
  826. X# include    <curses.h>
  827. X# include    "hunt.h"
  828. X# include    <signal.h>
  829. X# include    <ctype.h>
  830. X# include    <sys/stat.h>
  831. X
  832. XFLAG    Last_player = FALSE;
  833. X# ifdef MONITOR
  834. XFLAG    Am_monitor = FALSE;
  835. X# endif MONITOR
  836. XFLAG    Query_driver = FALSE;
  837. X
  838. Xchar    Buf[BUFSIZ];
  839. X
  840. Xint    Master_pid;
  841. Xint    Socket;
  842. X# ifdef INTERNET
  843. Xchar    *Sock_host;
  844. X# endif INTERNET
  845. X
  846. XSOCKET    Daemon;
  847. X# ifdef    INTERNET
  848. X# define    DAEMON_SIZE    (sizeof Daemon)
  849. X# else    INTERNET
  850. X# define    DAEMON_SIZE    (sizeof Daemon - 1)
  851. X# endif    INTERNET
  852. X
  853. Xchar    map_key[256];            /* what to map keys to */
  854. X
  855. Xstatic char    name[NAMELEN];
  856. X
  857. Xextern int    cur_row, cur_col, _putchar();
  858. Xextern char    *tgoto();
  859. X
  860. X# ifdef ROBOT
  861. Xextern int robot_player, daemon_player;
  862. X# endif ROBOT
  863. X
  864. X/*
  865. X * main:
  866. X *    Main program for local process
  867. X */
  868. Xmain(ac, av)
  869. Xint    ac;
  870. Xchar    **av;
  871. X{
  872. X    char        *term;
  873. X    extern int    errno;
  874. X    extern int    Otto_mode;
  875. X    int        dumpit(), intr(), sigterm(), sigemt(), tstp();
  876. X    int should_quit;
  877. X
  878. X    for (ac--, av++; ac > 0 && av[0][0] == '-'; ac--, av++) {
  879. X        switch (av[0][1]) {
  880. X
  881. X        case 'l':    /* rsh compatibility */
  882. X        case 'n':
  883. X            if (ac <= 1)
  884. X                goto usage;
  885. X            ac--, av++;
  886. X            (void) strcpy(name, av[0]);
  887. X            break;
  888. X        case 'o':
  889. X# ifndef OTTO
  890. X            fputs("The -o flag is reserved for future use.\n",
  891. X                stderr);
  892. X            goto usage;
  893. X# else OTTO
  894. X            Otto_mode = TRUE;
  895. X            break;
  896. X# endif OTTO
  897. X# ifdef MONITOR
  898. X        case 'm':
  899. X            Am_monitor = TRUE;
  900. X            break;
  901. X# endif MONITOR
  902. X# ifdef ROBOT
  903. X        case 'r':
  904. X            robot_player = TRUE;
  905. X            break;
  906. X        case 'd':
  907. X            daemon_player = TRUE;
  908. X            break;
  909. X# endif ROBOT
  910. X# ifdef INTERNET
  911. X        case 'q':    /* query whether hunt is running */
  912. X            Query_driver = TRUE;
  913. X            break;
  914. X        case 'h':
  915. X            if (ac <= 1)
  916. X                goto usage;
  917. X            ac--, av++;
  918. X            Sock_host = av[0];
  919. X            break;
  920. X# endif INTERNET
  921. X        default:
  922. X        usage:
  923. X# ifdef ROBOT
  924. X#  ifdef INTERNET
  925. X#   ifdef MONITOR
  926. X#    define    USAGE    "usage: hunt [-q] [-n name] [-h host] [-m] [-r [-d] ]\n"
  927. X#   else MONITOR
  928. X#    define    USAGE    "usage: hunt [-q] [-n name] [-h host] [-r [-d] ]\n"
  929. X#   endif MONITOR
  930. X#  else INTERNET
  931. X#   ifdef MONITOR
  932. X#    define    USAGE    "usage: hunt [-n name] [-m] [-r [-d] ]\n"
  933. X#   else MONITOR
  934. X#    define    USAGE    "usage: hunt [-n name] [-r [-d] ]\n"
  935. X#   endif MONITOR
  936. X#  endif INTERNET
  937. X# else ROBOT
  938. X#  ifdef INTERNET
  939. X#   ifdef MONITOR
  940. X#    define    USAGE    "usage: hunt [-q] [-n name] [-h host] [-m]\n"
  941. X#   else MONITOR
  942. X#    define    USAGE    "usage: hunt [-q] [-n name] [-h host]\n"
  943. X#   endif MONITOR
  944. X#  else INTERNET
  945. X#   ifdef MONITOR
  946. X#    define    USAGE    "usage: hunt [-n name] [-m]\n"
  947. X#   else MONITOR
  948. X#    define    USAGE    "usage: hunt [-n name]\n"
  949. X#   endif MONITOR
  950. X#  endif INTERNET
  951. X# endif ROBOT
  952. X            fputs(USAGE, stderr);
  953. X# undef USAGE
  954. X            exit(1);
  955. X        }
  956. X    }
  957. X# ifdef INTERNET
  958. X    if (ac > 1)
  959. X        goto usage;
  960. X    else if (ac > 0)
  961. X        Sock_host = av[0];
  962. X# else INTERNET
  963. X    if (ac > 0)
  964. X        goto usage;
  965. X# endif INTERNET    
  966. X
  967. X# ifdef INTERNET
  968. X    if (Query_driver) {
  969. X        find_driver(FALSE);
  970. X        if (Daemon.sin_port != 0) {
  971. X            struct    hostent    *hp;
  972. X
  973. X            hp = gethostbyaddr(&Daemon.sin_addr,
  974. X                sizeof Daemon.sin_addr, AF_INET);
  975. X            fprintf(stderr, "HUNT!! found on %s\n", hp != NULL
  976. X                ? hp->h_name : inet_ntoa(Daemon.sin_addr));
  977. X        }
  978. X        exit(Daemon.sin_port == 0);
  979. X    }
  980. X# endif INTERNET
  981. X# ifdef OTTO
  982. X    if (Otto_mode)
  983. X        (void) strcpy(name, "otto");
  984. X    else
  985. X# endif OTTO
  986. X    env_init();
  987. X
  988. X    (void) fflush(stdout);
  989. X    if (!isatty(0) || (term = getenv("TERM")) == NULL) {
  990. X        fprintf(stderr, "no terminal type\n");
  991. X        exit(1);
  992. X    }
  993. X    if (!daemon_player)
  994. X    {
  995. X        _tty_ch = 0;
  996. X        gettmode();
  997. X        setterm(term);
  998. X        noecho();
  999. X        cbreak();
  1000. X        _puts(TI);
  1001. X        _puts(VS);
  1002. X    }
  1003. X    clear_screen();
  1004. X    (void) signal(SIGINT, intr);
  1005. X    (void) signal(SIGTERM, sigterm);
  1006. X    (void) signal(SIGEMT, sigemt);
  1007. X    (void) signal(SIGQUIT, dumpit);
  1008. X    (void) signal(SIGPIPE, SIG_IGN);
  1009. X    (void) signal(SIGTSTP, tstp);
  1010. X
  1011. X    do {
  1012. X# ifdef    INTERNET
  1013. X        find_driver(TRUE);
  1014. X
  1015. X        do {
  1016. X            int    msg;
  1017. X
  1018. X# ifndef OLDIPC
  1019. X            Socket = socket(SOCK_FAMILY, SOCK_STREAM, 0);
  1020. X# else OLDIPC
  1021. X            Socket = socket(SOCK_STREAM, 0, 0, 0);
  1022. X# endif OLDIPC
  1023. X            if (Socket < 0) {
  1024. X                perror("socket");
  1025. X                exit(1);
  1026. X            }
  1027. X# ifndef OLDIPC
  1028. X            msg = 1;
  1029. X            if (setsockopt(Socket, SOL_SOCKET, SO_USELOOPBACK,
  1030. X                &msg, sizeof msg) < 0)
  1031. X                perror("setsockopt loopback");
  1032. X# endif OLDIPC
  1033. X            errno = 0;
  1034. X            if (connect(Socket, (struct sockaddr *) &Daemon,
  1035. X                DAEMON_SIZE) < 0) {
  1036. X                if (errno != ECONNREFUSED) {
  1037. X                    perror("connect");
  1038. X                    leave(1, "connect");
  1039. X                }
  1040. X            }
  1041. X            else
  1042. X                break;
  1043. X            sleep(1);
  1044. X        } while (close(Socket) == 0);
  1045. X# else    INTERNET
  1046. X        /*
  1047. X         * set up a socket
  1048. X         */
  1049. X
  1050. X        if ((Socket = socket(SOCK_FAMILY, SOCK_STREAM, 0)) < 0) {
  1051. X            perror("socket");
  1052. X            exit(1);
  1053. X        }
  1054. X
  1055. X        /*
  1056. X         * attempt to connect the socket to a name; if it fails that
  1057. X         * usually means that the driver isn't running, so we start
  1058. X         * up the driver.
  1059. X         */
  1060. X
  1061. X        Daemon.sun_family = SOCK_FAMILY;
  1062. X        (void) strcpy(Daemon.sun_path, Sock_name);
  1063. X        if (connect(Socket, &Daemon, DAEMON_SIZE) < 0) {
  1064. X            if (errno != ENOENT) {
  1065. X                perror("connect");
  1066. X                leave(1, "connect2");
  1067. X            }
  1068. X            start_driver();
  1069. X
  1070. X            do {
  1071. X                (void) close(Socket);
  1072. X                if ((Socket = socket(SOCK_FAMILY, SOCK_STREAM, 0)) < 0) {
  1073. X                    perror("socket");
  1074. X                    exit(1);
  1075. X                }
  1076. X                sleep(2);
  1077. X            } while (connect(Socket, &Daemon, DAEMON_SIZE) < 0);
  1078. X        }
  1079. X# endif INTERNET
  1080. X
  1081. X        do_connect(name);
  1082. X        setup_to_play();
  1083. X
  1084. X# ifdef ROBOT
  1085. X        if (robot_player)
  1086. X        {
  1087. X            do_robot();
  1088. X            should_quit = FALSE;
  1089. X        }
  1090. X        else
  1091. X# endif ROBOT
  1092. X        {
  1093. X            playit();
  1094. X            should_quit = quit();
  1095. X        }
  1096. X    } while (!should_quit);
  1097. X    leave(0, NULL);
  1098. X    /* NOTREACHED */
  1099. X}
  1100. X
  1101. X# ifdef INTERNET
  1102. X# ifdef BROADCAST
  1103. Xbroadcast_vec(s, vector)
  1104. X    int            s;        /* socket */
  1105. X    struct    sockaddr    **vector;
  1106. X{
  1107. X    char            if_buf[BUFSIZ];
  1108. X    struct    ifconf        ifc;
  1109. X    struct    ifreq        *ifr;
  1110. X    int            n;
  1111. X    int            vec_cnt;
  1112. X
  1113. X    *vector = NULL;
  1114. X    ifc.ifc_len = sizeof if_buf;
  1115. X    ifc.ifc_buf = if_buf;
  1116. X    if (ioctl(s, SIOCGIFCONF, (char *) &ifc) < 0)
  1117. X        return 0;
  1118. X    vec_cnt = 0;
  1119. X    n = ifc.ifc_len / sizeof (struct ifreq);
  1120. X    *vector = (struct sockaddr *) malloc(n * sizeof (struct sockaddr));
  1121. X    for (ifr = ifc.ifc_req; n > 0; n--, ifr++)
  1122. X        if (ioctl(s, SIOCGIFBRDADDR, ifr) >= 0)
  1123. X            bcopy(&ifr->ifr_addr, &(*vector)[vec_cnt++],
  1124. X                        sizeof (struct sockaddr));
  1125. X    return vec_cnt;
  1126. X}
  1127. X# endif BROADCAST
  1128. X
  1129. Xfind_driver(do_startup)
  1130. XFLAG    do_startup;
  1131. X{
  1132. X    int            msg;
  1133. X    static SOCKET        test;
  1134. X    int            test_socket;
  1135. X    int            namelen;
  1136. X    char            local_name[80];
  1137. X    static            initial = TRUE;
  1138. X    static struct in_addr    local_address;
  1139. X    register struct hostent    *hp;
  1140. X    int sigalrm();
  1141. X    struct sigvec vec, ovec;
  1142. X    extern int        errno;
  1143. X# ifdef BROADCAST
  1144. X    static    int        brdc;
  1145. X    static    SOCKET        *brdv;
  1146. X    int            i;
  1147. X# endif BROADCAST
  1148. X
  1149. X    if (Sock_host != NULL) {
  1150. X        if (!initial)
  1151. X            return;        /* Daemon address already valid */
  1152. X        initial = FALSE;
  1153. X        if ((hp = gethostbyname(Sock_host)) == NULL) {
  1154. X            leave(1, "Unknown host");
  1155. X            /* NOTREACHED */
  1156. X        }
  1157. X        Daemon.sin_family = SOCK_FAMILY;
  1158. X        Daemon.sin_port = htons(Sock_port);
  1159. X        Daemon.sin_addr = *((struct in_addr *) hp->h_addr);
  1160. X        if (!Query_driver)
  1161. X            return;
  1162. X    }
  1163. X
  1164. X
  1165. X    if (initial) {            /* do one time initialization */
  1166. X# ifndef BROADCAST
  1167. X        sethostent(1);        /* don't bother to close host file */
  1168. X# endif BROADCAST
  1169. X        if (gethostname(local_name, sizeof local_name) < 0) {
  1170. X            leave(1, "Sorry, I have no name.");
  1171. X            /* NOTREACHED */
  1172. X        }
  1173. X        if ((hp = gethostbyname(local_name)) == NULL) {
  1174. X            leave(1, "Can't find myself.");
  1175. X            /* NOTREACHED */
  1176. X        }
  1177. X        local_address = * ((struct in_addr *) hp->h_addr);
  1178. X
  1179. X        test.sin_family = SOCK_FAMILY;
  1180. X        test.sin_addr = local_address;
  1181. X        test.sin_port = htons(Test_port);
  1182. X    }
  1183. X
  1184. X# ifndef OLDIPC
  1185. X    test_socket = socket(SOCK_FAMILY, SOCK_DGRAM, 0);
  1186. X# else OLDIPC
  1187. X    test_socket = socket(SOCK_DGRAM, 0, 0, 0);
  1188. X# endif OLCIPC
  1189. X    if (test_socket < 0) {
  1190. X        perror("socket");
  1191. X        leave(1, "socket system call failed");
  1192. X        /* NOTREACHED */
  1193. X    }
  1194. X
  1195. X    msg = 1;
  1196. X    if (Query_driver && Sock_host != NULL) {
  1197. X        test.sin_family = SOCK_FAMILY;
  1198. X        test.sin_addr = Daemon.sin_addr;
  1199. X        test.sin_port = htons(Test_port);
  1200. X# ifndef OLDIPC
  1201. X        (void) sendto(test_socket, (char *) &msg, sizeof msg, 0,
  1202. X            (struct sockaddr *) &test, DAEMON_SIZE);
  1203. X# else OLDIPC
  1204. X        (void) send(test_socket, (struct sockaddr *) &test,
  1205. X            (char *) &msg, sizeof msg);
  1206. X# endif OLDIPC
  1207. X        goto get_response;
  1208. X    }
  1209. X
  1210. X    if (!initial) {
  1211. X        /* favor host of previous session by broadcasting to it first */
  1212. X        test.sin_addr = Daemon.sin_addr;
  1213. X        test.sin_port = htons(Test_port);
  1214. X        (void) sendto(test_socket, (char *) &msg, sizeof msg, 0,
  1215. X            (struct sockaddr *) &test, DAEMON_SIZE);
  1216. X    }
  1217. X
  1218. X
  1219. X# ifdef BROADCAST
  1220. X    if (initial)
  1221. X        brdc = broadcast_vec(test_socket, &brdv);
  1222. X
  1223. X    if (brdc <= 0) {
  1224. X        Daemon.sin_family = SOCK_FAMILY;
  1225. X        Daemon.sin_addr = local_address;
  1226. X        Daemon.sin_port = htons(Sock_port);
  1227. X        initial = FALSE;
  1228. X        return;
  1229. X    }
  1230. X
  1231. X    if (setsockopt(test_socket, SOL_SOCKET, SO_BROADCAST,
  1232. X        (int) &msg, sizeof msg) < 0) {
  1233. X        perror("setsockopt broadcast");
  1234. X        leave(1, "setsockopt broadcast");
  1235. X        /* NOTREACHED */
  1236. X    }
  1237. X
  1238. X    /* send broadcast packets on all interfaces */
  1239. X    for (i = 0; i < brdc; i++) {
  1240. X        bcopy(&brdv[i], &test, sizeof (SOCKET));
  1241. X        test.sin_port = htons(Test_port);
  1242. X        if (sendto(test_socket, (char *) &msg, sizeof msg, 0,
  1243. X            (struct sockaddr *) &test, DAEMON_SIZE) < 0) {
  1244. X            perror("sendto");
  1245. X            leave(1, "sendto");
  1246. X            /* NOTREACHED */
  1247. X        }
  1248. X    }
  1249. X# else BROADCAST
  1250. X    /* loop thru all hosts on local net and send msg to them. */
  1251. X    sethostent(0);        /* rewind host file */
  1252. X    while (hp = gethostent()) {
  1253. X        if (inet_netof(test.sin_addr)
  1254. X        == inet_netof(* ((struct in_addr *) hp->h_addr))) {
  1255. X            test.sin_addr = * ((struct in_addr *) hp->h_addr);
  1256. X# ifndef OLDIPC
  1257. X            (void) sendto(test_socket, (char *) &msg, sizeof msg, 0,
  1258. X                (struct sockaddr *) &test, DAEMON_SIZE);
  1259. X# else OLDIPC
  1260. X            (void) send(test_socket, (struct sockaddr *) &test,
  1261. X                (char *) &msg, sizeof msg);
  1262. X# endif OLDIPC
  1263. X        }
  1264. X    }
  1265. X# endif BROADCAST
  1266. X
  1267. Xget_response:
  1268. X    namelen = DAEMON_SIZE;
  1269. X    vec.sv_handler = sigalrm;
  1270. X    vec.sv_mask = 0;
  1271. X    vec.sv_flags = SV_INTERRUPT;
  1272. X    (void) sigvec(SIGALRM, &vec, &ovec);
  1273. X    errno = 0;
  1274. X    (void) alarm(1);
  1275. X# ifndef OLDIPC
  1276. X    if (recvfrom(test_socket, (char *) &msg, sizeof msg, 0,
  1277. X        (struct sockaddr *) &Daemon, &namelen) < 0)
  1278. X# else OLDIPC
  1279. X    if (receive(test_socket, (struct sockaddr *) &Daemon, &msg,
  1280. X        sizeof msg) < 0)
  1281. X# endif OLDIPC
  1282. X    {
  1283. X        if (errno != EINTR) {
  1284. X            perror("recvfrom");
  1285. X            leave(1, "recvfrom");
  1286. X            /* NOTREACHED */
  1287. X        }
  1288. X        (void) alarm(0);
  1289. X        (void) sigvec (SIGALRM, &ovec, NULL);
  1290. X        Daemon.sin_family = SOCK_FAMILY;
  1291. X        Daemon.sin_port = htons(Sock_port);
  1292. X        Daemon.sin_addr = local_address;
  1293. X        if (!do_startup)
  1294. X            Daemon.sin_port = 0;
  1295. X        else
  1296. X            start_driver();
  1297. X    }
  1298. X    else {
  1299. X        (void) alarm(0);
  1300. X        (void) sigvec (SIGALRM, &ovec, NULL);
  1301. X        Daemon.sin_port = htons(Sock_port);
  1302. X    }
  1303. X    (void) close(test_socket);
  1304. X    initial = FALSE;
  1305. X}
  1306. X# endif INTERNET
  1307. X
  1308. Xstart_driver()
  1309. X{
  1310. X    register int    procid;
  1311. X
  1312. X# ifdef MONITOR
  1313. X    if (Am_monitor) {
  1314. X        leave(1, "No one playing.");
  1315. X        /* NOTREACHED */
  1316. X    }
  1317. X# endif MONITOR
  1318. X
  1319. X# ifdef INTERNET
  1320. X    if (Sock_host != NULL) {
  1321. X        sleep(3);
  1322. X        return 0;
  1323. X    }
  1324. X# endif INTERNET
  1325. X
  1326. X    if (!daemon_player)
  1327. X    {
  1328. X        mvcur(cur_row, cur_col, 23, 0);
  1329. X        put_str("Starting...");
  1330. X        fflush(stdout);
  1331. X    }
  1332. X    cur_row = 23;
  1333. X    cur_col = 0;
  1334. X    procid = vfork();
  1335. X    if (procid == -1) {
  1336. X        perror("fork");
  1337. X        leave(1, "fork failed.");
  1338. X    }
  1339. X    if (procid == 0) {
  1340. X        (void) signal(SIGINT, SIG_IGN);
  1341. X        (void) close(Socket);
  1342. X        execl(Driver, "HUNT", NULL);
  1343. X        /* only get here if exec failed */
  1344. X        kill(getppid(), SIGEMT);    /* tell mom */
  1345. X        _exit(1);
  1346. X    }
  1347. X    if (!daemon_player)
  1348. X    {
  1349. X        mvcur(cur_row, cur_col, 23, 0);
  1350. X        put_str("Connecting...");
  1351. X        fflush(stdout);
  1352. X    }
  1353. X    cur_row = 23;
  1354. X    cur_col = 0;
  1355. X    return 0;
  1356. X}
  1357. X
  1358. X/*
  1359. X * bad_con:
  1360. X *    We had a bad connection.  For the moment we assume that this
  1361. X *    means the game is full.
  1362. X */
  1363. Xbad_con()
  1364. X{
  1365. X    leave(1, "The game is full.  Sorry.");
  1366. X    /* NOTREACHED */
  1367. X}
  1368. X
  1369. X/*
  1370. X * dumpit:
  1371. X *    Handle a core dump signal by not dumping core, just leaving,
  1372. X *    so we end up with a core dump from the driver
  1373. X */
  1374. Xdumpit()
  1375. X{
  1376. X    (void) kill(Master_pid, SIGQUIT);
  1377. X    (void) chdir("coredump");
  1378. X    abort();
  1379. X}
  1380. X
  1381. X/*
  1382. X * sigterm:
  1383. X *    Handle a terminate signal
  1384. X */
  1385. Xsigterm()
  1386. X{
  1387. X    leave(0, NULL);
  1388. X    /* NOTREACHED */
  1389. X}
  1390. X
  1391. X
  1392. X/*
  1393. X * sigemt:
  1394. X *    Handle a emt signal - shouldn't happen on vaxes(?)
  1395. X */
  1396. Xsigemt()
  1397. X{
  1398. X    leave(1, "Unable to start driver.  Try again.");
  1399. X    /* NOTREACHED */
  1400. X}
  1401. X
  1402. X# ifdef INTERNET
  1403. X/*
  1404. X * sigalrm:
  1405. X *    Handle an alarm signal
  1406. X */
  1407. Xsigalrm()
  1408. X{
  1409. X    return;
  1410. X}
  1411. X# endif INTERNET
  1412. X
  1413. X/*
  1414. X * rmnl:
  1415. X *    Remove a '\n' at the end of a string if there is one
  1416. X */
  1417. Xrmnl(s)
  1418. Xchar    *s;
  1419. X{
  1420. X    register char    *cp;
  1421. X    char        *rindex();
  1422. X
  1423. X    cp = rindex(s, '\n');
  1424. X    if (cp != NULL)
  1425. X        *cp = '\0';
  1426. X}
  1427. X
  1428. X/*
  1429. X * intr:
  1430. X *    Handle a interrupt signal
  1431. X */
  1432. Xintr()
  1433. X{
  1434. X    if (!daemon_player)
  1435. X    {
  1436. X        register int    ch;
  1437. X        register int    explained;
  1438. X        register int    y, x;
  1439. X    
  1440. X        (void) signal(SIGINT, SIG_IGN);
  1441. X        y = cur_row;
  1442. X        x = cur_col;
  1443. X        mvcur(cur_row, cur_col, 23, 0);
  1444. X        cur_row = 23;
  1445. X        cur_col = 0;
  1446. X        put_str("Really quit? ");
  1447. X        clear_eol();
  1448. X        fflush(stdout);
  1449. X        explained = FALSE;
  1450. X        for (;;) {
  1451. X            ch = getchar();
  1452. X            if (isupper(ch))
  1453. X                ch = tolower(ch);
  1454. X            if (ch == 'y') {
  1455. X                (void) write(Socket, "q", 1);
  1456. X                (void) close(Socket);
  1457. X                leave(0, NULL);
  1458. X            }
  1459. X            else if (ch == 'n') {
  1460. X                (void) signal(SIGINT, intr);
  1461. X                mvcur(cur_row, cur_col, y, x);
  1462. X                cur_row = y;
  1463. X                cur_col = x;
  1464. X                fflush(stdout);
  1465. X                return;
  1466. X            }
  1467. X            if (!explained) {
  1468. X                put_str("(Y or N) ");
  1469. X                fflush(stdout);
  1470. X                explained = TRUE;
  1471. X            }
  1472. X            (void) putchar(CTRL(G));
  1473. X            (void) fflush(stdout);
  1474. X        }
  1475. X    }
  1476. X    else
  1477. X    {
  1478. X        leave (0, NULL);
  1479. X    }
  1480. X}
  1481. X
  1482. X/*
  1483. X * leave:
  1484. X *    Leave the game somewhat gracefully, restoring all current
  1485. X *    tty stats.
  1486. X */
  1487. Xleave(eval, mesg)
  1488. Xint    eval;
  1489. Xchar    *mesg;
  1490. X{
  1491. X    if (!daemon_player)
  1492. X    {
  1493. X        mvcur(cur_row, cur_col, 23, 0);
  1494. X        if (mesg == NULL)
  1495. X            clear_eol();
  1496. X        else {
  1497. X            put_str(mesg);
  1498. X            clear_eol();
  1499. X            putchar('\n');
  1500. X            fflush(stdout);        /* flush in case VE changes pages */
  1501. X        } 
  1502. X        resetty();
  1503. X        _puts(VE);
  1504. X        _puts(TE);
  1505. X    }
  1506. X    if (eval == -1)
  1507. X        /* abort(); */ return;
  1508. X    exit(eval);
  1509. X}
  1510. X
  1511. X/*
  1512. X * tstp:
  1513. X *    Handle stop and start signals
  1514. X */
  1515. Xtstp()
  1516. X{
  1517. X    static struct sgttyb    tty;
  1518. X    int    y, x;
  1519. X
  1520. X    if (!daemon_player)
  1521. X    {
  1522. X    
  1523. X        tty = _tty;
  1524. X        y = cur_row;
  1525. X        x = cur_col;
  1526. X        mvcur(cur_row, cur_col, 23, 0);
  1527. X        cur_row = 23;
  1528. X        cur_col = 0;
  1529. X        _puts(VE);
  1530. X        _puts(TE);
  1531. X        (void) fflush(stdout);
  1532. X        resetty();
  1533. X    }
  1534. X    (void) kill(getpid(), SIGSTOP);
  1535. X    (void) signal(SIGTSTP, tstp);
  1536. X    if (!daemon_player)
  1537. X    {
  1538. X        _tty = tty;
  1539. X        (void) stty(_tty_ch, &_tty);
  1540. X        _puts(TI);
  1541. X        _puts(VS);
  1542. X        cur_row = y;
  1543. X        cur_col = x;
  1544. X        _puts(tgoto(CM, cur_row, cur_col));
  1545. X        redraw_screen();
  1546. X        fflush(stdout);
  1547. X    }
  1548. X}
  1549. X
  1550. Xenv_init()
  1551. X{
  1552. X    register int    i;
  1553. X    char    *envp, *envname, *s, *index();
  1554. X
  1555. X    for (i = 0; i < 256; i++)
  1556. X        map_key[i] = (char) i;
  1557. X
  1558. X    envname = NULL;
  1559. X    if ((envp = getenv("HUNT")) != NULL) {
  1560. X        while ((s = index(envp, '=')) != NULL) {
  1561. X            if (strncmp(envp, "name=", s - envp + 1) == 0) {
  1562. X                envname = s + 1;
  1563. X                if ((s = index(envp, ',')) == NULL) {
  1564. X                    *envp = '\0';
  1565. X                    break;
  1566. X                }
  1567. X                *s = '\0';
  1568. X                envp = s + 1;
  1569. X            }            /* must be last option */
  1570. X            else if (strncmp(envp, "mapkey=", s - envp + 1) == 0) {
  1571. X                for (s = s + 1; *s != '\0'; s += 2) {
  1572. X                    map_key[(unsigned int) *s] = *(s + 1);
  1573. X                    if (*(s + 1) == '\0') {
  1574. X                        break;
  1575. X                    }
  1576. X                }
  1577. X                *envp = '\0';
  1578. X                break;
  1579. X            } else {
  1580. X                *s = '\0';
  1581. X                printf("unknown option %s\n", envp);
  1582. X                if ((s = index(envp, ',')) == NULL) {
  1583. X                    *envp = '\0';
  1584. X                    break;
  1585. X                }
  1586. X                envp = s + 1;
  1587. X            }
  1588. X        }
  1589. X        if (*envp != '\0')
  1590. X            if (envname == NULL)
  1591. X                envname = envp;
  1592. X            else
  1593. X                printf("unknown option %s\n", envp);
  1594. X    }
  1595. X    if (envname != NULL) {
  1596. X        (void) strcpy(name, envname);
  1597. X        printf("Entering as '%s'\n", envname);
  1598. X    }
  1599. X    else if (name[0] == '\0') {
  1600. X        printf("Enter your code name: ");
  1601. X        if (fgets(name, sizeof name, stdin) == NULL)
  1602. X            exit(1);
  1603. X    }
  1604. X    rmnl(name);
  1605. X}
  1606. END_OF_FILE
  1607. if test 16374 -ne `wc -c <'hunt.c'`; then
  1608.     echo shar: \"'hunt.c'\" unpacked with wrong size!
  1609. fi
  1610. # end of 'hunt.c'
  1611. fi
  1612. if test -f 'shots.c' -a "${1}" != "-c" ; then 
  1613.   echo shar: Will not clobber existing file \"'shots.c'\"
  1614. else
  1615. echo shar: Extracting \"'shots.c'\" \(16569 characters\)
  1616. sed "s/^X//" >'shots.c' <<'END_OF_FILE'
  1617. X/*
  1618. X * Copyright (c) 1985 Regents of the University of California.
  1619. X * All rights reserved.
  1620. X *
  1621. X * Redistribution and use in source and binary forms are permitted
  1622. X * provided that the above copyright notice and this paragraph are
  1623. X * duplicated in all such forms and that any documentation,
  1624. X * advertising materials, and other materials related to such
  1625. X * distribution and use acknowledge that the software was developed
  1626. X * by the University of California, Berkeley.  The name of the
  1627. X * University may not be used to endorse or promote products derived
  1628. X * from this software without specific prior written permission.
  1629. X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  1630. X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  1631. X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  1632. X */
  1633. X
  1634. X#ifndef lint
  1635. Xstatic char sccsid[] = "@(#)shots.c    5.2 (Berkeley) 6/27/88";
  1636. X#endif /* not lint */
  1637. X
  1638. X/*
  1639. X *  Hunt
  1640. X *  Copyright (c) 1985 Conrad C. Huang, Gregory S. Couch, Kenneth C.R.C. Arnold
  1641. X *  San Francisco, California
  1642. X */
  1643. X
  1644. X# include    "hunt.h"
  1645. X# include    <signal.h>
  1646. X
  1647. X# define    PLUS_DELTA(x, max)    if (x < max) x++; else x--
  1648. X# define    MINUS_DELTA(x, min)    if (x > min) x--; else x++
  1649. X
  1650. X/*
  1651. X * moveshots:
  1652. X *    Move the shots already in the air, taking explosions into account
  1653. X */
  1654. Xmoveshots()
  1655. X{
  1656. X    register BULLET    *bp, *next;
  1657. X    register PLAYER    *pp;
  1658. X    register int    x, y;
  1659. X    register BULLET    *blist;
  1660. X    register int    i;
  1661. X
  1662. X    rollexpl();
  1663. X    if (Bullets == NULL)
  1664. X        goto ret;
  1665. X
  1666. X    /*
  1667. X     * First we move through the bullet list BULSPD times, looking
  1668. X     * for things we may have run into.  If we do run into
  1669. X     * something, we set up the explosion and disappear, checking
  1670. X     * for damage to any player who got in the way.
  1671. X     */
  1672. X
  1673. X    blist = Bullets;
  1674. X    Bullets = NULL;
  1675. X    for (bp = blist; bp != NULL; bp = next) {
  1676. X        next = bp->b_next;
  1677. X        x = bp->b_x;
  1678. X        y = bp->b_y;
  1679. X        Maze[y][x] = bp->b_over;
  1680. X        for (pp = Player; pp < End_player; pp++)
  1681. X            check(pp, y, x);
  1682. X# ifdef MONITOR
  1683. X        for (pp = Monitor; pp < End_monitor; pp++)
  1684. X            check(pp, y, x);
  1685. X# endif MONITOR
  1686. X
  1687. X        for (i = 0; i < BULSPD; i++) {
  1688. X            if (bp->b_expl)
  1689. X                break;
  1690. X
  1691. X            x = bp->b_x;
  1692. X            y = bp->b_y;
  1693. X
  1694. X            switch (bp->b_face) {
  1695. X              case LEFTS:
  1696. X                x--;
  1697. X                break;
  1698. X              case RIGHT:
  1699. X                x++;
  1700. X                break;
  1701. X              case ABOVE:
  1702. X                y--;
  1703. X                break;
  1704. X              case BELOW:
  1705. X                y++;
  1706. X                break;
  1707. X            }
  1708. X
  1709. X            switch (Maze[y][x]) {
  1710. X              case SHOT:
  1711. X                if (rand_num(100) < 5) {
  1712. X                    zapshot(Bullets, bp);
  1713. X                    zapshot(next, bp);
  1714. X                }
  1715. X                break;
  1716. X              case GRENADE:
  1717. X                if (rand_num(100) < 10) {
  1718. X                    zapshot(Bullets, bp);
  1719. X                    zapshot(next, bp);
  1720. X                }
  1721. X                break;
  1722. X# ifdef    REFLECT
  1723. X              case WALL4:    /* reflecting walls */
  1724. X                switch (bp->b_face) {
  1725. X                  case LEFTS:
  1726. X                    bp->b_face = BELOW;
  1727. X                    break;
  1728. X                  case RIGHT:
  1729. X                    bp->b_face = ABOVE;
  1730. X                    break;
  1731. X                  case ABOVE:
  1732. X                    bp->b_face = RIGHT;
  1733. X                    break;
  1734. X                  case BELOW:
  1735. X                    bp->b_face = LEFTS;
  1736. X                    break;
  1737. X                }
  1738. X                Maze[y][x] = WALL5;
  1739. X# ifdef MONITOR
  1740. X                for (pp = Monitor; pp < End_monitor; pp++)
  1741. X                    check(pp, y, x);
  1742. X# endif MONITOR
  1743. X                break;
  1744. X              case WALL5:
  1745. X                switch (bp->b_face) {
  1746. X                  case LEFTS:
  1747. X                    bp->b_face = ABOVE;
  1748. X                    break;
  1749. X                  case RIGHT:
  1750. X                    bp->b_face = BELOW;
  1751. X                    break;
  1752. X                  case ABOVE:
  1753. X                    bp->b_face = LEFTS;
  1754. X                    break;
  1755. X                  case BELOW:
  1756. X                    bp->b_face = RIGHT;
  1757. X                    break;
  1758. X                }
  1759. X                Maze[y][x] = WALL4;
  1760. X# ifdef MONITOR
  1761. X                for (pp = Monitor; pp < End_monitor; pp++)
  1762. X                    check(pp, y, x);
  1763. X# endif MONITOR
  1764. X                break;
  1765. X# endif REFLECT
  1766. X# ifdef RANDOM
  1767. X              case DOOR:
  1768. X                switch (rand_num(4)) {
  1769. X                  case 0:
  1770. X                    bp->b_face = ABOVE;
  1771. X                    break;
  1772. X                  case 1:
  1773. X                    bp->b_face = BELOW;
  1774. X                    break;
  1775. X                  case 2:
  1776. X                    bp->b_face = LEFTS;
  1777. X                    break;
  1778. X                  case 3:
  1779. X                    bp->b_face = RIGHT;
  1780. X                    break;
  1781. X                }
  1782. X                break;
  1783. X# endif RANDOM
  1784. X              case LEFTS:
  1785. X              case RIGHT:
  1786. X              case BELOW:
  1787. X              case ABOVE:
  1788. X# ifdef FLY
  1789. X              case FLYER:
  1790. X# endif FLY
  1791. X                /*
  1792. X                 * give the person a chance to catch a
  1793. X                 * grenade if s/he is facing it
  1794. X                 */
  1795. X                if (rand_num(100) < 10
  1796. X                    && opposite(bp->b_face, Maze[y][x])) {
  1797. X                    if (bp->b_owner != NULL)
  1798. X                        message(bp->b_owner,
  1799. X                        "Your charge was absorbed!");
  1800. X                    pp = play_at(y, x);
  1801. X                    pp->p_ammo += bp->b_charge;
  1802. X                    (void) sprintf(Buf,
  1803. X                        "Absorbed charge (good shield!)");
  1804. X                    message(pp, Buf);
  1805. X                    free((char *) bp);
  1806. X                    (void) sprintf(Buf, "%3d", pp->p_ammo);
  1807. X                    cgoto(pp, STAT_AMMO_ROW, STAT_VALUE_COL);
  1808. X                    outstr(pp, Buf, 3);
  1809. X                    goto next_bullet;
  1810. X                }
  1811. X                /* FALLTHROUGH */
  1812. X# ifndef RANDOM
  1813. X              case DOOR:
  1814. X# endif RANDOM
  1815. X              case WALL1:
  1816. X              case WALL2:
  1817. X              case WALL3:
  1818. X                bp->b_expl = TRUE;
  1819. X                break;
  1820. X            }
  1821. X
  1822. X            bp->b_x = x;
  1823. X            bp->b_y = y;
  1824. X        }
  1825. X
  1826. X        bp->b_next = Bullets;
  1827. X        Bullets = bp;
  1828. Xnext_bullet:
  1829. X        ;
  1830. X    }
  1831. X
  1832. X    blist = Bullets;
  1833. X    Bullets = NULL;
  1834. X    for (bp = blist; bp != NULL; bp = next) {
  1835. X        next = bp->b_next;
  1836. X        if (!bp->b_expl) {
  1837. X            save_bullet(bp);
  1838. X# ifdef MONITOR
  1839. X            for (pp = Monitor; pp < End_monitor; pp++)
  1840. X                check(pp, bp->b_y, bp->b_x);
  1841. X# endif MONITOR
  1842. X            continue;
  1843. X        }
  1844. X
  1845. X        chkshot(bp);
  1846. X        free((char *) bp);
  1847. X    }
  1848. X    for (pp = Player; pp < End_player; pp++)
  1849. X        Maze[pp->p_y][pp->p_x] = pp->p_face;
  1850. Xret:
  1851. X    for (pp = Player; pp < End_player; pp++) {
  1852. X# ifdef FLY
  1853. X        if (pp->p_flying >= 0) {
  1854. X            Maze[pp->p_y][pp->p_x] = pp->p_over;
  1855. X            x = pp->p_x + pp->p_flyx;
  1856. X            y = pp->p_y + pp->p_flyy;
  1857. X            if (x < 1) {
  1858. X                x = 1 - x;
  1859. X                pp->p_flyx = -pp->p_flyx;
  1860. X            }
  1861. X            else if (x > WIDTH - 2) {
  1862. X                x = (WIDTH - 2) - (x - (WIDTH - 2));
  1863. X                pp->p_flyx = -pp->p_flyx;
  1864. X            }
  1865. X            if (y < 1) {
  1866. X                y = 1 - y;
  1867. X                pp->p_flyy = -pp->p_flyy;
  1868. X            }
  1869. X            else if (y > HEIGHT - 2) {
  1870. X                y = (HEIGHT - 2) - (y - (HEIGHT - 2));
  1871. X                pp->p_flyy = -pp->p_flyy;
  1872. X            }
  1873. Xagain:            switch (Maze[y][x]) {
  1874. X              case LEFTS:
  1875. X              case RIGHT:
  1876. X              case ABOVE:
  1877. X              case BELOW:
  1878. X              case FLYER:
  1879. X                switch (rand_num(4)) {
  1880. X                  case 0:
  1881. X                    PLUS_DELTA(x, WIDTH - 2);
  1882. X                    break;
  1883. X                  case 1:
  1884. X                    MINUS_DELTA(x, 1);
  1885. X                    break;
  1886. X                  case 2:
  1887. X                    PLUS_DELTA(y, HEIGHT - 2);
  1888. X                    break;
  1889. X                  case 3:
  1890. X                    MINUS_DELTA(y, 1);
  1891. X                    break;
  1892. X                }
  1893. X                goto again;
  1894. X              case WALL1:
  1895. X              case WALL2:
  1896. X              case WALL3:
  1897. X# ifdef    REFLECT
  1898. X              case WALL4:
  1899. X              case WALL5:
  1900. X# endif REFLECT
  1901. X# ifdef    RANDOM
  1902. X              case DOOR:
  1903. X# endif    RANDOM
  1904. X                if (pp->p_flying == 0)
  1905. X                    pp->p_flying++;
  1906. X                break;
  1907. X              case MINE:
  1908. X                checkdam(pp, NULL, NULL, MINDAM, MINE);
  1909. X                Maze[y][x] = SPACE;
  1910. X                break;
  1911. X              case GMINE:
  1912. X                checkdam(pp, NULL, NULL, MINDAM, GMINE);
  1913. X                checkdam(pp, NULL, NULL, MINDAM, GMINE);
  1914. X                Maze[y][x] = SPACE;
  1915. X                break;
  1916. X            }
  1917. X            pp->p_y = y;
  1918. X            pp->p_x = x;
  1919. X            pp->p_over = Maze[y][x];
  1920. X            if (pp->p_flying-- == 0) {
  1921. X                checkdam(pp, NULL, NULL,
  1922. X                    rand_num(pp->p_damage / 5), FALL);
  1923. X                rand_face(pp);
  1924. X                showstat(pp);
  1925. X            }
  1926. X            Maze[y][x] = pp->p_face;
  1927. X            showexpl(y, x, pp->p_face);
  1928. X        }
  1929. X# endif FLY
  1930. X        sendcom(pp, REFRESH);    /* Flush out the explosions */
  1931. X        look(pp);
  1932. X        sendcom(pp, REFRESH);
  1933. X    }
  1934. X# ifdef MONITOR
  1935. X    for (pp = Monitor; pp < End_monitor; pp++)
  1936. X        sendcom(pp, REFRESH);
  1937. X# endif MONITOR
  1938. X
  1939. X# ifdef CONSTANT_MOVE
  1940. X    if (Bullets != NULL) {
  1941. X        bul_alarm(1);
  1942. X        return;
  1943. X    }
  1944. X    for (i = 0; i < EXPLEN; i++)
  1945. X        if (Expl[i] != NULL) {
  1946. X            bul_alarm(1);
  1947. X            return;
  1948. X        }
  1949. X    bul_alarm(0);
  1950. X# endif CONSTANT_MOVE
  1951. X
  1952. X    return;
  1953. X}
  1954. X
  1955. Xsave_bullet(bp)
  1956. Xregister BULLET    *bp;
  1957. X{
  1958. X    bp->b_over = Maze[bp->b_y][bp->b_x];
  1959. X    switch (bp->b_over) {
  1960. X      case SHOT:
  1961. X      case GRENADE:
  1962. X      case SATCHEL:
  1963. X      case BOMB:
  1964. X# ifdef OOZE
  1965. X      case SLIME:
  1966. X# ifdef VOLCANO
  1967. X      case LAVA:
  1968. X# endif VOLCANO
  1969. X# endif OOZE
  1970. X        find_under(Bullets, bp);
  1971. X        break;
  1972. X    }
  1973. X
  1974. X    switch (bp->b_over) {
  1975. X      case LEFTS:
  1976. X      case RIGHT:
  1977. X      case ABOVE:
  1978. X      case BELOW:
  1979. X# ifdef FLY
  1980. X      case FLYER:
  1981. X# endif FLY
  1982. X        mark_player(bp);
  1983. X        break;
  1984. X        
  1985. X      default:
  1986. X        Maze[bp->b_y][bp->b_x] = bp->b_type;
  1987. X        break;
  1988. X    }
  1989. X
  1990. X    bp->b_next = Bullets;
  1991. X    Bullets = bp;
  1992. X}
  1993. X
  1994. X/*
  1995. X * chkshot
  1996. X *    Handle explosions
  1997. X */
  1998. Xchkshot(bp)
  1999. Xregister BULLET    *bp;
  2000. X{
  2001. X    register int    y, x;
  2002. X    register int    dy, dx, absdy;
  2003. X    register int    delta, damage;
  2004. X    register char    expl;
  2005. X    register PLAYER    *pp;
  2006. X
  2007. X    switch (bp->b_type) {
  2008. X      case SHOT:
  2009. X      case MINE:
  2010. X        delta = 0;
  2011. X        break;
  2012. X      case GRENADE:
  2013. X      case GMINE:
  2014. X        delta = 1;
  2015. X        break;
  2016. X      case SATCHEL:
  2017. X        delta = 2;
  2018. X        break;
  2019. X      case BOMB:
  2020. X        delta = 3;
  2021. X        break;
  2022. X# ifdef    OOZE
  2023. X      case SLIME:
  2024. X# ifdef VOLCANO
  2025. X      case LAVA:
  2026. X# endif VOLCANO
  2027. X        chkslime(bp);
  2028. X        return;
  2029. X# endif    OOZE
  2030. X    }
  2031. X    for (y = bp->b_y - delta; y <= bp->b_y + delta; y++) {
  2032. X        if (y < 0 || y >= HEIGHT)
  2033. X            continue;
  2034. X        dy = y - bp->b_y;
  2035. X        absdy = (dy < 0) ? -dy : dy;
  2036. X        for (x = bp->b_x - delta; x <= bp->b_x + delta; x++) {
  2037. X            if (x < 0 || x >= WIDTH)
  2038. X                continue;
  2039. X            dx = x - bp->b_x;
  2040. X            if (dx == 0)
  2041. X                expl = (dy == 0) ? '*' : '|';
  2042. X            else if (dy == 0)
  2043. X                expl = '-';
  2044. X            else if (dx == dy)
  2045. X                expl = '\\';
  2046. X            else if (dx == -dy)
  2047. X                expl = '/';
  2048. X            else
  2049. X                expl = '*';
  2050. X            showexpl(y, x, expl);
  2051. X            switch (Maze[y][x]) {
  2052. X              case LEFTS:
  2053. X              case RIGHT:
  2054. X              case ABOVE:
  2055. X              case BELOW:
  2056. X# ifdef FLY
  2057. X              case FLYER:
  2058. X# endif FLY
  2059. X                if (dx < 0)
  2060. X                    dx = -dx;
  2061. X                if (absdy > dx)
  2062. X                    damage = delta - absdy + 1;
  2063. X                else
  2064. X                    damage = delta - dx + 1;
  2065. X                pp = play_at(y, x);
  2066. X                while (damage-- > 0)
  2067. X                    checkdam(pp, bp->b_owner, bp->b_score,
  2068. X                        MINDAM, bp->b_type);
  2069. X                break;
  2070. X              case GMINE:
  2071. X              case MINE:
  2072. X                add_shot((Maze[y][x] == GMINE) ?
  2073. X                    GRENADE : SHOT,
  2074. X                    y, x, LEFTS,
  2075. X                    (Maze[y][x] == GMINE) ?
  2076. X                    GRENREQ : BULREQ,
  2077. X                    (PLAYER *) NULL, TRUE, SPACE);
  2078. X                Maze[y][x] = SPACE;
  2079. X                break;
  2080. X            }
  2081. X        }
  2082. X    }
  2083. X}
  2084. X
  2085. X# ifdef    OOZE
  2086. X/*
  2087. X * chkslime:
  2088. X *    handle slime shot exploding
  2089. X */
  2090. Xchkslime(bp)
  2091. Xregister BULLET    *bp;
  2092. X{
  2093. X    register BULLET    *nbp;
  2094. X
  2095. X    switch (Maze[bp->b_y][bp->b_x]) {
  2096. X      case WALL1:
  2097. X      case WALL2:
  2098. X      case WALL3:
  2099. X# ifdef    REFLECT
  2100. X      case WALL4:
  2101. X      case WALL5:
  2102. X# endif REFLECT
  2103. X# ifdef    RANDOM
  2104. X      case DOOR:
  2105. X# endif    RANDOM
  2106. X        switch (bp->b_face) {
  2107. X          case LEFTS:
  2108. X            bp->b_x++;
  2109. X            break;
  2110. X          case RIGHT:
  2111. X            bp->b_x--;
  2112. X            break;
  2113. X          case ABOVE:
  2114. X            bp->b_y++;
  2115. X            break;
  2116. X          case BELOW:
  2117. X            bp->b_y--;
  2118. X            break;
  2119. X        }
  2120. X        break;
  2121. X    }
  2122. X    nbp = (BULLET *) malloc(sizeof (BULLET));
  2123. X    *nbp = *bp;
  2124. X# ifdef VOLCANO
  2125. X    moveslime(nbp, nbp->b_type == SLIME ? SLIMESPEED : LAVASPEED);
  2126. X# else VOLCANO
  2127. X    moveslime(nbp, SLIMESPEED);
  2128. X# endif VOLCANO
  2129. X}
  2130. X
  2131. X/*
  2132. X * moveslime:
  2133. X *    move the given slime shot speed times and add it back if
  2134. X *    it hasn't fizzled yet
  2135. X */
  2136. Xmoveslime(bp, speed)
  2137. Xregister BULLET    *bp;
  2138. Xregister int    speed;
  2139. X{
  2140. X    register int    i, j, dirmask, count;
  2141. X    register PLAYER    *pp;
  2142. X    register BULLET    *nbp;
  2143. X
  2144. X    if (speed == 0) {
  2145. X        if (bp->b_charge <= 0)
  2146. X            free((char *) bp);
  2147. X        else
  2148. X            save_bullet(bp);
  2149. X        return;
  2150. X    }
  2151. X
  2152. X# ifdef VOLCANO
  2153. X    showexpl(bp->b_y, bp->b_x, bp->b_type == LAVA ? LAVA : '*');
  2154. X# else VOLCANO
  2155. X    showexpl(bp->b_y, bp->b_x, '*');
  2156. X# endif VOLCANO
  2157. X    switch (Maze[bp->b_y][bp->b_x]) {
  2158. X      case LEFTS:
  2159. X      case RIGHT:
  2160. X      case ABOVE:
  2161. X      case BELOW:
  2162. X# ifdef FLY
  2163. X      case FLYER:
  2164. X# endif FLY
  2165. X        pp = play_at(bp->b_y, bp->b_x);
  2166. X        message(pp, "You've been slimed.");
  2167. X        checkdam(pp, bp->b_owner, bp->b_score, MINDAM, bp->b_type);
  2168. X        break;
  2169. X    }
  2170. X
  2171. X    if (--bp->b_charge <= 0) {
  2172. X        free((char *) bp);
  2173. X        return;
  2174. X    }
  2175. X
  2176. X    dirmask = 0;
  2177. X    count = 0;
  2178. X    switch (bp->b_face) {
  2179. X      case LEFTS:
  2180. X        if (!iswall(bp->b_y, bp->b_x - 1))
  2181. X            dirmask |= WEST, count++;
  2182. X        if (!iswall(bp->b_y - 1, bp->b_x))
  2183. X            dirmask |= NORTH, count++;
  2184. X        if (!iswall(bp->b_y + 1, bp->b_x))
  2185. X            dirmask |= SOUTH, count++;
  2186. X        if (dirmask == 0)
  2187. X            if (!iswall(bp->b_y, bp->b_x + 1))
  2188. X                dirmask |= EAST, count++;
  2189. X        break;
  2190. X      case RIGHT:
  2191. X        if (!iswall(bp->b_y, bp->b_x + 1))
  2192. X            dirmask |= EAST, count++;
  2193. X        if (!iswall(bp->b_y - 1, bp->b_x))
  2194. X            dirmask |= NORTH, count++;
  2195. X        if (!iswall(bp->b_y + 1, bp->b_x))
  2196. X            dirmask |= SOUTH, count++;
  2197. X        if (dirmask == 0)
  2198. X            if (!iswall(bp->b_y, bp->b_x - 1))
  2199. X                dirmask |= WEST, count++;
  2200. X        break;
  2201. X      case ABOVE:
  2202. X        if (!iswall(bp->b_y - 1, bp->b_x))
  2203. X            dirmask |= NORTH, count++;
  2204. X        if (!iswall(bp->b_y, bp->b_x - 1))
  2205. X            dirmask |= WEST, count++;
  2206. X        if (!iswall(bp->b_y, bp->b_x + 1))
  2207. X            dirmask |= EAST, count++;
  2208. X        if (dirmask == 0)
  2209. X            if (!iswall(bp->b_y + 1, bp->b_x))
  2210. X                dirmask |= SOUTH, count++;
  2211. X        break;
  2212. X      case BELOW:
  2213. X        if (!iswall(bp->b_y + 1, bp->b_x))
  2214. X            dirmask |= SOUTH, count++;
  2215. X        if (!iswall(bp->b_y, bp->b_x - 1))
  2216. X            dirmask |= WEST, count++;
  2217. X        if (!iswall(bp->b_y, bp->b_x + 1))
  2218. X            dirmask |= EAST, count++;
  2219. X        if (dirmask == 0)
  2220. X            if (!iswall(bp->b_y - 1, bp->b_x))
  2221. X                dirmask |= NORTH, count++;
  2222. X        break;
  2223. X    }
  2224. X    if (count == 0) {
  2225. X        /*
  2226. X         * No place to go.  Just sit here for a while and wait
  2227. X         * for adjacent squares to clear out.
  2228. X         */
  2229. X        save_bullet(bp);
  2230. X        return;
  2231. X    }
  2232. X    if (bp->b_charge < count) {
  2233. X        /* Only bp->b_charge paths may be taken */
  2234. X        while (count > bp->b_charge) {
  2235. X            if (dirmask & WEST)
  2236. X                dirmask &= ~WEST;
  2237. X            else if (dirmask & EAST)
  2238. X                dirmask &= ~EAST;
  2239. X            else if (dirmask & NORTH)
  2240. X                dirmask &= ~NORTH;
  2241. X            else if (dirmask & SOUTH)
  2242. X                dirmask &= ~SOUTH;
  2243. X            count--;
  2244. X        }
  2245. X    }
  2246. X
  2247. X    i = bp->b_charge / count;
  2248. X    j = bp->b_charge % count;
  2249. X    if (dirmask & WEST) {
  2250. X        count--;
  2251. X        nbp = create_shot(bp->b_type, bp->b_y, bp->b_x - 1, LEFTS,
  2252. X            i, bp->b_owner, bp->b_score, TRUE, SPACE);
  2253. X        moveslime(nbp, speed - 1);
  2254. X    }
  2255. X    if (dirmask & EAST) {
  2256. X        count--;
  2257. X        nbp = create_shot(bp->b_type, bp->b_y, bp->b_x + 1, RIGHT,
  2258. X            (count < j) ? i + 1 : i, bp->b_owner, bp->b_score,
  2259. X            TRUE, SPACE);
  2260. X        moveslime(nbp, speed - 1);
  2261. X    }
  2262. X    if (dirmask & NORTH) {
  2263. X        count--;
  2264. X        nbp = create_shot(bp->b_type, bp->b_y - 1, bp->b_x, ABOVE,
  2265. X            (count < j) ? i + 1 : i, bp->b_owner, bp->b_score,
  2266. X            TRUE, SPACE);
  2267. X        moveslime(nbp, speed - 1);
  2268. X    }
  2269. X    if (dirmask & SOUTH) {
  2270. X        count--;
  2271. X        nbp = create_shot(bp->b_type, bp->b_y + 1, bp->b_x, BELOW,
  2272. X            (count < j) ? i + 1 : i, bp->b_owner, bp->b_score,
  2273. X            TRUE, SPACE);
  2274. X        moveslime(nbp, speed - 1);
  2275. X    }
  2276. X
  2277. X    free((char *) bp);
  2278. X}
  2279. X
  2280. X/*
  2281. X * iswall:
  2282. X *    returns whether the given location is a wall
  2283. X */
  2284. Xiswall(y, x)
  2285. Xregister int    y, x;
  2286. X{
  2287. X    if (y < 0 || x < 0 || y >= HEIGHT || x >= WIDTH)
  2288. X        return TRUE;
  2289. X    switch (Maze[y][x]) {
  2290. X      case WALL1:
  2291. X      case WALL2:
  2292. X      case WALL3:
  2293. X# ifdef    REFLECT
  2294. X      case WALL4:
  2295. X      case WALL5:
  2296. X# endif    REFLECT
  2297. X# ifdef    RANDOM
  2298. X      case DOOR:
  2299. X# endif    RANDOM
  2300. X# ifdef VOLCANO
  2301. X      case LAVA:
  2302. X# endif VOLCANO
  2303. X        return TRUE;
  2304. X    }
  2305. X    return FALSE;
  2306. X}
  2307. X# endif    OOZE
  2308. X
  2309. X/*
  2310. X * zapshot:
  2311. X *    Take a shot out of the air.
  2312. X */
  2313. Xzapshot(blist, obp)
  2314. Xregister BULLET    *blist, *obp;
  2315. X{
  2316. X    register BULLET    *bp;
  2317. X    register FLAG    explode;
  2318. X
  2319. X    explode = FALSE;
  2320. X    for (bp = blist; bp != NULL; bp = bp->b_next) {
  2321. X        if (bp->b_x != obp->b_x || bp->b_y != obp->b_y)
  2322. X            continue;
  2323. X        if (bp->b_face == obp->b_face)
  2324. X            continue;
  2325. X        explode = TRUE;
  2326. X        break;
  2327. X    }
  2328. X    if (!explode)
  2329. X        return;
  2330. X    explshot(blist, obp->b_y, obp->b_x);
  2331. X}
  2332. X
  2333. X/*
  2334. X * explshot -
  2335. X *    Make all shots at this location blow up
  2336. X */
  2337. Xexplshot(blist, y, x)
  2338. Xregister BULLET    *blist;
  2339. Xregister int    y, x;
  2340. X{
  2341. X    register BULLET    *bp;
  2342. X
  2343. X    for (bp = blist; bp != NULL; bp = bp->b_next)
  2344. X        if (bp->b_x == x && bp->b_y == y) {
  2345. X            bp->b_expl = TRUE;
  2346. X            if (bp->b_owner != NULL)
  2347. X                message(bp->b_owner, "Shot intercepted");
  2348. X        }
  2349. X}
  2350. X
  2351. X/*
  2352. X * play_at:
  2353. X *    Return a pointer to the player at the given location
  2354. X */
  2355. XPLAYER *
  2356. Xplay_at(y, x)
  2357. Xregister int    y, x;
  2358. X{
  2359. X    register PLAYER    *pp;
  2360. X
  2361. X    for (pp = Player; pp < End_player; pp++)
  2362. X        if (pp->p_x == x && pp->p_y == y)
  2363. X            return pp;
  2364. X    fprintf(stderr, "driver: couldn't find player at (%d,%d)\n", x, y);
  2365. X    abort();
  2366. X    /* NOTREACHED */
  2367. X}
  2368. X
  2369. X/*
  2370. X * opposite:
  2371. X *    Return TRUE if the bullet direction faces the opposite direction
  2372. X *    of the player in the maze
  2373. X */
  2374. Xopposite(face, dir)
  2375. Xint    face;
  2376. Xchar    dir;
  2377. X{
  2378. X    switch (face) {
  2379. X      case LEFTS:
  2380. X        return (dir == RIGHT);
  2381. X      case RIGHT:
  2382. X        return (dir == LEFTS);
  2383. X      case ABOVE:
  2384. X        return (dir == BELOW);
  2385. X      case BELOW:
  2386. X        return (dir == ABOVE);
  2387. X      default:
  2388. X        return FALSE;
  2389. X    }
  2390. X}
  2391. X
  2392. X/*
  2393. X * is_bullet:
  2394. X *    Is there a bullet at the given coordinates?  If so, return
  2395. X *    a pointer to the bullet, otherwise return NULL
  2396. X */
  2397. XBULLET *
  2398. Xis_bullet(y, x)
  2399. Xregister int    y, x;
  2400. X{
  2401. X    register BULLET    *bp;
  2402. X
  2403. X    for (bp = Bullets; bp != NULL; bp = bp->b_next)
  2404. X        if (bp->b_y == y && bp->b_x == x)
  2405. X            return bp;
  2406. X    return NULL;
  2407. X}
  2408. X
  2409. X/*
  2410. X * fixshots:
  2411. X *    change the underlying character of the shots at a location
  2412. X *    to the given character.
  2413. X */
  2414. Xfixshots(y, x, over)
  2415. Xregister int    y, x;
  2416. Xchar        over;
  2417. X{
  2418. X    register BULLET    *bp;
  2419. X
  2420. X    for (bp = Bullets; bp != NULL; bp = bp->b_next)
  2421. X        if (bp->b_y == y && bp->b_x == x)
  2422. X            bp->b_over = over;
  2423. X}
  2424. X
  2425. X/*
  2426. X * find_under:
  2427. X *    find the underlying character for a bullet when it lands
  2428. X *    on another bullet.
  2429. X */
  2430. Xfind_under(blist, bp)
  2431. Xregister BULLET    *blist, *bp;
  2432. X{
  2433. X    register BULLET    *nbp;
  2434. X
  2435. X    for (nbp = blist; nbp != NULL; nbp = nbp->b_next)
  2436. X        if (bp->b_y == nbp->b_y && bp->b_x == nbp->b_x) {
  2437. X            bp->b_over = nbp->b_over;
  2438. X            break;
  2439. X        }
  2440. X}
  2441. X
  2442. X/*
  2443. X * mark_player:
  2444. X *    mark a player as under a shot
  2445. X */
  2446. Xmark_player(bp)
  2447. Xregister BULLET    *bp;
  2448. X{
  2449. X    register PLAYER    *pp;
  2450. X
  2451. X    for (pp = Player; pp < End_player; pp++)
  2452. X        if (pp->p_y == bp->b_y && pp->p_x == bp->b_x) {
  2453. X            pp->p_undershot = TRUE;
  2454. X            break;
  2455. X        }
  2456. X}
  2457. END_OF_FILE
  2458. if test 16569 -ne `wc -c <'shots.c'`; then
  2459.     echo shar: \"'shots.c'\" unpacked with wrong size!
  2460. fi
  2461. # end of 'shots.c'
  2462. fi
  2463. echo shar: End of archive 2 \(of 4\).
  2464. cp /dev/null ark2isdone
  2465. MISSING=""
  2466. for I in 1 2 3 4 ; do
  2467.     if test ! -f ark${I}isdone ; then
  2468.     MISSING="${MISSING} ${I}"
  2469.     fi
  2470. done
  2471. if test "${MISSING}" = "" ; then
  2472.     echo You have unpacked all 4 archives.
  2473.     rm -f ark[1-9]isdone
  2474. else
  2475.     echo You still need to unpack the following archives:
  2476.     echo "        " ${MISSING}
  2477. fi
  2478. ##  End of shell archive.
  2479. exit 0
  2480.