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
)