1/*	SCCS Id: @(#)sp_lev.c	3.4	2001/09/06	*/
2/*	Copyright (c) 1989 by Jean-Christophe Collet */
3/* NetHack may be freely redistributed.  See license for details. */
4
5/*
6 * This file contains the various functions that are related to the special
7 * levels.
8 * It contains also the special level loader.
9 *
10 */
11
12#include "hack.h"
13#include "dlb.h"
14/* #define DEBUG */	/* uncomment to enable code debugging */
15
16#ifdef NETHACK_DEBUG
17# ifdef WIZARD
18#define debugpline	if (wizard) pline
19# else
20#define debugpline	pline
21# endif
22#endif
23
24#include "sp_lev.h"
25#include "rect.h"
26
27extern void FDECL(mkmap, (lev_init *));
28
29STATIC_DCL void FDECL(get_room_loc, (schar *, schar *, struct mkroom *));
30STATIC_DCL void FDECL(get_free_room_loc, (schar *, schar *, struct mkroom *));
31STATIC_DCL void FDECL(create_trap, (trap *, struct mkroom *));
32STATIC_DCL int FDECL(noncoalignment, (ALIGNTYP_P));
33STATIC_DCL void FDECL(create_monster, (monster *, struct mkroom *));
34STATIC_DCL void FDECL(create_object, (object *, struct mkroom *));
35STATIC_DCL void FDECL(create_engraving, (engraving *,struct mkroom *));
36STATIC_DCL void FDECL(create_stairs, (stair *, struct mkroom *));
37STATIC_DCL void FDECL(create_altar, (altar *, struct mkroom *));
38STATIC_DCL void FDECL(create_gold, (gold *, struct mkroom *));
39STATIC_DCL void FDECL(create_feature, (int,int,struct mkroom *,int));
40STATIC_DCL boolean FDECL(search_door, (struct mkroom *, xchar *, xchar *,
41					XCHAR_P, int));
42STATIC_DCL void NDECL(fix_stair_rooms);
43STATIC_DCL void FDECL(create_corridor, (corridor *));
44
45STATIC_DCL boolean FDECL(create_subroom, (struct mkroom *, XCHAR_P, XCHAR_P,
46					XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P));
47
48#define LEFT	1
49#define H_LEFT	2
50#define CENTER	3
51#define H_RIGHT	4
52#define RIGHT	5
53
54#define TOP	1
55#define BOTTOM	5
56
57#define sq(x) ((x)*(x))
58
59#define XLIM	4
60#define YLIM	3
61
62#define Fread	(void)dlb_fread
63#define Fgetc	(schar)dlb_fgetc
64#define New(type)		(type *) alloc(sizeof(type))
65#define NewTab(type, size)	(type **) alloc(sizeof(type *) * (unsigned)size)
66#define Free(ptr)		if(ptr) free((genericptr_t) (ptr))
67
68static NEARDATA walk walklist[50];
69extern int min_rx, max_rx, min_ry, max_ry; /* from mkmap.c */
70
71static char Map[COLNO][ROWNO];
72static char robjects[10], rloc_x[10], rloc_y[10], rmonst[10];
73static aligntyp	ralign[3] = { AM_CHAOTIC, AM_NEUTRAL, AM_LAWFUL };
74static NEARDATA xchar xstart, ystart;
75static NEARDATA char xsize, ysize;
76
77STATIC_DCL void FDECL(set_wall_property, (XCHAR_P,XCHAR_P,XCHAR_P,XCHAR_P,int));
78STATIC_DCL int NDECL(rnddoor);
79STATIC_DCL int NDECL(rndtrap);
80STATIC_DCL void FDECL(get_location, (schar *,schar *,int));
81STATIC_DCL void FDECL(sp_lev_shuffle, (char *,char *,int));
82STATIC_DCL void FDECL(light_region, (region *));
83STATIC_DCL void FDECL(load_common_data, (dlb *,int));
84STATIC_DCL void FDECL(load_one_monster, (dlb *,monster *));
85STATIC_DCL void FDECL(load_one_object, (dlb *,object *));
86STATIC_DCL void FDECL(load_one_engraving, (dlb *,engraving *));
87STATIC_DCL boolean FDECL(load_rooms, (dlb *));
88STATIC_DCL void FDECL(maze1xy, (coord *,int));
89STATIC_DCL boolean FDECL(load_maze, (dlb *));
90STATIC_DCL void FDECL(create_door, (room_door *, struct mkroom *));
91STATIC_DCL void FDECL(free_rooms,(room **, int));
92STATIC_DCL void FDECL(build_room, (room *, room*));
93
94char *lev_message = 0;
95lev_region *lregions = 0;
96int num_lregions = 0;
97lev_init init_lev;
98
99/*
100 * Make walls of the area (x1, y1, x2, y2) non diggable/non passwall-able
101 */
102
103STATIC_OVL void
104set_wall_property(x1,y1,x2,y2, prop)
105xchar x1, y1, x2, y2;
106int prop;
107{
108	register xchar x, y;
109
110	for(y = y1; y <= y2; y++)
111	    for(x = x1; x <= x2; x++)
112		if(IS_STWALL(levl[x][y].typ))
113		    levl[x][y].wall_info |= prop;
114}
115
116/*
117 * Choose randomly the state (nodoor, open, closed or locked) for a door
118 */
119STATIC_OVL int
120rnddoor()
121{
122	int i = 1 << rn2(5);
123	i >>= 1;
124	return i;
125}
126
127/*
128 * Select a random trap
129 */
130STATIC_OVL int
131rndtrap()
132{
133	int rtrap;
134
135	do {
136	    rtrap = rnd(TRAPNUM-1);
137	    switch (rtrap) {
138	     case HOLE:		/* no random holes on special levels */
139	     case MAGIC_PORTAL:	rtrap = NO_TRAP;
140				break;
141	     case TRAPDOOR:	if (!Can_dig_down(&u.uz)) rtrap = NO_TRAP;
142				break;
143	     case LEVEL_TELEP:
144	     case TELEP_TRAP:	if (level.flags.noteleport) rtrap = NO_TRAP;
145				break;
146	     case ROLLING_BOULDER_TRAP:
147	     case ROCKTRAP:	if (In_endgame(&u.uz)) rtrap = NO_TRAP;
148				break;
149	    }
150	} while (rtrap == NO_TRAP);
151	return rtrap;
152}
153
154/*
155 * Coordinates in special level files are handled specially:
156 *
157 *	if x or y is -11, we generate a random coordinate.
158 *	if x or y is between -1 and -10, we read one from the corresponding
159 *	register (x0, x1, ... x9).
160 *	if x or y is nonnegative, we convert it from relative to the local map
161 *	to global coordinates.
162 *	The "humidity" flag is used to insure that engravings aren't
163 *	created underwater, or eels on dry land.
164 */
165#define DRY	0x1
166#define WET	0x2
167
168STATIC_DCL boolean FDECL(is_ok_location, (SCHAR_P, SCHAR_P, int));
169
170STATIC_OVL void
171get_location(x, y, humidity)
172schar *x, *y;
173int humidity;
174{
175	int cpt = 0;
176
177	if (*x >= 0) {			/* normal locations */
178		*x += xstart;
179		*y += ystart;
180	} else if (*x > -11) {		/* special locations */
181		*y = ystart + rloc_y[ - *y - 1];
182		*x = xstart + rloc_x[ - *x - 1];
183	} else {			/* random location */
184	    do {
185		*x = xstart + rn2((int)xsize);
186		*y = ystart + rn2((int)ysize);
187		if (is_ok_location(*x,*y,humidity)) break;
188	    } while (++cpt < 100);
189	    if (cpt >= 100) {
190		register int xx, yy;
191		/* last try */
192		for (xx = 0; xx < xsize; xx++)
193		    for (yy = 0; yy < ysize; yy++) {
194			*x = xstart + xx;
195			*y = ystart + yy;
196			if (is_ok_location(*x,*y,humidity)) goto found_it;
197		    }
198		panic("get_location:  can't find a place!");
199	    }
200	}
201found_it:;
202
203	if (!isok(*x,*y)) {
204	    impossible("get_location:  (%d,%d) out of bounds", *x, *y);
205	    *x = x_maze_max; *y = y_maze_max;
206	}
207}
208
209STATIC_OVL boolean
210is_ok_location(x, y, humidity)
211register schar x, y;
212register int humidity;
213{
214	register int typ;
215
216	if (Is_waterlevel(&u.uz)) return TRUE;	/* accept any spot */
217
218	if (humidity & DRY) {
219	    typ = levl[x][y].typ;
220	    if (typ == ROOM || typ == AIR ||
221		    typ == CLOUD || typ == ICE || typ == CORR)
222		return TRUE;
223	}
224	if (humidity & WET) {
225	    if (is_pool(x,y) || is_lava(x,y))
226		return TRUE;
227	}
228	return FALSE;
229}
230
231/*
232 * Shuffle the registers for locations, objects or monsters
233 */
234
235STATIC_OVL void
236sp_lev_shuffle(list1, list2, n)
237char list1[], list2[];
238int n;
239{
240	register int i, j;
241	register char k;
242
243	for (i = n - 1; i > 0; i--) {
244		if ((j = rn2(i + 1)) == i) continue;
245		k = list1[j];
246		list1[j] = list1[i];
247		list1[i] = k;
248		if (list2) {
249			k = list2[j];
250			list2[j] = list2[i];
251			list2[i] = k;
252		}
253	}
254}
255
256/*
257 * Get a relative position inside a room.
258 * negative values for x or y means RANDOM!
259 */
260
261STATIC_OVL void
262get_room_loc(x,y, croom)
263schar		*x, *y;
264struct mkroom	*croom;
265{
266	coord c;
267
268	if (*x <0 && *y <0) {
269		if (somexy(croom, &c)) {
270			*x = c.x;
271			*y = c.y;
272		} else
273		    panic("get_room_loc : can't find a place!");
274	} else {
275		if (*x < 0)
276		    *x = rn2(croom->hx - croom->lx + 1);
277		if (*y < 0)
278		    *y = rn2(croom->hy - croom->ly + 1);
279		*x += croom->lx;
280		*y += croom->ly;
281	}
282}
283
284/*
285 * Get a relative position inside a room.
286 * negative values for x or y means RANDOM!
287 */
288
289STATIC_OVL void
290get_free_room_loc(x,y, croom)
291schar		*x, *y;
292struct mkroom	*croom;
293{
294	schar try_x, try_y;
295	register int trycnt = 0;
296
297	do {
298	    try_x = *x,  try_y = *y;
299	    get_room_loc(&try_x, &try_y, croom);
300	} while (levl[try_x][try_y].typ != ROOM && ++trycnt <= 100);
301
302	if (trycnt > 100)
303	    panic("get_free_room_loc:  can't find a place!");
304	*x = try_x,  *y = try_y;
305}
306
307boolean
308check_room(lowx, ddx, lowy, ddy, vault)
309xchar *lowx, *ddx, *lowy, *ddy;
310boolean vault;
311{
312	register int x,y,hix = *lowx + *ddx, hiy = *lowy + *ddy;
313	register struct rm *lev;
314	int xlim, ylim, ymax;
315
316	xlim = XLIM + (vault ? 1 : 0);
317	ylim = YLIM + (vault ? 1 : 0);
318
319	if (*lowx < 3)		*lowx = 3;
320	if (*lowy < 2)		*lowy = 2;
321	if (hix > COLNO-3)	hix = COLNO-3;
322	if (hiy > ROWNO-3)	hiy = ROWNO-3;
323chk:
324	if (hix <= *lowx || hiy <= *lowy)	return FALSE;
325
326	/* check area around room (and make room smaller if necessary) */
327	for (x = *lowx - xlim; x<= hix + xlim; x++) {
328		if(x <= 0 || x >= COLNO) continue;
329		y = *lowy - ylim;	ymax = hiy + ylim;
330		if(y < 0) y = 0;
331		if(ymax >= ROWNO) ymax = (ROWNO-1);
332		lev = &levl[x][y];
333		for (; y <= ymax; y++) {
334			if (lev++->typ) {
335#ifdef NETHACK_DEBUG
336				if(!vault)
337				    debugpline("strange area [%d,%d] in check_room.",x,y);
338#endif
339				if (!rn2(3))	return FALSE;
340				if (x < *lowx)
341				    *lowx = x + xlim + 1;
342				else
343				    hix = x - xlim - 1;
344				if (y < *lowy)
345				    *lowy = y + ylim + 1;
346				else
347				    hiy = y - ylim - 1;
348				goto chk;
349			}
350		}
351	}
352	*ddx = hix - *lowx;
353	*ddy = hiy - *lowy;
354	return TRUE;
355}
356
357/*
358 * Create a new room.
359 * This is still very incomplete...
360 */
361
362boolean
363create_room(x,y,w,h,xal,yal,rtype,rlit)
364xchar	x,y;
365xchar	w,h;
366xchar	xal,yal;
367xchar	rtype, rlit;
368{
369	xchar	xabs, yabs;
370	int	wtmp, htmp, xaltmp, yaltmp, xtmp, ytmp;
371	NhRect	*r1 = 0, r2;
372	int	trycnt = 0;
373	boolean	vault = FALSE;
374	int	xlim = XLIM, ylim = YLIM;
375
376	if (rtype == -1)	/* Is the type random ? */
377	    rtype = OROOM;
378
379	if (rtype == VAULT) {
380		vault = TRUE;
381		xlim++;
382		ylim++;
383	}
384
385	/* on low levels the room is lit (usually) */
386	/* some other rooms may require lighting */
387
388	/* is light state random ? */
389	if (rlit == -1)
390	    rlit = (rnd(1+abs(depth(&u.uz))) < 11 && rn2(77)) ? TRUE : FALSE;
391
392	/*
393	 * Here we will try to create a room. If some parameters are
394	 * random we are willing to make several try before we give
395	 * it up.
396	 */
397	do {
398		xchar xborder, yborder;
399		wtmp = w; htmp = h;
400		xtmp = x; ytmp = y;
401		xaltmp = xal; yaltmp = yal;
402
403		/* First case : a totaly random room */
404
405		if((xtmp < 0 && ytmp <0 && wtmp < 0 && xaltmp < 0 &&
406		   yaltmp < 0) || vault) {
407			xchar hx, hy, lx, ly, dx, dy;
408			r1 = rnd_rect(); /* Get a random rectangle */
409
410			if (!r1) { /* No more free rectangles ! */
411#ifdef NETHACK_DEBUG
412				debugpline("No more rects...");
413#endif
414				return FALSE;
415			}
416			hx = r1->hx;
417			hy = r1->hy;
418			lx = r1->lx;
419			ly = r1->ly;
420			if (vault)
421			    dx = dy = 1;
422			else {
423				dx = 2 + rn2((hx-lx > 28) ? 12 : 8);
424				dy = 2 + rn2(4);
425				if(dx*dy > 50)
426				    dy = 50/dx;
427			}
428			xborder = (lx > 0 && hx < COLNO -1) ? 2*xlim : xlim+1;
429			yborder = (ly > 0 && hy < ROWNO -1) ? 2*ylim : ylim+1;
430			if(hx-lx < dx + 3 + xborder ||
431			   hy-ly < dy + 3 + yborder) {
432				r1 = 0;
433				continue;
434			}
435			xabs = lx + (lx > 0 ? xlim : 3)
436			    + rn2(hx - (lx>0?lx : 3) - dx - xborder + 1);
437			yabs = ly + (ly > 0 ? ylim : 2)
438			    + rn2(hy - (ly>0?ly : 2) - dy - yborder + 1);
439			if (ly == 0 && hy >= (ROWNO-1) &&
440			    (!nroom || !rn2(nroom)) && (yabs+dy > ROWNO/2)) {
441			    yabs = rn1(3, 2);
442			    if(nroom < 4 && dy>1) dy--;
443		        }
444			if (!check_room(&xabs, &dx, &yabs, &dy, vault)) {
445				r1 = 0;
446				continue;
447			}
448			wtmp = dx+1;
449			htmp = dy+1;
450			r2.lx = xabs-1; r2.ly = yabs-1;
451			r2.hx = xabs + wtmp;
452			r2.hy = yabs + htmp;
453		} else {	/* Only some parameters are random */
454			int rndpos = 0;
455			if (xtmp < 0 && ytmp < 0) { /* Position is RANDOM */
456				xtmp = rnd(5);
457				ytmp = rnd(5);
458				rndpos = 1;
459			}
460			if (wtmp < 0 || htmp < 0) { /* Size is RANDOM */
461				wtmp = rn1(15, 3);
462				htmp = rn1(8, 2);
463			}
464			if (xaltmp == -1) /* Horizontal alignment is RANDOM */
465			    xaltmp = rnd(3);
466			if (yaltmp == -1) /* Vertical alignment is RANDOM */
467			    yaltmp = rnd(3);
468
469			/* Try to generate real (absolute) coordinates here! */
470
471			xabs = (((xtmp-1) * COLNO) / 5) + 1;
472			yabs = (((ytmp-1) * ROWNO) / 5) + 1;
473			switch (xaltmp) {
474			      case LEFT:
475				break;
476			      case RIGHT:
477				xabs += (COLNO / 5) - wtmp;
478				break;
479			      case CENTER:
480				xabs += ((COLNO / 5) - wtmp) / 2;
481				break;
482			}
483			switch (yaltmp) {
484			      case TOP:
485				break;
486			      case BOTTOM:
487				yabs += (ROWNO / 5) - htmp;
488				break;
489			      case CENTER:
490				yabs += ((ROWNO / 5) - htmp) / 2;
491				break;
492			}
493
494			if (xabs + wtmp - 1 > COLNO - 2)
495			    xabs = COLNO - wtmp - 3;
496			if (xabs < 2)
497			    xabs = 2;
498			if (yabs + htmp - 1> ROWNO - 2)
499			    yabs = ROWNO - htmp - 3;
500			if (yabs < 2)
501			    yabs = 2;
502
503			/* Try to find a rectangle that fit our room ! */
504
505			r2.lx = xabs-1; r2.ly = yabs-1;
506			r2.hx = xabs + wtmp + rndpos;
507			r2.hy = yabs + htmp + rndpos;
508			r1 = get_rect(&r2);
509		}
510	} while (++trycnt <= 100 && !r1);
511	if (!r1) {	/* creation of room failed ? */
512		return FALSE;
513	}
514	split_rects(r1, &r2);
515
516	if (!vault) {
517		smeq[nroom] = nroom;
518		add_room(xabs, yabs, xabs+wtmp-1, yabs+htmp-1,
519			 rlit, rtype, FALSE);
520	} else {
521		rooms[nroom].lx = xabs;
522		rooms[nroom].ly = yabs;
523	}
524	return TRUE;
525}
526
527/*
528 * Create a subroom in room proom at pos x,y with width w & height h.
529 * x & y are relative to the parent room.
530 */
531
532STATIC_OVL boolean
533create_subroom(proom, x, y, w,  h, rtype, rlit)
534struct mkroom *proom;
535xchar x,y;
536xchar w,h;
537xchar rtype, rlit;
538{
539	xchar width, height;
540
541	width = proom->hx - proom->lx + 1;
542	height = proom->hy - proom->ly + 1;
543
544	/* There is a minimum size for the parent room */
545	if (width < 4 || height < 4)
546	    return FALSE;
547
548	/* Check for random position, size, etc... */
549
550	if (w == -1)
551	    w = rnd(width - 3);
552	if (h == -1)
553	    h = rnd(height - 3);
554	if (x == -1)
555	    x = rnd(width - w - 1) - 1;
556	if (y == -1)
557	    y = rnd(height - h - 1) - 1;
558	if (x == 1)
559	    x = 0;
560	if (y == 1)
561	    y = 0;
562	if ((x + w + 1) == width)
563	    x++;
564	if ((y + h + 1) == height)
565	    y++;
566	if (rtype == -1)
567	    rtype = OROOM;
568	if (rlit == -1)
569	    rlit = (rnd(1+abs(depth(&u.uz))) < 11 && rn2(77)) ? TRUE : FALSE;
570	add_subroom(proom, proom->lx + x, proom->ly + y,
571		    proom->lx + x + w - 1, proom->ly + y + h - 1,
572		    rlit, rtype, FALSE);
573	return TRUE;
574}
575
576/*
577 * Create a new door in a room.
578 * It's placed on a wall (north, south, east or west).
579 */
580
581STATIC_OVL void
582create_door(dd, broom)
583room_door *dd;
584struct mkroom *broom;
585{
586	int	x, y;
587	int	trycnt = 0;
588
589	if (dd->secret == -1)
590	    dd->secret = rn2(2);
591
592	if (dd->mask == -1) {
593		/* is it a locked door, closed, or a doorway? */
594		if (!dd->secret) {
595			if(!rn2(3)) {
596				if(!rn2(5))
597				    dd->mask = D_ISOPEN;
598				else if(!rn2(6))
599				    dd->mask = D_LOCKED;
600				else
601				    dd->mask = D_CLOSED;
602				if (dd->mask != D_ISOPEN && !rn2(25))
603				    dd->mask |= D_TRAPPED;
604			} else
605			    dd->mask = D_NODOOR;
606		} else {
607			if(!rn2(5))	dd->mask = D_LOCKED;
608			else		dd->mask = D_CLOSED;
609
610			if(!rn2(20)) dd->mask |= D_TRAPPED;
611		}
612	}
613
614	do {
615		register int dwall, dpos;
616
617		dwall = dd->wall;
618		if (dwall == -1)	/* The wall is RANDOM */
619		    dwall = 1 << rn2(4);
620
621		dpos = dd->pos;
622		if (dpos == -1)	/* The position is RANDOM */
623		    dpos = rn2((dwall == W_WEST || dwall == W_EAST) ?
624			    (broom->hy - broom->ly) : (broom->hx - broom->lx));
625
626		/* Convert wall and pos into an absolute coordinate! */
627
628		switch (dwall) {
629		      case W_NORTH:
630			y = broom->ly - 1;
631			x = broom->lx + dpos;
632			break;
633		      case W_SOUTH:
634			y = broom->hy + 1;
635			x = broom->lx + dpos;
636			break;
637		      case W_WEST:
638			x = broom->lx - 1;
639			y = broom->ly + dpos;
640			break;
641		      case W_EAST:
642			x = broom->hx + 1;
643			y = broom->ly + dpos;
644			break;
645		      default:
646			x = y = 0;
647			panic("create_door: No wall for door!");
648			break;
649		}
650		if (okdoor(x,y))
651		    break;
652	} while (++trycnt <= 100);
653	if (trycnt > 100) {
654		impossible("create_door: Can't find a proper place!");
655		return;
656	}
657	add_door(x,y,broom);
658	levl[x][y].typ = (dd->secret ? SDOOR : DOOR);
659	levl[x][y].doormask = dd->mask;
660}
661
662/*
663 * Create a secret door in croom on any one of the specified walls.
664 */
665void
666create_secret_door(croom, walls)
667    struct mkroom *croom;
668    xchar walls; /* any of W_NORTH | W_SOUTH | W_EAST | W_WEST (or W_ANY) */
669{
670    xchar sx, sy; /* location of the secret door */
671    int count;
672
673    for(count = 0; count < 100; count++) {
674	sx = rn1(croom->hx - croom->lx + 1, croom->lx);
675	sy = rn1(croom->hy - croom->ly + 1, croom->ly);
676
677	switch(rn2(4)) {
678	case 0:  /* top */
679	    if(!(walls & W_NORTH)) continue;
680	    sy = croom->ly-1; break;
681	case 1: /* bottom */
682	    if(!(walls & W_SOUTH)) continue;
683	    sy = croom->hy+1; break;
684	case 2: /* left */
685	    if(!(walls & W_EAST)) continue;
686	    sx = croom->lx-1; break;
687	case 3: /* right */
688	    if(!(walls & W_WEST)) continue;
689	    sx = croom->hx+1; break;
690	}
691
692	if(okdoor(sx,sy)) {
693	    levl[sx][sy].typ = SDOOR;
694	    levl[sx][sy].doormask = D_CLOSED;
695	    add_door(sx,sy,croom);
696	    return;
697	}
698    }
699
700    impossible("couldn't create secret door on any walls 0x%x", walls);
701}
702
703/*
704 * Create a trap in a room.
705 */
706
707STATIC_OVL void
708create_trap(t,croom)
709trap	*t;
710struct mkroom	*croom;
711{
712    schar	x,y;
713    coord	tm;
714
715    if (rn2(100) < t->chance) {
716	x = t->x;
717	y = t->y;
718	if (croom)
719	    get_free_room_loc(&x, &y, croom);
720	else
721	    get_location(&x, &y, DRY);
722
723	tm.x = x;
724	tm.y = y;
725
726	mktrap(t->type, 1, (struct mkroom*) 0, &tm);
727    }
728}
729
730/*
731 * Create a monster in a room.
732 */
733
734STATIC_OVL int
735noncoalignment(alignment)
736aligntyp alignment;
737{
738	int k;
739
740	k = rn2(2);
741	if (!alignment)
742		return(k ? -1 : 1);
743	return(k ? -alignment : 0);
744}
745
746STATIC_OVL void
747create_monster(m,croom)
748monster	*m;
749struct mkroom	*croom;
750{
751    struct monst *mtmp;
752    schar x, y;
753    char class;
754    aligntyp amask;
755    coord cc;
756    struct permonst *pm;
757    unsigned g_mvflags;
758
759    if (rn2(100) < m->chance) {
760
761	if (m->class >= 0)
762	    class = (char) def_char_to_monclass((char)m->class);
763	else if (m->class > -11)
764	    class = (char) def_char_to_monclass(rmonst[- m->class - 1]);
765	else
766	    class = 0;
767
768	if (class == MAXMCLASSES)
769	    panic("create_monster: unknown monster class '%c'", m->class);
770
771	amask = (m->align == AM_SPLEV_CO) ?
772			Align2amask(u.ualignbase[A_ORIGINAL]) :
773		(m->align == AM_SPLEV_NONCO) ?
774			Align2amask(noncoalignment(u.ualignbase[A_ORIGINAL])) :
775		(m->align <= -11) ? induced_align(80) :
776		(m->align < 0 ? ralign[-m->align-1] : m->align);
777
778	if (!class)
779	    pm = (struct permonst *) 0;
780	else if (m->id != NON_PM) {
781	    pm = &mons[m->id];
782	    g_mvflags = (unsigned) mvitals[monsndx(pm)].mvflags;
783	    if ((pm->geno & G_UNIQ) && (g_mvflags & G_EXTINCT))
784		goto m_done;
785	    else if (g_mvflags & G_GONE)	/* genocided or extinct */
786		pm = (struct permonst *) 0;	/* make random monster */
787	} else {
788	    pm = mkclass(class,G_NOGEN);
789	    /* if we can't get a specific monster type (pm == 0) then the
790	       class has been genocided, so settle for a random monster */
791	}
792	if (In_mines(&u.uz) && pm && your_race(pm) &&
793			(Race_if(PM_DWARF) || Race_if(PM_GNOME)) && rn2(3))
794	    pm = (struct permonst *) 0;
795
796	x = m->x;
797	y = m->y;
798	if (croom)
799	    get_room_loc(&x, &y, croom);
800	else {
801	    if (!pm || !is_swimmer(pm))
802		get_location(&x, &y, DRY);
803	    else if (pm->mlet == S_EEL)
804		get_location(&x, &y, WET);
805	    else
806		get_location(&x, &y, DRY|WET);
807	}
808	/* try to find a close place if someone else is already there */
809	if (MON_AT(x,y) && enexto(&cc, x, y, pm))
810	    x = cc.x,  y = cc.y;
811
812	if(m->align != -12)
813	    mtmp = mk_roamer(pm, Amask2align(amask), x, y, m->peaceful);
814	else if(PM_ARCHEOLOGIST <= m->id && m->id <= PM_WIZARD)
815	         mtmp = mk_mplayer(pm, x, y, FALSE);
816	else mtmp = makemon(pm, x, y, NO_MM_FLAGS);
817
818	if (mtmp) {
819	    /* handle specific attributes for some special monsters */
820	    if (m->name.str) mtmp = christen_monst(mtmp, m->name.str);
821
822	    /*
823	     * This is currently hardwired for mimics only.  It should
824	     * eventually be expanded.
825	     */
826	    if (m->appear_as.str && mtmp->data->mlet == S_MIMIC) {
827		int i;
828
829		switch (m->appear) {
830		    case M_AP_NOTHING:
831			impossible(
832		"create_monster: mon has an appearance, \"%s\", but no type",
833				m->appear_as.str);
834			break;
835
836		    case M_AP_FURNITURE:
837			for (i = 0; i < MAXPCHARS; i++)
838			    if (!strcmp(defsyms[i].explanation,
839					m->appear_as.str))
840				break;
841			if (i == MAXPCHARS) {
842			    impossible(
843				"create_monster: can't find feature \"%s\"",
844				m->appear_as.str);
845			} else {
846			    mtmp->m_ap_type = M_AP_FURNITURE;
847			    mtmp->mappearance = i;
848			}
849			break;
850
851		    case M_AP_OBJECT:
852			for (i = 0; i < NUM_OBJECTS; i++)
853			    if (OBJ_NAME(objects[i]) &&
854				!strcmp(OBJ_NAME(objects[i]),m->appear_as.str))
855				break;
856			if (i == NUM_OBJECTS) {
857			    impossible(
858				"create_monster: can't find object \"%s\"",
859				m->appear_as.str);
860			} else {
861			    mtmp->m_ap_type = M_AP_OBJECT;
862			    mtmp->mappearance = i;
863			}
864			break;
865
866		    case M_AP_MONSTER:
867			/* note: mimics don't appear as monsters! */
868			/*	 (but chameleons can :-)	  */
869		    default:
870			impossible(
871		"create_monster: unimplemented mon appear type [%d,\"%s\"]",
872				m->appear, m->appear_as.str);
873			break;
874		}
875		if (does_block(x, y, &levl[x][y]))
876		    block_point(x, y);
877	    }
878
879	    if (m->peaceful >= 0) {
880		mtmp->mpeaceful = m->peaceful;
881		/* changed mpeaceful again; have to reset malign */
882		set_malign(mtmp);
883	    }
884	    if (m->asleep >= 0) {
885#ifdef UNIXPC
886		/* optimizer bug strikes again */
887		if (m->asleep)
888			mtmp->msleeping = 1;
889		else
890			mtmp->msleeping = 0;
891#else
892		mtmp->msleeping = m->asleep;
893#endif
894	    }
895	}
896
897    }		/* if (rn2(100) < m->chance) */
898 m_done:
899    Free(m->name.str);
900    Free(m->appear_as.str);
901}
902
903/*
904 * Create an object in a room.
905 */
906
907STATIC_OVL void
908create_object(o,croom)
909object	*o;
910struct mkroom	*croom;
911{
912    struct obj *otmp;
913    schar x, y;
914    char c;
915    boolean named;	/* has a name been supplied in level description? */
916
917    if (rn2(100) < o->chance) {
918	named = o->name.str ? TRUE : FALSE;
919
920	x = o->x; y = o->y;
921	if (croom)
922	    get_room_loc(&x, &y, croom);
923	else
924	    get_location(&x, &y, DRY);
925
926	if (o->class >= 0)
927	    c = o->class;
928	else if (o->class > -11)
929	    c = robjects[ -(o->class+1)];
930	else
931	    c = 0;
932
933	if (!c)
934	    otmp = mkobj_at(RANDOM_CLASS, x, y, !named);
935	else if (o->id != -1)
936	    otmp = mksobj_at(o->id, x, y, TRUE, !named);
937	else {
938	    /*
939	     * The special levels are compiled with the default "text" object
940	     * class characters.  We must convert them to the internal format.
941	     */
942	    char oclass = (char) def_char_to_objclass(c);
943
944	    if (oclass == MAXOCLASSES)
945		panic("create_object:  unexpected object class '%c'",c);
946
947	    /* KMH -- Create piles of gold properly */
948	    if (oclass == COIN_CLASS)
949		otmp = mkgold(0L, x, y);
950	    else
951		otmp = mkobj_at(oclass, x, y, !named);
952	}
953
954	if (o->spe != -127)	/* That means NOT RANDOM! */
955	    otmp->spe = (schar)o->spe;
956
957	switch (o->curse_state) {
958	      case 1:	bless(otmp); break; /* BLESSED */
959	      case 2:	unbless(otmp); uncurse(otmp); break; /* uncursed */
960	      case 3:	curse(otmp); break; /* CURSED */
961	      default:	break;	/* Otherwise it's random and we're happy
962				 * with what mkobj gave us! */
963	}
964
965	/*	corpsenm is "empty" if -1, random if -2, otherwise specific */
966	if (o->corpsenm == NON_PM - 1) otmp->corpsenm = rndmonnum();
967	else if (o->corpsenm != NON_PM) otmp->corpsenm = o->corpsenm;
968
969	/* assume we wouldn't be given an egg corpsenm unless it was
970	   hatchable */
971	if (otmp->otyp == EGG && otmp->corpsenm != NON_PM) {
972	    if (dead_species(otmp->otyp, TRUE))
973		kill_egg(otmp);	/* make sure nothing hatches */
974	    else
975		attach_egg_hatch_timeout(otmp);	/* attach new hatch timeout */
976	}
977
978	if (named)
979	    otmp = oname(otmp, o->name.str);
980
981	switch(o->containment) {
982	    static struct obj *container = 0;
983
984	    /* contents */
985	    case 1:
986		if (!container) {
987		    impossible("create_object: no container");
988		    break;
989		}
990		remove_object(otmp);
991		(void) add_to_container(container, otmp);
992		goto o_done;		/* don't stack, but do other cleanup */
993	    /* container */
994	    case 2:
995		delete_contents(otmp);
996		container = otmp;
997		break;
998	    /* nothing */
999	    case 0: break;
1000
1001	    default: impossible("containment type %d?", (int) o->containment);
1002	}
1003
1004	/* Medusa level special case: statues are petrified monsters, so they
1005	 * are not stone-resistant and have monster inventory.  They also lack
1006	 * other contents, but that can be specified as an empty container.
1007	 */
1008	if (o->id == STATUE && Is_medusa_level(&u.uz) &&
1009		    o->corpsenm == NON_PM) {
1010	    struct monst *was;
1011	    struct obj *obj;
1012	    int wastyp;
1013
1014	    /* Named random statues are of player types, and aren't stone-
1015	     * resistant (if they were, we'd have to reset the name as well as
1016	     * setting corpsenm).
1017	     */
1018	    for (wastyp = otmp->corpsenm; ; wastyp = rndmonnum()) {
1019		/* makemon without rndmonst() might create a group */
1020		was = makemon(&mons[wastyp], 0, 0, NO_MM_FLAGS);
1021		if (!resists_ston(was)) break;
1022		mongone(was);
1023	    }
1024	    otmp->corpsenm = wastyp;
1025	    while(was->minvent) {
1026		obj = was->minvent;
1027		obj->owornmask = 0;
1028		obj_extract_self(obj);
1029		(void) add_to_container(otmp, obj);
1030	    }
1031	    otmp->owt = weight(otmp);
1032	    mongone(was);
1033	}
1034
1035	stackobj(otmp);
1036
1037    }		/* if (rn2(100) < o->chance) */
1038 o_done:
1039    Free(o->name.str);
1040}
1041
1042/*
1043 * Randomly place a specific engraving, then release its memory.
1044 */
1045STATIC_OVL void
1046create_engraving(e, croom)
1047engraving *e;
1048struct mkroom *croom;
1049{
1050	xchar x, y;
1051
1052	x = e->x,  y = e->y;
1053	if (croom)
1054	    get_room_loc(&x, &y, croom);
1055	else
1056	    get_location(&x, &y, DRY);
1057
1058	make_engr_at(x, y, e->engr.str, 0L, e->etype);
1059	free((genericptr_t) e->engr.str);
1060}
1061
1062/*
1063 * Create stairs in a room.
1064 *
1065 */
1066
1067STATIC_OVL void
1068create_stairs(s,croom)
1069stair	*s;
1070struct mkroom	*croom;
1071{
1072	schar		x,y;
1073
1074	x = s->x; y = s->y;
1075	get_free_room_loc(&x, &y, croom);
1076	mkstairs(x,y,(char)s->up, croom);
1077}
1078
1079/*
1080 * Create an altar in a room.
1081 */
1082
1083STATIC_OVL void
1084create_altar(a, croom)
1085	altar		*a;
1086	struct mkroom	*croom;
1087{
1088	schar		sproom,x,y;
1089	aligntyp	amask;
1090	boolean		croom_is_temple = TRUE;
1091	int oldtyp;
1092
1093	x = a->x; y = a->y;
1094
1095	if (croom) {
1096	    get_free_room_loc(&x, &y, croom);
1097	    if (croom->rtype != TEMPLE)
1098		croom_is_temple = FALSE;
1099	} else {
1100	    get_location(&x, &y, DRY);
1101	    if ((sproom = (schar) *in_rooms(x, y, TEMPLE)) != 0)
1102		croom = &rooms[sproom - ROOMOFFSET];
1103	    else
1104		croom_is_temple = FALSE;
1105	}
1106
1107	/* check for existing features */
1108	oldtyp = levl[x][y].typ;
1109	if (oldtyp == STAIRS || oldtyp == LADDER)
1110	    return;
1111
1112	a->x = x;
1113	a->y = y;
1114
1115	/* Is the alignment random ?
1116	 * If so, it's an 80% chance that the altar will be co-aligned.
1117	 *
1118	 * The alignment is encoded as amask values instead of alignment
1119	 * values to avoid conflicting with the rest of the encoding,
1120	 * shared by many other parts of the special level code.
1121	 */
1122
1123	amask = (a->align == AM_SPLEV_CO) ?
1124			Align2amask(u.ualignbase[A_ORIGINAL]) :
1125		(a->align == AM_SPLEV_NONCO) ?
1126			Align2amask(noncoalignment(u.ualignbase[A_ORIGINAL])) :
1127		(a->align == -11) ? induced_align(80) :
1128		(a->align < 0 ? ralign[-a->align-1] : a->align);
1129
1130	levl[x][y].typ = ALTAR;
1131	levl[x][y].altarmask = amask;
1132
1133	if (a->shrine < 0) a->shrine = rn2(2);	/* handle random case */
1134
1135	if (oldtyp == FOUNTAIN)
1136	    level.flags.nfountains--;
1137	else if (oldtyp == SINK)
1138	    level.flags.nsinks--;
1139
1140	if (!croom_is_temple || !a->shrine) return;
1141
1142	if (a->shrine) {	/* Is it a shrine  or sanctum? */
1143	    priestini(&u.uz, croom, x, y, (a->shrine > 1));
1144	    levl[x][y].altarmask |= AM_SHRINE;
1145	    level.flags.has_temple = TRUE;
1146	}
1147}
1148
1149/*
1150 * Create a gold pile in a room.
1151 */
1152
1153STATIC_OVL void
1154create_gold(g,croom)
1155gold *g;
1156struct mkroom	*croom;
1157{
1158	schar		x,y;
1159
1160	x = g->x; y= g->y;
1161	if (croom)
1162	    get_room_loc(&x, &y, croom);
1163	else
1164	    get_location(&x, &y, DRY);
1165
1166	if (g->amount == -1)
1167	    g->amount = rnd(200);
1168	(void) mkgold((long) g->amount, x, y);
1169}
1170
1171/*
1172 * Create a feature (e.g a fountain) in a room.
1173 */
1174
1175STATIC_OVL void
1176create_feature(fx, fy, croom, typ)
1177int		fx, fy;
1178struct mkroom	*croom;
1179int		typ;
1180{
1181	schar		x,y;
1182	int		trycnt = 0;
1183
1184	x = fx;  y = fy;
1185	if (croom) {
1186	    if (x < 0 && y < 0)
1187		do {
1188		    x = -1;  y = -1;
1189		    get_room_loc(&x, &y, croom);
1190		} while (++trycnt <= 200 && occupied(x,y));
1191	    else
1192		get_room_loc(&x, &y, croom);
1193	    if(trycnt > 200)
1194		return;
1195	} else {
1196	    get_location(&x, &y, DRY);
1197	}
1198	/* Don't cover up an existing feature (particularly randomly
1199	   placed stairs).  However, if the _same_ feature is already
1200	   here, it came from the map drawing and we still need to
1201	   update the special counters. */
1202	if (IS_FURNITURE(levl[x][y].typ) && levl[x][y].typ != typ)
1203	    return;
1204
1205	levl[x][y].typ = typ;
1206	if (typ == FOUNTAIN)
1207	    level.flags.nfountains++;
1208	else if (typ == SINK)
1209	    level.flags.nsinks++;
1210}
1211
1212/*
1213 * Search for a door in a room on a specified wall.
1214 */
1215
1216STATIC_OVL boolean
1217search_door(croom,x,y,wall,cnt)
1218struct mkroom *croom;
1219xchar *x, *y;
1220xchar wall;
1221int cnt;
1222{
1223	int dx, dy;
1224	int xx,yy;
1225
1226	switch(wall) {
1227	      case W_NORTH:
1228		dy = 0; dx = 1;
1229		xx = croom->lx;
1230		yy = croom->hy + 1;
1231		break;
1232	      case W_SOUTH:
1233		dy = 0; dx = 1;
1234		xx = croom->lx;
1235		yy = croom->ly - 1;
1236		break;
1237	      case W_EAST:
1238		dy = 1; dx = 0;
1239		xx = croom->hx + 1;
1240		yy = croom->ly;
1241		break;
1242	      case W_WEST:
1243		dy = 1; dx = 0;
1244		xx = croom->lx - 1;
1245		yy = croom->ly;
1246		break;
1247	      default:
1248		dx = dy = xx = yy = 0;
1249		panic("search_door: Bad wall!");
1250		break;
1251	}
1252	while (xx <= croom->hx+1 && yy <= croom->hy+1) {
1253		if (IS_DOOR(levl[xx][yy].typ) || levl[xx][yy].typ == SDOOR) {
1254			*x = xx;
1255			*y = yy;
1256			if (cnt-- <= 0)
1257			    return TRUE;
1258		}
1259		xx += dx;
1260		yy += dy;
1261	}
1262	return FALSE;
1263}
1264
1265/*
1266 * Dig a corridor between two points.
1267 */
1268
1269boolean
1270dig_corridor(org,dest,nxcor,ftyp,btyp)
1271coord *org, *dest;
1272boolean nxcor;
1273schar ftyp, btyp;
1274{
1275	register int dx=0, dy=0, dix, diy, cct;
1276	register struct rm *crm;
1277	register int tx, ty, xx, yy;
1278
1279	xx = org->x;  yy = org->y;
1280	tx = dest->x; ty = dest->y;
1281	if (xx <= 0 || yy <= 0 || tx <= 0 || ty <= 0 ||
1282	    xx > COLNO-1 || tx > COLNO-1 ||
1283	    yy > ROWNO-1 || ty > ROWNO-1) {
1284#ifdef NETHACK_DEBUG
1285		debugpline("dig_corridor: bad coords : (%d,%d) (%d,%d).",
1286			   xx,yy,tx,ty);
1287#endif
1288		return FALSE;
1289	}
1290	if (tx > xx)		dx = 1;
1291	else if (ty > yy)	dy = 1;
1292	else if (tx < xx)	dx = -1;
1293	else			dy = -1;
1294
1295	xx -= dx;
1296	yy -= dy;
1297	cct = 0;
1298	while(xx != tx || yy != ty) {
1299	    /* loop: dig corridor at [xx,yy] and find new [xx,yy] */
1300	    if(cct++ > 500 || (nxcor && !rn2(35)))
1301		return FALSE;
1302
1303	    xx += dx;
1304	    yy += dy;
1305
1306	    if(xx >= COLNO-1 || xx <= 0 || yy <= 0 || yy >= ROWNO-1)
1307		return FALSE;		/* impossible */
1308
1309	    crm = &levl[xx][yy];
1310	    if(crm->typ == btyp) {
1311		if(ftyp != CORR || rn2(100)) {
1312			crm->typ = ftyp;
1313			if(nxcor && !rn2(50))
1314				(void) mksobj_at(BOULDER, xx, yy, TRUE, FALSE);
1315		} else {
1316			crm->typ = SCORR;
1317		}
1318	    } else
1319	    if(crm->typ != ftyp && crm->typ != SCORR) {
1320		/* strange ... */
1321		return FALSE;
1322	    }
1323
1324	    /* find next corridor position */
1325	    dix = abs(xx-tx);
1326	    diy = abs(yy-ty);
1327
1328	    /* do we have to change direction ? */
1329	    if(dy && dix > diy) {
1330		register int ddx = (xx > tx) ? -1 : 1;
1331
1332		crm = &levl[xx+ddx][yy];
1333		if(crm->typ == btyp || crm->typ == ftyp || crm->typ == SCORR) {
1334		    dx = ddx;
1335		    dy = 0;
1336		    continue;
1337		}
1338	    } else if(dx && diy > dix) {
1339		register int ddy = (yy > ty) ? -1 : 1;
1340
1341		crm = &levl[xx][yy+ddy];
1342		if(crm->typ == btyp || crm->typ == ftyp || crm->typ == SCORR) {
1343		    dy = ddy;
1344		    dx = 0;
1345		    continue;
1346		}
1347	    }
1348
1349	    /* continue straight on? */
1350	    crm = &levl[xx+dx][yy+dy];
1351	    if(crm->typ == btyp || crm->typ == ftyp || crm->typ == SCORR)
1352		continue;
1353
1354	    /* no, what must we do now?? */
1355	    if(dx) {
1356		dx = 0;
1357		dy = (ty < yy) ? -1 : 1;
1358	    } else {
1359		dy = 0;
1360		dx = (tx < xx) ? -1 : 1;
1361	    }
1362	    crm = &levl[xx+dx][yy+dy];
1363	    if(crm->typ == btyp || crm->typ == ftyp || crm->typ == SCORR)
1364		continue;
1365	    dy = -dy;
1366	    dx = -dx;
1367	}
1368	return TRUE;
1369}
1370
1371/*
1372 * Disgusting hack: since special levels have their rooms filled before
1373 * sorting the rooms, we have to re-arrange the speed values upstairs_room
1374 * and dnstairs_room after the rooms have been sorted.  On normal levels,
1375 * stairs don't get created until _after_ sorting takes place.
1376 */
1377STATIC_OVL void
1378fix_stair_rooms()
1379{
1380    int i;
1381    struct mkroom *croom;
1382
1383    if(xdnstair &&
1384       !((dnstairs_room->lx <= xdnstair && xdnstair <= dnstairs_room->hx) &&
1385	 (dnstairs_room->ly <= ydnstair && ydnstair <= dnstairs_room->hy))) {
1386	for(i=0; i < nroom; i++) {
1387	    croom = &rooms[i];
1388	    if((croom->lx <= xdnstair && xdnstair <= croom->hx) &&
1389	       (croom->ly <= ydnstair && ydnstair <= croom->hy)) {
1390		dnstairs_room = croom;
1391		break;
1392	    }
1393	}
1394	if(i == nroom)
1395	    panic("Couldn't find dnstair room in fix_stair_rooms!");
1396    }
1397    if(xupstair &&
1398       !((upstairs_room->lx <= xupstair && xupstair <= upstairs_room->hx) &&
1399	 (upstairs_room->ly <= yupstair && yupstair <= upstairs_room->hy))) {
1400	for(i=0; i < nroom; i++) {
1401	    croom = &rooms[i];
1402	    if((croom->lx <= xupstair && xupstair <= croom->hx) &&
1403	       (croom->ly <= yupstair && yupstair <= croom->hy)) {
1404		upstairs_room = croom;
1405		break;
1406	    }
1407	}
1408	if(i == nroom)
1409	    panic("Couldn't find upstair room in fix_stair_rooms!");
1410    }
1411}
1412
1413/*
1414 * Corridors always start from a door. But it can end anywhere...
1415 * Basically we search for door coordinates or for endpoints coordinates
1416 * (from a distance).
1417 */
1418
1419STATIC_OVL void
1420create_corridor(c)
1421corridor	*c;
1422{
1423	coord org, dest;
1424
1425	if (c->src.room == -1) {
1426		sort_rooms();
1427		fix_stair_rooms();
1428		makecorridors();
1429		return;
1430	}
1431
1432	if( !search_door(&rooms[c->src.room], &org.x, &org.y, c->src.wall,
1433			 c->src.door))
1434	    return;
1435
1436	if (c->dest.room != -1) {
1437		if(!search_door(&rooms[c->dest.room], &dest.x, &dest.y,
1438				c->dest.wall, c->dest.door))
1439		    return;
1440		switch(c->src.wall) {
1441		      case W_NORTH: org.y--; break;
1442		      case W_SOUTH: org.y++; break;
1443		      case W_WEST:  org.x--; break;
1444		      case W_EAST:  org.x++; break;
1445		}
1446		switch(c->dest.wall) {
1447		      case W_NORTH: dest.y--; break;
1448		      case W_SOUTH: dest.y++; break;
1449		      case W_WEST:  dest.x--; break;
1450		      case W_EAST:  dest.x++; break;
1451		}
1452		(void) dig_corridor(&org, &dest, FALSE, CORR, STONE);
1453	}
1454}
1455
1456
1457/*
1458 * Fill a room (shop, zoo, etc...) with appropriate stuff.
1459 */
1460
1461void
1462fill_room(croom, prefilled)
1463struct mkroom *croom;
1464boolean prefilled;
1465{
1466	if (!croom || croom->rtype == OROOM)
1467	    return;
1468
1469	if (!prefilled) {
1470	    int x,y;
1471
1472	    /* Shop ? */
1473	    if (croom->rtype >= SHOPBASE) {
1474		    stock_room(croom->rtype - SHOPBASE, croom);
1475		    level.flags.has_shop = TRUE;
1476		    return;
1477	    }
1478
1479	    switch (croom->rtype) {
1480		case VAULT:
1481		    for (x=croom->lx;x<=croom->hx;x++)
1482			for (y=croom->ly;y<=croom->hy;y++)
1483			    (void) mkgold((long)rn1(abs(depth(&u.uz))*100, 51), x, y);
1484		    break;
1485		case COURT:
1486		case ZOO:
1487		case BEEHIVE:
1488		case MORGUE:
1489		case BARRACKS:
1490		    fill_zoo(croom);
1491		    break;
1492	    }
1493	}
1494	switch (croom->rtype) {
1495	    case VAULT:
1496		level.flags.has_vault = TRUE;
1497		break;
1498	    case ZOO:
1499		level.flags.has_zoo = TRUE;
1500		break;
1501	    case COURT:
1502		level.flags.has_court = TRUE;
1503		break;
1504	    case MORGUE:
1505		level.flags.has_morgue = TRUE;
1506		break;
1507	    case BEEHIVE:
1508		level.flags.has_beehive = TRUE;
1509		break;
1510	    case BARRACKS:
1511		level.flags.has_barracks = TRUE;
1512		break;
1513	    case TEMPLE:
1514		level.flags.has_temple = TRUE;
1515		break;
1516	    case SWAMP:
1517		level.flags.has_swamp = TRUE;
1518		break;
1519	}
1520}
1521
1522STATIC_OVL void
1523free_rooms(ro, n)
1524room **ro;
1525int n;
1526{
1527	short j;
1528	room *r;
1529
1530	while(n--) {
1531		r = ro[n];
1532		Free(r->name);
1533		Free(r->parent);
1534		if ((j = r->ndoor) != 0) {
1535			while(j--)
1536			    Free(r->doors[j]);
1537			Free(r->doors);
1538		}
1539		if ((j = r->nstair) != 0) {
1540			while(j--)
1541			    Free(r->stairs[j]);
1542			Free(r->stairs);
1543		}
1544		if ((j = r->naltar) != 0) {
1545			while (j--)
1546			    Free(r->altars[j]);
1547			Free(r->altars);
1548		}
1549		if ((j = r->nfountain) != 0) {
1550			while(j--)
1551			    Free(r->fountains[j]);
1552			Free(r->fountains);
1553		}
1554		if ((j = r->nsink) != 0) {
1555			while(j--)
1556			    Free(r->sinks[j]);
1557			Free(r->sinks);
1558		}
1559		if ((j = r->npool) != 0) {
1560			while(j--)
1561			    Free(r->pools[j]);
1562			Free(r->pools);
1563		}
1564		if ((j = r->ntrap) != 0) {
1565			while (j--)
1566			    Free(r->traps[j]);
1567			Free(r->traps);
1568		}
1569		if ((j = r->nmonster) != 0) {
1570			while (j--)
1571				Free(r->monsters[j]);
1572			Free(r->monsters);
1573		}
1574		if ((j = r->nobject) != 0) {
1575			while (j--)
1576				Free(r->objects[j]);
1577			Free(r->objects);
1578		}
1579		if ((j = r->ngold) != 0) {
1580			while(j--)
1581			    Free(r->golds[j]);
1582			Free(r->golds);
1583		}
1584		if ((j = r->nengraving) != 0) {
1585			while (j--)
1586				Free(r->engravings[j]);
1587			Free(r->engravings);
1588		}
1589		Free(r);
1590	}
1591	Free(ro);
1592}
1593
1594STATIC_OVL void
1595build_room(r, pr)
1596room *r, *pr;
1597{
1598	boolean okroom;
1599	struct mkroom	*aroom;
1600	short i;
1601	xchar rtype = (!r->chance || rn2(100) < r->chance) ? r->rtype : OROOM;
1602
1603	if(pr) {
1604		aroom = &subrooms[nsubroom];
1605		okroom = create_subroom(pr->mkr, r->x, r->y, r->w, r->h,
1606					rtype, r->rlit);
1607	} else {
1608		aroom = &rooms[nroom];
1609		okroom = create_room(r->x, r->y, r->w, r->h, r->xalign,
1610				     r->yalign, rtype, r->rlit);
1611		r->mkr = aroom;
1612	}
1613
1614	if (okroom) {
1615		/* Create subrooms if necessary... */
1616		for(i=0; i < r->nsubroom; i++)
1617		    build_room(r->subrooms[i], r);
1618		/* And now we can fill the room! */
1619
1620		/* Priority to the stairs */
1621
1622		for(i=0; i <r->nstair; i++)
1623		    create_stairs(r->stairs[i], aroom);
1624
1625		/* Then to the various elements (sinks, etc..) */
1626		for(i = 0; i<r->nsink; i++)
1627		    create_feature(r->sinks[i]->x, r->sinks[i]->y, aroom, SINK);
1628		for(i = 0; i<r->npool; i++)
1629		    create_feature(r->pools[i]->x, r->pools[i]->y, aroom, POOL);
1630		for(i = 0; i<r->nfountain; i++)
1631		    create_feature(r->fountains[i]->x, r->fountains[i]->y,
1632				   aroom, FOUNTAIN);
1633		for(i = 0; i<r->naltar; i++)
1634		    create_altar(r->altars[i], aroom);
1635		for(i = 0; i<r->ndoor; i++)
1636		    create_door(r->doors[i], aroom);
1637
1638		/* The traps */
1639		for(i = 0; i<r->ntrap; i++)
1640		    create_trap(r->traps[i], aroom);
1641
1642		/* The monsters */
1643		for(i = 0; i<r->nmonster; i++)
1644		    create_monster(r->monsters[i], aroom);
1645
1646		/* The objects */
1647		for(i = 0; i<r->nobject; i++)
1648		    create_object(r->objects[i], aroom);
1649
1650		/* The gold piles */
1651		for(i = 0; i<r->ngold; i++)
1652		    create_gold(r->golds[i], aroom);
1653
1654		/* The engravings */
1655		for (i = 0; i < r->nengraving; i++)
1656		    create_engraving(r->engravings[i], aroom);
1657
1658#ifdef SPECIALIZATION
1659		topologize(aroom,FALSE);		/* set roomno */
1660#else
1661		topologize(aroom);			/* set roomno */
1662#endif
1663		/* MRS - 07/04/91 - This is temporary but should result
1664		 * in proper filling of shops, etc.
1665		 * DLC - this can fail if corridors are added to this room
1666		 * at a later point.  Currently no good way to fix this.
1667		 */
1668		if(aroom->rtype != OROOM && r->filled) fill_room(aroom, FALSE);
1669	}
1670}
1671
1672/*
1673 * set lighting in a region that will not become a room.
1674 */
1675STATIC_OVL void
1676light_region(tmpregion)
1677    region  *tmpregion;
1678{
1679    register boolean litstate = tmpregion->rlit ? 1 : 0;
1680    register int hiy = tmpregion->y2;
1681    register int x, y;
1682    register struct rm *lev;
1683    int lowy = tmpregion->y1;
1684    int lowx = tmpregion->x1, hix = tmpregion->x2;
1685
1686    if(litstate) {
1687	/* adjust region size for walls, but only if lighted */
1688	lowx = max(lowx-1,1);
1689	hix = min(hix+1,COLNO-1);
1690	lowy = max(lowy-1,0);
1691	hiy = min(hiy+1, ROWNO-1);
1692    }
1693    for(x = lowx; x <= hix; x++) {
1694	lev = &levl[x][lowy];
1695	for(y = lowy; y <= hiy; y++) {
1696	    if (lev->typ != LAVAPOOL) /* this overrides normal lighting */
1697		lev->lit = litstate;
1698	    lev++;
1699	}
1700    }
1701}
1702
1703/* initialization common to all special levels */
1704STATIC_OVL void
1705load_common_data(fd, typ)
1706dlb *fd;
1707int typ;
1708{
1709	uchar	n;
1710	long	lev_flags;
1711	int	i;
1712
1713      {
1714	aligntyp atmp;
1715	/* shuffle 3 alignments; can't use sp_lev_shuffle() on aligntyp's */
1716	i = rn2(3);   atmp=ralign[2]; ralign[2]=ralign[i]; ralign[i]=atmp;
1717	if (rn2(2)) { atmp=ralign[1]; ralign[1]=ralign[0]; ralign[0]=atmp; }
1718      }
1719
1720	level.flags.is_maze_lev = typ == SP_LEV_MAZE;
1721
1722	/* Read the level initialization data */
1723	Fread((genericptr_t) &init_lev, 1, sizeof(lev_init), fd);
1724	if(init_lev.init_present) {
1725	    if(init_lev.lit < 0)
1726		init_lev.lit = rn2(2);
1727	    mkmap(&init_lev);
1728	}
1729
1730	/* Read the per level flags */
1731	Fread((genericptr_t) &lev_flags, 1, sizeof(lev_flags), fd);
1732	if (lev_flags & NOTELEPORT)
1733	    level.flags.noteleport = 1;
1734	if (lev_flags & HARDFLOOR)
1735	    level.flags.hardfloor = 1;
1736	if (lev_flags & NOMMAP)
1737	    level.flags.nommap = 1;
1738	if (lev_flags & SHORTSIGHTED)
1739	    level.flags.shortsighted = 1;
1740	if (lev_flags & ARBOREAL)
1741	    level.flags.arboreal = 1;
1742
1743	/* Read message */
1744	Fread((genericptr_t) &n, 1, sizeof(n), fd);
1745	if (n) {
1746	    lev_message = (char *) alloc(n + 1);
1747	    Fread((genericptr_t) lev_message, 1, (int) n, fd);
1748	    lev_message[n] = 0;
1749	}
1750}
1751
1752STATIC_OVL void
1753load_one_monster(fd, m)
1754dlb *fd;
1755monster *m;
1756{
1757	int size;
1758
1759	Fread((genericptr_t) m, 1, sizeof *m, fd);
1760	if ((size = m->name.len) != 0) {
1761	    m->name.str = (char *) alloc((unsigned)size + 1);
1762	    Fread((genericptr_t) m->name.str, 1, size, fd);
1763	    m->name.str[size] = '\0';
1764	} else
1765	    m->name.str = (char *) 0;
1766	if ((size = m->appear_as.len) != 0) {
1767	    m->appear_as.str = (char *) alloc((unsigned)size + 1);
1768	    Fread((genericptr_t) m->appear_as.str, 1, size, fd);
1769	    m->appear_as.str[size] = '\0';
1770	} else
1771	    m->appear_as.str = (char *) 0;
1772}
1773
1774STATIC_OVL void
1775load_one_object(fd, o)
1776dlb *fd;
1777object *o;
1778{
1779	int size;
1780
1781	Fread((genericptr_t) o, 1, sizeof *o, fd);
1782	if ((size = o->name.len) != 0) {
1783	    o->name.str = (char *) alloc((unsigned)size + 1);
1784	    Fread((genericptr_t) o->name.str, 1, size, fd);
1785	    o->name.str[size] = '\0';
1786	} else
1787	    o->name.str = (char *) 0;
1788}
1789
1790STATIC_OVL void
1791load_one_engraving(fd, e)
1792dlb *fd;
1793engraving *e;
1794{
1795	int size;
1796
1797	Fread((genericptr_t) e, 1, sizeof *e, fd);
1798	size = e->engr.len;
1799	e->engr.str = (char *) alloc((unsigned)size+1);
1800	Fread((genericptr_t) e->engr.str, 1, size, fd);
1801	e->engr.str[size] = '\0';
1802}
1803
1804STATIC_OVL boolean
1805load_rooms(fd)
1806dlb *fd;
1807{
1808	xchar		nrooms, ncorr;
1809	char		n;
1810	short		size;
1811	corridor	tmpcor;
1812	room**		tmproom;
1813	int		i, j;
1814
1815	load_common_data(fd, SP_LEV_ROOMS);
1816
1817	Fread((genericptr_t) &n, 1, sizeof(n), fd); /* nrobjects */
1818	if (n) {
1819		Fread((genericptr_t)robjects, sizeof(*robjects), n, fd);
1820		sp_lev_shuffle(robjects, (char *)0, (int)n);
1821	}
1822
1823	Fread((genericptr_t) &n, 1, sizeof(n), fd); /* nrmonst */
1824	if (n) {
1825		Fread((genericptr_t)rmonst, sizeof(*rmonst), n, fd);
1826		sp_lev_shuffle(rmonst, (char *)0, (int)n);
1827	}
1828
1829	Fread((genericptr_t) &nrooms, 1, sizeof(nrooms), fd);
1830						/* Number of rooms to read */
1831	tmproom = NewTab(room,nrooms);
1832	for (i=0;i<nrooms;i++) {
1833		room *r;
1834
1835		r = tmproom[i] = New(room);
1836
1837		/* Let's see if this room has a name */
1838		Fread((genericptr_t) &size, 1, sizeof(size), fd);
1839		if (size > 0) {	/* Yup, it does! */
1840			r->name = (char *) alloc((unsigned)size + 1);
1841			Fread((genericptr_t) r->name, 1, size, fd);
1842			r->name[size] = 0;
1843		} else
1844		    r->name = (char *) 0;
1845
1846		/* Let's see if this room has a parent */
1847		Fread((genericptr_t) &size, 1, sizeof(size), fd);
1848		if (size > 0) {	/* Yup, it does! */
1849			r->parent = (char *) alloc((unsigned)size + 1);
1850			Fread((genericptr_t) r->parent, 1, size, fd);
1851			r->parent[size] = 0;
1852		} else
1853		    r->parent = (char *) 0;
1854
1855		Fread((genericptr_t) &r->x, 1, sizeof(r->x), fd);
1856					/* x pos on the grid (1-5) */
1857		Fread((genericptr_t) &r->y, 1, sizeof(r->y), fd);
1858					 /* y pos on the grid (1-5) */
1859		Fread((genericptr_t) &r->w, 1, sizeof(r->w), fd);
1860					 /* width of the room */
1861		Fread((genericptr_t) &r->h, 1, sizeof(r->h), fd);
1862					 /* height of the room */
1863		Fread((genericptr_t) &r->xalign, 1, sizeof(r->xalign), fd);
1864					 /* horizontal alignment */
1865		Fread((genericptr_t) &r->yalign, 1, sizeof(r->yalign), fd);
1866					 /* vertical alignment */
1867		Fread((genericptr_t) &r->rtype, 1, sizeof(r->rtype), fd);
1868					 /* type of room (zoo, shop, etc.) */
1869		Fread((genericptr_t) &r->chance, 1, sizeof(r->chance), fd);
1870					 /* chance of room being special. */
1871		Fread((genericptr_t) &r->rlit, 1, sizeof(r->rlit), fd);
1872					 /* lit or not ? */
1873		Fread((genericptr_t) &r->filled, 1, sizeof(r->filled), fd);
1874					 /* to be filled? */
1875		r->nsubroom= 0;
1876
1877		/* read the doors */
1878		Fread((genericptr_t) &r->ndoor, 1, sizeof(r->ndoor), fd);
1879		if ((n = r->ndoor) != 0)
1880		    r->doors = NewTab(room_door, n);
1881		while(n--) {
1882			r->doors[(int)n] = New(room_door);
1883			Fread((genericptr_t) r->doors[(int)n], 1,
1884				sizeof(room_door), fd);
1885		}
1886
1887		/* read the stairs */
1888		Fread((genericptr_t) &r->nstair, 1, sizeof(r->nstair), fd);
1889		if ((n = r->nstair) != 0)
1890		    r->stairs = NewTab(stair, n);
1891		while (n--) {
1892			r->stairs[(int)n] = New(stair);
1893			Fread((genericptr_t) r->stairs[(int)n], 1,
1894				sizeof(stair), fd);
1895		}
1896
1897		/* read the altars */
1898		Fread((genericptr_t) &r->naltar, 1, sizeof(r->naltar), fd);
1899		if ((n = r->naltar) != 0)
1900		    r->altars = NewTab(altar, n);
1901		while (n--) {
1902			r->altars[(int)n] = New(altar);
1903			Fread((genericptr_t) r->altars[(int)n], 1,
1904				sizeof(altar), fd);
1905		}
1906
1907		/* read the fountains */
1908		Fread((genericptr_t) &r->nfountain, 1,
1909			sizeof(r->nfountain), fd);
1910		if ((n = r->nfountain) != 0)
1911		    r->fountains = NewTab(fountain, n);
1912		while (n--) {
1913			r->fountains[(int)n] = New(fountain);
1914			Fread((genericptr_t) r->fountains[(int)n], 1,
1915				sizeof(fountain), fd);
1916		}
1917
1918		/* read the sinks */
1919		Fread((genericptr_t) &r->nsink, 1, sizeof(r->nsink), fd);
1920		if ((n = r->nsink) != 0)
1921		    r->sinks = NewTab(sink, n);
1922		while (n--) {
1923			r->sinks[(int)n] = New(sink);
1924			Fread((genericptr_t) r->sinks[(int)n], 1, sizeof(sink), fd);
1925		}
1926
1927		/* read the pools */
1928		Fread((genericptr_t) &r->npool, 1, sizeof(r->npool), fd);
1929		if ((n = r->npool) != 0)
1930		    r->pools = NewTab(pool,n);
1931		while (n--) {
1932			r->pools[(int)n] = New(pool);
1933			Fread((genericptr_t) r->pools[(int)n], 1, sizeof(pool), fd);
1934		}
1935
1936		/* read the traps */
1937		Fread((genericptr_t) &r->ntrap, 1, sizeof(r->ntrap), fd);
1938		if ((n = r->ntrap) != 0)
1939		    r->traps = NewTab(trap, n);
1940		while(n--) {
1941			r->traps[(int)n] = New(trap);
1942			Fread((genericptr_t) r->traps[(int)n], 1, sizeof(trap), fd);
1943		}
1944
1945		/* read the monsters */
1946		Fread((genericptr_t) &r->nmonster, 1, sizeof(r->nmonster), fd);
1947		if ((n = r->nmonster) != 0) {
1948		    r->monsters = NewTab(monster, n);
1949		    while(n--) {
1950			r->monsters[(int)n] = New(monster);
1951			load_one_monster(fd, r->monsters[(int)n]);
1952		    }
1953		} else
1954		    r->monsters = 0;
1955
1956		/* read the objects, in same order as mazes */
1957		Fread((genericptr_t) &r->nobject, 1, sizeof(r->nobject), fd);
1958		if ((n = r->nobject) != 0) {
1959		    r->objects = NewTab(object, n);
1960		    for (j = 0; j < n; ++j) {
1961			r->objects[j] = New(object);
1962			load_one_object(fd, r->objects[j]);
1963		    }
1964		} else
1965		    r->objects = 0;
1966
1967		/* read the gold piles */
1968		Fread((genericptr_t) &r->ngold, 1, sizeof(r->ngold), fd);
1969		if ((n = r->ngold) != 0)
1970		    r->golds = NewTab(gold, n);
1971		while (n--) {
1972			r->golds[(int)n] = New(gold);
1973			Fread((genericptr_t) r->golds[(int)n], 1, sizeof(gold), fd);
1974		}
1975
1976		/* read the engravings */
1977		Fread((genericptr_t) &r->nengraving, 1,
1978			sizeof(r->nengraving), fd);
1979		if ((n = r->nengraving) != 0) {
1980		    r->engravings = NewTab(engraving,n);
1981		    while (n--) {
1982			r->engravings[(int)n] = New(engraving);
1983			load_one_engraving(fd, r->engravings[(int)n]);
1984		    }
1985		} else
1986		    r->engravings = 0;
1987
1988	}
1989
1990	/* Now that we have loaded all the rooms, search the
1991	 * subrooms and create the links.
1992	 */
1993
1994	for (i = 0; i<nrooms; i++)
1995	    if (tmproom[i]->parent) {
1996		    /* Search the parent room */
1997		    for(j=0; j<nrooms; j++)
1998			if (tmproom[j]->name && !strcmp(tmproom[j]->name,
1999						       tmproom[i]->parent)) {
2000				n = tmproom[j]->nsubroom++;
2001				tmproom[j]->subrooms[(int)n] = tmproom[i];
2002				break;
2003			}
2004	    }
2005
2006	/*
2007	 * Create the rooms now...
2008	 */
2009
2010	for (i=0; i < nrooms; i++)
2011	    if(!tmproom[i]->parent)
2012		build_room(tmproom[i], (room *) 0);
2013
2014	free_rooms(tmproom, nrooms);
2015
2016	/* read the corridors */
2017
2018	Fread((genericptr_t) &ncorr, sizeof(ncorr), 1, fd);
2019	for (i=0; i<ncorr; i++) {
2020		Fread((genericptr_t) &tmpcor, 1, sizeof(tmpcor), fd);
2021		create_corridor(&tmpcor);
2022	}
2023
2024	return TRUE;
2025}
2026
2027/*
2028 * Select a random coordinate in the maze.
2029 *
2030 * We want a place not 'touched' by the loader.  That is, a place in
2031 * the maze outside every part of the special level.
2032 */
2033
2034STATIC_OVL void
2035maze1xy(m, humidity)
2036coord *m;
2037int humidity;
2038{
2039	register int x, y, tryct = 2000;
2040	/* tryct:  normally it won't take more than ten or so tries due
2041	   to the circumstances under which we'll be called, but the
2042	   `humidity' screening might drastically change the chances */
2043
2044	do {
2045	    x = rn1(x_maze_max - 3, 3);
2046	    y = rn1(y_maze_max - 3, 3);
2047	    if (--tryct < 0) break;	/* give up */
2048	} while (!(x % 2) || !(y % 2) || Map[x][y] ||
2049		 !is_ok_location((schar)x, (schar)y, humidity));
2050
2051	m->x = (xchar)x,  m->y = (xchar)y;
2052}
2053
2054/*
2055 * The Big Thing: special maze loader
2056 *
2057 * Could be cleaner, but it works.
2058 */
2059
2060STATIC_OVL boolean
2061load_maze(fd)
2062dlb *fd;
2063{
2064    xchar   x, y, typ;
2065    boolean prefilled, room_not_needed;
2066
2067    char    n, numpart = 0;
2068    xchar   nwalk = 0, nwalk_sav;
2069    schar   filling;
2070    char    halign, valign;
2071
2072    int     xi, dir, size;
2073    coord   mm;
2074    int     mapcount, mapcountmax, mapfact;
2075
2076    lev_region  tmplregion;
2077    region  tmpregion;
2078    door    tmpdoor;
2079    trap    tmptrap;
2080    monster tmpmons;
2081    object  tmpobj;
2082    drawbridge tmpdb;
2083    walk    tmpwalk;
2084    digpos  tmpdig;
2085    lad     tmplad;
2086    stair   tmpstair, prevstair;
2087    altar   tmpaltar;
2088    gold    tmpgold;
2089    fountain tmpfountain;
2090    engraving tmpengraving;
2091    xchar   mustfill[(MAXNROFROOMS+1)*2];
2092    struct trap *badtrap;
2093    boolean has_bounds;
2094
2095    (void) memset((genericptr_t)&Map[0][0], 0, sizeof Map);
2096    load_common_data(fd, SP_LEV_MAZE);
2097
2098    /* Initialize map */
2099    Fread((genericptr_t) &filling, 1, sizeof(filling), fd);
2100    if (!init_lev.init_present) { /* don't init if mkmap() has been called */
2101      for(x = 2; x <= x_maze_max; x++)
2102	for(y = 0; y <= y_maze_max; y++)
2103	    if (filling == -1) {
2104#ifndef WALLIFIED_MAZE
2105		    levl[x][y].typ = STONE;
2106#else
2107		    levl[x][y].typ =
2108			(y < 2 || ((x % 2) && (y % 2))) ? STONE : HWALL;
2109#endif
2110	    } else {
2111		    levl[x][y].typ = filling;
2112	    }
2113    }
2114
2115    /* Start reading the file */
2116    Fread((genericptr_t) &numpart, 1, sizeof(numpart), fd);
2117						/* Number of parts */
2118    if (!numpart || numpart > 9)
2119	panic("load_maze error: numpart = %d", (int) numpart);
2120
2121    while (numpart--) {
2122	Fread((genericptr_t) &halign, 1, sizeof(halign), fd);
2123					/* Horizontal alignment */
2124	Fread((genericptr_t) &valign, 1, sizeof(valign), fd);
2125					/* Vertical alignment */
2126	Fread((genericptr_t) &xsize, 1, sizeof(xsize), fd);
2127					/* size in X */
2128	Fread((genericptr_t) &ysize, 1, sizeof(ysize), fd);
2129					/* size in Y */
2130	switch((int) halign) {
2131	    case LEFT:	    xstart = 3;					break;
2132	    case H_LEFT:    xstart = 2+((x_maze_max-2-xsize)/4);	break;
2133	    case CENTER:    xstart = 2+((x_maze_max-2-xsize)/2);	break;
2134	    case H_RIGHT:   xstart = 2+((x_maze_max-2-xsize)*3/4);	break;
2135	    case RIGHT:     xstart = x_maze_max-xsize-1;		break;
2136	}
2137	switch((int) valign) {
2138	    case TOP:	    ystart = 3;					break;
2139	    case CENTER:    ystart = 2+((y_maze_max-2-ysize)/2);	break;
2140	    case BOTTOM:    ystart = y_maze_max-ysize-1;		break;
2141	}
2142	if (!(xstart % 2)) xstart++;
2143	if (!(ystart % 2)) ystart++;
2144	if ((ystart < 0) || (ystart + ysize > ROWNO)) {
2145	    /* try to move the start a bit */
2146	    ystart += (ystart > 0) ? -2 : 2;
2147	    if(ysize == ROWNO) ystart = 0;
2148	    if(ystart < 0 || ystart + ysize > ROWNO)
2149		panic("reading special level with ysize too large");
2150	}
2151
2152	/*
2153	 * If any CROSSWALLs are found, must change to ROOM after REGION's
2154	 * are laid out.  CROSSWALLS are used to specify "invisible"
2155	 * boundaries where DOOR syms look bad or aren't desirable.
2156	 */
2157	has_bounds = FALSE;
2158
2159	if(init_lev.init_present && xsize <= 1 && ysize <= 1) {
2160	    xstart = 1;
2161	    ystart = 0;
2162	    xsize = COLNO-1;
2163	    ysize = ROWNO;
2164	} else {
2165	    /* Load the map */
2166	    for(y = ystart; y < ystart+ysize; y++)
2167		for(x = xstart; x < xstart+xsize; x++) {
2168		    levl[x][y].typ = Fgetc(fd);
2169		    levl[x][y].lit = FALSE;
2170		    /* clear out levl: load_common_data may set them */
2171		    levl[x][y].flags = 0;
2172		    levl[x][y].horizontal = 0;
2173		    levl[x][y].roomno = 0;
2174		    levl[x][y].edge = 0;
2175		    /*
2176		     * Note: Even though levl[x][y].typ is type schar,
2177		     *	 lev_comp.y saves it as type char. Since schar != char
2178		     *	 all the time we must make this exception or hack
2179		     *	 through lev_comp.y to fix.
2180		     */
2181
2182		    /*
2183		     *  Set secret doors to closed (why not trapped too?).  Set
2184		     *  the horizontal bit.
2185		     */
2186		    if (levl[x][y].typ == SDOOR || IS_DOOR(levl[x][y].typ)) {
2187			if(levl[x][y].typ == SDOOR)
2188			    levl[x][y].doormask = D_CLOSED;
2189			/*
2190			 *  If there is a wall to the left that connects to a
2191			 *  (secret) door, then it is horizontal.  This does
2192			 *  not allow (secret) doors to be corners of rooms.
2193			 */
2194			if (x != xstart && (IS_WALL(levl[x-1][y].typ) ||
2195					    levl[x-1][y].horizontal))
2196			    levl[x][y].horizontal = 1;
2197		    } else if(levl[x][y].typ == HWALL ||
2198				levl[x][y].typ == IRONBARS)
2199			levl[x][y].horizontal = 1;
2200		    else if(levl[x][y].typ == LAVAPOOL)
2201			levl[x][y].lit = 1;
2202		    else if(levl[x][y].typ == CROSSWALL)
2203			has_bounds = TRUE;
2204		    Map[x][y] = 1;
2205		}
2206	    if (init_lev.init_present && init_lev.joined)
2207		remove_rooms(xstart, ystart, xstart+xsize, ystart+ysize);
2208	}
2209
2210	Fread((genericptr_t) &n, 1, sizeof(n), fd);
2211						/* Number of level regions */
2212	if(n) {
2213	    if(num_lregions) {
2214		/* realloc the lregion space to add the new ones */
2215		/* don't really free it up until the whole level is done */
2216		lev_region *newl = (lev_region *) alloc(sizeof(lev_region) *
2217						(unsigned)(n+num_lregions));
2218		(void) memcpy((genericptr_t)(newl+n), (genericptr_t)lregions,
2219					sizeof(lev_region) * num_lregions);
2220		Free(lregions);
2221		num_lregions += n;
2222		lregions = newl;
2223	    } else {
2224		num_lregions = n;
2225		lregions = (lev_region *)
2226				alloc(sizeof(lev_region) * (unsigned)n);
2227	    }
2228	}
2229
2230	while(n--) {
2231	    Fread((genericptr_t) &tmplregion, sizeof(tmplregion), 1, fd);
2232	    if ((size = tmplregion.rname.len) != 0) {
2233		tmplregion.rname.str = (char *) alloc((unsigned)size + 1);
2234		Fread((genericptr_t) tmplregion.rname.str, size, 1, fd);
2235		tmplregion.rname.str[size] = '\0';
2236	    } else
2237		tmplregion.rname.str = (char *) 0;
2238	    if(!tmplregion.in_islev) {
2239		get_location(&tmplregion.inarea.x1, &tmplregion.inarea.y1,
2240								DRY|WET);
2241		get_location(&tmplregion.inarea.x2, &tmplregion.inarea.y2,
2242								DRY|WET);
2243	    }
2244	    if(!tmplregion.del_islev) {
2245		get_location(&tmplregion.delarea.x1, &tmplregion.delarea.y1,
2246								DRY|WET);
2247		get_location(&tmplregion.delarea.x2, &tmplregion.delarea.y2,
2248								DRY|WET);
2249	    }
2250	    lregions[(int)n] = tmplregion;
2251	}
2252
2253	Fread((genericptr_t) &n, 1, sizeof(n), fd);
2254						/* Random objects */
2255	if(n) {
2256		Fread((genericptr_t)robjects, sizeof(*robjects), (int) n, fd);
2257		sp_lev_shuffle(robjects, (char *)0, (int)n);
2258	}
2259
2260	Fread((genericptr_t) &n, 1, sizeof(n), fd);
2261						/* Random locations */
2262	if(n) {
2263		Fread((genericptr_t)rloc_x, sizeof(*rloc_x), (int) n, fd);
2264		Fread((genericptr_t)rloc_y, sizeof(*rloc_y), (int) n, fd);
2265		sp_lev_shuffle(rloc_x, rloc_y, (int)n);
2266	}
2267
2268	Fread((genericptr_t) &n, 1, sizeof(n), fd);
2269						/* Random monsters */
2270	if(n) {
2271		Fread((genericptr_t)rmonst, sizeof(*rmonst), (int) n, fd);
2272		sp_lev_shuffle(rmonst, (char *)0, (int)n);
2273	}
2274
2275	(void) memset((genericptr_t)mustfill, 0, sizeof(mustfill));
2276	Fread((genericptr_t) &n, 1, sizeof(n), fd);
2277						/* Number of subrooms */
2278	while(n--) {
2279		register struct mkroom *troom;
2280
2281		Fread((genericptr_t)&tmpregion, 1, sizeof(tmpregion), fd);
2282
2283		if(tmpregion.rtype > MAXRTYPE) {
2284		    tmpregion.rtype -= MAXRTYPE+1;
2285		    prefilled = TRUE;
2286		} else
2287		    prefilled = FALSE;
2288
2289		if(tmpregion.rlit < 0)
2290		    tmpregion.rlit = (rnd(1+abs(depth(&u.uz))) < 11 && rn2(77))
2291			? TRUE : FALSE;
2292
2293		get_location(&tmpregion.x1, &tmpregion.y1, DRY|WET);
2294		get_location(&tmpregion.x2, &tmpregion.y2, DRY|WET);
2295
2296		/* for an ordinary room, `prefilled' is a flag to force
2297		   an actual room to be created (such rooms are used to
2298		   control placement of migrating monster arrivals) */
2299		room_not_needed = (tmpregion.rtype == OROOM &&
2300				   !tmpregion.rirreg && !prefilled);
2301		if (room_not_needed || nroom >= MAXNROFROOMS) {
2302		    if (!room_not_needed)
2303			impossible("Too many rooms on new level!");
2304		    light_region(&tmpregion);
2305		    continue;
2306		}
2307
2308		troom = &rooms[nroom];
2309
2310		/* mark rooms that must be filled, but do it later */
2311		if (tmpregion.rtype != OROOM)
2312		    mustfill[nroom] = (prefilled ? 2 : 1);
2313
2314		if(tmpregion.rirreg) {
2315		    min_rx = max_rx = tmpregion.x1;
2316		    min_ry = max_ry = tmpregion.y1;
2317		    flood_fill_rm(tmpregion.x1, tmpregion.y1,
2318				  nroom+ROOMOFFSET, tmpregion.rlit, TRUE);
2319		    add_room(min_rx, min_ry, max_rx, max_ry,
2320			     FALSE, tmpregion.rtype, TRUE);
2321		    troom->rlit = tmpregion.rlit;
2322		    troom->irregular = TRUE;
2323		} else {
2324		    add_room(tmpregion.x1, tmpregion.y1,
2325			     tmpregion.x2, tmpregion.y2,
2326			     tmpregion.rlit, tmpregion.rtype, TRUE);
2327#ifdef SPECIALIZATION
2328		    topologize(troom,FALSE);		/* set roomno */
2329#else
2330		    topologize(troom);			/* set roomno */
2331#endif
2332		}
2333	}
2334
2335	Fread((genericptr_t) &n, 1, sizeof(n), fd);
2336						/* Number of doors */
2337	while(n--) {
2338		struct mkroom *croom = &rooms[0];
2339
2340		Fread((genericptr_t)&tmpdoor, 1, sizeof(tmpdoor), fd);
2341
2342		x = tmpdoor.x;	y = tmpdoor.y;
2343		typ = tmpdoor.mask == -1 ? rnddoor() : tmpdoor.mask;
2344
2345		get_location(&x, &y, DRY);
2346		if(levl[x][y].typ != SDOOR)
2347			levl[x][y].typ = DOOR;
2348		else {
2349			if(typ < D_CLOSED)
2350			    typ = D_CLOSED; /* force it to be closed */
2351		}
2352		levl[x][y].doormask = typ;
2353
2354		/* Now the complicated part, list it with each subroom */
2355		/* The dog move and mail daemon routines use this */
2356		while(croom->hx >= 0 && doorindex < DOORMAX) {
2357		    if(croom->hx >= x-1 && croom->lx <= x+1 &&
2358		       croom->hy >= y-1 && croom->ly <= y+1) {
2359			/* Found it */
2360			add_door(x, y, croom);
2361		    }
2362		    croom++;
2363		}
2364	}
2365
2366	/* now that we have rooms _and_ associated doors, fill the rooms */
2367	for(n = 0; n < SIZE(mustfill); n++)
2368	    if(mustfill[(int)n])
2369		fill_room(&rooms[(int)n], (mustfill[(int)n] == 2));
2370
2371	/* if special boundary syms (CROSSWALL) in map, remove them now */
2372	if(has_bounds) {
2373	    for(x = xstart; x < xstart+xsize; x++)
2374		for(y = ystart; y < ystart+ysize; y++)
2375		    if(levl[x][y].typ == CROSSWALL)
2376			levl[x][y].typ = ROOM;
2377	}
2378
2379	Fread((genericptr_t) &n, 1, sizeof(n), fd);
2380						/* Number of drawbridges */
2381	while(n--) {
2382		Fread((genericptr_t)&tmpdb, 1, sizeof(tmpdb), fd);
2383
2384		x = tmpdb.x;  y = tmpdb.y;
2385		get_location(&x, &y, DRY|WET);
2386
2387		if (!create_drawbridge(x, y, tmpdb.dir, tmpdb.db_open))
2388		    impossible("Cannot create drawbridge.");
2389	}
2390
2391	Fread((genericptr_t) &n, 1, sizeof(n), fd);
2392						/* Number of mazewalks */
2393	while(n--) {
2394		Fread((genericptr_t)&tmpwalk, 1, sizeof(tmpwalk), fd);
2395
2396		get_location(&tmpwalk.x, &tmpwalk.y, DRY|WET);
2397
2398		walklist[nwalk++] = tmpwalk;
2399	}
2400
2401	Fread((genericptr_t) &n, 1, sizeof(n), fd);
2402						/* Number of non_diggables */
2403	while(n--) {
2404		Fread((genericptr_t)&tmpdig, 1, sizeof(tmpdig), fd);
2405
2406		get_location(&tmpdig.x1, &tmpdig.y1, DRY|WET);
2407		get_location(&tmpdig.x2, &tmpdig.y2, DRY|WET);
2408
2409		set_wall_property(tmpdig.x1, tmpdig.y1,
2410				  tmpdig.x2, tmpdig.y2, W_NONDIGGABLE);
2411	}
2412
2413	Fread((genericptr_t) &n, 1, sizeof(n), fd);
2414						/* Number of non_passables */
2415	while(n--) {
2416		Fread((genericptr_t)&tmpdig, 1, sizeof(tmpdig), fd);
2417
2418		get_location(&tmpdig.x1, &tmpdig.y1, DRY|WET);
2419		get_location(&tmpdig.x2, &tmpdig.y2, DRY|WET);
2420
2421		set_wall_property(tmpdig.x1, tmpdig.y1,
2422				  tmpdig.x2, tmpdig.y2, W_NONPASSWALL);
2423	}
2424
2425	Fread((genericptr_t) &n, 1, sizeof(n), fd);
2426						/* Number of ladders */
2427	while(n--) {
2428		Fread((genericptr_t)&tmplad, 1, sizeof(tmplad), fd);
2429
2430		x = tmplad.x;  y = tmplad.y;
2431		get_location(&x, &y, DRY);
2432
2433		levl[x][y].typ = LADDER;
2434		if (tmplad.up == 1) {
2435			xupladder = x;	yupladder = y;
2436			levl[x][y].ladder = LA_UP;
2437		} else {
2438			xdnladder = x;	ydnladder = y;
2439			levl[x][y].ladder = LA_DOWN;
2440		}
2441	}
2442
2443	prevstair.x = prevstair.y = 0;
2444	Fread((genericptr_t) &n, 1, sizeof(n), fd);
2445						/* Number of stairs */
2446	while(n--) {
2447		Fread((genericptr_t)&tmpstair, 1, sizeof(tmpstair), fd);
2448
2449		xi = 0;
2450		do {
2451		    x = tmpstair.x;  y = tmpstair.y;
2452		    get_location(&x, &y, DRY);
2453		} while(prevstair.x && xi++ < 100 &&
2454			distmin(x,y,prevstair.x,prevstair.y) <= 8);
2455		if ((badtrap = t_at(x,y)) != 0) deltrap(badtrap);
2456		mkstairs(x, y, (char)tmpstair.up, (struct mkroom *)0);
2457		prevstair.x = x;
2458		prevstair.y = y;
2459	}
2460
2461	Fread((genericptr_t) &n, 1, sizeof(n), fd);
2462						/* Number of altars */
2463	while(n--) {
2464		Fread((genericptr_t)&tmpaltar, 1, sizeof(tmpaltar), fd);
2465
2466		create_altar(&tmpaltar, (struct mkroom *)0);
2467	}
2468
2469	Fread((genericptr_t) &n, 1, sizeof(n), fd);
2470						/* Number of fountains */
2471	while (n--) {
2472		Fread((genericptr_t)&tmpfountain, 1, sizeof(tmpfountain), fd);
2473
2474		create_feature(tmpfountain.x, tmpfountain.y,
2475			       (struct mkroom *)0, FOUNTAIN);
2476	}
2477
2478	Fread((genericptr_t) &n, 1, sizeof(n), fd);
2479						/* Number of traps */
2480	while(n--) {
2481		Fread((genericptr_t)&tmptrap, 1, sizeof(tmptrap), fd);
2482
2483		create_trap(&tmptrap, (struct mkroom *)0);
2484	}
2485
2486	Fread((genericptr_t) &n, 1, sizeof(n), fd);
2487						/* Number of monsters */
2488	while(n--) {
2489		load_one_monster(fd, &tmpmons);
2490
2491		create_monster(&tmpmons, (struct mkroom *)0);
2492	}
2493
2494	Fread((genericptr_t) &n, 1, sizeof(n), fd);
2495						/* Number of objects */
2496	while(n--) {
2497		load_one_object(fd, &tmpobj);
2498
2499		create_object(&tmpobj, (struct mkroom *)0);
2500	}
2501
2502	Fread((genericptr_t) &n, 1, sizeof(n), fd);
2503						/* Number of gold piles */
2504	while (n--) {
2505		Fread((genericptr_t)&tmpgold, 1, sizeof(tmpgold), fd);
2506
2507		create_gold(&tmpgold, (struct mkroom *)0);
2508	}
2509
2510	Fread((genericptr_t) &n, 1, sizeof(n), fd);
2511						/* Number of engravings */
2512	while(n--) {
2513		load_one_engraving(fd, &tmpengraving);
2514
2515		create_engraving(&tmpengraving, (struct mkroom *)0);
2516	}
2517
2518    }		/* numpart loop */
2519
2520    nwalk_sav = nwalk;
2521    while(nwalk--) {
2522	    x = (xchar) walklist[nwalk].x;
2523	    y = (xchar) walklist[nwalk].y;
2524	    dir = walklist[nwalk].dir;
2525
2526	    /* don't use move() - it doesn't use W_NORTH, etc. */
2527	    switch (dir) {
2528		case W_NORTH: --y; break;
2529		case W_SOUTH: y++; break;
2530		case W_EAST:  x++; break;
2531		case W_WEST:  --x; break;
2532		default: panic("load_maze: bad MAZEWALK direction");
2533	    }
2534
2535	    if(!IS_DOOR(levl[x][y].typ)) {
2536#ifndef WALLIFIED_MAZE
2537		levl[x][y].typ = CORR;
2538#else
2539		levl[x][y].typ = ROOM;
2540#endif
2541		levl[x][y].flags = 0;
2542	    }
2543
2544	    /*
2545	     * We must be sure that the parity of the coordinates for
2546	     * walkfrom() is odd.  But we must also take into account
2547	     * what direction was chosen.
2548	     */
2549	    if(!(x % 2)) {
2550		if (dir == W_EAST)
2551		    x++;
2552		else
2553		    x--;
2554
2555		/* no need for IS_DOOR check; out of map bounds */
2556#ifndef WALLIFIED_MAZE
2557		levl[x][y].typ = CORR;
2558#else
2559		levl[x][y].typ = ROOM;
2560#endif
2561		levl[x][y].flags = 0;
2562	    }
2563
2564	    if (!(y % 2)) {
2565		if (dir == W_SOUTH)
2566		    y++;
2567		else
2568		    y--;
2569	    }
2570
2571	    walkfrom(x, y);
2572    }
2573    wallification(1, 0, COLNO-1, ROWNO-1);
2574
2575    /*
2576     * If there's a significant portion of maze unused by the special level,
2577     * we don't want it empty.
2578     *
2579     * Makes the number of traps, monsters, etc. proportional
2580     * to the size of the maze.
2581     */
2582    mapcountmax = mapcount = (x_maze_max - 2) * (y_maze_max - 2);
2583
2584    for(x = 2; x < x_maze_max; x++)
2585	for(y = 0; y < y_maze_max; y++)
2586	    if(Map[x][y]) mapcount--;
2587
2588    if (nwalk_sav && (mapcount > (int) (mapcountmax / 10))) {
2589	    mapfact = (int) ((mapcount * 100L) / mapcountmax);
2590	    for(x = rnd((int) (20 * mapfact) / 100); x; x--) {
2591		    maze1xy(&mm, DRY);
2592		    (void) mkobj_at(rn2(2) ? GEM_CLASS : RANDOM_CLASS,
2593							mm.x, mm.y, TRUE);
2594	    }
2595	    for(x = rnd((int) (12 * mapfact) / 100); x; x--) {
2596		    maze1xy(&mm, DRY);
2597		    (void) mksobj_at(BOULDER, mm.x, mm.y, TRUE, FALSE);
2598	    }
2599	    for (x = rn2(2); x; x--) {
2600		maze1xy(&mm, DRY);
2601		(void) makemon(&mons[PM_MINOTAUR], mm.x, mm.y, NO_MM_FLAGS);
2602	    }
2603	    for(x = rnd((int) (12 * mapfact) / 100); x; x--) {
2604		    maze1xy(&mm, WET|DRY);
2605		    (void) makemon((struct permonst *) 0, mm.x, mm.y, NO_MM_FLAGS);
2606	    }
2607	    for(x = rn2((int) (15 * mapfact) / 100); x; x--) {
2608		    maze1xy(&mm, DRY);
2609		    (void) mkgold(0L,mm.x,mm.y);
2610	    }
2611	    for(x = rn2((int) (15 * mapfact) / 100); x; x--) {
2612		    int trytrap;
2613
2614		    maze1xy(&mm, DRY);
2615		    trytrap = rndtrap();
2616		    if (sobj_at(BOULDER, mm.x, mm.y))
2617			while (trytrap == PIT || trytrap == SPIKED_PIT ||
2618				trytrap == TRAPDOOR || trytrap == HOLE)
2619			    trytrap = rndtrap();
2620		    (void) maketrap(mm.x, mm.y, trytrap);
2621	    }
2622    }
2623    return TRUE;
2624}
2625
2626/*
2627 * General loader
2628 */
2629
2630boolean
2631load_special(name)
2632const char *name;
2633{
2634	dlb *fd;
2635	boolean result = FALSE;
2636	char c;
2637	struct version_info vers_info;
2638
2639	fd = dlb_fopen(name, RDBMODE);
2640	if (!fd) return FALSE;
2641
2642	Fread((genericptr_t) &vers_info, sizeof vers_info, 1, fd);
2643	if (!check_version(&vers_info, name, TRUE))
2644	    goto give_up;
2645
2646	Fread((genericptr_t) &c, sizeof c, 1, fd); /* c Header */
2647
2648	switch (c) {
2649		case SP_LEV_ROOMS:
2650		    result = load_rooms(fd);
2651		    break;
2652		case SP_LEV_MAZE:
2653		    result = load_maze(fd);
2654		    break;
2655		default:	/* ??? */
2656		    result = FALSE;
2657	}
2658 give_up:
2659	(void)dlb_fclose(fd);
2660	return result;
2661}
2662
2663/*sp_lev.c*/
2664