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++) for(y=0; y<ROWNO; y++)
61 oinit(); /* assign level dependent obj probabilities */
63 if(dlevel >= rn1(3, 26)) { /* there might be several mazes */
68 /* construct the rooms */
73 /* construct stairs (up and down in different rooms if possible) */
74 croom = &rooms[rn2(nroom)];
77 levl[xdnstair][ydnstair].scrsym ='>';
78 levl[xdnstair][ydnstair].typ = STAIRS;
81 croom = &rooms[rn2(nroom-1)];
82 if(croom >= troom) croom++;
84 xupstair = somex(); /* %% < and > might be in the same place */
86 levl[xupstair][yupstair].scrsym ='<';
87 levl[xupstair][yupstair].typ = STAIRS;
89 /* for each room: put things inside */
90 for(croom = rooms; croom->hx > 0; croom++) {
92 /* put a sleeping monster inside */
93 /* Note: monster may be on the stairs. This cannot be
94 avoided: maybe the player fell through a trapdoor
95 while a monster was on the stairs. Conclusion:
96 we have to check for monsters on the stairs anyway. */
98 makemon((struct permonst *) 0, somex(), somey());
100 /* put traps and mimics inside */
102 while(!rn2(8-(dlevel/6))) mktrap(0,0,croom);
103 if(!goldseen && !rn2(3)) mkgold(0L,somex(),somey());
105 mkobj_at(0, somex(), somey());
109 printf("tryct overflow4\n");
112 mkobj_at(0, somex(), somey());
117 qsort((char *) rooms, nroom, sizeof(struct mkroom), comp);
121 /* make a secret treasure vault, not connected to the rest */
122 if(nroom <= (2*MAXNROFROOMS/3)) if(rn2(3)) {
123 troom = &rooms[nroom];
126 troom->rtype = VAULT; /* treasure vault */
127 for(x = troom->lx; x <= troom->hx; x++)
128 for(y = troom->ly; y <= troom->hy; y++)
129 mkgold((long)(rnd(dlevel*100) + 50), x, y);
137 if(wizard && getenv("SHOPTYPE")) mkshop(); else
139 if(dlevel > 1 && dlevel < 20 && rn2(dlevel) < 3) mkshop();
141 if(dlevel > 6 && !rn2(7)) mkzoo(ZOO);
143 if(dlevel > 9 && !rn2(5)) mkzoo(BEEHIVE);
145 if(dlevel > 11 && !rn2(6)) mkzoo(MORGUE);
147 if(dlevel > 18 && !rn2(6)) mkswamp();
154 struct rectangle *rsp;
155 int lx, ly, hx, hy, lowx, lowy, hix, hiy, dx, dy;
156 int tryct = 0, xlim, ylim;
159 xlim = XLIM + secret;
160 ylim = YLIM + secret;
163 rsp->rlx = rsp->rly = 0;
170 /* make rooms until satisfied */
171 while(rscnt > 0 && nroom < MAXNROFROOMS-1) {
172 if(!secret && nroom > (MAXNROFROOMS/3) &&
173 !rn2((MAXNROFROOMS-nroom)*(MAXNROFROOMS-nroom)))
176 /* pick a rectangle */
177 rsp = &rs[rn2(rscnt)];
183 /* find size of room */
187 dx = 2 + rn2((hx-lx-8 > 20) ? 12 : 8);
193 /* look whether our room will fit */
194 if(hx-lx < dx + dx/2 + 2*xlim || hy-ly < dy + dy/3 + 2*ylim) {
196 /* maybe we throw this area out */
197 if(secret || !rn2(MAXNROFROOMS+1-nroom-tryct)) {
201 rs[rscnt] = rs[rsmax];
208 lowx = lx + xlim + rn2(hx - lx - dx - 2*xlim + 1);
209 lowy = ly + ylim + rn2(hy - ly - dy - 2*ylim + 1);
213 if(maker(lowx, dx, lowy, dy)) {
216 addrs(lowx-1, lowy-1, hix+1, hiy+1);
222 return(0); /* failed to make vault - very strange */
226 addrs(int lowx, int lowy, int hix, int hiy)
228 struct rectangle *rsp;
229 int lx,ly,hx,hy,xlim,ylim;
232 xlim = XLIM + secret;
233 ylim = YLIM + secret;
235 /* walk down since rscnt and rsmax change */
236 for(rsp = &rs[rsmax-1]; rsp >= rs; rsp--) {
238 if((lx = rsp->rlx) > hix || (ly = rsp->rly) > hiy ||
239 (hx = rsp->rhx) < lowx || (hy = rsp->rhy) < lowy)
241 if((discarded = (rsp >= &rs[rscnt]))) {
248 rs[rscnt] = rs[rsmax];
250 if(lowy - ly > 2*ylim + 4)
251 addrsx(lx,ly,hx,lowy-2,discarded);
252 if(lowx - lx > 2*xlim + 4)
253 addrsx(lx,ly,lowx-2,hy,discarded);
254 if(hy - hiy > 2*ylim + 4)
255 addrsx(lx,hiy+2,hx,hy,discarded);
256 if(hx - hix > 2*xlim + 4)
257 addrsx(hix+2,ly,hx,hy,discarded);
261 /* discarded = piece of a discarded area */
263 addrsx(int lx, int ly, int hx, int hy, bool discarded)
265 struct rectangle *rsp;
267 /* check inclusions */
268 for(rsp = rs; rsp < &rs[rsmax]; rsp++) {
269 if(lx >= rsp->rlx && hx <= rsp->rhx &&
270 ly >= rsp->rly && hy <= rsp->rhy)
274 /* make a new entry */
277 if(wizard) pline("MAXRS may be too small.");
294 comp(const void *vx, const void *vy)
296 const struct mkroom *x, *y;
299 if(x->lx < y->lx) return(-1);
300 return(x->lx > y->lx);
304 finddpos(int xl, int yl, int xh, int yh)
309 x = (xl == xh) ? xl : (xl + rn2(xh-xl+1));
310 y = (yl == yh) ? yl : (yl + rn2(yh-yl+1));
314 for(x = xl; x <= xh; x++) for(y = yl; y <= yh; y++)
318 for(x = xl; x <= xh; x++) for(y = yl; y <= yh; y++)
319 if(levl[x][y].typ == DOOR || levl[x][y].typ == SDOOR)
321 /* cannot find something reasonable -- strange */
330 /* see whether it is allowable to create a door at [x,y] */
334 if(levl[x-1][y].typ == DOOR || levl[x+1][y].typ == DOOR ||
335 levl[x][y+1].typ == DOOR || levl[x][y-1].typ == DOOR ||
336 levl[x-1][y].typ == SDOOR || levl[x+1][y].typ == SDOOR ||
337 levl[x][y-1].typ == SDOOR || levl[x][y+1].typ == SDOOR ||
338 (levl[x][y].typ != HWALL && levl[x][y].typ != VWALL) ||
339 doorindex >= DOORMAX)
345 dodoor(int x, int y, struct mkroom *aroom)
347 if(doorindex >= DOORMAX) {
348 impossible("DOORMAX exceeded?");
351 if(!okdoor(x,y) && nxcor)
353 dosdoor(x,y,aroom,rn2(8) ? DOOR : SDOOR);
357 dosdoor(int x, int y, struct mkroom *aroom, int type)
359 struct mkroom *broom;
362 if(!IS_WALL(levl[x][y].typ)) /* avoid SDOORs with '+' as scrsym */
364 levl[x][y].typ = type;
366 levl[x][y].scrsym = '+';
369 if(broom->hx < 0) tmp = doorindex; else
370 for(tmp = doorindex; tmp > broom->fdoor; tmp--)
371 doors[tmp] = doors[tmp-1];
375 for( ; broom->hx >= 0; broom++) broom->fdoor++;
378 /* Only called from makerooms() */
380 maker(schar lowx, schar ddx, schar lowy, schar ddy)
382 struct mkroom *croom;
383 int x, y, hix = lowx+ddx, hiy = lowy+ddy;
384 int xlim = XLIM + secret, ylim = YLIM + secret;
386 if(nroom >= MAXNROFROOMS) return(0);
387 if(lowx < XLIM) lowx = XLIM;
388 if(lowy < YLIM) lowy = YLIM;
389 if(hix > COLNO-XLIM-1) hix = COLNO-XLIM-1;
390 if(hiy > ROWNO-YLIM-1) hiy = ROWNO-YLIM-1;
392 if(hix <= lowx || hiy <= lowy) return(0);
394 /* check area around room (and make room smaller if necessary) */
395 for(x = lowx - xlim; x <= hix + xlim; x++) {
396 for(y = lowy - ylim; y <= hiy + ylim; y++) {
399 if(wizard && !secret)
400 pline("Strange area [%d,%d] in maker().",x,y);
402 if(!rn2(3)) return(0);
416 croom = &rooms[nroom];
418 /* on low levels the room is lit (usually) */
419 /* secret vaults are always lit */
420 if((rnd(dlevel) < 10 && rn2(77)) || (ddx == 1 && ddy == 1)) {
421 for(x = lowx-1; x <= hix+1; x++)
422 for(y = lowy-1; y <= hiy+1; y++)
431 croom->rtype = croom->doorct = croom->fdoor = 0;
433 for(x = lowx-1; x <= hix+1; x++)
434 for(y = lowy-1; y <= hiy+1; y += (hiy-lowy+2)) {
435 levl[x][y].scrsym = '-';
436 levl[x][y].typ = HWALL;
438 for(x = lowx-1; x <= hix+1; x += (hix-lowx+2))
439 for(y = lowy; y <= hiy; y++) {
440 levl[x][y].scrsym = '|';
441 levl[x][y].typ = VWALL;
443 for(x = lowx; x <= hix; x++)
444 for(y = lowy; y <= hiy; y++) {
445 levl[x][y].scrsym = '.';
446 levl[x][y].typ = ROOM;
462 for(a = 0; a < nroom-1; a++)
464 for(a = 0; a < nroom-2; a++)
465 if(smeq[a] != smeq[a+2])
467 for(a = 0; a < nroom; a++)
468 for(b = 0; b < nroom; b++)
469 if(smeq[a] != smeq[b])
472 for(nxcor = rn2(nroom) + 4; nxcor; nxcor--) {
486 struct mkroom *croom, *troom;
487 int dx, dy, dix, diy, cct;
492 /* find positions cc and tt for doors in croom and troom
493 and direction for a corridor between them */
495 if(troom->hx < 0 || croom->hx < 0 || doorindex >= DOORMAX) return;
496 if(troom->lx > croom->hx) {
501 cc = finddpos(xx,croom->ly,xx,croom->hy);
502 tt = finddpos(tx,troom->ly,tx,troom->hy);
503 } else if(troom->hy < croom->ly) {
507 cc = finddpos(croom->lx,yy,croom->hx,yy);
509 tt = finddpos(troom->lx,ty,troom->hx,ty);
510 } else if(troom->hx < croom->lx) {
515 cc = finddpos(xx,croom->ly,xx,croom->hy);
516 tt = finddpos(tx,troom->ly,tx,troom->hy);
522 cc = finddpos(croom->lx,yy,croom->hx,yy);
523 tt = finddpos(troom->lx,ty,troom->hx,ty);
529 if(nxcor && levl[xx+dx][yy+dy].typ)
534 while(xx != tx || yy != ty) {
538 /* loop: dig corridor at [xx,yy] and find new [xx,yy] */
539 if(cct++ > 500 || (nxcor && !rn2(35)))
542 if(xx == COLNO-1 || xx == 0 || yy == 0 || yy == ROWNO-1)
543 return; /* impossible */
549 crm->scrsym = CORR_SYM;
550 if(nxcor && !rn2(50))
551 mkobj_at(ROCK_SYM, xx, yy);
557 if(crm->typ != CORR && crm->typ != SCORR) {
562 /* find next corridor position */
566 /* do we have to change direction ? */
567 if(dy && dix > diy) {
568 int ddx = (xx > tx) ? -1 : 1;
570 crm = &levl[xx+ddx][yy];
571 if(!crm->typ || crm->typ == CORR || crm->typ == SCORR) {
576 } else if(dx && diy > dix) {
577 int ddy = (yy > ty) ? -1 : 1;
579 crm = &levl[xx][yy+ddy];
580 if(!crm->typ || crm->typ == CORR || crm->typ == SCORR) {
587 /* continue straight on? */
588 crm = &levl[xx+dx][yy+dy];
589 if(!crm->typ || crm->typ == CORR || crm->typ == SCORR)
592 /* no, what must we do now?? */
595 dy = (ty < yy) ? -1 : 1;
596 crm = &levl[xx+dx][yy+dy];
597 if(!crm->typ || crm->typ == CORR || crm->typ == SCORR)
603 dx = (tx < xx) ? -1 : 1;
604 crm = &levl[xx+dx][yy+dy];
605 if(!crm->typ || crm->typ == CORR || crm->typ == SCORR)
612 /* we succeeded in digging the corridor */
613 dodoor(tt.x, tt.y, troom);
615 if(smeq[a] < smeq[b])
624 int ct = rnd(nroom/2 + 1);
625 while(ct--) makeniche(FALSE);
635 makeniche(bool with_trap)
637 struct mkroom *aroom;
644 if(doorindex < DOORMAX)
646 aroom = &rooms[rn2(nroom-1)];
647 if(aroom->rtype != 0) continue; /* not an ordinary room */
648 if(aroom->doorct == 1 && rn2(5)) continue;
651 dd = finddpos(aroom->lx,aroom->hy+1,aroom->hx,aroom->hy+1);
654 dd = finddpos(aroom->lx,aroom->ly-1,aroom->hx,aroom->ly-1);
658 if((rm = &levl[xx][yy+dy])->typ) continue;
659 if(with_trap || !rn2(4)) {
663 ttmp = maketrap(xx, yy+dy, TELEP_TRAP);
665 make_engr_at(xx, yy-dy, "ad ae?ar um");
667 dosdoor(xx, yy, aroom, SDOOR);
670 rm->scrsym = CORR_SYM;
672 dosdoor(xx, yy, aroom, rn2(5) ? SDOOR : DOOR);
674 mksobj_at(SCR_TELEPORTATION, xx, yy+dy);
675 if(!rn2(3)) mkobj_at(0, xx, yy+dy);
682 /* make a trap somewhere (in croom if mazeflag = 0) */
684 mktrap(int num, int mazeflag, struct mkroom *croom)
687 int kind,nopierc,nomimic,fakedoor,fakegold,tryct = 0;
690 if(!num || num >= TRAPNUM) {
691 nopierc = (dlevel < 4) ? 1 : 0;
692 nomimic = (dlevel < 9 || goldseen ) ? 1 : 0;
693 if(index(fut_geno, 'M')) nomimic = 1;
694 kind = rn2(TRAPNUM - nopierc - nomimic);
695 /* note: PIERC = 7, MIMIC = 8, TRAPNUM = 9 */
701 fakedoor = (!rn2(3) && !mazeflag);
702 fakegold = (!fakedoor && !rn2(2));
703 if(fakegold) goldseen = TRUE;
705 if(++tryct > 200) return;
707 /* note: fakedoor maybe on actual door */
711 else mx = croom->lx-1;
716 else my = croom->ly-1;
719 } else if(mazeflag) {
728 } while(m_at(mx,my) || levl[mx][my].typ == STAIRS);
729 if((mtmp = makemon(PM_MIMIC,mx,my))) {
732 fakegold ? '$' : fakedoor ? '+' :
733 (mazeflag && rn2(2)) ? AMULET_SYM :
734 "=/)%?![<>" [ rn2(9) ];
751 } while(t_at(mx, my) || levl[mx][my].typ == STAIRS);
752 ttmp = maketrap(mx, my, kind);
753 if(mazeflag && !rn2(10) && ttmp->ttyp < PIERC)