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