1 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
2 /* hack.mklev.c - version 1.0.3 */
3 /* $FreeBSD: src/games/hack/hack.mklev.c,v 1.6 1999/11/16 10:26:36 marcel Exp $ */
4 /* $DragonFly: src/games/hack/hack.mklev.c,v 1.4 2006/08/21 19:45:32 pavalos Exp $ */
8 #define somex() ((random()%(croom->hx-croom->lx+1))+croom->lx)
9 #define somey() ((random()%(croom->hy-croom->ly+1))+croom->ly)
11 #define XLIM 4 /* define minimum required space around a room */
13 boolean secret; /* TRUE while making a vault: increase [XY]LIM */
14 struct mkroom rooms[MAXNROFROOMS+1];
15 int smeq[MAXNROFROOMS+1];
22 xchar xdnstair, xupstair, ydnstair, yupstair;
24 /* Definitions used by makerooms() and addrs() */
25 #define MAXRS 50 /* max lth of temp rectangle table - arbitrary */
27 xchar rlx, rly, rhx, rhy;
29 int rscnt, rsmax; /* 0..rscnt-1: currently under consideration */
30 /* rscnt..rsmax: discarded */
32 static bool makerooms(void);
33 static void addrs(int, int, int, int);
34 static void addrsx(int, int, int, int, bool);
35 static int comp(const void *, const void *);
36 static coord finddpos(int, int, int, int);
37 static bool okdoor(int, int);
38 static void dodoor(int, int, struct mkroom *);
39 static void dosdoor(int, int, struct mkroom *, int);
40 static bool maker(schar, schar, schar, schar);
41 static void makecorridors(void);
42 static void join(int, int);
43 static void make_niches(void);
44 static void makevtele(void);
45 static void makeniche(bool);
50 struct mkroom *croom, *troom;
56 rooms[0].hx = -1; /* in case we are in a maze */
58 for (x = 0; x < COLNO; x++)
59 for (y = 0; y < ROWNO; y++)
62 oinit(); /* assign level dependent obj probabilities */
64 if (dlevel >= rn1(3, 26)) { /* there might be several mazes */
69 /* construct the rooms */
74 /* construct stairs (up and down in different rooms if possible) */
75 croom = &rooms[rn2(nroom)];
78 levl[xdnstair][ydnstair].scrsym = '>';
79 levl[xdnstair][ydnstair].typ = STAIRS;
82 croom = &rooms[rn2(nroom - 1)];
86 xupstair = somex(); /* %% < and > might be in the same place */
88 levl[xupstair][yupstair].scrsym = '<';
89 levl[xupstair][yupstair].typ = STAIRS;
91 /* for each room: put things inside */
92 for (croom = rooms; croom->hx > 0; croom++) {
93 /* put a sleeping monster inside */
95 * Note: monster may be on the stairs. This cannot be
96 * avoided: maybe the player fell through a trapdoor while a
97 * monster was on the stairs. Conclusion: we have to check
98 * for monsters on the stairs anyway.
101 makemon(NULL, somex(), somey());
103 /* put traps and mimics inside */
105 while (!rn2(8 - (dlevel / 6)))
107 if (!goldseen && !rn2(3))
108 mkgold(0L, somex(), somey());
110 mkobj_at(0, somex(), somey());
114 printf("tryct overflow4\n");
117 mkobj_at(0, somex(), somey());
122 qsort((char *)rooms, nroom, sizeof(struct mkroom), comp);
126 /* make a secret treasure vault, not connected to the rest */
127 if (nroom <= (2 * MAXNROFROOMS / 3))
129 troom = &rooms[nroom];
132 troom->rtype = VAULT; /* treasure vault */
133 for (x = troom->lx; x <= troom->hx; x++)
134 for (y = troom->ly; y <= troom->hy; y++)
135 mkgold((long)(rnd(dlevel *
144 if (wizard && getenv("SHOPTYPE"))
148 if (dlevel > 1 && dlevel < 20 && rn2(dlevel) < 3)
150 else if (dlevel > 6 && !rn2(7))
152 else if (dlevel > 9 && !rn2(5))
154 else if (dlevel > 11 && !rn2(6))
156 else if (dlevel > 18 && !rn2(6))
164 struct rectangle *rsp;
165 int lx, ly, hx, hy, lowx, lowy, hix, hiy, dx, dy;
166 int tryct = 0, xlim, ylim;
169 xlim = XLIM + secret;
170 ylim = YLIM + secret;
173 rsp->rlx = rsp->rly = 0;
174 rsp->rhx = COLNO - 1;
175 rsp->rhy = ROWNO - 1;
180 /* make rooms until satisfied */
181 while (rscnt > 0 && nroom < MAXNROFROOMS - 1) {
182 if (!secret && nroom > (MAXNROFROOMS / 3) &&
183 !rn2((MAXNROFROOMS - nroom) * (MAXNROFROOMS - nroom)))
186 /* pick a rectangle */
187 rsp = &rs[rn2(rscnt)];
193 /* find size of room */
197 dx = 2 + rn2((hx - lx - 8 > 20) ? 12 : 8);
203 /* look whether our room will fit */
204 if (hx - lx < dx + dx / 2 + 2 * xlim || hy - ly < dy + dy / 3 + 2 * ylim) {
206 /* maybe we throw this area out */
207 if (secret || !rn2(MAXNROFROOMS + 1 - nroom - tryct)) {
211 rs[rscnt] = rs[rsmax];
218 lowx = lx + xlim + rn2(hx - lx - dx - 2 * xlim + 1);
219 lowy = ly + ylim + rn2(hy - ly - dy - 2 * ylim + 1);
223 if (maker(lowx, dx, lowy, dy)) {
226 addrs(lowx - 1, lowy - 1, hix + 1, hiy + 1);
228 } else if (tryct++ > 100)
231 return (0); /* failed to make vault - very strange */
235 addrs(int lowx, int lowy, int hix, int hiy)
237 struct rectangle *rsp;
238 int lx, ly, hx, hy, xlim, ylim;
241 xlim = XLIM + secret;
242 ylim = YLIM + secret;
244 /* walk down since rscnt and rsmax change */
245 for (rsp = &rs[rsmax - 1]; rsp >= rs; rsp--) {
246 if ((lx = rsp->rlx) > hix || (ly = rsp->rly) > hiy ||
247 (hx = rsp->rhx) < lowx || (hy = rsp->rhy) < lowy)
249 if ((discarded = (rsp >= &rs[rscnt]))) {
256 rs[rscnt] = rs[rsmax];
258 if (lowy - ly > 2 * ylim + 4)
259 addrsx(lx, ly, hx, lowy - 2, discarded);
260 if (lowx - lx > 2 * xlim + 4)
261 addrsx(lx, ly, lowx - 2, hy, discarded);
262 if (hy - hiy > 2 * ylim + 4)
263 addrsx(lx, hiy + 2, hx, hy, discarded);
264 if (hx - hix > 2 * xlim + 4)
265 addrsx(hix + 2, ly, hx, hy, discarded);
269 /* discarded: piece of a discarded area */
271 addrsx(int lx, int ly, int hx, int hy, bool discarded)
273 struct rectangle *rsp;
275 /* check inclusions */
276 for (rsp = rs; rsp < &rs[rsmax]; rsp++) {
277 if (lx >= rsp->rlx && hx <= rsp->rhx &&
278 ly >= rsp->rly && hy <= rsp->rhy)
282 /* make a new entry */
283 if (rsmax >= MAXRS) {
286 pline("MAXRS may be too small.");
303 comp(const void *vx, const void *vy)
305 const struct mkroom *x, *y;
311 return (x->lx > y->lx);
315 finddpos(int xl, int yl, int xh, int yh)
320 x = (xl == xh) ? xl : (xl + rn2(xh - xl + 1));
321 y = (yl == yh) ? yl : (yl + rn2(yh - yl + 1));
325 for (x = xl; x <= xh; x++)
326 for (y = yl; y <= yh; y++)
330 for (x = xl; x <= xh; x++)
331 for (y = yl; y <= yh; y++)
332 if (levl[x][y].typ == DOOR || levl[x][y].typ == SDOOR)
334 /* cannot find something reasonable -- strange */
343 /* see whether it is allowable to create a door at [x,y] */
347 if (levl[x - 1][y].typ == DOOR || levl[x + 1][y].typ == DOOR ||
348 levl[x][y + 1].typ == DOOR || levl[x][y - 1].typ == DOOR ||
349 levl[x - 1][y].typ == SDOOR || levl[x + 1][y].typ == SDOOR ||
350 levl[x][y - 1].typ == SDOOR || levl[x][y + 1].typ == SDOOR ||
351 (levl[x][y].typ != HWALL && levl[x][y].typ != VWALL) ||
352 doorindex >= DOORMAX)
358 dodoor(int x, int y, struct mkroom *aroom)
360 if (doorindex >= DOORMAX) {
361 impossible("DOORMAX exceeded?");
364 if (!okdoor(x, y) && nxcor)
366 dosdoor(x, y, aroom, rn2(8) ? DOOR : SDOOR);
370 dosdoor(int x, int y, struct mkroom *aroom, int type)
372 struct mkroom *broom;
375 if (!IS_WALL(levl[x][y].typ)) /* avoid SDOORs with '+' as scrsym */
377 levl[x][y].typ = type;
379 levl[x][y].scrsym = '+';
385 for (tmp = doorindex; tmp > broom->fdoor; tmp--)
386 doors[tmp] = doors[tmp - 1];
390 for (; broom->hx >= 0; broom++)
394 /* Only called from makerooms() */
396 maker(schar lowx, schar ddx, schar lowy, schar ddy)
398 struct mkroom *croom;
399 int x, y, hix = lowx + ddx, hiy = lowy + ddy;
400 int xlim = XLIM + secret, ylim = YLIM + secret;
402 if (nroom >= MAXNROFROOMS)
408 if (hix > COLNO - XLIM - 1)
409 hix = COLNO - XLIM - 1;
410 if (hiy > ROWNO - YLIM - 1)
411 hiy = ROWNO - YLIM - 1;
413 if (hix <= lowx || hiy <= lowy)
416 /* check area around room (and make room smaller if necessary) */
417 for (x = lowx - xlim; x <= hix + xlim; x++) {
418 for (y = lowy - ylim; y <= hiy + ylim; y++) {
419 if (levl[x][y].typ) {
421 if (wizard && !secret)
422 pline("Strange area [%d,%d] in maker().", x, y);
439 croom = &rooms[nroom];
441 /* on low levels the room is lit (usually) */
442 /* secret vaults are always lit */
443 if ((rnd(dlevel) < 10 && rn2(77)) || (ddx == 1 && ddy == 1)) {
444 for (x = lowx - 1; x <= hix + 1; x++)
445 for (y = lowy - 1; y <= hiy + 1; y++)
454 croom->rtype = croom->doorct = croom->fdoor = 0;
456 for (x = lowx - 1; x <= hix + 1; x++)
457 for (y = lowy - 1; y <= hiy + 1; y += (hiy - lowy + 2)) {
458 levl[x][y].scrsym = '-';
459 levl[x][y].typ = HWALL;
461 for (x = lowx - 1; x <= hix + 1; x += (hix - lowx + 2))
462 for (y = lowy; y <= hiy; y++) {
463 levl[x][y].scrsym = '|';
464 levl[x][y].typ = VWALL;
466 for (x = lowx; x <= hix; x++)
467 for (y = lowy; y <= hiy; y++) {
468 levl[x][y].scrsym = '.';
469 levl[x][y].typ = ROOM;
485 for (a = 0; a < nroom - 1; a++)
487 for (a = 0; a < nroom - 2; a++)
488 if (smeq[a] != smeq[a + 2])
490 for (a = 0; a < nroom; a++)
491 for (b = 0; b < nroom; b++)
492 if (smeq[a] != smeq[b])
495 for (nxcor = rn2(nroom) + 4; nxcor; nxcor--) {
510 struct mkroom *croom, *troom;
511 int dx, dy, dix, diy, cct;
517 * find positions cc and tt for doors in croom and troom and
518 * direction for a corridor between them
521 if (troom->hx < 0 || croom->hx < 0 || doorindex >= DOORMAX)
523 if (troom->lx > croom->hx) {
528 cc = finddpos(xx, croom->ly, xx, croom->hy);
529 tt = finddpos(tx, troom->ly, tx, troom->hy);
530 } else if (troom->hy < croom->ly) {
534 cc = finddpos(croom->lx, yy, croom->hx, yy);
536 tt = finddpos(troom->lx, ty, troom->hx, ty);
537 } else if (troom->hx < croom->lx) {
542 cc = finddpos(xx, croom->ly, xx, croom->hy);
543 tt = finddpos(tx, troom->ly, tx, troom->hy);
549 cc = finddpos(croom->lx, yy, croom->hx, yy);
550 tt = finddpos(troom->lx, ty, troom->hx, ty);
556 if (nxcor && levl[xx + dx][yy + dy].typ)
558 dodoor(xx, yy, croom);
561 while (xx != tx || yy != ty) {
565 /* loop: dig corridor at [xx,yy] and find new [xx,yy] */
566 if (cct++ > 500 || (nxcor && !rn2(35)))
569 if (xx == COLNO - 1 || xx == 0 || yy == 0 || yy == ROWNO - 1)
570 return; /* impossible */
576 crm->scrsym = CORR_SYM;
577 if (nxcor && !rn2(50))
578 mkobj_at(ROCK_SYM, xx, yy);
583 } else if (crm->typ != CORR && crm->typ != SCORR) {
587 /* find next corridor position */
591 /* do we have to change direction ? */
592 if (dy && dix > diy) {
593 int ddx = (xx > tx) ? -1 : 1;
595 crm = &levl[xx + ddx][yy];
596 if (!crm->typ || crm->typ == CORR || crm->typ == SCORR) {
601 } else if (dx && diy > dix) {
602 int ddy = (yy > ty) ? -1 : 1;
604 crm = &levl[xx][yy + ddy];
605 if (!crm->typ || crm->typ == CORR || crm->typ == SCORR) {
612 /* continue straight on? */
613 crm = &levl[xx + dx][yy + dy];
614 if (!crm->typ || crm->typ == CORR || crm->typ == SCORR)
617 /* no, what must we do now?? */
620 dy = (ty < yy) ? -1 : 1;
621 crm = &levl[xx + dx][yy + dy];
622 if (!crm->typ || crm->typ == CORR || crm->typ == SCORR)
628 dx = (tx < xx) ? -1 : 1;
629 crm = &levl[xx + dx][yy + dy];
630 if (!crm->typ || crm->typ == CORR || crm->typ == SCORR)
637 /* we succeeded in digging the corridor */
638 dodoor(tt.x, tt.y, troom);
640 if (smeq[a] < smeq[b])
649 int ct = rnd(nroom / 2 + 1);
661 makeniche(bool with_trap)
663 struct mkroom *aroom;
670 if (doorindex < DOORMAX)
672 aroom = &rooms[rn2(nroom - 1)];
673 if (aroom->rtype != 0) /* not an ordinary room */
675 if (aroom->doorct == 1 && rn2(5))
679 dd = finddpos(aroom->lx, aroom->hy + 1,
684 dd = finddpos(aroom->lx, aroom->ly - 1,
690 if ((rm = &levl[xx][yy + dy])->typ)
692 if (with_trap || !rn2(4)) {
696 ttmp = maketrap(xx, yy + dy, TELEP_TRAP);
698 make_engr_at(xx, yy - dy, "ad ae?ar um");
700 dosdoor(xx, yy, aroom, SDOOR);
703 rm->scrsym = CORR_SYM;
705 dosdoor(xx, yy, aroom, rn2(5) ? SDOOR : DOOR);
707 mksobj_at(SCR_TELEPORTATION, xx, yy + dy);
709 mkobj_at(0, xx, yy + dy);
716 /* make a trap somewhere (in croom if mazeflag = 0) */
718 mktrap(int num, int mazeflag, struct mkroom *croom)
721 int kind, nopierc, nomimic, fakedoor, fakegold, tryct = 0;
724 if (!num || num >= TRAPNUM) {
725 nopierc = (dlevel < 4) ? 1 : 0;
726 nomimic = (dlevel < 9 || goldseen) ? 1 : 0;
727 if (strchr(fut_geno, 'M'))
729 kind = rn2(TRAPNUM - nopierc - nomimic);
730 /* note: PIERC = 7, MIMIC = 8, TRAPNUM = 9 */
737 fakedoor = (!rn2(3) && !mazeflag);
738 fakegold = (!fakedoor && !rn2(2));
745 /* note: fakedoor maybe on actual door */
759 } else if (mazeflag) {
768 } while (m_at(mx, my) || levl[mx][my].typ == STAIRS);
769 if ((mtmp = makemon(PM_MIMIC, mx, my)) != NULL) {
772 fakegold ? '$' : fakedoor ? '+' :
773 (mazeflag && rn2(2)) ? AMULET_SYM :
791 } while (t_at(mx, my) || levl[mx][my].typ == STAIRS);
792 ttmp = maketrap(mx, my, kind);
793 if (mazeflag && !rn2(10) && ttmp->ttyp < PIERC)