home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / games / volume16 / nethack31 / part54 < prev    next >
Internet Message Format  |  1993-02-04  |  58KB

  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: v16i062:  nethack31 - display oriented dungeons & dragons (Ver. 3.1), Part54/108
  5. Message-ID: <4365@master.CNA.TEK.COM>
  6. Date: 1 Feb 93 19:43:32 GMT
  7. Sender: news@master.CNA.TEK.COM
  8. Lines: 2307
  9. Approved: billr@saab.CNA.TEK.COM
  10. Xref: uunet comp.sources.games:1612
  11.  
  12. Submitted-by: izchak@linc.cis.upenn.edu (Izchak Miller)
  13. Posting-number: Volume 16, Issue 62
  14. Archive-name: nethack31/Part54
  15. Supersedes: nethack3p9: Volume 10, Issue 46-102
  16. Environment: Amiga, Atari, Mac, MS-DOS, OS2, Unix, VMS, X11
  17.  
  18.  
  19.  
  20. #! /bin/sh
  21. # This is a shell archive.  Remove anything before this line, then unpack
  22. # it by saving it into a file and typing "sh file".  To overwrite existing
  23. # files, type "sh file -c".  You can also feed this as standard input via
  24. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  25. # will see the following message at the end:
  26. #        "End of archive 54 (of 108)."
  27. # Contents:  src/mklev.c src/save.c
  28. # Wrapped by billr@saab on Wed Jan 27 16:09:07 1993
  29. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  30. if test -f 'src/mklev.c' -a "${1}" != "-c" ; then 
  31.   echo shar: Will not clobber existing file \"'src/mklev.c'\"
  32. else
  33. echo shar: Extracting \"'src/mklev.c'\" \(33549 characters\)
  34. sed "s/^X//" >'src/mklev.c' <<'END_OF_FILE'
  35. X/*    SCCS Id: @(#)mklev.c    3.1    92/10/10    */
  36. X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
  37. X/* NetHack may be freely redistributed.  See license for details. */
  38. X
  39. X#include "hack.h"
  40. X/* #define DEBUG     /* uncomment to enable code debugging */
  41. X
  42. X#ifdef DEBUG
  43. X# ifdef WIZARD
  44. X#define debugpline    if (wizard) pline
  45. X# else
  46. X#define debugpline    pline
  47. X# endif
  48. X#endif
  49. X
  50. X/* for UNIX, Rand #def'd to (long)lrand48() or (long)random() */
  51. X/* croom->lx etc are schar (width <= int), so % arith ensures that */
  52. X/* conversion of result to int is reasonable */
  53. X
  54. X
  55. Xstatic void FDECL(mkfount,(int,struct mkroom *));
  56. X#ifdef SINKS
  57. Xstatic void FDECL(mksink,(struct mkroom *));
  58. X#endif
  59. Xstatic void FDECL(mkaltar,(struct mkroom *));
  60. Xstatic void NDECL(makevtele);
  61. Xstatic void NDECL(clear_level_structures);
  62. Xstatic void NDECL(makelevel);
  63. Xstatic boolean FDECL(bydoor,(XCHAR_P,XCHAR_P));
  64. Xstatic struct mkroom *FDECL(find_branch_room, (coord *));
  65. Xstatic struct mkroom *FDECL(pos_to_room, (XCHAR_P, XCHAR_P));
  66. Xstatic boolean FDECL(place_niche,(struct mkroom *,int*,int*,int*));
  67. Xstatic void FDECL(makeniche,(int));
  68. Xstatic void NDECL(make_niches);
  69. XSTATIC_PTR int FDECL(do_comp,(const genericptr,const genericptr));
  70. Xstatic void FDECL(dosdoor,(XCHAR_P,XCHAR_P,struct mkroom *,int));
  71. Xstatic void FDECL(join,(int,int,BOOLEAN_P));
  72. Xstatic void FDECL(do_room_or_subroom, (struct mkroom *,int,int,int,int,
  73. X                       BOOLEAN_P,SCHAR_P,BOOLEAN_P,BOOLEAN_P));
  74. Xstatic void NDECL(makerooms);
  75. Xstatic void FDECL(finddpos,(coord *,XCHAR_P,XCHAR_P,XCHAR_P,XCHAR_P));
  76. Xstatic void FDECL(mkinvpos, (XCHAR_P,XCHAR_P,int));
  77. X#ifdef MULDGN
  78. Xstatic void FDECL(mk_knox_portal, (XCHAR_P,XCHAR_P));
  79. X#endif
  80. X
  81. X#define create_vault()    create_room(-1, -1, 2, 2, -1, -1, VAULT, TRUE)
  82. X#define init_vault()    vault_x = -1
  83. X#define do_vault()    (vault_x != -1)
  84. Xstatic xchar        vault_x, vault_y;
  85. Xboolean goldseen;
  86. Xstatic boolean made_branch;    /* used only during level creation */
  87. X
  88. X/* Args must be (const genericptr) so that qsort will always be happy. */
  89. X
  90. XSTATIC_PTR int
  91. Xdo_comp(vx,vy)
  92. Xconst genericptr vx;
  93. Xconst genericptr vy;
  94. X{
  95. X#ifdef LINT
  96. X/* lint complains about possible pointer alignment problems, but we know
  97. X   that vx and vy are always properly aligned. Hence, the following
  98. X   bogus definition:
  99. X*/
  100. X    return (vx == vy) ? 0 : -1;
  101. X#else
  102. X    register const struct mkroom *x, *y;
  103. X
  104. X    x = (const struct mkroom *)vx;
  105. X    y = (const struct mkroom *)vy;
  106. X    if(x->lx < y->lx) return(-1);
  107. X    return(x->lx > y->lx);
  108. X#endif /* LINT */
  109. X}
  110. X
  111. Xstatic void
  112. Xfinddpos(cc, xl,yl,xh,yh)
  113. Xcoord    *cc;
  114. Xxchar    xl,yl,xh,yh;
  115. X{
  116. X    register xchar x, y;
  117. X
  118. X    x = (xl == xh) ? xl : (xl + rn2(xh-xl+1));
  119. X    y = (yl == yh) ? yl : (yl + rn2(yh-yl+1));
  120. X    if(okdoor(x, y))
  121. X        goto gotit;
  122. X
  123. X    for(x = xl; x <= xh; x++) for(y = yl; y <= yh; y++)
  124. X        if(okdoor(x, y))
  125. X            goto gotit;
  126. X
  127. X    for(x = xl; x <= xh; x++) for(y = yl; y <= yh; y++)
  128. X        if(IS_DOOR(levl[x][y].typ) || levl[x][y].typ == SDOOR)
  129. X            goto gotit;
  130. X    /* cannot find something reasonable -- strange */
  131. X    x = xl;
  132. X    y = yh;
  133. Xgotit:
  134. X    cc->x = x;
  135. X    cc->y = y;
  136. X    return;
  137. X}
  138. X
  139. Xvoid
  140. Xsort_rooms()
  141. X{
  142. X#if defined(SYSV) || defined(DGUX)
  143. X    qsort((genericptr_t) rooms, (unsigned)nroom, sizeof(struct mkroom), do_comp);
  144. X#else
  145. X    qsort((genericptr_t) rooms, nroom, sizeof(struct mkroom), do_comp);
  146. X#endif
  147. X}
  148. X
  149. Xstatic void
  150. Xdo_room_or_subroom(croom, lowx, lowy, hix, hiy, lit, rtype, special, is_room)
  151. X    register struct mkroom *croom;
  152. X    int lowx, lowy;
  153. X    register int hix, hiy;
  154. X    boolean lit;
  155. X    schar rtype;
  156. X    boolean special;
  157. X    boolean is_room;
  158. X{
  159. X    register int x, y;
  160. X    struct rm *lev;
  161. X
  162. X    /* locations might bump level edges in wall-less rooms */
  163. X    /* add/subtract 1 to allow for edge locations */
  164. X    if(!lowx) lowx++;
  165. X    if(!lowy) lowy++;
  166. X    if(hix >= COLNO-1) hix = COLNO-2;
  167. X    if(hiy >= ROWNO-1) hiy = ROWNO-2;
  168. X
  169. X    if(lit) {
  170. X        for(x = lowx-1; x <= hix+1; x++) {
  171. X            lev = &levl[x][max(lowy-1,0)];
  172. X            for(y = lowy-1; y <= hiy+1; y++)
  173. X                lev++->lit = 1;
  174. X        }
  175. X        croom->rlit = 1;
  176. X    } else
  177. X        croom->rlit = 0;
  178. X
  179. X    croom->lx = lowx;
  180. X    croom->hx = hix;
  181. X    croom->ly = lowy;
  182. X    croom->hy = hiy;
  183. X    croom->rtype = rtype;
  184. X    croom->doorct = 0;
  185. X    /* if we're not making a vault, doorindex will still be 0
  186. X     * if we are, we'll have problems adding niches to the previous room
  187. X     * unless fdoor is at least doorindex
  188. X     */
  189. X    croom->fdoor = doorindex;
  190. X    croom->irregular = FALSE;
  191. X
  192. X    croom->nsubrooms = 0;
  193. X    croom->sbrooms[0] = (struct mkroom *) 0;
  194. X    if (!special) {
  195. X        for(x = lowx-1; x <= hix+1; x++)
  196. X        for(y = lowy-1; y <= hiy+1; y += (hiy-lowy+2)) {
  197. X            levl[x][y].typ = HWALL;
  198. X            levl[x][y].horizontal = 1;    /* For open/secret doors. */
  199. X        }
  200. X        for(x = lowx-1; x <= hix+1; x += (hix-lowx+2))
  201. X        for(y = lowy; y <= hiy; y++) {
  202. X            levl[x][y].typ = VWALL;
  203. X            levl[x][y].horizontal = 0;    /* For open/secret doors. */
  204. X        }
  205. X        for(x = lowx; x <= hix; x++) {
  206. X        lev = &levl[x][lowy];
  207. X        for(y = lowy; y <= hiy; y++)
  208. X            lev++->typ = ROOM;
  209. X        }
  210. X        if (is_room) {
  211. X        levl[lowx-1][lowy-1].typ = TLCORNER;
  212. X        levl[hix+1][lowy-1].typ = TRCORNER;
  213. X        levl[lowx-1][hiy+1].typ = BLCORNER;
  214. X        levl[hix+1][hiy+1].typ = BRCORNER;
  215. X        } else {    /* a subroom */
  216. X        wallification(lowx-1, lowy-1, hix+1, hiy+1);
  217. X        }
  218. X    }
  219. X}
  220. X
  221. X
  222. Xvoid
  223. Xadd_room(lowx, lowy, hix, hiy, lit, rtype, special)
  224. Xregister int lowx, lowy, hix, hiy;
  225. Xboolean lit;
  226. Xschar rtype;
  227. Xboolean special;
  228. X{
  229. X    register struct mkroom *croom;
  230. X
  231. X    croom = &rooms[nroom];
  232. X    do_room_or_subroom(croom, lowx, lowy, hix, hiy, lit,
  233. X                        rtype, special, (boolean) TRUE);
  234. X    croom++;
  235. X    croom->hx = -1;
  236. X    nroom++;
  237. X}
  238. X
  239. Xvoid
  240. Xadd_subroom(proom, lowx, lowy, hix, hiy, lit, rtype, special)
  241. Xstruct mkroom *proom;
  242. Xregister int lowx, lowy, hix, hiy;
  243. Xboolean lit;
  244. Xschar rtype;
  245. Xboolean special;
  246. X{
  247. X    register struct mkroom *croom;
  248. X
  249. X    croom = &subrooms[nsubroom];
  250. X    do_room_or_subroom(croom, lowx, lowy, hix, hiy, lit,
  251. X                        rtype, special, (boolean) FALSE);
  252. X    proom->sbrooms[proom->nsubrooms++] = croom;
  253. X    croom++;
  254. X    croom->hx = -1;
  255. X    nsubroom++;
  256. X}
  257. X
  258. Xstatic void
  259. Xmakerooms()
  260. X{
  261. X    boolean tried_vault = FALSE;
  262. X
  263. X    /* make rooms until satisfied */
  264. X    /* rnd_rect() will returns 0 if no more rects are available... */
  265. X    while(nroom < MAXNROFROOMS && rnd_rect()) {
  266. X        if(nroom >= (MAXNROFROOMS/6) && rn2(2) && !tried_vault) {
  267. X            tried_vault = TRUE;
  268. X            if (create_vault()) {
  269. X                vault_x = rooms[nroom].lx;
  270. X                vault_y = rooms[nroom].ly;
  271. X                rooms[nroom].hx = -1;
  272. X            }
  273. X        } else
  274. X            if (!create_room(-1, -1, -1, -1, -1, -1, OROOM, -1))
  275. X            return;
  276. X    }
  277. X    return;
  278. X}
  279. X
  280. Xstatic void
  281. Xjoin(a,b,nxcor)
  282. Xregister int a, b;
  283. Xboolean nxcor;
  284. X{
  285. X    coord cc,tt, org, dest;
  286. X    register int tx, ty, xx, yy;
  287. X    register struct mkroom *croom, *troom;
  288. X    register int dx, dy;
  289. X
  290. X    croom = &rooms[a];
  291. X    troom = &rooms[b];
  292. X
  293. X    /* find positions cc and tt for doors in croom and troom
  294. X       and direction for a corridor between them */
  295. X
  296. X    if(troom->hx < 0 || croom->hx < 0 || doorindex >= DOORMAX) return;
  297. X    if(troom->lx > croom->hx) {
  298. X        dx = 1;
  299. X        dy = 0;
  300. X        xx = croom->hx+1;
  301. X        tx = troom->lx-1;
  302. X        finddpos(&cc, xx, croom->ly, xx, croom->hy);
  303. X        finddpos(&tt, tx, troom->ly, tx, troom->hy);
  304. X    } else if(troom->hy < croom->ly) {
  305. X        dy = -1;
  306. X        dx = 0;
  307. X        yy = croom->ly-1;
  308. X        finddpos(&cc, croom->lx, yy, croom->hx, yy);
  309. X        ty = troom->hy+1;
  310. X        finddpos(&tt, troom->lx, ty, troom->hx, ty);
  311. X    } else if(troom->hx < croom->lx) {
  312. X        dx = -1;
  313. X        dy = 0;
  314. X        xx = croom->lx-1;
  315. X        tx = troom->hx+1;
  316. X        finddpos(&cc, xx, croom->ly, xx, croom->hy);
  317. X        finddpos(&tt, tx, troom->ly, tx, troom->hy);
  318. X    } else {
  319. X        dy = 1;
  320. X        dx = 0;
  321. X        yy = croom->hy+1;
  322. X        ty = troom->ly-1;
  323. X        finddpos(&cc, croom->lx, yy, croom->hx, yy);
  324. X        finddpos(&tt, troom->lx, ty, troom->hx, ty);
  325. X    }
  326. X    xx = cc.x;
  327. X    yy = cc.y;
  328. X    tx = tt.x - dx;
  329. X    ty = tt.y - dy;
  330. X    if(nxcor && levl[xx+dx][yy+dy].typ)
  331. X        return;
  332. X    if (okdoor(xx,yy) || !nxcor)
  333. X        dodoor(xx,yy,croom);
  334. X
  335. X    org.x  = xx+dx; org.y  = yy+dy;
  336. X    dest.x = tx; dest.y = ty;
  337. X
  338. X    if (!dig_corridor(org, dest, nxcor, CORR, STONE))
  339. X        return;
  340. X
  341. X    /* we succeeded in digging the corridor */
  342. X    if (okdoor(tt.x, tt.y) || !nxcor)
  343. X        dodoor(tt.x, tt.y, troom);
  344. X
  345. X    if(smeq[a] < smeq[b])
  346. X        smeq[b] = smeq[a];
  347. X    else
  348. X        smeq[a] = smeq[b];
  349. X}
  350. X
  351. Xvoid
  352. Xmakecorridors()
  353. X{
  354. X    int a, b, i;
  355. X    boolean any = TRUE;
  356. X
  357. X    for(a = 0; a < nroom-1; a++) {
  358. X        join(a, a+1, FALSE);
  359. X        if(!rn2(50)) break; /* allow some randomness */
  360. X    }
  361. X    for(a = 0; a < nroom-2; a++)
  362. X        if(smeq[a] != smeq[a+2])
  363. X        join(a, a+2, FALSE);
  364. X    for(a = 0; any && a < nroom; a++) {
  365. X        any = FALSE;
  366. X        for(b = 0; b < nroom; b++)
  367. X        if(smeq[a] != smeq[b]) {
  368. X            join(a, b, FALSE);
  369. X            any = TRUE;
  370. X        }
  371. X    }
  372. X    if(nroom > 2)
  373. X        for(i = rn2(nroom) + 4; i; i--) {
  374. X        a = rn2(nroom);
  375. X        b = rn2(nroom-2);
  376. X        if(b >= a) b += 2;
  377. X        join(a, b, TRUE);
  378. X        }
  379. X}
  380. X
  381. Xvoid
  382. Xadd_door(x,y,aroom)
  383. Xregister int x, y;
  384. Xregister struct mkroom *aroom;
  385. X{
  386. X    register struct mkroom *broom;
  387. X    register int tmp;
  388. X
  389. X    aroom->doorct++;
  390. X    broom = aroom+1;
  391. X    if(broom->hx < 0)
  392. X        tmp = doorindex;
  393. X    else
  394. X        for(tmp = doorindex; tmp > broom->fdoor; tmp--)
  395. X            doors[tmp] = doors[tmp-1];
  396. X    doorindex++;
  397. X    doors[tmp].x = x;
  398. X    doors[tmp].y = y;
  399. X    for( ; broom->hx >= 0; broom++) broom->fdoor++;
  400. X}
  401. X
  402. Xstatic void
  403. Xdosdoor(x,y,aroom,type)
  404. Xregister xchar x, y;
  405. Xregister struct mkroom *aroom;
  406. Xregister int type;
  407. X{
  408. X    boolean shdoor = ((*in_rooms(x, y, SHOPBASE))? TRUE : FALSE);
  409. X
  410. X    if(!IS_WALL(levl[x][y].typ)) /* avoid SDOORs on already made doors */
  411. X        type = DOOR;
  412. X    levl[x][y].typ = type;
  413. X    if(type == DOOR) {
  414. X        if(!rn2(3)) {      /* is it a locked door, closed, or a doorway? */
  415. X        if(!rn2(5))
  416. X            levl[x][y].doormask = D_ISOPEN;
  417. X        else if(!rn2(6))
  418. X            levl[x][y].doormask = D_LOCKED;
  419. X        else
  420. X            levl[x][y].doormask = D_CLOSED;
  421. X
  422. X        if (levl[x][y].doormask != D_ISOPEN && !shdoor && !rn2(25))
  423. X            levl[x][y].doormask |= D_TRAPPED;
  424. X        } else
  425. X#ifdef STUPID
  426. X        if (shdoor)
  427. X            levl[x][y].doormask = D_ISOPEN;
  428. X        else
  429. X            levl[x][y].doormask = D_NODOOR;
  430. X#else
  431. X        levl[x][y].doormask = (shdoor ? D_ISOPEN : D_NODOOR);
  432. X#endif
  433. X        if(levl[x][y].doormask & D_TRAPPED) {
  434. X        struct monst *mtmp;
  435. X
  436. X        if (level_difficulty() >= 9 && !rn2(5) &&
  437. X           !((mons[PM_SMALL_MIMIC].geno & (G_GENOD | G_EXTINCT)) &&
  438. X             (mons[PM_LARGE_MIMIC].geno & (G_GENOD | G_EXTINCT)) &&
  439. X             (mons[PM_GIANT_MIMIC].geno & (G_GENOD | G_EXTINCT)))) {
  440. X            /* make a mimic instead */
  441. X            levl[x][y].doormask = D_NODOOR;
  442. X            mtmp = makemon(mkclass(S_MIMIC,0), x, y);
  443. X            if (mtmp)
  444. X            set_mimic_sym(mtmp);
  445. X        }
  446. X        }
  447. X        /* newsym(x,y); */
  448. X    } else { /* SDOOR */
  449. X        if(shdoor || !rn2(5))    levl[x][y].doormask = D_LOCKED;
  450. X        else            levl[x][y].doormask = D_CLOSED;
  451. X
  452. X        if(!shdoor && !rn2(20)) levl[x][y].doormask |= D_TRAPPED;
  453. X    }
  454. X
  455. X    add_door(x,y,aroom);
  456. X}
  457. X
  458. Xstatic boolean
  459. Xplace_niche(aroom,dy,xx,yy)
  460. Xregister struct mkroom *aroom;
  461. Xint *dy, *xx, *yy;
  462. X{
  463. X    coord dd;
  464. X
  465. X    if(rn2(2)) {
  466. X        *dy = 1;
  467. X        finddpos(&dd, aroom->lx, aroom->hy+1, aroom->hx, aroom->hy+1);
  468. X    } else {
  469. X        *dy = -1;
  470. X        finddpos(&dd, aroom->lx, aroom->ly-1, aroom->hx, aroom->ly-1);
  471. X    }
  472. X    *xx = dd.x;
  473. X    *yy = dd.y;
  474. X    return(isok(*xx,*yy+*dy) && levl[*xx][(*yy)+(*dy)].typ == STONE);
  475. X}
  476. X
  477. X/* there should be one of these per trap */
  478. Xconst char *trap_engravings[TRAPNUM] = {
  479. X                "", "", "", "", "", "", "",
  480. X                "", "", "", "", "", "",
  481. X                "ad ae?ar um", "?la? ?as ?er?", "ad ae?ar um",
  482. X                "", "", "", ""
  483. X#ifdef POLYSELF
  484. X                ,""
  485. X#endif
  486. X                };
  487. X
  488. Xstatic void
  489. Xmakeniche(trap_type)
  490. Xint trap_type;
  491. X{
  492. X    register struct mkroom *aroom;
  493. X    register struct rm *rm;
  494. X    register int vct = 8;
  495. X    int dy, xx, yy;
  496. X    register struct trap *ttmp;
  497. X
  498. X    if(doorindex < DOORMAX)
  499. X      while(vct--) {
  500. X        aroom = &rooms[rn2(nroom)];
  501. X        if(aroom->rtype != OROOM) continue;    /* not an ordinary room */
  502. X        if(aroom->doorct == 1 && rn2(5)) continue;
  503. X        if(!place_niche(aroom,&dy,&xx,&yy)) continue;
  504. X
  505. X        rm = &levl[xx][yy+dy];
  506. X        if(trap_type || !rn2(4)) {
  507. X
  508. X        rm->typ = SCORR;
  509. X        if(trap_type) {
  510. X            if(trap_type == TRAPDOOR && !Can_fall_thru(&u.uz))
  511. X            trap_type = ROCKTRAP;
  512. X            ttmp = maketrap(xx, yy+dy, trap_type);
  513. X            ttmp->once = 1;
  514. X            if (*trap_engravings[trap_type])
  515. X            make_engr_at(xx, yy-dy, trap_engravings[trap_type], 0L, DUST);
  516. X        }
  517. X        dosdoor(xx, yy, aroom, SDOOR);
  518. X        } else {
  519. X        rm->typ = CORR;
  520. X        if(rn2(7))
  521. X            dosdoor(xx, yy, aroom, rn2(5) ? SDOOR : DOOR);
  522. X        else {
  523. X            (void) mksobj_at(SCR_TELEPORTATION, xx, yy+dy, TRUE);
  524. X            if(!rn2(3)) (void) mkobj_at(0, xx, yy+dy, TRUE);
  525. X        }
  526. X        }
  527. X        return;
  528. X    }
  529. X}
  530. X
  531. Xstatic void
  532. Xmake_niches()
  533. X{
  534. X    register int ct = rnd((nroom>>1) + 1);
  535. X    boolean    ltptr = TRUE,
  536. X        vamp = TRUE;
  537. X
  538. X    while(ct--) {
  539. X
  540. X        if(depth(&u.uz) > 15 && !rn2(6) && ltptr) {
  541. X            ltptr = FALSE;
  542. X            makeniche(LEVEL_TELEP);
  543. X        } else if(depth(&u.uz) > 5 && depth(&u.uz) < 25
  544. X                            && !rn2(6) && vamp) {
  545. X            vamp = FALSE;
  546. X            makeniche(TRAPDOOR);
  547. X        } else    makeniche(NO_TRAP);
  548. X    }
  549. X}
  550. X
  551. Xstatic void
  552. Xmakevtele()
  553. X{
  554. X    makeniche(TELEP_TRAP);
  555. X}
  556. X
  557. X/* clear out various globals that keep information on the current level.
  558. X * some of this is only necessary for some types of levels (maze, normal,
  559. X * special) but it's easier to put it all in one place than make sure
  560. X * each type initializes what it needs to separately.
  561. X */
  562. Xstatic void
  563. Xclear_level_structures()
  564. X{
  565. X    static struct rm zerorm = { cmap_to_glyph(S_stone),
  566. X                        0, 0, 0, 0, 0, 0, 0, 0 };
  567. X    register int x,y;
  568. X    register struct rm *lev;
  569. X
  570. X    for(x=0; x<COLNO; x++) {
  571. X        lev = &levl[x][0];
  572. X        for(y=0; y<ROWNO; y++) {
  573. X        *lev++ = zerorm;
  574. X#ifdef MICROPORT_BUG
  575. X        level.objects[x][y] = (struct obj *)0;
  576. X        level.monsters[x][y] = (struct monst *)0;
  577. X#endif
  578. X        }
  579. X    }
  580. X#ifndef MICROPORT_BUG
  581. X    (void) memset((genericptr_t)level.objects, 0, sizeof(level.objects));
  582. X    (void) memset((genericptr_t)level.monsters, 0, sizeof(level.monsters));
  583. X#endif
  584. X    level.flags.nfountains = 0;
  585. X    level.flags.nsinks = 0;
  586. X    level.flags.has_shop = 0;
  587. X    level.flags.has_vault = 0;
  588. X    level.flags.has_zoo = 0;
  589. X    level.flags.has_court = 0;
  590. X    level.flags.has_morgue = 0;
  591. X    level.flags.has_beehive = 0;
  592. X#ifdef ARMY
  593. X    level.flags.has_barracks = 0;
  594. X#endif
  595. X    level.flags.has_temple = 0;
  596. X    level.flags.has_swamp = 0;
  597. X    level.flags.noteleport = 0;
  598. X    level.flags.hardfloor = 0;
  599. X    level.flags.nommap = 0;
  600. X    level.flags.hero_memory = 1;
  601. X    level.flags.shortsighted = 0;
  602. X    level.flags.is_maze_lev = 0;
  603. X    level.flags.is_cavernous_lev = 0;
  604. X
  605. X    nroom = 0;
  606. X    rooms[0].hx = -1;
  607. X    nsubroom = 0;
  608. X    doorindex = 0;
  609. X    init_rect();
  610. X    init_vault();
  611. X    xdnstair = ydnstair = xupstair = yupstair = 0;
  612. X    sstairs.sx = sstairs.sy = 0;
  613. X    xdnladder = ydnladder = xupladder = yupladder = 0;
  614. X    made_branch = FALSE;
  615. X}
  616. X
  617. Xstatic void
  618. Xmakelevel()
  619. X{
  620. X    register struct mkroom *croom, *troom;
  621. X    register int tryct;
  622. X    register int x, y;
  623. X    struct monst *tmonst;    /* always put a web with a spider */
  624. X
  625. X    if(wiz1_level.dlevel == 0) init_dungeons();
  626. X    oinit();    /* assign level dependent obj probabilities */
  627. X    clear_level_structures();
  628. X
  629. X    {
  630. X        register s_level *slev = Is_special(&u.uz);
  631. X
  632. X        /* check for special levels */
  633. X#ifdef REINCARNATION
  634. X        if (slev && !Is_rogue_level(&u.uz))
  635. X#else
  636. X        if (slev)
  637. X#endif
  638. X        {
  639. X            makemaz(slev->proto);
  640. X            return;
  641. X        } else if (dungeons[u.uz.dnum].proto[0]) {
  642. X            makemaz("");
  643. X            return;
  644. X#ifdef MULDGN
  645. X        } else if (In_mines(&u.uz)) {
  646. X            makemaz("minefill");
  647. X            return;
  648. X        } else if (In_quest(&u.uz)) {
  649. X            char    fillname[9];
  650. X            s_level    *loc_lev;
  651. X
  652. X            Sprintf(fillname, "%c-locate", pl_character[0]);
  653. X            loc_lev = find_level(fillname);
  654. X
  655. X            Sprintf(fillname, "%c-fill", pl_character[0]);
  656. X            Strcat(fillname,
  657. X               (u.uz.dlevel < loc_lev->dlevel.dlevel) ? "a" : "b");
  658. X            makemaz(fillname);
  659. X            return;
  660. X#endif
  661. X        } else if(In_hell(&u.uz) ||
  662. X          (rn2(5) && u.uz.dnum == medusa_level.dnum
  663. X              && depth(&u.uz) > depth(&medusa_level))) {
  664. X            makemaz("");
  665. X            return;
  666. X        }
  667. X    }
  668. X
  669. X    /* otherwise, fall through - it's a "regular" level. */
  670. X
  671. X#ifdef REINCARNATION
  672. X    if (Is_rogue_level(&u.uz)) {
  673. X        makeroguerooms();
  674. X        makerogueghost();
  675. X    } else
  676. X#endif
  677. X        makerooms();
  678. X    sort_rooms();
  679. X
  680. X    /* construct stairs (up and down in different rooms if possible) */
  681. X    croom = &rooms[rn2(nroom)];
  682. X    if (!Is_botlevel(&u.uz))
  683. X         mkstairs(somex(croom), somey(croom), 0, croom);    /* down */
  684. X    if (nroom > 1) {
  685. X        troom = croom;
  686. X        croom = &rooms[rn2(nroom-1)];
  687. X        if (croom == troom) croom++;
  688. X    }
  689. X
  690. X    if (u.uz.dlevel != 1) {
  691. X        xchar sx, sy;
  692. X        do {
  693. X        sx = somex(croom);
  694. X        sy = somey(croom);
  695. X        } while(occupied(sx, sy));
  696. X        mkstairs(sx, sy, 1, croom);    /* up */
  697. X    }
  698. X
  699. X#ifdef REINCARNATION
  700. X    if (Is_rogue_level(&u.uz)) goto skip0;
  701. X#endif
  702. X    makecorridors();
  703. X    make_niches();
  704. X
  705. X    /* make a secret treasure vault, not connected to the rest */
  706. X    if(do_vault()) {
  707. X        xchar w,h;
  708. X#ifdef DEBUG
  709. X        debugpline("trying to make a vault...");
  710. X#endif
  711. X        w = 1;
  712. X        h = 1;
  713. X        if (check_room(&vault_x, &w, &vault_y, &h, TRUE)) {
  714. X            fill_vault:
  715. X            add_room(vault_x, vault_y, vault_x+w,
  716. X                 vault_y+h, TRUE, VAULT, FALSE);
  717. X            level.flags.has_vault = 1;
  718. X            fill_room(&rooms[nroom - 1], FALSE);
  719. X#ifdef MULDGN
  720. X            mk_knox_portal(vault_x+w, vault_y+h);
  721. X#endif
  722. X            if(!rn2(3)) makevtele();
  723. X        } else if(rnd_rect() && create_vault()) {
  724. X            vault_x = rooms[nroom].lx;
  725. X            vault_y = rooms[nroom].ly;
  726. X            if (check_room(&vault_x, &w, &vault_y, &h, TRUE))
  727. X                goto fill_vault;
  728. X            else
  729. X                rooms[nroom].hx = -1;
  730. X        }
  731. X    }
  732. X
  733. X#ifdef WIZARD
  734. X    if(wizard && getenv("SHOPTYPE")) mkroom(SHOPBASE); else
  735. X#endif
  736. X    if(depth(&u.uz) > 1 &&
  737. X       depth(&u.uz) < depth(&medusa_level) &&
  738. X       rn2(depth(&u.uz)) < 3) mkroom(SHOPBASE);
  739. X    else if(depth(&u.uz) > 4 && !rn2(6)) mkroom(COURT);
  740. X    else if(depth(&u.uz) > 6 && !rn2(7)) mkroom(ZOO);
  741. X    else if(depth(&u.uz) > 8 && !rn2(5)) mkroom(TEMPLE);
  742. X    else if(depth(&u.uz) > 9 && !rn2(5) &&
  743. X       !(mons[PM_KILLER_BEE].geno & (G_GENOD | G_EXTINCT))) mkroom(BEEHIVE);
  744. X    else if(depth(&u.uz) > 11 && !rn2(6)) mkroom(MORGUE);
  745. X    else
  746. X#ifdef ARMY
  747. X    if(depth(&u.uz) > 14 && !rn2(4) &&
  748. X       !(mons[PM_SOLDIER].geno & (G_GENOD | G_EXTINCT))) mkroom(BARRACKS);
  749. X    else
  750. X#endif
  751. X    if(depth(&u.uz) > 18 && !rn2(6)) mkroom(SWAMP);
  752. X
  753. X#ifdef REINCARNATION
  754. Xskip0:
  755. X#endif
  756. X    /* Place multi-dungeon branch. */
  757. X    place_branch(Is_branchlev(&u.uz), 0, 0);
  758. X
  759. X    /* for each room: put things inside */
  760. X    for(croom = rooms; croom->hx > 0; croom++) {
  761. X        if(croom->rtype != OROOM) continue;
  762. X
  763. X        /* put a sleeping monster inside */
  764. X        /* Note: monster may be on the stairs. This cannot be
  765. X           avoided: maybe the player fell through a trap door
  766. X           while a monster was on the stairs. Conclusion:
  767. X           we have to check for monsters on the stairs anyway. */
  768. X
  769. X        if(u.uhave.amulet || !rn2(3)) {
  770. X            x = somex(croom); y = somey(croom);
  771. X            tmonst = makemon((struct permonst *) 0, x,y);
  772. X            if (tmonst && tmonst->data == &mons[PM_GIANT_SPIDER] &&
  773. X            !is_pool(x,y))
  774. X            (void) maketrap (x,y,WEB);
  775. X        }
  776. X        /* put traps and mimics inside */
  777. X        goldseen = FALSE;
  778. X        x = 8 - (level_difficulty()/6);
  779. X        if (x <= 1) x = 2;
  780. X        while (!rn2(x))
  781. X            mktrap(0,0,croom,(coord*)0);
  782. X        if(!goldseen && !rn2(3)) mkgold(0L, somex(croom), somey(croom));
  783. X#ifdef REINCARNATION
  784. X        if(Is_rogue_level(&u.uz)) goto skip_nonrogue;
  785. X#endif
  786. X        if(!rn2(10)) mkfount(0,croom);
  787. X#ifdef SINKS
  788. X        if(!rn2(60)) mksink(croom);
  789. X#endif
  790. X        if(!rn2(60)) mkaltar(croom);
  791. X        /* put statues inside */
  792. X        if(!rn2(20))
  793. X            (void) mkcorpstat(STATUE, (struct permonst *)0,
  794. X                      somex(croom), somey(croom), TRUE);
  795. X
  796. X        /* put box/chest inside;
  797. X         *  40% chance for at least 1 box, regardless of number
  798. X         *  of rooms; about 5 - 7.5% for 2 boxes, least likely
  799. X         *  when few rooms; chance for 3 or more is neglible.
  800. X         */
  801. X        if(!rn2(nroom * 5 / 2))
  802. X            (void) mksobj_at((rn2(3)) ? LARGE_BOX : CHEST,
  803. X                     somex(croom), somey(croom), TRUE);
  804. X
  805. X        /* maybe make some graffiti */
  806. X        if(!rn2(27 + 3 * depth(&u.uz))) {
  807. X            const char *mesg = random_engraving();
  808. X            if (mesg) {
  809. X            do {
  810. X                x = somex(croom);  y = somey(croom);
  811. X            } while(levl[x][y].typ != ROOM && !rn2(40));
  812. X            if (!(IS_POOL(levl[x][y].typ) ||
  813. X                  IS_FURNITURE(levl[x][y].typ)))
  814. X                make_engr_at(x, y, mesg, 0L, MARK);
  815. X            }
  816. X        }
  817. X
  818. X#ifdef REINCARNATION
  819. X    skip_nonrogue:
  820. X#endif
  821. X        if(!rn2(3)) {
  822. X            (void) mkobj_at(0, somex(croom), somey(croom), TRUE);
  823. X            tryct = 0;
  824. X            while(!rn2(5)) {
  825. X            if(++tryct > 100) {
  826. X                impossible("tryct overflow4");
  827. X                break;
  828. X            }
  829. X            (void) mkobj_at(0, somex(croom), somey(croom), TRUE);
  830. X            }
  831. X        }
  832. X    }
  833. X}
  834. X
  835. Xvoid
  836. Xmklev()
  837. X{
  838. X    struct mkroom *croom;
  839. X
  840. X    if(getbones()) return;
  841. X    in_mklev = TRUE;
  842. X    makelevel();
  843. X    bound_digging();
  844. X    in_mklev = FALSE;
  845. X    if(!level.flags.is_maze_lev) {
  846. X        for (croom = &rooms[0]; croom != &rooms[nroom]; croom++)
  847. X#ifdef SPECIALIZATION
  848. X        topologize(croom, FALSE);
  849. X#else
  850. X        topologize(croom);
  851. X#endif
  852. X    }
  853. X}
  854. X
  855. Xvoid
  856. X#ifdef SPECIALIZATION
  857. Xtopologize(croom, do_ordinary)
  858. Xregister struct mkroom *croom;
  859. Xboolean do_ordinary;
  860. X#else
  861. Xtopologize(croom)
  862. Xregister struct mkroom *croom;
  863. X#endif
  864. X{
  865. X    register int x, y, roomno = (croom - rooms) + ROOMOFFSET;
  866. X    register int lowx = croom->lx, lowy = croom->ly;
  867. X    register int hix = croom->hx, hiy = croom->hy;
  868. X#ifdef SPECIALIZATION
  869. X    register schar rtype = croom->rtype;
  870. X#endif
  871. X    register int subindex, nsubrooms = croom->nsubrooms;
  872. X
  873. X    /* skip the room if already done; i.e. a shop handled out of order */
  874. X    /* also skip if this is non-rectangular (it _must_ be done already) */
  875. X    if (levl[lowx][lowy].roomno == roomno || croom->irregular)
  876. X        return;
  877. X#ifdef SPECIALIZATION
  878. X# ifdef REINCARNATION
  879. X    if (Is_rogue_level(&u.uz))
  880. X        do_ordinary = TRUE;        /* vision routine helper */
  881. X# endif
  882. X    if ((rtype != OROOM) || do_ordinary)
  883. X#endif
  884. X    {
  885. X        /* do innards first */
  886. X        for(x = lowx; x <= hix; x++)
  887. X        for(y = lowy; y <= hiy; y++)
  888. X#ifdef SPECIALIZATION
  889. X            if (rtype == OROOM)
  890. X            levl[x][y].roomno = NO_ROOM;
  891. X            else
  892. X#endif
  893. X            levl[x][y].roomno = roomno;
  894. X        /* top and bottom edges */
  895. X        for(x = lowx-1; x <= hix+1; x++)
  896. X        for(y = lowy-1; y <= hiy+1; y += (hiy-lowy+2)) {
  897. X            levl[x][y].edge = 1;
  898. X            if (levl[x][y].roomno)
  899. X            levl[x][y].roomno = SHARED;
  900. X            else
  901. X            levl[x][y].roomno = roomno;
  902. X        }
  903. X        /* sides */
  904. X        for(x = lowx-1; x <= hix+1; x += (hix-lowx+2))
  905. X        for(y = lowy; y <= hiy; y++) {
  906. X            levl[x][y].edge = 1;
  907. X            if (levl[x][y].roomno)
  908. X            levl[x][y].roomno = SHARED;
  909. X            else
  910. X            levl[x][y].roomno = roomno;
  911. X        }
  912. X    }
  913. X    /* subrooms */
  914. X    for (subindex = 0; subindex < nsubrooms; subindex++)
  915. X#ifdef SPECIALIZATION
  916. X        topologize(croom->sbrooms[subindex], (rtype != OROOM));
  917. X#else
  918. X        topologize(croom->sbrooms[subindex]);
  919. X#endif
  920. X}
  921. X
  922. X/* Find an unused room for a branch location. */
  923. Xstatic struct mkroom *
  924. Xfind_branch_room(mp)
  925. X    coord *mp;
  926. X{
  927. X    struct mkroom *croom = 0;
  928. X
  929. X    if (nroom == 0) {
  930. X    mazexy(mp);        /* already verifies location */
  931. X    } else {
  932. X    /* not perfect - there may be only one stairway */
  933. X    if(nroom > 2) {
  934. X        int tryct = 0;
  935. X
  936. X        do
  937. X        croom = &rooms[rn2(nroom)];
  938. X        while((croom == dnstairs_room || croom == upstairs_room ||
  939. X          croom->rtype != OROOM) && (++tryct < 100));
  940. X    } else
  941. X        croom = &rooms[rn2(nroom)];
  942. X
  943. X    do {
  944. X        if (!somexy(croom, mp))
  945. X        impossible("Can't place branch!");
  946. X    } while(occupied(mp->x, mp->y) ||
  947. X        (levl[mp->x][mp->y].typ != CORR && levl[mp->x][mp->y].typ != ROOM));
  948. X    }
  949. X    return croom;
  950. X}
  951. X
  952. X/* Find the room for (x,y).  Return NULL of not in a room. */
  953. Xstatic struct mkroom *
  954. Xpos_to_room(x, y)
  955. X    xchar x, y;
  956. X{
  957. X    int i;
  958. X    struct mkroom *curr;
  959. X
  960. X    for (curr = rooms, i = 0; i < nroom; curr++, i++)
  961. X    if (inside_room(curr, x, y)) return curr;;
  962. X    return (struct mkroom *) 0;
  963. X}
  964. X
  965. X
  966. X/* If given a branch, randomly place a special stair or portal. */
  967. Xvoid
  968. Xplace_branch(br, x, y)
  969. Xbranch *br;    /* branch to place */
  970. Xxchar x, y;    /* location */
  971. X{
  972. X    coord          m;
  973. X    d_level          *dest;
  974. X    boolean          make_stairs;
  975. X    struct mkroom *br_room;
  976. X
  977. X    /*
  978. X     * Return immediately if there is no branch to make or we have
  979. X     * already made one.  This routine can be called twice when
  980. X     * a special level is loaded that specifies an SSTAIR location
  981. X     * as a favored spot for a branch.
  982. X     */
  983. X    if (!br || made_branch) return;
  984. X
  985. X    if (!x) {    /* find random coordinates for branch */
  986. X        br_room = find_branch_room(&m);
  987. X        x = m.x;
  988. X        y = m.y;
  989. X    } else {
  990. X        br_room = pos_to_room(x, y);
  991. X    }
  992. X
  993. X    if (on_level(&br->end1, &u.uz)) {
  994. X        /* we're on end1 */
  995. X        make_stairs = br->type != BR_NO_END1;
  996. X        dest = &br->end2;
  997. X    } else {
  998. X        /* we're on end2 */
  999. X        make_stairs = br->type != BR_NO_END2;
  1000. X        dest = &br->end1;
  1001. X    }
  1002. X
  1003. X    if (br->type == BR_PORTAL) {
  1004. X        mkportal(x, y, dest->dnum, dest->dlevel);
  1005. X    } else if (make_stairs) {
  1006. X        sstairs.sx = x;
  1007. X        sstairs.sy = y;
  1008. X        sstairs.up = (char) on_level(&br->end1, &u.uz) ?
  1009. X                        br->end1_up : !br->end1_up;
  1010. X        assign_level(&sstairs.tolev, dest);
  1011. X        sstairs_room = br_room;
  1012. X
  1013. X        levl[x][y].ladder = sstairs.up ? LA_UP : LA_DOWN;
  1014. X        levl[x][y].typ = STAIRS;
  1015. X    }
  1016. X    /*
  1017. X     * Set made_branch to TRUE even if we didn't make a stairwell (i.e.
  1018. X     * make_stairs is false) since there is currently only one branch
  1019. X     * per level, if we failed once, we're going to fail again on the
  1020. X     * next call.
  1021. X     */
  1022. X    made_branch = TRUE;
  1023. X}
  1024. X
  1025. Xstatic boolean
  1026. Xbydoor(x, y)
  1027. Xregister xchar x, y;
  1028. X{
  1029. X    register boolean tmp1, tmp2;
  1030. X
  1031. X    /* break up large expression to help some compilers */
  1032. X    tmp1 = (IS_DOOR(levl[x+1][y].typ) || levl[x+1][y].typ == SDOOR ||
  1033. X        IS_DOOR(levl[x-1][y].typ) || levl[x-1][y].typ == SDOOR);
  1034. X    tmp2 = (IS_DOOR(levl[x][y+1].typ) || levl[x][y+1].typ == SDOOR ||
  1035. X        IS_DOOR(levl[x][y-1].typ) || levl[x][y-1].typ == SDOOR);
  1036. X    return(tmp1 || tmp2);
  1037. X}
  1038. X
  1039. X/* see whether it is allowable to create a door at [x,y] */
  1040. Xint
  1041. Xokdoor(x,y)
  1042. Xregister xchar x, y;
  1043. X{
  1044. X    register boolean near_door = bydoor(x, y);
  1045. X
  1046. X    return((levl[x][y].typ == HWALL || levl[x][y].typ == VWALL) &&
  1047. X            doorindex < DOORMAX && !near_door);
  1048. X}
  1049. X
  1050. Xvoid
  1051. Xdodoor(x,y,aroom)
  1052. Xregister int x, y;
  1053. Xregister struct mkroom *aroom;
  1054. X{
  1055. X    if(doorindex >= DOORMAX) {
  1056. X        impossible("DOORMAX exceeded?");
  1057. X        return;
  1058. X    }
  1059. X
  1060. X    dosdoor(x,y,aroom,rn2(8) ? DOOR : SDOOR);
  1061. X}
  1062. X
  1063. Xboolean
  1064. Xoccupied(x, y)
  1065. Xregister xchar x, y;
  1066. X{
  1067. X    return(t_at(x, y) || levl[x][y].typ == STAIRS
  1068. X        || IS_FOUNTAIN(levl[x][y].typ)
  1069. X        || IS_THRONE(levl[x][y].typ)
  1070. X#ifdef SINKS
  1071. X        || IS_SINK(levl[x][y].typ)
  1072. X#endif
  1073. X        || levl[x][y].typ == ALTAR
  1074. X        || is_lava(x,y)
  1075. X        || is_pool(x,y)
  1076. X        || invocation_pos(x,y)
  1077. X        );
  1078. X}
  1079. X
  1080. X/* make a trap somewhere (in croom if mazeflag = 0 && !tm) */
  1081. X/* if tm != NULL, make trap at that location */
  1082. Xvoid
  1083. Xmktrap(num, mazeflag, croom, tm)
  1084. Xregister int num, mazeflag;
  1085. Xregister struct mkroom *croom;
  1086. Xcoord *tm;
  1087. X{
  1088. X    register int kind;
  1089. X    coord m;
  1090. X
  1091. X    /* no traps in pools */
  1092. X    if (tm && is_pool(tm->x,tm->y)) return;
  1093. X
  1094. X    if (num > 0 && num < TRAPNUM) {
  1095. X        kind = num;
  1096. X#ifdef REINCARNATION
  1097. X    } else if (Is_rogue_level(&u.uz)) {
  1098. X        switch (rn2(7)) {
  1099. X        default: kind = BEAR_TRAP; break; /* 0 */
  1100. X        case 1: kind = ARROW_TRAP; break;
  1101. X        case 2: kind = DART_TRAP; break;
  1102. X        case 3: kind = TRAPDOOR; break;
  1103. X        case 4: kind = PIT; break;
  1104. X        case 5: kind = SLP_GAS_TRAP; break;
  1105. X        case 6: kind = RUST_TRAP; break;
  1106. X        }
  1107. X#endif
  1108. X    } else if (Inhell && !rn2(5)) {
  1109. X        /* bias the frequency of fire traps in Gehennom */
  1110. X        kind = FIRE_TRAP;
  1111. X    } else {
  1112. X        unsigned lvl = level_difficulty();
  1113. X
  1114. X        do {
  1115. X        kind = rnd(TRAPNUM-1);
  1116. X        /* reject "too hard" traps */
  1117. X        switch (kind) {
  1118. X            case LEVEL_TELEP:
  1119. X            case LANDMINE:
  1120. X            if (lvl < 5) kind = NO_TRAP; break;
  1121. X            case SPIKED_PIT:
  1122. X#ifdef POLYSELF
  1123. X            case POLY_TRAP:
  1124. X#endif
  1125. X            if (lvl < 6) kind = NO_TRAP; break;
  1126. X            case WEB:
  1127. X            case STATUE_TRAP:
  1128. X            if (lvl < 7) kind = NO_TRAP; break;
  1129. X            case FIRE_TRAP:
  1130. X            if (!Inhell) kind = NO_TRAP; break;
  1131. X        }
  1132. X        } while (kind == NO_TRAP || kind == MAGIC_PORTAL);
  1133. X    }
  1134. X
  1135. X    if (kind == TRAPDOOR && !Can_fall_thru(&u.uz)) kind = ROCKTRAP;
  1136. X
  1137. X    if (tm)
  1138. X        m = *tm;
  1139. X    else {
  1140. X        register int tryct = 0;
  1141. X
  1142. X        do {
  1143. X        if (++tryct > 200)
  1144. X            return;
  1145. X        if (mazeflag)
  1146. X            mazexy(&m);
  1147. X        else if (!somexy(croom,&m))
  1148. X            return;
  1149. X        } while (occupied(m.x, m.y) || is_pool(m.x,m.y) ||
  1150. X                     (sobj_at(BOULDER, m.x, m.y) &&
  1151. X                      (kind == PIT || kind == SPIKED_PIT ||
  1152. X                       kind == TRAPDOOR)));
  1153. X    }
  1154. X
  1155. X    (void) maketrap(m.x, m.y, kind);
  1156. X    if (kind == WEB) (void) makemon(&mons[PM_GIANT_SPIDER], m.x, m.y);
  1157. X}
  1158. X
  1159. Xvoid
  1160. Xmkstairs(x, y, up, croom)
  1161. Xxchar x, y;
  1162. Xchar  up;
  1163. Xstruct mkroom *croom;
  1164. X{
  1165. X    if (! (x || y)) {
  1166. X        impossible("mkstairs:  bogus stair attempt at (%d,%d)", x, y);
  1167. X        return;
  1168. X    }
  1169. X
  1170. X    /*
  1171. X     * We can't make a regular stair off an end of the dungeon.  This
  1172. X     * attempt can happen when a special level is placed at an end and
  1173. X     * has an up or down stair specified in its description file.
  1174. X     */
  1175. X    if ((dunlev(&u.uz) == 1 && up) ||
  1176. X            (dunlev(&u.uz) == dunlevs_in_dungeon(&u.uz) && !up))
  1177. X        return;
  1178. X
  1179. X    if(up) {
  1180. X        xupstair = x;
  1181. X        yupstair = y;
  1182. X        upstairs_room = croom;
  1183. X    } else {
  1184. X        xdnstair = x;
  1185. X        ydnstair = y;
  1186. X        dnstairs_room = croom;
  1187. X    }
  1188. X
  1189. X    levl[x][y].typ = STAIRS;
  1190. X    levl[x][y].ladder = up ? LA_UP : LA_DOWN;
  1191. X}
  1192. X
  1193. Xstatic
  1194. Xvoid
  1195. Xmkfount(mazeflag,croom)
  1196. Xregister int mazeflag;
  1197. Xregister struct mkroom *croom;
  1198. X{
  1199. X    coord m;
  1200. X    register int tryct = 0;
  1201. X
  1202. X    do {
  1203. X        if(++tryct > 200) return;
  1204. X        if(mazeflag)
  1205. X        mazexy(&m);
  1206. X        else
  1207. X        if (!somexy(croom, &m))
  1208. X            return;
  1209. X    } while(occupied(m.x, m.y) || bydoor(m.x, m.y));
  1210. X
  1211. X    /* Put a fountain at m.x, m.y */
  1212. X    levl[m.x][m.y].typ = FOUNTAIN;
  1213. X    /* Is it a "blessed" fountain? (affects drinking from fountain) */
  1214. X    if(!rn2(7)) levl[m.x][m.y].blessedftn = 1;
  1215. X
  1216. X    level.flags.nfountains++;
  1217. X}
  1218. X
  1219. X#ifdef SINKS
  1220. Xstatic void
  1221. Xmksink(croom)
  1222. Xregister struct mkroom *croom;
  1223. X{
  1224. X    coord m;
  1225. X    register int tryct = 0;
  1226. X
  1227. X    do {
  1228. X        if(++tryct > 200) return;
  1229. X        if (!somexy(croom, &m))
  1230. X        return;
  1231. X    } while(occupied(m.x, m.y) || bydoor(m.x, m.y));
  1232. X
  1233. X    /* Put a sink at m.x, m.y */
  1234. X    levl[m.x][m.y].typ = SINK;
  1235. X
  1236. X    level.flags.nsinks++;
  1237. X}
  1238. X#endif /* SINKS /**/
  1239. X
  1240. X
  1241. Xstatic void
  1242. Xmkaltar(croom)
  1243. Xregister struct mkroom *croom;
  1244. X{
  1245. X    coord m;
  1246. X    register int tryct = 0;
  1247. X    aligntyp al;
  1248. X
  1249. X    if(croom->rtype != OROOM) return;
  1250. X
  1251. X    do {
  1252. X        if(++tryct > 200) return;
  1253. X        if (!somexy(croom, &m))
  1254. X        return;
  1255. X    } while(occupied(m.x, m.y) || bydoor(m.x, m.y));
  1256. X
  1257. X    /* Put an altar at m.x, m.y */
  1258. X    levl[m.x][m.y].typ = ALTAR;
  1259. X
  1260. X    /* -1 - A_CHAOTIC, 0 - A_NEUTRAL, 1 - A_LAWFUL */
  1261. X    al = rn2((int)A_LAWFUL+2) - 1;
  1262. X    levl[m.x][m.y].altarmask = Align2amask( al );
  1263. X}
  1264. X
  1265. X/*
  1266. X * Major level transmutation: add a set of stairs (to the Sanctum) after
  1267. X * an earthquake that leaves behind a a new topology, centered at inv_pos.
  1268. X * Assumes there are no rooms within the invocation area and that inv_pos
  1269. X * is not too close to the edge of the map.  Also assume the hero can see.
  1270. X */
  1271. Xvoid
  1272. Xmkinvokearea()
  1273. X{
  1274. X    int dist;
  1275. X    xchar xmin = inv_pos.x, xmax = inv_pos.x;
  1276. X    xchar ymin = inv_pos.y, ymax = inv_pos.y;
  1277. X    register xchar i;
  1278. X
  1279. X    pline("The floor shakes violently under you!");
  1280. X    pline("The walls around you begin to move and fall down!");
  1281. X    display_nhwindow(WIN_MESSAGE, TRUE);
  1282. X
  1283. X    for(dist = 1; dist < 7; dist++) {
  1284. X    xmin--; xmax++;
  1285. X
  1286. X    /* top and bottom */
  1287. X    if(dist != 3) { /* the area is wider that it is high */
  1288. X        ymin--; ymax++;
  1289. X        for(i = xmin+1; i < xmax; i++) {
  1290. X        mkinvpos(i, ymin, dist);
  1291. X        mkinvpos(i, ymax, dist);
  1292. X        }
  1293. X    }
  1294. X
  1295. X    /* left and right */
  1296. X    for(i = ymin; i <= ymax; i++) {
  1297. X        mkinvpos(xmin, i, dist);
  1298. X        mkinvpos(xmax, i, dist);
  1299. X    }
  1300. X
  1301. X    flush_screen(1);    /* make sure the new glyphs shows up */
  1302. X    delay_output();
  1303. X    }
  1304. X
  1305. X    You("are standing at the top of a stairwell leading down!");
  1306. X    mkstairs(u.ux, u.uy, 0, (struct mkroom *)0); /* down */
  1307. X    newsym(u.ux, u.uy);
  1308. X    vision_full_recalc = 1;    /* everything changed */
  1309. X}
  1310. X
  1311. X/* Change level topology.  Messes with vision tables and ignores things like
  1312. X * boulders in the name of a nice effect.  Vision will get fixed up again
  1313. X * immediately after the effect is complete.
  1314. X */
  1315. Xstatic void
  1316. Xmkinvpos(x,y,dist)
  1317. Xxchar x,y;
  1318. Xint dist;
  1319. X{
  1320. X    struct trap *ttmp;
  1321. X    register struct rm *lev = &levl[x][y];
  1322. X
  1323. X    unblock_point(x,y);    /* make sure vision knows this location is open */
  1324. X
  1325. X    /* fake out saved state */
  1326. X    lev->seen = FALSE;
  1327. X    lev->doormask = 0;
  1328. X    if(dist < 6) lev->lit = TRUE;
  1329. X    lev->waslit = TRUE;
  1330. X    lev->horizontal = FALSE;
  1331. X    viz_array[y][x] = (dist < 6 ) ?
  1332. X    (IN_SIGHT|COULD_SEE) : /* short-circuit vision recalc */
  1333. X    COULD_SEE;
  1334. X
  1335. X    switch(dist) {
  1336. X    case 1: /* fire traps */
  1337. X    lev->typ = ROOM;
  1338. X    if (is_pool(x,y)) break;
  1339. X    ttmp = maketrap(x, y, FIRE_TRAP);
  1340. X    ttmp->tseen = TRUE;
  1341. X    break;
  1342. X    case 2: /* lit room locations */
  1343. X    case 3:
  1344. X    case 6:
  1345. X    if ((ttmp = t_at(x,y)) != 0) deltrap(ttmp);
  1346. X    lev->typ = ROOM;
  1347. X    break;
  1348. X    case 4: /* pools (aka a wide moat) */
  1349. X    case 5:
  1350. X    if ((ttmp = t_at(x,y)) != 0) deltrap(ttmp);
  1351. X    lev->typ = MOAT;
  1352. X    break;
  1353. X    default:
  1354. X    impossible("mkinvpos called with dist %d", dist);
  1355. X    break;
  1356. X    }
  1357. X
  1358. X    /* display new value of position; could have a monster/object on it */
  1359. X    newsym(x,y);
  1360. X}
  1361. X
  1362. X#ifdef MULDGN
  1363. X/*
  1364. X * The portal to Ludios is special.  The entrance can only occur within a
  1365. X * vault in the main dungeon at a depth greater than 10.  The Ludios branch
  1366. X * structure reflects this by having a bogus "source" dungeon:  the value
  1367. X * of n_dgns (thus, Is_branchlev() will never find it).
  1368. X *
  1369. X * Ludios will remain isolated until the branch is corrected by this function.
  1370. X */
  1371. Xstatic void
  1372. Xmk_knox_portal(x, y)
  1373. Xxchar x, y;
  1374. X{
  1375. X    extern int n_dgns;        /* from dungeon.c */
  1376. X    d_level *source;
  1377. X    branch *br;
  1378. X    xchar u_depth;
  1379. X
  1380. X    br = dungeon_branch("Fort Ludios");
  1381. X    if (on_level(&knox_level, &br->end1)) {
  1382. X        source = &br->end2;
  1383. X    } else {
  1384. X        /* disallow Knox branch on a level with one branch already */
  1385. X        if(Is_branchlev(&u.uz))
  1386. X        return;
  1387. X        source = &br->end1;
  1388. X    }
  1389. X
  1390. X    /* Already set or 2/3 chance of deferring until a later level. */
  1391. X    if (source->dnum < n_dgns || (rn2(3)
  1392. X#ifdef WIZARD
  1393. X                      && !wizard
  1394. X#endif
  1395. X                      )) return;
  1396. X
  1397. X    if (! (u.uz.dnum == oracle_level.dnum        /* in main dungeon */
  1398. X        && !at_dgn_entrance("The Quest")    /* but not Quest's entry */
  1399. X        && (u_depth = depth(&u.uz)) > 10    /* beneath 10 */
  1400. X        && u_depth < depth(&medusa_level))) /* and above Medusa */
  1401. X        return;
  1402. X
  1403. X    /* Adjust source to be current level and re-insert branch. */
  1404. X    *source = u.uz;
  1405. X    insert_branch(br, TRUE);
  1406. X
  1407. X# ifdef DEBUG
  1408. X    pline("Made knox portal.");
  1409. X# endif
  1410. X    place_branch(br, x, y);
  1411. X}
  1412. X#endif
  1413. X
  1414. X/*mklev.c*/
  1415. END_OF_FILE
  1416. if test 33549 -ne `wc -c <'src/mklev.c'`; then
  1417.     echo shar: \"'src/mklev.c'\" unpacked with wrong size!
  1418. fi
  1419. # end of 'src/mklev.c'
  1420. fi
  1421. if test -f 'src/save.c' -a "${1}" != "-c" ; then 
  1422.   echo shar: Will not clobber existing file \"'src/save.c'\"
  1423. else
  1424. echo shar: Extracting \"'src/save.c'\" \(19844 characters\)
  1425. sed "s/^X//" >'src/save.c' <<'END_OF_FILE'
  1426. X/*    SCCS Id: @(#)save.c    3.1    93/01/07    */
  1427. X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
  1428. X/* NetHack may be freely redistributed.  See license for details. */
  1429. X
  1430. X#include "hack.h"
  1431. X#include "lev.h"
  1432. X
  1433. X#ifndef NO_SIGNAL
  1434. X#include <signal.h>
  1435. X#endif /* !NO_SIGNAL */
  1436. X#if defined(EXPLORE_MODE) && !defined(LSC) && !defined(O_WRONLY) && !defined(AZTEC_C)
  1437. X#include <fcntl.h>
  1438. X#endif /* EXPLORE_MODE */
  1439. X
  1440. Xboolean hu;        /* set during hang-up */
  1441. X
  1442. X#ifdef MULDGN
  1443. X#include "quest.h"
  1444. X#endif
  1445. X
  1446. X#ifdef MFLOPPY
  1447. Xextern struct finfo fileinfo[];
  1448. Xlong bytes_counted;
  1449. Xstatic int count_only;
  1450. X#else
  1451. Xextern boolean level_exists[];
  1452. X#endif
  1453. X
  1454. X#ifdef MICRO
  1455. Xint dotcnt;    /* also used in restore */
  1456. X#endif
  1457. X
  1458. X#ifdef ZEROCOMP
  1459. Xstatic void FDECL(bputc, (UCHAR_P));
  1460. X#endif
  1461. Xstatic void FDECL(savelevchn, (int, int));
  1462. Xstatic void FDECL(savedamage, (int,struct damage *, int));
  1463. Xstatic void FDECL(saveobjchn, (int,struct obj *, int));
  1464. Xstatic void FDECL(savemonchn, (int,struct monst *, int));
  1465. Xstatic void FDECL(savetrapchn, (int,struct trap *, int));
  1466. Xstatic void FDECL(savegenoinfo, (int));
  1467. Xstatic void FDECL(savegamestate, (int, int));
  1468. X#ifdef MFLOPPY
  1469. Xstatic void FDECL(savelev0, (int,XCHAR_P,int));
  1470. Xstatic boolean NDECL(swapout_oldest);
  1471. Xstatic void FDECL(copyfile, (char *,char *));
  1472. X#endif /* MFLOPPY */
  1473. X#ifdef GCC_WARN
  1474. Xstatic long nulls[10];
  1475. X#else
  1476. X#define nulls nul
  1477. X#endif
  1478. X
  1479. Xint
  1480. Xdosave()
  1481. X{
  1482. X    clear_nhwindow(WIN_MESSAGE);
  1483. X    if(yn("Really save?") == 'n') {
  1484. X        clear_nhwindow(WIN_MESSAGE);
  1485. X        if(multi > 0) nomul(0);
  1486. X    } else {
  1487. X        clear_nhwindow(WIN_MESSAGE);
  1488. X        pline("Saving...");
  1489. X        mark_synch();    /* flush output */
  1490. X        hu = FALSE;
  1491. X        if(dosave0()) {
  1492. X            /* make sure they see the Saving message */
  1493. X            display_nhwindow(WIN_MESSAGE, TRUE);
  1494. X            exit_nhwindows("Be seeing you...");
  1495. X            terminate(0);
  1496. X        } else (void)doredraw();
  1497. X    }
  1498. X    return 0;
  1499. X}
  1500. X
  1501. X#ifndef NOSAVEONHANGUP
  1502. Xint
  1503. Xhangup() {
  1504. X    if(!hu) {
  1505. X        hu = TRUE;
  1506. X        (void) dosave0();
  1507. X# ifndef VMS
  1508. X        terminate(1);
  1509. X# endif
  1510. X    }
  1511. X    return 0;
  1512. X}
  1513. X#endif
  1514. X
  1515. X/* returns 1 if save successful */
  1516. Xint
  1517. Xdosave0()
  1518. X{
  1519. X    register int fd, ofd;
  1520. X    xchar ltmp;
  1521. X#ifdef MFLOPPY
  1522. X    long fds, needed;
  1523. X#endif
  1524. X
  1525. X    if (!SAVEF[0])
  1526. X        return 0;
  1527. X
  1528. X#if defined(UNIX) || defined(VMS)
  1529. X    (void) signal(SIGHUP, SIG_IGN);
  1530. X#endif
  1531. X#ifndef NO_SIGNAL
  1532. X    (void) signal(SIGINT, SIG_IGN);
  1533. X#endif
  1534. X
  1535. X#if defined(MICRO) && defined(MFLOPPY)
  1536. X    if(!hu && !saveDiskPrompt(0))    return 0;
  1537. X#endif
  1538. X
  1539. X#ifdef EXPLORE_MODE
  1540. X    if(!hu && flags.window_inited) {
  1541. X        fd = open_savefile();
  1542. X        if (fd > 0) {
  1543. X        (void) close(fd);
  1544. X        clear_nhwindow(WIN_MESSAGE);
  1545. X        pline("There seems to be an old save file.");
  1546. X        if (yn("Overwrite the old file?") == 'n') return 0;
  1547. X        }
  1548. X    }
  1549. X#endif
  1550. X    
  1551. X    fd = create_savefile();
  1552. X
  1553. X    if(fd < 0) {
  1554. X        if(!hu) pline("Cannot open save file.");
  1555. X        (void) delete_savefile();    /* ab@unido */
  1556. X        return(0);
  1557. X    }
  1558. X    if(flags.moonphase == FULL_MOON)    /* ut-sally!fletcher */
  1559. X        change_luck(-1);        /* and unido!ab */
  1560. X    if(flags.friday13)
  1561. X        change_luck(1);
  1562. X    if(flags.window_inited)
  1563. X        clear_nhwindow(WIN_MESSAGE);
  1564. X
  1565. X#ifdef MFLOPPY
  1566. X    if(!hu) {
  1567. X        dotcnt = 0;
  1568. X        curs(WIN_MAP, 1, 1);
  1569. X        putstr(WIN_MAP, 0, "Saving:");
  1570. X    }
  1571. X    /* make sure there is enough disk space */
  1572. X    savelev(fd, ledger_no(&u.uz), COUNT_SAVE);
  1573. X    savegamestate(fd, COUNT_SAVE);
  1574. X    needed = bytes_counted;
  1575. X    for (ltmp = 1; ltmp <= maxledgerno(); ltmp++)
  1576. X        if (ltmp != ledger_no(&u.uz) && fileinfo[ltmp].where)
  1577. X            needed += fileinfo[ltmp].size + (sizeof ltmp);
  1578. X# ifdef AMIGA
  1579. X    needed+=ami_wbench_iconsize(SAVEF);
  1580. X# endif
  1581. X    fds = freediskspace(SAVEF);
  1582. X    if(needed > fds) {
  1583. X        if(!hu) {
  1584. X        pline("There is insufficient space on SAVE disk.");
  1585. X        pline("Require %ld bytes but only have %ld.", needed, fds);
  1586. X        }
  1587. X        flushout();
  1588. X        (void) close(fd);
  1589. X        (void) delete_savefile();
  1590. X        return 0;
  1591. X    }
  1592. X#endif /* MFLOPPY */
  1593. X
  1594. X    bufon(fd);
  1595. X    savelev(fd, ledger_no(&u.uz), WRITE_SAVE | FREE_SAVE);
  1596. X    savegamestate(fd, WRITE_SAVE | FREE_SAVE);
  1597. X
  1598. X    for(ltmp = (xchar)1; ltmp <= maxledgerno(); ltmp++) {
  1599. X        if (ltmp == ledger_no(&u.uz)) continue;
  1600. X#ifdef MFLOPPY
  1601. X        if (!fileinfo[ltmp].where) continue;
  1602. X#else
  1603. X        if(!level_exists[ltmp]) continue;
  1604. X#endif
  1605. X#ifdef MICRO
  1606. X        if(!hu) {
  1607. X            curs(WIN_MAP, 8 + dotcnt++, 1);
  1608. X            putstr(WIN_MAP, 0, ".");
  1609. X        }
  1610. X#endif
  1611. X        ofd = open_levelfile(ltmp);
  1612. X        if(ofd < 0) {
  1613. X            if(!hu) pline("Cannot read level %d.", ltmp);
  1614. X            (void) close(fd);
  1615. X            (void) delete_savefile();
  1616. X            if(!hu) done(TRICKED);
  1617. X            return(0);
  1618. X        }
  1619. X        minit();    /* ZEROCOMP */
  1620. X        getlev(ofd, hackpid, ltmp, FALSE);
  1621. X        (void) close(ofd);
  1622. X        bwrite(fd, (genericptr_t) <mp, sizeof ltmp); /* level number*/
  1623. X        savelev(fd, ltmp, WRITE_SAVE | FREE_SAVE);     /* actual level*/
  1624. X        delete_levelfile(ltmp);
  1625. X    }
  1626. X    bclose(fd);
  1627. X
  1628. X    /* get rid of current level --jgm */
  1629. X    delete_levelfile(ledger_no(&u.uz));
  1630. X    delete_levelfile(0);
  1631. X    compress(SAVEF);
  1632. X#ifdef AMIGA
  1633. X    ami_wbench_iconwrite(SAVEF);
  1634. X#endif
  1635. X    return(1);
  1636. X}
  1637. X
  1638. Xstatic void
  1639. Xsavegamestate(fd, mode)
  1640. Xregister int fd, mode;
  1641. X{
  1642. X    int tmp;        /* not register ! */
  1643. X
  1644. X#ifdef MFLOPPY
  1645. X    count_only = (mode & COUNT_SAVE);
  1646. X#endif
  1647. X    saveobjchn(fd, invent, mode);
  1648. X    saveobjchn(fd, migrating_objs, mode);
  1649. X    savemonchn(fd, migrating_mons, mode);
  1650. X    savegenoinfo(fd);
  1651. X    tmp = getuid();
  1652. X    bwrite(fd, (genericptr_t) &tmp, sizeof tmp);
  1653. X    bwrite(fd, (genericptr_t) &flags, sizeof(struct flag));
  1654. X    bwrite(fd, (genericptr_t) &u, sizeof(struct you));
  1655. X    save_dungeon(fd);
  1656. X    bwrite(fd, (genericptr_t) &inv_pos, sizeof inv_pos);
  1657. X    savelevchn(fd, mode);
  1658. X    bwrite(fd, (genericptr_t) &moves, sizeof moves);
  1659. X    bwrite(fd, (genericptr_t) &monstermoves, sizeof monstermoves);
  1660. X#ifdef MULDGN
  1661. X    bwrite(fd, (genericptr_t) &quest_status, sizeof(struct q_score));
  1662. X#endif
  1663. X    bwrite(fd, (genericptr_t) spl_book, 
  1664. X                sizeof(struct spell) * (MAXSPELL + 1));
  1665. X    save_artifacts(fd);
  1666. X    save_oracles(fd);
  1667. X    if(u.ustuck)
  1668. X        bwrite(fd, (genericptr_t) &(u.ustuck->m_id), sizeof u.ustuck->m_id);
  1669. X    bwrite(fd, (genericptr_t) pl_character, sizeof pl_character);
  1670. X#ifdef TUTTI_FRUTTI
  1671. X    bwrite(fd, (genericptr_t) pl_fruit, sizeof pl_fruit);
  1672. X    bwrite(fd, (genericptr_t) ¤t_fruit, sizeof current_fruit);
  1673. X    savefruitchn(fd, mode);
  1674. X#endif
  1675. X    savenames(fd);
  1676. X    save_waterlevel(fd);
  1677. X    bflush(fd);
  1678. X}
  1679. X
  1680. X#ifdef INSURANCE
  1681. Xvoid
  1682. Xsavestateinlock()
  1683. X{
  1684. X    int fd, hpid;
  1685. X    static boolean havestate = TRUE;
  1686. X
  1687. X    /* When checkpointing is on, the full state needs to be written
  1688. X     * on each checkpoint.  When checkpointing is off, only the pid
  1689. X     * needs to be in the level.0 file, so it does not need to be
  1690. X     * constantly rewritten.  When checkpointing is turned off during
  1691. X     * a game, however, the file has to be rewritten once to truncate
  1692. X     * it and avoid restoring from outdated information.
  1693. X     *
  1694. X     * Restricting havestate to this routine means that an additional
  1695. X     * noop pid rewriting will take place on the first "checkpoint" after
  1696. X     * the game is started or restored, if checkpointing is off.
  1697. X     */
  1698. X    if (flags.ins_chkpt || havestate) {
  1699. X        /* save the rest of the current game state in the lock file,
  1700. X         * following the original int pid, the current level number,
  1701. X         * and the current savefile name, which should not be subject
  1702. X         * to any internal compression schemes since they must be
  1703. X         * readable by an external utility
  1704. X         */
  1705. X        fd = open_levelfile(0);
  1706. X        if (fd < 0) {
  1707. X            pline("Cannot open level 0.");
  1708. X            pline("Probably someone removed it.");
  1709. X            done(TRICKED);
  1710. X            return;
  1711. X        }
  1712. X
  1713. X        (void) read(fd, (genericptr_t) &hpid, sizeof(hpid));
  1714. X        if (hackpid != hpid) {
  1715. X            pline("Level 0 pid bad!");
  1716. X            done(TRICKED);
  1717. X        }
  1718. X        (void) close(fd);
  1719. X
  1720. X        fd = create_levelfile(0);
  1721. X        if (fd < 0) {
  1722. X            pline("Cannot rewrite level 0.");
  1723. X            done(TRICKED);
  1724. X            return;
  1725. X        }
  1726. X        (void) write(fd, (genericptr_t) &hackpid, sizeof(hackpid));
  1727. X        if (flags.ins_chkpt) {
  1728. X            int currlev = ledger_no(&u.uz);
  1729. X
  1730. X            (void) write(fd, (genericptr_t) &currlev, sizeof(currlev));
  1731. X            save_savefile_name(fd);
  1732. X            bufon(fd);
  1733. X            savegamestate(fd, WRITE_SAVE);
  1734. X        }
  1735. X        bclose(fd);
  1736. X    }
  1737. X    havestate = flags.ins_chkpt;
  1738. X}
  1739. X#endif
  1740. X
  1741. X#ifdef MFLOPPY
  1742. Xboolean
  1743. Xsavelev(fd, lev, mode)
  1744. Xint fd;
  1745. Xxchar lev;
  1746. Xint mode;
  1747. X{
  1748. X    if (mode & COUNT_SAVE) {
  1749. X        bytes_counted = 0;
  1750. X        savelev0(fd, lev, COUNT_SAVE);
  1751. X        while (bytes_counted > freediskspace(levels))
  1752. X            if (!swapout_oldest())
  1753. X                return FALSE;
  1754. X    }
  1755. X    if (mode & WRITE_SAVE) {
  1756. X        bytes_counted = 0;
  1757. X        /* mode is WRITE_SAVE and possibly FREE_SAVE */
  1758. X        savelev0(fd, lev, mode);
  1759. X    }
  1760. X    fileinfo[lev].where = ACTIVE;
  1761. X    fileinfo[lev].time = moves;
  1762. X    fileinfo[lev].size = bytes_counted;
  1763. X    return TRUE;
  1764. X}
  1765. X
  1766. Xstatic void
  1767. Xsavelev0(fd,lev,mode)
  1768. X#else
  1769. Xvoid
  1770. Xsavelev(fd,lev,mode)
  1771. X#endif
  1772. Xint fd;
  1773. Xxchar lev;
  1774. Xint mode;
  1775. X{
  1776. X#ifdef TOS
  1777. X    short tlev;
  1778. X#endif
  1779. X
  1780. X    if(fd < 0) panic("Save on bad file!");    /* impossible */
  1781. X#ifdef MFLOPPY
  1782. X    count_only = (mode & COUNT_SAVE);
  1783. X#else
  1784. X    if(lev >= 0 && lev <= maxledgerno()) level_exists[lev] = TRUE;
  1785. X#endif
  1786. X    bwrite(fd,(genericptr_t) &hackpid,sizeof(hackpid));
  1787. X#ifdef TOS
  1788. X    tlev=lev; tlev &= 0x00ff;
  1789. X    bwrite(fd,(genericptr_t) &tlev,sizeof(tlev));
  1790. X#else
  1791. X    bwrite(fd,(genericptr_t) &lev,sizeof(lev));
  1792. X#endif
  1793. X#ifdef RLECOMP
  1794. X    {
  1795. X        /* perform run-length encoding of rm structs */
  1796. X        struct rm *prm, *rgrm;
  1797. X        int x, y;
  1798. X        uchar match;
  1799. X        
  1800. X        rgrm = &levl[0][0];        /* start matching at first rm */
  1801. X        match = 0;
  1802. X
  1803. X        for (y = 0; y < ROWNO; y++) {
  1804. X        for (x = 0; x < COLNO; x++) {
  1805. X            prm = &levl[x][y];
  1806. X            if (prm->glyph == rgrm->glyph
  1807. X            && prm->typ == rgrm->typ
  1808. X            && prm->seen == rgrm->seen
  1809. X            && prm->lit == rgrm->lit
  1810. X            && prm->doormask == rgrm->doormask
  1811. X            && prm->horizontal == rgrm->horizontal
  1812. X            && prm->waslit == rgrm->waslit
  1813. X            && prm->roomno == rgrm->roomno
  1814. X            && prm->edge == rgrm->edge) {
  1815. X            match++;
  1816. X            if (match > 254) {
  1817. X                match = 254;    /* undo this match */
  1818. X                goto writeout;
  1819. X            }
  1820. X            } else {
  1821. X            /* the run has been broken,
  1822. X             * write out run-length encoding */
  1823. X            writeout:
  1824. X            bwrite(fd, (genericptr_t)&match, sizeof(uchar));
  1825. X            bwrite(fd, (genericptr_t)rgrm, sizeof(struct rm));
  1826. X            /* start encoding again. we have at least 1 rm
  1827. X             * in the next run, viz. this one. */
  1828. X            match = 1;    
  1829. X            rgrm = prm;
  1830. X            }
  1831. X        }
  1832. X        }
  1833. X        if (match > 0) {
  1834. X        bwrite(fd, (genericptr_t)&match, sizeof(uchar));
  1835. X        bwrite(fd, (genericptr_t)rgrm, sizeof(struct rm));
  1836. X        }
  1837. X    }
  1838. X#else
  1839. X    bwrite(fd,(genericptr_t) levl,sizeof(levl));
  1840. X#endif /* RLECOMP */
  1841. X
  1842. X    bwrite(fd,(genericptr_t) &monstermoves,sizeof(monstermoves));
  1843. X    bwrite(fd,(genericptr_t) &upstair,sizeof(stairway));
  1844. X    bwrite(fd,(genericptr_t) &dnstair,sizeof(stairway));
  1845. X    bwrite(fd,(genericptr_t) &upladder,sizeof(stairway));
  1846. X    bwrite(fd,(genericptr_t) &dnladder,sizeof(stairway));
  1847. X    bwrite(fd,(genericptr_t) &sstairs,sizeof(stairway));
  1848. X    bwrite(fd,(genericptr_t) &updest,sizeof(dest_area));
  1849. X    bwrite(fd,(genericptr_t) &dndest,sizeof(dest_area));
  1850. X    bwrite(fd,(genericptr_t) &level.flags,sizeof(level.flags));
  1851. X    savemonchn(fd, fmon, mode);
  1852. X    save_worm(fd, mode);    /* save worm information */
  1853. X    savetrapchn(fd, ftrap, mode);
  1854. X    saveobjchn(fd, fobj, mode);
  1855. X    saveobjchn(fd, billobjs, mode);
  1856. X
  1857. X    save_engravings(fd, mode);
  1858. X    save_rooms(fd);
  1859. X    bwrite(fd,(genericptr_t) doors,sizeof(doors));
  1860. X    savedamage(fd, level.damagelist, mode);
  1861. X    if (mode & FREE_SAVE) {
  1862. X        billobjs = 0;
  1863. X        ftrap = 0;
  1864. X        fmon = 0;
  1865. X        fobj = 0;
  1866. X    }
  1867. X    bflush(fd);
  1868. X}
  1869. X
  1870. X#ifdef ZEROCOMP
  1871. X/* The runs of zero-run compression are flushed after the game state or a
  1872. X * level is written out.  This adds a couple bytes to a save file, where
  1873. X * the runs could be mashed together, but it allows gluing together game
  1874. X * state and level files to form a save file, and it means the flushing
  1875. X * does not need to be specifically called for every other time a level
  1876. X * file is written out.
  1877. X */
  1878. X
  1879. X#define RLESC '\0'    /* Leading character for run of LRESC's */
  1880. X#define flushoutrun(ln) (bputc(RLESC), bputc(ln), ln = -1)
  1881. X
  1882. X#ifndef ZEROCOMP_BUFSIZ
  1883. X#define ZEROCOMP_BUFSIZ BUFSZ
  1884. X#endif
  1885. Xstatic unsigned char NEARDATA outbuf[ZEROCOMP_BUFSIZ];
  1886. Xstatic unsigned short NEARDATA outbufp = 0;
  1887. Xstatic short NEARDATA outrunlength = -1;
  1888. Xstatic int NEARDATA bwritefd;
  1889. X
  1890. X/*dbg()
  1891. X{
  1892. X   if(!hu) printf("outbufp %d outrunlength %d\n", outbufp,outrunlength);
  1893. X}*/
  1894. X
  1895. Xstatic void
  1896. Xbputc(c)
  1897. Xunsigned char c;
  1898. X{
  1899. X#ifdef MFLOPPY
  1900. X    bytes_counted++;
  1901. X    if (count_only)
  1902. X      return;
  1903. X#endif
  1904. X    if (outbufp >= sizeof outbuf) {
  1905. X    (void) write(bwritefd, outbuf, sizeof outbuf);
  1906. X    outbufp = 0;
  1907. X    }
  1908. X    outbuf[outbufp++] = c;
  1909. X}
  1910. X
  1911. X/*ARGSUSED*/
  1912. Xvoid
  1913. Xbufon(fd)
  1914. X    int fd;
  1915. X{
  1916. X    return;
  1917. X}
  1918. X
  1919. Xvoid
  1920. Xbflush(fd)  /* flush run and buffer */
  1921. Xregister int fd;
  1922. X{
  1923. X      bwritefd = fd;
  1924. X      if (outrunlength >= 0) {    /* flush run */
  1925. X      flushoutrun(outrunlength);
  1926. X      }
  1927. X      if (outbufp) {
  1928. X#ifdef MFLOPPY
  1929. X      if (!count_only)    /* flush buffer */
  1930. X#endif
  1931. X          (void) write(fd, outbuf, outbufp);
  1932. X      outbufp = 0;
  1933. X      }
  1934. X      /*printf("bflush()"); getret();*/
  1935. X}
  1936. X
  1937. Xvoid
  1938. Xbwrite(fd, loc, num)
  1939. Xregister int fd;
  1940. Xgenericptr_t loc;
  1941. Xregister unsigned num;
  1942. X{
  1943. X      bwritefd = fd;
  1944. X      for (; num; num--, (*(char **)&loc)++) {
  1945. X          if (*((char *)loc) == RLESC) { /* One more char in run */
  1946. X          if (++outrunlength == 0xFF) {
  1947. X              flushoutrun(outrunlength);
  1948. X          }
  1949. X          } else { /* end of run */
  1950. X          if (outrunlength >= 0) {    /* flush run */
  1951. X              flushoutrun(outrunlength);
  1952. X          }
  1953. X          bputc(*((char *)loc));
  1954. X          }
  1955. X      }
  1956. X}
  1957. X
  1958. Xvoid
  1959. Xbclose(fd)
  1960. X    int fd;
  1961. X{
  1962. X    if (outbufp)
  1963. X    panic("closing file with buffered data still unwritten");
  1964. X    (void) close(fd);
  1965. X}
  1966. X
  1967. X#else /* ZEROCOMP */
  1968. X
  1969. Xstatic int bw_fd = -1;
  1970. Xstatic FILE *bw_FILE = 0;
  1971. X
  1972. Xvoid
  1973. Xbufon(fd)
  1974. X    int fd;
  1975. X{
  1976. X#ifdef UNIX
  1977. X    if(bw_fd >= 0)
  1978. X    panic("double buffering unexpected");
  1979. X    bw_fd = fd;
  1980. X    if((bw_FILE = fdopen(fd, "w")) == 0)
  1981. X    panic("buffering of file %d failed", fd);
  1982. X#endif
  1983. X}
  1984. X
  1985. Xvoid
  1986. Xbflush(fd)
  1987. X    int fd;
  1988. X{
  1989. X#ifdef UNIX
  1990. X    if(fd == bw_fd) {
  1991. X    if(fflush(bw_FILE) == EOF)
  1992. X        panic("flush of savefile failed!");
  1993. X    }
  1994. X#endif
  1995. X    return;
  1996. X}
  1997. X
  1998. Xvoid
  1999. Xbwrite(fd,loc,num)
  2000. Xregister int fd;
  2001. Xregister genericptr_t loc;
  2002. Xregister unsigned num;
  2003. X{
  2004. X#ifdef MFLOPPY
  2005. X    bytes_counted += num;
  2006. X    if (!count_only)
  2007. X#endif
  2008. X    {
  2009. X#ifdef UNIX
  2010. X        if(fd != bw_fd)
  2011. X        panic("unbuffered write to fd %d (!= %d)", fd, bw_fd);
  2012. X
  2013. X        if(fwrite(loc, (int)num, 1, bw_FILE) != 1)
  2014. X/* lint wants the 3rd arg of write to be an int; lint -p an unsigned */
  2015. X#else
  2016. X# if defined(BSD) || defined(ULTRIX)
  2017. X        if(write(fd, loc, (int)num) != (int)num)
  2018. X# else /* e.g. SYSV, __TURBOC__ */
  2019. X        if(write(fd, loc, num) != num)
  2020. X# endif
  2021. X#endif
  2022. X        {
  2023. X        if(!hu) panic("cannot write %u bytes to file #%d", num, fd);
  2024. X        else    terminate(1);
  2025. X        }
  2026. X    }
  2027. X}
  2028. X
  2029. Xvoid
  2030. Xbclose(fd)
  2031. X    int fd;
  2032. X{
  2033. X    bflush(fd);
  2034. X#ifdef UNIX
  2035. X    if (fd == bw_fd) {
  2036. X    (void) fclose(bw_FILE);
  2037. X    bw_fd = -1;
  2038. X    bw_FILE = 0;
  2039. X    return;
  2040. X    }
  2041. X#endif
  2042. X    (void) close(fd);
  2043. X}
  2044. X#endif /* ZEROCOMP */
  2045. X
  2046. Xstatic void
  2047. Xsavelevchn(fd, mode)
  2048. Xregister int fd, mode;
  2049. X{
  2050. X    int cnt = 0;
  2051. X    s_level    *tmplev, *tmplev2;
  2052. X
  2053. X    for(tmplev = sp_levchn; tmplev; tmplev = tmplev->next) cnt++;
  2054. X    bwrite(fd, (genericptr_t) &cnt, sizeof(int));
  2055. X
  2056. X    for(tmplev = sp_levchn; tmplev; tmplev = tmplev2) {
  2057. X
  2058. X        tmplev2 = tmplev->next;
  2059. X        bwrite(fd, (genericptr_t) tmplev, sizeof(s_level));
  2060. X        if (mode & FREE_SAVE)
  2061. X        free((genericptr_t) tmplev);
  2062. X    }
  2063. X}
  2064. X
  2065. Xstatic void
  2066. Xsavedamage(fd, damageptr, mode)
  2067. Xregister int fd, mode;
  2068. Xregister struct damage *damageptr;
  2069. X{
  2070. X    register struct damage *tmp_dam;
  2071. X    unsigned int xl = 0;
  2072. X
  2073. X    for (tmp_dam = damageptr; tmp_dam; tmp_dam = tmp_dam->next) 
  2074. X        xl++;
  2075. X    bwrite(fd, (genericptr_t) &xl, sizeof(xl));
  2076. X    while (xl--) {
  2077. X        bwrite(fd, (genericptr_t) damageptr, sizeof(*damageptr)); 
  2078. X        tmp_dam = damageptr;
  2079. X        damageptr = damageptr->next;
  2080. X        if (mode & FREE_SAVE)
  2081. X        free((genericptr_t)tmp_dam);
  2082. X    }
  2083. X    if (mode & FREE_SAVE)
  2084. X        level.damagelist = 0;
  2085. X}
  2086. X
  2087. Xstatic void
  2088. Xsaveobjchn(fd,otmp,mode)
  2089. Xregister int fd, mode;
  2090. Xregister struct obj *otmp;
  2091. X{
  2092. X    register struct obj *otmp2;
  2093. X    unsigned int xl;
  2094. X    int minusone = -1;
  2095. X
  2096. X    while(otmp) {
  2097. X        otmp2 = otmp->nobj;
  2098. X        xl = otmp->onamelth;
  2099. X        bwrite(fd, (genericptr_t) &xl, sizeof(int));
  2100. X        bwrite(fd, (genericptr_t) otmp, xl + sizeof(struct obj));
  2101. X
  2102. X        if (Is_container(otmp) || otmp->otyp == STATUE)
  2103. X        saveobjchn(fd,otmp->cobj,mode);
  2104. X        if (mode & FREE_SAVE)
  2105. X        dealloc_obj(otmp);
  2106. X        otmp = otmp2;
  2107. X    }
  2108. X    bwrite(fd, (genericptr_t) &minusone, sizeof(int));
  2109. X}
  2110. X
  2111. Xstatic void
  2112. Xsavemonchn(fd,mtmp,mode)
  2113. Xregister int fd, mode;
  2114. Xregister struct monst *mtmp;
  2115. X{
  2116. X    register struct monst *mtmp2;
  2117. X    unsigned int xl;
  2118. X    int minusone = -1;
  2119. X    struct permonst *monbegin = &mons[0];
  2120. X
  2121. X    bwrite(fd, (genericptr_t) &monbegin, sizeof(monbegin));
  2122. X
  2123. X    while(mtmp) {
  2124. X        mtmp2 = mtmp->nmon;
  2125. X#ifdef MUSE
  2126. X        if (mtmp->mw && mtmp->mw != mtmp->minvent) sort_mwep(mtmp);
  2127. X#endif
  2128. X        xl = mtmp->mxlth + mtmp->mnamelth;
  2129. X        bwrite(fd, (genericptr_t) &xl, sizeof(int));
  2130. X        bwrite(fd, (genericptr_t) mtmp, xl + sizeof(struct monst));
  2131. X        if(mtmp->minvent) saveobjchn(fd,mtmp->minvent,mode);
  2132. X        if (mode & FREE_SAVE)
  2133. X            dealloc_monst(mtmp);
  2134. X        mtmp = mtmp2;
  2135. X    }
  2136. X    bwrite(fd, (genericptr_t) &minusone, sizeof(int));
  2137. X}
  2138. X
  2139. Xstatic void
  2140. Xsavetrapchn(fd,trap,mode)
  2141. Xregister int fd,mode;
  2142. Xregister struct trap *trap;
  2143. X{
  2144. X    register struct trap *trap2;
  2145. X    while(trap) {
  2146. X        trap2 = trap->ntrap;
  2147. X        bwrite(fd, (genericptr_t) trap, sizeof(struct trap));
  2148. X        if (mode & FREE_SAVE)
  2149. X            dealloc_trap(trap);
  2150. X        trap = trap2;
  2151. X    }
  2152. X    bwrite(fd, (genericptr_t)nulls, sizeof(struct trap));
  2153. X}
  2154. X
  2155. X#ifdef TUTTI_FRUTTI
  2156. X/* save all the fruit names and ID's; this is used only in saving whole games
  2157. X * (not levels) and in saving bones levels.  When saving a bones level,
  2158. X * we only want to save the fruits which exist on the bones level; the bones
  2159. X * level routine marks nonexistent fruits by making the fid negative.
  2160. X */
  2161. Xvoid
  2162. Xsavefruitchn(fd, mode)
  2163. Xregister int fd, mode;
  2164. X{
  2165. X    register struct fruit *f2, *f1;
  2166. X
  2167. X    f1 = ffruit;
  2168. X    while(f1) {
  2169. X        f2 = f1->nextf;
  2170. X        if (f1->fid >= 0) {
  2171. X            bwrite(fd, (genericptr_t) f1, sizeof(struct fruit));
  2172. X        }
  2173. X        if (mode & FREE_SAVE)
  2174. X            dealloc_fruit(f1);
  2175. X        f1 = f2;
  2176. X    }
  2177. X    bwrite(fd, (genericptr_t)nulls, sizeof(struct fruit));
  2178. X}
  2179. X#endif
  2180. X
  2181. Xstatic void
  2182. Xsavegenoinfo(fd)
  2183. Xregister int fd;
  2184. X{
  2185. X    register int i;
  2186. X    unsigned genolist[NUMMONS];
  2187. X
  2188. X    for (i = 0; i < NUMMONS; i++)
  2189. X        genolist[i] = mons[i].geno;
  2190. X
  2191. X    bwrite(fd, (genericptr_t) genolist, sizeof(genolist));
  2192. X}
  2193. X
  2194. X#ifdef MFLOPPY
  2195. Xboolean
  2196. Xswapin_file(lev)
  2197. Xint lev;
  2198. X{
  2199. X    char to[PATHLEN], from[PATHLEN];
  2200. X
  2201. X    Sprintf(from, "%s%s", permbones, alllevels);
  2202. X    Sprintf(to, "%s%s", levels, alllevels);
  2203. X    set_levelfile_name(from, lev);
  2204. X    set_levelfile_name(to, lev);
  2205. X    while (fileinfo[lev].size > freediskspace(to))
  2206. X        if (!swapout_oldest())
  2207. X            return FALSE;
  2208. X# ifdef WIZARD
  2209. X    if (wizard) {
  2210. X        pline("Swapping in `%s'", from);
  2211. X        wait_synch();
  2212. X    }
  2213. X# endif
  2214. X    copyfile(from, to);
  2215. X    (void) unlink(from);
  2216. X    fileinfo[lev].where = ACTIVE;
  2217. X    return TRUE;
  2218. X}
  2219. X
  2220. Xstatic boolean
  2221. Xswapout_oldest() {
  2222. X    char to[PATHLEN], from[PATHLEN];
  2223. X    int i, oldest;
  2224. X    long oldtime;
  2225. X
  2226. X    if (!ramdisk)
  2227. X        return FALSE;
  2228. X    for (i = 1, oldtime = 0, oldest = 0; i <= maxledgerno(); i++)
  2229. X        if (fileinfo[i].where == ACTIVE
  2230. X        && (!oldtime || fileinfo[i].time < oldtime)) {
  2231. X            oldest = i;
  2232. X            oldtime = fileinfo[i].time;
  2233. X        }
  2234. X    if (!oldest)
  2235. X        return FALSE;
  2236. X    Sprintf(from, "%s%s", levels, alllevels);
  2237. X    Sprintf(to, "%s%s", permbones, alllevels);
  2238. X    set_levelfile_name(from, oldest);
  2239. X    set_levelfile_name(to, oldest);
  2240. X# ifdef WIZARD
  2241. X    if (wizard) {
  2242. X        pline("Swapping out `%s'.", from);
  2243. X        wait_synch();
  2244. X    }
  2245. X# endif
  2246. X    copyfile(from, to);
  2247. X    (void) unlink(from);
  2248. X    fileinfo[oldest].where = SWAPPED;
  2249. X    return TRUE;
  2250. X}
  2251. X
  2252. Xstatic void
  2253. Xcopyfile(from, to)
  2254. Xchar *from, *to;
  2255. X{
  2256. X# ifdef TOS
  2257. X
  2258. X    if (_copyfile(from, to))
  2259. X        panic("Can't copy %s to %s", from, to);
  2260. X# else
  2261. X    char buf[BUFSIZ];    /* this is system interaction, therefore
  2262. X                 * BUFSIZ instead of NetHack's BUFSZ */
  2263. X    int nfrom, nto, fdfrom, fdto;
  2264. X
  2265. X    if ((fdfrom = open(from, O_RDONLY | O_BINARY, FCMASK)) < 0)
  2266. X        panic("Can't copy from %s !?", from);
  2267. X    if ((fdto = open(to, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC, FCMASK)) < 0)
  2268. X        panic("Can't copy to %s", to);
  2269. X    do {
  2270. X        nfrom = read(fdfrom, buf, BUFSIZ);
  2271. X        nto = write(fdto, buf, nfrom);
  2272. X        if (nto != nfrom)
  2273. X            panic("Copyfile failed!");
  2274. X    } while (nfrom == BUFSIZ);
  2275. X    (void) close(fdfrom);
  2276. X    (void) close(fdto);
  2277. X# endif /* TOS */
  2278. X}
  2279. X
  2280. Xvoid
  2281. Xco_false()        /* see comment in bones.c */
  2282. X{
  2283. X    count_only = FALSE;
  2284. X    return;
  2285. X}
  2286. X
  2287. X#endif /* MFLOPPY */
  2288. X
  2289. X/*save.c*/
  2290. END_OF_FILE
  2291. if test 19844 -ne `wc -c <'src/save.c'`; then
  2292.     echo shar: \"'src/save.c'\" unpacked with wrong size!
  2293. fi
  2294. # end of 'src/save.c'
  2295. fi
  2296. echo shar: End of archive 54 \(of 108\).
  2297. cp /dev/null ark54isdone
  2298. MISSING=""
  2299. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 \
  2300. 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 \
  2301. 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 \
  2302. 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 \
  2303. 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 \
  2304. 101 102 103 104 105 106 107 108 ; do
  2305.     if test ! -f ark${I}isdone ; then
  2306.     MISSING="${MISSING} ${I}"
  2307.     fi
  2308. done
  2309. if test "${MISSING}" = "" ; then
  2310.     echo You have unpacked all 108 archives.
  2311.     echo "Now execute 'rebuild.sh'"
  2312.     rm -f ark10[0-8]isdone ark[1-9]isdone ark[1-9][0-9]isdone
  2313. else
  2314.     echo You still need to unpack the following archives:
  2315.     echo "        " ${MISSING}
  2316. fi
  2317. ##  End of shell archive.
  2318. exit 0
  2319.