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