1 /* $NetBSD: hack.mklev.c,v 1.7 2009/06/07 18:30:39 dholland Exp $ */
4 * Copyright (c) 1985, Stichting Centrum voor Wiskunde en Informatica,
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are
12 * - Redistributions of source code must retain the above copyright notice,
13 * this list of conditions and the following disclaimer.
15 * - Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * - Neither the name of the Stichting Centrum voor Wiskunde en
20 * Informatica, nor the names of its contributors may be used to endorse or
21 * promote products derived from this software without specific prior
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
25 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
26 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
27 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
28 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
29 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
30 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
31 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
32 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
33 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
34 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 * Copyright (c) 1982 Jay Fenlason <hack@gnu.org>
39 * All rights reserved.
41 * Redistribution and use in source and binary forms, with or without
42 * modification, are permitted provided that the following conditions
44 * 1. Redistributions of source code must retain the above copyright
45 * notice, this list of conditions and the following disclaimer.
46 * 2. Redistributions in binary form must reproduce the above copyright
47 * notice, this list of conditions and the following disclaimer in the
48 * documentation and/or other materials provided with the distribution.
49 * 3. The name of the author may not be used to endorse or promote products
50 * derived from this software without specific prior written permission.
52 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
53 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
54 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
55 * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
56 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
57 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
58 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
59 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
60 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
61 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
64 #include <sys/cdefs.h>
66 __RCSID("$NetBSD: hack.mklev.c,v 1.7 2009/06/07 18:30:39 dholland Exp $");
74 #define somex() ((random()%(croom->hx-croom->lx+1))+croom->lx)
75 #define somey() ((random()%(croom->hy-croom->ly+1))+croom->ly)
77 #include "def.mkroom.h"
78 #define XLIM 4 /* define minimum required space around a
81 static boolean secret
; /* TRUE while making a vault: increase
83 static int smeq
[MAXNROFROOMS
+ 1];
84 static const struct rm zerorm
;
86 static boolean goldseen
;
91 /* Definitions used by makerooms() and addrs() */
92 #define MAXRS 50 /* max lth of temp rectangle table -
94 static struct rectangle
{
95 xchar rlx
, rly
, rhx
, rhy
;
97 static int rscnt
, rsmax
; /* 0..rscnt-1: currently under consideration */
98 /* rscnt..rsmax: discarded */
100 static int makerooms(void);
101 static void addrs(int, int, int, int);
102 static void addrsx(int, int, int, int, boolean
);
103 static int comp(const void *, const void *);
104 static coord
finddpos(int, int, int, int);
105 static int okdoor(int, int);
106 static void dodoor(int, int, struct mkroom
*);
107 static void dosdoor(int, int, struct mkroom
*, int);
108 static int maker(schar
, schar
, schar
, schar
);
109 static void makecorridors(void);
110 static void join(int, int);
111 static void make_niches(void);
112 static void makevtele(void);
113 static void makeniche(boolean
);
118 struct mkroom
*croom
, *troom
;
124 rooms
[0].hx
= -1; /* in case we are in a maze */
126 for (x
= 0; x
< COLNO
; x
++)
127 for (y
= 0; y
< ROWNO
; y
++)
130 oinit(); /* assign level dependent obj probabilities */
132 if (dlevel
>= rn1(3, 26)) { /* there might be several mazes */
136 /* construct the rooms */
141 /* construct stairs (up and down in different rooms if possible) */
142 croom
= &rooms
[rn2(nroom
)];
145 levl
[xdnstair
][ydnstair
].scrsym
= '>';
146 levl
[xdnstair
][ydnstair
].typ
= STAIRS
;
149 croom
= &rooms
[rn2(nroom
- 1)];
153 xupstair
= somex(); /* %% < and > might be in the same place */
155 levl
[xupstair
][yupstair
].scrsym
= '<';
156 levl
[xupstair
][yupstair
].typ
= STAIRS
;
158 /* for each room: put things inside */
159 for (croom
= rooms
; croom
->hx
> 0; croom
++) {
161 /* put a sleeping monster inside */
163 * Note: monster may be on the stairs. This cannot be
164 * avoided: maybe the player fell through a trapdoor while a
165 * monster was on the stairs. Conclusion: we have to check
166 * for monsters on the stairs anyway.
170 makemon((struct permonst
*) 0, somex(), somey());
172 /* put traps and mimics inside */
174 while (!rn2(8 - (dlevel
/ 6)))
176 if (!goldseen
&& !rn2(3))
177 mkgold(0L, somex(), somey());
179 (void) mkobj_at(0, somex(), somey());
183 printf("tryct overflow4\n");
186 (void) mkobj_at(0, somex(), somey());
191 qsort((char *) rooms
, nroom
, sizeof(struct mkroom
), comp
);
195 /* make a secret treasure vault, not connected to the rest */
196 if (nroom
<= (2 * MAXNROFROOMS
/ 3))
198 troom
= &rooms
[nroom
];
201 troom
->rtype
= VAULT
; /* treasure vault */
202 for (x
= troom
->lx
; x
<= troom
->hx
; x
++)
203 for (y
= troom
->ly
; y
<= troom
->hy
; y
++)
204 mkgold((long) (rnd(dlevel
* 100) + 50), x
, y
);
211 if (wizard
&& getenv("SHOPTYPE"))
215 if (dlevel
> 1 && dlevel
< 20 && rn2(dlevel
) < 3)
217 else if (dlevel
> 6 && !rn2(7))
219 else if (dlevel
> 9 && !rn2(5))
221 else if (dlevel
> 11 && !rn2(6))
223 else if (dlevel
> 18 && !rn2(6))
231 struct rectangle
*rsp
;
232 int lx
, ly
, hx
, hy
, lowx
, lowy
, hix
, hiy
, dx
, dy
;
233 int tryct
= 0, xlim
, ylim
;
236 xlim
= XLIM
+ secret
;
237 ylim
= YLIM
+ secret
;
240 rsp
->rlx
= rsp
->rly
= 0;
241 rsp
->rhx
= COLNO
- 1;
242 rsp
->rhy
= ROWNO
- 1;
247 /* make rooms until satisfied */
248 while (rscnt
> 0 && nroom
< MAXNROFROOMS
- 1) {
249 if (!secret
&& nroom
> (MAXNROFROOMS
/ 3) &&
250 !rn2((MAXNROFROOMS
- nroom
) * (MAXNROFROOMS
- nroom
)))
253 /* pick a rectangle */
254 rsp
= &rs
[rn2(rscnt
)];
260 /* find size of room */
264 dx
= 2 + rn2((hx
- lx
- 8 > 20) ? 12 : 8);
270 /* look whether our room will fit */
271 if (hx
- lx
< dx
+ dx
/ 2 + 2 * xlim
|| hy
- ly
< dy
+ dy
/ 3 + 2 * ylim
) {
273 /* maybe we throw this area out */
274 if (secret
|| !rn2(MAXNROFROOMS
+ 1 - nroom
- tryct
)) {
278 rs
[rscnt
] = rs
[rsmax
];
284 lowx
= lx
+ xlim
+ rn2(hx
- lx
- dx
- 2 * xlim
+ 1);
285 lowy
= ly
+ ylim
+ rn2(hy
- ly
- dy
- 2 * ylim
+ 1);
289 if (maker(lowx
, dx
, lowy
, dy
)) {
292 addrs(lowx
- 1, lowy
- 1, hix
+ 1, hiy
+ 1);
294 } else if (tryct
++ > 100)
297 return (0); /* failed to make vault - very strange */
301 addrs(int lowx
, int lowy
, int hix
, int hiy
)
303 struct rectangle
*rsp
;
304 int lx
, ly
, hx
, hy
, xlim
, ylim
;
307 xlim
= XLIM
+ secret
;
308 ylim
= YLIM
+ secret
;
310 /* walk down since rscnt and rsmax change */
311 for (rsp
= &rs
[rsmax
- 1]; rsp
>= rs
; rsp
--) {
313 if ((lx
= rsp
->rlx
) > hix
|| (ly
= rsp
->rly
) > hiy
||
314 (hx
= rsp
->rhx
) < lowx
|| (hy
= rsp
->rhy
) < lowy
)
316 if ((discarded
= (rsp
>= &rs
[rscnt
]))) {
323 rs
[rscnt
] = rs
[rsmax
];
325 if (lowy
- ly
> 2 * ylim
+ 4)
326 addrsx(lx
, ly
, hx
, lowy
- 2, discarded
);
327 if (lowx
- lx
> 2 * xlim
+ 4)
328 addrsx(lx
, ly
, lowx
- 2, hy
, discarded
);
329 if (hy
- hiy
> 2 * ylim
+ 4)
330 addrsx(lx
, hiy
+ 2, hx
, hy
, discarded
);
331 if (hx
- hix
> 2 * xlim
+ 4)
332 addrsx(hix
+ 2, ly
, hx
, hy
, discarded
);
336 /* discarded: piece of a discarded area */
338 addrsx(int lx
, int ly
, int hx
, int hy
, boolean discarded
)
340 struct rectangle
*rsp
;
342 /* check inclusions */
343 for (rsp
= rs
; rsp
< &rs
[rsmax
]; rsp
++) {
344 if (lx
>= rsp
->rlx
&& hx
<= rsp
->rhx
&&
345 ly
>= rsp
->rly
&& hy
<= rsp
->rhy
)
349 /* make a new entry */
350 if (rsmax
>= MAXRS
) {
353 pline("MAXRS may be too small.");
370 comp(const void *vx
, const void *vy
)
372 const struct mkroom
*x
= vx
, *y
= vy
;
375 return (x
->lx
> y
->lx
);
379 finddpos(int xl
, int yl
, int xh
, int yh
)
384 x
= (xl
== xh
) ? xl
: (xl
+ rn2(xh
- xl
+ 1));
385 y
= (yl
== yh
) ? yl
: (yl
+ rn2(yh
- yl
+ 1));
389 for (x
= xl
; x
<= xh
; x
++)
390 for (y
= yl
; y
<= yh
; y
++)
394 for (x
= xl
; x
<= xh
; x
++)
395 for (y
= yl
; y
<= yh
; y
++)
396 if (levl
[x
][y
].typ
== DOOR
|| levl
[x
][y
].typ
== SDOOR
)
398 /* cannot find something reasonable -- strange */
407 /* see whether it is allowable to create a door at [x,y] */
411 if (levl
[x
- 1][y
].typ
== DOOR
|| levl
[x
+ 1][y
].typ
== DOOR
||
412 levl
[x
][y
+ 1].typ
== DOOR
|| levl
[x
][y
- 1].typ
== DOOR
||
413 levl
[x
- 1][y
].typ
== SDOOR
|| levl
[x
+ 1][y
].typ
== SDOOR
||
414 levl
[x
][y
- 1].typ
== SDOOR
|| levl
[x
][y
+ 1].typ
== SDOOR
||
415 (levl
[x
][y
].typ
!= HWALL
&& levl
[x
][y
].typ
!= VWALL
) ||
416 doorindex
>= DOORMAX
)
422 dodoor(int x
, int y
, struct mkroom
*aroom
)
424 if (doorindex
>= DOORMAX
) {
425 impossible("DOORMAX exceeded?");
428 if (!okdoor(x
, y
) && nxcor
)
430 dosdoor(x
, y
, aroom
, rn2(8) ? DOOR
: SDOOR
);
434 dosdoor(int x
, int y
, struct mkroom
*aroom
, int type
)
436 struct mkroom
*broom
;
439 if (!IS_WALL(levl
[x
][y
].typ
)) /* avoid SDOORs with '+' as scrsym */
441 levl
[x
][y
].typ
= type
;
443 levl
[x
][y
].scrsym
= '+';
449 for (tmp
= doorindex
; tmp
> broom
->fdoor
; tmp
--)
450 doors
[tmp
] = doors
[tmp
- 1];
454 for (; broom
->hx
>= 0; broom
++)
458 /* Only called from makerooms() */
460 maker(schar lowx
, schar ddx
, schar lowy
, schar ddy
)
462 struct mkroom
*croom
;
463 int x
, y
, hix
= lowx
+ ddx
, hiy
= lowy
+ ddy
;
464 int xlim
= XLIM
+ secret
, ylim
= YLIM
+ secret
;
466 if (nroom
>= MAXNROFROOMS
)
472 if (hix
> COLNO
- XLIM
- 1)
473 hix
= COLNO
- XLIM
- 1;
474 if (hiy
> ROWNO
- YLIM
- 1)
475 hiy
= ROWNO
- YLIM
- 1;
477 if (hix
<= lowx
|| hiy
<= lowy
)
480 /* check area around room (and make room smaller if necessary) */
481 for (x
= lowx
- xlim
; x
<= hix
+ xlim
; x
++) {
482 for (y
= lowy
- ylim
; y
<= hiy
+ ylim
; y
++) {
483 if (levl
[x
][y
].typ
) {
485 if (wizard
&& !secret
)
486 pline("Strange area [%d,%d] in maker().", x
, y
);
503 croom
= &rooms
[nroom
];
505 /* on low levels the room is lit (usually) */
506 /* secret vaults are always lit */
507 if ((rnd(dlevel
) < 10 && rn2(77)) || (ddx
== 1 && ddy
== 1)) {
508 for (x
= lowx
- 1; x
<= hix
+ 1; x
++)
509 for (y
= lowy
- 1; y
<= hiy
+ 1; y
++)
518 croom
->rtype
= croom
->doorct
= croom
->fdoor
= 0;
520 for (x
= lowx
- 1; x
<= hix
+ 1; x
++)
521 for (y
= lowy
- 1; y
<= hiy
+ 1; y
+= (hiy
- lowy
+ 2)) {
522 levl
[x
][y
].scrsym
= '-';
523 levl
[x
][y
].typ
= HWALL
;
525 for (x
= lowx
- 1; x
<= hix
+ 1; x
+= (hix
- lowx
+ 2))
526 for (y
= lowy
; y
<= hiy
; y
++) {
527 levl
[x
][y
].scrsym
= '|';
528 levl
[x
][y
].typ
= VWALL
;
530 for (x
= lowx
; x
<= hix
; x
++)
531 for (y
= lowy
; y
<= hiy
; y
++) {
532 levl
[x
][y
].scrsym
= '.';
533 levl
[x
][y
].typ
= ROOM
;
549 for (a
= 0; a
< nroom
- 1; a
++)
551 for (a
= 0; a
< nroom
- 2; a
++)
552 if (smeq
[a
] != smeq
[a
+ 2])
554 for (a
= 0; a
< nroom
; a
++)
555 for (b
= 0; b
< nroom
; b
++)
556 if (smeq
[a
] != smeq
[b
])
559 for (nxcor
= rn2(nroom
) + 4; nxcor
; nxcor
--) {
574 struct mkroom
*croom
, *troom
;
575 int dx
, dy
, dix
, diy
, cct
;
581 * find positions cc and tt for doors in croom and troom and
582 * direction for a corridor between them
585 if (troom
->hx
< 0 || croom
->hx
< 0 || doorindex
>= DOORMAX
)
587 if (troom
->lx
> croom
->hx
) {
592 cc
= finddpos(xx
, croom
->ly
, xx
, croom
->hy
);
593 tt
= finddpos(tx
, troom
->ly
, tx
, troom
->hy
);
594 } else if (troom
->hy
< croom
->ly
) {
598 cc
= finddpos(croom
->lx
, yy
, croom
->hx
, yy
);
600 tt
= finddpos(troom
->lx
, ty
, troom
->hx
, ty
);
601 } else if (troom
->hx
< croom
->lx
) {
606 cc
= finddpos(xx
, croom
->ly
, xx
, croom
->hy
);
607 tt
= finddpos(tx
, troom
->ly
, tx
, troom
->hy
);
613 cc
= finddpos(croom
->lx
, yy
, croom
->hx
, yy
);
614 tt
= finddpos(troom
->lx
, ty
, troom
->hx
, ty
);
620 if (nxcor
&& levl
[xx
+ dx
][yy
+ dy
].typ
)
622 dodoor(xx
, yy
, croom
);
625 while (xx
!= tx
|| yy
!= ty
) {
629 /* loop: dig corridor at [xx,yy] and find new [xx,yy] */
630 if (cct
++ > 500 || (nxcor
&& !rn2(35)))
633 if (xx
== COLNO
- 1 || xx
== 0 || yy
== 0 || yy
== ROWNO
- 1)
634 return; /* impossible */
640 crm
->scrsym
= CORR_SYM
;
641 if (nxcor
&& !rn2(50))
642 (void) mkobj_at(ROCK_SYM
, xx
, yy
);
647 } else if (crm
->typ
!= CORR
&& crm
->typ
!= SCORR
) {
651 /* find next corridor position */
655 /* do we have to change direction ? */
656 if (dy
&& dix
> diy
) {
657 int ddx
= (xx
> tx
) ? -1 : 1;
659 crm
= &levl
[xx
+ ddx
][yy
];
660 if (!crm
->typ
|| crm
->typ
== CORR
|| crm
->typ
== SCORR
) {
665 } else if (dx
&& diy
> dix
) {
666 int ddy
= (yy
> ty
) ? -1 : 1;
668 crm
= &levl
[xx
][yy
+ ddy
];
669 if (!crm
->typ
|| crm
->typ
== CORR
|| crm
->typ
== SCORR
) {
675 /* continue straight on? */
676 crm
= &levl
[xx
+ dx
][yy
+ dy
];
677 if (!crm
->typ
|| crm
->typ
== CORR
|| crm
->typ
== SCORR
)
680 /* no, what must we do now?? */
683 dy
= (ty
< yy
) ? -1 : 1;
684 crm
= &levl
[xx
+ dx
][yy
+ dy
];
685 if (!crm
->typ
|| crm
->typ
== CORR
|| crm
->typ
== SCORR
)
691 dx
= (tx
< xx
) ? -1 : 1;
692 crm
= &levl
[xx
+ dx
][yy
+ dy
];
693 if (!crm
->typ
|| crm
->typ
== CORR
|| crm
->typ
== SCORR
)
700 /* we succeeded in digging the corridor */
701 dodoor(tt
.x
, tt
.y
, troom
);
703 if (smeq
[a
] < smeq
[b
])
712 int ct
= rnd(nroom
/ 2 + 1);
724 makeniche(boolean with_trap
)
726 struct mkroom
*aroom
;
733 if (doorindex
< DOORMAX
)
735 aroom
= &rooms
[rn2(nroom
- 1)];
736 if (aroom
->rtype
!= 0)
737 continue; /* not an ordinary room */
738 if (aroom
->doorct
== 1 && rn2(5))
742 dd
= finddpos(aroom
->lx
, aroom
->hy
+ 1, aroom
->hx
, aroom
->hy
+ 1);
745 dd
= finddpos(aroom
->lx
, aroom
->ly
- 1, aroom
->hx
, aroom
->ly
- 1);
749 if ((rm
= &levl
[xx
][yy
+ dy
])->typ
)
751 if (with_trap
|| !rn2(4)) {
755 ttmp
= maketrap(xx
, yy
+ dy
, TELEP_TRAP
);
757 make_engr_at(xx
, yy
- dy
, "ad ae?ar um");
759 dosdoor(xx
, yy
, aroom
, SDOOR
);
762 rm
->scrsym
= CORR_SYM
;
764 dosdoor(xx
, yy
, aroom
, rn2(5) ? SDOOR
: DOOR
);
766 mksobj_at(SCR_TELEPORTATION
, xx
, yy
+ dy
);
768 (void) mkobj_at(0, xx
, yy
+ dy
);
775 /* make a trap somewhere (in croom if mazeflag = 0) */
777 mktrap(int num
, int mazeflag
, struct mkroom
*croom
)
780 int kind
, nopierc
, nomimic
, fakedoor
, fakegold
, tryct
= 0;
783 if (!num
|| num
>= TRAPNUM
) {
784 nopierc
= (dlevel
< 4) ? 1 : 0;
785 nomimic
= (dlevel
< 9 || goldseen
) ? 1 : 0;
786 if (strchr(fut_geno
, 'M'))
788 kind
= rn2(TRAPNUM
- nopierc
- nomimic
);
789 /* note: PIERC = 7, MIMIC = 8, TRAPNUM = 9 */
796 fakedoor
= (!rn2(3) && !mazeflag
);
797 fakegold
= (!fakedoor
&& !rn2(2));
804 /* note: fakedoor maybe on actual door */
818 } else if (mazeflag
) {
827 } while (m_at(mx
, my
) || levl
[mx
][my
].typ
== STAIRS
);
828 if ((mtmp
= makemon(PM_MIMIC
, mx
, my
)) != NULL
) {
831 fakegold
? '$' : fakedoor
? '+' :
832 (mazeflag
&& rn2(2)) ? AMULET_SYM
:
849 } while (t_at(mx
, my
) || levl
[mx
][my
].typ
== STAIRS
);
850 ttmp
= maketrap(mx
, my
, kind
);
851 if (mazeflag
&& !rn2(10) && ttmp
->ttyp
< PIERC
)