xref: /openbsd-src/games/hack/hack.mklev.c (revision a28daedfc357b214be5c701aa8ba8adb29a7f1c2)
1 /*	$OpenBSD: hack.mklev.c,v 1.6 2003/05/19 06:30:56 pjanzen Exp $	*/
2 
3 /*
4  * Copyright (c) 1985, Stichting Centrum voor Wiskunde en Informatica,
5  * Amsterdam
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions are
10  * met:
11  *
12  * - Redistributions of source code must retain the above copyright notice,
13  * this list of conditions and the following disclaimer.
14  *
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.
18  *
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
22  * written permission.
23  *
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.
35  */
36 
37 /*
38  * Copyright (c) 1982 Jay Fenlason <hack@gnu.org>
39  * All rights reserved.
40  *
41  * Redistribution and use in source and binary forms, with or without
42  * modification, are permitted provided that the following conditions
43  * are met:
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.
51  *
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.
62  */
63 
64 #ifndef lint
65 static const char rcsid[] = "$OpenBSD: hack.mklev.c,v 1.6 2003/05/19 06:30:56 pjanzen Exp $";
66 #endif /* not lint */
67 
68 #include <stdio.h>
69 #include <stdlib.h>
70 #include <unistd.h>
71 #include "hack.h"
72 
73 #define somex() ((random()%(croom->hx-croom->lx+1))+croom->lx)
74 #define somey() ((random()%(croom->hy-croom->ly+1))+croom->ly)
75 
76 #define	XLIM	4	/* define minimum required space around a room */
77 #define	YLIM	3
78 boolean secret;		/* TRUE while making a vault: increase [XY]LIM */
79 struct mkroom rooms[MAXNROFROOMS+1];
80 int smeq[MAXNROFROOMS+1];
81 coord doors[DOORMAX];
82 int doorindex;
83 struct rm zerorm;
84 schar nxcor;
85 boolean goldseen;
86 int nroom;
87 xchar xdnstair,xupstair,ydnstair,yupstair;
88 
89 /* Definitions used by makerooms() and addrs() */
90 #define	MAXRS	50	/* max lth of temp rectangle table - arbitrary */
91 struct rectangle {
92 	xchar rlx,rly,rhx,rhy;
93 } rs[MAXRS+1];
94 int rscnt,rsmax;	/* 0..rscnt-1: currently under consideration */
95 			/* rscnt..rsmax: discarded */
96 
97 static void addrs(int, int, int, int);
98 static void addrsx(int, int, int, int, boolean);
99 int comp(const void *, const void *);
100 static coord finddpos(int, int, int, int);
101 static int  okdoor(int, int);
102 static void dodoor(int, int, struct mkroom *);
103 static void dosdoor(int, int, struct mkroom *, int);
104 static int  maker(schar, schar, schar, schar);
105 static void makecorridors(void);
106 static void join(int, int);
107 static void make_niches(void);
108 static void makevtele(void);
109 static void makeniche(boolean);
110 
111 void
112 makelevel()
113 {
114 	struct mkroom *croom, *troom;
115 	unsigned tryct;
116 	int x,y;
117 
118 	nroom = 0;
119 	doorindex = 0;
120 	rooms[0].hx = -1;	/* in case we are in a maze */
121 
122 	for(x=0; x<COLNO; x++) for(y=0; y<ROWNO; y++)
123 		levl[x][y] = zerorm;
124 
125 	oinit();	/* assign level dependent obj probabilities */
126 
127 	if(dlevel >= rn1(3, 26)) {	/* there might be several mazes */
128 		makemaz();
129 		return;
130 	}
131 
132 	/* construct the rooms */
133 	nroom = 0;
134 	secret = FALSE;
135 	(void) makerooms();
136 
137 	/* construct stairs (up and down in different rooms if possible) */
138 	croom = &rooms[rn2(nroom)];
139 	xdnstair = somex();
140 	ydnstair = somey();
141 	levl[(int)xdnstair][(int)ydnstair].scrsym ='>';
142 	levl[(int)xdnstair][(int)ydnstair].typ = STAIRS;
143 	if(nroom > 1) {
144 		troom = croom;
145 		croom = &rooms[rn2(nroom-1)];
146 		if(croom >= troom) croom++;
147 	}
148 	xupstair = somex();	/* %% < and > might be in the same place */
149 	yupstair = somey();
150 	levl[(int)xupstair][(int)yupstair].scrsym ='<';
151 	levl[(int)xupstair][(int)yupstair].typ = STAIRS;
152 
153 	/* for each room: put things inside */
154 	for(croom = rooms; croom->hx > 0; croom++) {
155 
156 		/* put a sleeping monster inside */
157 		/* Note: monster may be on the stairs. This cannot be
158 		   avoided: maybe the player fell through a trapdoor
159 		   while a monster was on the stairs. Conclusion:
160 		   we have to check for monsters on the stairs anyway. */
161 		if(!rn2(3)) (void)
162 			makemon((struct permonst *) 0, somex(), somey());
163 
164 		/* put traps and mimics inside */
165 		goldseen = FALSE;
166 		while(!rn2(8-(dlevel/6))) mktrap(0,0,croom);
167 		if(!goldseen && !rn2(3)) mkgold(0L,somex(),somey());
168 		if(!rn2(3)) {
169 			(void) mkobj_at(0, somex(), somey());
170 			tryct = 0;
171 			while(!rn2(5)) {
172 				if(++tryct > 100){
173 					printf("tryct overflow4\n");
174 					break;
175 				}
176 				(void) mkobj_at(0, somex(), somey());
177 			}
178 		}
179 	}
180 
181 	qsort((char *) rooms, nroom, sizeof(struct mkroom), comp);
182 	makecorridors();
183 	make_niches();
184 
185 	/* make a secret treasure vault, not connected to the rest */
186 	if(nroom <= (2*MAXNROFROOMS/3)) if(rn2(3)) {
187 		troom = &rooms[nroom];
188 		secret = TRUE;
189 		if(makerooms()) {
190 			troom->rtype = VAULT;		/* treasure vault */
191 			for(x = troom->lx; x <= troom->hx; x++)
192 			for(y = troom->ly; y <= troom->hy; y++)
193 				mkgold((long)(rnd(dlevel*100) + 50), x, y);
194 			if(!rn2(3))
195 				makevtele();
196 		}
197 	}
198 
199 #ifndef QUEST
200 #ifdef WIZARD
201 	if(wizard && getenv("SHOPTYPE")) mkshop(); else
202 #endif /* WIZARD */
203  	if(dlevel > 1 && dlevel < 20 && rn2(dlevel) < 3) mkshop();
204 	else
205 	if(dlevel > 6 && !rn2(7)) mkzoo(ZOO);
206 	else
207 	if(dlevel > 9 && !rn2(5)) mkzoo(BEEHIVE);
208 	else
209 	if(dlevel > 11 && !rn2(6)) mkzoo(MORGUE);
210 	else
211 	if(dlevel > 18 && !rn2(6)) mkswamp();
212 #endif /* QUEST */
213 }
214 
215 int
216 makerooms()
217 {
218 	struct rectangle *rsp;
219 	int lx, ly, hx, hy, lowx, lowy, hix, hiy, dx, dy;
220 	int tryct = 0, xlim, ylim;
221 
222 	/* init */
223 	xlim = XLIM + secret;
224 	ylim = YLIM + secret;
225 	if(nroom == 0) {
226 		rsp = rs;
227 		rsp->rlx = rsp->rly = 0;
228 		rsp->rhx = COLNO-1;
229 		rsp->rhy = ROWNO-1;
230 		rsmax = 1;
231 	}
232 	rscnt = rsmax;
233 
234 	/* make rooms until satisfied */
235 	while(rscnt > 0 && nroom < MAXNROFROOMS-1) {
236 		if(!secret && nroom > (MAXNROFROOMS/3) &&
237 		   !rn2((MAXNROFROOMS-nroom)*(MAXNROFROOMS-nroom)))
238 			return(0);
239 
240 		/* pick a rectangle */
241 		rsp = &rs[rn2(rscnt)];
242 		hx = rsp->rhx;
243 		hy = rsp->rhy;
244 		lx = rsp->rlx;
245 		ly = rsp->rly;
246 
247 		/* find size of room */
248 		if(secret)
249 			dx = dy = 1;
250 		else {
251 			dx = 2 + rn2((hx-lx-8 > 20) ? 12 : 8);
252 			dy = 2 + rn2(4);
253 			if(dx*dy > 50)
254 				dy = 50/dx;
255 		}
256 
257 		/* look whether our room will fit */
258 		if(hx-lx < dx + dx/2 + 2*xlim || hy-ly < dy + dy/3 + 2*ylim) {
259 					/* no, too small */
260 					/* maybe we throw this area out */
261 			if(secret || !rn2(MAXNROFROOMS+1-nroom-tryct)) {
262 				rscnt--;
263 				rs[rsmax] = *rsp;
264 				*rsp = rs[rscnt];
265 				rs[rscnt] = rs[rsmax];
266 				tryct = 0;
267 			} else
268 				tryct++;
269 			continue;
270 		}
271 
272 		lowx = lx + xlim + rn2(hx - lx - dx - 2*xlim + 1);
273 		lowy = ly + ylim + rn2(hy - ly - dy - 2*ylim + 1);
274 		hix = lowx + dx;
275 		hiy = lowy + dy;
276 
277 		if(maker(lowx, dx, lowy, dy)) {
278 			if(secret)
279 				return(1);
280 			addrs(lowx-1, lowy-1, hix+1, hiy+1);
281 			tryct = 0;
282 		} else
283 			if(tryct++ > 100)
284 				break;
285 	}
286 	return(0);	/* failed to make vault - very strange */
287 }
288 
289 static void
290 addrs(int lowx, int lowy, int hix, int hiy)
291 {
292 	struct rectangle *rsp;
293 	int lx,ly,hx,hy,xlim,ylim;
294 	boolean discarded;
295 
296 	xlim = XLIM + secret;
297 	ylim = YLIM + secret;
298 
299 	/* walk down since rscnt and rsmax change */
300 	for(rsp = &rs[rsmax-1]; rsp >= rs; rsp--) {
301 
302 		if((lx = rsp->rlx) > hix || (ly = rsp->rly) > hiy ||
303 		   (hx = rsp->rhx) < lowx || (hy = rsp->rhy) < lowy)
304 			continue;
305 		if((discarded = (rsp >= &rs[rscnt]))) {
306 			*rsp = rs[--rsmax];
307 		} else {
308 			rsmax--;
309 			rscnt--;
310 			*rsp = rs[rscnt];
311 			if(rscnt != rsmax)
312 				rs[rscnt] = rs[rsmax];
313 		}
314 		if(lowy - ly > 2*ylim + 4)
315 			addrsx(lx,ly,hx,lowy-2,discarded);
316 		if(lowx - lx > 2*xlim + 4)
317 			addrsx(lx,ly,lowx-2,hy,discarded);
318 		if(hy - hiy > 2*ylim + 4)
319 			addrsx(lx,hiy+2,hx,hy,discarded);
320 		if(hx - hix > 2*xlim + 4)
321 			addrsx(hix+2,ly,hx,hy,discarded);
322 	}
323 }
324 
325 static void
326 addrsx(int lx, int ly, int hx, int hy, boolean discarded)
327 /* boolean discarded;		 piece of a discarded area */
328 {
329 	struct rectangle *rsp;
330 
331 	/* check inclusions */
332 	for(rsp = rs; rsp < &rs[rsmax]; rsp++) {
333 		if(lx >= rsp->rlx && hx <= rsp->rhx &&
334 		   ly >= rsp->rly && hy <= rsp->rhy)
335 			return;
336 	}
337 
338 	/* make a new entry */
339 	if(rsmax >= MAXRS) {
340 #ifdef WIZARD
341 		if(wizard) pline("MAXRS may be too small.");
342 #endif /* WIZARD */
343 		return;
344 	}
345 	rsmax++;
346 	if(!discarded) {
347 		*rsp = rs[rscnt];
348 		rsp = &rs[rscnt];
349 		rscnt++;
350 	}
351 	rsp->rlx = lx;
352 	rsp->rly = ly;
353 	rsp->rhx = hx;
354 	rsp->rhy = hy;
355 }
356 
357 int
358 comp(const void *x, const void *y)
359 {
360 	if(((struct mkroom *)x)->lx < ((struct mkroom *)y)->lx)
361 		return(-1);
362 	return(((struct mkroom *)x)->lx > ((struct mkroom *)y)->lx);
363 }
364 
365 static coord
366 finddpos(int xl, int yl, int xh, int yh)
367 {
368 	coord ff;
369 	int x,y;
370 
371 	x = (xl == xh) ? xl : (xl + rn2(xh-xl+1));
372 	y = (yl == yh) ? yl : (yl + rn2(yh-yl+1));
373 	if(okdoor(x, y))
374 		goto gotit;
375 
376 	for(x = xl; x <= xh; x++) for(y = yl; y <= yh; y++)
377 		if(okdoor(x, y))
378 			goto gotit;
379 
380 	for(x = xl; x <= xh; x++) for(y = yl; y <= yh; y++)
381 		if(levl[x][y].typ == DOOR || levl[x][y].typ == SDOOR)
382 			goto gotit;
383 	/* cannot find something reasonable -- strange */
384 	x = xl;
385 	y = yh;
386 gotit:
387 	ff.x = x;
388 	ff.y = y;
389 	return(ff);
390 }
391 
392 /* see whether it is allowable to create a door at [x,y] */
393 static int
394 okdoor(int x, int y)
395 {
396 	if(levl[x-1][y].typ == DOOR || levl[x+1][y].typ == DOOR ||
397 	   levl[x][y+1].typ == DOOR || levl[x][y-1].typ == DOOR ||
398 	   levl[x-1][y].typ == SDOOR || levl[x+1][y].typ == SDOOR ||
399 	   levl[x][y-1].typ == SDOOR || levl[x][y+1].typ == SDOOR ||
400 	   (levl[x][y].typ != HWALL && levl[x][y].typ != VWALL) ||
401 	   doorindex >= DOORMAX)
402 		return(0);
403 	return(1);
404 }
405 
406 static void
407 dodoor(int x, int y, struct mkroom *aroom)
408 {
409 	if(doorindex >= DOORMAX) {
410 		impossible("DOORMAX exceeded?");
411 		return;
412 	}
413 	if(!okdoor(x,y) && nxcor)
414 		return;
415 	dosdoor(x,y,aroom,rn2(8) ? DOOR : SDOOR);
416 }
417 
418 static void
419 dosdoor(int x, int y, struct mkroom *aroom, int type)
420 {
421 	struct mkroom *broom;
422 	int tmp;
423 
424 	if(!IS_WALL(levl[x][y].typ))	/* avoid SDOORs with '+' as scrsym */
425 		type = DOOR;
426 	levl[x][y].typ = type;
427 	if(type == DOOR)
428 		levl[x][y].scrsym = '+';
429 	aroom->doorct++;
430 	broom = aroom+1;
431 	if(broom->hx < 0) tmp = doorindex; else
432 	for(tmp = doorindex; tmp > broom->fdoor; tmp--)
433 		doors[tmp] = doors[tmp-1];
434 	doorindex++;
435 	doors[tmp].x = x;
436 	doors[tmp].y = y;
437 	for( ; broom->hx >= 0; broom++) broom->fdoor++;
438 }
439 
440 /* Only called from makerooms() */
441 static int
442 maker(schar lowx, schar ddx, schar lowy, schar ddy)
443 {
444 	struct mkroom *croom;
445 	int x, y, hix = lowx+ddx, hiy = lowy+ddy;
446 	int xlim = XLIM + secret, ylim = YLIM + secret;
447 
448 	if(nroom >= MAXNROFROOMS) return(0);
449 	if(lowx < XLIM) lowx = XLIM;
450 	if(lowy < YLIM) lowy = YLIM;
451 	if(hix > COLNO-XLIM-1) hix = COLNO-XLIM-1;
452 	if(hiy > ROWNO-YLIM-1) hiy = ROWNO-YLIM-1;
453 chk:
454 	if(hix <= lowx || hiy <= lowy) return(0);
455 
456 	/* check area around room (and make room smaller if necessary) */
457 	for(x = lowx - xlim; x <= hix + xlim; x++) {
458 		for(y = lowy - ylim; y <= hiy + ylim; y++) {
459 			if(levl[x][y].typ) {
460 #ifdef WIZARD
461 			    if(wizard && !secret)
462 				pline("Strange area [%d,%d] in maker().",x,y);
463 #endif /* WIZARD */
464 				if(!rn2(3)) return(0);
465 				if(x < lowx)
466 					lowx = x+xlim+1;
467 				else
468 					hix = x-xlim-1;
469 				if(y < lowy)
470 					lowy = y+ylim+1;
471 				else
472 					hiy = y-ylim-1;
473 				goto chk;
474 			}
475 		}
476 	}
477 
478 	croom = &rooms[nroom];
479 
480 	/* on low levels the room is lit (usually) */
481 	/* secret vaults are always lit */
482 	if((rnd(dlevel) < 10 && rn2(77)) || (ddx == 1 && ddy == 1)) {
483 		for(x = lowx-1; x <= hix+1; x++)
484 			for(y = lowy-1; y <= hiy+1; y++)
485 				levl[x][y].lit = 1;
486 		croom->rlit = 1;
487 	} else
488 		croom->rlit = 0;
489 	croom->lx = lowx;
490 	croom->hx = hix;
491 	croom->ly = lowy;
492 	croom->hy = hiy;
493 	croom->rtype = croom->doorct = croom->fdoor = 0;
494 
495 	for(x = lowx-1; x <= hix+1; x++)
496 	    for(y = lowy-1; y <= hiy+1; y += (hiy-lowy+2)) {
497 		levl[x][y].scrsym = '-';
498 		levl[x][y].typ = HWALL;
499 	}
500 	for(x = lowx-1; x <= hix+1; x += (hix-lowx+2))
501 	    for(y = lowy; y <= hiy; y++) {
502 		levl[x][y].scrsym = '|';
503 		levl[x][y].typ = VWALL;
504 	}
505 	for(x = lowx; x <= hix; x++)
506 	    for(y = lowy; y <= hiy; y++) {
507 		levl[x][y].scrsym = '.';
508 		levl[x][y].typ = ROOM;
509 	}
510 
511 	smeq[nroom] = nroom;
512 	croom++;
513 	croom->hx = -1;
514 	nroom++;
515 	return(1);
516 }
517 
518 static void
519 makecorridors()
520 {
521 	int a,b;
522 
523 	nxcor = 0;
524 	for(a = 0; a < nroom-1; a++)
525 		join(a, a+1);
526 	for(a = 0; a < nroom-2; a++)
527 	    if(smeq[a] != smeq[a+2])
528 		join(a, a+2);
529 	for(a = 0; a < nroom; a++)
530 	    for(b = 0; b < nroom; b++)
531 		if(smeq[a] != smeq[b])
532 		    join(a, b);
533 	if(nroom > 2)
534 	    for(nxcor = rn2(nroom) + 4; nxcor; nxcor--) {
535 		a = rn2(nroom);
536 		b = rn2(nroom-2);
537 		if(b >= a) b += 2;
538 		join(a, b);
539 	    }
540 }
541 
542 static void
543 join(int a, int b)
544 {
545 	coord cc,tt;
546 	int tx, ty, xx, yy;
547 	struct rm *crm;
548 	struct mkroom *croom, *troom;
549 	int dx, dy, dix, diy, cct;
550 
551 	croom = &rooms[a];
552 	troom = &rooms[b];
553 
554 	/* find positions cc and tt for doors in croom and troom
555 	   and direction for a corridor between them */
556 
557 	if(troom->hx < 0 || croom->hx < 0 || doorindex >= DOORMAX) return;
558 	if(troom->lx > croom->hx) {
559 		dx = 1;
560 		dy = 0;
561 		xx = croom->hx+1;
562 		tx = troom->lx-1;
563 		cc = finddpos(xx,croom->ly,xx,croom->hy);
564 		tt = finddpos(tx,troom->ly,tx,troom->hy);
565 	} else if(troom->hy < croom->ly) {
566 		dy = -1;
567 		dx = 0;
568 		yy = croom->ly-1;
569 		cc = finddpos(croom->lx,yy,croom->hx,yy);
570 		ty = troom->hy+1;
571 		tt = finddpos(troom->lx,ty,troom->hx,ty);
572 	} else if(troom->hx < croom->lx) {
573 		dx = -1;
574 		dy = 0;
575 		xx = croom->lx-1;
576 		tx = troom->hx+1;
577 		cc = finddpos(xx,croom->ly,xx,croom->hy);
578 		tt = finddpos(tx,troom->ly,tx,troom->hy);
579 	} else {
580 		dy = 1;
581 		dx = 0;
582 		yy = croom->hy+1;
583 		ty = troom->ly-1;
584 		cc = finddpos(croom->lx,yy,croom->hx,yy);
585 		tt = finddpos(troom->lx,ty,troom->hx,ty);
586 	}
587 	xx = cc.x;
588 	yy = cc.y;
589 	tx = tt.x - dx;
590 	ty = tt.y - dy;
591 	if(nxcor && levl[xx+dx][yy+dy].typ)
592 		return;
593 	dodoor(xx,yy,croom);
594 
595 	cct = 0;
596 	while(xx != tx || yy != ty) {
597 	    xx += dx;
598 	    yy += dy;
599 
600 	    /* loop: dig corridor at [xx,yy] and find new [xx,yy] */
601 	    if(cct++ > 500 || (nxcor && !rn2(35)))
602 		return;
603 
604 	    if(xx == COLNO-1 || xx == 0 || yy == 0 || yy == ROWNO-1)
605 		return;		/* impossible */
606 
607 	    crm = &levl[xx][yy];
608 	    if(!(crm->typ)) {
609 		if(rn2(100)) {
610 			crm->typ = CORR;
611 			crm->scrsym = CORR_SYM;
612 			if(nxcor && !rn2(50))
613 				(void) mkobj_at(ROCK_SYM, xx, yy);
614 		} else {
615 			crm->typ = SCORR;
616 			crm->scrsym = ' ';
617 		}
618 	    } else
619 	    if(crm->typ != CORR && crm->typ != SCORR) {
620 		/* strange ... */
621 		return;
622 	    }
623 
624 	    /* find next corridor position */
625 	    dix = abs(xx-tx);
626 	    diy = abs(yy-ty);
627 
628 	    /* do we have to change direction ? */
629 	    if(dy && dix > diy) {
630 		int ddx = (xx > tx) ? -1 : 1;
631 
632 		crm = &levl[xx+ddx][yy];
633 		if(!crm->typ || crm->typ == CORR || crm->typ == SCORR) {
634 		    dx = ddx;
635 		    dy = 0;
636 		    continue;
637 		}
638 	    } else if(dx && diy > dix) {
639 		int ddy = (yy > ty) ? -1 : 1;
640 
641 		crm = &levl[xx][yy+ddy];
642 		if(!crm->typ || crm->typ == CORR || crm->typ == SCORR) {
643 		    dy = ddy;
644 		    dx = 0;
645 		    continue;
646 		}
647 	    }
648 
649 	    /* continue straight on? */
650 	    crm = &levl[xx+dx][yy+dy];
651 	    if(!crm->typ || crm->typ == CORR || crm->typ == SCORR)
652 		continue;
653 
654 	    /* no, what must we do now?? */
655 	    if(dx) {
656 		dx = 0;
657 		dy = (ty < yy) ? -1 : 1;
658 		crm = &levl[xx+dx][yy+dy];
659 		if(!crm->typ || crm->typ == CORR || crm->typ == SCORR)
660 		    continue;
661 		dy = -dy;
662 		continue;
663 	    } else {
664 		dy = 0;
665 		dx = (tx < xx) ? -1 : 1;
666 		crm = &levl[xx+dx][yy+dy];
667 		if(!crm->typ || crm->typ == CORR || crm->typ == SCORR)
668 		    continue;
669 		dx = -dx;
670 		continue;
671 	    }
672 	}
673 
674 	/* we succeeded in digging the corridor */
675 	dodoor(tt.x, tt.y, troom);
676 
677 	if(smeq[a] < smeq[b])
678 		smeq[b] = smeq[a];
679 	else
680 		smeq[a] = smeq[b];
681 }
682 
683 static void
684 make_niches()
685 {
686 	int ct = rnd(nroom/2 + 1);
687 	while(ct--) makeniche(FALSE);
688 }
689 
690 static void
691 makevtele()
692 {
693 	makeniche(TRUE);
694 }
695 
696 static void
697 makeniche(boolean with_trap)
698 {
699 	struct mkroom *aroom;
700 	struct rm *rm;
701 	int vct = 8;
702 	coord dd;
703 	int dy,xx,yy;
704 	struct trap *ttmp;
705 
706 	if(doorindex < DOORMAX)
707 	  while(vct--) {
708 	    aroom = &rooms[rn2(nroom-1)];
709 	    if(aroom->rtype != 0) continue;	/* not an ordinary room */
710 	    if(aroom->doorct == 1 && rn2(5)) continue;
711 	    if(rn2(2)) {
712 		dy = 1;
713 		dd = finddpos(aroom->lx,aroom->hy+1,aroom->hx,aroom->hy+1);
714 	    } else {
715 		dy = -1;
716 		dd = finddpos(aroom->lx,aroom->ly-1,aroom->hx,aroom->ly-1);
717 	    }
718 	    xx = dd.x;
719 	    yy = dd.y;
720 	    if((rm = &levl[xx][yy+dy])->typ) continue;
721 	    if(with_trap || !rn2(4)) {
722 		rm->typ = SCORR;
723 		rm->scrsym = ' ';
724 		if(with_trap) {
725 		    ttmp = maketrap(xx, yy+dy, TELEP_TRAP);
726 		    ttmp->once = 1;
727 		    make_engr_at(xx, yy-dy, "ad ae?ar um");
728 		}
729 		dosdoor(xx, yy, aroom, SDOOR);
730 	    } else {
731 		rm->typ = CORR;
732 		rm->scrsym = CORR_SYM;
733 		if(rn2(7))
734 		    dosdoor(xx, yy, aroom, rn2(5) ? SDOOR : DOOR);
735 		else {
736 		    mksobj_at(SCR_TELEPORTATION, xx, yy+dy);
737 		    if(!rn2(3)) (void) mkobj_at(0, xx, yy+dy);
738 		}
739 	    }
740 	    return;
741 	}
742 }
743 
744 /* make a trap somewhere (in croom if mazeflag = 0) */
745 void
746 mktrap(int num, int mazeflag, struct mkroom *croom)
747 {
748 	struct trap *ttmp;
749 	int kind,nopierc,nomimic,fakedoor,fakegold,tryct = 0;
750 	xchar mx,my;
751 	extern char fut_geno[];
752 
753 	if(!num || num >= TRAPNUM) {
754 		nopierc = (dlevel < 4) ? 1 : 0;
755 		nomimic = (dlevel < 9 || goldseen ) ? 1 : 0;
756 		if(strchr(fut_geno, 'M')) nomimic = 1;
757 		kind = rn2(TRAPNUM - nopierc - nomimic);
758 		/* note: PIERC = 7, MIMIC = 8, TRAPNUM = 9 */
759 	} else kind = num;
760 
761 	if(kind == MIMIC) {
762 		struct monst *mtmp;
763 
764 		fakedoor = (!rn2(3) && !mazeflag);
765 		fakegold = (!fakedoor && !rn2(2));
766 		if(fakegold) goldseen = TRUE;
767 		do {
768 			if(++tryct > 200) return;
769 			if(fakedoor) {
770 				/* note: fakedoor maybe on actual door */
771 				if(rn2(2)){
772 					if(rn2(2))
773 						mx = croom->hx+1;
774 					else mx = croom->lx-1;
775 					my = somey();
776 				} else {
777 					if(rn2(2))
778 						my = croom->hy+1;
779 					else my = croom->ly-1;
780 					mx = somex();
781 				}
782 			} else if(mazeflag) {
783 				coord mm;
784 				mx = mm.x;
785 				my = mm.y;
786 			} else {
787 				mx = somex();
788 				my = somey();
789 			}
790 		} while(m_at(mx,my) || levl[(int)mx][(int)my].typ == STAIRS);
791 		if ((mtmp = makemon(PM_MIMIC,mx,my))) {
792 		    mtmp->mimic = 1;
793 		    mtmp->mappearance =
794 			fakegold ? '$' : fakedoor ? '+' :
795 			(mazeflag && rn2(2)) ? AMULET_SYM :
796 			"=/)%?![<>" [ rn2(9) ];
797 		}
798 		return;
799 	}
800 
801 	do {
802 		if(++tryct > 200)
803 			return;
804 		if(mazeflag){
805 			extern coord mazexy();
806 			coord mm;
807 			mm = mazexy();
808 			mx = mm.x;
809 			my = mm.y;
810 		} else {
811 			mx = somex();
812 			my = somey();
813 		}
814 	} while(t_at(mx, my) || levl[(int)mx][(int)my].typ == STAIRS);
815 	ttmp = maketrap(mx, my, kind);
816 	if(mazeflag && !rn2(10) && ttmp->ttyp < PIERC)
817 		ttmp->tseen = 1;
818 }
819