home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / games / volume7 / nethack3 / part27 < prev    next >
Text File  |  1989-07-31  |  56KB  |  2,428 lines

  1. Path: uunet!zephyr.ens.tek.com!tektronix!tekgen!tekred!saab!billr
  2. From: billr@saab.CNA.TEK.COM (Bill Randle)
  3. Newsgroups: comp.sources.games
  4. Subject: v07i082:  NetHack3 -  display oriented dungeons & dragons (Ver. 3.0), Part27/38
  5. Message-ID: <4339@tekred.CNA.TEK.COM>
  6. Date: 24 Jul 89 19:05:57 GMT
  7. Sender: nobody@tekred.CNA.TEK.COM
  8. Lines: 2417
  9. Approved: billr@saab.CNA.TEK.COM
  10.  
  11. Submitted-by: Izchak Miller <izchak@linc.cis.upenn.edu>
  12. Posting-number: Volume 7, Issue 82
  13. Archive-name: NetHack3/Part27
  14.  
  15.  
  16.  
  17. #! /bin/sh
  18. # This is a shell archive.  Remove anything before this line, then unpack
  19. # it by saving it into a file and typing "sh file".  To overwrite existing
  20. # files, type "sh file -c".  You can also feed this as standard input via
  21. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  22. # will see the following message at the end:
  23. #        "End of archive 27 (of 38)."
  24. # Contents:  others/pcmain.c src/mkmaze.c src/sp_lev.c src/unixmain.c
  25. # Wrapped by billr@saab on Sun Jul 23 21:33:10 1989
  26. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  27. if test -f 'others/pcmain.c' -a "${1}" != "-c" ; then 
  28.   echo shar: Will not clobber existing file \"'others/pcmain.c'\"
  29. else
  30. echo shar: Extracting \"'others/pcmain.c'\" \(12406 characters\)
  31. sed "s/^X//" >'others/pcmain.c' <<'END_OF_FILE'
  32. X/*    SCCS Id: @(#)pcmain.c    3.0    88/11/23
  33. X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
  34. X/* NetHack may be freely redistributed.  See license for details. */
  35. X/* main.c - (PC, TOS and AMIGA) version */
  36. X
  37. X#ifndef TOS
  38. X#include <signal.h>
  39. X#else
  40. X#define msmsg    cprintf
  41. X#endif
  42. X#include "hack.h"
  43. X
  44. Xchar orgdir[PATHLEN];
  45. X
  46. Xextern struct permonst mons[NUMMONS];
  47. Xextern char plname[PL_NSIZ], pl_character[PL_CSIZ];
  48. X
  49. Xint (*afternmv)(), (*occupation)();
  50. Xstatic void moveloop();    /* a helper function for MSC optimizer */
  51. X
  52. X#if defined(DGK) && !defined(TOS)
  53. Xstruct finfo    zfinfo = ZFINFO;
  54. Xint i;
  55. X#endif /* DGK && !TOS */
  56. X
  57. Xchar SAVEF[FILENAME];
  58. Xchar *hname = "NetHack";    /* used for syntax messages */
  59. Xchar obuf[BUFSIZ];    /* BUFSIZ is defined in stdio.h */
  60. Xint hackpid;        /* not used anymore, but kept in for save files */
  61. X
  62. Xextern char *nomovemsg;
  63. Xextern long wailmsg;
  64. X#ifdef __TURBOC__    /* tell Turbo C to make a bigger stack */
  65. Xextern unsigned _stklen = 0x2000;    /* 8K */
  66. Xextern unsigned char _osmajor;
  67. X#endif
  68. X
  69. X#ifdef TOS
  70. X#define OMASK    0x8000
  71. X#else
  72. X#define OMASK    0
  73. X#endif
  74. X
  75. Xint
  76. Xmain(argc,argv)
  77. Xint argc;
  78. Xchar *argv[];
  79. X{
  80. X    extern int x_maze_max, y_maze_max;
  81. X    register int fd;
  82. X    register char *dir;
  83. X
  84. X#ifdef AMIGA
  85. X    /*
  86. X     *  Make sure screen IO is initialized before anything happens.
  87. X     */
  88. X    gettty();
  89. X    startup();
  90. X#else /* AMIGA */
  91. X    /* Save current directory and make sure it gets restored when
  92. X     * the game is exited.
  93. X     */
  94. X    int (*funcp)();
  95. X
  96. X# ifdef __TURBOC__
  97. X    if (_osmajor >= 3) hname = argv[0];    /* DOS 3.0+ */
  98. X# endif
  99. X    if (getcwd(orgdir, sizeof orgdir) == NULL) {
  100. X        xputs("NetHack: current directory path too long\n");
  101. X        _exit(1);
  102. X    }
  103. X    funcp = exit;    /* Kludge to get around LINT_ARGS of signal.
  104. X             * This will produce a compiler warning, but that's OK.
  105. X             */
  106. X# ifndef TOS
  107. X    signal(SIGINT, (SIG_RET_TYPE) funcp);    /* restore original directory */
  108. X# endif
  109. X#endif /* AMIGA */
  110. X
  111. X    /* Set the default values of the presentation characters */
  112. X    memcpy((genericptr_t) &showsyms, (genericptr_t) &defsyms, sizeof(struct symbols));
  113. X    if ((dir = getenv("HACKDIR")) != NULL) {
  114. X        Strcpy(hackdir, dir);
  115. X#ifdef CHDIR
  116. X        chdirx (dir, 1);
  117. X#endif
  118. X    }
  119. X#if defined(DGK) && !defined(TOS)
  120. X    /* zero "fileinfo" array to prevent crashes on level change */
  121. X    for (i = 0 ; i <= MAXLEVEL + 1; i++)
  122. X        fileinfo[i] = zfinfo;
  123. X#endif /* DGK && !TOS */
  124. X    initoptions();
  125. X    if (!hackdir[0])
  126. X        Strcpy(hackdir, orgdir);
  127. X#ifdef TOS
  128. X    if(argc > 1 && !strncmp(argv[1], "-D", 2)) {
  129. X#else
  130. X    if(argc > 1 && !strncmp(argv[1], "-d", 2)) {
  131. X#endif
  132. X        argc--;
  133. X        argv++;
  134. X        dir = argv[0]+2;
  135. X        if(*dir == '=' || *dir == ':') dir++;
  136. X        if(!*dir && argc > 1) {
  137. X            argc--;
  138. X            argv++;
  139. X            dir = argv[0];
  140. X        }
  141. X        if(!*dir)
  142. X            error("Flag -d must be followed by a directory name.");
  143. X        Strcpy(hackdir, dir);
  144. X    }
  145. X
  146. X    /*
  147. X     * Now we know the directory containing 'record' and
  148. X     * may do a prscore().
  149. X     */
  150. X#ifdef TOS
  151. X    if(argc > 1 && !strncmp(argv[1], "-S", 2)) {
  152. X#else
  153. X    if(argc > 1 && !strncmp(argv[1], "-s", 2)) {
  154. X#endif
  155. X#ifdef CHDIR
  156. X        chdirx(hackdir,0);
  157. X#endif
  158. X        prscore(argc, argv);
  159. X        exit(0);
  160. X    }
  161. X
  162. X#ifndef AMIGA
  163. X    /*
  164. X     * It seems he really wants to play.
  165. X     * Remember tty modes, to be restored on exit.
  166. X     */
  167. X    gettty();
  168. X    setbuf(stdout,obuf);
  169. X    startup();
  170. X#endif
  171. X    setrandom();
  172. X    cls();
  173. X    u.uhp = 1;    /* prevent RIP on early quits */
  174. X    u.ux = FAR;    /* prevent nscr() */
  175. X#ifndef TOS
  176. X    /*
  177. X     * We cannot do chdir earlier, otherwise gethdate will fail.
  178. X     */
  179. X#ifdef CHDIR
  180. X    chdirx(hackdir,1);
  181. X#endif
  182. X#endif
  183. X    /*
  184. X     * Process options.
  185. X     */
  186. X    while(argc > 1 && argv[1][0] == '-'){
  187. X        argv++;
  188. X        argc--;
  189. X        switch(argv[0][1]){
  190. X#if defined(WIZARD) || defined(EXPLORE_MODE)
  191. X#ifndef TOS
  192. X        case 'D':
  193. X#endif    /* TOS */
  194. X        case 'X':
  195. X# ifdef WIZARD
  196. X            /* Must have "name" set correctly by NETHACK.CNF,
  197. X             * NETHACKOPTIONS, or -U
  198. X             * before this flag to enter wizard mode. */
  199. X            if(!strcmp(plname, WIZARD))
  200. X                wizard = TRUE;
  201. X# endif
  202. X# if defined(WIZARD) && defined(EXPLORE_MODE)
  203. X            else
  204. X# endif
  205. X# ifdef EXPLORE_MODE
  206. X                discover = TRUE;
  207. X# endif
  208. X            break;
  209. X#endif
  210. X#ifdef NEWS
  211. X        case 'N':
  212. X            flags.nonews = TRUE;
  213. X            break;
  214. X#endif
  215. X        case 'U':
  216. X            if(argv[0][2])
  217. X              (void) strncpy(plname, argv[0]+2, sizeof(plname)-1);
  218. X            else if(argc > 1) {
  219. X              argc--;
  220. X              argv++;
  221. X              (void) strncpy(plname, argv[0], sizeof(plname)-1);
  222. X            } else
  223. X                Printf("Player name expected after -U\n");
  224. X            break;
  225. X#ifdef DGK
  226. X        /* Person does not want to use a ram disk
  227. X         */
  228. X        case 'R':
  229. X            ramdisk = FALSE;
  230. X            break;
  231. X#endif
  232. X        case 'C':   /* character role is next character */
  233. X            /* allow -T for Tourist, etc. */
  234. X            (void) strncpy(pl_character, argv[0]+2,
  235. X                sizeof(pl_character)-1);
  236. X        default:
  237. X            Printf("Unknown option: %s\n", *argv);
  238. X        }
  239. X    }
  240. X
  241. X#ifdef DGK
  242. X    set_lock_and_bones();
  243. X    copybones(FROMPERM);
  244. X#endif
  245. X#ifdef WIZARD
  246. X    if (wizard)
  247. X        Strcpy(plname, "wizard");
  248. X    else
  249. X#endif
  250. X    if (!*plname)
  251. X        askname();
  252. X    plnamesuffix();        /* strip suffix from name; calls askname() */
  253. X                /* again if suffix was whole name */
  254. X                /* accepts any suffix */
  255. X#ifndef DGK
  256. X    Strcpy(lock,plname);
  257. X    Strcat(lock,".99");
  258. X#endif
  259. X    start_screen();
  260. X
  261. X    /*
  262. X     * Initialisation of the boundaries of the mazes
  263. X     * Both boundaries have to be even.
  264. X     */
  265. X
  266. X    x_maze_max = COLNO-1;
  267. X    if (x_maze_max % 2)
  268. X        x_maze_max--;
  269. X    y_maze_max = ROWNO-1;
  270. X    if (y_maze_max % 2)
  271. X        y_maze_max--;
  272. X
  273. X    /* initialize static monster strength array */
  274. X    init_monstr();
  275. X
  276. X#ifdef AMIGA
  277. X    (void) strncat(SAVEF, plname, 31-4);
  278. X#else
  279. X    (void) strncat(SAVEF, plname, 8);
  280. X#endif
  281. X    Strcat(SAVEF, ".sav");
  282. X    cls();
  283. X    if (
  284. X#ifdef DGK
  285. X        saveDiskPrompt(1) &&
  286. X#endif /* DGK */
  287. X        ((fd = open(SAVEF, OMASK)) >= 0) &&
  288. X        (uptodate(fd) || !unlink(SAVEF))) {
  289. X#ifndef TOS
  290. X        (void) signal(SIGINT, (SIG_RET_TYPE) done1);
  291. X#endif
  292. X        pline("Restoring old save file...");
  293. X        (void) fflush(stdout);
  294. X        if(!dorecover(fd))
  295. X            goto not_recovered;
  296. X        pline("Hello %s, welcome to NetHack!", plname);
  297. X        /* get shopkeeper set properly if restore is in shop */
  298. X        (void) inshop();
  299. X#ifdef EXPLORE_MODE
  300. X        if (discover) {
  301. X            You("are in non-scoring discovery mode.");
  302. X            pline("Do you want to keep the save file? ");
  303. X            if(yn() == 'n')
  304. X                (void) unlink(SAVEF);
  305. X        }
  306. X#endif
  307. X        flags.move = 0;
  308. X    } else {
  309. Xnot_recovered:
  310. X#ifdef DGK
  311. X        gameDiskPrompt();
  312. X#endif
  313. X        fobj = fcobj = invent = 0;
  314. X        fmon = fallen_down = 0;
  315. X        ftrap = 0;
  316. X        fgold = 0;
  317. X        flags.ident = 1;
  318. X        init_objects();
  319. X        u_init();
  320. X#ifndef TOS
  321. X        (void) signal(SIGINT, (SIG_RET_TYPE) done1);
  322. X#endif
  323. X        mklev();
  324. X        u.ux = xupstair;
  325. X        u.uy = yupstair;
  326. X        (void) inshop();
  327. X        setsee();
  328. X        flags.botlx = 1;
  329. X        /* Fix bug with dog not being made because a monster
  330. X         * was on the level 1 staircase
  331. X         */
  332. X        if(levl[u.ux][u.uy].mmask) mnexto(m_at(u.ux, u.uy));
  333. X        (void) makedog();
  334. X        seemons();
  335. X#ifdef NEWS
  336. X        if(flags.nonews || !readnews())
  337. X            /* after reading news we did docrt() already */
  338. X#endif
  339. X            docrt();
  340. X
  341. X        /* give welcome message before pickup messages */
  342. X        pline("Hello %s, welcome to NetHack!", plname);
  343. X        set_wear();
  344. X        pickup(1);
  345. X        read_engr_at(u.ux,u.uy);
  346. X        flags.move = 0;
  347. X    }
  348. X    flags.moonphase = phase_of_the_moon();
  349. X    if(flags.moonphase == FULL_MOON) {
  350. X        You("are lucky!  Full moon tonight.");
  351. X        if(!u.uluck) change_luck(1);
  352. X    } else if(flags.moonphase == NEW_MOON) {
  353. X        pline("Be careful!  New moon tonight.");
  354. X    }
  355. X
  356. X    initrack();
  357. X#ifndef TOS
  358. X    (void) signal(SIGINT, SIG_IGN);
  359. X#endif
  360. X    /* Help for Microsoft optimizer.  Otherwise main is too large -dgk*/
  361. X    moveloop();
  362. X    return 0;
  363. X}
  364. X
  365. Xstatic void
  366. Xmoveloop()
  367. X{
  368. X    char ch;
  369. X    int abort;
  370. X
  371. X    for(;;) {
  372. X        if(flags.move) {    /* actual time passed */
  373. X
  374. X#ifdef SOUNDS
  375. X            dosounds();
  376. X#endif
  377. X            settrack();
  378. X
  379. X            if(moves%2 == 0 ||
  380. X              (!(Fast & ~INTRINSIC) && (!Fast || rn2(3)))) {
  381. X                movemon();
  382. X#ifdef HARD
  383. X                if(!rn2(u.udemigod?25:(dlevel>30)?50:70))
  384. X#else
  385. X                if(!rn2(70))
  386. X#endif
  387. X                    (void) makemon((struct permonst *)0, 0, 0);
  388. X            }
  389. X            if(Glib) glibr();
  390. X            timeout();
  391. X            ++moves;
  392. X#ifdef THEOLOGY
  393. X            if (u.ublesscnt)  u.ublesscnt--;
  394. X#endif
  395. X#ifdef POLYSELF
  396. X            if(u.mtimedone)
  397. X                if(u.mh < 1) rehumanize();
  398. X            else
  399. X#endif
  400. X                if(u.uhp < 1) {
  401. X                You("die...");
  402. X                done("died");
  403. X                }
  404. X#ifdef POLYSELF
  405. X            if (u.mtimedone) {
  406. X                if (u.mh < u.mhmax) {
  407. X                if (Regeneration || !(moves%20)) {
  408. X                    flags.botl = 1;
  409. X                    u.mh++;
  410. X                }
  411. X                }
  412. X            }
  413. X#endif
  414. X            if(u.uhp < u.uhpmax) {
  415. X                if(u.ulevel > 9) {
  416. X                    int heal;
  417. X
  418. X                    if(HRegeneration || !(moves%3)) {
  419. X                    flags.botl = 1;
  420. X                    if (ACURR(A_CON) <= 12) heal = 1;
  421. X                    else heal = rnd((int) ACURR(A_CON)-12);
  422. X                    if (heal > u.ulevel-9) heal = u.ulevel-9;
  423. X                    u.uhp += heal;
  424. X                    if(u.uhp > u.uhpmax)
  425. X                        u.uhp = u.uhpmax;
  426. X                    }
  427. X                } else if(HRegeneration ||
  428. X                    (!(moves%((MAXULEV+12)/(u.ulevel+2)+1)))) {
  429. X                    flags.botl = 1;
  430. X                    u.uhp++;
  431. X                }
  432. X            }
  433. X#ifdef SPELLS
  434. X            if ((u.uen<u.uenmax) && (!(moves%(19-ACURR(A_INT)/2)))) {
  435. X                u.uen += rn2((int)ACURR(A_WIS)/5 + 1) + 1;
  436. X                if (u.uen > u.uenmax)  u.uen = u.uenmax;
  437. X                flags.botl = 1;
  438. X            }
  439. X#endif
  440. X            if(Teleportation && !rn2(85)) tele();
  441. X#ifdef POLYSELF
  442. X            if(Polymorph && !rn2(100))
  443. X                polyself();
  444. X            if(u.ulycn >= 0 && !rn2(80 - (20 * night())))
  445. X                you_were();
  446. X#endif
  447. X            if(Searching && multi >= 0) (void) dosearch0(1);
  448. X            gethungry();
  449. X            hatch_eggs();
  450. X            invault();
  451. X            amulet();
  452. X#ifdef HARD
  453. X            if (!rn2(40+(int)(ACURR(A_DEX)*3))) u_wipe_engr(rnd(3));
  454. X            if (u.udemigod) {
  455. X
  456. X                u.udg_cnt--;
  457. X                if(u.udg_cnt <= 0) {
  458. X
  459. X                    intervene();
  460. X                    u.udg_cnt = rn1(200, 50);
  461. X                }
  462. X            }
  463. X#endif
  464. X            restore_attrib();
  465. X        }
  466. X        if(multi < 0) {
  467. X            if(!++multi){
  468. X                pline(nomovemsg ? nomovemsg :
  469. X                    "You can move again.");
  470. X                nomovemsg = 0;
  471. X                if(afternmv) (*afternmv)();
  472. X                afternmv = 0;
  473. X            }
  474. X        }
  475. X
  476. X        find_ac();
  477. X        if(!flags.mv || Blind)
  478. X        {
  479. X            seeobjs();
  480. X            seemons();
  481. X            seeglds();
  482. X            nscr();
  483. X        }
  484. X        if(flags.time) flags.botl = 1;
  485. X
  486. X        if(flags.botl || flags.botlx) bot();
  487. X
  488. X        flags.move = 1;
  489. X
  490. X        if(multi >= 0 && occupation) {
  491. X            abort = 0;
  492. X            if (kbhit()) {
  493. X                if ((ch = Getchar()) == ABORT)
  494. X                    abort++;
  495. X#ifdef REDO
  496. X                else
  497. X                    pushch(ch);
  498. X#endif /* REDO */
  499. X            }
  500. X            if(abort || monster_nearby())
  501. X                stop_occupation();
  502. X            else if ((*occupation)() == 0)
  503. X                occupation = 0;
  504. X            if (!(++occtime % 7))
  505. X                (void) fflush(stdout);
  506. X            continue;
  507. X        }
  508. X
  509. X        if((u.uhave_amulet || Clairvoyant) && 
  510. X#ifdef ENDGAME
  511. X            dlevel != ENDLEVEL &&
  512. X#endif
  513. X            !(moves%15) && !rn2(2)) do_vicinity_map();
  514. X
  515. X        u.umoved = FALSE;
  516. X        if(multi > 0) {
  517. X            lookaround();
  518. X            if(!multi) {    /* lookaround may clear multi */
  519. X                flags.move = 0;
  520. X                continue;
  521. X            }
  522. X            if(flags.mv) {
  523. X                if(multi < COLNO && !--multi)
  524. X                    flags.mv = flags.run = 0;
  525. X                domove();
  526. X            } else {
  527. X                --multi;
  528. X                rhack(save_cm);
  529. X            }
  530. X        } else if(multi == 0) {
  531. X#ifdef MAIL
  532. X            ckmailstatus();
  533. X#endif
  534. X            rhack(NULL);
  535. X        }
  536. X        if(multi && multi%7 == 0)
  537. X            (void) fflush(stdout);
  538. X    }
  539. X}
  540. X
  541. X/*
  542. X * plname is filled either by an option (-U Player  or  -UPlayer) or
  543. X * explicitly (by being the wizard) or by askname.
  544. X * It may still contain a suffix denoting pl_character.
  545. X */
  546. Xvoid
  547. Xaskname() {
  548. X    register int c, ct;
  549. X
  550. X    Printf("\nWho are you? ");
  551. X    (void) fflush(stdout);
  552. X    ct = 0;
  553. X    while((c = Getchar()) != '\n') {
  554. X        if(c == EOF) error("End of input\n");
  555. X        /* some people get confused when their erase char is not ^H */
  556. X        if(c == '\b') {
  557. X            if(ct) {
  558. X                ct--;
  559. X#ifdef MSDOS
  560. X                msmsg("\b \b");
  561. X#endif
  562. X            }
  563. X            continue;
  564. X        }
  565. X        if(c != '-')
  566. X        if(c < 'A' || (c > 'Z' && c < 'a') || c > 'z') c = '_';
  567. X        if(ct < sizeof(plname)-1) {
  568. X#ifdef MSDOS
  569. X            msmsg("%c", c);
  570. X#endif
  571. X            plname[ct++] = c;
  572. X    }
  573. X    }
  574. X    plname[ct] = 0;
  575. X    if(ct == 0) askname();
  576. X}
  577. X
  578. X/*VARARGS1*/
  579. Xvoid
  580. Ximpossible(s,x1,x2)
  581. X    register char *s, *x1, *x2;
  582. X{
  583. X    pline(s,x1,x2);
  584. X    pline("Program in disorder - perhaps you'd better Quit.");
  585. X}
  586. X
  587. X#ifdef CHDIR
  588. Xvoid
  589. Xchdirx(dir, wr)
  590. Xchar *dir;
  591. Xboolean wr;
  592. X{
  593. X
  594. X    if(dir && chdir(dir) < 0) {
  595. X        error("Cannot chdir to %s.", dir);
  596. X    }
  597. X
  598. X    /* Change the default drive as well.
  599. X     */
  600. X#ifndef AMIGA
  601. X    chdrive(dir);
  602. X#endif
  603. X
  604. X    /* warn the player if he cannot write the record file */
  605. X    /* perhaps we should also test whether . is writable */
  606. X    /* unfortunately the access systemcall is worthless */
  607. X    if(wr) {
  608. X        register int fd;
  609. X
  610. X        if(dir == NULL)
  611. X#ifdef AMIGA
  612. X        dir = "";
  613. X#else
  614. X        dir = ".";
  615. X#endif
  616. X        if((fd = open(RECORD, 2)) < 0) {
  617. X#ifdef DGK
  618. X        char tmp[PATHLEN];
  619. X
  620. X        Strcpy(tmp, dir);
  621. X        append_slash(tmp);
  622. X        msmsg("Warning: cannot write %s%s\n", tmp, RECORD);
  623. X        getreturn("to continue");
  624. X#else
  625. X        Printf("Warning: cannot write %s/%s", dir, RECORD);
  626. X        getret();
  627. X#endif
  628. X        } else
  629. X        (void) close(fd);
  630. X    }
  631. X}
  632. X#endif /* CHDIR /**/
  633. X
  634. Xvoid
  635. Xstop_occupation()
  636. X{
  637. X    if(occupation) {
  638. X        You("stop %s.", occtxt);
  639. X        occupation = 0;
  640. X#ifdef REDO
  641. X        multi = 0;
  642. X        pushch(0);
  643. X#endif
  644. X    }
  645. X}
  646. END_OF_FILE
  647. if test 12406 -ne `wc -c <'others/pcmain.c'`; then
  648.     echo shar: \"'others/pcmain.c'\" unpacked with wrong size!
  649. fi
  650. # end of 'others/pcmain.c'
  651. fi
  652. if test -f 'src/mkmaze.c' -a "${1}" != "-c" ; then 
  653.   echo shar: Will not clobber existing file \"'src/mkmaze.c'\"
  654. else
  655. echo shar: Extracting \"'src/mkmaze.c'\" \(12398 characters\)
  656. sed "s/^X//" >'src/mkmaze.c' <<'END_OF_FILE'
  657. X/*    SCCS Id: @(#)mkmaze.c    3.0    88/10/25
  658. X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
  659. X/* NetHack may be freely redistributed.  See license for details. */
  660. X
  661. X#include "hack.h"
  662. X
  663. Xextern int x_maze_max, y_maze_max;
  664. X
  665. X#if defined(WALLIFIED_MAZE) || defined(STRONGHOLD)
  666. Xstatic int
  667. Xiswall(x,y)
  668. Xint x,y;
  669. X{
  670. X# ifndef WALLIFIED_MAZE
  671. X    if (x<0 || y<0 || x>COLNO-1 || y>ROWNO-1)
  672. X# else
  673. X    if (x<0 || y<0 || x>COLNO || y>ROWNO)
  674. X# endif
  675. X        return 0;
  676. X    return (IS_WALL(levl[x][y].typ) || IS_DOOR(levl[x][y].typ)
  677. X        || levl[x][y].typ == SDOOR);
  678. X}
  679. X
  680. Xvoid
  681. Xwallification(x1, y1, x2, y2, see)
  682. Xint x1, y1, x2, y2;
  683. Xboolean see;
  684. X{
  685. X    char type;
  686. X    short x,y;
  687. X    register struct rm *room;
  688. X
  689. X    if (x1 < 0) x1 = 0;
  690. X    if (x2 < x1) x2 = x1;
  691. X    if (x2 > COLNO-1) x2 = COLNO-1;
  692. X    if (x1 > x2) x1 = x2;
  693. X    if (y1 < 0) y1 = 0;
  694. X    if (y2 < y1) y2 = y1;
  695. X    if (y2 > COLNO-1) y2 = ROWNO-1;
  696. X    if (y1 > y2) y1 = y2;
  697. X    for(x = x1; x <= x2; x++)
  698. X        for(y = y1; y <= y2; y++) {
  699. X        room = &levl[x][y];
  700. X        type = room->typ;
  701. X        if (iswall(x,y)) {
  702. X            if (IS_DOOR(type)) {
  703. X            room->scrsym = DOOR_SYM;
  704. X            continue;
  705. X            } else
  706. X            if (iswall(x,y-1))
  707. X            if (iswall(x,y+1))
  708. X                if (iswall(x-1,y))
  709. X                if (iswall(x+1,y)) {
  710. X                    room->scrsym = CRWALL_SYM; /* -+- */
  711. X                    room->typ = CROSSWALL;
  712. X                } else {
  713. X                    room->scrsym = TLWALL_SYM; /* -| */
  714. X                    room->typ = TLWALL;
  715. X                }
  716. X                else
  717. X                if (iswall(x+1,y)) {
  718. X                    room->scrsym = TRWALL_SYM; /* |- */
  719. X                    room->typ = TRWALL;
  720. X                } else {
  721. X                    room->typ = VWALL;
  722. X#ifdef STRONGHOLD
  723. X                    if (is_drawbridge_wall(x,y) >= 0)
  724. X                        room->scrsym = DB_VWALL_SYM;
  725. X                    else
  726. X#endif
  727. X                        room->scrsym = VWALL_SYM; /* | */
  728. X                }
  729. X            else
  730. X                if (iswall(x-1,y))
  731. X                if (iswall(x+1,y)) {              
  732. X                    room->scrsym = TUWALL_SYM;  /*  |  */
  733. X                    room->typ = TUWALL;        /* -+- */
  734. X                } else {
  735. X                    room->scrsym = BRCORN_SYM;  /*    | */
  736. X                    room->typ = BRCORNER;        /* -+ */
  737. X                }
  738. X                else
  739. X                if (iswall(x+1,y)) {            
  740. X                    room->scrsym = BLCORN_SYM;  /* |  */
  741. X                    room->typ = BLCORNER;        /* +- */
  742. X                } else {
  743. X                    room->typ = VWALL;
  744. X#ifdef STRONGHOLD
  745. X                    if (is_drawbridge_wall(x,y) >= 0)
  746. X                        room->scrsym = DB_VWALL_SYM;
  747. X                    else
  748. X#endif
  749. X                        room->scrsym = VWALL_SYM; /* | */
  750. X                }
  751. X            else
  752. X            if (iswall(x,y+1))
  753. X                if (iswall(x-1,y))
  754. X                if (iswall(x+1,y)) {
  755. X                    room->scrsym = TDWALL_SYM;  /* -+- */
  756. X                    room->typ = TDWALL;        /*    | */
  757. X                } else {
  758. X                    room->scrsym = TRCORN_SYM;  /* -+ */
  759. X                    room->typ = TRCORNER;        /*    | */
  760. X                }
  761. X                else
  762. X                if (iswall(x+1,y)) {
  763. X                    room->scrsym = TLCORN_SYM;  /* +- */
  764. X                    room->typ = TLCORNER;        /* |  */
  765. X                } else {
  766. X                    room->typ = VWALL;
  767. X#ifdef STRONGHOLD
  768. X                    if (is_drawbridge_wall(x,y) >= 0)
  769. X                        room->scrsym = DB_VWALL_SYM;
  770. X                    else
  771. X#endif
  772. X                        room->scrsym = VWALL_SYM; /* | */
  773. X                }
  774. X            else {
  775. X                room->typ = HWALL;
  776. X#ifdef STRONGHOLD
  777. X                if (is_drawbridge_wall(x,y) >= 0)
  778. X                    room->scrsym = DB_HWALL_SYM;
  779. X                else
  780. X#endif
  781. X                    room->scrsym = HWALL_SYM;
  782. X            }
  783. X            if (type == SDOOR) room->typ = type;
  784. X            if (see) room->seen = 0;
  785. X        } else {
  786. X            switch(room->typ) {
  787. X            case STONE:
  788. X                room->scrsym = STONE_SYM;
  789. X                break;
  790. X            case CORR:
  791. X                room->scrsym = CORR_SYM;
  792. X                break;
  793. X            case ROOM:
  794. X                room->scrsym = ROOM_SYM;
  795. X            }
  796. X            if (see) room->seen = 0;
  797. X        }
  798. X        }
  799. X}
  800. X#endif /* WALLIFIED_MAZE /**/
  801. X
  802. Xstatic boolean
  803. Xokay(x,y,dir)
  804. Xint x,y;
  805. Xregister int dir;
  806. X{
  807. X    move(&x,&y,dir);
  808. X    move(&x,&y,dir);
  809. X    if(x<3 || y<3 || x>x_maze_max || y>y_maze_max || levl[x][y].typ != 0)
  810. X        return(FALSE);
  811. X    return(TRUE);
  812. X}
  813. X
  814. Xstatic void
  815. Xmaze0xy(cc)    /* find random starting point for maze generation */
  816. X    coord    *cc;
  817. X{
  818. X    cc->x = 3 + 2*rn2((x_maze_max>>1) - 1);
  819. X    cc->y = 3 + 2*rn2((y_maze_max>>1) - 1);
  820. X    return;
  821. X}
  822. X
  823. Xstatic const uchar tower[] = {
  824. X    MOAT,      MOAT,     MOAT,     MOAT,    MOAT,      MOAT,     MOAT,
  825. X    MOAT,      MOAT,     TLCORNER, HWALL,    TRCORNER, MOAT,     MOAT,
  826. X    MOAT,      TLCORNER, BRCORNER, ROOM,    BLCORNER, TRCORNER, MOAT,
  827. X    MOAT,      VWALL,    ROOM,     ROOM,    ROOM,      VWALL,    MOAT,
  828. X    MOAT,      BLCORNER, TRCORNER, ROOM,    TLCORNER, BRCORNER, MOAT,
  829. X    MOAT,      MOAT,     BLCORNER, HWALL,    BRCORNER, MOAT,     MOAT,
  830. X    MOAT,      MOAT,     MOAT,     MOAT,    MOAT,      MOAT,     MOAT,
  831. X};
  832. Xvoid
  833. Xmakemaz()
  834. X{
  835. X    int x,y;
  836. X    register int zx,zy;
  837. X    coord mm;
  838. X    int i;
  839. X
  840. X    is_maze_lev = TRUE;
  841. X#ifdef STRONGHOLD
  842. X    xdnladder = ydnladder = xupladder = yupladder = 0;
  843. X    if (dlevel == stronghold_level) {
  844. X        if (load_special("castle")) {
  845. X            xupstair = yupstair = 3;
  846. X            levl[xupstair][yupstair].scrsym = UP_SYM;
  847. X            levl[xupstair][yupstair].typ = STAIRS;
  848. X            return;
  849. X        }
  850. X        impossible("Cannot build the STRONGHOLD!");
  851. X    }
  852. X    if (dlevel == tower_level) {
  853. X        if (load_special("tower1")) {
  854. X            xupstair = yupstair = 3;
  855. X            levl[xupstair][yupstair].scrsym = UP_SYM;
  856. X            levl[xupstair][yupstair].typ = STAIRS;
  857. X            return;
  858. X        }
  859. X        impossible("Cannot build the TOWER!");
  860. X    }
  861. X    if (dlevel == tower_level+1) {
  862. X        if (load_special("tower2")) {
  863. X            xupstair = yupstair = 3;
  864. X            levl[xupstair][yupstair].scrsym = UP_SYM;
  865. X            levl[xupstair][yupstair].typ = STAIRS;
  866. X            return;
  867. X        }
  868. X        impossible("Cannot build the TOWER!");
  869. X    }
  870. X    if (dlevel == tower_level+2) {
  871. X        if (load_special("tower3")) {
  872. X            xupstair = yupstair = 3;
  873. X            levl[xupstair][yupstair].scrsym = UP_SYM;
  874. X            levl[xupstair][yupstair].typ = STAIRS;
  875. X            return;
  876. X        }
  877. X        impossible("Cannot build the TOWER!");
  878. X    }
  879. X# ifdef ENDGAME
  880. X    if (dlevel == ENDLEVEL) {    /* EndGame level */
  881. X        if (load_special("endgame")) {
  882. X            pline("Well done, mortal!");
  883. X            pline("But now thou must face the final Test...");
  884. X            pline("Prove thyself worthy or perish!");
  885. X            u.ux = x_maze_max - 1;
  886. X            u.uy = y_maze_max - 1;
  887. X            xupstair = yupstair = 0;
  888. X            return;
  889. X        }
  890. X        impossible("Cannot build the EndGame Level!");
  891. X        done("escaped");
  892. X    }
  893. X# endif
  894. X#endif
  895. X#ifndef WALLIFIED_MAZE
  896. X    for(x = 2; x < x_maze_max; x++)
  897. X        for(y = 2; y < y_maze_max; y++)
  898. X            levl[x][y].typ = STONE;
  899. X#else
  900. X    for(x = 2; x <= x_maze_max; x++)
  901. X        for(y = 2; y <= y_maze_max; y++)
  902. X            levl[x][y].typ = ((x % 2) && (y % 2)) ? STONE : HWALL;
  903. X#endif
  904. X
  905. X    /* make decoy wizard levels */
  906. X    if((dlevel == wiz_level) ||
  907. X#ifdef STRONGHOLD
  908. X       (!rn2(3) && (dlevel > stronghold_level+1))) {
  909. X#else
  910. X       (!rn2(3) && (dlevel > medusa_level+1))) {
  911. X#endif
  912. X
  913. X        register struct monst *mtmp;
  914. X
  915. X        zx = x_maze_max / 2;
  916. X        zy = y_maze_max / 2;
  917. X        if (!(zx % 2)) zx++;
  918. X        if (!(zy % 2)) zy++;
  919. X        for(y = zy-3, i=0; y <= zy+3; y++)
  920. X        for(x = zx-3; x <= zx+3; x++)
  921. X            levl[x][y].typ = tower[i++];
  922. X        walkfrom(zx+4, zy);
  923. X        if(mtmp = makemon(&mons[PM_HELL_HOUND], zx+1, zy))
  924. X        mtmp->msleep = 1;
  925. X        (void) makemon(&mons[PM_KRAKEN], zx+2, zy+2);
  926. X        if (dlevel == wiz_level) {
  927. X
  928. X        (void) mksobj_at(AMULET_OF_YENDOR, zx, zy);
  929. X        flags.made_amulet = 1;
  930. X#ifndef STRONGHOLD
  931. X        if(mtmp = makemon(&mons[PM_VLAD_THE_IMPALER], zx-1, zy))
  932. X            mtmp->msleep = 1;
  933. X#endif
  934. X        if(mtmp = makemon(&mons[PM_WIZARD_OF_YENDOR], zx, zy))
  935. X            mtmp->msleep = 1;
  936. X        } else {
  937. X        struct obj *ot;
  938. X            /* make a cheap plastic imitation */
  939. X        if (ot = mksobj_at(AMULET_OF_YENDOR, zx, zy))
  940. X            ot-> spe = -1;
  941. X#ifndef STRONGHOLD
  942. X        if (mtmp = makemon(&mons[PM_VAMPIRE_LORD], zx-1, zy))
  943. X            mtmp->msleep = 1;
  944. X#endif
  945. X        (void) makemon(&mons[dprince()], zx, zy);
  946. X        }
  947. X        /* they should wake up when we intrude */
  948. X        (void) maketrap(zx-1, zy, SQBRD);
  949. X        (void) maketrap(zx+1, zy, SQBRD);
  950. X        (void) maketrap(zx, zy-1, SQBRD);
  951. X        (void) maketrap(zx, zy+1, SQBRD);
  952. X    } else {
  953. X        maze0xy(&mm);
  954. X        zx = mm.x;
  955. X        zy = mm.y;
  956. X        walkfrom(zx,zy);
  957. X#ifndef STRONGHOLD    /* it's in the castle */
  958. X# ifdef HARD        /* only one wand of wishing created */
  959. X        if(!rn2(10) || (dlevel == medusa_level + 1))
  960. X# endif
  961. X        (void) mksobj_at(WAN_WISHING, zx, zy);
  962. X#endif
  963. X        (void) mksobj_at(BOULDER, zx, zy);  /* put a boulder on top of it */
  964. X    }
  965. X
  966. X#ifdef WALLIFIED_MAZE
  967. X    wallification(2, 2, x_maze_max, y_maze_max, TRUE);
  968. X#else
  969. X    for(x = 2; x < x_maze_max; x++)
  970. X        for(y = 2; y < y_maze_max; y++) {
  971. X            switch(levl[x][y].typ) {
  972. X            case STONE:
  973. X                levl[x][y].scrsym = STONE_SYM;
  974. X                break;
  975. X            case CORR:
  976. X                levl[x][y].scrsym = CORR_SYM;
  977. X                break;
  978. X            case ROOM:
  979. X                levl[x][y].scrsym = ROOM_SYM;
  980. X                break;
  981. X            case HWALL:
  982. X                levl[x][y].scrsym = HWALL_SYM;
  983. X                break;
  984. X            case VWALL:
  985. X                levl[x][y].scrsym = VWALL_SYM;
  986. X                break;
  987. X            case TLCORNER:
  988. X                levl[x][y].scrsym = TLCORN_SYM;
  989. X                break;
  990. X            case TRCORNER:
  991. X                levl[x][y].scrsym = TRCORN_SYM;
  992. X                break;
  993. X            case BLCORNER:
  994. X                levl[x][y].scrsym = BLCORN_SYM;
  995. X                break;
  996. X            case BRCORNER:
  997. X                levl[x][y].scrsym = BRCORN_SYM;
  998. X                break;
  999. X            }
  1000. X        }
  1001. X#endif
  1002. X    mazexy(&mm);
  1003. X    levl[(xupstair = mm.x)][(yupstair = mm.y)].scrsym = UP_SYM;
  1004. X    levl[xupstair][yupstair].typ = STAIRS;
  1005. X    xdnstair = ydnstair = 0;
  1006. X#ifdef STRONGHOLD
  1007. X    if (dlevel < stronghold_level) {
  1008. X        mazexy(&mm);
  1009. X        levl[(xdnstair = mm.x)][(ydnstair = mm.y)].scrsym = DN_SYM;
  1010. X        levl[xdnstair][ydnstair].typ = STAIRS;
  1011. X    }
  1012. X#endif
  1013. X    for(x = rn1(8,11); x; x--) {
  1014. X        mazexy(&mm);
  1015. X        (void) mkobj_at(rn2(2) ? GEM_SYM : 0, mm.x, mm.y);
  1016. X    }
  1017. X    for(x = rn1(10,2); x; x--) {
  1018. X        mazexy(&mm);
  1019. X        (void) mksobj_at(BOULDER, mm.x, mm.y);
  1020. X    }
  1021. X    mazexy(&mm);
  1022. X    (void) makemon(&mons[PM_MINOTAUR], mm.x, mm.y);
  1023. X    for(x = rn1(5,7); x; x--) {
  1024. X        mazexy(&mm);
  1025. X        (void) makemon((struct permonst *) 0, mm.x, mm.y);
  1026. X    }
  1027. X    for(x = rn1(6,7); x; x--) {
  1028. X        mazexy(&mm);
  1029. X        mkgold(0L,mm.x,mm.y);
  1030. X    }
  1031. X    for(x = rn1(6,7); x; x--)
  1032. X        mktrap(0,1,(struct mkroom *) 0);
  1033. X}
  1034. X
  1035. X#ifdef MSDOS
  1036. X/* Make the mazewalk iterative by faking a stack.  This is needed to
  1037. X * ensure the mazewalk is successful in the limited stack space of
  1038. X * the program.  This iterative version uses the mimumum amount of stack
  1039. X * that is totally safe.
  1040. X */
  1041. Xvoid
  1042. Xwalkfrom(x,y)
  1043. Xint x,y;
  1044. X{
  1045. X#define CELLS (ROWNO * COLNO) / 4        /* a maze cell is 4 squares */
  1046. X    char mazex[CELLS + 1], mazey[CELLS + 1];    /* char's are OK */
  1047. X    int q, a, dir, pos;
  1048. X    int dirs[4];
  1049. X
  1050. X    pos = 1;
  1051. X    mazex[pos] = (char) x;
  1052. X    mazey[pos] = (char) y;
  1053. X    while (pos) {
  1054. X        x = (int) mazex[pos];
  1055. X        y = (int) mazey[pos];
  1056. X#ifndef WALLIFIED_MAZE
  1057. X        levl[x][y].typ = CORR;
  1058. X#else
  1059. X        levl[x][y].typ = ROOM;
  1060. X#endif
  1061. X        q = 0;
  1062. X        for (a = 0; a < 4; a++)
  1063. X            if(okay(x, y, a)) dirs[q++]= a;
  1064. X        if (!q)
  1065. X            pos--;
  1066. X        else {
  1067. X            dir = dirs[rn2(q)];
  1068. X            move(&x, &y, dir);
  1069. X#ifndef WALLIFIED_MAZE
  1070. X            levl[x][y].typ = CORR;
  1071. X#else
  1072. X            levl[x][y].typ = ROOM;
  1073. X#endif
  1074. X            move(&x, &y, dir);
  1075. X            pos++;
  1076. X            if (pos > CELLS)
  1077. X                panic("Overflow in walkfrom");
  1078. X            mazex[pos] = (char) x;
  1079. X            mazey[pos] = (char) y;
  1080. X        }
  1081. X    }
  1082. X}
  1083. X#else
  1084. X
  1085. Xvoid
  1086. Xwalkfrom(x,y) int x,y; {
  1087. Xregister int q,a,dir;
  1088. Xint dirs[4];
  1089. X#ifndef WALLIFIED_MAZE
  1090. X    levl[x][y].typ = CORR;
  1091. X#else
  1092. X    levl[x][y].typ = ROOM;
  1093. X#endif
  1094. X    while(1) {
  1095. X        q = 0;
  1096. X        for(a = 0; a < 4; a++)
  1097. X            if(okay(x,y,a)) dirs[q++]= a;
  1098. X        if(!q) return;
  1099. X        dir = dirs[rn2(q)];
  1100. X        move(&x,&y,dir);
  1101. X#ifndef WALLIFIED_MAZE
  1102. X        levl[x][y].typ = CORR;
  1103. X#else
  1104. X        levl[x][y].typ = ROOM;
  1105. X#endif
  1106. X        move(&x,&y,dir);
  1107. X        walkfrom(x,y);
  1108. X    }
  1109. X}
  1110. X#endif /* MSDOS */
  1111. X
  1112. Xvoid
  1113. Xmove(x,y,dir)
  1114. Xregister int *x, *y;
  1115. Xregister int dir;
  1116. X{
  1117. X    switch(dir){
  1118. X        case 0: --(*y); break;
  1119. X        case 1: (*x)++; break;
  1120. X        case 2: (*y)++; break;
  1121. X        case 3: --(*x); break;
  1122. X    }
  1123. X}
  1124. X
  1125. Xvoid
  1126. Xmazexy(cc)    /* find random point in generated corridors
  1127. X           i.e., don't create items in moats, bunkers, or walls */
  1128. X    coord    *cc;
  1129. X{
  1130. X    int cpt=0;
  1131. X
  1132. X    do {
  1133. X        cc->x = 3 + 2*rn2((x_maze_max>>1) - 1);
  1134. X        cc->y = 3 + 2*rn2((y_maze_max>>1) - 1);
  1135. X        cpt++;
  1136. X#ifndef WALLIFIED_MAZE
  1137. X    } while (cpt < 100 && levl[cc->x][cc->y].typ != CORR);
  1138. X#else
  1139. X    } while (cpt < 100 && levl[cc->x][cc->y].typ != ROOM);
  1140. X#endif
  1141. X    if (cpt >= 100) panic("mazexy: can't find a place!");
  1142. X    return;
  1143. X}
  1144. X
  1145. Xvoid
  1146. Xbound_digging()
  1147. X/* put a non-diggable boundary around the initial portion of a level map.
  1148. X * assumes that no level will initially put things beyond the isok() range.
  1149. X */
  1150. X{
  1151. X    register int x,y;
  1152. X    register boolean found;
  1153. X    int xmin,xmax,ymin,ymax;
  1154. X
  1155. X    found = FALSE;
  1156. X    for(xmin=1; !found; xmin++)
  1157. X        for(y=0; y<=ROWNO-1; y++)
  1158. X            if(levl[xmin][y].typ != STONE) found = TRUE;
  1159. X    xmin -= 2;
  1160. X
  1161. X    found = FALSE;
  1162. X    for(xmax=COLNO-2; !found; xmax--)
  1163. X        for(y=0; y<=ROWNO-1; y++)
  1164. X            if(levl[xmax][y].typ != STONE) found = TRUE;
  1165. X    xmax += 2;
  1166. X
  1167. X    found = FALSE;
  1168. X    for(ymin=1; !found; ymin++)
  1169. X        for(x=xmin; x<=xmax; x++)
  1170. X            if(levl[x][ymin].typ != STONE) found = TRUE;
  1171. X    ymin -= 2;
  1172. X
  1173. X    found = FALSE;
  1174. X    for(ymax=ROWNO-2; !found; ymax--)
  1175. X        for(x=xmin; x<=xmax; x++)
  1176. X            if(levl[x][ymax].typ != STONE) found = TRUE;
  1177. X    ymax += 2;
  1178. X
  1179. X    for(x=xmin; x<=xmax; x++) {
  1180. X        levl[x][ymin].diggable = W_NONDIGGABLE;
  1181. X        levl[x][ymax].diggable = W_NONDIGGABLE;
  1182. X    }
  1183. X
  1184. X    for(y=ymin; y<=ymax; y++) {
  1185. X        levl[xmin][y].diggable = W_NONDIGGABLE;
  1186. X        levl[xmax][y].diggable = W_NONDIGGABLE;
  1187. X    }
  1188. X}
  1189. END_OF_FILE
  1190. if test 12398 -ne `wc -c <'src/mkmaze.c'`; then
  1191.     echo shar: \"'src/mkmaze.c'\" unpacked with wrong size!
  1192. fi
  1193. # end of 'src/mkmaze.c'
  1194. fi
  1195. if test -f 'src/sp_lev.c' -a "${1}" != "-c" ; then 
  1196.   echo shar: Will not clobber existing file \"'src/sp_lev.c'\"
  1197. else
  1198. echo shar: Extracting \"'src/sp_lev.c'\" \(12800 characters\)
  1199. sed "s/^X//" >'src/sp_lev.c' <<'END_OF_FILE'
  1200. X/*    SCCS Id: @(#)sp_lev.c    3.0    89/01/11
  1201. X/*    Copyright (c) 1989 by Jean-Christophe Collet */
  1202. X/* NetHack may be freely redistributed.  See license for details. */
  1203. X
  1204. X/*
  1205. X * This file contains the various functions that are related to the special
  1206. X * levels.
  1207. X * It contains also the special level loader.
  1208. X *
  1209. X */
  1210. X
  1211. X#include "hack.h"
  1212. X
  1213. X#ifdef STRONGHOLD
  1214. X#include "sp_lev.h"
  1215. X
  1216. X#if defined(MSDOS) && !defined(AMIGA)
  1217. X# define RDMODE "rb"
  1218. X#else
  1219. X# define RDMODE "r"
  1220. X#endif
  1221. X
  1222. X#define LEFT    1
  1223. X#define CENTER    2
  1224. X#define RIGHT    3
  1225. X#define TOP    1
  1226. X#define BOTTOM    3
  1227. X
  1228. Xstatic walk walklist[50];
  1229. Xextern int x_maze_max, y_maze_max;
  1230. X
  1231. Xstatic char Map[COLNO][ROWNO];
  1232. Xstatic char robjects[10], rloc_x[10], rloc_y[10], rmonst[10],
  1233. X    ralign[3] = { A_CHAOS, A_NEUTRAL, A_LAW };
  1234. Xstatic xchar xstart, ystart, xsize, ysize;
  1235. X
  1236. X/*
  1237. X * Make walls of the area (x1, y1, x2, y2) non diggable
  1238. X */
  1239. X
  1240. Xstatic void
  1241. Xmake_walls_nondiggable(x1,y1,x2,y2)
  1242. Xxchar x1, y1, x2, y2;
  1243. X{
  1244. X    register xchar x, y;
  1245. X
  1246. X    for(y = y1; y <= y2; y++)
  1247. X        for(x = x1; x <= x2; x++)
  1248. X        if(IS_WALL(levl[x][y].typ))
  1249. X            levl[x][y].diggable |= W_NONDIGGABLE;
  1250. X}
  1251. X
  1252. X/*
  1253. X * Choose randomly the state (nodoor, open, closed or locked) for a door
  1254. X */
  1255. X
  1256. Xstatic int
  1257. Xrnddoor()
  1258. X{
  1259. X    int i;
  1260. X    
  1261. X    i = 1 << rn2(5);
  1262. X    i >>= 1;
  1263. X    return i;
  1264. X}
  1265. X
  1266. X/* 
  1267. X * Select a random trap
  1268. X */
  1269. X
  1270. Xstatic int
  1271. Xrndtrap()
  1272. X{
  1273. X    return(rnd(TRAPNUM-1));
  1274. X}
  1275. X
  1276. X/* 
  1277. X * Coordinates in special level files are handled specially:
  1278. X *
  1279. X *    if x or y is -11, we generate a random coordinate.
  1280. X *    if x or y is between -1 and -10, we read one from the corresponding
  1281. X *    register (x0, x1, ... x9).
  1282. X *    if x or y is nonnegative, we convert it from relative to the local map
  1283. X *    to global coordinates.
  1284. X */
  1285. X
  1286. Xstatic void
  1287. Xget_location(x, y)
  1288. Xschar *x, *y;
  1289. X{
  1290. X    int cpt = 0;
  1291. X
  1292. X    if (*x >= 0) {            /* normal locations */
  1293. X        *x += xstart;
  1294. X        *y += ystart;
  1295. X    } else if (*x > -11) {        /* special locations */
  1296. X        *y = ystart + rloc_y[ - *y - 1];
  1297. X        *x = xstart + rloc_x[ - *x - 1];
  1298. X    } else {            /* random location */
  1299. X        do {
  1300. X            *x = xstart + rn2((int)xsize);
  1301. X            *y = ystart + rn2((int)ysize);
  1302. X        } while (cpt < 100 &&
  1303. X             levl[*x][*y].typ != ROOM &&
  1304. X             levl[*x][*y].typ != CORR);
  1305. X        if(cpt >= 100)
  1306. X            panic("get_location: can't find a place!");
  1307. X    }
  1308. X
  1309. X    if (*x < 0 || *x > x_maze_max || *y < 0 || *y > y_maze_max) {
  1310. X        impossible("get_location: (%d,%d) out of bounds", *x, *y);
  1311. X        *x = x_maze_max; *y = y_maze_max;
  1312. X    }
  1313. X}
  1314. X
  1315. X/*
  1316. X * Shuffle the registers for locations, objects or monsters
  1317. X */
  1318. X
  1319. Xstatic void
  1320. Xshuffle(list, n)
  1321. Xchar list[];
  1322. Xxchar n;
  1323. X{
  1324. X    int i, j;
  1325. X    char k;
  1326. X
  1327. X    for(i = n-1; i; i--) {
  1328. X        j = rn2(i);
  1329. X
  1330. X        k = list[j];
  1331. X        list[j] = list[i];
  1332. X        list[i] = k;
  1333. X    }
  1334. X}
  1335. X
  1336. X/* 
  1337. X * Shuffle two arrays in the same order (for rloc_x & rloc_y)
  1338. X */
  1339. X
  1340. Xstatic void
  1341. Xshuffle2(list1, list2, n)
  1342. Xchar list1[], list2[];
  1343. Xxchar n;
  1344. X{
  1345. X    int i, j;
  1346. X    char k1, k2;
  1347. X
  1348. X    for(i = n-1; i; i--) {
  1349. X        j = rn2(i);
  1350. X
  1351. X        k1 = list1[j];
  1352. X        k2 = list2[j];
  1353. X
  1354. X        list1[j] = list1[i];
  1355. X        list2[j] = list2[i];
  1356. X
  1357. X        list1[i] = k1;
  1358. X        list2[i] = k2;
  1359. X    }
  1360. X}
  1361. X
  1362. X/* 
  1363. X * NOT YET IMPLEMENTED!!!
  1364. X */
  1365. X
  1366. Xstatic boolean
  1367. Xload_rooms(fd)
  1368. XFILE *fd;
  1369. X{
  1370. X    return FALSE;
  1371. X}
  1372. X
  1373. X/*
  1374. X * Select a random coordinate in the maze.
  1375. X *
  1376. X * We want a place not 'touched' by the loader.  That is, a place in
  1377. X * the maze outside every part of the special level.
  1378. X */
  1379. X
  1380. Xstatic void
  1381. Xmaze1xy(m)
  1382. Xcoord *m;
  1383. X{
  1384. X    do {
  1385. X        m->x = rn1(x_maze_max - 3, 3);
  1386. X        m->y = rn1(y_maze_max - 3, 3);
  1387. X    } while (!(m->x % 2) || !(m->y % 2) || Map[m->x][m->y]);
  1388. X}
  1389. X
  1390. X/* 
  1391. X * The Big Thing: special maze loader
  1392. X *
  1393. X * Could be cleaner, but it works.
  1394. X */
  1395. X
  1396. Xstatic boolean
  1397. Xload_maze(fd)
  1398. XFILE *fd;
  1399. X{
  1400. X    xchar   x, y, n, typ;
  1401. X    char    c;
  1402. X
  1403. X    xchar   numpart = 0, nwalk = 0;
  1404. X    uchar   halign, valign;
  1405. X
  1406. X    int     xi, yi, dir;
  1407. X    coord   mm;
  1408. X    int     mapcount, mapcountmax, mapfact;
  1409. X
  1410. X    region  tmpregion;
  1411. X    door    tmpdoor;
  1412. X    trap    tmptrap;
  1413. X    monster tmpmons;
  1414. X    object  tmpobj;
  1415. X    drawbridge tmpdb;
  1416. X    walk    tmpwalk;
  1417. X    dig     tmpdig;
  1418. X    lad     tmplad;
  1419. X#ifdef ALTARS
  1420. X    altar   tmpaltar;
  1421. X#endif
  1422. X
  1423. X    /* shuffle alignments */
  1424. X    shuffle(ralign,3);
  1425. X
  1426. X    /* Initialize map */
  1427. X    xupstair = yupstair = xdnstair = ydnstair = doorindex = 0;
  1428. X    for(x = 2; x <= x_maze_max; x++)
  1429. X    for(y = 2; y <= y_maze_max; y++) {
  1430. X#ifndef WALLIFIED_MAZE
  1431. X        levl[x][y].typ = STONE;
  1432. X#else
  1433. X        levl[x][y].typ = ((x % 2) && (y % 2)) ? STONE : HWALL;
  1434. X#endif
  1435. X        Map[x][y] = 0;
  1436. X    }
  1437. X
  1438. X    /* Start reading the file */
  1439. X    numpart = fgetc(fd); /* Number of parts */
  1440. X    if (!numpart || numpart > 9)
  1441. X    panic("load_maze error: numpart = %d", (int) numpart);
  1442. X
  1443. X    while (numpart--) {
  1444. X    halign = fgetc(fd); /* Horizontal alignment */
  1445. X    valign = fgetc(fd); /* Vertical alignment */
  1446. X    xsize  = fgetc(fd); /* size in X */
  1447. X    ysize  = fgetc(fd); /* size in Y */
  1448. X
  1449. X    switch((int) halign) {
  1450. X        case LEFT:        xstart = 3;                 break;
  1451. X        case CENTER:    xstart = 2+((x_maze_max-2-xsize)/2);    break;
  1452. X        case RIGHT:     xstart = x_maze_max-xsize-1;        break;
  1453. X    }
  1454. X    switch((int) valign) {
  1455. X        case TOP:        ystart = 3;                 break;
  1456. X        case CENTER:    ystart = 2+((y_maze_max-2-ysize)/2);    break;
  1457. X        case BOTTOM:    ystart = y_maze_max-ysize-1;        break;
  1458. X    }
  1459. X    if (!(xstart % 2)) xstart++;
  1460. X    if (!(ystart % 2)) ystart++;
  1461. X
  1462. X    /* Load the map */
  1463. X    for(y = ystart; y < ystart+ysize; y++)
  1464. X        for(x = xstart; x < xstart+xsize; x++) {
  1465. X        levl[x][y].typ = fgetc(fd);
  1466. X        initsym(x,y);
  1467. X        /* secret doors default closed */
  1468. X        if (levl[x][y].typ == SDOOR)
  1469. X          levl[x][y].doormask = D_CLOSED;
  1470. X        Map[x][y] = 1;
  1471. X        }
  1472. X
  1473. X    n = fgetc(fd); /* Random objects */
  1474. X    if(n) {
  1475. X        (void) fread((genericptr_t)robjects, 1, (int) n, fd);
  1476. X        shuffle(robjects, n);
  1477. X    }
  1478. X
  1479. X    n = fgetc(fd); /* Random locations */
  1480. X    if(n) {
  1481. X        (void) fread((genericptr_t)rloc_x, 1, (int) n, fd);
  1482. X        (void) fread((genericptr_t)rloc_y, 1, (int) n, fd);
  1483. X        shuffle2(rloc_x, rloc_y, n);
  1484. X    }
  1485. X
  1486. X    n = fgetc(fd); /* Random monsters */
  1487. X    if(n) {
  1488. X        (void) fread((genericptr_t)rmonst, 1, (int) n, fd);
  1489. X        shuffle(rmonst, n);
  1490. X    }
  1491. X
  1492. X    n = fgetc(fd); /* Number of subrooms */
  1493. X    while(n--) {
  1494. X        (void) fread((genericptr_t)&tmpregion, sizeof(tmpregion), 1, fd);
  1495. X        if (nroom >= MAXNROFROOMS) continue;
  1496. X
  1497. X        get_location(&tmpregion.x1, &tmpregion.y1);
  1498. X        get_location(&tmpregion.x2, &tmpregion.y2);
  1499. X
  1500. X        rooms[nroom].lx = tmpregion.x1;
  1501. X        rooms[nroom].ly = tmpregion.y1;
  1502. X        rooms[nroom].hx = tmpregion.x2;
  1503. X        rooms[nroom].hy = tmpregion.y2;
  1504. X        rooms[nroom].rtype = tmpregion.rtype;
  1505. X        rooms[nroom].rlit = tmpregion.rlit;
  1506. X        if (tmpregion.rlit == 1)
  1507. X            for(x = rooms[nroom].lx-1; x <= rooms[nroom].hx+1; x++)
  1508. X                for(y = rooms[nroom].ly-1; y <= rooms[nroom].hy+1; y++)
  1509. X                    levl[x][y].lit = 1;
  1510. X
  1511. X        rooms[nroom].fdoor = rooms[nroom].doorct = 0;
  1512. X
  1513. X        ++nroom;
  1514. X        rooms[nroom].hx = -1;
  1515. X    }
  1516. X
  1517. X    n = fgetc(fd); /* Number of doors */
  1518. X    while(n--) {
  1519. X        struct mkroom *croom = &rooms[0], *broom;
  1520. X        int tmp;
  1521. X
  1522. X        (void) fread((genericptr_t)&tmpdoor, sizeof(tmpdoor), 1, fd);
  1523. X
  1524. X        x = tmpdoor.x;    y = tmpdoor.y;
  1525. X        typ = tmpdoor.mask == -1 ? rnddoor() : tmpdoor.mask;
  1526. X
  1527. X        get_location(&x, &y);
  1528. X        levl[x][y].doormask = typ;
  1529. X
  1530. X        /* Now the complicated part, list it with each subroom */
  1531. X        /* The dog move and mail daemon routines use this */
  1532. X        while(croom->hx >= 0 && doorindex < DOORMAX) {
  1533. X            if(croom->hx >= x-1 && croom->lx <= x+1 &&
  1534. X               croom->hy >= y-1 && croom->ly <= y+1) {
  1535. X            /* Found it */
  1536. X            croom->doorct++;
  1537. X
  1538. X            /* Append or insert into doors[] */
  1539. X            broom = croom+1;
  1540. X            if(broom->hx < 0) tmp = doorindex;
  1541. X            else
  1542. X                for(tmp = doorindex; tmp > broom->fdoor; tmp--)
  1543. X                doors[tmp] = doors[tmp-1];
  1544. X
  1545. X            doors[tmp].x = x;
  1546. X            doors[tmp].y = y;
  1547. X            doorindex++;
  1548. X
  1549. X            for( ; broom->hx >= 0; broom++) broom->fdoor++;
  1550. X            }
  1551. X            croom++;
  1552. X        }
  1553. X    }
  1554. X
  1555. X    n = fgetc(fd); /* Number of traps */
  1556. X    while(n--) {
  1557. X        (void) fread((genericptr_t)&tmptrap, sizeof(tmptrap), 1, fd);
  1558. X
  1559. X        x = tmptrap.x;    y = tmptrap.y;
  1560. X        typ = (tmptrap.type == -1 ? rndtrap() : tmptrap.type);
  1561. X
  1562. X        get_location(&x, &y);
  1563. X        (void) maketrap(x, y, typ);
  1564. X    }
  1565. X
  1566. X    n = fgetc(fd);    /* Number of monsters */
  1567. X    while(n--) {
  1568. X        (void) fread((genericptr_t)&tmpmons, sizeof(tmpmons), 1, fd);
  1569. X
  1570. X        x = tmpmons.x;    y = tmpmons.y;
  1571. X        get_location(&x, &y);
  1572. X
  1573. X        if    (tmpmons.class >= 0)
  1574. X            c = tmpmons.class;
  1575. X        else if (tmpmons.class > -11)
  1576. X            c = rmonst[-tmpmons.class - 1];
  1577. X        else
  1578. X            c = 0;
  1579. X
  1580. X        if (!c)
  1581. X            (void) makemon((struct permonst *) 0, x, y);
  1582. X        else if (tmpmons.id != -1)
  1583. X            (void) makemon(&mons[tmpmons.id], x, y);
  1584. X        else
  1585. X            (void) makemon(mkclass(c), x, y);
  1586. X    }
  1587. X
  1588. X    n = fgetc(fd); /* Number of objects */
  1589. X    while(n--) {
  1590. X        (void) fread((genericptr_t) &tmpobj, sizeof(object),1, fd);
  1591. X
  1592. X        x = tmpobj.x;  y = tmpobj.y;
  1593. X        get_location(&x, &y);
  1594. X
  1595. X        if    (tmpobj.class >= 0)
  1596. X            c = tmpobj.class;
  1597. X        else if (tmpobj.class > -11)
  1598. X            c = robjects[-tmpobj.class - 1];
  1599. X        else
  1600. X            c = 0;
  1601. X
  1602. X        if (!c)
  1603. X            (void) mkobj_at(0, x, y);
  1604. X        else if (tmpobj.id != -1)
  1605. X            (void) mksobj_at(tmpobj.id, x, y);
  1606. X        else
  1607. X            (void) mkobj_at(c, x, y);
  1608. X    }
  1609. X
  1610. X    n = fgetc(fd); /* Number of drawbridges */
  1611. X    while(n--) {
  1612. X        (void) fread((genericptr_t)&tmpdb, sizeof(tmpdb), 1, fd);
  1613. X
  1614. X        x = tmpdb.x;  y = tmpdb.y;
  1615. X        get_location(&x, &y);
  1616. X
  1617. X        if (!create_drawbridge(x, y, tmpdb.dir, tmpdb.open))
  1618. X            impossible("Cannot create drawbridge.");
  1619. X    }
  1620. X
  1621. X    n = fgetc(fd); /* Number of mazewalks */
  1622. X    while(n--) {
  1623. X        (void) fread((genericptr_t)&tmpwalk, sizeof(tmpwalk), 1, fd);
  1624. X
  1625. X        get_location(&tmpwalk.x, &tmpwalk.y);
  1626. X
  1627. X        walklist[nwalk++] = tmpwalk;
  1628. X    }
  1629. X
  1630. X    n = fgetc(fd); /* Number of non_diggables */
  1631. X    while(n--) {
  1632. X        (void) fread((genericptr_t)&tmpdig, sizeof(tmpdig), 1, fd);
  1633. X
  1634. X        get_location(&tmpdig.x1, &tmpdig.y1);
  1635. X        get_location(&tmpdig.x2, &tmpdig.y2);
  1636. X
  1637. X        make_walls_nondiggable(tmpdig.x1, tmpdig.y1,
  1638. X                       tmpdig.x2, tmpdig.y2);
  1639. X    }
  1640. X
  1641. X    n = fgetc(fd); /* Number of ladders */
  1642. X    while(n--) {
  1643. X        (void) fread((genericptr_t)&tmplad, sizeof(tmplad), 1, fd);
  1644. X
  1645. X        x = tmplad.x;  y = tmplad.y;
  1646. X        get_location(&x, &y);
  1647. X
  1648. X        levl[x][y].typ = LADDER;
  1649. X        if (tmplad.up == 1) {
  1650. X            xupladder = x;    yupladder = y;
  1651. X            levl[x][y].ladder = LA_UP;
  1652. X        } else {
  1653. X            xdnladder = x;    ydnladder = y;
  1654. X            levl[x][y].ladder = LA_DOWN;
  1655. X        }
  1656. X    }
  1657. X
  1658. X#ifdef ALTARS
  1659. X    n = fgetc(fd); /* Number of altars */
  1660. X    while(n--) {
  1661. X        (void) fread((genericptr_t)&tmpaltar, sizeof(tmpaltar), 1, fd);
  1662. X
  1663. X        x = tmpaltar.x;  y = tmpaltar.y;
  1664. X        get_location(&x, &y);
  1665. X
  1666. X        typ = tmpaltar.align == -11 ? rn2(3) :
  1667. X              tmpaltar.align < 0    ? ralign[-tmpaltar.align-1] :
  1668. X                          tmpaltar.align;
  1669. X        if (tmpaltar.shrine)
  1670. X            typ |= A_SHRINE;
  1671. X
  1672. X        levl[x][y].typ = ALTAR;
  1673. X        levl[x][y].altarmask = typ;
  1674. X    }
  1675. X#endif /* ALTARS /**/
  1676. X    }
  1677. X
  1678. X    while(nwalk--) {
  1679. X        xi = walklist[nwalk].x;
  1680. X        yi = walklist[nwalk].y;
  1681. X        dir = walklist[nwalk].dir;
  1682. X
  1683. X        move(&xi, &yi, dir);
  1684. X        x = xi;
  1685. X        y = yi;
  1686. X
  1687. X#ifndef WALLIFIED_MAZE
  1688. X        levl[x][y].typ = CORR;
  1689. X#else
  1690. X        levl[x][y].typ = ROOM;
  1691. X#endif
  1692. X
  1693. X        /*
  1694. X         * We must be sure that the parity of the coordinates for
  1695. X         * walkfrom() is odd.  But we must also take into account
  1696. X         * what direction was chosen.
  1697. X         */
  1698. X        if(!(x % 2))
  1699. X        if (dir == W_EAST)
  1700. X            x++;
  1701. X        else
  1702. X            x--;
  1703. X
  1704. X#ifndef WALLIFIED_MAZE
  1705. X        levl[x][y].typ = CORR;
  1706. X#else
  1707. X        levl[x][y].typ = ROOM;
  1708. X#endif
  1709. X
  1710. X        if (!(y % 2))
  1711. X        if (dir == W_SOUTH)
  1712. X            y++;
  1713. X        else
  1714. X            y--;
  1715. X
  1716. X        walkfrom(x, y);
  1717. X    }
  1718. X    wallification(2, 2, x_maze_max, y_maze_max, TRUE);
  1719. X
  1720. X    /*
  1721. X     * If there's a significant portion of maze unused by the special level,
  1722. X     * we don't want it empty.
  1723. X     *
  1724. X     * Makes the number of traps, monsters, etc. proportional
  1725. X     * to the size of the maze.
  1726. X     */
  1727. X    mapcountmax = mapcount = (x_maze_max - 2) * (y_maze_max - 2);
  1728. X
  1729. X    for(x = 2; x < x_maze_max; x++)
  1730. X    for(y = 2; y < y_maze_max; y++)
  1731. X        if(Map[x][y]) mapcount--;
  1732. X
  1733. X    if (mapcount > (int) (mapcountmax / 10)) {
  1734. X        mapfact = (int) ((mapcount * 100L) / mapcountmax);
  1735. X        for(x = rnd((int) (20 * mapfact) / 100); x; x--) {
  1736. X            maze1xy(&mm);
  1737. X            (void) mkobj_at(rn2(2) ? GEM_SYM : 0, mm.x, mm.y);
  1738. X        }
  1739. X        for(x = rnd((int) (12 * mapfact) / 100); x; x--) {
  1740. X            maze1xy(&mm);
  1741. X            (void) mksobj_at(BOULDER, mm.x, mm.y);
  1742. X        }
  1743. X        maze1xy(&mm);
  1744. X        (void) makemon(&mons[PM_MINOTAUR], mm.x, mm.y);
  1745. X        for(x = rnd((int) (12 * mapfact) / 100); x; x--) {
  1746. X            maze1xy(&mm);
  1747. X            (void) makemon((struct permonst *) 0, mm.x, mm.y);
  1748. X        }
  1749. X        for(x = rn2((int) (15 * mapfact) / 100); x; x--) {
  1750. X            maze1xy(&mm);
  1751. X            mkgold(0L,mm.x,mm.y);
  1752. X        }
  1753. X        for(x = rn2((int) (15 * mapfact) / 100); x; x--) {
  1754. X            maze1xy(&mm);
  1755. X            (void) maketrap(mm.x, mm.y,rndtrap());
  1756. X        }
  1757. X    }
  1758. X    return TRUE;
  1759. X}
  1760. X
  1761. X/*
  1762. X * General loader
  1763. X */
  1764. X
  1765. Xboolean
  1766. Xload_special(name)
  1767. Xchar *name;
  1768. X{
  1769. X    FILE *fd;
  1770. X    boolean result;
  1771. X    schar c;
  1772. X
  1773. X    fd = fopen(name, RDMODE);
  1774. X    if (!fd) return FALSE;
  1775. X
  1776. X    if ((c = fgetc(fd)) == EOF) {
  1777. X        (void)fclose(fd);
  1778. X        return FALSE;
  1779. X    }
  1780. X
  1781. X    switch (c) {
  1782. X        case 1:     /* Alas, this is not yet implemented. */
  1783. X            result = load_rooms(fd);
  1784. X            break;
  1785. X        case 2:     /* But this is implemented :-) */
  1786. X            result = load_maze(fd);
  1787. X            break;
  1788. X        default:    /* ??? */
  1789. X            result = FALSE;
  1790. X    }
  1791. X    (void)fclose(fd);
  1792. X    return result;
  1793. X}
  1794. X#endif /* STRONGHOLD /**/
  1795. END_OF_FILE
  1796. if test 12800 -ne `wc -c <'src/sp_lev.c'`; then
  1797.     echo shar: \"'src/sp_lev.c'\" unpacked with wrong size!
  1798. fi
  1799. # end of 'src/sp_lev.c'
  1800. fi
  1801. if test -f 'src/unixmain.c' -a "${1}" != "-c" ; then 
  1802.   echo shar: Will not clobber existing file \"'src/unixmain.c'\"
  1803. else
  1804. echo shar: Extracting \"'src/unixmain.c'\" \(12696 characters\)
  1805. sed "s/^X//" >'src/unixmain.c' <<'END_OF_FILE'
  1806. X/*    SCCS Id: @(#)unixmain.c    3.0    89/01/13
  1807. X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
  1808. X/* NetHack may be freely redistributed.  See license for details. */
  1809. X/* main.c - (Unix) version */
  1810. X
  1811. X#include <signal.h>
  1812. X#include <pwd.h>
  1813. X
  1814. X#include "hack.h"
  1815. X
  1816. Xint hackpid = 0;                /* current pid */
  1817. Xint locknum = 0;                /* max num of players */
  1818. X#ifdef DEF_PAGER
  1819. Xchar *catmore = 0;                /* default pager */
  1820. X#endif
  1821. Xchar SAVEF[PL_NSIZ + 11] = "save/";    /* save/99999player */
  1822. Xchar *hname = 0;        /* name of the game (argv[0] of call) */
  1823. Xchar obuf[BUFSIZ];    /* BUFSIZ is defined in stdio.h */
  1824. X
  1825. Xint (*occupation)() = DUMMY;
  1826. Xint (*afternmv)() = DUMMY;
  1827. X#ifdef CHDIR
  1828. Xstatic void chdirx();
  1829. X#endif /* CHDIR */
  1830. Xstatic void whoami(), newgame();
  1831. X
  1832. Xmain(argc,argv)
  1833. Xint argc;
  1834. Xchar *argv[];
  1835. X{
  1836. X    struct passwd *pw;
  1837. X    extern struct passwd *getpwuid();
  1838. X    extern int x_maze_max, y_maze_max;
  1839. X    register int fd;
  1840. X#ifdef CHDIR
  1841. X    register char *dir;
  1842. X#endif
  1843. X#ifdef COMPRESS
  1844. X    char    cmd[80], old[80];
  1845. X#endif
  1846. X    hname = argv[0];
  1847. X    hackpid = getpid();
  1848. X    (void) umask(0);
  1849. X
  1850. X#ifdef CHDIR            /* otherwise no chdir() */
  1851. X    /*
  1852. X     * See if we must change directory to the playground.
  1853. X     * (Perhaps hack runs suid and playground is inaccessible
  1854. X     *  for the player.)
  1855. X     * The environment variable HACKDIR is overridden by a
  1856. X     *  -d command line option (must be the first option given)
  1857. X     */
  1858. X
  1859. X    dir = getenv("HACKDIR");
  1860. X    if(argc > 1 && !strncmp(argv[1], "-d", 2)) {
  1861. X        argc--;
  1862. X        argv++;
  1863. X        dir = argv[0]+2;
  1864. X        if(*dir == '=' || *dir == ':') dir++;
  1865. X        if(!*dir && argc > 1) {
  1866. X            argc--;
  1867. X            argv++;
  1868. X            dir = argv[0];
  1869. X        }
  1870. X        if(!*dir)
  1871. X            error("Flag -d must be followed by a directory name.");
  1872. X    }
  1873. X#endif /* CHDIR /**/
  1874. X    /* Set the default values of the presentation characters */
  1875. X    (void) memcpy((char *) &showsyms, 
  1876. X        (char *) &defsyms, sizeof(struct symbols));
  1877. X    initoptions();
  1878. X    whoami();
  1879. X    /*
  1880. X     * Now we know the directory containing 'record' and
  1881. X     * may do a prscore().
  1882. X     */
  1883. X    if(argc > 1 && !strncmp(argv[1], "-s", 2)) {
  1884. X#ifdef CHDIR
  1885. X        chdirx(dir,0);
  1886. X#endif
  1887. X        prscore(argc, argv);
  1888. X        exit(0);
  1889. X    }
  1890. X
  1891. X    /*
  1892. X     * It seems he really wants to play.
  1893. X     * Remember tty modes, to be restored on exit.
  1894. X     */
  1895. X    gettty();
  1896. X    setbuf(stdout,obuf);
  1897. X    setrandom();
  1898. X    startup();
  1899. X    cls();
  1900. X    u.uhp = 1;    /* prevent RIP on early quits */
  1901. X    u.ux = FAR;    /* prevent nscr() */
  1902. X    (void) signal(SIGHUP, (SIG_RET_TYPE) hangup);
  1903. X
  1904. X    /*
  1905. X     * Find the creation date of this game,
  1906. X     * so as to avoid restoring outdated savefiles.
  1907. X     */
  1908. X    gethdate(hname);
  1909. X
  1910. X    /*
  1911. X     * We cannot do chdir earlier, otherwise gethdate will fail.
  1912. X     */
  1913. X#ifdef CHDIR
  1914. X    chdirx(dir,1);
  1915. X#endif
  1916. X
  1917. X    /*
  1918. X     * Process options.
  1919. X     */
  1920. X    while(argc > 1 && argv[1][0] == '-'){
  1921. X        argv++;
  1922. X        argc--;
  1923. X        switch(argv[0][1]){
  1924. X#if defined(WIZARD) || defined(EXPLORE_MODE)
  1925. X        case 'D':
  1926. X        case 'X':
  1927. X            pw = getpwuid(getuid());
  1928. X# ifdef WIZARD
  1929. X            if(!strcmp(pw->pw_name, WIZARD))
  1930. X                wizard = TRUE;
  1931. X# endif
  1932. X# if defined(WIZARD) && defined(EXPLORE_MODE)
  1933. X            else
  1934. X# endif
  1935. X# ifdef EXPLORE_MODE
  1936. X                discover = TRUE;
  1937. X# endif
  1938. X            break;
  1939. X#endif
  1940. X#ifdef NEWS
  1941. X        case 'n':
  1942. X            flags.nonews = TRUE;
  1943. X            break;
  1944. X#endif
  1945. X        case 'u':
  1946. X            if(argv[0][2])
  1947. X              (void) strncpy(plname, argv[0]+2, sizeof(plname)-1);
  1948. X            else if(argc > 1) {
  1949. X              argc--;
  1950. X              argv++;
  1951. X              (void) strncpy(plname, argv[0], sizeof(plname)-1);
  1952. X            } else
  1953. X                Printf("Player name expected after -u\n");
  1954. X            break;
  1955. X        default:
  1956. X            /* allow -T for Tourist, etc. */
  1957. X            (void) strncpy(pl_character, argv[0]+1,
  1958. X                sizeof(pl_character)-1);
  1959. X
  1960. X            /* Printf("Unknown option: %s\n", *argv); */
  1961. X        }
  1962. X    }
  1963. X
  1964. X    if(argc > 1)
  1965. X        locknum = atoi(argv[1]);
  1966. X#ifdef MAX_NR_OF_PLAYERS
  1967. X    if(!locknum || locknum > MAX_NR_OF_PLAYERS)
  1968. X        locknum = MAX_NR_OF_PLAYERS;
  1969. X#endif
  1970. X#ifdef DEF_PAGER
  1971. X    if(!(catmore = getenv("HACKPAGER")) && !(catmore = getenv("PAGER")))
  1972. X        catmore = DEF_PAGER;
  1973. X#endif
  1974. X#ifdef MAIL
  1975. X    getmailstatus();
  1976. X#endif
  1977. X#ifdef WIZARD
  1978. X    if(wizard) Strcpy(plname, "wizard"); else
  1979. X#endif
  1980. X    if(!*plname || !strncmp(plname, "player", 4)
  1981. X            || !strncmp(plname, "games", 4))
  1982. X        askname();
  1983. X    plnamesuffix();        /* strip suffix from name; calls askname() */
  1984. X                /* again if suffix was whole name */
  1985. X                /* accepts any suffix */
  1986. X#ifdef WIZARD
  1987. X    if(!wizard) {
  1988. X#endif
  1989. X        /*
  1990. X         * check for multiple games under the same name
  1991. X         * (if !locknum) or check max nr of players (otherwise)
  1992. X         */
  1993. X        (void) signal(SIGQUIT,SIG_IGN);
  1994. X        (void) signal(SIGINT,SIG_IGN);
  1995. X        if(!locknum)
  1996. X            Strcpy(lock,plname);
  1997. X        getlock();    /* sets lock if locknum != 0 */
  1998. X#ifdef WIZARD
  1999. X    } else
  2000. X        Strcpy(lock,plname);
  2001. X#endif /* WIZARD /**/
  2002. X    setftty();
  2003. X
  2004. X    /* 
  2005. X     * Initialisation of the boundaries of the mazes
  2006. X     * Both boundaries have to be even.
  2007. X     */
  2008. X     
  2009. X    x_maze_max = COLNO-1;
  2010. X    if (x_maze_max % 2) 
  2011. X        x_maze_max--;
  2012. X    y_maze_max = ROWNO-1;
  2013. X    if (y_maze_max % 2) 
  2014. X        y_maze_max--;
  2015. X
  2016. X    /* initialize static monster strength array */
  2017. X    init_monstr();
  2018. X
  2019. X    Sprintf(SAVEF, "save/%d%s", getuid(), plname);
  2020. X    regularize(SAVEF+5);        /* avoid . or / in name */
  2021. X#ifdef COMPRESS
  2022. X    Strcpy(old,SAVEF);
  2023. X    Strcat(SAVEF,".Z");
  2024. X    if((fd = open(SAVEF,0)) >= 0) {
  2025. X         (void) close(fd);
  2026. X        Strcpy(cmd, COMPRESS);
  2027. X        Strcat(cmd, " -d ");    /* uncompress */
  2028. X# ifdef COMPRESS_OPTIONS
  2029. X        Strcat(cmd, COMPRESS_OPTIONS);
  2030. X        Strcat(cmd, " ");
  2031. X# endif
  2032. X        Strcat(cmd,SAVEF);
  2033. X        (void) system(cmd);
  2034. X    }
  2035. X    Strcpy(SAVEF,old);
  2036. X#endif
  2037. X    if((fd = open(SAVEF,0)) >= 0 &&
  2038. X       (uptodate(fd) || unlink(SAVEF) == 666)) {
  2039. X        (void) signal(SIGINT, (SIG_RET_TYPE) done1);
  2040. X        pline("Restoring old save file...");
  2041. X        (void) fflush(stdout);
  2042. X        if(!dorecover(fd))
  2043. X            goto not_recovered;
  2044. X        pline("Hello %s, welcome to NetHack!", plname);
  2045. X        /* get shopkeeper set properly if restore is in shop */
  2046. X        (void) inshop();
  2047. X#ifdef EXPLORE_MODE
  2048. X        if (discover) {
  2049. X            You("are in non-scoring discovery mode.");
  2050. X            pline("Do you want to keep the save file? ");
  2051. X            if(yn() == 'n')
  2052. X                (void) unlink(SAVEF);
  2053. X        }
  2054. X#endif
  2055. X        flags.move = 0;
  2056. X    } else {
  2057. Xnot_recovered:
  2058. X        newgame();
  2059. X        /* give welcome message before pickup messages */
  2060. X        pline("Hello %s, welcome to NetHack!", plname);
  2061. X#ifdef EXPLORE_MODE
  2062. X        if (discover)
  2063. X            You("are in non-scoring discovery mode.");
  2064. X#endif
  2065. X        flags.move = 0;
  2066. X        set_wear();
  2067. X        pickup(1);
  2068. X        read_engr_at(u.ux,u.uy);
  2069. X    }
  2070. X
  2071. X    flags.moonphase = phase_of_the_moon();
  2072. X    if(flags.moonphase == FULL_MOON) {
  2073. X        You("are lucky!  Full moon tonight.");
  2074. X        if(!u.uluck) change_luck(1);
  2075. X    } else if(flags.moonphase == NEW_MOON) {
  2076. X        pline("Be careful!  New moon tonight.");
  2077. X    }
  2078. X
  2079. X    initrack();
  2080. X
  2081. X    for(;;) {
  2082. X        if(flags.move) {    /* actual time passed */
  2083. X
  2084. X#ifdef SOUNDS
  2085. X            dosounds();
  2086. X#endif
  2087. X            settrack();
  2088. X
  2089. X            if(moves%2 == 0 ||
  2090. X              (!(Fast & ~INTRINSIC) && (!Fast || rn2(3)))) {
  2091. X                movemon();
  2092. X#ifdef HARD
  2093. X                if(!rn2(u.udemigod?25:(dlevel>30)?50:70))
  2094. X#else
  2095. X                if(!rn2(70))
  2096. X#endif
  2097. X                    (void) makemon((struct permonst *)0, 0, 0);
  2098. X            }
  2099. X            if(Glib) glibr();
  2100. X            timeout();
  2101. X            ++moves;
  2102. X#ifdef THEOLOGY
  2103. X            if (u.ublesscnt)  u.ublesscnt--;
  2104. X#endif
  2105. X            if(flags.time) flags.botl = 1;
  2106. X#ifdef POLYSELF
  2107. X            if(u.mtimedone)
  2108. X                if(u.mh < 1) rehumanize();
  2109. X            else
  2110. X#endif
  2111. X                if(u.uhp < 1) {
  2112. X                You("die...");
  2113. X                done("died");
  2114. X                }
  2115. X#ifdef POLYSELF
  2116. X            if (u.mtimedone) {
  2117. X                if (u.mh < u.mhmax) {
  2118. X                if (Regeneration || !(moves%20)) {
  2119. X                    flags.botl = 1;
  2120. X                    u.mh++;
  2121. X                }
  2122. X                }
  2123. X            }
  2124. X#endif
  2125. X            if(u.uhp < u.uhpmax) {
  2126. X                if(u.ulevel > 9) {
  2127. X                    int heal;
  2128. X
  2129. X                    if(HRegeneration || !(moves%3)) {
  2130. X                    flags.botl = 1;
  2131. X                    if (ACURR(A_CON) <= 12) heal = 1;
  2132. X                    else heal = rnd((int) ACURR(A_CON)-12);
  2133. X                    if (heal > u.ulevel-9) heal = u.ulevel-9;
  2134. X                    u.uhp += heal;
  2135. X                    if(u.uhp > u.uhpmax)
  2136. X                        u.uhp = u.uhpmax;
  2137. X                    }
  2138. X                } else if(HRegeneration ||
  2139. X                      (!(moves%((MAXULEV+12)/(u.ulevel+2)+1)))) {
  2140. X                    flags.botl = 1;
  2141. X                    u.uhp++;
  2142. X                }
  2143. X            }
  2144. X#ifdef SPELLS
  2145. X            if ((u.uen<u.uenmax) && (!(moves%(19-ACURR(A_INT)/2)))) {
  2146. X                u.uen += rn2((int)ACURR(A_WIS)/5 + 1) + 1;
  2147. X                if (u.uen > u.uenmax)  u.uen = u.uenmax;
  2148. X                flags.botl = 1;
  2149. X            }
  2150. X#endif
  2151. X            if(Teleportation && !rn2(85)) tele();
  2152. X#ifdef POLYSELF
  2153. X            if(Polymorph && !rn2(100)) polyself();
  2154. X            if(u.ulycn >= 0 && !rn2(80 - (20 * night())))
  2155. X                you_were();
  2156. X#endif
  2157. X            if(Searching && multi >= 0) (void) dosearch0(1);
  2158. X            hatch_eggs();
  2159. X            gethungry();
  2160. X            invault();
  2161. X            amulet();
  2162. X#ifdef HARD
  2163. X            if (!rn2(40+(int)(ACURR(A_DEX)*3))) u_wipe_engr(rnd(3));
  2164. X            if (u.udemigod) {
  2165. X
  2166. X                if(u.udg_cnt) u.udg_cnt--;
  2167. X                if(!u.udg_cnt) {
  2168. X
  2169. X                    intervene();
  2170. X                    u.udg_cnt = rn1(200, 50);
  2171. X                }
  2172. X            }
  2173. X#endif
  2174. X            restore_attrib();
  2175. X        }
  2176. X        if(multi < 0) {
  2177. X            if(!++multi){
  2178. X                pline(nomovemsg ? nomovemsg :
  2179. X                    "You can move again.");
  2180. X                nomovemsg = 0;
  2181. X                if(afternmv) (*afternmv)();
  2182. X                afternmv = 0;
  2183. X            }
  2184. X        }
  2185. X
  2186. X        find_ac();
  2187. X        if(!flags.mv || Blind)
  2188. X        {
  2189. X            seeobjs();
  2190. X            seemons();
  2191. X            seeglds();
  2192. X            nscr();
  2193. X        }
  2194. X        if(flags.botl || flags.botlx) bot();
  2195. X
  2196. X        flags.move = 1;
  2197. X
  2198. X        if(multi >= 0 && occupation) {
  2199. X
  2200. X            if(monster_nearby())
  2201. X                stop_occupation();
  2202. X            else if ((*occupation)() == 0)
  2203. X                occupation = 0;
  2204. X            continue;
  2205. X        }
  2206. X
  2207. X        if((u.uhave_amulet || Clairvoyant) && 
  2208. X#ifdef ENDGAME
  2209. X            dlevel != ENDLEVEL &&
  2210. X#endif
  2211. X            !(moves%15) && !rn2(2)) do_vicinity_map();
  2212. X
  2213. X        u.umoved = FALSE;
  2214. X        if(multi > 0) {
  2215. X            lookaround();
  2216. X            if(!multi) {    /* lookaround may clear multi */
  2217. X                flags.move = 0;
  2218. X                continue;
  2219. X            }
  2220. X            if(flags.mv) {
  2221. X                if(multi < COLNO && !--multi)
  2222. X                    flags.mv = flags.run = 0;
  2223. X                domove();
  2224. X            } else {
  2225. X                --multi;
  2226. X                rhack(save_cm);
  2227. X            }
  2228. X        } else if(multi == 0) {
  2229. X#ifdef MAIL
  2230. X            ckmailstatus();
  2231. X#endif
  2232. X            rhack(NULL);
  2233. X        }
  2234. X        if(multi && multi%7 == 0)
  2235. X            (void) fflush(stdout);
  2236. X    }
  2237. X}
  2238. X
  2239. Xvoid
  2240. Xglo(foo)
  2241. Xregister int foo;
  2242. X{
  2243. X    /* construct the string  xlock.n  */
  2244. X    register char *tf;
  2245. X
  2246. X    tf = lock;
  2247. X    while(*tf && *tf != '.') tf++;
  2248. X    Sprintf(tf, ".%d", foo);
  2249. X}
  2250. X
  2251. X/*
  2252. X * plname is filled either by an option (-u Player  or  -uPlayer) or
  2253. X * explicitly (by being the wizard) or by askname.
  2254. X * It may still contain a suffix denoting pl_character.
  2255. X */
  2256. Xvoid
  2257. Xaskname(){
  2258. Xregister int c,ct;
  2259. X    Printf("\nWho are you? ");
  2260. X    (void) fflush(stdout);
  2261. X    ct = 0;
  2262. X    while((c = Getchar()) != '\n'){
  2263. X        if(c == EOF) error("End of input\n");
  2264. X        /* some people get confused when their erase char is not ^H */
  2265. X        if(c == '\010') {
  2266. X            if(ct) ct--;
  2267. X            continue;
  2268. X        }
  2269. X        if(c != '-')
  2270. X        if(c < 'A' || (c > 'Z' && c < 'a') || c > 'z') c = '_';
  2271. X        if(ct < sizeof(plname)-1) plname[ct++] = c;
  2272. X    }
  2273. X    plname[ct] = 0;
  2274. X    if(ct == 0) askname();
  2275. X}
  2276. X
  2277. X/*VARARGS1*/
  2278. Xvoid
  2279. Ximpossible(s,x1,x2)
  2280. Xregister char *s, *x1, *x2;
  2281. X{
  2282. X    pline(s,x1,x2);
  2283. X    pline("Program in disorder - perhaps you'd better Quit.");
  2284. X}
  2285. X
  2286. X#ifdef CHDIR
  2287. Xstatic void
  2288. Xchdirx(dir, wr)
  2289. Xchar *dir;
  2290. Xboolean wr;
  2291. X{
  2292. X
  2293. X# ifdef SECURE
  2294. X    if(dir                    /* User specified directory? */
  2295. X#  ifdef HACKDIR
  2296. X           && strcmp(dir, HACKDIR)        /* and not the default? */
  2297. X#  endif
  2298. X        ) {
  2299. X        (void) setgid(getgid());
  2300. X        (void) setuid(getuid());        /* Ron Wessels */
  2301. X    }
  2302. X# endif
  2303. X
  2304. X# ifdef HACKDIR
  2305. X    if(dir == NULL)
  2306. X        dir = HACKDIR;
  2307. X# endif
  2308. X
  2309. X    if(dir && chdir(dir) < 0) {
  2310. X        perror(dir);
  2311. X        error("Cannot chdir to %s.", dir);
  2312. X    }
  2313. X
  2314. X    /* warn the player if he cannot write the record file */
  2315. X    /* perhaps we should also test whether . is writable */
  2316. X    /* unfortunately the access systemcall is worthless */
  2317. X    if(wr) {
  2318. X        register int fd;
  2319. X
  2320. X        if(dir == NULL)
  2321. X        dir = ".";
  2322. X        if((fd = open(RECORD, 2)) < 0) {
  2323. X        Printf("Warning: cannot write %s/%s", dir, RECORD);
  2324. X        getret();
  2325. X        } else
  2326. X        (void) close(fd);
  2327. X    }
  2328. X}
  2329. X#endif /* CHDIR /**/
  2330. X
  2331. Xvoid
  2332. Xstop_occupation()
  2333. X{
  2334. X    if(occupation) {
  2335. X        You("stop %s.", occtxt);
  2336. X        occupation = 0;
  2337. X#ifdef REDO
  2338. X        multi = 0;
  2339. X        pushch(0);        
  2340. X#endif
  2341. X    }
  2342. X}
  2343. X
  2344. Xstatic void
  2345. Xwhoami() {
  2346. X    /*
  2347. X     * Who am i? Algorithm: 1. Use name as specified in NETHACKOPTIONS
  2348. X     *            2. Use $USER or $LOGNAME    (if 1. fails)
  2349. X     *            3. Use getlogin()        (if 2. fails)
  2350. X     * The resulting name is overridden by command line options.
  2351. X     * If everything fails, or if the resulting name is some generic
  2352. X     * account like "games", "play", "player", "hack" then eventually
  2353. X     * we'll ask him.
  2354. X     * Note that we trust him here; it is possible to play under
  2355. X     * somebody else's name.
  2356. X     */
  2357. X    register char *s;
  2358. X
  2359. X    if(!*plname && (s = getenv("USER")))
  2360. X        (void) strncpy(plname, s, sizeof(plname)-1);
  2361. X    if(!*plname && (s = getenv("LOGNAME")))
  2362. X        (void) strncpy(plname, s, sizeof(plname)-1);
  2363. X    if(!*plname && (s = getlogin()))
  2364. X        (void) strncpy(plname, s, sizeof(plname)-1);
  2365. X}
  2366. X
  2367. Xstatic void
  2368. Xnewgame() {
  2369. X    fobj = fcobj = invent = 0;
  2370. X    fmon = fallen_down = 0;
  2371. X    ftrap = 0;
  2372. X    fgold = 0;
  2373. X    flags.ident = 1;
  2374. X
  2375. X    init_objects();
  2376. X    u_init();
  2377. X
  2378. X    (void) signal(SIGINT, (SIG_RET_TYPE) done1);
  2379. X
  2380. X    mklev();
  2381. X    u.ux = xupstair;
  2382. X    u.uy = yupstair;
  2383. X    (void) inshop();
  2384. X
  2385. X    setsee();
  2386. X    flags.botlx = 1;
  2387. X
  2388. X    /* Move the monster from under you or else
  2389. X     * makedog() will fail when it calls makemon().
  2390. X     *             - ucsfcgl!kneller
  2391. X     */
  2392. X    if(levl[u.ux][u.uy].mmask) mnexto(m_at(u.ux, u.uy));
  2393. X
  2394. X    (void) makedog();
  2395. X    seemons();
  2396. X#ifdef NEWS
  2397. X    if(flags.nonews || !readnews())
  2398. X        /* after reading news we did docrt() already */
  2399. X#endif
  2400. X        docrt();
  2401. X
  2402. X    return;
  2403. X}
  2404. END_OF_FILE
  2405. if test 12696 -ne `wc -c <'src/unixmain.c'`; then
  2406.     echo shar: \"'src/unixmain.c'\" unpacked with wrong size!
  2407. fi
  2408. # end of 'src/unixmain.c'
  2409. fi
  2410. echo shar: End of archive 27 \(of 38\).
  2411. cp /dev/null ark27isdone
  2412. MISSING=""
  2413. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 ; do
  2414.     if test ! -f ark${I}isdone ; then
  2415.     MISSING="${MISSING} ${I}"
  2416.     fi
  2417. done
  2418. if test "${MISSING}" = "" ; then
  2419.     echo You have unpacked all 38 archives.
  2420.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2421. else
  2422.     echo You still need to unpack the following archives:
  2423.     echo "        " ${MISSING}
  2424. fi
  2425. ##  End of shell archive.
  2426. exit 0
  2427.