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

  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: v16i058:  nethack31 - display oriented dungeons & dragons (Ver. 3.1), Part50/108
  5. Message-ID: <4361@master.CNA.TEK.COM>
  6. Date: 1 Feb 93 19:42:38 GMT
  7. Sender: news@master.CNA.TEK.COM
  8. Lines: 2248
  9. Approved: billr@saab.CNA.TEK.COM
  10. Xref: uunet comp.sources.games:1608
  11.  
  12. Submitted-by: izchak@linc.cis.upenn.edu (Izchak Miller)
  13. Posting-number: Volume 16, Issue 58
  14. Archive-name: nethack31/Part50
  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 50 (of 108)."
  27. # Contents:  src/dogmove.c util/lev_comp.y
  28. # Wrapped by billr@saab on Wed Jan 27 16:09:06 1993
  29. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  30. if test -f 'src/dogmove.c' -a "${1}" != "-c" ; then 
  31.   echo shar: Will not clobber existing file \"'src/dogmove.c'\"
  32. else
  33. echo shar: Extracting \"'src/dogmove.c'\" \(17769 characters\)
  34. sed "s/^X//" >'src/dogmove.c' <<'END_OF_FILE'
  35. X/*    SCCS Id: @(#)dogmove.c    3.1    92/11/26    */
  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
  41. X#include "mfndpos.h"
  42. X#include "edog.h"
  43. X
  44. X#ifdef OVL0
  45. X
  46. Xstatic boolean FDECL(dog_hunger,(struct monst *,struct edog *));
  47. Xstatic boolean FDECL(dog_invent,(struct monst *,struct edog *,int));
  48. Xstatic int FDECL(dog_goal,(struct monst *,struct edog *,int,int,int));
  49. X
  50. X#ifndef MUSE
  51. X#define DROPPABLES(mtmp) mtmp->minvent
  52. X#else
  53. Xstatic struct obj *FDECL(DROPPABLES, (struct monst *));
  54. X
  55. Xstatic struct obj *
  56. XDROPPABLES(mon)
  57. Xregister struct monst *mon;
  58. X{
  59. X    register struct obj *obj;
  60. X    struct obj *wep = MON_WEP(mon);
  61. X
  62. X    for(obj = mon->minvent; obj; obj = obj->nobj)
  63. X        if (!obj->owornmask && obj != wep) return obj;
  64. X    return (struct obj *)0;
  65. X}
  66. X#endif
  67. X
  68. Xstatic const char NEARDATA nofetch[] = { BALL_CLASS, CHAIN_CLASS, ROCK_CLASS, 0 };
  69. X
  70. X#endif /* OVL0 */
  71. X
  72. XSTATIC_VAR xchar gtyp, gx, gy;    /* type and position of dog's current goal */
  73. X
  74. XSTATIC_DCL void FDECL(dog_eat, (struct monst *, struct obj *, int, int));
  75. XSTATIC_PTR void FDECL(wantdoor, (int, int, genericptr_t));
  76. X
  77. X#ifdef OVLB
  78. X
  79. XSTATIC_OVL void
  80. Xdog_eat(mtmp, obj, x, y)
  81. Xregister struct monst *mtmp;
  82. Xregister struct obj * obj;
  83. Xint x, y;
  84. X{
  85. X    register struct edog *edog = EDOG(mtmp);
  86. X    int nutrit;
  87. X
  88. X    if(edog->hungrytime < moves)
  89. X        edog->hungrytime = moves;
  90. X    /*
  91. X     * It is arbitrary that the pet takes the same length of time to eat
  92. X     * as a human, but gets more nutritional value.
  93. X     */
  94. X    if (obj->oclass == FOOD_CLASS) {
  95. X        if(obj->otyp == CORPSE) {
  96. X        mtmp->meating = 3 + (mons[obj->corpsenm].cwt >> 6);
  97. X        nutrit = mons[obj->corpsenm].cnutrit;
  98. X        } else {
  99. X        mtmp->meating = objects[obj->otyp].oc_delay;
  100. X        nutrit = objects[obj->otyp].oc_nutrition;
  101. X        }
  102. X        switch(mtmp->data->msize) {
  103. X        case MZ_TINY: nutrit *= 8; break;
  104. X        case MZ_SMALL: nutrit *= 6; break;
  105. X        default:
  106. X        case MZ_MEDIUM: nutrit *= 5; break;
  107. X        case MZ_LARGE: nutrit *= 4; break;
  108. X        case MZ_HUGE: nutrit *= 3; break;
  109. X        case MZ_GIGANTIC: nutrit *= 2; break;
  110. X        }
  111. X        if(obj->oeaten) {
  112. X        mtmp->meating = eaten_stat(mtmp->meating, obj);
  113. X        nutrit = eaten_stat(nutrit, obj);
  114. X        }
  115. X    } else if (obj->oclass == GOLD_CLASS) {
  116. X        mtmp->meating = ((int)obj->quan/2000) + 1;
  117. X        nutrit = ((int)obj->quan/20);
  118. X    } else {
  119. X        /* Unusual pet such as gelatinous cube eating odd stuff.
  120. X         * meating made consistent with wild monsters in mon.c.
  121. X         * nutrit made consistent with polymorphed player nutrit in
  122. X         * eat.c.  (This also applies to pets eating gold.)
  123. X         */
  124. X        mtmp->meating = obj->owt/20 + 1;
  125. X        nutrit = 5*objects[obj->otyp].oc_nutrition;
  126. X    }
  127. X    edog->hungrytime += nutrit;
  128. X    mtmp->mconf = 0;
  129. X    if (mtmp->mtame < 20) mtmp->mtame++;
  130. X    if(cansee(x,y))
  131. X        pline("%s eats %s.", Monnam(mtmp), (obj->oclass==FOOD_CLASS)
  132. X        ? singular(obj, doname) : doname(obj));
  133. X    /* It's a reward if it's DOGFOOD and the player dropped/threw it. */
  134. X    /* We know the player had it if invlet is set -dlc */
  135. X    if(dogfood(mtmp,obj) == DOGFOOD && obj->invlet)
  136. X#ifdef LINT
  137. X        edog->apport = 0;
  138. X#else
  139. X        edog->apport += (unsigned)(200L/
  140. X        ((long)edog->dropdist+moves-edog->droptime));
  141. X#endif
  142. X    if (obj == uball) {
  143. X        unpunish();
  144. X        delobj(obj);
  145. X    } else if (obj == uchain)
  146. X        unpunish();
  147. X    else if (obj->quan > 1L && obj->oclass == FOOD_CLASS)
  148. X        obj->quan--;
  149. X    else
  150. X        delobj(obj);
  151. X}
  152. X
  153. X#endif /* OVLB */
  154. X#ifdef OVL0
  155. X
  156. X/* hunger effects -- returns TRUE on starvation */
  157. Xstatic boolean
  158. Xdog_hunger(mtmp, edog)
  159. Xregister struct monst *mtmp;
  160. Xregister struct edog *edog;
  161. X{
  162. X    if(moves > edog->hungrytime + 500) {
  163. X        if(!carnivorous(mtmp->data) && !herbivorous(mtmp->data)) {
  164. X        edog->hungrytime = moves + 500;
  165. X        /* but not too high; it might polymorph */
  166. X        } else if (!mtmp->mconf) {
  167. X        mtmp->mconf = 1;
  168. X        mtmp->mhpmax /= 3;
  169. X        if(mtmp->mhp > mtmp->mhpmax)
  170. X            mtmp->mhp = mtmp->mhpmax;
  171. X        if(mtmp->mhp < 1) goto dog_died;
  172. X        if(cansee(mtmp->mx, mtmp->my))
  173. X            pline("%s is confused from hunger.", Monnam(mtmp));
  174. X        else {
  175. X            char buf[BUFSZ];
  176. X
  177. X            Strcpy(buf, "the ");
  178. X            You("feel worried about %s.", mtmp->mnamelth ?
  179. X            NAME(mtmp) : strcat(buf, Hallucination
  180. X            ? rndmonnam() : mtmp->data->mname));
  181. X        }
  182. X        } else if(moves > edog->hungrytime + 750 || mtmp->mhp < 1) {
  183. X        dog_died:
  184. X#ifdef WALKIES
  185. X        if(mtmp->mleashed)
  186. X            Your("leash goes slack.");
  187. X#endif
  188. X        if(cansee(mtmp->mx, mtmp->my))
  189. X            pline("%s dies%s.", Monnam(mtmp),
  190. X                (mtmp->mhp >= 1) ? "" : " from hunger");
  191. X        else
  192. X            You("have a sad feeling for a moment, then it passes.");
  193. X        mondied(mtmp);
  194. X        return(TRUE);
  195. X        }
  196. X    }
  197. X    return(FALSE);
  198. X}
  199. X
  200. X/* do something with object (drop, pick up, eat) at current position
  201. X * returns TRUE if object eaten (since that counts as dog's move)
  202. X */
  203. Xstatic boolean
  204. Xdog_invent(mtmp, edog, udist)
  205. Xregister struct monst *mtmp;
  206. Xregister struct edog *edog;
  207. Xint udist;
  208. X{
  209. X    register int omx, omy;
  210. X    struct obj *obj;
  211. X
  212. X    omx = mtmp->mx;
  213. X    omy = mtmp->my;
  214. X
  215. X    /* if we are carrying sth then we drop it (perhaps near @) */
  216. X    /* Note: if apport == 1 then our behaviour is independent of udist */
  217. X    if(DROPPABLES(mtmp) || mtmp->mgold) {
  218. X        if(!rn2(udist) || !rn2((int) edog->apport))
  219. X        if(rn2(10) < edog->apport){
  220. X            relobj(mtmp, (int)mtmp->minvis, TRUE);
  221. X            if(edog->apport > 1) edog->apport--;
  222. X            edog->dropdist = udist;        /* hpscdi!jon */
  223. X            edog->droptime = moves;
  224. X        }
  225. X    } else {
  226. X        if((obj=level.objects[omx][omy]) && !index(nofetch,obj->oclass)
  227. X#ifdef MAIL
  228. X            && obj->otyp != SCR_MAIL
  229. X#endif
  230. X                                    ){
  231. X        if (dogfood(mtmp, obj) <= CADAVER) {
  232. X            dog_eat(mtmp, obj, omx, omy);
  233. X            return TRUE;
  234. X        }
  235. X        if(can_carry(mtmp, obj) && !obj->cursed)
  236. X            if(rn2(20) < edog->apport+3)
  237. X            if(rn2(udist) || !rn2((int) edog->apport)) {
  238. X                if (cansee(omx, omy) && flags.verbose)
  239. X                pline("%s picks up %s.", Monnam(mtmp),
  240. X                    distant_name(obj, doname));
  241. X                freeobj(obj);
  242. X                newsym(omx,omy);
  243. X                mpickobj(mtmp,obj);
  244. X            }
  245. X        }
  246. X    }
  247. X    return FALSE;
  248. X}
  249. X
  250. X/* set dog's goal -- gtyp, gx, gy
  251. X * returns -1/0/1 (dog's desire to approach player) or -2 (abort move)
  252. X */
  253. Xstatic int
  254. Xdog_goal(mtmp, edog, after, udist, whappr)
  255. Xregister struct monst *mtmp;
  256. Xstruct edog *edog;
  257. Xint after, udist, whappr;
  258. X{
  259. X    register int omx, omy;
  260. X    boolean in_masters_sight;
  261. X    register struct obj *obj;
  262. X    xchar otyp;
  263. X    int appr;
  264. X
  265. X    omx = mtmp->mx;
  266. X    omy = mtmp->my;
  267. X
  268. X    in_masters_sight = couldsee(omx, omy);
  269. X
  270. X    if (!edog
  271. X#ifdef WALKIES
  272. X            || mtmp->mleashed    /* he's not going anywhere... */
  273. X#endif
  274. X                    ) {
  275. X        gtyp = APPORT;
  276. X        gx = u.ux;
  277. X        gy = u.uy;
  278. X    } else {
  279. X#define DDIST(x,y) (dist2(x,y,omx,omy))
  280. X#define SQSRCHRADIUS 5
  281. X        int min_x, max_x, min_y, max_y;
  282. X        register int nx, ny;
  283. X
  284. X        gtyp = UNDEF;    /* no goal as yet */
  285. X        gx = gy = 0;    /* suppress 'used before set' message */
  286. X
  287. X        if ((min_x = omx - SQSRCHRADIUS) < 0) min_x = 0;
  288. X        if ((max_x = omx + SQSRCHRADIUS) >= COLNO) max_x = COLNO - 1;
  289. X        if ((min_y = omy - SQSRCHRADIUS) < 0) min_y = 0;
  290. X        if ((max_y = omy + SQSRCHRADIUS) >= ROWNO) max_y = ROWNO - 1;
  291. X
  292. X        /* nearby food is the first choice, then other objects */
  293. X        for (obj = fobj; obj; obj = obj->nobj) {
  294. X        nx = obj->ox;
  295. X        ny = obj->oy;
  296. X        if (nx >= min_x && nx <= max_x && ny >= min_y && ny <= max_y) {
  297. X            otyp = dogfood(mtmp, obj);
  298. X            if (otyp > gtyp || otyp == UNDEF)
  299. X            continue;
  300. X            if (otyp < MANFOOD) {
  301. X            if (otyp < gtyp || DDIST(nx,ny) < DDIST(gx,gy)) {
  302. X                gx = nx;
  303. X                gy = ny;
  304. X                gtyp = otyp;
  305. X            }
  306. X            } else if(gtyp == UNDEF && in_masters_sight &&
  307. X                  !mtmp->minvent &&
  308. X                  (!levl[omx][omy].lit || levl[u.ux][u.uy].lit) &&
  309. X                  (otyp == MANFOOD || m_cansee(mtmp, nx, ny)) &&
  310. X                  edog->apport > rn2(8) &&
  311. X                  can_carry(mtmp,obj)) {
  312. X            gx = nx;
  313. X            gy = ny;
  314. X            gtyp = APPORT;
  315. X            }
  316. X        }
  317. X        }
  318. X    }
  319. X
  320. X    /* follow player if appropriate */
  321. X    if (gtyp == UNDEF ||
  322. X        (gtyp != DOGFOOD && gtyp != APPORT && moves < edog->hungrytime)) {
  323. X        gx = u.ux;
  324. X        gy = u.uy;
  325. X        if (after && udist <= 4 && gx == u.ux && gy == u.uy)
  326. X            return(-2);
  327. X        appr = (udist >= 9) ? 1 : (mtmp->mflee) ? -1 : 0;
  328. X        if (udist > 1) {
  329. X            if (!IS_ROOM(levl[u.ux][u.uy].typ) || !rn2(4) ||
  330. X               whappr ||
  331. X               (mtmp->minvent && rn2((int) edog->apport)))
  332. X                appr = 1;
  333. X        }
  334. X        /* if you have dog food it'll follow you more closely */
  335. X        if (appr == 0) {
  336. X            obj = invent;
  337. X            while (obj) {
  338. X                if(dogfood(mtmp, obj) == DOGFOOD) {
  339. X                    appr = 1;
  340. X                    break;
  341. X                }
  342. X                obj = obj->nobj;
  343. X            }
  344. X        }
  345. X    } else
  346. X        appr = 1;    /* gtyp != UNDEF */
  347. X    if(mtmp->mconf)
  348. X        appr = 0;
  349. X
  350. X#define FARAWAY (COLNO + 2)        /* position outside screen */
  351. X    if (gx == u.ux && gy == u.uy && !in_masters_sight) {
  352. X        register coord *cp;
  353. X
  354. X        cp = gettrack(omx,omy);
  355. X        if (cp) {
  356. X        gx = cp->x;
  357. X        gy = cp->y;
  358. X        if(edog) edog->ogoal.x = 0;
  359. X        } else {
  360. X        /* assume master hasn't moved far, and reuse previous goal */
  361. X        if(edog && edog->ogoal.x &&
  362. X           ((edog->ogoal.x != omx) || (edog->ogoal.y != omy))) {
  363. X            gx = edog->ogoal.x;
  364. X            gy = edog->ogoal.y;
  365. X            edog->ogoal.x = 0;
  366. X        } else {
  367. X            int fardist = FARAWAY * FARAWAY;
  368. X            gx = gy = FARAWAY; /* random */
  369. X            do_clear_area(omx, omy, 9, wantdoor,
  370. X                  (genericptr_t)&fardist);
  371. X
  372. X            /* here gx == FARAWAY e.g. when dog is in a vault */
  373. X            if (gx == FARAWAY || (gx == omx && gy == omy)) {
  374. X            gx = u.ux;
  375. X            gy = u.uy;
  376. X            } else if(edog) {
  377. X            edog->ogoal.x = gx;
  378. X            edog->ogoal.y = gy;
  379. X            }
  380. X        }
  381. X        }
  382. X    } else if(edog) {
  383. X        edog->ogoal.x = 0;
  384. X    }
  385. X    return appr;
  386. X}
  387. X
  388. X/* return 0 (no move), 1 (move) or 2 (dead) */
  389. Xint
  390. Xdog_move(mtmp, after)
  391. Xregister struct monst *mtmp;
  392. Xregister int after;    /* this is extra fast monster movement */
  393. X{
  394. X    int omx, omy;        /* original mtmp position */
  395. X    int appr, whappr, udist;
  396. X    int i, j;
  397. X    register struct edog *edog = EDOG(mtmp);
  398. X    struct obj *obj = (struct obj *) 0;
  399. X    xchar otyp;
  400. X    boolean has_edog, cursemsg = FALSE, do_eat = FALSE;
  401. X    xchar nix, niy;        /* position mtmp is (considering) moving to */
  402. X    register int nx, ny;    /* temporary coordinates */
  403. X    xchar cnt, uncursedcnt, chcnt;
  404. X    int chi = -1, nidist, ndist;
  405. X    coord poss[9];
  406. X    long info[9], allowflags;
  407. X#define GDIST(x,y) (dist2(x,y,gx,gy))
  408. X
  409. X    /*
  410. X     * Tame Angels have isminion set and an ispriest structure instead of
  411. X     * an edog structure.  Fortunately, guardian Angels need not worry
  412. X     * about mundane things like eating and fetching objects, and can
  413. X     * spend all their energy defending the player.  (They are the only
  414. X     * monsters with other structures that can be tame.)
  415. X     */
  416. X    has_edog = !mtmp->isminion;
  417. X
  418. X    omx = mtmp->mx;
  419. X    omy = mtmp->my;
  420. X    if (has_edog && dog_hunger(mtmp, edog)) return(2);    /* starved */
  421. X
  422. X    udist = distu(omx,omy);
  423. X    /* maybe we tamed him while being swallowed --jgm */
  424. X    if (!udist) return(0);
  425. X
  426. X    nix = omx;    /* set before newdogpos */
  427. X    niy = omy;
  428. X
  429. X    if (has_edog && dog_invent(mtmp, edog, udist))    /* eating something */
  430. X        goto newdogpos;
  431. X
  432. X    if (has_edog)
  433. X        whappr = (moves - edog->whistletime < 5);
  434. X    else
  435. X        whappr = 0;
  436. X
  437. X    appr = dog_goal(mtmp, has_edog ? edog : (struct edog *)0,
  438. X                            after, udist, whappr);
  439. X    if (appr == -2) return(0);
  440. X
  441. X    allowflags = ALLOW_M | ALLOW_TRAPS | ALLOW_SSM | ALLOW_SANCT;
  442. X    if (passes_walls(mtmp->data)) allowflags |= (ALLOW_ROCK|ALLOW_WALL);
  443. X    if (throws_rocks(mtmp->data)) allowflags |= ALLOW_ROCK;
  444. X    if (Conflict && !resist(mtmp, RING_CLASS, 0, 0)) {
  445. X        allowflags |= ALLOW_U;
  446. X        if (!has_edog) {
  447. X        coord mm;
  448. X        /* Guardian angel refuses to be conflicted; rather,
  449. X         * it disappears, angrily, and sends in some nasties
  450. X         */
  451. X        if (canseemon(mtmp) || sensemon(mtmp)) {
  452. X            pline("%s rebukes you, saying:", Monnam(mtmp));
  453. X            verbalize("Since you desire conflict, have some more!");
  454. X        }
  455. X        mongone(mtmp);
  456. X        i = rnd(4);
  457. X        while(i--) {
  458. X            mm.x = u.ux;
  459. X            mm.y = u.uy;
  460. X            if(enexto(&mm, mm.x, mm.y, &mons[PM_ANGEL]))
  461. X            (void) mk_roamer(&mons[PM_ANGEL], u.ualign.type,
  462. X                     mm.x, mm.y, FALSE);
  463. X        }
  464. X        return(2);
  465. X
  466. X        }
  467. X    }
  468. X    if (!nohands(mtmp->data) && !verysmall(mtmp->data)) {
  469. X        allowflags |= OPENDOOR;
  470. X        if (m_carrying(mtmp, SKELETON_KEY)) allowflags |= BUSTDOOR;
  471. X    }
  472. X    if (is_giant(mtmp->data)) allowflags |= BUSTDOOR;
  473. X    if (tunnels(mtmp->data) && !needspick(mtmp->data))
  474. X        allowflags |= ALLOW_DIG;
  475. X    cnt = mfndpos(mtmp, poss, info, allowflags);
  476. X
  477. X    /* Normally dogs don't step on cursed items, but if they have no
  478. X     * other choice they will.  This requires checking ahead of time
  479. X     * to see how many cursed item squares are around.
  480. X     */
  481. X    uncursedcnt = 0;
  482. X    for (i = 0; i < cnt; i++) {
  483. X        nx = poss[i].x; ny = poss[i].y;
  484. X        if (MON_AT(nx,ny)) continue;
  485. X        for (obj = level.objects[nx][ny]; obj; obj = obj->nexthere)
  486. X            if (obj->cursed) goto skipu;
  487. X        uncursedcnt++;
  488. Xskipu:;
  489. X    }
  490. X
  491. X    chcnt = 0;
  492. X    chi = -1;
  493. X    nidist = GDIST(nix,niy);
  494. X
  495. X    for (i = 0; i < cnt; i++) {
  496. X        nx = poss[i].x;
  497. X        ny = poss[i].y;
  498. X#ifdef WALKIES
  499. X        /* if leashed, we drag him along. */
  500. X        if (mtmp->mleashed && distu(nx, ny) > 4) continue;
  501. X#endif
  502. X        /* if a guardian, try to stay close by choice */
  503. X        if (!has_edog &&
  504. X            (j = distu(nx, ny)) > 16 && j >= udist) continue;
  505. X
  506. X        if ((info[i] & ALLOW_M) && MON_AT(nx, ny)) {
  507. X            int stat;
  508. X            register struct monst *mtmp2 = m_at(nx,ny);
  509. X
  510. X            if ((int)mtmp2->m_lev >= (int)mtmp->m_lev+2 ||
  511. X            (mtmp2->data == &mons[PM_FLOATING_EYE] && rn2(10) &&
  512. X             mtmp->mcansee && haseyes(mtmp->data) && mtmp2->mcansee
  513. X             && (perceives(mtmp->data) || !mtmp2->minvis)) ||
  514. X            (mtmp2->data==&mons[PM_GELATINOUS_CUBE] && rn2(10)) ||
  515. X            (max_passive_dmg(mtmp2, mtmp) >= mtmp->mhp) ||
  516. X            (mtmp->mhp*4 < mtmp->mhpmax &&
  517. X             mtmp2->mpeaceful && !Conflict) ||
  518. X               (mtmp2->data->mlet == S_COCKATRICE &&
  519. X                !resists_ston(mtmp->data)))
  520. X            continue;
  521. X
  522. X            if (after) return(0); /* hit only once each move */
  523. X
  524. X            stat = mattackm(mtmp, mtmp2);
  525. X
  526. X            /* aggressor (pet) died */
  527. X            if (stat & MM_AGR_DIED) return 2;
  528. X
  529. X            if ((stat & MM_HIT) && !(stat & MM_DEF_DIED) &&
  530. X            rn2(4) && mtmp2->mlstmv != monstermoves) {
  531. X            stat = mattackm(mtmp2, mtmp);    /* return attack */
  532. X            if (stat & MM_DEF_DIED) return 2;
  533. X            }
  534. X
  535. X            return 0;
  536. X        }
  537. X
  538. X        {   /* dog avoids traps, but perhaps it has to pass a trap
  539. X             * in order to follow player
  540. X             */
  541. X            struct trap *trap;
  542. X
  543. X            if ((info[i] & ALLOW_TRAPS) && (trap = t_at(nx,ny))) {
  544. X            if ((trap->ttyp == RUST_TRAP
  545. X                    && mtmp->data != &mons[PM_IRON_GOLEM])
  546. X                || trap->ttyp == STATUE_TRAP
  547. X                || ((trap->ttyp == PIT
  548. X                    || trap->ttyp == SPIKED_PIT
  549. X                    || (trap->ttyp == TRAPDOOR &&
  550. X                    !Can_fall_thru(&u.uz)))
  551. X                    && (is_flyer(mtmp->data) ||
  552. X                    is_clinger(mtmp->data)))
  553. X                || (trap->ttyp == SLP_GAS_TRAP &&
  554. X                    resists_sleep(mtmp->data)))
  555. X                if(!trap->tseen || rn2(3)) continue;
  556. X#ifdef WALKIES
  557. X            if (!mtmp->mleashed) {
  558. X#endif
  559. X                if (!trap->tseen && rn2(40)) continue;
  560. X                if (rn2(10)) continue;
  561. X#ifdef WALKIES
  562. X            }
  563. X# ifdef SOUNDS
  564. X            else if (flags.soundok)
  565. X                whimper(mtmp);
  566. X# endif
  567. X#endif
  568. X            }
  569. X        }
  570. X
  571. X        /* dog eschews cursed objects, but likes dog food */
  572. X        for (obj = level.objects[nx][ny]; obj; obj = obj->nexthere) {
  573. X            if (obj->cursed && !mtmp->mleashed && uncursedcnt)
  574. X            goto nxti;
  575. X            if (obj->cursed) cursemsg = TRUE;
  576. X            if (has_edog && (otyp = dogfood(mtmp, obj)) < MANFOOD &&
  577. X                (otyp < ACCFOOD || edog->hungrytime <= moves)){
  578. X            /* Note: our dog likes the food so much that he
  579. X             * might eat it even when it conceals a cursed object */
  580. X            nix = nx;
  581. X            niy = ny;
  582. X            chi = i;
  583. X            do_eat = TRUE;
  584. X            goto newdogpos;
  585. X            }
  586. X        }
  587. X
  588. X        for (j = 0; j < MTSZ && j < cnt-1; j++)
  589. X            if (nx == mtmp->mtrack[j].x && ny == mtmp->mtrack[j].y)
  590. X                if (rn2(4*(cnt-j))) goto nxti;
  591. X
  592. X        j = ((ndist = GDIST(nx,ny)) - nidist) * appr;
  593. X        if ((j == 0 && !rn2(++chcnt)) || j < 0 ||
  594. X            (j > 0 && !whappr &&
  595. X                ((omx == nix && omy == niy && !rn2(3))
  596. X                    || !rn2(12))
  597. X            )) {
  598. X            nix = nx;
  599. X            niy = ny;
  600. X            nidist = ndist;
  601. X            if(j < 0) chcnt = 0;
  602. X            chi = i;
  603. X        }
  604. X    nxti:    ;
  605. X    }
  606. Xnewdogpos:
  607. X    if (nix != omx || niy != omy) {
  608. X        if (info[chi] & ALLOW_U) {
  609. X#ifdef WALKIES
  610. X            if (mtmp->mleashed) { /* play it safe */
  611. X                pline("%s breaks loose of %s leash!",
  612. X                    Monnam(mtmp),
  613. X                    humanoid(mtmp->data)
  614. X                        ? (mtmp->female ? "her" : "his")
  615. X                        : "its");
  616. X                m_unleash(mtmp);
  617. X            }
  618. X#endif
  619. X            (void) mattacku(mtmp);
  620. X            return(0);
  621. X        }
  622. X        /* insert a worm_move() if worms ever begin to eat things */
  623. X        remove_monster(omx, omy);
  624. X        place_monster(mtmp, nix, niy);
  625. X        if (cursemsg && (cansee(omx,omy) || cansee(nix,niy)))
  626. X            pline("%s moves only reluctantly.", Monnam(mtmp));
  627. X        for (j=MTSZ-1; j>0; j--) mtmp->mtrack[j] = mtmp->mtrack[j-1];
  628. X        mtmp->mtrack[0].x = omx;
  629. X        mtmp->mtrack[0].y = omy;
  630. X        /* We have to know if the pet's gonna do a combined eat and
  631. X         * move before moving it, but it can't eat until after being
  632. X         * moved.  Thus the do_eat flag.
  633. X         */
  634. X        if (do_eat)
  635. X            dog_eat(mtmp, obj, nix, niy);
  636. X    }
  637. X#ifdef WALKIES
  638. X      /* an incredible kludge, but the only way to keep pooch near
  639. X       * after it spends time eating or in a trap, etc.
  640. X       */
  641. X      else if (mtmp->mleashed && distu(omx, omy) > 4) {
  642. X        coord cc;
  643. X
  644. X        nx = sgn(omx - u.ux);
  645. X        ny = sgn(omy - u.uy);
  646. X        cc.x = u.ux + nx;
  647. X        cc.y = u.uy + ny;
  648. X        if (goodpos(cc.x, cc.y, mtmp, mtmp->data)) goto dognext;
  649. X
  650. X         i  = xytod(nx, ny);
  651. X        for (j = (i + 7)%8; j < (i + 1)%8; j++) {
  652. X            dtoxy(&cc, j);
  653. X            if (goodpos(cc.x, cc.y, mtmp, mtmp->data)) goto dognext;
  654. X        }
  655. X        for (j = (i + 6)%8; j < (i + 2)%8; j++) {
  656. X            dtoxy(&cc, j);
  657. X            if (goodpos(cc.x, cc.y, mtmp, mtmp->data)) goto dognext;
  658. X        }
  659. X        cc.x = mtmp->mx;
  660. X        cc.y = mtmp->my;
  661. Xdognext:
  662. X        remove_monster(mtmp->mx, mtmp->my);
  663. X        place_monster(mtmp, cc.x, cc.y);
  664. X        newsym(cc.x,cc.y);
  665. X        set_apparxy(mtmp);
  666. X    }
  667. X#endif
  668. X    return(1);
  669. X}
  670. X
  671. X#endif /* OVL0 */
  672. X#ifdef OVLB
  673. X
  674. X/*ARGSUSED*/    /* do_clear_area client */
  675. XSTATIC_PTR void
  676. Xwantdoor(x, y, distance)
  677. Xint x, y;
  678. Xgenericptr_t distance;
  679. X{
  680. X    register ndist;
  681. X
  682. X    if (*(int*)distance > (ndist = distu(x, y))) {
  683. X    gx = x;
  684. X    gy = y;
  685. X    *(int*)distance = ndist;
  686. X    }
  687. X}
  688. X
  689. X#endif /* OVLB */
  690. X
  691. X/*dogmove.c*/
  692. END_OF_FILE
  693. if test 17769 -ne `wc -c <'src/dogmove.c'`; then
  694.     echo shar: \"'src/dogmove.c'\" unpacked with wrong size!
  695. fi
  696. # end of 'src/dogmove.c'
  697. fi
  698. if test -f 'util/lev_comp.y' -a "${1}" != "-c" ; then 
  699.   echo shar: Will not clobber existing file \"'util/lev_comp.y'\"
  700. else
  701. echo shar: Extracting \"'util/lev_comp.y'\" \(35847 characters\)
  702. sed "s/^X//" >'util/lev_comp.y' <<'END_OF_FILE'
  703. X%{
  704. X/*    SCCS Id: @(#)lev_comp.c    3.1    92/07/12    */
  705. X/*    Copyright (c) 1989 by Jean-Christophe Collet */
  706. X/* NetHack may be freely redistributed.  See license for details. */
  707. X
  708. X/*
  709. X * This file contains the Level Compiler code
  710. X * It may handle special mazes & special room-levels
  711. X */
  712. X
  713. X/* In case we're using bison in AIX.  This definition must be
  714. X * placed before any other C-language construct in the file
  715. X * excluding comments and preprocessor directives (thanks IBM
  716. X * for this wonderful feature...).
  717. X *
  718. X * Note: some cpps barf on this 'undefined control' (#pragma).
  719. X * Addition of the leading space seems to prevent barfage for now,
  720. X * and AIX will still see the directive in its non-standard locale.
  721. X */
  722. X
  723. X#ifdef _AIX
  724. X #pragma alloca        /* keep leading space! */
  725. X#endif
  726. X
  727. X#include "hack.h"
  728. X#include "sp_lev.h"
  729. X#ifndef O_WRONLY
  730. X# include <fcntl.h>
  731. X#endif
  732. X#ifndef O_CREAT    /* some older BSD systems do not define O_CREAT in <fcntl.h> */
  733. X# include <sys/file.h>
  734. X#endif
  735. X#ifndef O_BINARY    /* used for micros, no-op for others */
  736. X# define O_BINARY 0
  737. X#endif
  738. X
  739. X#ifdef MICRO
  740. X# define OMASK FCMASK
  741. X#else
  742. X# define OMASK 0644
  743. X#endif
  744. X
  745. X#define MAX_REGISTERS    10
  746. X#define ERR        (-1)
  747. X
  748. X#define New(type)        (type *) alloc(sizeof(type))
  749. X#define NewTab(type, size)    (type **) alloc(sizeof(type *) * size)
  750. X
  751. X#ifdef MICRO
  752. X# undef exit
  753. Xextern void FDECL(exit, (int));
  754. X#endif
  755. X
  756. Xextern void FDECL(yyerror, (char *));
  757. Xextern void FDECL(yywarning, (char *));
  758. Xextern int NDECL(yylex);
  759. Xint NDECL(yyparse);
  760. X
  761. Xextern char *FDECL(dup_string,(char *));
  762. Xextern int FDECL(get_floor_type, (CHAR_P));
  763. Xextern int FDECL(get_room_type, (char *));
  764. Xextern int FDECL(get_trap_type, (char *));
  765. Xextern int FDECL(get_monster_id, (char *, CHAR_P));
  766. Xextern int FDECL(get_object_id, (char *));
  767. Xextern boolean FDECL(check_monster_char, (CHAR_P));
  768. Xextern boolean FDECL(check_object_char, (CHAR_P));
  769. Xextern char FDECL(what_map_char, (CHAR_P));
  770. Xextern void FDECL(scan_map, (char *));
  771. Xextern void NDECL(wallify_map);
  772. Xextern boolean NDECL(check_subrooms);
  773. Xextern void FDECL(check_coord, (int, int, char *));
  774. Xextern void NDECL(store_part);
  775. Xextern void NDECL(store_room);
  776. Xextern void FDECL(write_maze, (int, specialmaze *));
  777. Xextern void FDECL(write_lev, (int, splev *));
  778. Xextern void FDECL(free_rooms, (room **, int));
  779. X
  780. Xstatic struct reg {
  781. X    int x1, y1;
  782. X    int x2, y2;
  783. X}        current_region;
  784. X
  785. Xstatic struct coord {
  786. X    int x;
  787. X    int y;
  788. X}        current_coord, current_align;
  789. X
  790. Xstatic struct size {
  791. X    int height;
  792. X    int width;
  793. X}        current_size;
  794. X
  795. Xchar tmpmessage[256];
  796. Xaltar *tmpaltar[256];
  797. Xlad *tmplad[256];
  798. Xstair *tmpstair[256];
  799. Xdigpos *tmpdig[256];
  800. Xchar *tmpmap[ROWNO];
  801. Xregion *tmpreg[256];
  802. Xlev_region *tmplreg[32];
  803. Xdoor *tmpdoor[256];
  804. Xroom_door *tmprdoor[256];
  805. Xtrap *tmptrap[256];
  806. Xmonster *tmpmonst[256];
  807. Xobject *tmpobj[256];
  808. Xdrawbridge *tmpdb[256];
  809. Xwalk *tmpwalk[256];
  810. Xgold *tmpgold[256];
  811. Xfountain *tmpfountain[256];
  812. Xsink *tmpsink[256];
  813. Xpool *tmppool[256];
  814. Xengraving *tmpengraving[256];
  815. Xmazepart *tmppart[10];
  816. Xroom *tmproom[MAXNROFROOMS*2];
  817. Xcorridor *tmpcor[256];
  818. X
  819. Xstatic specialmaze maze;
  820. Xstatic splev special_lev;
  821. Xstatic lev_init init_lev;
  822. X
  823. Xstatic char olist[MAX_REGISTERS], mlist[MAX_REGISTERS];
  824. Xstatic struct coord plist[MAX_REGISTERS];
  825. X
  826. Xint n_olist = 0, n_mlist = 0, n_plist = 0;
  827. X
  828. Xunsigned int nlreg = 0, nreg = 0, ndoor = 0, ntrap = 0, nmons = 0, nobj = 0;
  829. Xunsigned int ndb = 0, nwalk = 0, npart = 0, ndig = 0, nlad = 0, nstair = 0;
  830. Xunsigned int naltar = 0, ncorridor = 0, nrooms = 0, ngold = 0, nengraving = 0;
  831. Xunsigned int nfountain = 0, npool = 0, nsink = 0;
  832. X
  833. Xstatic unsigned long lev_flags = 0;
  834. X
  835. Xunsigned int max_x_map, max_y_map;
  836. X
  837. Xstatic xchar in_room;
  838. X
  839. Xextern int fatal_error;
  840. Xextern int want_warnings;
  841. Xextern char* fname;
  842. X
  843. X%}
  844. X
  845. X%union
  846. X{
  847. X    int    i;
  848. X    char*    map;
  849. X    struct {
  850. X        xchar room;
  851. X        xchar wall;
  852. X        xchar door;
  853. X    } corpos;
  854. X}
  855. X
  856. X
  857. X%token    <i> CHAR INTEGER BOOLEAN
  858. X%token    <i> MESSAGE_ID MAZE_ID LEVEL_ID LEV_INIT_ID GEOMETRY_ID NOMAP_ID
  859. X%token    <i> OBJECT_ID MONSTER_ID TRAP_ID DOOR_ID DRAWBRIDGE_ID
  860. X%token    <i> MAZEWALK_ID WALLIFY_ID REGION_ID FILLING
  861. X%token    <i> RANDOM_OBJECTS_ID RANDOM_MONSTERS_ID RANDOM_PLACES_ID
  862. X%token    <i> ALTAR_ID LADDER_ID STAIR_ID NON_DIGGABLE_ID ROOM_ID
  863. X%token    <i> PORTAL_ID TELEPRT_ID BRANCH_ID LEV CHANCE_ID
  864. X%token    <i> CORRIDOR_ID GOLD_ID ENGRAVING_ID FOUNTAIN_ID POOL_ID SINK_ID NONE
  865. X%token    <i> RAND_CORRIDOR_ID DOOR_STATE LIGHT_STATE CURSE_TYPE ENGRAVING_TYPE
  866. X%token    <i> DIRECTION RANDOM_TYPE O_REGISTER M_REGISTER P_REGISTER A_REGISTER
  867. X%token    <i> ALIGNMENT LEFT_OR_RIGHT CENTER TOP_OR_BOT ALTAR_TYPE UP_OR_DOWN
  868. X%token    <i> SUBROOM_ID NAME_ID FLAGS_ID FLAG_TYPE MON_ATTITUDE MON_ALERTNESS
  869. X%token    <i> MON_APPEARANCE
  870. X%token    <i> ',' ':' '(' ')' '[' ']'
  871. X%token    <map> STRING MAP_ID
  872. X%type    <i> h_justif v_justif trap_name room_type door_state light_state
  873. X%type    <i> alignment altar_type a_register roomfill filling door_pos
  874. X%type    <i> door_wall walled secret curse_state enchantment amount
  875. X%type    <i> engraving_type flags flag_list prefilled lev_region lev_init
  876. X%type    <i> monster monster_c m_register object object_c o_register
  877. X%type    <map> string maze_def level_def m_name o_name art_name
  878. X%type    <corpos> corr_spec
  879. X%start    file
  880. X
  881. X%%
  882. Xfile        : /* nothing */
  883. X        | levels
  884. X        ;
  885. X
  886. Xlevels        : level
  887. X        | level levels
  888. X        ;
  889. X
  890. Xlevel        : maze_level
  891. X        | room_level
  892. X        ;
  893. X
  894. Xmaze_level    : maze_def flags lev_init messages regions
  895. X          {
  896. X              int fout, i;
  897. X
  898. X            if (fatal_error > 0) {
  899. X                fprintf(stderr,
  900. X                  "%s : %d errors detected. No output created!\n",
  901. X                    fname, fatal_error);
  902. X            } else {
  903. X                char lbuf[20];
  904. X                Strcpy(lbuf, $1);
  905. X                Strcat(lbuf, LEV_EXT);
  906. X#ifdef MAC_THINKC5
  907. X                fout = open(lbuf, O_WRONLY|O_CREAT|O_BINARY);
  908. X#else
  909. X                fout = open(lbuf, O_WRONLY|O_CREAT|O_BINARY, OMASK);
  910. X#endif
  911. X                if (fout < 0) {
  912. X                    yyerror("Can't open output file!!");
  913. X                    exit(1);
  914. X                }
  915. X                maze.flags = $2;
  916. X                memcpy(&(maze.init_lev), &(init_lev),
  917. X                       sizeof(lev_init));
  918. X                maze.numpart = npart;
  919. X                maze.parts = NewTab(mazepart, npart);
  920. X                for(i=0;i<npart;i++)
  921. X                    maze.parts[i] = tmppart[i];
  922. X                write_maze(fout, &maze);
  923. X                (void) close(fout);
  924. X                npart = 0;
  925. X            }
  926. X          }
  927. X        ;
  928. X
  929. Xroom_level    : level_def flags lev_init messages rreg_init rooms corridors_def
  930. X          {
  931. X            int fout, i;
  932. X
  933. X            if (fatal_error > 0) {
  934. X                fprintf(stderr,
  935. X                  "%s : %d errors detected. No output created!\n",
  936. X                    fname, fatal_error);
  937. X            } else {
  938. X                char lbuf[20];
  939. X                Strcpy(lbuf, $1);
  940. X                Strcat(lbuf, LEV_EXT);
  941. X#ifdef MAC_THINKC5
  942. X                fout = open(lbuf, O_WRONLY|O_CREAT|O_BINARY);
  943. X#else
  944. X                fout = open(lbuf, O_WRONLY|O_CREAT|O_BINARY, OMASK);
  945. X#endif
  946. X                if (fout < 0) {
  947. X                    yyerror("Can't open output file!!");
  948. X                    exit(1);
  949. X                }
  950. X                special_lev.flags = $2;
  951. X                memcpy(&(special_lev.init_lev), &(init_lev),
  952. X                       sizeof(lev_init));
  953. X                special_lev.nroom = nrooms;
  954. X                special_lev.rooms = NewTab(room, nrooms);
  955. X                for(i=0; i<nrooms; i++)
  956. X                    special_lev.rooms[i] = tmproom[i];
  957. X                special_lev.ncorr = ncorridor;
  958. X                special_lev.corrs = NewTab(corridor, ncorridor);
  959. X                for(i=0; i<ncorridor; i++)
  960. X                    special_lev.corrs[i] = tmpcor[i];
  961. X                if (check_subrooms())
  962. X                    write_lev(fout, &special_lev);
  963. X                free_rooms(special_lev.rooms,special_lev.nroom);
  964. X                nrooms = 0;
  965. X                ncorridor = 0;
  966. X                (void) close(fout);
  967. X            }
  968. X          }
  969. X        ;
  970. X
  971. Xlevel_def    : LEVEL_ID ':' string
  972. X          {
  973. X            if (index($3, '.'))
  974. X                yyerror("Invalid dot ('.') in level name.");
  975. X            if (strlen($3) > 8)
  976. X                yyerror("Level names limited to 8 characters.");
  977. X            $$ = $3;
  978. X            special_lev.nrobjects = 0;
  979. X            special_lev.nrmonst = 0;
  980. X          }
  981. X        ;
  982. X
  983. Xlev_init    : /* nothing */
  984. X          {
  985. X            init_lev.init_present = FALSE;
  986. X            $$ = 0;
  987. X          }
  988. X        | LEV_INIT_ID ':' CHAR ',' CHAR ',' BOOLEAN ',' BOOLEAN ',' light_state ',' walled
  989. X          {
  990. X            init_lev.init_present = TRUE;
  991. X            if((init_lev.fg = what_map_char($3)) == INVALID_TYPE)
  992. X                yyerror("Invalid foreground type.");
  993. X            if((init_lev.bg = what_map_char($5)) == INVALID_TYPE)
  994. X                yyerror("Invalid background type.");
  995. X            init_lev.smoothed = $7;
  996. X            init_lev.joined = $9;
  997. X            init_lev.lit = $11;
  998. X            init_lev.walled = $13;
  999. X            $$ = 1;
  1000. X          }
  1001. X        ;
  1002. X
  1003. Xwalled        : BOOLEAN
  1004. X        | RANDOM_TYPE
  1005. X        ;
  1006. X
  1007. Xflags        : /* nothing */
  1008. X          {
  1009. X            $$ = 0;
  1010. X          }
  1011. X        | FLAGS_ID ':' flag_list
  1012. X          {
  1013. X            $$ = lev_flags;
  1014. X          }
  1015. X        ;
  1016. X
  1017. Xflag_list    : FLAG_TYPE
  1018. X          {
  1019. X            lev_flags |= $1;
  1020. X          }
  1021. X        | FLAG_TYPE ',' flag_list
  1022. X          {
  1023. X            lev_flags |= $3;
  1024. X          }
  1025. X        ;
  1026. X
  1027. Xmessages    : /* nothing */
  1028. X        | message messages
  1029. X        ;
  1030. X
  1031. Xmessage        : MESSAGE_ID ':' STRING
  1032. X          {
  1033. X            int i, j;
  1034. X
  1035. X            i = strlen($3) + 1;
  1036. X            j = tmpmessage[0] ? strlen(tmpmessage) : 0;
  1037. X            if(i+j > 255) {
  1038. X               yyerror("Message string too long (>256 characters)");
  1039. X            } else {
  1040. X                if(j) tmpmessage[j++] = '\n';
  1041. X                strncpy(tmpmessage+j, $3, i-1);
  1042. X                tmpmessage[j+i-1] = 0;
  1043. X            }
  1044. X          }
  1045. X        ;
  1046. X
  1047. Xrreg_init    : /* nothing */
  1048. X        | rreg_init init_rreg
  1049. X        ;
  1050. X
  1051. Xinit_rreg    : RANDOM_OBJECTS_ID ':' object_list
  1052. X          {
  1053. X            if(special_lev.nrobjects) {
  1054. X                yyerror("Object registers already initialized!");
  1055. X            } else {
  1056. X                special_lev.nrobjects = n_olist;
  1057. X                special_lev.robjects = (char *) alloc(n_olist);
  1058. X                (void) memcpy((genericptr_t)special_lev.robjects,
  1059. X                      (genericptr_t)olist, n_olist);
  1060. X            }
  1061. X          }
  1062. X        | RANDOM_MONSTERS_ID ':' monster_list
  1063. X          {
  1064. X            if(special_lev.nrmonst) {
  1065. X                yyerror("Monster registers already initialized!");
  1066. X            } else {
  1067. X                special_lev.nrmonst = n_mlist;
  1068. X                special_lev.rmonst = (char *) alloc(n_mlist);
  1069. X                (void) memcpy((genericptr_t)special_lev.rmonst,
  1070. X                      (genericptr_t)mlist, n_mlist);
  1071. X              }
  1072. X          }
  1073. X        ;
  1074. X
  1075. Xrooms        : /* Nothing  -  dummy room for use with INIT_MAP */
  1076. X          {
  1077. X            tmproom[nrooms] = New(room);
  1078. X            (void) memset((genericptr_t) tmproom[nrooms], 0,
  1079. X                    sizeof *tmproom[nrooms]);
  1080. X            tmproom[nrooms]->name = (char *) 0;
  1081. X            tmproom[nrooms]->parent = (char *) 0;
  1082. X            tmproom[nrooms]->rtype = 0;
  1083. X            tmproom[nrooms]->rlit = 0;
  1084. X            tmproom[nrooms]->xalign = ERR;
  1085. X            tmproom[nrooms]->yalign = ERR;
  1086. X            tmproom[nrooms]->x = 0;
  1087. X            tmproom[nrooms]->y = 0;
  1088. X            tmproom[nrooms]->w = 2;
  1089. X            tmproom[nrooms]->h = 2;
  1090. X            in_room = 1;
  1091. X          }
  1092. X        | roomlist
  1093. X        ;
  1094. X
  1095. Xroomlist    : aroom
  1096. X        | aroom roomlist
  1097. X        ;
  1098. X
  1099. Xcorridors_def    : random_corridors
  1100. X        | corridors
  1101. X        ;
  1102. X
  1103. Xrandom_corridors: RAND_CORRIDOR_ID
  1104. X          {
  1105. X            tmpcor[0] = New(corridor);
  1106. X            tmpcor[0]->src.room = -1;
  1107. X            ncorridor = 1;
  1108. X          }
  1109. X        ;
  1110. X
  1111. Xcorridors    : /* nothing */
  1112. X        | corridors corridor
  1113. X        ;
  1114. X
  1115. Xcorridor    : CORRIDOR_ID ':' corr_spec ',' corr_spec
  1116. X          {
  1117. X            tmpcor[ncorridor] = New(corridor);
  1118. X            tmpcor[ncorridor]->src.room = $3.room;
  1119. X            tmpcor[ncorridor]->src.wall = $3.wall;
  1120. X            tmpcor[ncorridor]->src.door = $3.door;
  1121. X            tmpcor[ncorridor]->dest.room = $5.room;
  1122. X            tmpcor[ncorridor]->dest.wall = $5.wall;
  1123. X            tmpcor[ncorridor]->dest.door = $5.door;
  1124. X            ncorridor++;
  1125. X          }
  1126. X        | CORRIDOR_ID ':' corr_spec ',' INTEGER
  1127. X          {
  1128. X            tmpcor[ncorridor]->src.room = $3.room;
  1129. X            tmpcor[ncorridor]->src.wall = $3.wall;
  1130. X            tmpcor[ncorridor]->src.door = $3.door;
  1131. X            tmpcor[ncorridor]->dest.room = -1;
  1132. X            tmpcor[ncorridor]->dest.wall = $5;
  1133. X            ncorridor++;
  1134. X          }
  1135. X        ;
  1136. X
  1137. Xcorr_spec    : '(' INTEGER ',' DIRECTION ',' door_pos ')'
  1138. X          {
  1139. X            if ($2 >= nrooms)
  1140. X                yyerror("Wrong room number!");
  1141. X            $$.room = $2;
  1142. X            $$.wall = $4;
  1143. X            $$.door = $6;
  1144. X          }
  1145. X        ;
  1146. X
  1147. Xaroom        : room_def room_details
  1148. X          {
  1149. X            store_room();
  1150. X          }
  1151. X        | subroom_def room_details
  1152. X          {
  1153. X            store_room();
  1154. X          }
  1155. X        ;
  1156. X
  1157. Xsubroom_def    : SUBROOM_ID ':' room_type ',' light_state ',' subroom_pos ',' room_size ',' string roomfill
  1158. X          {
  1159. X            tmproom[nrooms] = New(room);
  1160. X            (void) memset((genericptr_t) tmproom[nrooms], 0,
  1161. X                    sizeof *tmproom[nrooms]);
  1162. X            tmproom[nrooms]->parent = dup_string($11);
  1163. X            tmproom[nrooms]->name = (char *) 0;
  1164. X            tmproom[nrooms]->rtype = $3;
  1165. X            tmproom[nrooms]->rlit = $5;
  1166. X            tmproom[nrooms]->filled = $12;
  1167. X            tmproom[nrooms]->xalign = ERR;
  1168. X            tmproom[nrooms]->yalign = ERR;
  1169. X            tmproom[nrooms]->x = current_coord.x;
  1170. X            tmproom[nrooms]->y = current_coord.y;
  1171. X            tmproom[nrooms]->w = current_size.width;
  1172. X            tmproom[nrooms]->h = current_size.height;
  1173. X            in_room = 1;
  1174. X          }
  1175. X        ;
  1176. X
  1177. Xroom_def    : ROOM_ID ':' room_type ',' light_state ',' room_pos ',' room_align ',' room_size roomfill
  1178. X          {
  1179. X            tmproom[nrooms] = New(room);
  1180. X            (void) memset((genericptr_t) tmproom[nrooms], 0,
  1181. X                    sizeof *tmproom[nrooms]);
  1182. X            tmproom[nrooms]->name = (char *) 0;
  1183. X            tmproom[nrooms]->parent = (char *) 0;
  1184. X            tmproom[nrooms]->rtype = $3;
  1185. X            tmproom[nrooms]->rlit = $5;
  1186. X            tmproom[nrooms]->filled = $12;
  1187. X            tmproom[nrooms]->xalign = current_align.x;
  1188. X            tmproom[nrooms]->yalign = current_align.y;
  1189. X            tmproom[nrooms]->x = current_coord.x;
  1190. X            tmproom[nrooms]->y = current_coord.y;
  1191. X            tmproom[nrooms]->w = current_size.width;
  1192. X            tmproom[nrooms]->h = current_size.height;
  1193. X            in_room = 1;
  1194. X          }
  1195. X        ;
  1196. X
  1197. Xroomfill    : /* nothing */
  1198. X          {
  1199. X            $$ = 1;
  1200. X          }
  1201. X        | ',' BOOLEAN
  1202. X          {
  1203. X            $$ = $2;
  1204. X          }
  1205. X        ;
  1206. X
  1207. Xroom_pos    : '(' INTEGER ',' INTEGER ')'
  1208. X          {
  1209. X            if ( $2 < 1 || $2 > 5 ||
  1210. X                $4 < 1 || $4 > 5 ) {
  1211. X                yyerror("Room position should be between 1 & 5!");
  1212. X            } else {
  1213. X                current_coord.x = $2;
  1214. X                current_coord.y = $4;
  1215. X            }
  1216. X          }
  1217. X        | RANDOM_TYPE
  1218. X          {
  1219. X            current_coord.x = current_coord.y = ERR;
  1220. X          }
  1221. X        ;
  1222. X
  1223. Xsubroom_pos    : '(' INTEGER ',' INTEGER ')'
  1224. X          {
  1225. X            if ( $2 < 0 || $4 < 0) {
  1226. X                yyerror("Invalid subroom position !");
  1227. X            } else {
  1228. X                current_coord.x = $2;
  1229. X                current_coord.y = $4;
  1230. X            }
  1231. X          }
  1232. X        | RANDOM_TYPE
  1233. X          {
  1234. X            current_coord.x = current_coord.y = ERR;
  1235. X          }
  1236. X        ;
  1237. X
  1238. Xroom_align    : '(' h_justif ',' v_justif ')'
  1239. X          {
  1240. X            current_align.x = $2;
  1241. X            current_align.y = $4;
  1242. X          }
  1243. X        | RANDOM_TYPE
  1244. X          {
  1245. X            current_align.x = current_align.y = ERR;
  1246. X          }
  1247. X        ;
  1248. X
  1249. Xroom_size    : '(' INTEGER ',' INTEGER ')'
  1250. X          {
  1251. X            current_size.width = $2;
  1252. X            current_size.height = $4;
  1253. X          }
  1254. X        | RANDOM_TYPE
  1255. X          {
  1256. X            current_size.height = current_size.width = ERR;
  1257. X          }
  1258. X        ;
  1259. X
  1260. Xroom_details    : /* nothing */
  1261. X        | room_details room_detail
  1262. X        ;
  1263. X
  1264. Xroom_detail    : room_name
  1265. X        | room_chance
  1266. X        | room_door
  1267. X        | monster_detail
  1268. X        | object_detail
  1269. X        | trap_detail
  1270. X        | altar_detail
  1271. X        | fountain_detail
  1272. X        | sink_detail
  1273. X        | pool_detail
  1274. X        | gold_detail
  1275. X        | engraving_detail
  1276. X        | stair_detail
  1277. X        ;
  1278. X
  1279. Xroom_name    : NAME_ID ':' string
  1280. X          {
  1281. X            if (tmproom[nrooms]->name)
  1282. X                yyerror("This room already has a name!");
  1283. X            else
  1284. X                tmproom[nrooms]->name = dup_string($3);
  1285. X          }
  1286. X        ;
  1287. X
  1288. Xroom_chance    : CHANCE_ID ':' INTEGER
  1289. X           {
  1290. X            if (tmproom[nrooms]->chance)
  1291. X                yyerror("This room already assigned a chance!");
  1292. X            else if (tmproom[nrooms]->rtype == OROOM)
  1293. X                yyerror("Only typed rooms can have a chance!");
  1294. X            else if ($3 < 1 || $3 > 99)
  1295. X                yyerror("The chance is supposed to be precentile.");
  1296. X            else
  1297. X                tmproom[nrooms]->chance = $3;
  1298. X           }
  1299. X        ;
  1300. X
  1301. Xroom_door    : DOOR_ID ':' secret ',' door_state ',' door_wall ',' door_pos
  1302. X          {
  1303. X            /* ERR means random here */
  1304. X            if ($7 == ERR && $9 != ERR) {
  1305. X             yyerror("If the door wall is random, so must be its pos!");
  1306. X            } else {
  1307. X                tmprdoor[ndoor] = New(room_door);
  1308. X                tmprdoor[ndoor]->secret = $3;
  1309. X                tmprdoor[ndoor]->mask = $5;
  1310. X                tmprdoor[ndoor]->wall = $7;
  1311. X                tmprdoor[ndoor]->pos = $9;
  1312. X                ndoor++;
  1313. X            }
  1314. X          }
  1315. X        ;
  1316. X
  1317. Xsecret        : BOOLEAN
  1318. X        | RANDOM_TYPE
  1319. X        ;
  1320. X
  1321. Xdoor_wall    : DIRECTION
  1322. X        | RANDOM_TYPE
  1323. X        ;
  1324. X
  1325. Xdoor_pos    : INTEGER
  1326. X        | RANDOM_TYPE
  1327. X        ;
  1328. X
  1329. Xmaze_def    : MAZE_ID ':' string ',' filling
  1330. X          {
  1331. X            maze.filling = $5;
  1332. X            if (index($3, '.'))
  1333. X                yyerror("Invalid dot ('.') in level name.");
  1334. X            if (strlen($3) > 8)
  1335. X                yyerror("Level names limited to 8 characters.");
  1336. X            $$ = $3;
  1337. X            in_room = 0;
  1338. X          }
  1339. X        ;
  1340. X
  1341. Xfilling        : CHAR
  1342. X          {
  1343. X            $$ = get_floor_type((char)$1);
  1344. X          }
  1345. X        | RANDOM_TYPE
  1346. X          {
  1347. X            $$ = -1;
  1348. X          }
  1349. X        ;
  1350. X
  1351. Xregions        : aregion
  1352. X        | aregion regions
  1353. X        ;
  1354. X
  1355. Xaregion        : map_definition reg_init map_details
  1356. X          {
  1357. X            store_part();
  1358. X          }
  1359. X        ;
  1360. X
  1361. Xmap_definition    : NOMAP_ID
  1362. X          {
  1363. X            tmppart[npart] = New(mazepart);
  1364. X            tmppart[npart]->halign = 1;
  1365. X            tmppart[npart]->valign = 1;
  1366. X            tmppart[npart]->nrobjects = 0;
  1367. X            tmppart[npart]->nloc = 0;
  1368. X            tmppart[npart]->nrmonst = 0;
  1369. X            tmppart[npart]->xsize = 1;
  1370. X            tmppart[npart]->ysize = 1;
  1371. X            tmppart[npart]->map = (char **) alloc(sizeof(char *));
  1372. X            tmppart[npart]->map[0] = (char *) alloc(1);
  1373. X            tmppart[npart]->map[0][0] = STONE;
  1374. X            max_x_map = COLNO-1;
  1375. X            max_y_map = ROWNO;
  1376. X          }
  1377. X        | map_geometry MAP_ID
  1378. X          {
  1379. X            tmppart[npart] = New(mazepart);
  1380. X            tmppart[npart]->halign = $<i>1 % 10;
  1381. X            tmppart[npart]->valign = $<i>1 / 10;
  1382. X            tmppart[npart]->nrobjects = 0;
  1383. X            tmppart[npart]->nloc = 0;
  1384. X            tmppart[npart]->nrmonst = 0;
  1385. X            scan_map($2);
  1386. X          }
  1387. X        ;
  1388. X
  1389. Xmap_geometry    : GEOMETRY_ID ':' h_justif ',' v_justif
  1390. X          {
  1391. X            $<i>$ = $<i>3 + ($<i>5 * 10);
  1392. X          }
  1393. X        ;
  1394. X
  1395. Xh_justif    : LEFT_OR_RIGHT
  1396. X        | CENTER
  1397. X        ;
  1398. X
  1399. Xv_justif    : TOP_OR_BOT
  1400. X        | CENTER
  1401. X        ;
  1402. X
  1403. Xreg_init    : /* nothing */
  1404. X        | reg_init init_reg
  1405. X        ;
  1406. X
  1407. Xinit_reg    : RANDOM_OBJECTS_ID ':' object_list
  1408. X          {
  1409. X            if (tmppart[npart]->nrobjects) {
  1410. X                yyerror("Object registers already initialized!");
  1411. X            } else {
  1412. X                tmppart[npart]->robjects = (char *)alloc(n_olist);
  1413. X                (void) memcpy((genericptr_t)tmppart[npart]->robjects,
  1414. X                      (genericptr_t)olist, n_olist);
  1415. X                tmppart[npart]->nrobjects = n_olist;
  1416. X            }
  1417. X          }
  1418. X        | RANDOM_PLACES_ID ':' place_list
  1419. X          {
  1420. X            if (tmppart[npart]->nloc) {
  1421. X                yyerror("Location registers already initialized!");
  1422. X            } else {
  1423. X                register int i;
  1424. X                tmppart[npart]->rloc_x = (char *) alloc(n_plist);
  1425. X                tmppart[npart]->rloc_y = (char *) alloc(n_plist);
  1426. X                for(i=0;i<n_plist;i++) {
  1427. X                tmppart[npart]->rloc_x[i] = plist[i].x;
  1428. X                tmppart[npart]->rloc_y[i] = plist[i].y;
  1429. X                }
  1430. X                tmppart[npart]->nloc = n_plist;
  1431. X            }
  1432. X          }
  1433. X        | RANDOM_MONSTERS_ID ':' monster_list
  1434. X          {
  1435. X            if (tmppart[npart]->nrmonst) {
  1436. X                yyerror("Monster registers already initialized!");
  1437. X            } else {
  1438. X                tmppart[npart]->rmonst = (char *) alloc(n_mlist);
  1439. X                (void) memcpy((genericptr_t)tmppart[npart]->rmonst,
  1440. X                      (genericptr_t)mlist, n_mlist);
  1441. X                tmppart[npart]->nrmonst = n_mlist;
  1442. X            }
  1443. X          }
  1444. X        ;
  1445. X
  1446. Xobject_list    : object
  1447. X          {
  1448. X            if (n_olist < MAX_REGISTERS)
  1449. X                olist[n_olist++] = $<i>1;
  1450. X            else
  1451. X                yyerror("Object list too long!");
  1452. X          }
  1453. X        | object ',' object_list
  1454. X          {
  1455. X            if (n_olist < MAX_REGISTERS)
  1456. X                olist[n_olist++] = $<i>1;
  1457. X            else
  1458. X                yyerror("Object list too long!");
  1459. X          }
  1460. X        ;
  1461. X
  1462. Xmonster_list    : monster
  1463. X          {
  1464. X            if (n_mlist < MAX_REGISTERS)
  1465. X                mlist[n_mlist++] = $<i>1;
  1466. X            else
  1467. X                yyerror("Monster list too long!");
  1468. X          }
  1469. X        | monster ',' monster_list
  1470. X          {
  1471. X            if (n_mlist < MAX_REGISTERS)
  1472. X                mlist[n_mlist++] = $<i>1;
  1473. X            else
  1474. X                yyerror("Monster list too long!");
  1475. X          }
  1476. X        ;
  1477. X
  1478. Xplace_list    : place
  1479. X          {
  1480. X            if (n_plist < MAX_REGISTERS)
  1481. X                plist[n_plist++] = current_coord;
  1482. X            else
  1483. X                yyerror("Location list too long!");
  1484. X          }
  1485. X        | place
  1486. X          {
  1487. X            if (n_plist < MAX_REGISTERS)
  1488. X                plist[n_plist++] = current_coord;
  1489. X            else
  1490. X                yyerror("Location list too long!");
  1491. X          }
  1492. X         ',' place_list
  1493. X        ;
  1494. X
  1495. Xmap_details    : /* nothing */
  1496. X        | map_details map_detail
  1497. X        ;
  1498. X
  1499. Xmap_detail    : monster_detail
  1500. X        | object_detail
  1501. X        | door_detail
  1502. X        | trap_detail
  1503. X        | drawbridge_detail
  1504. X        | region_detail
  1505. X        | stair_region
  1506. X        | portal_region
  1507. X        | teleprt_region
  1508. X        | branch_region
  1509. X        | altar_detail
  1510. X        | fountain_detail
  1511. X        | mazewalk_detail
  1512. X        | wallify_detail
  1513. X        | ladder_detail
  1514. X        | stair_detail
  1515. X        | gold_detail
  1516. X        | engraving_detail
  1517. X        | diggable_detail
  1518. X        ;
  1519. X
  1520. Xmonster_detail    : MONSTER_ID ':' monster_c ',' m_name ',' coordinate
  1521. X          {
  1522. X            tmpmonst[nmons] = New(monster);
  1523. X            tmpmonst[nmons]->x = current_coord.x;
  1524. X            tmpmonst[nmons]->y = current_coord.y;
  1525. X            tmpmonst[nmons]->class = $<i>3;
  1526. X            tmpmonst[nmons]->peaceful = -1; /* no override */
  1527. X            tmpmonst[nmons]->asleep = -1;
  1528. X            tmpmonst[nmons]->align = - MAX_REGISTERS - 2;
  1529. X            tmpmonst[nmons]->name = (char *) 0;
  1530. X            tmpmonst[nmons]->appear = 0;
  1531. X            tmpmonst[nmons]->appear_as = (char *) 0;
  1532. X            if (!in_room)
  1533. X                check_coord(current_coord.x, current_coord.y,
  1534. X                    "Monster");
  1535. X            if (!$5)
  1536. X                tmpmonst[nmons]->id = -1;
  1537. X            else {
  1538. X                int token = get_monster_id($5, (char) $<i>3);
  1539. X                if (token == ERR) {
  1540. X                    yywarning("Illegal monster name!  Making random monster.");
  1541. X                    tmpmonst[nmons]->id = -1;
  1542. X                } else
  1543. X                    tmpmonst[nmons]->id = token;
  1544. X            }
  1545. X          }
  1546. X         monster_infos
  1547. X          {
  1548. X            nmons++;
  1549. X          }
  1550. X        ;
  1551. X
  1552. Xmonster_infos    : /* nothing */
  1553. X        | monster_infos monster_info
  1554. X        ;
  1555. X
  1556. Xmonster_info    : ',' string
  1557. X          {
  1558. X            tmpmonst[nmons]->name = dup_string($2);
  1559. X          }
  1560. X        | ',' MON_ATTITUDE
  1561. X          {
  1562. X            tmpmonst[nmons]->peaceful = $<i>2;
  1563. X          }
  1564. X        | ',' MON_ALERTNESS
  1565. X          {
  1566. X            tmpmonst[nmons]->asleep = $<i>2;
  1567. X          }
  1568. X        | ',' alignment
  1569. X          {
  1570. X            tmpmonst[nmons]->align = $<i>2;
  1571. X          }
  1572. X        | ',' MON_APPEARANCE string
  1573. X          {
  1574. X            tmpmonst[nmons]->appear = $<i>2;
  1575. X            tmpmonst[nmons]->appear_as = dup_string($3);
  1576. X          }
  1577. X        ;
  1578. X
  1579. Xobject_detail    : OBJECT_ID ':' object_c ',' o_name ',' coordinate
  1580. X          {
  1581. X            tmpobj[nobj] = New(object);
  1582. X            tmpobj[nobj]->x = current_coord.x;
  1583. X            tmpobj[nobj]->y = current_coord.y;
  1584. X            tmpobj[nobj]->class = $<i>3;
  1585. X            tmpobj[nobj]->corpsenm = -1;    /* init as none */
  1586. X            tmpobj[nobj]->curse_state = -1;
  1587. X            tmpobj[nobj]->name = (char *) 0;
  1588. X            if (!in_room)
  1589. X                check_coord(current_coord.x, current_coord.y,
  1590. X                    "Object");
  1591. X            if (!$5)
  1592. X                tmpobj[nobj]->id = -1;
  1593. X            else {
  1594. X                int token = get_object_id($5);
  1595. X                if (token == ERR) {
  1596. X                    yywarning("Illegal object name!  Making random object.");
  1597. X                    tmpobj[nobj]->id = -1;
  1598. X                } else
  1599. X                    tmpobj[nobj]->id = token;
  1600. X            }
  1601. X          }
  1602. X         object_infos
  1603. X          {
  1604. X            nobj++;
  1605. X          }
  1606. X        ;
  1607. X
  1608. Xobject_infos    : /* nothing */
  1609. X          {
  1610. X            tmpobj[nobj]->spe = -127;
  1611. X          }
  1612. X        | ',' STRING ',' enchantment
  1613. X          {
  1614. X            int token = get_monster_id($2, (char)0);
  1615. X            if (token == ERR)    /* "random" */
  1616. X                tmpobj[nobj]->corpsenm = -2;
  1617. X            else
  1618. X                tmpobj[nobj]->corpsenm = token;
  1619. X            tmpobj[nobj]->spe = $<i>4;
  1620. X          }
  1621. X        | ',' curse_state ',' enchantment ',' art_name
  1622. X          {
  1623. X            tmpobj[nobj]->curse_state = $<i>2;
  1624. X            tmpobj[nobj]->spe = $<i>4;
  1625. X            if ($6)
  1626. X                tmpobj[nobj]->name = dup_string($6);
  1627. X            else
  1628. X                tmpobj[nobj]->name = (char *) 0;
  1629. X          }
  1630. X        ;
  1631. X
  1632. Xcurse_state    : RANDOM_TYPE
  1633. X        | CURSE_TYPE
  1634. X        ;
  1635. X
  1636. Xenchantment    : INTEGER
  1637. X        | RANDOM_TYPE
  1638. X          {
  1639. X            $<i>$ = -127;
  1640. X          }
  1641. X        ;
  1642. X
  1643. Xdoor_detail    : DOOR_ID ':' door_state ',' coordinate
  1644. X          {
  1645. X            tmpdoor[ndoor] = New(door);
  1646. X            tmpdoor[ndoor]->x = current_coord.x;
  1647. X            tmpdoor[ndoor]->y = current_coord.y;
  1648. X            tmpdoor[ndoor]->mask = $<i>3;
  1649. X            if(current_coord.x >= 0 && current_coord.y >= 0 &&
  1650. X               tmpmap[current_coord.y][current_coord.x] != DOOR &&
  1651. X               tmpmap[current_coord.y][current_coord.x] != SDOOR)
  1652. X                yyerror("Door decl doesn't match the map");
  1653. X            ndoor++;
  1654. X          }
  1655. X        ;
  1656. X
  1657. Xtrap_detail    : TRAP_ID ':' trap_name ',' coordinate
  1658. X          {
  1659. X            tmptrap[ntrap] = New(trap);
  1660. X            tmptrap[ntrap]->x = current_coord.x;
  1661. X            tmptrap[ntrap]->y = current_coord.y;
  1662. X            tmptrap[ntrap]->type = $<i>3;
  1663. X            if (!in_room)
  1664. X                check_coord(current_coord.x, current_coord.y,
  1665. X                    "Trap");
  1666. X            ntrap++;
  1667. X          }
  1668. X        ;
  1669. X
  1670. Xdrawbridge_detail: DRAWBRIDGE_ID ':' coordinate ',' DIRECTION ',' door_state
  1671. X           {
  1672. X                int x, y, dir;
  1673. X
  1674. X            tmpdb[ndb] = New(drawbridge);
  1675. X            x = tmpdb[ndb]->x = current_coord.x;
  1676. X            y = tmpdb[ndb]->y = current_coord.y;
  1677. X            /* convert dir from a DIRECTION to a DB_DIR */
  1678. X            dir = $5;
  1679. X            switch(dir) {
  1680. X            case W_NORTH: dir = DB_NORTH; y--; break;
  1681. X            case W_SOUTH: dir = DB_SOUTH; y++; break;
  1682. X            case W_EAST:  dir = DB_EAST;  x++; break;
  1683. X            case W_WEST:  dir = DB_WEST;  x--; break;
  1684. X            default:
  1685. X                yyerror("Invalid drawbridge direction");
  1686. X                break;
  1687. X            }
  1688. X            tmpdb[ndb]->dir = dir;
  1689. X            if (current_coord.x >= 0 && current_coord.y >= 0 &&
  1690. X                !IS_WALL(tmpmap[y][x])) {
  1691. X                char ebuf[60];
  1692. X                Sprintf(ebuf,
  1693. X                    "Wall needed for drawbridge (%02d, %02d)",
  1694. X                    current_coord.x, current_coord.y);
  1695. X                yyerror(ebuf);
  1696. X            }
  1697. X
  1698. X            if ( $<i>7 == D_ISOPEN )
  1699. X                tmpdb[ndb]->db_open = 1;
  1700. X            else if ( $<i>7 == D_CLOSED )
  1701. X                tmpdb[ndb]->db_open = 0;
  1702. X            else
  1703. X                yyerror("A drawbridge can only be open or closed!");
  1704. X            ndb++;
  1705. X           }
  1706. X        ;
  1707. X
  1708. Xmazewalk_detail : MAZEWALK_ID ':' coordinate ',' DIRECTION
  1709. X          {
  1710. X            tmpwalk[nwalk] = New(walk);
  1711. X            tmpwalk[nwalk]->x = current_coord.x;
  1712. X            tmpwalk[nwalk]->y = current_coord.y;
  1713. X            tmpwalk[nwalk]->dir = $5;
  1714. X            nwalk++;
  1715. X          }
  1716. X        ;
  1717. X
  1718. Xwallify_detail    : WALLIFY_ID
  1719. X          {
  1720. X            wallify_map();
  1721. X          }
  1722. X        ;
  1723. X
  1724. Xladder_detail    : LADDER_ID ':' coordinate ',' UP_OR_DOWN
  1725. X          {
  1726. X            tmplad[nlad] = New(lad);
  1727. X            tmplad[nlad]->x = current_coord.x;
  1728. X            tmplad[nlad]->y = current_coord.y;
  1729. X            tmplad[nlad]->up = $<i>5;
  1730. X            if (!in_room)
  1731. X                check_coord(current_coord.x, current_coord.y,
  1732. X                    "Ladder");
  1733. X            nlad++;
  1734. X          }
  1735. X        ;
  1736. X
  1737. Xstair_detail    : STAIR_ID ':' coordinate ',' UP_OR_DOWN
  1738. X          {
  1739. X            tmpstair[nstair] = New(stair);
  1740. X            tmpstair[nstair]->x = current_coord.x;
  1741. X            tmpstair[nstair]->y = current_coord.y;
  1742. X            tmpstair[nstair]->up = $<i>5;
  1743. X            if (!in_room)
  1744. X                check_coord(current_coord.x, current_coord.y,
  1745. X                    "Stairway");
  1746. X            nstair++;
  1747. X          }
  1748. X        ;
  1749. X
  1750. Xstair_region    : STAIR_ID ':' lev_region
  1751. X          {
  1752. X            tmplreg[nlreg] = New(lev_region);
  1753. X            tmplreg[nlreg]->in_islev = $3;
  1754. X            tmplreg[nlreg]->inarea.x1 = current_region.x1;
  1755. X            tmplreg[nlreg]->inarea.y1 = current_region.y1;
  1756. X            tmplreg[nlreg]->inarea.x2 = current_region.x2;
  1757. X            tmplreg[nlreg]->inarea.y2 = current_region.y2;
  1758. X          }
  1759. X         ',' lev_region ',' UP_OR_DOWN
  1760. X          {
  1761. X            tmplreg[nlreg]->del_islev = $6;
  1762. X            tmplreg[nlreg]->delarea.x1 = current_region.x1;
  1763. X            tmplreg[nlreg]->delarea.y1 = current_region.y1;
  1764. X            tmplreg[nlreg]->delarea.x2 = current_region.x2;
  1765. X            tmplreg[nlreg]->delarea.y2 = current_region.y2;
  1766. X            if($8)
  1767. X                tmplreg[nlreg]->rtype = LR_UPSTAIR;
  1768. X            else
  1769. X                tmplreg[nlreg]->rtype = LR_DOWNSTAIR;
  1770. X            tmplreg[nlreg]->rname = 0;
  1771. X            nlreg++;
  1772. X          }
  1773. X        ;
  1774. X
  1775. Xportal_region    : PORTAL_ID ':' lev_region
  1776. X          {
  1777. X            tmplreg[nlreg] = New(lev_region);
  1778. X            tmplreg[nlreg]->in_islev = $3;
  1779. X            tmplreg[nlreg]->inarea.x1 = current_region.x1;
  1780. X            tmplreg[nlreg]->inarea.y1 = current_region.y1;
  1781. X            tmplreg[nlreg]->inarea.x2 = current_region.x2;
  1782. X            tmplreg[nlreg]->inarea.y2 = current_region.y2;
  1783. X          }
  1784. X         ',' lev_region ',' string
  1785. X          {
  1786. X            tmplreg[nlreg]->del_islev = $6;
  1787. X            tmplreg[nlreg]->delarea.x1 = current_region.x1;
  1788. X            tmplreg[nlreg]->delarea.y1 = current_region.y1;
  1789. X            tmplreg[nlreg]->delarea.x2 = current_region.x2;
  1790. X            tmplreg[nlreg]->delarea.y2 = current_region.y2;
  1791. X            tmplreg[nlreg]->rtype = LR_PORTAL;
  1792. X            tmplreg[nlreg]->rname = $8;
  1793. X            nlreg++;
  1794. X          }
  1795. X        ;
  1796. X
  1797. Xteleprt_region    : TELEPRT_ID ':' lev_region
  1798. X          {
  1799. X            tmplreg[nlreg] = New(lev_region);
  1800. X            tmplreg[nlreg]->in_islev = $3;
  1801. X            tmplreg[nlreg]->inarea.x1 = current_region.x1;
  1802. X            tmplreg[nlreg]->inarea.y1 = current_region.y1;
  1803. X            tmplreg[nlreg]->inarea.x2 = current_region.x2;
  1804. X            tmplreg[nlreg]->inarea.y2 = current_region.y2;
  1805. X          }
  1806. X         ',' lev_region
  1807. X          {
  1808. X            tmplreg[nlreg]->del_islev = $6;
  1809. X            tmplreg[nlreg]->delarea.x1 = current_region.x1;
  1810. X            tmplreg[nlreg]->delarea.y1 = current_region.y1;
  1811. X            tmplreg[nlreg]->delarea.x2 = current_region.x2;
  1812. X            tmplreg[nlreg]->delarea.y2 = current_region.y2;
  1813. X          }
  1814. X        teleprt_detail
  1815. X          {
  1816. X            switch($<i>8) {
  1817. X            case -1: tmplreg[nlreg]->rtype = LR_TELE; break;
  1818. X            case 0: tmplreg[nlreg]->rtype = LR_DOWNTELE; break;
  1819. X            case 1: tmplreg[nlreg]->rtype = LR_UPTELE; break;
  1820. X            }
  1821. X            tmplreg[nlreg]->rname = 0;
  1822. X            nlreg++;
  1823. X          }
  1824. X        ;
  1825. X
  1826. Xbranch_region    : BRANCH_ID ':' lev_region
  1827. X          {
  1828. X            tmplreg[nlreg] = New(lev_region);
  1829. X            tmplreg[nlreg]->in_islev = $3;
  1830. X            tmplreg[nlreg]->inarea.x1 = current_region.x1;
  1831. X            tmplreg[nlreg]->inarea.y1 = current_region.y1;
  1832. X            tmplreg[nlreg]->inarea.x2 = current_region.x2;
  1833. X            tmplreg[nlreg]->inarea.y2 = current_region.y2;
  1834. X          }
  1835. X         ',' lev_region
  1836. X          {
  1837. X            tmplreg[nlreg]->del_islev = $6;
  1838. X            tmplreg[nlreg]->delarea.x1 = current_region.x1;
  1839. X            tmplreg[nlreg]->delarea.y1 = current_region.y1;
  1840. X            tmplreg[nlreg]->delarea.x2 = current_region.x2;
  1841. X            tmplreg[nlreg]->delarea.y2 = current_region.y2;
  1842. X            tmplreg[nlreg]->rtype = LR_BRANCH;
  1843. X            tmplreg[nlreg]->rname = 0;
  1844. X            nlreg++;
  1845. X          }
  1846. X        ;
  1847. X
  1848. Xteleprt_detail    : /* empty */
  1849. X          {
  1850. X            $<i>$ = -1;
  1851. X          }
  1852. X        | ',' UP_OR_DOWN
  1853. X          {
  1854. X            $<i>$ = $2;
  1855. X          }
  1856. X        ;
  1857. X
  1858. Xlev_region    : region
  1859. X          {
  1860. X            $$ = 0;
  1861. X          }
  1862. X        | LEV '(' INTEGER ',' INTEGER ',' INTEGER ',' INTEGER ')'
  1863. X          {
  1864. X/* This series of if statements is a hack for MSC 5.1.  It seems that its
  1865. X   tiny little brain cannot compile if these are all one big if statement. */
  1866. X            if ($3 <= 0 || $3 >= COLNO)
  1867. X                yyerror("Region out of level range!");
  1868. X            else if ($5 < 0 || $5 >= ROWNO)
  1869. X                yyerror("Region out of level range!");
  1870. X            else if ($7 <= 0 || $7 >= COLNO)
  1871. X                yyerror("Region out of level range!");
  1872. X            else if ($9 < 0 || $9 >= ROWNO)
  1873. X                yyerror("Region out of level range!");
  1874. X            current_region.x1 = $3;
  1875. X            current_region.y1 = $5;
  1876. X            current_region.x2 = $7;
  1877. X            current_region.y2 = $9;
  1878. X            $$ = 1;
  1879. X          }
  1880. X        ;
  1881. X
  1882. Xfountain_detail : FOUNTAIN_ID ':' coordinate
  1883. X          {
  1884. X            tmpfountain[nfountain] = New(fountain);
  1885. X            tmpfountain[nfountain]->x = current_coord.x;
  1886. X            tmpfountain[nfountain]->y = current_coord.y;
  1887. X            if (!in_room)
  1888. X                check_coord(current_coord.x, current_coord.y,
  1889. X                    "Fountain");
  1890. X            nfountain++;
  1891. X          }
  1892. X        ;
  1893. X
  1894. Xsink_detail : SINK_ID ':' coordinate
  1895. X          {
  1896. X            tmpsink[nsink] = New(sink);
  1897. X            tmpsink[nsink]->x = current_coord.x;
  1898. X            tmpsink[nsink]->y = current_coord.y;
  1899. X            nsink++;
  1900. X          }
  1901. X        ;
  1902. X
  1903. Xpool_detail : POOL_ID ':' coordinate
  1904. X          {
  1905. X            tmppool[npool] = New(pool);
  1906. X            tmppool[npool]->x = current_coord.x;
  1907. X            tmppool[npool]->y = current_coord.y;
  1908. X            npool++;
  1909. X          }
  1910. X        ;
  1911. X
  1912. Xdiggable_detail : NON_DIGGABLE_ID ':' region
  1913. X          {
  1914. X            tmpdig[ndig] = New(digpos);
  1915. X            tmpdig[ndig]->x1 = current_region.x1;
  1916. X            tmpdig[ndig]->y1 = current_region.y1;
  1917. X            tmpdig[ndig]->x2 = current_region.x2;
  1918. X            tmpdig[ndig]->y2 = current_region.y2;
  1919. X            ndig++;
  1920. X          }
  1921. X        ;
  1922. X
  1923. Xregion_detail    : REGION_ID ':' region ',' light_state ',' room_type prefilled
  1924. X          {
  1925. X            tmpreg[nreg] = New(region);
  1926. X            tmpreg[nreg]->x1 = current_region.x1;
  1927. X            tmpreg[nreg]->y1 = current_region.y1;
  1928. X            tmpreg[nreg]->x2 = current_region.x2;
  1929. X            tmpreg[nreg]->y2 = current_region.y2;
  1930. X            tmpreg[nreg]->rlit = $<i>5;
  1931. X            tmpreg[nreg]->rtype = $<i>7;
  1932. X            if($<i>8 & 1) tmpreg[nreg]->rtype += MAXRTYPE+1;
  1933. X            tmpreg[nreg]->rirreg = (($<i>8 & 2) != 0);
  1934. X            if(current_region.x1 > current_region.x2 ||
  1935. X               current_region.y1 > current_region.y2)
  1936. X               yyerror("Region start > end!");
  1937. X            if(tmpreg[nreg]->rtype == VAULT &&
  1938. X               (tmpreg[nreg]->rirreg ||
  1939. X                (tmpreg[nreg]->x2 - tmpreg[nreg]->x1 != 1) ||
  1940. X                (tmpreg[nreg]->y2 - tmpreg[nreg]->y1 != 1)))
  1941. X                yyerror("Vaults must be exactly 2x2!");
  1942. X            if(want_warnings && !tmpreg[nreg]->rirreg &&
  1943. X               current_region.x1 > 0 && current_region.y1 > 0 &&
  1944. X               current_region.x2 < max_x_map &&
  1945. X               current_region.y2 < max_y_map) {
  1946. X                /* check for walls in the room */
  1947. X                char ebuf[60];
  1948. X                register int x, y, nrock = 0;
  1949. X
  1950. X                for(y=current_region.y1; y<=current_region.y2; y++)
  1951. X                for(x=current_region.x1;
  1952. X                    x<=current_region.x2; x++)
  1953. X                    if(IS_ROCK(tmpmap[y][x]) ||
  1954. X                       IS_DOOR(tmpmap[y][x])) nrock++;
  1955. X                if(nrock) {
  1956. X                Sprintf(ebuf,
  1957. X                    "Rock in room (%02d,%02d,%02d,%02d)?!",
  1958. X                    current_region.x1, current_region.y1,
  1959. X                    current_region.x2, current_region.y2);
  1960. X                yywarning(ebuf);
  1961. X                }
  1962. X                if (
  1963. X        !IS_ROCK(tmpmap[current_region.y1-1][current_region.x1-1]) ||
  1964. X        !IS_ROCK(tmpmap[current_region.y2+1][current_region.x1-1]) ||
  1965. X        !IS_ROCK(tmpmap[current_region.y1-1][current_region.x2+1]) ||
  1966. X        !IS_ROCK(tmpmap[current_region.y2+1][current_region.x2+1])) {
  1967. X                Sprintf(ebuf,
  1968. X                "NonRock edge in room (%02d,%02d,%02d,%02d)?!",
  1969. X                    current_region.x1, current_region.y1,
  1970. X                    current_region.x2, current_region.y2);
  1971. X                yywarning(ebuf);
  1972. X                }
  1973. X            } else if(tmpreg[nreg]->rirreg &&
  1974. X        !IS_ROOM(tmpmap[current_region.y1][current_region.x1])) {
  1975. X                char ebuf[60];
  1976. X                Sprintf(ebuf,
  1977. X                    "Rock in irregular room (%02d,%02d)?!",
  1978. X                    current_region.x1, current_region.y1);
  1979. X                yyerror(ebuf);
  1980. X            }
  1981. X            nreg++;
  1982. X          }
  1983. X        ;
  1984. X
  1985. Xaltar_detail    : ALTAR_ID ':' coordinate ',' alignment ',' altar_type
  1986. X          {
  1987. X            tmpaltar[naltar] = New(altar);
  1988. X            tmpaltar[naltar]->x = current_coord.x;
  1989. X            tmpaltar[naltar]->y = current_coord.y;
  1990. X            tmpaltar[naltar]->align = $<i>5;
  1991. X            tmpaltar[naltar]->shrine = $<i>7;
  1992. X            if (!in_room)
  1993. X                check_coord(current_coord.x, current_coord.y,
  1994. X                    "Altar");
  1995. X            naltar++;
  1996. X          }
  1997. X        ;
  1998. X
  1999. Xgold_detail    : GOLD_ID ':' amount ',' coordinate
  2000. X          {
  2001. X            tmpgold[ngold] = New(gold);
  2002. X            tmpgold[ngold]->x = current_coord.x;
  2003. X            tmpgold[ngold]->y = current_coord.y;
  2004. X            tmpgold[ngold]->amount = $<i>3;
  2005. X            if (!in_room)
  2006. X                check_coord(current_coord.x, current_coord.y,
  2007. X                    "Gold");
  2008. X            ngold++;
  2009. X          }
  2010. X        ;
  2011. X
  2012. Xengraving_detail: ENGRAVING_ID ':' coordinate ',' engraving_type ',' string
  2013. X          {
  2014. X            tmpengraving[nengraving] = New(engraving);
  2015. X            tmpengraving[nengraving]->x = current_coord.x;
  2016. X            tmpengraving[nengraving]->y = current_coord.y;
  2017. X            tmpengraving[nengraving]->e.text = $7;
  2018. X            tmpengraving[nengraving]->etype = $<i>5;
  2019. X            if (!in_room)
  2020. X                check_coord(current_coord.x, current_coord.y,
  2021. X                    "Engraving");
  2022. X            nengraving++;
  2023. X          }
  2024. X        ;
  2025. X
  2026. Xmonster_c    : monster
  2027. X        | RANDOM_TYPE
  2028. X          {
  2029. X            $<i>$ = - MAX_REGISTERS - 1;
  2030. X          }
  2031. X        | m_register
  2032. X        ;
  2033. X
  2034. Xobject_c    : object
  2035. X        | RANDOM_TYPE
  2036. X          {
  2037. X            $<i>$ = - MAX_REGISTERS - 1;
  2038. X          }
  2039. X        | o_register
  2040. X        ;
  2041. X
  2042. Xm_name        : string
  2043. X        | RANDOM_TYPE
  2044. X          {
  2045. X            $$ = (char *) 0;
  2046. X          }
  2047. X        ;
  2048. X
  2049. Xo_name        : string
  2050. X        | RANDOM_TYPE
  2051. X          {
  2052. X            $$ = (char *) 0;
  2053. X          }
  2054. X        ;
  2055. X
  2056. Xtrap_name    : string
  2057. X          {
  2058. X            int token = get_trap_type($1);
  2059. X            if (token == ERR)
  2060. X                yyerror("Unknown trap type!");
  2061. X            $<i>$ = token;
  2062. X          }
  2063. X        | RANDOM_TYPE
  2064. X        ;
  2065. X
  2066. Xroom_type    : string
  2067. X          {
  2068. X            int token = get_room_type($1);
  2069. X            if (token == ERR) {
  2070. X                yywarning("Unknown room type!  Making ordinary room...");
  2071. X                $<i>$ = OROOM;
  2072. X            } else
  2073. X                $<i>$ = token;
  2074. X          }
  2075. X        | RANDOM_TYPE
  2076. X        ;
  2077. X
  2078. Xprefilled    : /* empty */
  2079. X          {
  2080. X            $<i>$ = 0;
  2081. X          }
  2082. X        | ',' FILLING
  2083. X          {
  2084. X            $<i>$ = $2;
  2085. X          }
  2086. X        | ',' FILLING ',' BOOLEAN
  2087. X          {
  2088. X            $<i>$ = $2 + ($4 << 1);
  2089. X          }
  2090. X        ;
  2091. X
  2092. Xcoordinate    : coord
  2093. X        | p_register
  2094. X        | RANDOM_TYPE
  2095. X          {
  2096. X            current_coord.x = current_coord.y = -MAX_REGISTERS-1;
  2097. X          }
  2098. X        ;
  2099. X
  2100. Xdoor_state    : DOOR_STATE
  2101. X        | RANDOM_TYPE
  2102. X        ;
  2103. X
  2104. Xlight_state    : LIGHT_STATE
  2105. X        | RANDOM_TYPE
  2106. X        ;
  2107. X
  2108. Xalignment    : ALIGNMENT
  2109. X        | a_register
  2110. X        | RANDOM_TYPE
  2111. X          {
  2112. X            $<i>$ = - MAX_REGISTERS - 1;
  2113. X          }
  2114. X        ;
  2115. X
  2116. Xaltar_type    : ALTAR_TYPE
  2117. X        | RANDOM_TYPE
  2118. X        ;
  2119. X
  2120. Xp_register    : P_REGISTER '[' INTEGER ']'
  2121. X          {
  2122. X            if ( $3 >= MAX_REGISTERS )
  2123. X                yyerror("Register Index overflow!");
  2124. X            else
  2125. X                current_coord.x = current_coord.y = - $3 - 1;
  2126. X          }
  2127. X        ;
  2128. X
  2129. Xo_register    : O_REGISTER '[' INTEGER ']'
  2130. X          {
  2131. X            if ( $3 >= MAX_REGISTERS )
  2132. X                yyerror("Register Index overflow!");
  2133. X            else
  2134. X                $<i>$ = - $3 - 1;
  2135. X          }
  2136. X        ;
  2137. X
  2138. Xm_register    : M_REGISTER '[' INTEGER ']'
  2139. X          {
  2140. X            if ( $3 >= MAX_REGISTERS )
  2141. X                yyerror("Register Index overflow!");
  2142. X            else
  2143. X                $<i>$ = - $3 - 1;
  2144. X          }
  2145. X        ;
  2146. X
  2147. Xa_register    : A_REGISTER '[' INTEGER ']'
  2148. X          {
  2149. X            if ( $3 >= 3 )
  2150. X                yyerror("Register Index overflow!");
  2151. X            else
  2152. X                $<i>$ = - $3 - 1;
  2153. X          }
  2154. X        ;
  2155. X
  2156. Xplace        : coord
  2157. X        ;
  2158. X
  2159. Xmonster        : CHAR
  2160. X          {
  2161. X            if (check_monster_char((char) $1))
  2162. X                $<i>$ = $1 ;
  2163. X            else {
  2164. X                yyerror("Unknown monster class!");
  2165. X                $<i>$ = ERR;
  2166. X            }
  2167. X          }
  2168. X        ;
  2169. X
  2170. Xobject        : CHAR
  2171. X          {
  2172. X            char c = $1;
  2173. X            if (check_object_char(c))
  2174. X                $<i>$ = c;
  2175. X            else {
  2176. X                yyerror("Unknown char class!");
  2177. X                $<i>$ = ERR;
  2178. X            }
  2179. X          }
  2180. X        ;
  2181. X
  2182. Xstring        : STRING
  2183. X        ;
  2184. X
  2185. Xart_name    : STRING
  2186. X        | NONE
  2187. X          {
  2188. X            $$ = (char *) 0;
  2189. X          }
  2190. X        ;
  2191. X
  2192. Xamount        : INTEGER
  2193. X        | RANDOM_TYPE
  2194. X        ;
  2195. X
  2196. Xengraving_type    : ENGRAVING_TYPE
  2197. X        | RANDOM_TYPE
  2198. X        ;
  2199. X
  2200. Xcoord        : '(' INTEGER ',' INTEGER ')'
  2201. X          {
  2202. X            if (!in_room && !init_lev.init_present &&
  2203. X                ($2 < 0 || $2 > max_x_map ||
  2204. X                 $4 < 0 || $4 > max_y_map))
  2205. X                yyerror("Coordinates out of map range!");
  2206. X            current_coord.x = $2;
  2207. X            current_coord.y = $4;
  2208. X          }
  2209. X        ;
  2210. X
  2211. Xregion        : '(' INTEGER ',' INTEGER ',' INTEGER ',' INTEGER ')'
  2212. X          {
  2213. X/* This series of if statements is a hack for MSC 5.1.  It seems that its
  2214. X   tiny little brain cannot compile if these are all one big if statement. */
  2215. X            if ($2 < 0 || $2 > max_x_map)
  2216. X                yyerror("Region out of map range!");
  2217. X            else if ($4 < 0 || $4 > max_y_map)
  2218. X                yyerror("Region out of map range!");
  2219. X            else if ($6 < 0 || $6 > max_x_map)
  2220. X                yyerror("Region out of map range!");
  2221. X            else if ($8 < 0 || $8 > max_y_map)
  2222. X                yyerror("Region out of map range!");
  2223. X            current_region.x1 = $2;
  2224. X            current_region.y1 = $4;
  2225. X            current_region.x2 = $6;
  2226. X            current_region.y2 = $8;
  2227. X          }
  2228. X        ;
  2229. X
  2230. X%%
  2231. END_OF_FILE
  2232. if test 35847 -ne `wc -c <'util/lev_comp.y'`; then
  2233.     echo shar: \"'util/lev_comp.y'\" unpacked with wrong size!
  2234. fi
  2235. # end of 'util/lev_comp.y'
  2236. fi
  2237. echo shar: End of archive 50 \(of 108\).
  2238. cp /dev/null ark50isdone
  2239. MISSING=""
  2240. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 \
  2241. 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 \
  2242. 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 \
  2243. 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 \
  2244. 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 \
  2245. 101 102 103 104 105 106 107 108 ; do
  2246.     if test ! -f ark${I}isdone ; then
  2247.     MISSING="${MISSING} ${I}"
  2248.     fi
  2249. done
  2250. if test "${MISSING}" = "" ; then
  2251.     echo You have unpacked all 108 archives.
  2252.     echo "Now execute 'rebuild.sh'"
  2253.     rm -f ark10[0-8]isdone ark[1-9]isdone ark[1-9][0-9]isdone
  2254. else
  2255.     echo You still need to unpack the following archives:
  2256.     echo "        " ${MISSING}
  2257. fi
  2258. ##  End of shell archive.
  2259. exit 0
  2260.