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
)