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