1    | /*	SCCS Id: @(#)mkroom.c	3.3	97/05/25	*/
2    | /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3    | /* NetHack may be freely redistributed.  See license for details. */
4    | 
5    | /*
6    |  * Entry points:
7    |  *	mkroom() -- make and stock a room of a given type
8    |  *	nexttodoor() -- return TRUE if adjacent to a door
9    |  *	has_dnstairs() -- return TRUE if given room has a down staircase
10   |  *	has_upstairs() -- return TRUE if given room has an up staircase
11   |  *	courtmon() -- generate a court monster
12   |  *	save_rooms() -- save rooms into file fd
13   |  *	rest_rooms() -- restore rooms from file fd
14   |  */
15   | 
16   | #include "hack.h"
17   | 
18   | #ifdef OVLB
19   | STATIC_DCL boolean FDECL(isbig, (struct mkroom *));
20   | STATIC_DCL struct mkroom * FDECL(pick_room,(BOOLEAN_P));
21   | STATIC_DCL void NDECL(mkshop), FDECL(mkzoo,(int)), NDECL(mkswamp);
22   | STATIC_DCL void NDECL(mktemple);
23   | STATIC_DCL coord * FDECL(shrine_pos, (int));
24   | STATIC_DCL struct permonst * NDECL(morguemon);
25   | STATIC_DCL struct permonst * NDECL(antholemon);
26   | STATIC_DCL struct permonst * NDECL(squadmon);
27   | STATIC_DCL void FDECL(save_room, (int,struct mkroom *));
28   | STATIC_DCL void FDECL(rest_room, (int,struct mkroom *));
29   | #endif /* OVLB */
30   | 
31   | #define sq(x) ((x)*(x))
32   | 
33   | extern const struct shclass shtypes[];	/* defined in shknam.c */
34   | 
35   | #ifdef OVLB
36   | 
37   | STATIC_OVL boolean
38   | isbig(sroom)
39   | register struct mkroom *sroom;
40   | {
41   | 	register int area = (sroom->hx - sroom->lx + 1)
42   | 			   * (sroom->hy - sroom->ly + 1);
43   | 	return((boolean)( area > 20 ));
44   | }
45   | 
46   | void
47   | mkroom(roomtype)
48   | /* make and stock a room of a given type */
49   | int	roomtype;
50   | {
51   |     if (roomtype >= SHOPBASE)
52   | 	mkshop();	/* someday, we should be able to specify shop type */
53   |     else switch(roomtype) {
54   | 	case COURT:	mkzoo(COURT); break;
55   | 	case ZOO:	mkzoo(ZOO); break;
56   | 	case BEEHIVE:	mkzoo(BEEHIVE); break;
57   | 	case MORGUE:	mkzoo(MORGUE); break;
58   | 	case BARRACKS:	mkzoo(BARRACKS); break;
59   | 	case SWAMP:	mkswamp(); break;
60   | 	case TEMPLE:	mktemple(); break;
61   | 	case LEPREHALL:	mkzoo(LEPREHALL); break;
62   | 	case COCKNEST:	mkzoo(COCKNEST); break;
63   | 	case ANTHOLE:	mkzoo(ANTHOLE); break;
64   | 	default:	impossible("Tried to make a room of type %d.", roomtype);
65   |     }
66   | }
67   | 
68   | STATIC_OVL void
69   | mkshop()
70   | {
71   | 	register struct mkroom *sroom;
72   | 	int i = -1;
73   | #ifdef WIZARD
74   | 	char *ep = (char *)0;	/* (init == lint suppression) */
75   | 
76   | 	/* first determine shoptype */
77   | 	if(wizard){
78   | #ifndef MAC
79   | 		ep = nh_getenv("SHOPTYPE");
80   | 		if(ep){
81   | 			if(*ep == 'z' || *ep == 'Z'){
82   | 				mkzoo(ZOO);
83   | 				return;
84   | 			}
85   | 			if(*ep == 'm' || *ep == 'M'){
86   | 				mkzoo(MORGUE);
87   | 				return;
88   | 			}
89   | 			if(*ep == 'b' || *ep == 'B'){
90   | 				mkzoo(BEEHIVE);
91   | 				return;
92   | 			}
93   | 			if(*ep == 't' || *ep == 'T' || *ep == '\\'){
94   | 				mkzoo(COURT);
95   | 				return;
96   | 			}
97   | 			if(*ep == 's' || *ep == 'S'){
98   | 				mkzoo(BARRACKS);
99   | 				return;
100  | 			}
101  | 			if(*ep == 'a' || *ep == 'A'){
102  | 				mkzoo(ANTHOLE);
103  | 				return;
104  | 			}
105  | 			if(*ep == 'c' || *ep == 'C'){
106  | 				mkzoo(COCKNEST);
107  | 				return;
108  | 			}
109  | 			if(*ep == 'l' || *ep == 'L'){
110  | 				mkzoo(LEPREHALL);
111  | 				return;
112  | 			}
113  | 			if(*ep == '_'){
114  | 				mktemple();
115  | 				return;
116  | 			}
117  | 			if(*ep == '}'){
118  | 				mkswamp();
119  | 				return;
120  | 			}
121  | 			for(i=0; shtypes[i].name; i++)
122  | 				if(*ep == def_oc_syms[(int)shtypes[i].symb])
123  | 				    goto gottype;
124  | 			if(*ep == 'g' || *ep == 'G')
125  | 				i = 0;
126  | 			else
127  | 				i = -1;
128  | 		}
129  | #endif
130  | 	}
131  | gottype:
132  | #endif
133  | 	for(sroom = &rooms[0]; ; sroom++){
134  | 		if(sroom->hx < 0) return;
135  | 		if(sroom - rooms >= nroom) {
136  | 			pline("rooms not closed by -1?");
137  | 			return;
138  | 		}
139  | 		if(sroom->rtype != OROOM) continue;
140  | 		if(has_dnstairs(sroom) || has_upstairs(sroom))
141  | 			continue;
142  | 		if(
143  | #ifdef WIZARD
144  | 		   (wizard && ep && sroom->doorct != 0) ||
145  | #endif
146  | 			sroom->doorct == 1) break;
147  | 	}
148  | 	if (!sroom->rlit) {
149  | 		int x, y;
150  | 
151  | 		for(x = sroom->lx - 1; x <= sroom->hx + 1; x++)
152  | 		for(y = sroom->ly - 1; y <= sroom->hy + 1; y++)
153  | 			levl[x][y].lit = 1;
154  | 		sroom->rlit = 1;
155  | 	}
156  | 
157  | 	if(i < 0) {			/* shoptype not yet determined */
158  | 	    register int j;
159  | 
160  | 	    /* pick a shop type at random */
161  | 	    for (j = rnd(100), i = 0; (j -= shtypes[i].prob) > 0; i++)
162  | 		continue;
163  | 
164  | 	    /* big rooms cannot be wand or book shops,
165  | 	     * - so make them general stores
166  | 	     */
167  | 	    if(isbig(sroom) && (shtypes[i].symb == WAND_CLASS
168  | 				|| shtypes[i].symb == SPBOOK_CLASS)) i = 0;
169  | 	}
170  | 	sroom->rtype = SHOPBASE + i;
171  | 
172  | 	/* set room bits before stocking the shop */
173  | #ifdef SPECIALIZATION
174  | 	topologize(sroom, FALSE); /* doesn't matter - this is a special room */
175  | #else
176  | 	topologize(sroom);
177  | #endif
178  | 
179  | 	/* stock the room with a shopkeeper and artifacts */
180  | 	stock_room(i, sroom);
181  | }
182  | 
183  | STATIC_OVL struct mkroom *
184  | pick_room(strict)
185  | register boolean strict;
186  | /* pick an unused room, preferably with only one door */
187  | {
188  | 	register struct mkroom *sroom;
189  | 	register int i = nroom;
190  | 
191  | 	for(sroom = &rooms[rn2(nroom)]; i--; sroom++) {
192  | 		if(sroom == &rooms[nroom])
193  | 			sroom = &rooms[0];
194  | 		if(sroom->hx < 0)
195  | 			return (struct mkroom *)0;
196  | 		if(sroom->rtype != OROOM)	continue;
197  | 		if(!strict) {
198  | 		    if(has_upstairs(sroom) || (has_dnstairs(sroom) && rn2(3)))
199  | 			continue;
200  | 		} else if(has_upstairs(sroom) || has_dnstairs(sroom))
201  | 			continue;
202  | 		if(sroom->doorct == 1 || !rn2(5)
203  | #ifdef WIZARD
204  | 						|| wizard
205  | #endif
206  | 							)
207  | 			return sroom;
208  | 	}
209  | 	return (struct mkroom *)0;
210  | }
211  | 
212  | STATIC_OVL void
213  | mkzoo(type)
214  | int type;
215  | {
216  | 	register struct mkroom *sroom;
217  | 
218  | 	if ((sroom = pick_room(FALSE)) != 0) {
219  | 		sroom->rtype = type;
220  | 		fill_zoo(sroom);
221  | 	}
222  | }
223  | 
224  | void
225  | fill_zoo(sroom)
226  | struct mkroom *sroom;
227  | {
228  | 	struct monst *mon;
229  | 	register int sx,sy,i;
230  | 	int sh, tx, ty, goldlim, type = sroom->rtype;
231  | 	int rmno = (sroom - rooms) + ROOMOFFSET;
232  | 	coord mm;
233  | 
234  | #ifdef GCC_WARN
235  | 	tx = ty = goldlim = 0;
236  | #endif
237  | 
238  | 	sh = sroom->fdoor;
239  | 	switch(type) {
240  | 	    case COURT:
241  | 		if(level.flags.is_maze_lev) {
242  | 		    for(tx = sroom->lx; tx <= sroom->hx; tx++)
243  | 			for(ty = sroom->ly; ty <= sroom->hy; ty++)
244  | 			    if(IS_THRONE(levl[tx][ty].typ))
245  | 				goto throne_placed;
246  | 		}
247  | 		i = 100;
248  | 		do {	/* don't place throne on top of stairs */
249  | 			(void) somexy(sroom, &mm);
250  | 			tx = mm.x; ty = mm.y;
251  | 		} while (occupied((xchar)tx, (xchar)ty) && --i > 0);
252  | 	    throne_placed:
253  | 		/* TODO: try to ensure the enthroned monster is an M2_PRINCE */
254  | 		break;
255  | 	    case BEEHIVE:
256  | 		tx = sroom->lx + (sroom->hx - sroom->lx + 1)/2;
257  | 		ty = sroom->ly + (sroom->hy - sroom->ly + 1)/2;
258  | 		if(sroom->irregular) {
259  | 		    /* center might not be valid, so put queen elsewhere */
260  | 		    if ((int) levl[tx][ty].roomno != rmno ||
261  | 			    levl[tx][ty].edge) {
262  | 			(void) somexy(sroom, &mm);
263  | 			tx = mm.x; ty = mm.y;
264  | 		    }
265  | 		}
266  | 		break;
267  | 	    case ZOO:
268  | 	    case LEPREHALL:
269  | 		goldlim = 500 * level_difficulty();
270  | 		break;
271  | 	}
272  | 	for(sx = sroom->lx; sx <= sroom->hx; sx++)
273  | 	    for(sy = sroom->ly; sy <= sroom->hy; sy++) {
274  | 		if(sroom->irregular) {
275  | 		    if ((int) levl[sx][sy].roomno != rmno ||
276  | 			  levl[sx][sy].edge ||
277  | 			  (sroom->doorct &&
278  | 			   distmin(sx, sy, doors[sh].x, doors[sh].y) <= 1))
279  | 			continue;
280  | 		} else if(!SPACE_POS(levl[sx][sy].typ) ||
281  | 			  (sroom->doorct &&
282  | 			   ((sx == sroom->lx && doors[sh].x == sx-1) ||
283  | 			    (sx == sroom->hx && doors[sh].x == sx+1) ||
284  | 			    (sy == sroom->ly && doors[sh].y == sy-1) ||
285  | 			    (sy == sroom->hy && doors[sh].y == sy+1))))
286  | 		    continue;
287  | 		/* don't place monster on explicitly placed throne */
288  | 		if(type == COURT && IS_THRONE(levl[sx][sy].typ))
289  | 		    continue;
290  | 		mon = makemon(
291  | 		    (type == COURT) ? courtmon() :
292  | 		    (type == BARRACKS) ? squadmon() :
293  | 		    (type == MORGUE) ? morguemon() :
294  | 		    (type == BEEHIVE) ?
295  | 			(sx == tx && sy == ty ? &mons[PM_QUEEN_BEE] :
296  | 			 &mons[PM_KILLER_BEE]) :
297  | 		    (type == LEPREHALL) ? &mons[PM_LEPRECHAUN] :
298  | 		    (type == COCKNEST) ? &mons[PM_COCKATRICE] :
299  | 		    (type == ANTHOLE) ? antholemon() :
300  | 		    (struct permonst *) 0,
301  | 		   sx, sy, NO_MM_FLAGS);
302  | 		if(mon) {
303  | 			mon->msleeping = 1;
304  | 			if (type==COURT && mon->mpeaceful) {
305  | 				mon->mpeaceful = 0;
306  | 				set_malign(mon);
307  | 			}
308  | 		}
309  | 		switch(type) {
310  | 		    case ZOO:
311  | 		    case LEPREHALL:
312  | 			if(sroom->doorct)
313  | 			{
314  | 			    int distval = dist2(sx,sy,doors[sh].x,doors[sh].y);
315  | 			    i = sq(distval);
316  | 			}
317  | 			else
318  | 			    i = goldlim;
319  | 			if(i >= goldlim) i = 5*level_difficulty();
320  | 			goldlim -= i;
321  | 			(void) mkgold((long) rn1(i, 10), sx, sy);
322  | 			break;
323  | 		    case MORGUE:
324  | 			if(!rn2(5))
325  | 			    (void) mk_tt_object(CORPSE, sx, sy);
326  | 			if(!rn2(10))	/* lots of treasure buried with dead */
327  | 			    (void) mksobj_at((rn2(3)) ? LARGE_BOX : CHEST,
328  | 					     sx, sy, TRUE);
329  | 			if (!rn2(5))
330  | 			    make_grave(sx, sy, (char *)0);
331  | 			break;
332  | 		    case BEEHIVE:
333  | 			if(!rn2(3))
334  | 			    (void) mksobj_at(LUMP_OF_ROYAL_JELLY, sx, sy, TRUE);
335  | 			break;
336  | 		    case BARRACKS:
337  | 			if(!rn2(20))	/* the payroll and some loot */
338  | 			    (void) mksobj_at((rn2(3)) ? LARGE_BOX : CHEST,
339  | 					     sx, sy, TRUE);
340  | 			break;
341  | 		    case COCKNEST:
342  | 			if(!rn2(3)) {
343  | 			    struct obj *sobj = mk_tt_object(STATUE, sx, sy);
344  | 
345  | 			    if (sobj)
346  | 			    	for (i = rn2(5); i; i--)
347  | 			    	    add_to_container(sobj, mkobj(RANDOM_CLASS, FALSE));
348  | 			}
349  | 			break;
350  | 		    case ANTHOLE:
351  | 			if(!rn2(3))
352  | 			    (void) mkobj_at(FOOD_CLASS, sx, sy, TRUE);
353  | 			break;
354  | 		}
355  | 	    }
356  | 	switch (type) {
357  | 	      case COURT:
358  | 		{
359  | 		  struct obj *chest;
360  | 		  levl[tx][ty].typ = THRONE;
361  | 		  (void) somexy(sroom, &mm);
362  | 		  (void) mkgold((long) rn1(50 * level_difficulty(),10), mm.x, mm.y);
363  | 		  chest = mksobj_at(CHEST, mm.x, mm.y, TRUE); /* the royal coffers */
364  | 		  chest->spe = 2; /* so it can be found later */
365  | 		  level.flags.has_court = 1;
366  | 		  break;
367  | 		}
368  | 	      case BARRACKS:
369  | 		  level.flags.has_barracks = 1;
370  | 		  break;
371  | 	      case ZOO:
372  | 		  level.flags.has_zoo = 1;
373  | 		  break;
374  | 	      case MORGUE:
375  | 		  level.flags.has_morgue = 1;
376  | 		  break;
377  | 	      case SWAMP:
378  | 		  level.flags.has_swamp = 1;
379  | 		  break;
380  | 	      case BEEHIVE:
381  | 		  level.flags.has_beehive = 1;
382  | 		  break;
383  | 	}
384  | }
385  | 
386  | /* make a swarm of undead around mm */
387  | void
388  | mkundead(mm, revive_corpses, mm_flags)
389  | coord *mm;
390  | boolean revive_corpses;
391  | int mm_flags;
392  | {
393  | 	int cnt = (level_difficulty() + 1)/10 + rnd(5);
394  | 	struct permonst *mdat;
395  | 	struct obj *otmp;
396  | 	coord cc;
397  | 
398  | 	while (cnt--) {
399  | 	    mdat = morguemon();
400  | 	    if (enexto(&cc, mm->x, mm->y, mdat) &&
401  | 		    (!revive_corpses ||
402  | 		     !(otmp = sobj_at(CORPSE, cc.x, cc.y)) ||
403  | 		     !revive(otmp)))
404  | 		(void) makemon(mdat, cc.x, cc.y, mm_flags);
405  | 	}
406  | 	level.flags.graveyard = TRUE;	/* reduced chance for undead corpse */
407  | }
408  | 
409  | STATIC_OVL struct permonst *
410  | morguemon()
411  | {
412  | 	register int i = rn2(100), hd = rn2(level_difficulty());
413  | 
414  | 	if(hd > 10 && i < 10)
415  | 		return((Inhell || In_endgame(&u.uz)) ? mkclass(S_DEMON,0) :
416  | 						       &mons[ndemon(A_NONE)]);
417  | 	if(hd > 8 && i > 85)
418  | 		return(mkclass(S_VAMPIRE,0));
419  | 
420  | 	return((i < 20) ? &mons[PM_GHOST]
421  | 			: (i < 40) ? &mons[PM_WRAITH] : mkclass(S_ZOMBIE,0));
422  | }
423  | 
424  | STATIC_OVL struct permonst *
425  | antholemon()
426  | {
427  | 	int mtyp;
428  | 
429  | 	/* Same monsters within a level, different ones between levels */
430  | 	switch ((level_difficulty() + ((long)u.ubirthday)) % 3) {
431  | 	default:	mtyp = PM_GIANT_ANT; break;
432  | 	case 0:		mtyp = PM_SOLDIER_ANT; break;
433  | 	case 1:		mtyp = PM_FIRE_ANT; break;
434  | 	}
435  | 	return ((mvitals[mtyp].mvflags & G_GONE) ?
436  | 			(struct permonst *)0 : &mons[mtyp]);
437  | }
438  | 
439  | STATIC_OVL void
440  | mkswamp()	/* Michiel Huisjes & Fred de Wilde */
441  | {
442  | 	register struct mkroom *sroom;
443  | 	register int sx,sy,i,eelct = 0;
444  | 
445  | 	for(i=0; i<5; i++) {		/* turn up to 5 rooms swampy */
446  | 		sroom = &rooms[rn2(nroom)];
447  | 		if(sroom->hx < 0 || sroom->rtype != OROOM ||
448  | 		   has_upstairs(sroom) || has_dnstairs(sroom))
449  | 			continue;
450  | 
451  | 		/* satisfied; make a swamp */
452  | 		sroom->rtype = SWAMP;
453  | 		for(sx = sroom->lx; sx <= sroom->hx; sx++)
454  | 		for(sy = sroom->ly; sy <= sroom->hy; sy++)
455  | 		if(!OBJ_AT(sx, sy) &&
456  | 		   !MON_AT(sx, sy) && !t_at(sx,sy) && !nexttodoor(sx,sy)) {
457  | 		    if((sx+sy)%2) {
458  | 			levl[sx][sy].typ = POOL;
459  | 			if(!eelct || !rn2(4)) {
460  | 			    /* mkclass() won't do, as we might get kraken */
461  | 			    (void) makemon(rn2(5) ? &mons[PM_GIANT_EEL]
462  | 						  : rn2(2) ? &mons[PM_PIRANHA]
463  | 						  : &mons[PM_ELECTRIC_EEL],
464  | 						sx, sy, NO_MM_FLAGS);
465  | 			    eelct++;
466  | 			}
467  | 		    } else
468  | 			if(!rn2(4))	/* swamps tend to be moldy */
469  | 			    (void) makemon(mkclass(S_FUNGUS,0),
470  | 						sx, sy, NO_MM_FLAGS);
471  | 		}
472  | 		level.flags.has_swamp = 1;
473  | 	}
474  | }
475  | 
476  | STATIC_OVL coord *
477  | shrine_pos(roomno)
478  | int roomno;
479  | {
480  | 	static coord buf;
481  | 	struct mkroom *troom = &rooms[roomno - ROOMOFFSET];
482  | 
483  | 	buf.x = troom->lx + ((troom->hx - troom->lx) / 2);
484  | 	buf.y = troom->ly + ((troom->hy - troom->ly) / 2);
485  | 	return(&buf);
486  | }
487  | 
488  | STATIC_OVL void
489  | mktemple()
490  | {
491  | 	register struct mkroom *sroom;
492  | 	coord *shrine_spot;
493  | 	register struct rm *lev;
494  | 
495  | 	if(!(sroom = pick_room(TRUE))) return;
496  | 
497  | 	/* set up Priest and shrine */
498  | 	sroom->rtype = TEMPLE;
499  | 	/*
500  | 	 * In temples, shrines are blessed altars
501  | 	 * located in the center of the room
502  | 	 */
503  | 	shrine_spot = shrine_pos((sroom - rooms) + ROOMOFFSET);
504  | 	lev = &levl[shrine_spot->x][shrine_spot->y];
505  | 	lev->typ = ALTAR;
506  | 	lev->altarmask = induced_align(80);
507  | 	priestini(&u.uz, sroom, shrine_spot->x, shrine_spot->y, FALSE);
508  | 	lev->altarmask |= AM_SHRINE;
509  | 	level.flags.has_temple = 1;
510  | }
511  | 
512  | boolean
513  | nexttodoor(sx,sy)
514  | register int sx, sy;
515  | {
516  | 	register int dx, dy;
517  | 	register struct rm *lev;
518  | 	for(dx = -1; dx <= 1; dx++) for(dy = -1; dy <= 1; dy++) {
519  | 		if(!isok(sx+dx, sy+dy)) continue;
520  | 		if(IS_DOOR((lev = &levl[sx+dx][sy+dy])->typ) ||
521  | 		    lev->typ == SDOOR)
522  | 			return(TRUE);
523  | 	}
524  | 	return(FALSE);
525  | }
526  | 
527  | boolean
528  | has_dnstairs(sroom)
529  | register struct mkroom *sroom;
530  | {
531  | 	if (sroom == dnstairs_room)
532  | 		return TRUE;
533  | 	if (sstairs.sx && !sstairs.up)
534  | 		return((boolean)(sroom == sstairs_room));
535  | 	return FALSE;
536  | }
537  | 
538  | boolean
539  | has_upstairs(sroom)
540  | register struct mkroom *sroom;
541  | {
542  | 	if (sroom == upstairs_room)
543  | 		return TRUE;
544  | 	if (sstairs.sx && sstairs.up)
545  | 		return((boolean)(sroom == sstairs_room));
546  | 	return FALSE;
547  | }
548  | 
549  | #endif /* OVLB */
550  | #ifdef OVL0
551  | 
552  | int
553  | somex(croom)
554  | register struct mkroom *croom;
555  | {
556  | 	return rn2(croom->hx-croom->lx+1) + croom->lx;
557  | }
558  | 
559  | int
560  | somey(croom)
561  | register struct mkroom *croom;
562  | {
563  | 	return rn2(croom->hy-croom->ly+1) + croom->ly;
564  | }
565  | 
566  | boolean
567  | inside_room(croom, x, y)
568  | struct mkroom *croom;
569  | xchar x, y;
570  | {
571  | 	return((boolean)(x >= croom->lx-1 && x <= croom->hx+1 &&
572  | 		y >= croom->ly-1 && y <= croom->hy+1));
573  | }
574  | 
575  | boolean
576  | somexy(croom, c)
577  | struct mkroom *croom;
578  | coord *c;
579  | {
580  | 	int try_cnt = 0;
581  | 	int i;
582  | 
583  | 	if (croom->irregular) {
584  | 	    i = (croom - rooms) + ROOMOFFSET;
585  | 
586  | 	    while(try_cnt++ < 100) {
587  | 		c->x = somex(croom);
588  | 		c->y = somey(croom);
589  | 		if (!levl[c->x][c->y].edge &&
590  | 			(int) levl[c->x][c->y].roomno == i)
591  | 		    return TRUE;
592  | 	    }
593  | 	    /* try harder; exhaustively search until one is found */
594  | 	    for(c->x = croom->lx; c->x <= croom->hx; c->x++)
595  | 		for(c->y = croom->ly; c->y <= croom->hy; c->y++)
596  | 		    if (!levl[c->x][c->y].edge &&
597  | 			    (int) levl[c->x][c->y].roomno == i)
598  | 			return TRUE;
599  | 	    return FALSE;
600  | 	}
601  | 
602  | 	if (!croom->nsubrooms) {
603  | 		c->x = somex(croom);
604  | 		c->y = somey(croom);
605  | 		return TRUE;
606  | 	}
607  | 
608  | 	/* Check that coords doesn't fall into a subroom or into a wall */
609  | 
610  | 	while(try_cnt++ < 100) {
611  | 		c->x = somex(croom);
612  | 		c->y = somey(croom);
613  | 		if (IS_WALL(levl[c->x][c->y].typ))
614  | 		    continue;
615  | 		for(i=0 ; i<croom->nsubrooms;i++)
616  | 		    if(inside_room(croom->sbrooms[i], c->x, c->y))
617  | 			goto you_lose;
618  | 		break;
619  | you_lose:	;
620  | 	}
621  | 	if (try_cnt >= 100)
622  | 	    return FALSE;
623  | 	return TRUE;
624  | }
625  | 
626  | /*
627  |  * Search for a special room given its type (zoo, court, etc...)
628  |  *	Special values :
629  |  *		- ANY_SHOP
630  |  *		- ANY_TYPE
631  |  */
632  | 
633  | struct mkroom *
634  | search_special(type)
635  | schar type;
636  | {
637  | 	register struct mkroom *croom;
638  | 
639  | 	for(croom = &rooms[0]; croom->hx >= 0; croom++)
640  | 	    if((type == ANY_TYPE && croom->rtype != OROOM) ||
641  | 	       (type == ANY_SHOP && croom->rtype >= SHOPBASE) ||
642  | 	       croom->rtype == type)
643  | 		return croom;
644  | 	for(croom = &subrooms[0]; croom->hx >= 0; croom++)
645  | 	    if((type == ANY_TYPE && croom->rtype != OROOM) ||
646  | 	       (type == ANY_SHOP && croom->rtype >= SHOPBASE) ||
647  | 	       croom->rtype == type)
648  | 		return croom;
649  | 	return (struct mkroom *) 0;
650  | }
651  | 
652  | #endif /* OVL0 */
653  | #ifdef OVLB
654  | 
655  | struct permonst *
656  | courtmon()
657  | {
658  | 	int     i = rn2(60) + rn2(3*level_difficulty());
659  | 	if (i > 100)		return(mkclass(S_DRAGON,0));
660  | 	else if (i > 95)	return(mkclass(S_GIANT,0));
661  | 	else if (i > 85)	return(mkclass(S_TROLL,0));
662  | 	else if (i > 75)	return(mkclass(S_CENTAUR,0));
663  | 	else if (i > 60)	return(mkclass(S_ORC,0));
664  | 	else if (i > 45)	return(&mons[PM_BUGBEAR]);
665  | 	else if (i > 30)	return(&mons[PM_HOBGOBLIN]);
666  | 	else if (i > 15)	return(mkclass(S_GNOME,0));
667  | 	else			return(mkclass(S_KOBOLD,0));
668  | }
669  | 
670  | #define NSTYPES (PM_CAPTAIN - PM_SOLDIER + 1)
671  | 
672  | static struct {
673  |     unsigned	pm;
674  |     unsigned	prob;
675  | } squadprob[NSTYPES] = {
676  |     {PM_SOLDIER, 80}, {PM_SERGEANT, 15}, {PM_LIEUTENANT, 4}, {PM_CAPTAIN, 1}
677  | };
678  | 
679  | STATIC_OVL struct permonst *
680  | squadmon()		/* return soldier types. */
681  | {
682  | 	int sel_prob, i, cpro, mndx;
683  | 
684  | 	sel_prob = rnd(80+level_difficulty());
685  | 
686  | 	cpro = 0;
687  | 	for (i = 0; i < NSTYPES; i++) {
688  | 	    cpro += squadprob[i].prob;
689  | 	    if (cpro > sel_prob) {
690  | 		mndx = squadprob[i].pm;
691  | 		goto gotone;
692  | 	    }
693  | 	}
694  | 	mndx = squadprob[rn2(NSTYPES)].pm;
695  | gotone:
696  | 	if (!(mvitals[mndx].mvflags & G_GONE)) return(&mons[mndx]);
697  | 	else			    return((struct permonst *) 0);
698  | }
699  | 
700  | /*
701  |  * save_room : A recursive function that saves a room and its subrooms
702  |  * (if any).
703  |  */
704  | 
705  | STATIC_OVL void
706  | save_room(fd, r)
707  | int	fd;
708  | struct mkroom *r;
709  | {
710  | 	short i;
711  | 	/*
712  | 	 * Well, I really should write only useful information instead
713  | 	 * of writing the whole structure. That is I should not write
714  | 	 * the subrooms pointers, but who cares ?
715  | 	 */
716  | 	bwrite(fd, (genericptr_t) r, sizeof(struct mkroom));
717  | 	for(i=0; i<r->nsubrooms; i++)
718  | 	    save_room(fd, r->sbrooms[i]);
719  | }
720  | 
721  | /*
722  |  * save_rooms : Save all the rooms on disk!
723  |  */
724  | 
725  | void
726  | save_rooms(fd)
727  | int fd;
728  | {
729  | 	short i;
730  | 
731  | 	/* First, write the number of rooms */
732  | 	bwrite(fd, (genericptr_t) &nroom, sizeof(nroom));
733  | 	for(i=0; i<nroom; i++)
734  | 	    save_room(fd, &rooms[i]);
735  | }
736  | 
737  | STATIC_OVL void
738  | rest_room(fd, r)
739  | int fd;
740  | struct mkroom *r;
741  | {
742  | 	short i;
743  | 
744  | 	mread(fd, (genericptr_t) r, sizeof(struct mkroom));
745  | 	for(i=0; i<r->nsubrooms; i++) {
746  | 		r->sbrooms[i] = &subrooms[nsubroom];
747  | 		rest_room(fd, &subrooms[nsubroom]);
748  | 		subrooms[nsubroom++].resident = (struct monst *)0;
749  | 	}
750  | }
751  | 
752  | /*
753  |  * rest_rooms : That's for restoring rooms. Read the rooms structure from
754  |  * the disk.
755  |  */
756  | 
757  | void
758  | rest_rooms(fd)
759  | int	fd;
760  | {
761  | 	short i;
762  | 
763  | 	mread(fd, (genericptr_t) &nroom, sizeof(nroom));
764  | 	nsubroom = 0;
765  | 	for(i = 0; i<nroom; i++) {
766  | 	    rest_room(fd, &rooms[i]);
767  | 	    rooms[i].resident = (struct monst *)0;
768  | 	}
769  | 	rooms[nroom].hx = -1;		/* restore ending flags */
770  | 	subrooms[nsubroom].hx = -1;
771  | }
772  | #endif /* OVLB */
773  | 
774  | /*mkroom.c*/