1    | /*	SCCS Id: @(#)sp_lev.c	3.3	1999/11/16	*/
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 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   | 
27   | extern void FDECL(mkmap, (lev_init *));
28   | 
29   | STATIC_DCL void FDECL(get_room_loc, (schar *, schar *, struct mkroom *));
30   | STATIC_DCL void FDECL(get_free_room_loc, (schar *, schar *, struct mkroom *));
31   | STATIC_DCL void FDECL(create_trap, (trap *, struct mkroom *));
32   | STATIC_DCL int FDECL(noncoalignment, (ALIGNTYP_P));
33   | STATIC_DCL void FDECL(create_monster, (monster *, struct mkroom *));
34   | STATIC_DCL void FDECL(create_object, (object *, struct mkroom *));
35   | STATIC_DCL void FDECL(create_engraving, (engraving *,struct mkroom *));
36   | STATIC_DCL void FDECL(create_stairs, (stair *, struct mkroom *));
37   | STATIC_DCL void FDECL(create_altar, (altar *, struct mkroom *));
38   | STATIC_DCL void FDECL(create_gold, (gold *, struct mkroom *));
39   | STATIC_DCL void FDECL(create_feature, (int,int,struct mkroom *,int));
40   | STATIC_DCL boolean FDECL(search_door, (struct mkroom *, xchar *, xchar *,
41   | 					XCHAR_P, int));
42   | STATIC_DCL void NDECL(fix_stair_rooms);
43   | STATIC_DCL void FDECL(create_corridor, (corridor *));
44   | 
45   | STATIC_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   | 
68   | static NEARDATA walk walklist[50];
69   | extern int min_rx, max_rx, min_ry, max_ry; /* from mkmap.c */
70   | 
71   | static char Map[COLNO][ROWNO];
72   | static char robjects[10], rloc_x[10], rloc_y[10], rmonst[10];
73   | static aligntyp	ralign[3] = { AM_CHAOTIC, AM_NEUTRAL, AM_LAWFUL };
74   | static NEARDATA xchar xstart, ystart;
75   | static NEARDATA char xsize, ysize;
76   | 
77   | STATIC_DCL void FDECL(set_wall_property, (XCHAR_P,XCHAR_P,XCHAR_P,XCHAR_P,int));
78   | STATIC_DCL int NDECL(rnddoor);
79   | STATIC_DCL int NDECL(rndtrap);
80   | STATIC_DCL void FDECL(get_location, (schar *,schar *,int));
81   | STATIC_DCL void FDECL(sp_lev_shuffle, (char *,char *,int));
82   | STATIC_DCL void FDECL(light_region, (region *));
83   | STATIC_DCL void FDECL(load_common_data, (dlb *,int));
84   | STATIC_DCL void FDECL(load_one_monster, (dlb *,monster *));
85   | STATIC_DCL void FDECL(load_one_object, (dlb *,object *));
86   | STATIC_DCL void FDECL(load_one_engraving, (dlb *,engraving *));
87   | STATIC_DCL boolean FDECL(load_rooms, (dlb *));
88   | STATIC_DCL void FDECL(maze1xy, (coord *,int));
89   | STATIC_DCL boolean FDECL(load_maze, (dlb *));
90   | STATIC_DCL void FDECL(create_door, (room_door *, struct mkroom *));
91   | STATIC_DCL void FDECL(free_rooms,(room **, int));
92   | STATIC_DCL void FDECL(build_room, (room *, room*));
93   | 
94   | char *lev_message = 0;
95   | lev_region *lregions = 0;
96   | int num_lregions = 0;
97   | lev_init init_lev;
98   | 
99   | /*
100  |  * Make walls of the area (x1, y1, x2, y2) non diggable/non passwall-able
101  |  */
102  | 
103  | STATIC_OVL void
104  | set_wall_property(x1,y1,x2,y2, prop)
105  | xchar x1, y1, x2, y2;
106  | int 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  |  */
119  | STATIC_OVL int
120  | rnddoor()
121  | {
122  | 	int i = 1 << rn2(5);
123  | 	i >>= 1;
124  | 	return i;
125  | }
126  | 
127  | /*
128  |  * Select a random trap
129  |  */
130  | STATIC_OVL int
131  | rndtrap()
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  | 
168  | STATIC_DCL boolean FDECL(is_ok_location, (SCHAR_P, SCHAR_P, int));
169  | 
170  | STATIC_OVL void
171  | get_location(x, y, humidity)
172  | schar *x, *y;
173  | int 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  | 	}
201  | found_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  | 
209  | STATIC_OVL boolean
210  | is_ok_location(x, y, humidity)
211  | register schar x, y;
212  | register 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  | 
235  | STATIC_OVL void
236  | sp_lev_shuffle(list1, list2, n)
237  | char list1[], list2[];
238  | int 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  | 
261  | STATIC_OVL void
262  | get_room_loc(x,y, croom)
263  | schar		*x, *y;
264  | struct 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  | 
289  | STATIC_OVL void
290  | get_free_room_loc(x,y, croom)
291  | schar		*x, *y;
292  | struct 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  | 
307  | boolean
308  | check_room(lowx, ddx, lowy, ddy, vault)
309  | xchar *lowx, *ddx, *lowy, *ddy;
310  | boolean 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;
323  | chk:
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 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  | 
362  | boolean
363  | create_room(x,y,w,h,xal,yal,rtype,rlit)
364  | xchar	x,y;
365  | xchar	w,h;
366  | xchar	xal,yal;
367  | xchar	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 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  | 
532  | STATIC_OVL boolean
533  | create_subroom(proom, x, y, w,  h, rtype, rlit)
534  | struct mkroom *proom;
535  | xchar x,y;
536  | xchar w,h;
537  | xchar 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  | 
581  | STATIC_OVL void
582  | create_door(dd, broom)
583  | room_door *dd;
584  | struct 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  |  */
665  | void
666  | create_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  | 
707  | STATIC_OVL void
708  | create_trap(t,croom)
709  | trap	*t;
710  | struct 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  | 
734  | STATIC_OVL int
735  | noncoalignment(alignment)
736  | aligntyp 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  | 
746  | STATIC_OVL void
747  | create_monster(m,croom)
748  | monster	*m;
749  | struct 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 (!strcmp(OBJ_NAME(objects[i]),
854  | 					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  | 
907  | STATIC_OVL void
908  | create_object(o,croom)
909  | object	*o;
910  | struct mkroom	*croom;
911  | {
912  |     struct obj *otmp;
913  |     schar x, y;
914  |     char c;
915  | 
916  |     if (rn2(100) < o->chance) {
917  | 
918  | 	x = o->x; y = o->y;
919  | 	if (croom)
920  | 	    get_room_loc(&x, &y, croom);
921  | 	else
922  | 	    get_location(&x, &y, DRY);
923  | 
924  | 	if (o->class >= 0)
925  | 	    c = o->class;
926  | 	else if (o->class > -11)
927  | 	    c = robjects[ -(o->class+1)];
928  | 	else
929  | 	    c = 0;
930  | 
931  | 	if (!c)
932  | 	    otmp = mkobj_at(RANDOM_CLASS, x, y, TRUE);
933  | 	else if (o->id != -1)
934  | 	    otmp = mksobj_at(o->id, x, y, TRUE);
935  | 	else {
936  | 	    /*
937  | 	     * The special levels are compiled with the default "text" object
938  | 	     * class characters.  We must convert them to the internal format.
939  | 	     */
940  | 	    char oclass = (char) def_char_to_objclass(c);
941  | 
942  | 	    if (oclass == MAXOCLASSES)
943  | 		panic("create_object:  unexpected object class '%c'",c);
944  | 
945  | 	    /* KMH -- Create piles of gold properly */
946  | 	    if (oclass == GOLD_CLASS)
947  | 	    	otmp = mkgold(0L, x, y);
948  | 	    else
949  | 	    	otmp = mkobj_at(oclass, x, y, TRUE);
950  | 	}
951  | 
952  | 	if (o->spe != -127)	/* That means NOT RANDOM! */
953  | 	    otmp->spe = (schar)o->spe;
954  | 
955  | 	switch (o->curse_state) {
956  | 	      case 1:	bless(otmp); break; /* BLESSED */
957  | 	      case 2:	unbless(otmp); uncurse(otmp); break; /* uncursed */
958  | 	      case 3:	curse(otmp); break; /* CURSED */
959  | 	      default:	break;	/* Otherwise it's random and we're happy
960  | 				 * with what mkobj gave us! */
961  | 	}
962  | 
963  | 	/*	corpsenm is "empty" if -1, random if -2, otherwise specific */
964  | 	if (o->corpsenm == NON_PM - 1) otmp->corpsenm = rndmonnum();
965  | 	else if (o->corpsenm != NON_PM) otmp->corpsenm = o->corpsenm;
966  | 
967  | 	/* assume we wouldn't be given an egg corpsenm unless it was
968  | 	   hatchable */
969  | 	if (otmp->otyp == EGG && otmp->corpsenm != NON_PM) {
970  | 	    if (dead_species(otmp->otyp, TRUE))
971  | 		kill_egg(otmp);	/* make sure nothing hatches */
972  | 	    else
973  | 		attach_egg_hatch_timeout(otmp);	/* attach new hatch timeout */
974  | 	}
975  | 
976  | 	if (o->name.str) {	/* Give a name to that object */
977  | 	    otmp = oname(otmp, o->name.str);
978  | 	}
979  | 
980  | 	switch(o->containment) {
981  | 	    static struct obj *container = 0;
982  | 
983  | 	    /* contents */
984  | 	    case 1:
985  | 		if (!container) {
986  | 		    impossible("create_object: no container");
987  | 		    break;
988  | 		}
989  | 		remove_object(otmp);
990  | 		add_to_container(container, otmp);
991  | 		goto o_done;		/* don't stack, but do other cleanup */
992  | 	    /* container */
993  | 	    case 2:
994  | 		delete_contents(otmp);
995  | 		container = otmp;
996  | 		break;
997  | 	    /* nothing */
998  | 	    case 0: break;
999  | 
1000 | 	    default: impossible("containment type %d?", (int) o->containment);
1001 | 	}
1002 | 
1003 | 	/* Medusa level special case: statues are petrified monsters, so they
1004 | 	 * are not stone-resistant and have monster inventory.  They also lack
1005 | 	 * other contents, but that can be specified as an empty container.
1006 | 	 */
1007 | 	if (o->id == STATUE && Is_medusa_level(&u.uz) &&
1008 | 		    o->corpsenm == NON_PM) {
1009 | 	    struct monst *was;
1010 | 	    struct obj *obj;
1011 | 	    int wastyp;
1012 | 
1013 | 	    /* Named random statues are of player types, and aren't stone-
1014 | 	     * resistant (if they were, we'd have to reset the name as well as
1015 | 	     * setting corpsenm).
1016 | 	     */
1017 | 	    for (wastyp = otmp->corpsenm; ; wastyp = rndmonnum()) {
1018 | 		/* makemon without rndmonst() might create a group */
1019 | 		was = makemon(&mons[wastyp], 0, 0, NO_MM_FLAGS);
1020 | 		if (!resists_ston(was)) break;
1021 | 		mongone(was);
1022 | 	    }
1023 | 	    otmp->corpsenm = wastyp;
1024 | 	    while(was->minvent) {
1025 | 		obj = was->minvent;
1026 | 		obj->owornmask = 0;
1027 | 		obj_extract_self(obj);
1028 | 		add_to_container(otmp, obj);
1029 | 	    }
1030 | 	    mongone(was);
1031 | 	}
1032 | 
1033 | 	stackobj(otmp);
1034 | 
1035 |     }		/* if (rn2(100) < o->chance) */
1036 |  o_done:
1037 |     Free(o->name.str);
1038 | }
1039 | 
1040 | /*
1041 |  * Randomly place a specific engraving, then release its memory.
1042 |  */
1043 | STATIC_OVL void
1044 | create_engraving(e, croom)
1045 | engraving *e;
1046 | struct mkroom *croom;
1047 | {
1048 | 	xchar x, y;
1049 | 
1050 | 	x = e->x,  y = e->y;
1051 | 	if (croom)
1052 | 	    get_room_loc(&x, &y, croom);
1053 | 	else
1054 | 	    get_location(&x, &y, DRY);
1055 | 
1056 | 	make_engr_at(x, y, e->engr.str, 0L, e->etype);
1057 | 	free((genericptr_t) e->engr.str);
1058 | }
1059 | 
1060 | /*
1061 |  * Create stairs in a room.
1062 |  *
1063 |  */
1064 | 
1065 | STATIC_OVL void
1066 | create_stairs(s,croom)
1067 | stair	*s;
1068 | struct mkroom	*croom;
1069 | {
1070 | 	schar		x,y;
1071 | 
1072 | 	x = s->x; y = s->y;
1073 | 	get_free_room_loc(&x, &y, croom);
1074 | 	mkstairs(x,y,(char)s->up, croom);
1075 | }
1076 | 
1077 | /*
1078 |  * Create an altar in a room.
1079 |  */
1080 | 
1081 | STATIC_OVL void
1082 | create_altar(a, croom)
1083 | 	altar		*a;
1084 | 	struct mkroom	*croom;
1085 | {
1086 | 	schar		sproom,x,y;
1087 | 	aligntyp	amask;
1088 | 	boolean		croom_is_temple = TRUE;
1089 | 	int oldtyp; 
1090 | 
1091 | 	x = a->x; y = a->y;
1092 | 
1093 | 	if (croom) {
1094 | 	    get_free_room_loc(&x, &y, croom);
1095 | 	    if (croom->rtype != TEMPLE)
1096 | 		croom_is_temple = FALSE;
1097 | 	} else {
1098 | 	    get_location(&x, &y, DRY);
1099 | 	    if ((sproom = (schar) *in_rooms(x, y, TEMPLE)) != 0)
1100 | 		croom = &rooms[sproom - ROOMOFFSET];
1101 | 	    else
1102 | 		croom_is_temple = FALSE;
1103 | 	}
1104 | 
1105 | 	/* check for existing features */
1106 | 	oldtyp = levl[x][y].typ;
1107 | 	if (oldtyp == STAIRS || oldtyp == LADDER)
1108 | 	    return;
1109 | 
1110 | 	a->x = x;
1111 | 	a->y = y;
1112 | 
1113 | 	/* Is the alignment random ?
1114 | 	 * If so, it's an 80% chance that the altar will be co-aligned.
1115 | 	 *
1116 | 	 * The alignment is encoded as amask values instead of alignment
1117 | 	 * values to avoid conflicting with the rest of the encoding,
1118 | 	 * shared by many other parts of the special level code.
1119 | 	 */
1120 | 
1121 | 	amask = (a->align == AM_SPLEV_CO) ?
1122 | 			Align2amask(u.ualignbase[A_ORIGINAL]) :
1123 | 		(a->align == AM_SPLEV_NONCO) ?
1124 | 			Align2amask(noncoalignment(u.ualignbase[A_ORIGINAL])) :
1125 | 		(a->align == -11) ? induced_align(80) :
1126 | 		(a->align < 0 ? ralign[-a->align-1] : a->align);
1127 | 
1128 | 	levl[x][y].typ = ALTAR;
1129 | 	levl[x][y].altarmask = amask;
1130 | 
1131 | 	if (a->shrine == -11) a->shrine = rn2(1);  /* handle random case */
1132 | 
1133 | 	if (oldtyp == FOUNTAIN)
1134 | 	    level.flags.nfountains--;
1135 | 	else if (oldtyp == SINK)
1136 | 	    level.flags.nsinks--;
1137 | 
1138 | 	if (!croom_is_temple || !a->shrine) return;
1139 | 
1140 | 	if (a->shrine) {	/* Is it a shrine  or sanctum? */
1141 | 	    priestini(&u.uz, croom, x, y, (a->shrine > 1));
1142 | 	    levl[x][y].altarmask |= AM_SHRINE;
1143 | 	    level.flags.has_temple = TRUE;
1144 | 	}
1145 | }
1146 | 
1147 | /*
1148 |  * Create a gold pile in a room.
1149 |  */
1150 | 
1151 | STATIC_OVL void
1152 | create_gold(g,croom)
1153 | gold *g;
1154 | struct mkroom	*croom;
1155 | {
1156 | 	schar		x,y;
1157 | 
1158 | 	x = g->x; y= g->y;
1159 | 	if (croom)
1160 | 	    get_room_loc(&x, &y, croom);
1161 | 	else
1162 | 	    get_location(&x, &y, DRY);
1163 | 
1164 | 	if (g->amount == -1)
1165 | 	    g->amount = rnd(200);
1166 | 	(void) mkgold((long) g->amount, x, y);
1167 | }
1168 | 
1169 | /*
1170 |  * Create a feature (e.g a fountain) in a room.
1171 |  */
1172 | 
1173 | STATIC_OVL void
1174 | create_feature(fx, fy, croom, typ)
1175 | int		fx, fy;
1176 | struct mkroom	*croom;
1177 | int		typ;
1178 | {
1179 | 	schar		x,y;
1180 | 	int		trycnt = 0;
1181 | 
1182 | 	x = fx;  y = fy;
1183 | 	if (croom) {
1184 | 	    if (x < 0 && y < 0)
1185 | 		do {
1186 | 		    x = -1;  y = -1;
1187 | 		    get_room_loc(&x, &y, croom);
1188 | 		} while (++trycnt <= 200 && occupied(x,y));
1189 | 	    else
1190 | 		get_room_loc(&x, &y, croom);
1191 | 	    if(trycnt > 200)
1192 | 		return;
1193 | 	} else {
1194 | 	    get_location(&x, &y, DRY);
1195 | 	}
1196 | 	/* Don't cover up an existing feature (particularly randomly
1197 | 	   placed stairs).  However, if the _same_ feature is already
1198 | 	   here, it came from the map drawing and we still need to
1199 | 	   update the special counters. */
1200 | 	if (IS_FURNITURE(levl[x][y].typ) && levl[x][y].typ != typ)
1201 | 	    return;
1202 | 
1203 | 	levl[x][y].typ = typ;
1204 | 	if (typ == FOUNTAIN)
1205 | 	    level.flags.nfountains++;
1206 | 	else if (typ == SINK)
1207 | 	    level.flags.nsinks++;
1208 | }
1209 | 
1210 | /*
1211 |  * Search for a door in a room on a specified wall.
1212 |  */
1213 | 
1214 | STATIC_OVL boolean
1215 | search_door(croom,x,y,wall,cnt)
1216 | struct mkroom *croom;
1217 | xchar *x, *y;
1218 | xchar wall;
1219 | int cnt;
1220 | {
1221 | 	int dx, dy;
1222 | 	int xx,yy;
1223 | 
1224 | 	switch(wall) {
1225 | 	      case W_NORTH:
1226 | 		dy = 0; dx = 1;
1227 | 		xx = croom->lx;
1228 | 		yy = croom->hy + 1;
1229 | 		break;
1230 | 	      case W_SOUTH:
1231 | 		dy = 0; dx = 1;
1232 | 		xx = croom->lx;
1233 | 		yy = croom->ly - 1;
1234 | 		break;
1235 | 	      case W_EAST:
1236 | 		dy = 1; dx = 0;
1237 | 		xx = croom->hx + 1;
1238 | 		yy = croom->ly;
1239 | 		break;
1240 | 	      case W_WEST:
1241 | 		dy = 1; dx = 0;
1242 | 		xx = croom->lx - 1;
1243 | 		yy = croom->ly;
1244 | 		break;
1245 | 	      default:
1246 | 		dx = dy = xx = yy = 0;
1247 | 		panic("search_door: Bad wall!");
1248 | 		break;
1249 | 	}
1250 | 	while (xx <= croom->hx+1 && yy <= croom->hy+1) {
1251 | 		if (IS_DOOR(levl[xx][yy].typ) || levl[xx][yy].typ == SDOOR) {
1252 | 			*x = xx;
1253 | 			*y = yy;
1254 | 			if (cnt-- <= 0)
1255 | 			    return TRUE;
1256 | 		}
1257 | 		xx += dx;
1258 | 		yy += dy;
1259 | 	}
1260 | 	return FALSE;
1261 | }
1262 | 
1263 | /*
1264 |  * Dig a corridor between two points.
1265 |  */
1266 | 
1267 | boolean
1268 | dig_corridor(org,dest,nxcor,ftyp,btyp)
1269 | coord *org, *dest;
1270 | boolean nxcor;
1271 | schar ftyp, btyp;
1272 | {
1273 | 	register int dx=0, dy=0, dix, diy, cct;
1274 | 	register struct rm *crm;
1275 | 	register int tx, ty, xx, yy;
1276 | 
1277 | 	xx = org->x;  yy = org->y;
1278 | 	tx = dest->x; ty = dest->y;
1279 | 	if (xx <= 0 || yy <= 0 || tx <= 0 || ty <= 0 ||
1280 | 	    xx > COLNO-1 || tx > COLNO-1 ||
1281 | 	    yy > ROWNO-1 || ty > ROWNO-1) {
1282 | #ifdef DEBUG
1283 | 		debugpline("dig_corridor: bad coords : (%d,%d) (%d,%d).",
1284 | 			   xx,yy,tx,ty);
1285 | #endif
1286 | 		return FALSE;
1287 | 	}
1288 | 	if (tx > xx)		dx = 1;
1289 | 	else if (ty > yy)	dy = 1;
1290 | 	else if (tx < xx)	dx = -1;
1291 | 	else			dy = -1;
1292 | 
1293 | 	xx -= dx;
1294 | 	yy -= dy;
1295 | 	cct = 0;
1296 | 	while(xx != tx || yy != ty) {
1297 | 	    /* loop: dig corridor at [xx,yy] and find new [xx,yy] */
1298 | 	    if(cct++ > 500 || (nxcor && !rn2(35)))
1299 | 		return FALSE;
1300 | 
1301 | 	    xx += dx;
1302 | 	    yy += dy;
1303 | 
1304 | 	    if(xx >= COLNO-1 || xx <= 0 || yy <= 0 || yy >= ROWNO-1)
1305 | 		return FALSE;		/* impossible */
1306 | 
1307 | 	    crm = &levl[xx][yy];
1308 | 	    if(crm->typ == btyp) {
1309 | 		if(ftyp != CORR || rn2(100)) {
1310 | 			crm->typ = ftyp;
1311 | 			if(nxcor && !rn2(50))
1312 | 				(void) mksobj_at(BOULDER, xx, yy, TRUE);
1313 | 		} else {
1314 | 			crm->typ = SCORR;
1315 | 		}
1316 | 	    } else
1317 | 	    if(crm->typ != ftyp && crm->typ != SCORR) {
1318 | 		/* strange ... */
1319 | 		return FALSE;
1320 | 	    }
1321 | 
1322 | 	    /* find next corridor position */
1323 | 	    dix = abs(xx-tx);
1324 | 	    diy = abs(yy-ty);
1325 | 
1326 | 	    /* do we have to change direction ? */
1327 | 	    if(dy && dix > diy) {
1328 | 		register int ddx = (xx > tx) ? -1 : 1;
1329 | 
1330 | 		crm = &levl[xx+ddx][yy];
1331 | 		if(crm->typ == btyp || crm->typ == ftyp || crm->typ == SCORR) {
1332 | 		    dx = ddx;
1333 | 		    dy = 0;
1334 | 		    continue;
1335 | 		}
1336 | 	    } else if(dx && diy > dix) {
1337 | 		register int ddy = (yy > ty) ? -1 : 1;
1338 | 
1339 | 		crm = &levl[xx][yy+ddy];
1340 | 		if(crm->typ == btyp || crm->typ == ftyp || crm->typ == SCORR) {
1341 | 		    dy = ddy;
1342 | 		    dx = 0;
1343 | 		    continue;
1344 | 		}
1345 | 	    }
1346 | 
1347 | 	    /* continue straight on? */
1348 | 	    crm = &levl[xx+dx][yy+dy];
1349 | 	    if(crm->typ == btyp || crm->typ == ftyp || crm->typ == SCORR)
1350 | 		continue;
1351 | 
1352 | 	    /* no, what must we do now?? */
1353 | 	    if(dx) {
1354 | 		dx = 0;
1355 | 		dy = (ty < yy) ? -1 : 1;
1356 | 	    } else {
1357 | 		dy = 0;
1358 | 		dx = (tx < xx) ? -1 : 1;
1359 | 	    }
1360 | 	    crm = &levl[xx+dx][yy+dy];
1361 | 	    if(crm->typ == btyp || crm->typ == ftyp || crm->typ == SCORR)
1362 | 		continue;
1363 | 	    dy = -dy;
1364 | 	    dx = -dx;
1365 | 	}
1366 | 	return TRUE;
1367 | }
1368 | 
1369 | /*
1370 |  * Disgusting hack: since special levels have their rooms filled before
1371 |  * sorting the rooms, we have to re-arrange the speed values upstairs_room
1372 |  * and dnstairs_room after the rooms have been sorted.  On normal levels,
1373 |  * stairs don't get created until _after_ sorting takes place.
1374 |  */
1375 | STATIC_OVL void
1376 | fix_stair_rooms()
1377 | {
1378 |     int i;
1379 |     struct mkroom *croom;
1380 | 
1381 |     if(xdnstair &&
1382 |        !((dnstairs_room->lx <= xdnstair && xdnstair <= dnstairs_room->hx) &&
1383 | 	 (dnstairs_room->ly <= ydnstair && ydnstair <= dnstairs_room->hy))) {
1384 | 	for(i=0; i < nroom; i++) {
1385 | 	    croom = &rooms[i];
1386 | 	    if((croom->lx <= xdnstair && xdnstair <= croom->hx) &&
1387 | 	       (croom->ly <= ydnstair && ydnstair <= croom->hy)) {
1388 | 		dnstairs_room = croom;
1389 | 		break;
1390 | 	    }
1391 | 	}
1392 | 	if(i == nroom)
1393 | 	    panic("Couldn't find dnstair room in fix_stair_rooms!");
1394 |     }
1395 |     if(xupstair &&
1396 |        !((upstairs_room->lx <= xupstair && xupstair <= upstairs_room->hx) &&
1397 | 	 (upstairs_room->ly <= yupstair && yupstair <= upstairs_room->hy))) {
1398 | 	for(i=0; i < nroom; i++) {
1399 | 	    croom = &rooms[i];
1400 | 	    if((croom->lx <= xupstair && xupstair <= croom->hx) &&
1401 | 	       (croom->ly <= yupstair && yupstair <= croom->hy)) {
1402 | 		upstairs_room = croom;
1403 | 		break;
1404 | 	    }
1405 | 	}
1406 | 	if(i == nroom)
1407 | 	    panic("Couldn't find upstair room in fix_stair_rooms!");
1408 |     }
1409 | }
1410 | 
1411 | /*
1412 |  * Corridors always start from a door. But it can end anywhere...
1413 |  * Basically we search for door coordinates or for endpoints coordinates
1414 |  * (from a distance).
1415 |  */
1416 | 
1417 | STATIC_OVL void
1418 | create_corridor(c)
1419 | corridor	*c;
1420 | {
1421 | 	coord org, dest;
1422 | 
1423 | 	if (c->src.room == -1) {
1424 | 		sort_rooms();
1425 | 		fix_stair_rooms();
1426 | 		makecorridors();
1427 | 		return;
1428 | 	}
1429 | 
1430 | 	if( !search_door(&rooms[c->src.room], &org.x, &org.y, c->src.wall,
1431 | 			 c->src.door))
1432 | 	    return;
1433 | 
1434 | 	if (c->dest.room != -1) {
1435 | 		if(!search_door(&rooms[c->dest.room], &dest.x, &dest.y,
1436 | 				c->dest.wall, c->dest.door))
1437 | 		    return;
1438 | 		switch(c->src.wall) {
1439 | 		      case W_NORTH: org.y--; break;
1440 | 		      case W_SOUTH: org.y++; break;
1441 | 		      case W_WEST:  org.x--; break;
1442 | 		      case W_EAST:  org.x++; break;
1443 | 		}
1444 | 		switch(c->dest.wall) {
1445 | 		      case W_NORTH: dest.y--; break;
1446 | 		      case W_SOUTH: dest.y++; break;
1447 | 		      case W_WEST:  dest.x--; break;
1448 | 		      case W_EAST:  dest.x++; break;
1449 | 		}
1450 | 		(void) dig_corridor(&org, &dest, FALSE, CORR, STONE);
1451 | 	}
1452 | }
1453 | 
1454 | 
1455 | /*
1456 |  * Fill a room (shop, zoo, etc...) with appropriate stuff.
1457 |  */
1458 | 
1459 | void
1460 | fill_room(croom, prefilled)
1461 | struct mkroom *croom;
1462 | boolean prefilled;
1463 | {
1464 | 	if (!croom || croom->rtype == OROOM)
1465 | 	    return;
1466 | 
1467 | 	if (!prefilled) {
1468 | 	    int x,y;
1469 | 
1470 | 	    /* Shop ? */
1471 | 	    if (croom->rtype >= SHOPBASE) {
1472 | 		    stock_room(croom->rtype - SHOPBASE, croom);
1473 | 		    level.flags.has_shop = TRUE;
1474 | 		    return;
1475 | 	    }
1476 | 
1477 | 	    switch (croom->rtype) {
1478 | 		case VAULT:
1479 | 		    for (x=croom->lx;x<=croom->hx;x++)
1480 | 			for (y=croom->ly;y<=croom->hy;y++)
1481 | 			    (void) mkgold((long)rn1(abs(depth(&u.uz))*100, 51), x, y);
1482 | 		    break;
1483 | 		case COURT:
1484 | 		case ZOO:
1485 | 		case BEEHIVE:
1486 | 		case MORGUE:
1487 | 		case BARRACKS:
1488 | 		    fill_zoo(croom);
1489 | 		    break;
1490 | 	    }
1491 | 	}
1492 | 	switch (croom->rtype) {
1493 | 	    case VAULT:
1494 | 		level.flags.has_vault = TRUE;
1495 | 		break;
1496 | 	    case ZOO:
1497 | 		level.flags.has_zoo = TRUE;
1498 | 		break;
1499 | 	    case COURT:
1500 | 		level.flags.has_court = TRUE;
1501 | 		break;
1502 | 	    case MORGUE:
1503 | 		level.flags.has_morgue = TRUE;
1504 | 		break;
1505 | 	    case BEEHIVE:
1506 | 		level.flags.has_beehive = TRUE;
1507 | 		break;
1508 | 	    case BARRACKS:
1509 | 		level.flags.has_barracks = TRUE;
1510 | 		break;
1511 | 	    case TEMPLE:
1512 | 		level.flags.has_temple = TRUE;
1513 | 		break;
1514 | 	    case SWAMP:
1515 | 		level.flags.has_swamp = TRUE;
1516 | 		break;
1517 | 	}
1518 | }
1519 | 
1520 | STATIC_OVL void
1521 | free_rooms(ro, n)
1522 | room **ro;
1523 | int n;
1524 | {
1525 | 	short j;
1526 | 	room *r;
1527 | 
1528 | 	while(n--) {
1529 | 		r = ro[n];
1530 | 		Free(r->name);
1531 | 		Free(r->parent);
1532 | 		if ((j = r->ndoor) != 0) {
1533 | 			while(j--)
1534 | 			    Free(r->doors[j]);
1535 | 			Free(r->doors);
1536 | 		}
1537 | 		if ((j = r->nstair) != 0) {
1538 | 			while(j--)
1539 | 			    Free(r->stairs[j]);
1540 | 			Free(r->stairs);
1541 | 		}
1542 | 		if ((j = r->naltar) != 0) {
1543 | 			while (j--)
1544 | 			    Free(r->altars[j]);
1545 | 			Free(r->altars);
1546 | 		}
1547 | 		if ((j = r->nfountain) != 0) {
1548 | 			while(j--)
1549 | 			    Free(r->fountains[j]);
1550 | 			Free(r->fountains);
1551 | 		}
1552 | 		if ((j = r->nsink) != 0) {
1553 | 			while(j--)
1554 | 			    Free(r->sinks[j]);
1555 | 			Free(r->sinks);
1556 | 		}
1557 | 		if ((j = r->npool) != 0) {
1558 | 			while(j--)
1559 | 			    Free(r->pools[j]);
1560 | 			Free(r->pools);
1561 | 		}
1562 | 		if ((j = r->ntrap) != 0) {
1563 | 			while (j--)
1564 | 			    Free(r->traps[j]);
1565 | 			Free(r->traps);
1566 | 		}
1567 | 		if ((j = r->nmonster) != 0) {
1568 | 			while (j--)
1569 | 				Free(r->monsters[j]);
1570 | 			Free(r->monsters);
1571 | 		}
1572 | 		if ((j = r->nobject) != 0) {
1573 | 			while (j--)
1574 | 				Free(r->objects[j]);
1575 | 			Free(r->objects);
1576 | 		}
1577 | 		if ((j = r->ngold) != 0) {
1578 | 			while(j--)
1579 | 			    Free(r->golds[j]);
1580 | 			Free(r->golds);
1581 | 		}
1582 | 		if ((j = r->nengraving) != 0) {
1583 | 			while (j--)
1584 | 				Free(r->engravings[j]);
1585 | 			Free(r->engravings);
1586 | 		}
1587 | 		Free(r);
1588 | 	}
1589 | 	Free(ro);
1590 | }
1591 | 
1592 | STATIC_OVL void
1593 | build_room(r, pr)
1594 | room *r, *pr;
1595 | {
1596 | 	boolean okroom;
1597 | 	struct mkroom	*aroom;
1598 | 	short i;
1599 | 	xchar rtype = (!r->chance || rn2(100) < r->chance) ? r->rtype : OROOM;
1600 | 
1601 | 	if(pr) {
1602 | 		aroom = &subrooms[nsubroom];
1603 | 		okroom = create_subroom(pr->mkr, r->x, r->y, r->w, r->h,
1604 | 					rtype, r->rlit);
1605 | 	} else {
1606 | 		aroom = &rooms[nroom];
1607 | 		okroom = create_room(r->x, r->y, r->w, r->h, r->xalign,
1608 | 				     r->yalign, rtype, r->rlit);
1609 | 		r->mkr = aroom;
1610 | 	}
1611 | 
1612 | 	if (okroom) {
1613 | 		/* Create subrooms if necessary... */
1614 | 		for(i=0; i < r->nsubroom; i++)
1615 | 		    build_room(r->subrooms[i], r);
1616 | 		/* And now we can fill the room! */
1617 | 
1618 | 		/* Priority to the stairs */
1619 | 
1620 | 		for(i=0; i <r->nstair; i++)
1621 | 		    create_stairs(r->stairs[i], aroom);
1622 | 
1623 | 		/* Then to the various elements (sinks, etc..) */
1624 | 		for(i = 0; i<r->nsink; i++)
1625 | 		    create_feature(r->sinks[i]->x, r->sinks[i]->y, aroom, SINK);
1626 | 		for(i = 0; i<r->npool; i++)
1627 | 		    create_feature(r->pools[i]->x, r->pools[i]->y, aroom, POOL);
1628 | 		for(i = 0; i<r->nfountain; i++)
1629 | 		    create_feature(r->fountains[i]->x, r->fountains[i]->y,
1630 | 				   aroom, FOUNTAIN);
1631 | 		for(i = 0; i<r->naltar; i++)
1632 | 		    create_altar(r->altars[i], aroom);
1633 | 		for(i = 0; i<r->ndoor; i++)
1634 | 		    create_door(r->doors[i], aroom);
1635 | 
1636 | 		/* The traps */
1637 | 		for(i = 0; i<r->ntrap; i++)
1638 | 		    create_trap(r->traps[i], aroom);
1639 | 
1640 | 		/* The monsters */
1641 | 		for(i = 0; i<r->nmonster; i++)
1642 | 		    create_monster(r->monsters[i], aroom);
1643 | 
1644 | 		/* The objects */
1645 | 		for(i = 0; i<r->nobject; i++)
1646 | 		    create_object(r->objects[i], aroom);
1647 | 
1648 | 		/* The gold piles */
1649 | 		for(i = 0; i<r->ngold; i++)
1650 | 		    create_gold(r->golds[i], aroom);
1651 | 
1652 | 		/* The engravings */
1653 | 		for (i = 0; i < r->nengraving; i++)
1654 | 		    create_engraving(r->engravings[i], aroom);
1655 | 
1656 | #ifdef SPECIALIZATION
1657 | 		topologize(aroom,FALSE);		/* set roomno */
1658 | #else
1659 | 		topologize(aroom);			/* set roomno */
1660 | #endif
1661 | 		/* MRS - 07/04/91 - This is temporary but should result
1662 | 		 * in proper filling of shops, etc.
1663 | 		 * DLC - this can fail if corridors are added to this room
1664 | 		 * at a later point.  Currently no good way to fix this.
1665 | 		 */
1666 | 		if(aroom->rtype != OROOM && r->filled) fill_room(aroom, FALSE);
1667 | 	}
1668 | }
1669 | 
1670 | /*
1671 |  * set lighting in a region that will not become a room.
1672 |  */
1673 | STATIC_OVL void
1674 | light_region(tmpregion)
1675 |     region  *tmpregion;
1676 | {
1677 |     register boolean litstate = tmpregion->rlit ? 1 : 0;
1678 |     register int hiy = tmpregion->y2;
1679 |     register int x, y;
1680 |     register struct rm *lev;
1681 |     int lowy = tmpregion->y1;
1682 |     int lowx = tmpregion->x1, hix = tmpregion->x2;
1683 | 
1684 |     if(litstate) {
1685 | 	/* adjust region size for walls, but only if lighted */
1686 | 	lowx = max(lowx-1,1);
1687 | 	hix = min(hix+1,COLNO-1);
1688 | 	lowy = max(lowy-1,0);
1689 | 	hiy = min(hiy+1, ROWNO-1);
1690 |     }
1691 |     for(x = lowx; x <= hix; x++) {
1692 | 	lev = &levl[x][lowy];
1693 | 	for(y = lowy; y <= hiy; y++) {
1694 | 	    if (lev->typ != LAVAPOOL) /* this overrides normal lighting */
1695 | 		lev->lit = litstate;
1696 | 	    lev++;
1697 | 	}
1698 |     }
1699 | }
1700 | 
1701 | /* initialization common to all special levels */
1702 | STATIC_OVL void
1703 | load_common_data(fd, typ)
1704 | dlb *fd;
1705 | int typ;
1706 | {
1707 | 	uchar	n;
1708 | 	long	lev_flags;
1709 | 	int	i;
1710 | 
1711 |       {
1712 | 	aligntyp atmp;
1713 | 	/* shuffle 3 alignments; can't use sp_lev_shuffle() on aligntyp's */
1714 | 	i = rn2(3);   atmp=ralign[2]; ralign[2]=ralign[i]; ralign[i]=atmp;
1715 | 	if (rn2(2)) { atmp=ralign[1]; ralign[1]=ralign[0]; ralign[0]=atmp; }
1716 |       }
1717 | 
1718 | 	level.flags.is_maze_lev = typ == SP_LEV_MAZE;
1719 | 
1720 | 	/* Read the level initialization data */
1721 | 	Fread((genericptr_t) &init_lev, 1, sizeof(lev_init), fd);
1722 | 	if(init_lev.init_present) {
1723 | 	    if(init_lev.lit < 0)
1724 | 		init_lev.lit = rn2(2);
1725 | 	    mkmap(&init_lev);
1726 | 	}
1727 | 
1728 | 	/* Read the per level flags */
1729 | 	Fread((genericptr_t) &lev_flags, 1, sizeof(lev_flags), fd);
1730 | 	if (lev_flags & NOTELEPORT)
1731 | 	    level.flags.noteleport = 1;
1732 | 	if (lev_flags & HARDFLOOR)
1733 | 	    level.flags.hardfloor = 1;
1734 | 	if (lev_flags & NOMMAP)
1735 | 	    level.flags.nommap = 1;
1736 | 	if (lev_flags & SHORTSIGHTED)
1737 | 	    level.flags.shortsighted = 1;
1738 | 	if (lev_flags & ARBOREAL)
1739 | 	    level.flags.arboreal = 1;
1740 | 
1741 | 	/* Read message */
1742 | 	Fread((genericptr_t) &n, 1, sizeof(n), fd);
1743 | 	if (n) {
1744 | 	    lev_message = (char *) alloc(n + 1);
1745 | 	    Fread((genericptr_t) lev_message, 1, (int) n, fd);
1746 | 	    lev_message[n] = 0;
1747 | 	}
1748 | }
1749 | 
1750 | STATIC_OVL void
1751 | load_one_monster(fd, m)
1752 | dlb *fd;
1753 | monster *m;
1754 | {
1755 | 	int size;
1756 | 
1757 | 	Fread((genericptr_t) m, 1, sizeof *m, fd);
1758 | 	if ((size = m->name.len) != 0) {
1759 | 	    m->name.str = (char *) alloc((unsigned)size + 1);
1760 | 	    Fread((genericptr_t) m->name.str, 1, size, fd);
1761 | 	    m->name.str[size] = '\0';
1762 | 	} else
1763 | 	    m->name.str = (char *) 0;
1764 | 	if ((size = m->appear_as.len) != 0) {
1765 | 	    m->appear_as.str = (char *) alloc((unsigned)size + 1);
1766 | 	    Fread((genericptr_t) m->appear_as.str, 1, size, fd);
1767 | 	    m->appear_as.str[size] = '\0';
1768 | 	} else
1769 | 	    m->appear_as.str = (char *) 0;
1770 | }
1771 | 
1772 | STATIC_OVL void
1773 | load_one_object(fd, o)
1774 | dlb *fd;
1775 | object *o;
1776 | {
1777 | 	int size;
1778 | 
1779 | 	Fread((genericptr_t) o, 1, sizeof *o, fd);
1780 | 	if ((size = o->name.len) != 0) {
1781 | 	    o->name.str = (char *) alloc((unsigned)size + 1);
1782 | 	    Fread((genericptr_t) o->name.str, 1, size, fd);
1783 | 	    o->name.str[size] = '\0';
1784 | 	} else
1785 | 	    o->name.str = (char *) 0;
1786 | }
1787 | 
1788 | STATIC_OVL void
1789 | load_one_engraving(fd, e)
1790 | dlb *fd;
1791 | engraving *e;
1792 | {
1793 | 	int size;
1794 | 
1795 | 	Fread((genericptr_t) e, 1, sizeof *e, fd);
1796 | 	size = e->engr.len;
1797 | 	e->engr.str = (char *) alloc((unsigned)size+1);
1798 | 	Fread((genericptr_t) e->engr.str, 1, size, fd);
1799 | 	e->engr.str[size] = '\0';
1800 | }
1801 | 
1802 | STATIC_OVL boolean
1803 | load_rooms(fd)
1804 | dlb *fd;
1805 | {
1806 | 	xchar		nrooms, ncorr;
1807 | 	char		n;
1808 | 	short		size;
1809 | 	corridor	tmpcor;
1810 | 	room**		tmproom;
1811 | 	int		i, j;
1812 | 
1813 | 	load_common_data(fd, SP_LEV_ROOMS);
1814 | 
1815 | 	Fread((genericptr_t) &n, 1, sizeof(n), fd); /* nrobjects */
1816 | 	if (n) {
1817 | 		Fread((genericptr_t)robjects, sizeof(*robjects), n, fd);
1818 | 		sp_lev_shuffle(robjects, (char *)0, (int)n);
1819 | 	}
1820 | 
1821 | 	Fread((genericptr_t) &n, 1, sizeof(n), fd); /* nrmonst */
1822 | 	if (n) {
1823 | 		Fread((genericptr_t)rmonst, sizeof(*rmonst), n, fd);
1824 | 		sp_lev_shuffle(rmonst, (char *)0, (int)n);
1825 | 	}
1826 | 
1827 | 	Fread((genericptr_t) &nrooms, 1, sizeof(nrooms), fd);
1828 | 						/* Number of rooms to read */
1829 | 	tmproom = NewTab(room,nrooms);
1830 | 	for (i=0;i<nrooms;i++) {
1831 | 		room *r;
1832 | 
1833 | 		r = tmproom[i] = New(room);
1834 | 
1835 | 		/* Let's see if this room has a name */
1836 | 		Fread((genericptr_t) &size, 1, sizeof(size), fd);
1837 | 		if (size > 0) {	/* Yup, it does! */
1838 | 			r->name = (char *) alloc((unsigned)size + 1);
1839 | 			Fread((genericptr_t) r->name, 1, size, fd);
1840 | 			r->name[size] = 0;
1841 | 		} else
1842 | 		    r->name = (char *) 0;
1843 | 
1844 | 		/* Let's see if this room has a parent */
1845 | 		Fread((genericptr_t) &size, 1, sizeof(size), fd);
1846 | 		if (size > 0) {	/* Yup, it does! */
1847 | 			r->parent = (char *) alloc((unsigned)size + 1);
1848 | 			Fread((genericptr_t) r->parent, 1, size, fd);
1849 | 			r->parent[size] = 0;
1850 | 		} else
1851 | 		    r->parent = (char *) 0;
1852 | 
1853 | 		Fread((genericptr_t) &r->x, 1, sizeof(r->x), fd);
1854 | 					/* x pos on the grid (1-5) */
1855 | 		Fread((genericptr_t) &r->y, 1, sizeof(r->y), fd);
1856 | 					 /* y pos on the grid (1-5) */
1857 | 		Fread((genericptr_t) &r->w, 1, sizeof(r->w), fd);
1858 | 					 /* width of the room */
1859 | 		Fread((genericptr_t) &r->h, 1, sizeof(r->h), fd);
1860 | 					 /* height of the room */
1861 | 		Fread((genericptr_t) &r->xalign, 1, sizeof(r->xalign), fd);
1862 | 					 /* horizontal alignment */
1863 | 		Fread((genericptr_t) &r->yalign, 1, sizeof(r->yalign), fd);
1864 | 					 /* vertical alignment */
1865 | 		Fread((genericptr_t) &r->rtype, 1, sizeof(r->rtype), fd);
1866 | 					 /* type of room (zoo, shop, etc.) */
1867 | 		Fread((genericptr_t) &r->chance, 1, sizeof(r->chance), fd);
1868 | 					 /* chance of room being special. */
1869 | 		Fread((genericptr_t) &r->rlit, 1, sizeof(r->rlit), fd);
1870 | 					 /* lit or not ? */
1871 | 		Fread((genericptr_t) &r->filled, 1, sizeof(r->filled), fd);
1872 | 					 /* to be filled? */
1873 | 		r->nsubroom= 0;
1874 | 
1875 | 		/* read the doors */
1876 | 		Fread((genericptr_t) &r->ndoor, 1, sizeof(r->ndoor), fd);
1877 | 		if ((n = r->ndoor) != 0)
1878 | 		    r->doors = NewTab(room_door, n);
1879 | 		while(n--) {
1880 | 			r->doors[(int)n] = New(room_door);
1881 | 			Fread((genericptr_t) r->doors[(int)n], 1,
1882 | 				sizeof(room_door), fd);
1883 | 		}
1884 | 
1885 | 		/* read the stairs */
1886 | 		Fread((genericptr_t) &r->nstair, 1, sizeof(r->nstair), fd);
1887 | 		if ((n = r->nstair) != 0)
1888 | 		    r->stairs = NewTab(stair, n);
1889 | 		while (n--) {
1890 | 			r->stairs[(int)n] = New(stair);
1891 | 			Fread((genericptr_t) r->stairs[(int)n], 1,
1892 | 				sizeof(stair), fd);
1893 | 		}
1894 | 
1895 | 		/* read the altars */
1896 | 		Fread((genericptr_t) &r->naltar, 1, sizeof(r->naltar), fd);
1897 | 		if ((n = r->naltar) != 0)
1898 | 		    r->altars = NewTab(altar, n);
1899 | 		while (n--) {
1900 | 			r->altars[(int)n] = New(altar);
1901 | 			Fread((genericptr_t) r->altars[(int)n], 1,
1902 | 				sizeof(altar), fd);
1903 | 		}
1904 | 
1905 | 		/* read the fountains */
1906 | 		Fread((genericptr_t) &r->nfountain, 1,
1907 | 			sizeof(r->nfountain), fd);
1908 | 		if ((n = r->nfountain) != 0)
1909 | 		    r->fountains = NewTab(fountain, n);
1910 | 		while (n--) {
1911 | 			r->fountains[(int)n] = New(fountain);
1912 | 			Fread((genericptr_t) r->fountains[(int)n], 1,
1913 | 				sizeof(fountain), fd);
1914 | 		}
1915 | 
1916 | 		/* read the sinks */
1917 | 		Fread((genericptr_t) &r->nsink, 1, sizeof(r->nsink), fd);
1918 | 		if ((n = r->nsink) != 0)
1919 | 		    r->sinks = NewTab(sink, n);
1920 | 		while (n--) {
1921 | 			r->sinks[(int)n] = New(sink);
1922 | 			Fread((genericptr_t) r->sinks[(int)n], 1, sizeof(sink), fd);
1923 | 		}
1924 | 
1925 | 		/* read the pools */
1926 | 		Fread((genericptr_t) &r->npool, 1, sizeof(r->npool), fd);
1927 | 		if ((n = r->npool) != 0)
1928 | 		    r->pools = NewTab(pool,n);
1929 | 		while (n--) {
1930 | 			r->pools[(int)n] = New(pool);
1931 | 			Fread((genericptr_t) r->pools[(int)n], 1, sizeof(pool), fd);
1932 | 		}
1933 | 
1934 | 		/* read the traps */
1935 | 		Fread((genericptr_t) &r->ntrap, 1, sizeof(r->ntrap), fd);
1936 | 		if ((n = r->ntrap) != 0)
1937 | 		    r->traps = NewTab(trap, n);
1938 | 		while(n--) {
1939 | 			r->traps[(int)n] = New(trap);
1940 | 			Fread((genericptr_t) r->traps[(int)n], 1, sizeof(trap), fd);
1941 | 		}
1942 | 
1943 | 		/* read the monsters */
1944 | 		Fread((genericptr_t) &r->nmonster, 1, sizeof(r->nmonster), fd);
1945 | 		if ((n = r->nmonster) != 0) {
1946 | 		    r->monsters = NewTab(monster, n);
1947 | 		    while(n--) {
1948 | 			r->monsters[(int)n] = New(monster);
1949 | 			load_one_monster(fd, r->monsters[(int)n]);
1950 | 		    }
1951 | 		} else
1952 | 		    r->monsters = 0;
1953 | 
1954 | 		/* read the objects */
1955 | 		Fread((genericptr_t) &r->nobject, 1, sizeof(r->nobject), fd);
1956 | 		if ((n = r->nobject) != 0) {
1957 | 		    r->objects = NewTab(object, n);
1958 | 		    while (n--) {
1959 | 			r->objects[(int)n] = New(object);
1960 | 			load_one_object(fd, r->objects[(int)n]);
1961 | 		    }
1962 | 		} else
1963 | 		    r->objects = 0;
1964 | 
1965 | 		/* read the gold piles */
1966 | 		Fread((genericptr_t) &r->ngold, 1, sizeof(r->ngold), fd);
1967 | 		if ((n = r->ngold) != 0)
1968 | 		    r->golds = NewTab(gold, n);
1969 | 		while (n--) {
1970 | 			r->golds[(int)n] = New(gold);
1971 | 			Fread((genericptr_t) r->golds[(int)n], 1, sizeof(gold), fd);
1972 | 		}
1973 | 
1974 | 		/* read the engravings */
1975 | 		Fread((genericptr_t) &r->nengraving, 1,
1976 | 			sizeof(r->nengraving), fd);
1977 | 		if ((n = r->nengraving) != 0) {
1978 | 		    r->engravings = NewTab(engraving,n);
1979 | 		    while (n--) {
1980 | 			r->engravings[(int)n] = New(engraving);
1981 | 			load_one_engraving(fd, r->engravings[(int)n]);
1982 | 		    }
1983 | 		} else
1984 | 		    r->engravings = 0;
1985 | 
1986 | 	}
1987 | 
1988 | 	/* Now that we have loaded all the rooms, search the
1989 | 	 * subrooms and create the links.
1990 | 	 */
1991 | 
1992 | 	for (i = 0; i<nrooms; i++)
1993 | 	    if (tmproom[i]->parent) {
1994 | 		    /* Search the parent room */
1995 | 		    for(j=0; j<nrooms; j++)
1996 | 			if (tmproom[j]->name && !strcmp(tmproom[j]->name,
1997 | 						       tmproom[i]->parent)) {
1998 | 				n = tmproom[j]->nsubroom++;
1999 | 				tmproom[j]->subrooms[(int)n] = tmproom[i];
2000 | 				break;
2001 | 			}
2002 | 	    }
2003 | 
2004 | 	/*
2005 | 	 * Create the rooms now...
2006 | 	 */
2007 | 
2008 | 	for (i=0; i < nrooms; i++)
2009 | 	    if(!tmproom[i]->parent)
2010 | 		build_room(tmproom[i], (room *) 0);
2011 | 
2012 | 	free_rooms(tmproom, nrooms);
2013 | 
2014 | 	/* read the corridors */
2015 | 
2016 | 	Fread((genericptr_t) &ncorr, sizeof(ncorr), 1, fd);
2017 | 	for (i=0; i<ncorr; i++) {
2018 | 		Fread((genericptr_t) &tmpcor, 1, sizeof(tmpcor), fd);
2019 | 		create_corridor(&tmpcor);
2020 | 	}
2021 | 
2022 | 	return TRUE;
2023 | }
2024 | 
2025 | /*
2026 |  * Select a random coordinate in the maze.
2027 |  *
2028 |  * We want a place not 'touched' by the loader.  That is, a place in
2029 |  * the maze outside every part of the special level.
2030 |  */
2031 | 
2032 | STATIC_OVL void
2033 | maze1xy(m, humidity)
2034 | coord *m;
2035 | int humidity;
2036 | {
2037 | 	register int x, y, tryct = 2000;
2038 | 	/* tryct:  normally it won't take more than ten or so tries due
2039 | 	   to the circumstances under which we'll be called, but the
2040 | 	   `humidity' screening might drastically change the chances */
2041 | 
2042 | 	do {
2043 | 	    x = rn1(x_maze_max - 3, 3);
2044 | 	    y = rn1(y_maze_max - 3, 3);
2045 | 	    if (--tryct < 0) break;	/* give up */
2046 | 	} while (!(x % 2) || !(y % 2) || Map[x][y] ||
2047 | 		 !is_ok_location((schar)x, (schar)y, humidity));
2048 | 
2049 | 	m->x = (xchar)x,  m->y = (xchar)y;
2050 | }
2051 | 
2052 | /*
2053 |  * The Big Thing: special maze loader
2054 |  *
2055 |  * Could be cleaner, but it works.
2056 |  */
2057 | 
2058 | STATIC_OVL boolean
2059 | load_maze(fd)
2060 | dlb *fd;
2061 | {
2062 |     xchar   x, y, typ;
2063 |     boolean prefilled, room_not_needed;
2064 | 
2065 |     char    n, numpart = 0;
2066 |     xchar   nwalk = 0, nwalk_sav;
2067 |     schar   filling;
2068 |     char    halign, valign;
2069 | 
2070 |     int     xi, dir, size;
2071 |     coord   mm;
2072 |     int     mapcount, mapcountmax, mapfact;
2073 | 
2074 |     lev_region  tmplregion;
2075 |     region  tmpregion;
2076 |     door    tmpdoor;
2077 |     trap    tmptrap;
2078 |     monster tmpmons;
2079 |     object  tmpobj;
2080 |     drawbridge tmpdb;
2081 |     walk    tmpwalk;
2082 |     digpos  tmpdig;
2083 |     lad     tmplad;
2084 |     stair   tmpstair, prevstair;
2085 |     altar   tmpaltar;
2086 |     gold    tmpgold;
2087 |     fountain tmpfountain;
2088 |     engraving tmpengraving;
2089 |     xchar   mustfill[(MAXNROFROOMS+1)*2];
2090 |     struct trap *badtrap;
2091 |     boolean has_bounds;
2092 | 
2093 |     (void) memset((genericptr_t)&Map[0][0], 0, sizeof Map);
2094 |     load_common_data(fd, SP_LEV_MAZE);
2095 | 
2096 |     /* Initialize map */
2097 |     Fread((genericptr_t) &filling, 1, sizeof(filling), fd);
2098 |     if (!init_lev.init_present) { /* don't init if mkmap() has been called */
2099 |       for(x = 2; x <= x_maze_max; x++)
2100 | 	for(y = 0; y <= y_maze_max; y++)
2101 | 	    if (filling == -1) {
2102 | #ifndef WALLIFIED_MAZE
2103 | 		    levl[x][y].typ = STONE;
2104 | #else
2105 | 		    levl[x][y].typ =
2106 | 			(y < 2 || ((x % 2) && (y % 2))) ? STONE : HWALL;
2107 | #endif
2108 | 	    } else {
2109 | 		    levl[x][y].typ = filling;
2110 | 	    }
2111 |     }
2112 | 
2113 |     /* Start reading the file */
2114 |     Fread((genericptr_t) &numpart, 1, sizeof(numpart), fd);
2115 | 						/* Number of parts */
2116 |     if (!numpart || numpart > 9)
2117 | 	panic("load_maze error: numpart = %d", (int) numpart);
2118 | 
2119 |     while (numpart--) {
2120 | 	Fread((genericptr_t) &halign, 1, sizeof(halign), fd);
2121 | 					/* Horizontal alignment */
2122 | 	Fread((genericptr_t) &valign, 1, sizeof(valign), fd);
2123 | 					/* Vertical alignment */
2124 | 	Fread((genericptr_t) &xsize, 1, sizeof(xsize), fd);
2125 | 					/* size in X */
2126 | 	Fread((genericptr_t) &ysize, 1, sizeof(ysize), fd);
2127 | 					/* size in Y */
2128 | 	switch((int) halign) {
2129 | 	    case LEFT:	    xstart = 3;					break;
2130 | 	    case H_LEFT:    xstart = 2+((x_maze_max-2-xsize)/4);	break;
2131 | 	    case CENTER:    xstart = 2+((x_maze_max-2-xsize)/2);	break;
2132 | 	    case H_RIGHT:   xstart = 2+((x_maze_max-2-xsize)*3/4);	break;
2133 | 	    case RIGHT:     xstart = x_maze_max-xsize-1;		break;
2134 | 	}
2135 | 	switch((int) valign) {
2136 | 	    case TOP:	    ystart = 3;					break;
2137 | 	    case CENTER:    ystart = 2+((y_maze_max-2-ysize)/2);	break;
2138 | 	    case BOTTOM:    ystart = y_maze_max-ysize-1;		break;
2139 | 	}
2140 | 	if (!(xstart % 2)) xstart++;
2141 | 	if (!(ystart % 2)) ystart++;
2142 | 	if ((ystart < 0) || (ystart + ysize > ROWNO)) {
2143 | 	    /* try to move the start a bit */
2144 | 	    ystart += (ystart > 0) ? -2 : 2;
2145 | 	    if(ysize == ROWNO) ystart = 0;
2146 | 	    if(ystart < 0 || ystart + ysize > ROWNO)
2147 | 		panic("reading special level with ysize too large");
2148 | 	}
2149 | 
2150 | 	/*
2151 | 	 * If any CROSSWALLs are found, must change to ROOM after REGION's
2152 | 	 * are laid out.  CROSSWALLS are used to specify "invisible"
2153 | 	 * boundaries where DOOR syms look bad or aren't desirable.
2154 | 	 */
2155 | 	has_bounds = FALSE;
2156 | 
2157 | 	if(init_lev.init_present && xsize <= 1 && ysize <= 1) {
2158 | 	    xstart = 1;
2159 | 	    ystart = 0;
2160 | 	    xsize = COLNO-1;
2161 | 	    ysize = ROWNO;
2162 | 	} else {
2163 | 	    /* Load the map */
2164 | 	    for(y = ystart; y < ystart+ysize; y++)
2165 | 		for(x = xstart; x < xstart+xsize; x++) {
2166 | 		    levl[x][y].typ = Fgetc(fd);
2167 | 		    levl[x][y].lit = FALSE;
2168 | 		    /*
2169 | 		     * Note: Even though levl[x][y].typ is type schar,
2170 | 		     *	 lev_comp.y saves it as type char. Since schar != char
2171 | 		     *	 all the time we must make this exception or hack
2172 | 		     *	 through lev_comp.y to fix.
2173 | 		     */
2174 | 
2175 | 		    /*
2176 | 		     *  Set secret doors to closed (why not trapped too?).  Set
2177 | 		     *  the horizontal bit.
2178 | 		     */
2179 | 		    if (levl[x][y].typ == SDOOR || IS_DOOR(levl[x][y].typ)) {
2180 | 			if(levl[x][y].typ == SDOOR)
2181 | 			    levl[x][y].doormask = D_CLOSED;
2182 | 			/*
2183 | 			 *  If there is a wall to the left that connects to a
2184 | 			 *  (secret) door, then it is horizontal.  This does
2185 | 			 *  not allow (secret) doors to be corners of rooms.
2186 | 			 */
2187 | 			if (x != xstart && (IS_WALL(levl[x-1][y].typ) ||
2188 | 					    levl[x-1][y].horizontal))
2189 | 			    levl[x][y].horizontal = 1;
2190 | 		    } else if(levl[x][y].typ == HWALL)
2191 | 			levl[x][y].horizontal = 1;
2192 | 		    else if(levl[x][y].typ == LAVAPOOL)
2193 | 			levl[x][y].lit = 1;
2194 | 		    else if(levl[x][y].typ == CROSSWALL)
2195 | 			has_bounds = TRUE;
2196 | 		    Map[x][y] = 1;
2197 | 		}
2198 | 	}
2199 | 
2200 | 	Fread((genericptr_t) &n, 1, sizeof(n), fd);
2201 | 						/* Number of level regions */
2202 | 	if(n) {
2203 | 	    if(num_lregions) {
2204 | 		/* realloc the lregion space to add the new ones */
2205 | 		/* don't really free it up until the whole level is done */
2206 | 		lev_region *newl = (lev_region *) alloc(sizeof(lev_region) *
2207 | 						(unsigned)(n+num_lregions));
2208 | 		(void) memcpy((genericptr_t)(newl+n), (genericptr_t)lregions,
2209 | 					sizeof(lev_region) * num_lregions);
2210 | 		Free(lregions);
2211 | 		num_lregions += n;
2212 | 		lregions = newl;
2213 | 	    } else {
2214 | 		num_lregions = n;
2215 | 		lregions = (lev_region *)
2216 | 				alloc(sizeof(lev_region) * (unsigned)n);
2217 | 	    }
2218 | 	}
2219 | 
2220 | 	while(n--) {
2221 | 	    Fread((genericptr_t) &tmplregion, sizeof(tmplregion), 1, fd);
2222 | 	    if ((size = tmplregion.rname.len) != 0) {
2223 | 		tmplregion.rname.str = (char *) alloc((unsigned)size + 1);
2224 | 		Fread((genericptr_t) tmplregion.rname.str, size, 1, fd);
2225 | 		tmplregion.rname.str[size] = '\0';
2226 | 	    } else
2227 | 		tmplregion.rname.str = (char *) 0;
2228 | 	    if(!tmplregion.in_islev) {
2229 | 		get_location(&tmplregion.inarea.x1, &tmplregion.inarea.y1,
2230 | 								DRY|WET);
2231 | 		get_location(&tmplregion.inarea.x2, &tmplregion.inarea.y2,
2232 | 								DRY|WET);
2233 | 	    }
2234 | 	    if(!tmplregion.del_islev) {
2235 | 		get_location(&tmplregion.delarea.x1, &tmplregion.delarea.y1,
2236 | 								DRY|WET);
2237 | 		get_location(&tmplregion.delarea.x2, &tmplregion.delarea.y2,
2238 | 								DRY|WET);
2239 | 	    }
2240 | 	    lregions[(int)n] = tmplregion;
2241 | 	}
2242 | 
2243 | 	Fread((genericptr_t) &n, 1, sizeof(n), fd);
2244 | 						/* Random objects */
2245 | 	if(n) {
2246 | 		Fread((genericptr_t)robjects, sizeof(*robjects), (int) n, fd);
2247 | 		sp_lev_shuffle(robjects, (char *)0, (int)n);
2248 | 	}
2249 | 
2250 | 	Fread((genericptr_t) &n, 1, sizeof(n), fd);
2251 | 						/* Random locations */
2252 | 	if(n) {
2253 | 		Fread((genericptr_t)rloc_x, sizeof(*rloc_x), (int) n, fd);
2254 | 		Fread((genericptr_t)rloc_y, sizeof(*rloc_y), (int) n, fd);
2255 | 		sp_lev_shuffle(rloc_x, rloc_y, (int)n);
2256 | 	}
2257 | 
2258 | 	Fread((genericptr_t) &n, 1, sizeof(n), fd);
2259 | 						/* Random monsters */
2260 | 	if(n) {
2261 | 		Fread((genericptr_t)rmonst, sizeof(*rmonst), (int) n, fd);
2262 | 		sp_lev_shuffle(rmonst, (char *)0, (int)n);
2263 | 	}
2264 | 
2265 | 	(void) memset((genericptr_t)mustfill, 0, sizeof(mustfill));
2266 | 	Fread((genericptr_t) &n, 1, sizeof(n), fd);
2267 | 						/* Number of subrooms */
2268 | 	while(n--) {
2269 | 		register struct mkroom *troom;
2270 | 
2271 | 		Fread((genericptr_t)&tmpregion, 1, sizeof(tmpregion), fd);
2272 | 
2273 | 		if(tmpregion.rtype > MAXRTYPE) {
2274 | 		    tmpregion.rtype -= MAXRTYPE+1;
2275 | 		    prefilled = TRUE;
2276 | 		} else
2277 | 		    prefilled = FALSE;
2278 | 
2279 | 		if(tmpregion.rlit < 0)
2280 | 		    tmpregion.rlit = (rnd(1+abs(depth(&u.uz))) < 11 && rn2(77))
2281 | 			? TRUE : FALSE;
2282 | 
2283 | 		get_location(&tmpregion.x1, &tmpregion.y1, DRY|WET);
2284 | 		get_location(&tmpregion.x2, &tmpregion.y2, DRY|WET);
2285 | 
2286 | 		/* for an ordinary room, `prefilled' is a flag to force
2287 | 		   an actual room to be created (such rooms are used to
2288 | 		   control placement of migrating monster arrivals) */
2289 | 		room_not_needed = (tmpregion.rtype == OROOM &&
2290 | 				   !tmpregion.rirreg && !prefilled);
2291 | 		if (room_not_needed || nroom >= MAXNROFROOMS) {
2292 | 		    if (!room_not_needed)
2293 | 			impossible("Too many rooms on new level!");
2294 | 		    light_region(&tmpregion);
2295 | 		    continue;
2296 | 		}
2297 | 
2298 | 		troom = &rooms[nroom];
2299 | 
2300 | 		/* mark rooms that must be filled, but do it later */
2301 | 		if (tmpregion.rtype != OROOM)
2302 | 		    mustfill[nroom] = (prefilled ? 2 : 1);
2303 | 
2304 | 		if(tmpregion.rirreg) {
2305 | 		    min_rx = max_rx = tmpregion.x1;
2306 | 		    min_ry = max_ry = tmpregion.y1;
2307 | 		    flood_fill_rm(tmpregion.x1, tmpregion.y1,
2308 | 				  nroom+ROOMOFFSET, tmpregion.rlit, TRUE);
2309 | 		    add_room(min_rx, min_ry, max_rx, max_ry,
2310 | 			     FALSE, tmpregion.rtype, TRUE);
2311 | 		    troom->rlit = tmpregion.rlit;
2312 | 		    troom->irregular = TRUE;
2313 | 		} else {
2314 | 		    add_room(tmpregion.x1, tmpregion.y1,
2315 | 			     tmpregion.x2, tmpregion.y2,
2316 | 			     tmpregion.rlit, tmpregion.rtype, TRUE);
2317 | #ifdef SPECIALIZATION
2318 | 		    topologize(troom,FALSE);		/* set roomno */
2319 | #else
2320 | 		    topologize(troom);			/* set roomno */
2321 | #endif
2322 | 		}
2323 | 	}
2324 | 
2325 | 	Fread((genericptr_t) &n, 1, sizeof(n), fd);
2326 | 						/* Number of doors */
2327 | 	while(n--) {
2328 | 		struct mkroom *croom = &rooms[0];
2329 | 
2330 | 		Fread((genericptr_t)&tmpdoor, 1, sizeof(tmpdoor), fd);
2331 | 
2332 | 		x = tmpdoor.x;	y = tmpdoor.y;
2333 | 		typ = tmpdoor.mask == -1 ? rnddoor() : tmpdoor.mask;
2334 | 
2335 | 		get_location(&x, &y, DRY);
2336 | 		if(levl[x][y].typ != SDOOR)
2337 | 			levl[x][y].typ = DOOR;
2338 | 		else {
2339 | 			if(typ < D_CLOSED)
2340 | 			    typ = D_CLOSED; /* force it to be closed */
2341 | 		}
2342 | 		levl[x][y].doormask = typ;
2343 | 
2344 | 		/* Now the complicated part, list it with each subroom */
2345 | 		/* The dog move and mail daemon routines use this */
2346 | 		while(croom->hx >= 0 && doorindex < DOORMAX) {
2347 | 		    if(croom->hx >= x-1 && croom->lx <= x+1 &&
2348 | 		       croom->hy >= y-1 && croom->ly <= y+1) {
2349 | 			/* Found it */
2350 | 			add_door(x, y, croom);
2351 | 		    }
2352 | 		    croom++;
2353 | 		}
2354 | 	}
2355 | 
2356 | 	/* now that we have rooms _and_ associated doors, fill the rooms */
2357 | 	for(n = 0; n < SIZE(mustfill); n++)
2358 | 	    if(mustfill[(int)n])
2359 | 		fill_room(&rooms[(int)n], (mustfill[(int)n] == 2));
2360 | 
2361 | 	/* if special boundary syms (CROSSWALL) in map, remove them now */
2362 | 	if(has_bounds) {
2363 | 	    for(x = xstart; x < xstart+xsize; x++)
2364 | 		for(y = ystart; y < ystart+ysize; y++)
2365 | 		    if(levl[x][y].typ == CROSSWALL)
2366 | 			levl[x][y].typ = ROOM;
2367 | 	}
2368 | 
2369 | 	Fread((genericptr_t) &n, 1, sizeof(n), fd);
2370 | 						/* Number of drawbridges */
2371 | 	while(n--) {
2372 | 		Fread((genericptr_t)&tmpdb, 1, sizeof(tmpdb), fd);
2373 | 
2374 | 		x = tmpdb.x;  y = tmpdb.y;
2375 | 		get_location(&x, &y, DRY|WET);
2376 | 
2377 | 		if (!create_drawbridge(x, y, tmpdb.dir, tmpdb.db_open))
2378 | 		    impossible("Cannot create drawbridge.");
2379 | 	}
2380 | 
2381 | 	Fread((genericptr_t) &n, 1, sizeof(n), fd);
2382 | 						/* Number of mazewalks */
2383 | 	while(n--) {
2384 | 		Fread((genericptr_t)&tmpwalk, 1, sizeof(tmpwalk), fd);
2385 | 
2386 | 		get_location(&tmpwalk.x, &tmpwalk.y, DRY|WET);
2387 | 
2388 | 		walklist[nwalk++] = tmpwalk;
2389 | 	}
2390 | 
2391 | 	Fread((genericptr_t) &n, 1, sizeof(n), fd);
2392 | 						/* Number of non_diggables */
2393 | 	while(n--) {
2394 | 		Fread((genericptr_t)&tmpdig, 1, sizeof(tmpdig), fd);
2395 | 
2396 | 		get_location(&tmpdig.x1, &tmpdig.y1, DRY|WET);
2397 | 		get_location(&tmpdig.x2, &tmpdig.y2, DRY|WET);
2398 | 
2399 | 		set_wall_property(tmpdig.x1, tmpdig.y1,
2400 | 				  tmpdig.x2, tmpdig.y2, W_NONDIGGABLE);
2401 | 	}
2402 | 
2403 | 	Fread((genericptr_t) &n, 1, sizeof(n), fd);
2404 | 						/* Number of non_passables */
2405 | 	while(n--) {
2406 | 		Fread((genericptr_t)&tmpdig, 1, sizeof(tmpdig), fd);
2407 | 
2408 | 		get_location(&tmpdig.x1, &tmpdig.y1, DRY|WET);
2409 | 		get_location(&tmpdig.x2, &tmpdig.y2, DRY|WET);
2410 | 
2411 | 		set_wall_property(tmpdig.x1, tmpdig.y1,
2412 | 				  tmpdig.x2, tmpdig.y2, W_NONPASSWALL);
2413 | 	}
2414 | 
2415 | 	Fread((genericptr_t) &n, 1, sizeof(n), fd);
2416 | 						/* Number of ladders */
2417 | 	while(n--) {
2418 | 		Fread((genericptr_t)&tmplad, 1, sizeof(tmplad), fd);
2419 | 
2420 | 		x = tmplad.x;  y = tmplad.y;
2421 | 		get_location(&x, &y, DRY);
2422 | 
2423 | 		levl[x][y].typ = LADDER;
2424 | 		if (tmplad.up == 1) {
2425 | 			xupladder = x;	yupladder = y;
2426 | 			levl[x][y].ladder = LA_UP;
2427 | 		} else {
2428 | 			xdnladder = x;	ydnladder = y;
2429 | 			levl[x][y].ladder = LA_DOWN;
2430 | 		}
2431 | 	}
2432 | 
2433 | 	prevstair.x = prevstair.y = 0;
2434 | 	Fread((genericptr_t) &n, 1, sizeof(n), fd);
2435 | 						/* Number of stairs */
2436 | 	while(n--) {
2437 | 		Fread((genericptr_t)&tmpstair, 1, sizeof(tmpstair), fd);
2438 | 
2439 | 		xi = 0;
2440 | 		do {
2441 | 		    x = tmpstair.x;  y = tmpstair.y;
2442 | 		    get_location(&x, &y, DRY);
2443 | 		} while(prevstair.x && xi++ < 100 &&
2444 | 			distmin(x,y,prevstair.x,prevstair.y) <= 8);
2445 | 		if ((badtrap = t_at(x,y)) != 0) deltrap(badtrap);
2446 | 		mkstairs(x, y, (char)tmpstair.up, (struct mkroom *)0);
2447 | 		prevstair.x = x;
2448 | 		prevstair.y = y;
2449 | 	}
2450 | 
2451 | 	Fread((genericptr_t) &n, 1, sizeof(n), fd);
2452 | 						/* Number of altars */
2453 | 	while(n--) {
2454 | 		Fread((genericptr_t)&tmpaltar, 1, sizeof(tmpaltar), fd);
2455 | 
2456 | 		create_altar(&tmpaltar, (struct mkroom *)0);
2457 | 	}
2458 | 
2459 | 	Fread((genericptr_t) &n, 1, sizeof(n), fd);
2460 | 						/* Number of fountains */
2461 | 	while (n--) {
2462 | 		Fread((genericptr_t)&tmpfountain, 1, sizeof(tmpfountain), fd);
2463 | 
2464 | 		create_feature(tmpfountain.x, tmpfountain.y,
2465 | 			       (struct mkroom *)0, FOUNTAIN);
2466 | 	}
2467 | 
2468 | 	Fread((genericptr_t) &n, 1, sizeof(n), fd);
2469 | 						/* Number of traps */
2470 | 	while(n--) {
2471 | 		Fread((genericptr_t)&tmptrap, 1, sizeof(tmptrap), fd);
2472 | 
2473 | 		create_trap(&tmptrap, (struct mkroom *)0);
2474 | 	}
2475 | 
2476 | 	Fread((genericptr_t) &n, 1, sizeof(n), fd);
2477 | 						/* Number of monsters */
2478 | 	while(n--) {
2479 | 		load_one_monster(fd, &tmpmons);
2480 | 
2481 | 		create_monster(&tmpmons, (struct mkroom *)0);
2482 | 	}
2483 | 
2484 | 	Fread((genericptr_t) &n, 1, sizeof(n), fd);
2485 | 						/* Number of objects */
2486 | 	while(n--) {
2487 | 		load_one_object(fd, &tmpobj);
2488 | 
2489 | 		create_object(&tmpobj, (struct mkroom *)0);
2490 | 	}
2491 | 
2492 | 	Fread((genericptr_t) &n, 1, sizeof(n), fd);
2493 | 						/* Number of gold piles */
2494 | 	while (n--) {
2495 | 		Fread((genericptr_t)&tmpgold, 1, sizeof(tmpgold), fd);
2496 | 
2497 | 		create_gold(&tmpgold, (struct mkroom *)0);
2498 | 	}
2499 | 
2500 | 	Fread((genericptr_t) &n, 1, sizeof(n), fd);
2501 | 						/* Number of engravings */
2502 | 	while(n--) {
2503 | 		load_one_engraving(fd, &tmpengraving);
2504 | 
2505 | 		create_engraving(&tmpengraving, (struct mkroom *)0);
2506 | 	}
2507 | 
2508 |     }		/* numpart loop */
2509 | 
2510 |     nwalk_sav = nwalk;
2511 |     while(nwalk--) {
2512 | 	    x = (xchar) walklist[nwalk].x;
2513 | 	    y = (xchar) walklist[nwalk].y;
2514 | 	    dir = walklist[nwalk].dir;
2515 | 
2516 | 	    /* don't use move() - it doesn't use W_NORTH, etc. */
2517 | 	    switch (dir) {
2518 | 		case W_NORTH: --y; break;
2519 | 		case W_SOUTH: y++; break;
2520 | 		case W_EAST:  x++; break;
2521 | 		case W_WEST:  --x; break;
2522 | 		default: panic("load_maze: bad MAZEWALK direction");
2523 | 	    }
2524 | 
2525 | 	    if(!IS_DOOR(levl[x][y].typ)) {
2526 | #ifndef WALLIFIED_MAZE
2527 | 		levl[x][y].typ = CORR;
2528 | #else
2529 | 		levl[x][y].typ = ROOM;
2530 | #endif
2531 | 		levl[x][y].flags = 0;
2532 | 	    }
2533 | 
2534 | 	    /*
2535 | 	     * We must be sure that the parity of the coordinates for
2536 | 	     * walkfrom() is odd.  But we must also take into account
2537 | 	     * what direction was chosen.
2538 | 	     */
2539 | 	    if(!(x % 2)) {
2540 | 		if (dir == W_EAST)
2541 | 		    x++;
2542 | 		else
2543 | 		    x--;
2544 | 
2545 | 		/* no need for IS_DOOR check; out of map bounds */
2546 | #ifndef WALLIFIED_MAZE
2547 | 		levl[x][y].typ = CORR;
2548 | #else
2549 | 		levl[x][y].typ = ROOM;
2550 | #endif
2551 | 		levl[x][y].flags = 0;
2552 | 	    }
2553 | 
2554 | 	    if (!(y % 2)) {
2555 | 		if (dir == W_SOUTH)
2556 | 		    y++;
2557 | 		else
2558 | 		    y--;
2559 | 	    }
2560 | 
2561 | 	    walkfrom(x, y);
2562 |     }
2563 |     wallification(1, 0, COLNO-1, ROWNO-1);
2564 | 
2565 |     /*
2566 |      * If there's a significant portion of maze unused by the special level,
2567 |      * we don't want it empty.
2568 |      *
2569 |      * Makes the number of traps, monsters, etc. proportional
2570 |      * to the size of the maze.
2571 |      */
2572 |     mapcountmax = mapcount = (x_maze_max - 2) * (y_maze_max - 2);
2573 | 
2574 |     for(x = 2; x < x_maze_max; x++)
2575 | 	for(y = 0; y < y_maze_max; y++)
2576 | 	    if(Map[x][y]) mapcount--;
2577 | 
2578 |     if (nwalk_sav && (mapcount > (int) (mapcountmax / 10))) {
2579 | 	    mapfact = (int) ((mapcount * 100L) / mapcountmax);
2580 | 	    for(x = rnd((int) (20 * mapfact) / 100); x; x--) {
2581 | 		    maze1xy(&mm, DRY);
2582 | 		    (void) mkobj_at(rn2(2) ? GEM_CLASS : RANDOM_CLASS,
2583 | 							mm.x, mm.y, TRUE);
2584 | 	    }
2585 | 	    for(x = rnd((int) (12 * mapfact) / 100); x; x--) {
2586 | 		    maze1xy(&mm, DRY);
2587 | 		    (void) mksobj_at(BOULDER, mm.x, mm.y, TRUE);
2588 | 	    }
2589 | 	    for (x = rn2(2); x; x--) {
2590 | 		maze1xy(&mm, DRY);
2591 | 		(void) makemon(&mons[PM_MINOTAUR], mm.x, mm.y, NO_MM_FLAGS);
2592 | 	    }
2593 | 	    for(x = rnd((int) (12 * mapfact) / 100); x; x--) {
2594 | 		    maze1xy(&mm, WET|DRY);
2595 | 		    (void) makemon((struct permonst *) 0, mm.x, mm.y, NO_MM_FLAGS);
2596 | 	    }
2597 | 	    for(x = rn2((int) (15 * mapfact) / 100); x; x--) {
2598 | 		    maze1xy(&mm, DRY);
2599 | 		    (void) mkgold(0L,mm.x,mm.y);
2600 | 	    }
2601 | 	    for(x = rn2((int) (15 * mapfact) / 100); x; x--) {
2602 | 		    int trytrap;
2603 | 
2604 | 		    maze1xy(&mm, DRY);
2605 | 		    trytrap = rndtrap();
2606 | 		    if (sobj_at(BOULDER, mm.x, mm.y))
2607 | 			while (trytrap == PIT || trytrap == SPIKED_PIT ||
2608 | 				trytrap == TRAPDOOR || trytrap == HOLE)
2609 | 			    trytrap = rndtrap();
2610 | 		    (void) maketrap(mm.x, mm.y, trytrap);
2611 | 	    }
2612 |     }
2613 |     return TRUE;
2614 | }
2615 | 
2616 | /*
2617 |  * General loader
2618 |  */
2619 | 
2620 | boolean
2621 | load_special(name)
2622 | const char *name;
2623 | {
2624 | 	dlb *fd;
2625 | 	boolean result = FALSE;
2626 | 	char c;
2627 | 	struct version_info vers_info;
2628 | 
2629 | 	fd = dlb_fopen(name, RDBMODE);
2630 | 	if (!fd) return FALSE;
2631 | 
2632 | 	Fread((genericptr_t) &vers_info, sizeof vers_info, 1, fd);
2633 | 	if (!check_version(&vers_info, name, TRUE))
2634 | 	    goto give_up;
2635 | 
2636 | 	Fread((genericptr_t) &c, sizeof c, 1, fd); /* c Header */
2637 | 
2638 | 	switch (c) {
2639 | 		case SP_LEV_ROOMS:
2640 | 		    result = load_rooms(fd);
2641 | 		    break;
2642 | 		case SP_LEV_MAZE:
2643 | 		    result = load_maze(fd);
2644 | 		    break;
2645 | 		default:	/* ??? */
2646 | 		    result = FALSE;
2647 | 	}
2648 |  give_up:
2649 | 	(void)dlb_fclose(fd);
2650 | 	return result;
2651 | }
2652 | 
2653 | /*sp_lev.c*/