1/*	SCCS Id: @(#)mklev.c	3.4	2001/11/29	*/
2/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3/* NetHack may be freely redistributed.  See license for details. */
4
5#include "hack.h"
6/* #define DEBUG */	/* uncomment to enable code debugging */
7
8#ifdef NETHACK_DEBUG
9# ifdef WIZARD
10#define debugpline	if (wizard) pline
11# else
12#define debugpline	pline
13# endif
14#endif
15
16/* for UNIX, Rand #def'd to (long)lrand48() or (long)random() */
17/* croom->lx etc are schar (width <= int), so % arith ensures that */
18/* conversion of result to int is reasonable */
19
20
21STATIC_DCL void FDECL(mkfount,(int,struct mkroom *));
22#ifdef SINKS
23STATIC_DCL void FDECL(mksink,(struct mkroom *));
24#endif
25STATIC_DCL void FDECL(mkaltar,(struct mkroom *));
26STATIC_DCL void FDECL(mkgrave,(struct mkroom *));
27STATIC_DCL void NDECL(makevtele);
28STATIC_DCL void NDECL(clear_level_structures);
29STATIC_DCL void NDECL(makelevel);
30STATIC_DCL void NDECL(mineralize);
31STATIC_DCL boolean FDECL(bydoor,(XCHAR_P,XCHAR_P));
32STATIC_DCL struct mkroom *FDECL(find_branch_room, (coord *));
33STATIC_DCL struct mkroom *FDECL(pos_to_room, (XCHAR_P, XCHAR_P));
34STATIC_DCL boolean FDECL(place_niche,(struct mkroom *,int*,int*,int*));
35STATIC_DCL void FDECL(makeniche,(int));
36STATIC_DCL void NDECL(make_niches);
37
38STATIC_PTR int FDECL( CFDECLSPEC do_comp,(const genericptr,const genericptr));
39
40STATIC_DCL void FDECL(dosdoor,(XCHAR_P,XCHAR_P,struct mkroom *,int));
41STATIC_DCL void FDECL(join,(int,int,BOOLEAN_P));
42STATIC_DCL void FDECL(do_room_or_subroom, (struct mkroom *,int,int,int,int,
43				       BOOLEAN_P,SCHAR_P,BOOLEAN_P,BOOLEAN_P));
44STATIC_DCL void NDECL(makerooms);
45STATIC_DCL void FDECL(finddpos,(coord *,XCHAR_P,XCHAR_P,XCHAR_P,XCHAR_P));
46STATIC_DCL void FDECL(mkinvpos, (XCHAR_P,XCHAR_P,int));
47STATIC_DCL void FDECL(mk_knox_portal, (XCHAR_P,XCHAR_P));
48
49#define create_vault()	create_room(-1, -1, 2, 2, -1, -1, VAULT, TRUE)
50#define init_vault()	vault_x = -1
51#define do_vault()	(vault_x != -1)
52static xchar		vault_x, vault_y;
53boolean goldseen;
54static boolean made_branch;	/* used only during level creation */
55
56/* Args must be (const genericptr) so that qsort will always be happy. */
57
58STATIC_PTR int CFDECLSPEC
59do_comp(vx,vy)
60const genericptr vx;
61const genericptr vy;
62{
63#ifdef LINT
64/* lint complains about possible pointer alignment problems, but we know
65   that vx and vy are always properly aligned. Hence, the following
66   bogus definition:
67*/
68	return (vx == vy) ? 0 : -1;
69#else
70	register const struct mkroom *x, *y;
71
72	x = (const struct mkroom *)vx;
73	y = (const struct mkroom *)vy;
74	if(x->lx < y->lx) return(-1);
75	return(x->lx > y->lx);
76#endif /* LINT */
77}
78
79STATIC_OVL void
80finddpos(cc, xl,yl,xh,yh)
81coord *cc;
82xchar xl,yl,xh,yh;
83{
84	register xchar x, y;
85
86	x = (xl == xh) ? xl : (xl + rn2(xh-xl+1));
87	y = (yl == yh) ? yl : (yl + rn2(yh-yl+1));
88	if(okdoor(x, y))
89		goto gotit;
90
91	for(x = xl; x <= xh; x++) for(y = yl; y <= yh; y++)
92		if(okdoor(x, y))
93			goto gotit;
94
95	for(x = xl; x <= xh; x++) for(y = yl; y <= yh; y++)
96		if(IS_DOOR(levl[x][y].typ) || levl[x][y].typ == SDOOR)
97			goto gotit;
98	/* cannot find something reasonable -- strange */
99	x = xl;
100	y = yh;
101gotit:
102	cc->x = x;
103	cc->y = y;
104	return;
105}
106
107void
108sort_rooms()
109{
110#if defined(SYSV) || defined(DGUX)
111	qsort((genericptr_t) rooms, (unsigned)nroom, sizeof(struct mkroom), do_comp);
112#else
113	qsort((genericptr_t) rooms, nroom, sizeof(struct mkroom), do_comp);
114#endif
115}
116
117STATIC_OVL void
118do_room_or_subroom(croom, lowx, lowy, hix, hiy, lit, rtype, special, is_room)
119    register struct mkroom *croom;
120    int lowx, lowy;
121    register int hix, hiy;
122    boolean lit;
123    schar rtype;
124    boolean special;
125    boolean is_room;
126{
127	register int x, y;
128	struct rm *lev;
129
130	/* locations might bump level edges in wall-less rooms */
131	/* add/subtract 1 to allow for edge locations */
132	if(!lowx) lowx++;
133	if(!lowy) lowy++;
134	if(hix >= COLNO-1) hix = COLNO-2;
135	if(hiy >= ROWNO-1) hiy = ROWNO-2;
136
137	if(lit) {
138		for(x = lowx-1; x <= hix+1; x++) {
139			lev = &levl[x][max(lowy-1,0)];
140			for(y = lowy-1; y <= hiy+1; y++)
141				lev++->lit = 1;
142		}
143		croom->rlit = 1;
144	} else
145		croom->rlit = 0;
146
147	croom->lx = lowx;
148	croom->hx = hix;
149	croom->ly = lowy;
150	croom->hy = hiy;
151	croom->rtype = rtype;
152	croom->doorct = 0;
153	/* if we're not making a vault, doorindex will still be 0
154	 * if we are, we'll have problems adding niches to the previous room
155	 * unless fdoor is at least doorindex
156	 */
157	croom->fdoor = doorindex;
158	croom->irregular = FALSE;
159
160	croom->nsubrooms = 0;
161	croom->sbrooms[0] = (struct mkroom *) 0;
162	if (!special) {
163	    for(x = lowx-1; x <= hix+1; x++)
164		for(y = lowy-1; y <= hiy+1; y += (hiy-lowy+2)) {
165		    levl[x][y].typ = HWALL;
166		    levl[x][y].horizontal = 1;	/* For open/secret doors. */
167		}
168	    for(x = lowx-1; x <= hix+1; x += (hix-lowx+2))
169		for(y = lowy; y <= hiy; y++) {
170		    levl[x][y].typ = VWALL;
171		    levl[x][y].horizontal = 0;	/* For open/secret doors. */
172		}
173	    for(x = lowx; x <= hix; x++) {
174		lev = &levl[x][lowy];
175		for(y = lowy; y <= hiy; y++)
176		    lev++->typ = ROOM;
177	    }
178	    if (is_room) {
179		levl[lowx-1][lowy-1].typ = TLCORNER;
180		levl[hix+1][lowy-1].typ = TRCORNER;
181		levl[lowx-1][hiy+1].typ = BLCORNER;
182		levl[hix+1][hiy+1].typ = BRCORNER;
183	    } else {	/* a subroom */
184		wallification(lowx-1, lowy-1, hix+1, hiy+1);
185	    }
186	}
187}
188
189
190void
191add_room(lowx, lowy, hix, hiy, lit, rtype, special)
192register int lowx, lowy, hix, hiy;
193boolean lit;
194schar rtype;
195boolean special;
196{
197	register struct mkroom *croom;
198
199	croom = &rooms[nroom];
200	do_room_or_subroom(croom, lowx, lowy, hix, hiy, lit,
201					    rtype, special, (boolean) TRUE);
202	croom++;
203	croom->hx = -1;
204	nroom++;
205}
206
207void
208add_subroom(proom, lowx, lowy, hix, hiy, lit, rtype, special)
209struct mkroom *proom;
210register int lowx, lowy, hix, hiy;
211boolean lit;
212schar rtype;
213boolean special;
214{
215	register struct mkroom *croom;
216
217	croom = &subrooms[nsubroom];
218	do_room_or_subroom(croom, lowx, lowy, hix, hiy, lit,
219					    rtype, special, (boolean) FALSE);
220	proom->sbrooms[proom->nsubrooms++] = croom;
221	croom++;
222	croom->hx = -1;
223	nsubroom++;
224}
225
226STATIC_OVL void
227makerooms()
228{
229	boolean tried_vault = FALSE;
230
231	/* make rooms until satisfied */
232	/* rnd_rect() will returns 0 if no more rects are available... */
233	while(nroom < MAXNROFROOMS && rnd_rect()) {
234		if(nroom >= (MAXNROFROOMS/6) && rn2(2) && !tried_vault) {
235			tried_vault = TRUE;
236			if (create_vault()) {
237				vault_x = rooms[nroom].lx;
238				vault_y = rooms[nroom].ly;
239				rooms[nroom].hx = -1;
240			}
241		} else
242		    if (!create_room(-1, -1, -1, -1, -1, -1, OROOM, -1))
243			return;
244	}
245	return;
246}
247
248STATIC_OVL void
249join(a,b,nxcor)
250register int a, b;
251boolean nxcor;
252{
253	coord cc,tt, org, dest;
254	register xchar tx, ty, xx, yy;
255	register struct mkroom *croom, *troom;
256	register int dx, dy;
257
258	croom = &rooms[a];
259	troom = &rooms[b];
260
261	/* find positions cc and tt for doors in croom and troom
262	   and direction for a corridor between them */
263
264	if(troom->hx < 0 || croom->hx < 0 || doorindex >= DOORMAX) return;
265	if(troom->lx > croom->hx) {
266		dx = 1;
267		dy = 0;
268		xx = croom->hx+1;
269		tx = troom->lx-1;
270		finddpos(&cc, xx, croom->ly, xx, croom->hy);
271		finddpos(&tt, tx, troom->ly, tx, troom->hy);
272	} else if(troom->hy < croom->ly) {
273		dy = -1;
274		dx = 0;
275		yy = croom->ly-1;
276		finddpos(&cc, croom->lx, yy, croom->hx, yy);
277		ty = troom->hy+1;
278		finddpos(&tt, troom->lx, ty, troom->hx, ty);
279	} else if(troom->hx < croom->lx) {
280		dx = -1;
281		dy = 0;
282		xx = croom->lx-1;
283		tx = troom->hx+1;
284		finddpos(&cc, xx, croom->ly, xx, croom->hy);
285		finddpos(&tt, tx, troom->ly, tx, troom->hy);
286	} else {
287		dy = 1;
288		dx = 0;
289		yy = croom->hy+1;
290		ty = troom->ly-1;
291		finddpos(&cc, croom->lx, yy, croom->hx, yy);
292		finddpos(&tt, troom->lx, ty, troom->hx, ty);
293	}
294	xx = cc.x;
295	yy = cc.y;
296	tx = tt.x - dx;
297	ty = tt.y - dy;
298	if(nxcor && levl[xx+dx][yy+dy].typ)
299		return;
300	if (okdoor(xx,yy) || !nxcor)
301	    dodoor(xx,yy,croom);
302
303	org.x  = xx+dx; org.y  = yy+dy;
304	dest.x = tx; dest.y = ty;
305
306	if (!dig_corridor(&org, &dest, nxcor,
307			level.flags.arboreal ? ROOM : CORR, STONE))
308	    return;
309
310	/* we succeeded in digging the corridor */
311	if (okdoor(tt.x, tt.y) || !nxcor)
312	    dodoor(tt.x, tt.y, troom);
313
314	if(smeq[a] < smeq[b])
315		smeq[b] = smeq[a];
316	else
317		smeq[a] = smeq[b];
318}
319
320void
321makecorridors()
322{
323	int a, b, i;
324	boolean any = TRUE;
325
326	for(a = 0; a < nroom-1; a++) {
327		join(a, a+1, FALSE);
328		if(!rn2(50)) break; /* allow some randomness */
329	}
330	for(a = 0; a < nroom-2; a++)
331	    if(smeq[a] != smeq[a+2])
332		join(a, a+2, FALSE);
333	for(a = 0; any && a < nroom; a++) {
334	    any = FALSE;
335	    for(b = 0; b < nroom; b++)
336		if(smeq[a] != smeq[b]) {
337		    join(a, b, FALSE);
338		    any = TRUE;
339		}
340	}
341	if(nroom > 2)
342	    for(i = rn2(nroom) + 4; i; i--) {
343		a = rn2(nroom);
344		b = rn2(nroom-2);
345		if(b >= a) b += 2;
346		join(a, b, TRUE);
347	    }
348}
349
350void
351add_door(x,y,aroom)
352register int x, y;
353register struct mkroom *aroom;
354{
355	register struct mkroom *broom;
356	register int tmp;
357
358	aroom->doorct++;
359	broom = aroom+1;
360	if(broom->hx < 0)
361		tmp = doorindex;
362	else
363		for(tmp = doorindex; tmp > broom->fdoor; tmp--)
364			doors[tmp] = doors[tmp-1];
365	doorindex++;
366	doors[tmp].x = x;
367	doors[tmp].y = y;
368	for( ; broom->hx >= 0; broom++) broom->fdoor++;
369}
370
371STATIC_OVL void
372dosdoor(x,y,aroom,type)
373register xchar x, y;
374register struct mkroom *aroom;
375register int type;
376{
377	boolean shdoor = ((*in_rooms(x, y, SHOPBASE))? TRUE : FALSE);
378
379	if(!IS_WALL(levl[x][y].typ)) /* avoid SDOORs on already made doors */
380		type = DOOR;
381	levl[x][y].typ = type;
382	if(type == DOOR) {
383	    if(!rn2(3)) {      /* is it a locked door, closed, or a doorway? */
384		if(!rn2(5))
385		    levl[x][y].doormask = D_ISOPEN;
386		else if(!rn2(6))
387		    levl[x][y].doormask = D_LOCKED;
388		else
389		    levl[x][y].doormask = D_CLOSED;
390
391		if (levl[x][y].doormask != D_ISOPEN && !shdoor &&
392		    level_difficulty() >= 5 && !rn2(25))
393		    levl[x][y].doormask |= D_TRAPPED;
394	    } else
395#ifdef STUPID
396		if (shdoor)
397			levl[x][y].doormask = D_ISOPEN;
398		else
399			levl[x][y].doormask = D_NODOOR;
400#else
401		levl[x][y].doormask = (shdoor ? D_ISOPEN : D_NODOOR);
402#endif
403	    if(levl[x][y].doormask & D_TRAPPED) {
404		struct monst *mtmp;
405
406		if (level_difficulty() >= 9 && !rn2(5) &&
407		   !((mvitals[PM_SMALL_MIMIC].mvflags & G_GONE) &&
408		     (mvitals[PM_LARGE_MIMIC].mvflags & G_GONE) &&
409		     (mvitals[PM_GIANT_MIMIC].mvflags & G_GONE))) {
410		    /* make a mimic instead */
411		    levl[x][y].doormask = D_NODOOR;
412		    mtmp = makemon(mkclass(S_MIMIC,0), x, y, NO_MM_FLAGS);
413		    if (mtmp)
414			set_mimic_sym(mtmp);
415		}
416	    }
417	    /* newsym(x,y); */
418	} else { /* SDOOR */
419		if(shdoor || !rn2(5))	levl[x][y].doormask = D_LOCKED;
420		else			levl[x][y].doormask = D_CLOSED;
421
422		if(!shdoor && level_difficulty() >= 4 && !rn2(20))
423		    levl[x][y].doormask |= D_TRAPPED;
424	}
425
426	add_door(x,y,aroom);
427}
428
429STATIC_OVL boolean
430place_niche(aroom,dy,xx,yy)
431register struct mkroom *aroom;
432int *dy, *xx, *yy;
433{
434	coord dd;
435
436	if(rn2(2)) {
437	    *dy = 1;
438	    finddpos(&dd, aroom->lx, aroom->hy+1, aroom->hx, aroom->hy+1);
439	} else {
440	    *dy = -1;
441	    finddpos(&dd, aroom->lx, aroom->ly-1, aroom->hx, aroom->ly-1);
442	}
443	*xx = dd.x;
444	*yy = dd.y;
445	return((boolean)((isok(*xx,*yy+*dy) && levl[*xx][*yy+*dy].typ == STONE)
446	    && (isok(*xx,*yy-*dy) && !IS_POOL(levl[*xx][*yy-*dy].typ)
447				  && !IS_FURNITURE(levl[*xx][*yy-*dy].typ))));
448}
449
450/* there should be one of these per trap, in the same order as trap.h */
451static NEARDATA const char *trap_engravings[TRAPNUM] = {
452			(char *)0, (char *)0, (char *)0, (char *)0, (char *)0,
453			(char *)0, (char *)0, (char *)0, (char *)0, (char *)0,
454			(char *)0, (char *)0, (char *)0, (char *)0,
455			/* 14..16: trap door, teleport, level-teleport */
456			"Vlad was here", "ad aerarium", "ad aerarium",
457			(char *)0, (char *)0, (char *)0, (char *)0, (char *)0,
458			(char *)0,
459};
460
461STATIC_OVL void
462makeniche(trap_type)
463int trap_type;
464{
465	register struct mkroom *aroom;
466	register struct rm *rm;
467	register int vct = 8;
468	int dy, xx, yy;
469	register struct trap *ttmp;
470
471	if(doorindex < DOORMAX)
472	  while(vct--) {
473	    aroom = &rooms[rn2(nroom)];
474	    if(aroom->rtype != OROOM) continue;	/* not an ordinary room */
475	    if(aroom->doorct == 1 && rn2(5)) continue;
476	    if(!place_niche(aroom,&dy,&xx,&yy)) continue;
477
478	    rm = &levl[xx][yy+dy];
479	    if(trap_type || !rn2(4)) {
480
481		rm->typ = SCORR;
482		if(trap_type) {
483		    if((trap_type == HOLE || trap_type == TRAPDOOR)
484			&& !Can_fall_thru(&u.uz))
485			trap_type = ROCKTRAP;
486		    ttmp = maketrap(xx, yy+dy, trap_type);
487		    if (ttmp) {
488			if (trap_type != ROCKTRAP) ttmp->once = 1;
489			if (trap_engravings[trap_type]) {
490			    make_engr_at(xx, yy-dy,
491				     trap_engravings[trap_type], 0L, DUST);
492			    wipe_engr_at(xx, yy-dy, 5); /* age it a little */
493			}
494		    }
495		}
496		dosdoor(xx, yy, aroom, SDOOR);
497	    } else {
498		rm->typ = CORR;
499		if(rn2(7))
500		    dosdoor(xx, yy, aroom, rn2(5) ? SDOOR : DOOR);
501		else {
502		    if (!level.flags.noteleport)
503			(void) mksobj_at(SCR_TELEPORTATION,
504					 xx, yy+dy, TRUE, FALSE);
505		    if (!rn2(3)) (void) mkobj_at(0, xx, yy+dy, TRUE);
506		}
507	    }
508	    return;
509	}
510}
511
512STATIC_OVL void
513make_niches()
514{
515	register int ct = rnd((nroom>>1) + 1), dep = depth(&u.uz);
516
517	boolean	ltptr = (!level.flags.noteleport && dep > 15),
518		vamp = (dep > 5 && dep < 25);
519
520	while(ct--) {
521		if (ltptr && !rn2(6)) {
522			ltptr = FALSE;
523			makeniche(LEVEL_TELEP);
524		} else if (vamp && !rn2(6)) {
525			vamp = FALSE;
526			makeniche(TRAPDOOR);
527		} else	makeniche(NO_TRAP);
528	}
529}
530
531STATIC_OVL void
532makevtele()
533{
534	makeniche(TELEP_TRAP);
535}
536
537/* clear out various globals that keep information on the current level.
538 * some of this is only necessary for some types of levels (maze, normal,
539 * special) but it's easier to put it all in one place than make sure
540 * each type initializes what it needs to separately.
541 */
542STATIC_OVL void
543clear_level_structures()
544{
545	static struct rm zerorm = { cmap_to_glyph(S_stone),
546						0, 0, 0, 0, 0, 0, 0, 0 };
547	register int x,y;
548	register struct rm *lev;
549
550	for(x=0; x<COLNO; x++) {
551	    lev = &levl[x][0];
552	    for(y=0; y<ROWNO; y++) {
553		*lev++ = zerorm;
554#ifdef MICROPORT_BUG
555		level.objects[x][y] = (struct obj *)0;
556		level.monsters[x][y] = (struct monst *)0;
557#endif
558	    }
559	}
560#ifndef MICROPORT_BUG
561	(void) memset((genericptr_t)level.objects, 0, sizeof(level.objects));
562	(void) memset((genericptr_t)level.monsters, 0, sizeof(level.monsters));
563#endif
564	level.objlist = (struct obj *)0;
565	level.buriedobjlist = (struct obj *)0;
566	level.monlist = (struct monst *)0;
567	level.damagelist = (struct damage *)0;
568
569	level.flags.nfountains = 0;
570	level.flags.nsinks = 0;
571	level.flags.has_shop = 0;
572	level.flags.has_vault = 0;
573	level.flags.has_zoo = 0;
574	level.flags.has_court = 0;
575	level.flags.has_morgue = level.flags.graveyard = 0;
576	level.flags.has_beehive = 0;
577	level.flags.has_barracks = 0;
578	level.flags.has_temple = 0;
579	level.flags.has_swamp = 0;
580	level.flags.noteleport = 0;
581	level.flags.hardfloor = 0;
582	level.flags.nommap = 0;
583	level.flags.hero_memory = 1;
584	level.flags.shortsighted = 0;
585	level.flags.arboreal = 0;
586	level.flags.is_maze_lev = 0;
587	level.flags.is_cavernous_lev = 0;
588
589	nroom = 0;
590	rooms[0].hx = -1;
591	nsubroom = 0;
592	subrooms[0].hx = -1;
593	doorindex = 0;
594	init_rect();
595	init_vault();
596	xdnstair = ydnstair = xupstair = yupstair = 0;
597	sstairs.sx = sstairs.sy = 0;
598	xdnladder = ydnladder = xupladder = yupladder = 0;
599	made_branch = FALSE;
600	clear_regions();
601}
602
603STATIC_OVL void
604makelevel()
605{
606	register struct mkroom *croom, *troom;
607	register int tryct;
608	register int x, y;
609	struct monst *tmonst;	/* always put a web with a spider */
610	branch *branchp;
611	int room_threshold;
612
613	if(wiz1_level.dlevel == 0) init_dungeons();
614	oinit();	/* assign level dependent obj probabilities */
615	clear_level_structures();
616
617	{
618	    register s_level *slev = Is_special(&u.uz);
619
620	    /* check for special levels */
621#ifdef REINCARNATION
622	    if (slev && !Is_rogue_level(&u.uz))
623#else
624	    if (slev)
625#endif
626	    {
627		    makemaz(slev->proto);
628		    return;
629	    } else if (dungeons[u.uz.dnum].proto[0]) {
630		    makemaz("");
631		    return;
632	    } else if (In_mines(&u.uz)) {
633		    makemaz("minefill");
634		    return;
635	    } else if (In_quest(&u.uz)) {
636		    char	fillname[9];
637		    s_level	*loc_lev;
638
639		    Sprintf(fillname, "%s-loca", urole.filecode);
640		    loc_lev = find_level(fillname);
641
642		    Sprintf(fillname, "%s-fil", urole.filecode);
643		    Strcat(fillname,
644			   (u.uz.dlevel < loc_lev->dlevel.dlevel) ? "a" : "b");
645		    makemaz(fillname);
646		    return;
647	    } else if(In_hell(&u.uz) ||
648		  (rn2(5) && u.uz.dnum == medusa_level.dnum
649			  && depth(&u.uz) > depth(&medusa_level))) {
650		    makemaz("");
651		    return;
652	    }
653	}
654
655	/* otherwise, fall through - it's a "regular" level. */
656
657#ifdef REINCARNATION
658	if (Is_rogue_level(&u.uz)) {
659		makeroguerooms();
660		makerogueghost();
661	} else
662#endif
663		makerooms();
664	sort_rooms();
665
666	/* construct stairs (up and down in different rooms if possible) */
667	croom = &rooms[rn2(nroom)];
668	if (!Is_botlevel(&u.uz))
669	     mkstairs(somex(croom), somey(croom), 0, croom);	/* down */
670	if (nroom > 1) {
671	    troom = croom;
672	    croom = &rooms[rn2(nroom-1)];
673	    if (croom == troom) croom++;
674	}
675
676	if (u.uz.dlevel != 1) {
677	    xchar sx, sy;
678	    do {
679		sx = somex(croom);
680		sy = somey(croom);
681	    } while(occupied(sx, sy));
682	    mkstairs(sx, sy, 1, croom);	/* up */
683	}
684
685	branchp = Is_branchlev(&u.uz);	/* possible dungeon branch */
686	room_threshold = branchp ? 4 : 3; /* minimum number of rooms needed
687					     to allow a random special room */
688#ifdef REINCARNATION
689	if (Is_rogue_level(&u.uz)) goto skip0;
690#endif
691	makecorridors();
692	make_niches();
693
694	/* make a secret treasure vault, not connected to the rest */
695	if(do_vault()) {
696		xchar w,h;
697#ifdef NETHACK_DEBUG
698		debugpline("trying to make a vault...");
699#endif
700		w = 1;
701		h = 1;
702		if (check_room(&vault_x, &w, &vault_y, &h, TRUE)) {
703		    fill_vault:
704			add_room(vault_x, vault_y, vault_x+w,
705				 vault_y+h, TRUE, VAULT, FALSE);
706			level.flags.has_vault = 1;
707			++room_threshold;
708			fill_room(&rooms[nroom - 1], FALSE);
709			mk_knox_portal(vault_x+w, vault_y+h);
710			if(!level.flags.noteleport && !rn2(3)) makevtele();
711		} else if(rnd_rect() && create_vault()) {
712			vault_x = rooms[nroom].lx;
713			vault_y = rooms[nroom].ly;
714			if (check_room(&vault_x, &w, &vault_y, &h, TRUE))
715				goto fill_vault;
716			else
717				rooms[nroom].hx = -1;
718		}
719	}
720
721    {
722	register int u_depth = depth(&u.uz);
723
724#ifdef WIZARD
725	if(wizard && nh_getenv("SHOPTYPE")) mkroom(SHOPBASE); else
726#endif
727	if (u_depth > 1 &&
728	    u_depth < depth(&medusa_level) &&
729	    nroom >= room_threshold &&
730	    rn2(u_depth) < 3) mkroom(SHOPBASE);
731	else if (u_depth > 4 && !rn2(6)) mkroom(COURT);
732	else if (u_depth > 5 && !rn2(8) &&
733	   !(mvitals[PM_LEPRECHAUN].mvflags & G_GONE)) mkroom(LEPREHALL);
734	else if (u_depth > 6 && !rn2(7)) mkroom(ZOO);
735	else if (u_depth > 8 && !rn2(5)) mkroom(TEMPLE);
736	else if (u_depth > 9 && !rn2(5) &&
737	   !(mvitals[PM_KILLER_BEE].mvflags & G_GONE)) mkroom(BEEHIVE);
738	else if (u_depth > 11 && !rn2(6)) mkroom(MORGUE);
739	else if (u_depth > 12 && !rn2(8)) mkroom(ANTHOLE);
740	else if (u_depth > 14 && !rn2(4) &&
741	   !(mvitals[PM_SOLDIER].mvflags & G_GONE)) mkroom(BARRACKS);
742	else if (u_depth > 15 && !rn2(6)) mkroom(SWAMP);
743	else if (u_depth > 16 && !rn2(8) &&
744	   !(mvitals[PM_COCKATRICE].mvflags & G_GONE)) mkroom(COCKNEST);
745    }
746
747#ifdef REINCARNATION
748skip0:
749#endif
750	/* Place multi-dungeon branch. */
751	place_branch(branchp, 0, 0);
752
753	/* for each room: put things inside */
754	for(croom = rooms; croom->hx > 0; croom++) {
755		if(croom->rtype != OROOM) continue;
756
757		/* put a sleeping monster inside */
758		/* Note: monster may be on the stairs. This cannot be
759		   avoided: maybe the player fell through a trap door
760		   while a monster was on the stairs. Conclusion:
761		   we have to check for monsters on the stairs anyway. */
762
763		if(u.uhave.amulet || !rn2(3)) {
764		    x = somex(croom); y = somey(croom);
765		    tmonst = makemon((struct permonst *) 0, x,y,NO_MM_FLAGS);
766		    if (tmonst && tmonst->data == &mons[PM_GIANT_SPIDER] &&
767			    !occupied(x, y))
768			(void) maketrap(x, y, WEB);
769		}
770		/* put traps and mimics inside */
771		goldseen = FALSE;
772		x = 8 - (level_difficulty()/6);
773		if (x <= 1) x = 2;
774		while (!rn2(x))
775		    mktrap(0,0,croom,(coord*)0);
776		if (!goldseen && !rn2(3))
777		    (void) mkgold(0L, somex(croom), somey(croom));
778#ifdef REINCARNATION
779		if(Is_rogue_level(&u.uz)) goto skip_nonrogue;
780#endif
781		if(!rn2(10)) mkfount(0,croom);
782#ifdef SINKS
783		if(!rn2(60)) mksink(croom);
784#endif
785		if(!rn2(60)) mkaltar(croom);
786		x = 80 - (depth(&u.uz) * 2);
787		if (x < 2) x = 2;
788		if(!rn2(x)) mkgrave(croom);
789
790		/* put statues inside */
791		if(!rn2(20))
792		    (void) mkcorpstat(STATUE, (struct monst *)0,
793				      (struct permonst *)0,
794				      somex(croom), somey(croom), TRUE);
795		/* put box/chest inside;
796		 *  40% chance for at least 1 box, regardless of number
797		 *  of rooms; about 5 - 7.5% for 2 boxes, least likely
798		 *  when few rooms; chance for 3 or more is neglible.
799		 */
800		if(!rn2(nroom * 5 / 2))
801		    (void) mksobj_at((rn2(3)) ? LARGE_BOX : CHEST,
802				     somex(croom), somey(croom), TRUE, FALSE);
803
804		/* maybe make some graffiti */
805		if(!rn2(27 + 3 * abs(depth(&u.uz)))) {
806		    char buf[BUFSZ];
807		    const char *mesg = random_engraving(buf);
808		    if (mesg) {
809			do {
810			    x = somex(croom);  y = somey(croom);
811			} while(levl[x][y].typ != ROOM && !rn2(40));
812			if (!(IS_POOL(levl[x][y].typ) ||
813			      IS_FURNITURE(levl[x][y].typ)))
814			    make_engr_at(x, y, mesg, 0L, MARK);
815		    }
816		}
817
818#ifdef REINCARNATION
819	skip_nonrogue:
820#endif
821		if(!rn2(3)) {
822		    (void) mkobj_at(0, somex(croom), somey(croom), TRUE);
823		    tryct = 0;
824		    while(!rn2(5)) {
825			if(++tryct > 100) {
826			    impossible("tryct overflow4");
827			    break;
828			}
829			(void) mkobj_at(0, somex(croom), somey(croom), TRUE);
830		    }
831		}
832	}
833}
834
835/*
836 *	Place deposits of minerals (gold and misc gems) in the stone
837 *	surrounding the rooms on the map.
838 *	Also place kelp in water.
839 */
840STATIC_OVL void
841mineralize()
842{
843	s_level *sp;
844	struct obj *otmp;
845	int goldprob, gemprob, x, y, cnt;
846
847
848	/* Place kelp, except on the plane of water */
849	if (In_endgame(&u.uz)) return;
850	for (x = 2; x < (COLNO - 2); x++)
851	    for (y = 1; y < (ROWNO - 1); y++)
852		if ((levl[x][y].typ == POOL && !rn2(10)) ||
853			(levl[x][y].typ == MOAT && !rn2(30)))
854		    (void) mksobj_at(KELP_FROND, x, y, TRUE, FALSE);
855
856	/* determine if it is even allowed;
857	   almost all special levels are excluded */
858	if (In_hell(&u.uz) || In_V_tower(&u.uz) ||
859#ifdef REINCARNATION
860		Is_rogue_level(&u.uz) ||
861#endif
862		level.flags.arboreal ||
863		((sp = Is_special(&u.uz)) != 0 && !Is_oracle_level(&u.uz)
864					&& (!In_mines(&u.uz) || sp->flags.town)
865	    )) return;
866
867	/* basic level-related probabilities */
868	goldprob = 20 + depth(&u.uz) / 3;
869	gemprob = goldprob / 4;
870
871	/* mines have ***MORE*** goodies - otherwise why mine? */
872	if (In_mines(&u.uz)) {
873	    goldprob *= 2;
874	    gemprob *= 3;
875	} else if (In_quest(&u.uz)) {
876	    goldprob /= 4;
877	    gemprob /= 6;
878	}
879
880	/*
881	 * Seed rock areas with gold and/or gems.
882	 * We use fairly low level object handling to avoid unnecessary
883	 * overhead from placing things in the floor chain prior to burial.
884	 */
885	for (x = 2; x < (COLNO - 2); x++)
886	  for (y = 1; y < (ROWNO - 1); y++)
887	    if (levl[x][y+1].typ != STONE) {	 /* <x,y> spot not eligible */
888		y += 2;		/* next two spots aren't eligible either */
889	    } else if (levl[x][y].typ != STONE) { /* this spot not eligible */
890		y += 1;		/* next spot isn't eligible either */
891	    } else if (!(levl[x][y].wall_info & W_NONDIGGABLE) &&
892		  levl[x][y-1].typ   == STONE &&
893		  levl[x+1][y-1].typ == STONE && levl[x-1][y-1].typ == STONE &&
894		  levl[x+1][y].typ   == STONE && levl[x-1][y].typ   == STONE &&
895		  levl[x+1][y+1].typ == STONE && levl[x-1][y+1].typ == STONE) {
896		if (rn2(1000) < goldprob) {
897		    if ((otmp = mksobj(GOLD_PIECE, FALSE, FALSE)) != 0) {
898			otmp->ox = x,  otmp->oy = y;
899			otmp->quan = 1L + rnd(goldprob * 3);
900			otmp->owt = weight(otmp);
901			if (!rn2(3)) add_to_buried(otmp);
902			else place_object(otmp, x, y);
903		    }
904		}
905		if (rn2(1000) < gemprob) {
906		    for (cnt = rnd(2 + dunlev(&u.uz) / 3); cnt > 0; cnt--)
907			if ((otmp = mkobj(GEM_CLASS, FALSE)) != 0) {
908			    if (otmp->otyp == ROCK) {
909				dealloc_obj(otmp);	/* discard it */
910			    } else {
911				otmp->ox = x,  otmp->oy = y;
912				if (!rn2(3)) add_to_buried(otmp);
913				else place_object(otmp, x, y);
914			    }
915		    }
916		}
917	    }
918}
919
920void
921mklev()
922{
923	struct mkroom *croom;
924
925	if(getbones()) return;
926	in_mklev = TRUE;
927	makelevel();
928	bound_digging();
929	mineralize();
930	in_mklev = FALSE;
931	/* has_morgue gets cleared once morgue is entered; graveyard stays
932	   set (graveyard might already be set even when has_morgue is clear
933	   [see fixup_special()], so don't update it unconditionally) */
934	if (level.flags.has_morgue)
935	    level.flags.graveyard = 1;
936	if (!level.flags.is_maze_lev) {
937	    for (croom = &rooms[0]; croom != &rooms[nroom]; croom++)
938#ifdef SPECIALIZATION
939		topologize(croom, FALSE);
940#else
941		topologize(croom);
942#endif
943	}
944	set_wall_state();
945}
946
947void
948#ifdef SPECIALIZATION
949topologize(croom, do_ordinary)
950register struct mkroom *croom;
951boolean do_ordinary;
952#else
953topologize(croom)
954register struct mkroom *croom;
955#endif
956{
957	register int x, y, roomno = (croom - rooms) + ROOMOFFSET;
958	register int lowx = croom->lx, lowy = croom->ly;
959	register int hix = croom->hx, hiy = croom->hy;
960#ifdef SPECIALIZATION
961	register schar rtype = croom->rtype;
962#endif
963	register int subindex, nsubrooms = croom->nsubrooms;
964
965	/* skip the room if already done; i.e. a shop handled out of order */
966	/* also skip if this is non-rectangular (it _must_ be done already) */
967	if ((int) levl[lowx][lowy].roomno == roomno || croom->irregular)
968	    return;
969#ifdef SPECIALIZATION
970# ifdef REINCARNATION
971	if (Is_rogue_level(&u.uz))
972	    do_ordinary = TRUE;		/* vision routine helper */
973# endif
974	if ((rtype != OROOM) || do_ordinary)
975#endif
976	{
977	    /* do innards first */
978	    for(x = lowx; x <= hix; x++)
979		for(y = lowy; y <= hiy; y++)
980#ifdef SPECIALIZATION
981		    if (rtype == OROOM)
982			levl[x][y].roomno = NO_ROOM;
983		    else
984#endif
985			levl[x][y].roomno = roomno;
986	    /* top and bottom edges */
987	    for(x = lowx-1; x <= hix+1; x++)
988		for(y = lowy-1; y <= hiy+1; y += (hiy-lowy+2)) {
989		    levl[x][y].edge = 1;
990		    if (levl[x][y].roomno)
991			levl[x][y].roomno = SHARED;
992		    else
993			levl[x][y].roomno = roomno;
994		}
995	    /* sides */
996	    for(x = lowx-1; x <= hix+1; x += (hix-lowx+2))
997		for(y = lowy; y <= hiy; y++) {
998		    levl[x][y].edge = 1;
999		    if (levl[x][y].roomno)
1000			levl[x][y].roomno = SHARED;
1001		    else
1002			levl[x][y].roomno = roomno;
1003		}
1004	}
1005	/* subrooms */
1006	for (subindex = 0; subindex < nsubrooms; subindex++)
1007#ifdef SPECIALIZATION
1008		topologize(croom->sbrooms[subindex], (rtype != OROOM));
1009#else
1010		topologize(croom->sbrooms[subindex]);
1011#endif
1012}
1013
1014/* Find an unused room for a branch location. */
1015STATIC_OVL struct mkroom *
1016find_branch_room(mp)
1017    coord *mp;
1018{
1019    struct mkroom *croom = 0;
1020
1021    if (nroom == 0) {
1022	mazexy(mp);		/* already verifies location */
1023    } else {
1024	/* not perfect - there may be only one stairway */
1025	if(nroom > 2) {
1026	    int tryct = 0;
1027
1028	    do
1029		croom = &rooms[rn2(nroom)];
1030	    while((croom == dnstairs_room || croom == upstairs_room ||
1031		  croom->rtype != OROOM) && (++tryct < 100));
1032	} else
1033	    croom = &rooms[rn2(nroom)];
1034
1035	do {
1036	    if (!somexy(croom, mp))
1037		impossible("Can't place branch!");
1038	} while(occupied(mp->x, mp->y) ||
1039	    (levl[mp->x][mp->y].typ != CORR && levl[mp->x][mp->y].typ != ROOM));
1040    }
1041    return croom;
1042}
1043
1044/* Find the room for (x,y).  Return null if not in a room. */
1045STATIC_OVL struct mkroom *
1046pos_to_room(x, y)
1047    xchar x, y;
1048{
1049    int i;
1050    struct mkroom *curr;
1051
1052    for (curr = rooms, i = 0; i < nroom; curr++, i++)
1053	if (inside_room(curr, x, y)) return curr;;
1054    return (struct mkroom *) 0;
1055}
1056
1057
1058/* If given a branch, randomly place a special stair or portal. */
1059void
1060place_branch(br, x, y)
1061branch *br;	/* branch to place */
1062xchar x, y;	/* location */
1063{
1064	coord	      m;
1065	d_level	      *dest;
1066	boolean	      make_stairs;
1067	struct mkroom *br_room;
1068
1069	/*
1070	 * Return immediately if there is no branch to make or we have
1071	 * already made one.  This routine can be called twice when
1072	 * a special level is loaded that specifies an SSTAIR location
1073	 * as a favored spot for a branch.
1074	 */
1075	if (!br || made_branch) return;
1076
1077	if (!x) {	/* find random coordinates for branch */
1078	    br_room = find_branch_room(&m);
1079	    x = m.x;
1080	    y = m.y;
1081	} else {
1082	    br_room = pos_to_room(x, y);
1083	}
1084
1085	if (on_level(&br->end1, &u.uz)) {
1086	    /* we're on end1 */
1087	    make_stairs = br->type != BR_NO_END1;
1088	    dest = &br->end2;
1089	} else {
1090	    /* we're on end2 */
1091	    make_stairs = br->type != BR_NO_END2;
1092	    dest = &br->end1;
1093	}
1094
1095	if (br->type == BR_PORTAL) {
1096	    mkportal(x, y, dest->dnum, dest->dlevel);
1097	} else if (make_stairs) {
1098	    sstairs.sx = x;
1099	    sstairs.sy = y;
1100	    sstairs.up = (char) on_level(&br->end1, &u.uz) ?
1101					    br->end1_up : !br->end1_up;
1102	    assign_level(&sstairs.tolev, dest);
1103	    sstairs_room = br_room;
1104
1105	    levl[x][y].ladder = sstairs.up ? LA_UP : LA_DOWN;
1106	    levl[x][y].typ = STAIRS;
1107	}
1108	/*
1109	 * Set made_branch to TRUE even if we didn't make a stairwell (i.e.
1110	 * make_stairs is false) since there is currently only one branch
1111	 * per level, if we failed once, we're going to fail again on the
1112	 * next call.
1113	 */
1114	made_branch = TRUE;
1115}
1116
1117STATIC_OVL boolean
1118bydoor(x, y)
1119register xchar x, y;
1120{
1121	register int typ;
1122
1123	if (isok(x+1, y)) {
1124		typ = levl[x+1][y].typ;
1125		if (IS_DOOR(typ) || typ == SDOOR) return TRUE;
1126	}
1127	if (isok(x-1, y)) {
1128		typ = levl[x-1][y].typ;
1129		if (IS_DOOR(typ) || typ == SDOOR) return TRUE;
1130	}
1131	if (isok(x, y+1)) {
1132		typ = levl[x][y+1].typ;
1133		if (IS_DOOR(typ) || typ == SDOOR) return TRUE;
1134	}
1135	if (isok(x, y-1)) {
1136		typ = levl[x][y-1].typ;
1137		if (IS_DOOR(typ) || typ == SDOOR) return TRUE;
1138	}
1139	return FALSE;
1140}
1141
1142/* see whether it is allowable to create a door at [x,y] */
1143int
1144okdoor(x,y)
1145register xchar x, y;
1146{
1147	register boolean near_door = bydoor(x, y);
1148
1149	return((levl[x][y].typ == HWALL || levl[x][y].typ == VWALL) &&
1150			doorindex < DOORMAX && !near_door);
1151}
1152
1153void
1154dodoor(x,y,aroom)
1155register int x, y;
1156register struct mkroom *aroom;
1157{
1158	if(doorindex >= DOORMAX) {
1159		impossible("DOORMAX exceeded?");
1160		return;
1161	}
1162
1163	dosdoor(x,y,aroom,rn2(8) ? DOOR : SDOOR);
1164}
1165
1166boolean
1167occupied(x, y)
1168register xchar x, y;
1169{
1170	return((boolean)(t_at(x, y)
1171		|| IS_FURNITURE(levl[x][y].typ)
1172		|| is_lava(x,y)
1173		|| is_pool(x,y)
1174		|| invocation_pos(x,y)
1175		));
1176}
1177
1178/* make a trap somewhere (in croom if mazeflag = 0 && !tm) */
1179/* if tm != null, make trap at that location */
1180void
1181mktrap(num, mazeflag, croom, tm)
1182register int num, mazeflag;
1183register struct mkroom *croom;
1184coord *tm;
1185{
1186	register int kind;
1187	coord m;
1188
1189	/* no traps in pools */
1190	if (tm && is_pool(tm->x,tm->y)) return;
1191
1192	if (num > 0 && num < TRAPNUM) {
1193	    kind = num;
1194#ifdef REINCARNATION
1195	} else if (Is_rogue_level(&u.uz)) {
1196	    switch (rn2(7)) {
1197		default: kind = BEAR_TRAP; break; /* 0 */
1198		case 1: kind = ARROW_TRAP; break;
1199		case 2: kind = DART_TRAP; break;
1200		case 3: kind = TRAPDOOR; break;
1201		case 4: kind = PIT; break;
1202		case 5: kind = SLP_GAS_TRAP; break;
1203		case 6: kind = RUST_TRAP; break;
1204	    }
1205#endif
1206	} else if (Inhell && !rn2(5)) {
1207	    /* bias the frequency of fire traps in Gehennom */
1208	    kind = FIRE_TRAP;
1209	} else {
1210	    unsigned lvl = level_difficulty();
1211
1212	    do {
1213		kind = rnd(TRAPNUM-1);
1214		/* reject "too hard" traps */
1215		switch (kind) {
1216		    case MAGIC_PORTAL:
1217			kind = NO_TRAP; break;
1218		    case ROLLING_BOULDER_TRAP:
1219		    case SLP_GAS_TRAP:
1220			if (lvl < 2) kind = NO_TRAP; break;
1221		    case LEVEL_TELEP:
1222			if (lvl < 5 || level.flags.noteleport)
1223			    kind = NO_TRAP; break;
1224		    case SPIKED_PIT:
1225			if (lvl < 5) kind = NO_TRAP; break;
1226		    case LANDMINE:
1227			if (lvl < 6) kind = NO_TRAP; break;
1228		    case WEB:
1229			if (lvl < 7) kind = NO_TRAP; break;
1230		    case STATUE_TRAP:
1231		    case POLY_TRAP:
1232			if (lvl < 8) kind = NO_TRAP; break;
1233		    case FIRE_TRAP:
1234			if (!Inhell) kind = NO_TRAP; break;
1235		    case TELEP_TRAP:
1236			if (level.flags.noteleport) kind = NO_TRAP; break;
1237		    case HOLE:
1238			/* make these much less often than other traps */
1239			if (rn2(7)) kind = NO_TRAP; break;
1240		}
1241	    } while (kind == NO_TRAP);
1242	}
1243
1244	if ((kind == TRAPDOOR || kind == HOLE) && !Can_fall_thru(&u.uz))
1245		kind = ROCKTRAP;
1246
1247	if (tm)
1248	    m = *tm;
1249	else {
1250	    register int tryct = 0;
1251	    boolean avoid_boulder = (kind == PIT || kind == SPIKED_PIT ||
1252				     kind == TRAPDOOR || kind == HOLE);
1253
1254	    do {
1255		if (++tryct > 200)
1256		    return;
1257		if (mazeflag)
1258		    mazexy(&m);
1259		else if (!somexy(croom,&m))
1260		    return;
1261	    } while (occupied(m.x, m.y) ||
1262			(avoid_boulder && sobj_at(BOULDER, m.x, m.y)));
1263	}
1264
1265	(void) maketrap(m.x, m.y, kind);
1266	if (kind == WEB) (void) makemon(&mons[PM_GIANT_SPIDER],
1267						m.x, m.y, NO_MM_FLAGS);
1268}
1269
1270void
1271mkstairs(x, y, up, croom)
1272xchar x, y;
1273char  up;
1274struct mkroom *croom;
1275{
1276	if (!x) {
1277	    impossible("mkstairs:  bogus stair attempt at <%d,%d>", x, y);
1278	    return;
1279	}
1280
1281	/*
1282	 * We can't make a regular stair off an end of the dungeon.  This
1283	 * attempt can happen when a special level is placed at an end and
1284	 * has an up or down stair specified in its description file.
1285	 */
1286	if ((dunlev(&u.uz) == 1 && up) ||
1287			(dunlev(&u.uz) == dunlevs_in_dungeon(&u.uz) && !up))
1288	    return;
1289
1290	if(up) {
1291		xupstair = x;
1292		yupstair = y;
1293		upstairs_room = croom;
1294	} else {
1295		xdnstair = x;
1296		ydnstair = y;
1297		dnstairs_room = croom;
1298	}
1299
1300	levl[x][y].typ = STAIRS;
1301	levl[x][y].ladder = up ? LA_UP : LA_DOWN;
1302}
1303
1304STATIC_OVL
1305void
1306mkfount(mazeflag,croom)
1307register int mazeflag;
1308register struct mkroom *croom;
1309{
1310	coord m;
1311	register int tryct = 0;
1312
1313	do {
1314	    if(++tryct > 200) return;
1315	    if(mazeflag)
1316		mazexy(&m);
1317	    else
1318		if (!somexy(croom, &m))
1319		    return;
1320	} while(occupied(m.x, m.y) || bydoor(m.x, m.y));
1321
1322	/* Put a fountain at m.x, m.y */
1323	levl[m.x][m.y].typ = FOUNTAIN;
1324	/* Is it a "blessed" fountain? (affects drinking from fountain) */
1325	if(!rn2(7)) levl[m.x][m.y].blessedftn = 1;
1326
1327	level.flags.nfountains++;
1328}
1329
1330#ifdef SINKS
1331STATIC_OVL void
1332mksink(croom)
1333register struct mkroom *croom;
1334{
1335	coord m;
1336	register int tryct = 0;
1337
1338	do {
1339	    if(++tryct > 200) return;
1340	    if (!somexy(croom, &m))
1341		return;
1342	} while(occupied(m.x, m.y) || bydoor(m.x, m.y));
1343
1344	/* Put a sink at m.x, m.y */
1345	levl[m.x][m.y].typ = SINK;
1346
1347	level.flags.nsinks++;
1348}
1349#endif /* SINKS */
1350
1351
1352STATIC_OVL void
1353mkaltar(croom)
1354register struct mkroom *croom;
1355{
1356	coord m;
1357	register int tryct = 0;
1358	aligntyp al;
1359
1360	if (croom->rtype != OROOM) return;
1361
1362	do {
1363	    if(++tryct > 200) return;
1364	    if (!somexy(croom, &m))
1365		return;
1366	} while (occupied(m.x, m.y) || bydoor(m.x, m.y));
1367
1368	/* Put an altar at m.x, m.y */
1369	levl[m.x][m.y].typ = ALTAR;
1370
1371	/* -1 - A_CHAOTIC, 0 - A_NEUTRAL, 1 - A_LAWFUL */
1372	al = rn2((int)A_LAWFUL+2) - 1;
1373	levl[m.x][m.y].altarmask = Align2amask( al );
1374}
1375
1376static void
1377mkgrave(croom)
1378struct mkroom *croom;
1379{
1380	coord m;
1381	register int tryct = 0;
1382	register struct obj *otmp;
1383	boolean dobell = !rn2(10);
1384
1385
1386	if(croom->rtype != OROOM) return;
1387
1388	do {
1389	    if(++tryct > 200) return;
1390	    if (!somexy(croom, &m))
1391		return;
1392	} while (occupied(m.x, m.y) || bydoor(m.x, m.y));
1393
1394	/* Put a grave at m.x, m.y */
1395	make_grave(m.x, m.y, dobell ? "Saved by the bell!" : (char *) 0);
1396
1397	/* Possibly fill it with objects */
1398	if (!rn2(3)) (void) mkgold(0L, m.x, m.y);
1399	for (tryct = rn2(5); tryct; tryct--) {
1400	    otmp = mkobj(RANDOM_CLASS, TRUE);
1401	    if (!otmp) return;
1402	    curse(otmp);
1403	    otmp->ox = m.x;
1404	    otmp->oy = m.y;
1405	    add_to_buried(otmp);
1406	}
1407
1408	/* Leave a bell, in case we accidentally buried someone alive */
1409	if (dobell) (void) mksobj_at(BELL, m.x, m.y, TRUE, FALSE);
1410	return;
1411}
1412
1413
1414/* maze levels have slightly different constraints from normal levels */
1415#define x_maze_min 2
1416#define y_maze_min 2
1417/*
1418 * Major level transmutation: add a set of stairs (to the Sanctum) after
1419 * an earthquake that leaves behind a a new topology, centered at inv_pos.
1420 * Assumes there are no rooms within the invocation area and that inv_pos
1421 * is not too close to the edge of the map.  Also assume the hero can see,
1422 * which is guaranteed for normal play due to the fact that sight is needed
1423 * to read the Book of the Dead.
1424 */
1425void
1426mkinvokearea()
1427{
1428    int dist;
1429    xchar xmin = inv_pos.x, xmax = inv_pos.x;
1430    xchar ymin = inv_pos.y, ymax = inv_pos.y;
1431    register xchar i;
1432
1433    pline_The("floor shakes violently under you!");
1434    pline_The("walls around you begin to bend and crumble!");
1435    display_nhwindow(WIN_MESSAGE, TRUE);
1436
1437    mkinvpos(xmin, ymin, 0);		/* middle, before placing stairs */
1438
1439    for(dist = 1; dist < 7; dist++) {
1440	xmin--; xmax++;
1441
1442	/* top and bottom */
1443	if(dist != 3) { /* the area is wider that it is high */
1444	    ymin--; ymax++;
1445	    for(i = xmin+1; i < xmax; i++) {
1446		mkinvpos(i, ymin, dist);
1447		mkinvpos(i, ymax, dist);
1448	    }
1449	}
1450
1451	/* left and right */
1452	for(i = ymin; i <= ymax; i++) {
1453	    mkinvpos(xmin, i, dist);
1454	    mkinvpos(xmax, i, dist);
1455	}
1456
1457	flush_screen(1);	/* make sure the new glyphs shows up */
1458	delay_output();
1459    }
1460
1461    You("are standing at the top of a stairwell leading down!");
1462    mkstairs(u.ux, u.uy, 0, (struct mkroom *)0); /* down */
1463    newsym(u.ux, u.uy);
1464    vision_full_recalc = 1;	/* everything changed */
1465}
1466
1467/* Change level topology.  Boulders in the vicinity are eliminated.
1468 * Temporarily overrides vision in the name of a nice effect.
1469 */
1470STATIC_OVL void
1471mkinvpos(x,y,dist)
1472xchar x,y;
1473int dist;
1474{
1475    struct trap *ttmp;
1476    struct obj *otmp;
1477    boolean make_rocks;
1478    register struct rm *lev = &levl[x][y];
1479
1480    /* clip at existing map borders if necessary */
1481    if (!within_bounded_area(x, y, x_maze_min + 1, y_maze_min + 1,
1482				   x_maze_max - 1, y_maze_max - 1)) {
1483	/* only outermost 2 columns and/or rows may be truncated due to edge */
1484	if (dist < (7 - 2))
1485	    panic("mkinvpos: <%d,%d> (%d) off map edge!", x, y, dist);
1486	return;
1487    }
1488
1489    /* clear traps */
1490    if ((ttmp = t_at(x,y)) != 0) deltrap(ttmp);
1491
1492    /* clear boulders; leave some rocks for non-{moat|trap} locations */
1493    make_rocks = (dist != 1 && dist != 4 && dist != 5) ? TRUE : FALSE;
1494    while ((otmp = sobj_at(BOULDER, x, y)) != 0) {
1495	if (make_rocks) {
1496	    fracture_rock(otmp);
1497	    make_rocks = FALSE;		/* don't bother with more rocks */
1498	} else {
1499	    obj_extract_self(otmp);
1500	    obfree(otmp, (struct obj *)0);
1501	}
1502    }
1503    unblock_point(x,y);	/* make sure vision knows this location is open */
1504
1505    /* fake out saved state */
1506    lev->seenv = 0;
1507    lev->doormask = 0;
1508    if(dist < 6) lev->lit = TRUE;
1509    lev->waslit = TRUE;
1510    lev->horizontal = FALSE;
1511    viz_array[y][x] = (dist < 6 ) ?
1512	(IN_SIGHT|COULD_SEE) : /* short-circuit vision recalc */
1513	COULD_SEE;
1514
1515    switch(dist) {
1516    case 1: /* fire traps */
1517	if (is_pool(x,y)) break;
1518	lev->typ = ROOM;
1519	ttmp = maketrap(x, y, FIRE_TRAP);
1520	if (ttmp) ttmp->tseen = TRUE;
1521	break;
1522    case 0: /* lit room locations */
1523    case 2:
1524    case 3:
1525    case 6: /* unlit room locations */
1526	lev->typ = ROOM;
1527	break;
1528    case 4: /* pools (aka a wide moat) */
1529    case 5:
1530	lev->typ = MOAT;
1531	/* No kelp! */
1532	break;
1533    default:
1534	impossible("mkinvpos called with dist %d", dist);
1535	break;
1536    }
1537
1538    /* display new value of position; could have a monster/object on it */
1539    newsym(x,y);
1540}
1541
1542/*
1543 * The portal to Ludios is special.  The entrance can only occur within a
1544 * vault in the main dungeon at a depth greater than 10.  The Ludios branch
1545 * structure reflects this by having a bogus "source" dungeon:  the value
1546 * of n_dgns (thus, Is_branchlev() will never find it).
1547 *
1548 * Ludios will remain isolated until the branch is corrected by this function.
1549 */
1550STATIC_OVL void
1551mk_knox_portal(x, y)
1552xchar x, y;
1553{
1554	extern int n_dgns;		/* from dungeon.c */
1555	d_level *source;
1556	branch *br;
1557	schar u_depth;
1558
1559	br = dungeon_branch("Fort Ludios");
1560	if (on_level(&knox_level, &br->end1)) {
1561	    source = &br->end2;
1562	} else {
1563	    /* disallow Knox branch on a level with one branch already */
1564	    if(Is_branchlev(&u.uz))
1565		return;
1566	    source = &br->end1;
1567	}
1568
1569	/* Already set or 2/3 chance of deferring until a later level. */
1570	if (source->dnum < n_dgns || (rn2(3)
1571#ifdef WIZARD
1572				      && !wizard
1573#endif
1574				      )) return;
1575
1576	if (! (u.uz.dnum == oracle_level.dnum	    /* in main dungeon */
1577		&& !at_dgn_entrance("The Quest")    /* but not Quest's entry */
1578		&& (u_depth = depth(&u.uz)) > 10    /* beneath 10 */
1579		&& u_depth < depth(&medusa_level))) /* and above Medusa */
1580	    return;
1581
1582	/* Adjust source to be current level and re-insert branch. */
1583	*source = u.uz;
1584	insert_branch(br, TRUE);
1585
1586#ifdef NETHACK_DEBUG
1587	pline("Made knox portal.");
1588#endif
1589	place_branch(br, x, y);
1590}
1591
1592/*mklev.c*/
1593