1 /**
2  * \file gen-room.c
3  * \brief Dungeon room generation.
4  *
5  * Copyright (c) 1997 Ben Harrison, James E. Wilson, Robert A. Koeneke
6  * Copyright (c) 2013 Erik Osheim, Nick McConnell
7  *
8  * This work is free software; you can redistribute it and/or modify it
9  * under the terms of either:
10  *
11  * a) the GNU General Public License as published by the Free Software
12  *    Foundation, version 2, or
13  *
14  * b) the "Angband licence":
15  *    This software may be copied and distributed for educational, research,
16  *    and not for profit purposes provided that this copyright and statement
17  *    are included in all such copies.  Other copyrights may also apply.
18  *
19  * This file covers everything to do with generation of individual rooms in
20  * the dungeon.  It consists of room generating helper functions plus the
21  * actual room builders (which are referred to in the room profiles in
22  * generate.c).
23  *
24  * The room builders all take as arguments the chunk they are being generated
25  * in, and the co-ordinates of the room centre in that chunk.  Each room
26  * builder is also able to find space for itself in the chunk using the
27  * find_space() function; the chunk generating functions can ask it to do that
28  * by passing too large centre co-ordinates.
29  */
30 
31 #include "angband.h"
32 #include "cave.h"
33 #include "datafile.h"
34 #include "math.h"
35 #include "game-event.h"
36 #include "generate.h"
37 #include "init.h"
38 #include "mon-group.h"
39 #include "mon-make.h"
40 #include "mon-spell.h"
41 #include "obj-tval.h"
42 #include "trap.h"
43 #include "z-queue.h"
44 #include "z-type.h"
45 
46 /**
47  * ------------------------------------------------------------------------
48  * Selection of random templates
49  * ------------------------------------------------------------------------ */
50 /**
51  * Chooses a room template of a particular kind at random.
52  * \param typ template room type - currently unused
53  * \return a pointer to the room template
54  */
random_room_template(int typ,int rating)55 struct room_template *random_room_template(int typ, int rating)
56 {
57 	struct room_template *t = room_templates;
58 	struct room_template *r = NULL;
59 	int n = 1;
60 	do {
61 		if ((t->typ == typ) && (t->rat == rating)) {
62 			if (one_in_(n)) r = t;
63 			n++;
64 		}
65 		t = t->next;
66 	} while(t);
67 	return r;
68 }
69 
70 /**
71  * Chooses a vault of a particular kind at random.
72  * \param depth the current depth, for vault boun checking
73  * \param typ vault type
74  * \return a pointer to the vault template
75  */
random_vault(int depth,const char * typ)76 struct vault *random_vault(int depth, const char *typ)
77 {
78 	struct vault *v = vaults;
79 	struct vault *r = NULL;
80 	int n = 1;
81 	do {
82 		if (streq(v->typ, typ) && (v->min_lev <= depth)
83 			&& (v->max_lev >= depth)) {
84 			if (one_in_(n)) r = v;
85 			n++;
86 		}
87 		v = v->next;
88 	} while(v);
89 	return r;
90 }
91 
92 
93 
94 /**
95  * ------------------------------------------------------------------------
96  * Room build helper functions
97  * ------------------------------------------------------------------------ */
98 /**
99  * Mark squares as being in a room, and optionally light them.
100  * \param c the current chunk
101  * \param y1 inclusive room boundaries
102  * \param x1 inclusive room boundaries
103  * \param y2 inclusive room boundaries
104  * \param x2 inclusive room boundaries
105  * \param light whether or not to light the room
106  */
generate_room(struct chunk * c,int y1,int x1,int y2,int x2,int light)107 static void generate_room(struct chunk *c, int y1, int x1, int y2, int x2,
108 						  int light)
109 {
110 	struct loc grid;
111 	for (grid.y = y1; grid.y <= y2; grid.y++)
112 		for (grid.x = x1; grid.x <= x2; grid.x++) {
113 			sqinfo_on(square(c, grid)->info, SQUARE_ROOM);
114 			if (light)
115 				sqinfo_on(square(c, grid)->info, SQUARE_GLOW);
116 		}
117 }
118 
119 /**
120  * Mark a rectangle with a sqinfo flag
121  * \param c the current chunk
122  * \param y1 inclusive room boundaries
123  * \param x1 inclusive room boundaries
124  * \param y2 inclusive room boundaries
125  * \param x2 inclusive room boundaries
126  * \param flag the SQUARE_* flag we are marking with
127  */
generate_mark(struct chunk * c,int y1,int x1,int y2,int x2,int flag)128 void generate_mark(struct chunk *c, int y1, int x1, int y2, int x2, int flag)
129 {
130 	struct loc grid;
131 	for (grid.y = y1; grid.y <= y2; grid.y++) {
132 		for (grid.x = x1; grid.x <= x2; grid.x++) {
133 			sqinfo_on(square(c, grid)->info, flag);
134 		}
135 	}
136 }
137 
138 /**
139  * Fill a rectangle with a feature.
140  * \param c the current chunk
141  * \param y1 inclusive room boundaries
142  * \param x1 inclusive room boundaries
143  * \param y2 inclusive room boundaries
144  * \param x2 inclusive room boundaries
145  * \param feat the terrain feature
146  * \param flag the SQUARE_* flag we are marking with
147  */
fill_rectangle(struct chunk * c,int y1,int x1,int y2,int x2,int feat,int flag)148 void fill_rectangle(struct chunk *c, int y1, int x1, int y2, int x2, int feat,
149 					int flag)
150 {
151 	int y, x;
152 	for (y = y1; y <= y2; y++)
153 		for (x = x1; x <= x2; x++)
154 			square_set_feat(c, loc(x, y), feat);
155 	if (flag) generate_mark(c, y1, x1, y2, x2, flag);
156 }
157 
158 /**
159  * Fill the edges of a rectangle with a feature.
160  * \param c the current chunk
161  * \param y1 inclusive room boundaries
162  * \param x1 inclusive room boundaries
163  * \param y2 inclusive room boundaries
164  * \param x2 inclusive room boundaries
165  * \param feat the terrain feature
166  * \param flag the SQUARE_* flag we are marking with
167  */
draw_rectangle(struct chunk * c,int y1,int x1,int y2,int x2,int feat,int flag)168 void draw_rectangle(struct chunk *c, int y1, int x1, int y2, int x2, int feat,
169 					int flag)
170 {
171 	int y, x;
172 
173 	for (y = y1; y <= y2; y++) {
174 		square_set_feat(c, loc(x1, y), feat);
175 		square_set_feat(c, loc(x2, y), feat);
176 	}
177 	if (flag) {
178 		generate_mark(c, y1, x1, y2, x1, flag);
179 		generate_mark(c, y1, x2, y2, x2, flag);
180 	}
181 	for (x = x1; x <= x2; x++) {
182 		square_set_feat(c, loc(x, y1), feat);
183 		square_set_feat(c, loc(x, y2), feat);
184 	}
185 	if (flag) {
186 		generate_mark(c, y1, x1, y1, x2, flag);
187 		generate_mark(c, y2, x1, y2, x2, flag);
188 	}
189 }
190 
191 /**
192  * Fill a horizontal range with the given feature/info.
193  * \param c the current chunk
194  * \param y inclusive room boundaries
195  * \param x1 inclusive room boundaries
196  * \param x2 inclusive range boundaries
197  * \param feat the terrain feature
198  * \param flag the SQUARE_* flag we are marking with
199  * \param light lit or not
200  */
fill_xrange(struct chunk * c,int y,int x1,int x2,int feat,int flag,bool light)201 static void fill_xrange(struct chunk *c, int y, int x1, int x2, int feat,
202 						int flag, bool light)
203 {
204 	int x;
205 	for (x = x1; x <= x2; x++) {
206 		struct loc grid = loc(x, y);
207 		square_set_feat(c, grid, feat);
208 		sqinfo_on(square(c, grid)->info, SQUARE_ROOM);
209 		if (flag) sqinfo_on(square(c, grid)->info, flag);
210 		if (light)
211 			sqinfo_on(square(c, grid)->info, SQUARE_GLOW);
212 	}
213 }
214 
215 /**
216  * Fill a vertical range with the given feature/info.
217  * \param c the current chunk
218  * \param x inclusive room boundaries
219  * \param y1 inclusive room boundaries
220  * \param y2 inclusive range boundaries
221  * \param feat the terrain feature
222  * \param flag the SQUARE_* flag we are marking with
223  * \param light lit or not
224  */
fill_yrange(struct chunk * c,int x,int y1,int y2,int feat,int flag,bool light)225 static void fill_yrange(struct chunk *c, int x, int y1, int y2, int feat,
226 						int flag, bool light)
227 {
228 	int y;
229 	for (y = y1; y <= y2; y++) {
230 		struct loc grid = loc(x, y);
231 		square_set_feat(c, grid, feat);
232 		sqinfo_on(square(c, grid)->info, SQUARE_ROOM);
233 		if (flag) sqinfo_on(square(c, grid)->info, flag);
234 		if (light)
235 			sqinfo_on(square(c, grid)->info, SQUARE_GLOW);
236 	}
237 }
238 
239 /**
240  * Fill a circle with the given feature/info.
241  * \param c the current chunk
242  * \param y0 the circle centre
243  * \param x0 the circle centre
244  * \param radius the circle radius
245  * \param border the width of the circle border
246  * \param feat the terrain feature
247  * \param flag the SQUARE_* flag we are marking with
248  * \param light lit or not
249  */
fill_circle(struct chunk * c,int y0,int x0,int radius,int border,int feat,int flag,bool light)250 static void fill_circle(struct chunk *c, int y0, int x0, int radius, int border,
251 						int feat, int flag, bool light)
252 {
253 	int i, last = 0;
254 	int r2 = radius * radius;
255 	for(i = 0; i <= radius; i++) {
256 		double j = sqrt(r2 - (i * i));
257 		int k = (int)(j + 0.5);
258 
259 		int b = border;
260 		if (border && last > k) b++;
261 
262 		fill_xrange(c, y0 - i, x0 - k - b, x0 + k + b, feat, flag, light);
263 		fill_xrange(c, y0 + i, x0 - k - b, x0 + k + b, feat, flag, light);
264 		fill_yrange(c, x0 - i, y0 - k - b, y0 + k + b, feat, flag, light);
265 		fill_yrange(c, x0 + i, y0 - k - b, y0 + k + b, feat, flag, light);
266 		last = k;
267 	}
268 }
269 
270 /**
271  * Fill the lines of a cross/plus with a feature.
272  *
273  * \param c the current chunk
274  * \param y1 inclusive room boundaries
275  * \param x1 inclusive room boundaries
276  * \param y2 inclusive room boundaries
277  * \param x2 inclusive room boundaries
278  * \param feat the terrain feature
279  * \param flag the SQUARE_* flag we are marking with
280  * When combined with draw_rectangle() this will generate a large rectangular
281  * room which is split into four sub-rooms.
282  */
generate_plus(struct chunk * c,int y1,int x1,int y2,int x2,int feat,int flag)283 static void generate_plus(struct chunk *c, int y1, int x1, int y2, int x2,
284 						  int feat, int flag)
285 {
286 	int y, x;
287 
288 	/* Find the center */
289 	int y0 = (y1 + y2) / 2;
290 	int x0 = (x1 + x2) / 2;
291 
292 	assert(c);
293 
294 	for (y = y1; y <= y2; y++) square_set_feat(c, loc(x0, y), feat);
295 	if (flag) generate_mark(c, y1, x0, y2, x0, flag);
296 	for (x = x1; x <= x2; x++) square_set_feat(c, loc(x, y0), feat);
297 	if (flag) generate_mark(c, y0, x1, y0, x2, flag);
298 }
299 
300 /**
301  * Generate helper -- open all sides of a rectangle with a feature
302  * \param c the current chunk
303  * \param y1 inclusive room boundaries
304  * \param x1 inclusive room boundaries
305  * \param y2 inclusive room boundaries
306  * \param x2 inclusive room boundaries
307  * \param feat the terrain feature
308  */
generate_open(struct chunk * c,int y1,int x1,int y2,int x2,int feat)309 static void generate_open(struct chunk *c, int y1, int x1, int y2, int x2,
310 						  int feat)
311 {
312 	int y0, x0;
313 
314 	/* Center */
315 	y0 = (y1 + y2) / 2;
316 	x0 = (x1 + x2) / 2;
317 
318 	/* Open all sides */
319 	square_set_feat(c, loc(x0, y1), feat);
320 	square_set_feat(c, loc(x1, y0), feat);
321 	square_set_feat(c, loc(x0, y2), feat);
322 	square_set_feat(c, loc(x2, y0), feat);
323 }
324 
325 
326 /**
327  * Generate helper -- open one side of a rectangle with a feature
328  * \param c the current chunk
329  * \param y1 inclusive room boundaries
330  * \param x1 inclusive room boundaries
331  * \param y2 inclusive room boundaries
332  * \param x2 inclusive room boundaries
333  * \param feat the terrain feature
334  */
generate_hole(struct chunk * c,int y1,int x1,int y2,int x2,int feat)335 static void generate_hole(struct chunk *c, int y1, int x1, int y2, int x2,
336 						  int feat)
337 {
338 	/* Find the center */
339 	int y0 = (y1 + y2) / 2;
340 	int x0 = (x1 + x2) / 2;
341 
342 	assert(c);
343 
344 	/* Open random side */
345 	switch (randint0(4)) {
346 	case 0: square_set_feat(c, loc(x0, y1), feat); break;
347 	case 1: square_set_feat(c, loc(x1, y0), feat); break;
348 	case 2: square_set_feat(c, loc(x0, y2), feat); break;
349 	case 3: square_set_feat(c, loc(x2, y0), feat); break;
350 	}
351 }
352 
353 /**
354  * Place a square of granite with a flag
355  * \param c the current chunk
356  * \param y the square co-ordinates
357  * \param x the square co-ordinates
358  * \param flag the SQUARE_* flag we are marking with
359  */
set_marked_granite(struct chunk * c,struct loc grid,int flag)360 void set_marked_granite(struct chunk *c, struct loc grid, int flag)
361 {
362 	square_set_feat(c, grid, FEAT_GRANITE);
363 	if (flag) generate_mark(c, grid.y, grid.x, grid.y, grid.x, flag);
364 }
365 
366 /**
367  * Make a starburst room. -LM-
368  *
369  * \param c the current chunk
370  * \param y1 boundaries which will contain the starburst
371  * \param x1 boundaries which will contain the starburst
372  * \param y2 boundaries which will contain the starburst
373  * \param x2 boundaries which will contain the starburst
374  * \param light lit or not
375  * \param feat the terrain feature to make the starburst of
376  * \param special_ok allow wacky cloverleaf rooms
377  * \return success
378  *
379  * Starburst rooms are made in three steps:
380  * 1: Choose a room size-dependent number of arcs.  Large rooms need to
381  *    look less granular and alter their shape more often, so they need
382  *    more arcs.
383  * 2: For each of the arcs, calculate the portion of the full circle it
384  *    includes, and its maximum effect range (how far in that direction
385  *    we can change features in).  This depends on room size, shape, and
386  *    the maximum effect range of the previous arc.
387  * 3: Use the table "get_angle_to_grid" to supply angles to each grid in
388  *    the room.  If the distance to that grid is not greater than the
389  *    maximum effect range that applies at that angle, change the feature
390  *    if appropriate (this depends on feature type).
391  *
392  * Usage notes:
393  * - This function uses a table that cannot handle distances larger than
394  *   20, so it calculates a distance conversion factor for larger rooms.
395  * - This function is not good at handling rooms much longer along one axis
396  *   than the other, so it divides such rooms up, and calls itself to handle
397  *   each section.
398  * - It is safe to call this function on areas that might contain vaults or
399  *   pits, because "icky" and occupied grids are left untouched.
400  *
401  * - Mixing these rooms (using normal floor) with rectangular ones on a
402  *   regular basis produces a somewhat chaotic looking dungeon.  However,
403  *   this code does works well for lakes, etc.
404  *
405  */
generate_starburst_room(struct chunk * c,int y1,int x1,int y2,int x2,bool light,int feat,bool special_ok)406 extern bool generate_starburst_room(struct chunk *c, int y1, int x1, int y2,
407 									int x2, bool light, int feat,
408 									bool special_ok)
409 {
410 	int y0, x0, y, x, ny, nx;
411 	int i, d;
412 	int dist, max_dist, dist_conv, dist_check;
413 	int height, width;
414 	int degree_first, center_of_arc, degree;
415 
416 	/* Special variant room.  Discovered by accident. */
417 	bool make_cloverleaf = false;
418 
419 	/* Holds first degree of arc, maximum effect distance in arc. */
420 	int arc[45][2];
421 
422 	/* Number (max 45) of arcs. */
423 	int arc_num;
424 
425 	/* Make certain the room does not cross the dungeon edge. */
426 	if ((!square_in_bounds(c, loc(x1, y1))) ||
427 		(!square_in_bounds(c, loc(x2, y2))))
428 		return (false);
429 
430 	/* Robustness -- test sanity of input coordinates. */
431 	if ((y1 + 2 >= y2) || (x1 + 2 >= x2))
432 		return (false);
433 
434 
435 	/* Get room height and width. */
436 	height = 1 + y2 - y1;
437 	width = 1 + x2 - x1;
438 
439 
440 	/* Handle long, narrow rooms by dividing them up. */
441 	if ((height > 5 * width / 2) || (width > 5 * height / 2)) {
442 		int tmp_ay, tmp_ax, tmp_by, tmp_bx;
443 
444 		/* Get bottom-left borders of the first room. */
445 		tmp_ay = y2;
446 		tmp_ax = x2;
447 		if (height > width)
448 			tmp_ay = y1 + 2 * height / 3;
449 		else
450 			tmp_ax = x1 + 2 * width / 3;
451 
452 		/* Make the first room. */
453 		(void) generate_starburst_room(c, y1, x1, tmp_ay, tmp_ax, light, feat,
454 									   false);
455 
456 
457 		/* Get top_right borders of the second room. */
458 		tmp_by = y1;
459 		tmp_bx = x1;
460 		if (height > width)
461 			tmp_by = y1 + 1 * height / 3;
462 		else
463 			tmp_bx = x1 + 1 * width / 3;
464 
465 		/* Make the second room. */
466 		(void) generate_starburst_room(c, tmp_by, tmp_bx, y2, x2, light, feat,
467 									   false);
468 
469 
470 		/* If floor, extend a "corridor" between room centers, to ensure
471 		 * that the rooms are connected together. */
472 		if (feat_is_floor(feat)) {
473 			for (y = (y1 + tmp_ay) / 2; y <= (tmp_by + y2) / 2; y++) {
474 				for (x = (x1 + tmp_ax) / 2; x <= (tmp_bx + x2) / 2; x++) {
475 					square_set_feat(c, loc(x, y), feat);
476 				}
477 			}
478 		} else {
479 			/* Otherwise fill any gap between two starbursts. */
480 			int tmp_cy1, tmp_cx1, tmp_cy2, tmp_cx2;
481 
482 			if (height > width) {
483 				tmp_cy1 = y1 + (height - width) / 2;
484 				tmp_cx1 = x1;
485 				tmp_cy2 = tmp_cy1 - (height - width) / 2;
486 				tmp_cx2 = x2;
487 			} else {
488 				tmp_cy1 = y1;
489 				tmp_cx1 = x1 + (width - height) / 2;
490 				tmp_cy2 = y2;
491 				tmp_cx2 = tmp_cx1 + (width - height) / 2;
492 			}
493 
494 			/* Make the third room. */
495 			(void) generate_starburst_room(c, tmp_cy1, tmp_cx1, tmp_cy2,
496 										   tmp_cx2, light, feat, false);
497 		}
498 
499 		/* Return. */
500 		return (true);
501 	}
502 
503 
504 	/* Get a shrinkage ratio for large rooms, as table is limited. */
505 	if ((width > 44) || (height > 44)) {
506 		if (width > height)
507 			dist_conv = 10 * width / 44;
508 		else
509 			dist_conv = 10 * height / 44;
510 	} else
511 		dist_conv = 10;
512 
513 
514 	/* Make a cloverleaf room sometimes. */
515 	if ((special_ok) && (height > 10) && (randint0(20) == 0)) {
516 		arc_num = 12;
517 		make_cloverleaf = true;
518 	}
519 
520 	/* Usually, we make a normal starburst. */
521 	else {
522 		/* Ask for a reasonable number of arcs. */
523 		arc_num = 8 + (height * width / 80);
524 		arc_num = arc_num + 3 - randint0(7);
525 		if (arc_num < 8)
526 			arc_num = 8;
527 		if (arc_num > 45)
528 			arc_num = 45;
529 	}
530 
531 
532 	/* Get the center of the starburst. */
533 	y0 = y1 + height / 2;
534 	x0 = x1 + width / 2;
535 
536 	/* Start out at zero degrees. */
537 	degree_first = 0;
538 
539 
540 	/* Determine the start degrees and expansion distance for each arc. */
541 	for (i = 0; i < arc_num; i++) {
542 		/* Get the first degree for this arc. */
543 		arc[i][0] = degree_first;
544 
545 		/* Get a slightly randomized start degree for the next arc. */
546 		degree_first += (180 + randint0(arc_num)) / arc_num;
547 		if (degree_first < 180 * (i + 1) / arc_num)
548 			degree_first = 180 * (i + 1) / arc_num;
549 		if (degree_first > (180 + arc_num) * (i + 1) / arc_num)
550 			degree_first = (180 + arc_num) * (i + 1) / arc_num;
551 
552 
553 		/* Get the center of the arc. */
554 		center_of_arc = degree_first + arc[i][0];
555 
556 		/* Calculate a reasonable distance to expand vertically. */
557 		if (((center_of_arc > 45) && (center_of_arc < 135))
558 			|| ((center_of_arc > 225) && (center_of_arc < 315))) {
559 			arc[i][1] = height / 4 + randint0((height + 3) / 4);
560 		}
561 
562 		/* Calculate a reasonable distance to expand horizontally. */
563 		else if (((center_of_arc < 45) || (center_of_arc > 315))
564 				 || ((center_of_arc < 225) && (center_of_arc > 135))) {
565 			arc[i][1] = width / 4 + randint0((width + 3) / 4);
566 		}
567 
568 		/* Handle arcs that count as neither vertical nor horizontal */
569 		else if (i != 0) {
570 			if (make_cloverleaf)
571 				arc[i][1] = 0;
572 			else
573 				arc[i][1] = arc[i - 1][1] + 3 - randint0(7);
574 		}
575 
576 
577 		/* Keep variability under control. */
578 		if ((!make_cloverleaf) && (i != 0) && (i != arc_num - 1)) {
579 			/* Water edges must be quite smooth. */
580 			if (feat_is_smooth(feat)) {
581 				if (arc[i][1] > arc[i - 1][1] + 2)
582 					arc[i][1] = arc[i - 1][1] + 2;
583 
584 				if (arc[i][1] > arc[i - 1][1] - 2)
585 					arc[i][1] = arc[i - 1][1] - 2;
586 			} else {
587 				if (arc[i][1] > 3 * (arc[i - 1][1] + 1) / 2)
588 					arc[i][1] = 3 * (arc[i - 1][1] + 1) / 2;
589 
590 				if (arc[i][1] < 2 * (arc[i - 1][1] - 1) / 3)
591 					arc[i][1] = 2 * (arc[i - 1][1] - 1) / 3;
592 			}
593 		}
594 
595 		/* Neaten up final arc of circle by comparing it to the first. */
596 		if ((i == arc_num - 1) && (ABS(arc[i][1] - arc[0][1]) > 3)) {
597 			if (arc[i][1] > arc[0][1])
598 				arc[i][1] -= randint0(arc[i][1] - arc[0][1]);
599 			else if (arc[i][1] < arc[0][1])
600 				arc[i][1] += randint0(arc[0][1] - arc[i][1]);
601 		}
602 	}
603 
604 
605 	/* Precalculate check distance. */
606 	dist_check = 21 * dist_conv / 10;
607 
608 	/* Change grids between (and not including) the edges. */
609 	for (y = y1 + 1; y < y2; y++) {
610 		for (x = x1 + 1; x < x2; x++) {
611 			struct loc grid = loc(x, y);
612 
613 			/* Do not touch vault grids. */
614 			if (square_isvault(c, grid))
615 				continue;
616 
617 			/* Do not touch occupied grids. */
618 			if (square_monster(c, grid))
619 				continue;
620 			if (square_object(c, grid))
621 				continue;
622 
623 			/* Get distance to grid. */
624 			dist = distance(loc(x0, y0), grid);
625 
626 			/* Reject grid if outside check distance. */
627 			if (dist >= dist_check)
628 				continue;
629 
630 			/* Convert and reorient grid for table access. */
631 			ny = 20 + 10 * (y - y0) / dist_conv;
632 			nx = 20 + 10 * (x - x0) / dist_conv;
633 
634 			/* Illegal table access is bad. */
635 			if ((ny < 0) || (ny > 40) || (nx < 0) || (nx > 40))
636 				continue;
637 
638 			/* Get angle to current grid. */
639 			degree = get_angle_to_grid[ny][nx];
640 
641 			/* Scan arcs to find the one that applies here. */
642 			for (i = arc_num - 1; i >= 0; i--) {
643 				if (arc[i][0] <= degree) {
644 					max_dist = arc[i][1];
645 
646 					/* Must be within effect range. */
647 					if (max_dist >= dist) {
648 						/* If new feature is not passable, or floor, always
649 						 * place it. */
650 						if (feat_is_floor(feat) || !feat_is_passable(feat)) {
651 							square_set_feat(c, grid, feat);
652 
653 							if (feat_is_floor(feat)) {
654 								sqinfo_on(square(c, grid)->info, SQUARE_ROOM);
655 							} else {
656 								sqinfo_off(square(c, grid)->info, SQUARE_ROOM);
657 							}
658 
659 							if (light) {
660 								sqinfo_on(square(c, grid)->info, SQUARE_GLOW);
661 							} else if (!square_isbright(c, grid)) {
662 								sqinfo_off(square(c, grid)->info, SQUARE_GLOW);
663 							}
664 						}
665 
666 						/* If new feature is non-floor passable terrain,
667 						 * place it only over floor. */
668 						else {
669 							/* Replace old feature entirely in some cases. */
670 							if (feat_is_smooth(feat)) {
671 								if (square_isfloor(c, grid))
672 									square_set_feat(c, grid, feat);
673 							} else {
674 								/* Make denser in the middle. */
675 								if (square_isfloor(c, grid) &&
676 									(randint1(max_dist + 5) >= dist + 5))
677 									square_set_feat(c, grid, feat);
678 							}
679 
680 							/* Light grid. */
681 							if (light)
682 								sqinfo_on(square(c, grid)->info, SQUARE_GLOW);
683 						}
684 					}
685 
686 					/* Arc found.  End search */
687 					break;
688 				}
689 			}
690 		}
691 	}
692 
693 	/*
694 	 * If we placed floors or dungeon granite, all dungeon granite next
695 	 * to floors needs to become outer wall.
696 	 */
697 	if (feat_is_floor(feat) || feat == FEAT_GRANITE) {
698 		for (y = y1 + 1; y < y2; y++) {
699 			for (x = x1 + 1; x < x2; x++) {
700 
701 				struct loc grid = loc(x, y);
702 				/* Floor grids only */
703 				if (square_isfloor(c, grid)) {
704 					/* Look in all directions. */
705 					for (d = 0; d < 8; d++) {
706 						/* Extract adjacent location */
707 						struct loc grid1 = loc_sum(grid, ddgrid_ddd[d]);
708 
709 						/* Join to room, forbid stairs */
710 						sqinfo_on(square(c, grid1)->info, SQUARE_ROOM);
711 						sqinfo_on(square(c, grid1)->info, SQUARE_NO_STAIRS);
712 
713 						/* Illuminate if requested. */
714 						if (light)
715 							sqinfo_on(square(c, grid1)->info, SQUARE_GLOW);
716 
717 						/* Look for dungeon granite. */
718 						if (square(c, grid1)->feat == FEAT_GRANITE) {
719 							/* Mark as outer wall. */
720 							set_marked_granite(c, grid1, SQUARE_WALL_OUTER);
721 						}
722 					}
723 				}
724 			}
725 		}
726 	}
727 
728 	/* Success */
729 	return (true);
730 }
731 
732 /**
733  * Hook for picking monsters appropriate to a nest/pit or region.
734  * \param race the race being tested for inclusion
735  * \return the race is acceptable
736  * Requires dun->pit_type to be set.
737  */
mon_pit_hook(struct monster_race * race)738 bool mon_pit_hook(struct monster_race *race)
739 {
740 	bool match_base = true;
741 	bool match_color = true;
742 	int innate_freq = dun->pit_type->freq_innate;
743 
744 	assert(race);
745 	assert(dun->pit_type);
746 
747 	if (rf_has(race->flags, RF_UNIQUE)) {
748 		return false;
749 	} else if (!rf_is_subset(race->flags, dun->pit_type->flags)) {
750 		return false;
751 	} else if (rf_is_inter(race->flags, dun->pit_type->forbidden_flags)) {
752 		return false;
753 	} else if (!rsf_is_subset(race->spell_flags, dun->pit_type->spell_flags)) {
754 		return false;
755 	} else if (rsf_is_inter(race->spell_flags,
756 							dun->pit_type->forbidden_spell_flags)) {
757 		return false;
758 	} else if (race->freq_innate < innate_freq) {
759 		return false;
760 	} else if (dun->pit_type->forbidden_monsters) {
761 		struct pit_forbidden_monster *monster;
762 		for (monster = dun->pit_type->forbidden_monsters; monster;
763 			 monster = monster->next) {
764 			if (race == monster->race)
765 				return false;
766 		}
767 	}
768 
769 	if (dun->pit_type->bases) {
770 		struct pit_monster_profile *bases;
771 		match_base = false;
772 
773 		for (bases = dun->pit_type->bases; bases; bases = bases->next) {
774 			if (race->base == bases->base)
775 				match_base = true;
776 		}
777 	}
778 
779 	if (dun->pit_type->colors) {
780 		struct pit_color_profile *colors;
781 		match_color = false;
782 
783 		for (colors = dun->pit_type->colors; colors; colors = colors->next) {
784 			if (race->d_attr == colors->color)
785 				match_color = true;
786 		}
787 	}
788 
789 	return (match_base && match_color);
790 }
791 
792 /**
793  * Pick a type of monster for pits (or other purposes), based on the level.
794  *
795  * We scan through all pit profiles, and for each one generate a random depth
796  * using a normal distribution, with the mean given in pit.txt, and a
797  * standard deviation of 10. Then we pick the profile that gave us a depth that
798  * is closest to the player's actual depth.
799  *
800  * Sets dun->pit_type, which is required for mon_pit_hook.
801  * \param depth is the pit profile depth to aim for in selection
802  * \param type is 1 for pits, 2 for nests, 0 for any profile
803  */
set_pit_type(int depth,int type)804 void set_pit_type(int depth, int type)
805 {
806 	int i;
807 	int pit_idx = 0;
808 
809 	/* Hack -- set initial distance large */
810 	int pit_dist = 999;
811 
812 	for (i = 0; i < z_info->pit_max; i++) {
813 		int offset, dist;
814 		struct pit_profile *pit = &pit_info[i];
815 
816 		/* Skip empty pits or pits of the wrong room type */
817 		if (type && (!pit->name || pit->room_type != type)) continue;
818 
819 		offset = Rand_normal(pit->ave, 10);
820 		dist = ABS(offset - depth);
821 
822 		if (dist < pit_dist && one_in_(pit->rarity)) {
823 			/* This pit is the closest so far */
824 			pit_idx = i;
825 			pit_dist = dist;
826 		}
827 	}
828 
829 	dun->pit_type = &pit_info[pit_idx];
830 }
831 
832 /**
833  * Find a good spot for the next room.
834  *
835  * \param y centre of the room
836  * \param x centre of the room
837  * \param height dimensions of the room
838  * \param width dimensions of the room
839  * \return success
840  *
841  * Find and allocate a free space in the dungeon large enough to hold
842  * the room calling this function.
843  *
844  * We allocate space in blocks.
845  *
846  * Be careful to include the edges of the room in height and width!
847  *
848  * Return true and values for the center of the room if all went well.
849  * Otherwise, return false.
850  */
find_space(struct loc * centre,int height,int width)851 static bool find_space(struct loc *centre, int height, int width)
852 {
853 	int i;
854 	int by, bx, by1, bx1, by2, bx2;
855 
856 	bool filled;
857 
858 	/* Find out how many blocks we need. */
859 	int blocks_high = 1 + ((height - 1) / dun->block_hgt);
860 	int blocks_wide = 1 + ((width - 1) / dun->block_wid);
861 
862 	/* Deal with staircase "rooms" */
863 	if (OPT(player, birth_levels_persist) && (height * width == 1)) {
864 		struct connector *join = dun->join;
865 		bool found = false;
866 
867 		/* Acquire the location of the room */
868 		int n = dun->cent_n;
869 
870 		while (n) {
871 			join = join->next;
872 			n--;
873 		}
874 		if (join) {
875 			*centre = join->grid;
876 			found = true;
877 		}
878 
879 		/* Check we have found one */
880 		if (found) {
881 			/* Get the blocks */
882 			by = (centre->y + 1) / dun->block_hgt;
883 			bx = (centre->x + 1) / dun->block_wid;
884 
885 			/* Save the room location */
886 			if (dun->cent_n < z_info->level_room_max) {
887 				dun->cent[dun->cent_n] = *centre;
888 				dun->cent_n++;
889 			}
890 
891 			/* Reserve a block, marked with the room index */
892 			dun->room_map[by][bx] = dun->cent_n;
893 
894 			/* Success. */
895 			return (true);
896 		}
897 	}
898 
899 	/* We'll allow twenty-five guesses. */
900 	for (i = 0; i < 25; i++) {
901 		filled = false;
902 
903 		/* Pick a top left block at random */
904 		by1 = randint0(dun->row_blocks);
905 		bx1 = randint0(dun->col_blocks);
906 
907 		/* Extract bottom right corner block */
908 		by2 = by1 + blocks_high - 1;
909 		bx2 = bx1 + blocks_wide - 1;
910 
911 		/* Never run off the screen */
912 		if (by1 < 0 || by2 >= dun->row_blocks) continue;
913 		if (bx1 < 0 || bx2 >= dun->col_blocks) continue;
914 
915 		/* Verify open space */
916 		for (by = by1; by <= by2; by++) {
917 			for (bx = bx1; bx <= bx2; bx++) {
918 				if (dun->room_map[by][bx])
919 					filled = true;
920 			}
921 		}
922 
923 		/* If space filled, try again. */
924 		if (filled)	continue;
925 
926 		/* Get the location of the room */
927 		centre->y = ((by1 + by2 + 1) * dun->block_hgt) / 2;
928 		centre->x = ((bx1 + bx2 + 1) * dun->block_wid) / 2;
929 
930 		/* Save the room location */
931 		if (dun->cent_n < z_info->level_room_max) {
932 			dun->cent[dun->cent_n] = *centre;
933 			dun->cent_n++;
934 		}
935 
936 		/* Reserve some blocks */
937 		for (by = by1; by <= by2; by++) {
938 			for (bx = bx1; bx <= bx2; bx++) {
939 				dun->room_map[by][bx] = true;
940 			}
941 		}
942 
943 		/* Success. */
944 		return (true);
945 	}
946 
947 	/* Failure. */
948 	return (false);
949 }
950 
951 /**
952  * Build a room template from its string representation.
953  * \param c the chunk the room is being built in
954  *\ param centre the room centre; out of chunk centre invokes find_space()
955  * \param ymax the room dimensions
956  * \param xmax the room dimensions
957  * \param doors the door position
958  * \param data the room template text description
959  * \param tval the object type for any included objects
960  * \return success
961  */
build_room_template(struct chunk * c,struct loc centre,int ymax,int xmax,int doors,const char * data,int tval)962 static bool build_room_template(struct chunk *c, struct loc centre, int ymax,
963 								int xmax, int doors, const char *data, int tval)
964 {
965 	int dx, dy, rnddoors, doorpos;
966 	const char *t;
967 	bool rndwalls, light;
968 
969 
970 	assert(c);
971 
972 	/* Occasional light */
973 	light = c->depth <= randint1(25) ? true : false;
974 
975 	/* Set the random door position here so it generates doors in all squares
976 	 * marked with the same number */
977 	rnddoors = randint1(doors);
978 
979 	/* Decide whether optional walls will be generated this time */
980 	rndwalls = one_in_(2) ? true : false;
981 
982 	/* Find and reserve some space in the dungeon.  Get center of room. */
983 	if ((centre.y >= c->height) || (centre.x >= c->width)) {
984 		if (!find_space(&centre, ymax + 2, xmax + 2))
985 			return (false);
986 	}
987 
988 	/* Place dungeon features and objects */
989 	for (t = data, dy = 0; dy < ymax && *t; dy++) {
990 		for (dx = 0; dx < xmax && *t; dx++, t++) {
991 			/* Extract the location */
992 			struct loc grid = loc(centre.x - (xmax / 2) + dx,
993 								  centre.y - (ymax / 2) + dy);
994 
995 			/* Skip non-grids */
996 			if (*t == ' ') continue;
997 
998 			/* Lay down a floor */
999 			square_set_feat(c, grid, FEAT_FLOOR);
1000 
1001 			/* Debugging assertion */
1002 			assert(square_isempty(c, grid));
1003 
1004 			/* Analyze the grid */
1005 			switch (*t) {
1006 			case '%': set_marked_granite(c, grid, SQUARE_WALL_OUTER); break;
1007 			case '#': set_marked_granite(c, grid, SQUARE_WALL_SOLID); break;
1008 			case '+': place_closed_door(c, grid); break;
1009 			case '^': if (one_in_(4)) place_trap(c, grid, -1, c->depth); break;
1010 			case 'x': {
1011 
1012 				/* If optional walls are generated, put a wall in this square */
1013 				if (rndwalls)
1014 					set_marked_granite(c, grid, SQUARE_WALL_SOLID);
1015 				break;
1016 			}
1017 			case '(': {
1018 
1019 				/* If optional walls are generated, put a door in this square */
1020 				if (rndwalls)
1021 					place_secret_door(c, grid);
1022 				break;
1023 			}
1024 			case ')': {
1025 				/* If no optional walls generated, put a door in this square */
1026 				if (!rndwalls)
1027 					place_secret_door(c, grid);
1028 				else
1029 					set_marked_granite(c, grid, SQUARE_WALL_SOLID);
1030 				break;
1031 			}
1032 			case '8': {
1033 
1034 				/* Put something nice in this square
1035 				 * Object (80%) or Stairs (20%) */
1036 				if ((randint0(100) < 80) || OPT(player, birth_levels_persist))
1037 					place_object(c, grid, c->depth, false, false,
1038 								 ORIGIN_SPECIAL, 0);
1039 				else
1040 					place_random_stairs(c, grid);
1041 
1042 				/* Some monsters to guard it */
1043 				vault_monsters(c, grid, c->depth + 2, randint0(2) + 3);
1044 
1045 				break;
1046 			}
1047 			case '9': {
1048 				/* Create some interesting stuff nearby */
1049 				struct loc off2 = loc(2, -2);
1050 				struct loc off3 = loc(3, 3);
1051 
1052 				/* A few monsters */
1053 				vault_monsters(c, loc_diff(grid, off3), c->depth + randint0(2),
1054 							   randint1(2));
1055 				vault_monsters(c, loc_sum(grid, off3), c->depth + randint0(2),
1056 							   randint1(2));
1057 
1058 				/* And maybe a bit of treasure */
1059 				if (one_in_(2))
1060 					vault_objects(c, loc_sum(grid, off2), c->depth,
1061 								  1 + randint0(2));
1062 
1063 				if (one_in_(2))
1064 					vault_objects(c, loc_diff(grid, off2), c->depth,
1065 								  1 + randint0(2));
1066 
1067 				break;
1068 
1069 			}
1070 			case '[': {
1071 
1072 				/* Place an object of the template's specified tval */
1073 				place_object(c, grid, c->depth, false, false, ORIGIN_SPECIAL,
1074 							 tval);
1075 				break;
1076 			}
1077 			case '1':
1078 			case '2':
1079 			case '3':
1080 			case '4':
1081 			case '5':
1082 			case '6': {
1083 				/* Check if this is chosen random door position */
1084 				doorpos = (int) (*t - '0');
1085 
1086 				if (doorpos == rnddoors)
1087 					place_secret_door(c, grid);
1088 				else
1089 					set_marked_granite(c, grid, SQUARE_WALL_SOLID);
1090 
1091 				break;
1092 			}
1093 			}
1094 
1095 			/* Part of a room */
1096 			sqinfo_on(square(c, grid)->info, SQUARE_ROOM);
1097 			if (light)
1098 				sqinfo_on(square(c, grid)->info, SQUARE_GLOW);
1099 		}
1100 	}
1101 
1102 	return true;
1103 }
1104 
1105 /**
1106  * Helper function for building room templates.
1107  * \param c the chunk the room is being built in
1108  *\ param centre the room centre; out of chunk centre invokes find_space()
1109  * \param typ the room template type (currently unused)
1110  * \return success
1111  */
build_room_template_type(struct chunk * c,struct loc centre,int typ,int rating)1112 static bool build_room_template_type(struct chunk *c, struct loc centre,
1113 									 int typ, int rating)
1114 {
1115 	struct room_template *room = random_room_template(typ, rating);
1116 
1117 	if (room == NULL)
1118 		return false;
1119 
1120 	/* Build the room */
1121 	if (!build_room_template(c, centre, room->hgt, room->wid, room->dor,
1122 							 room->text, room->tval))
1123 		return false;
1124 
1125 	ROOM_LOG("Room template (%s)", room->name);
1126 
1127 	return true;
1128 }
1129 
1130 /**
1131  * Build a vault from its string representation.
1132  * \param c the chunk the room is being built in
1133  *\ param centre the room centre; out of chunk centre invokes find_space()
1134  * \param v pointer to the vault template
1135  * \return success
1136  */
build_vault(struct chunk * c,struct loc centre,struct vault * v)1137 bool build_vault(struct chunk *c, struct loc centre, struct vault *v)
1138 {
1139 	const char *data = v->text;
1140 	int y1, x1, y2, x2;
1141 	int x, y, races_local = 0;
1142 	const char *t;
1143 	char racial_symbol[30] = "";
1144 	bool icky;
1145 
1146 	assert(c);
1147 
1148 	/* Find and reserve some space in the dungeon.  Get center of room. */
1149 	if ((centre.y >= c->height) || (centre.x >= c->width)) {
1150 		if (!find_space(&centre, v->hgt + 2, v->wid + 2))
1151 			return (false);
1152 	}
1153 
1154 	/* Get the room corners */
1155 	y1 = centre.y - (v->hgt / 2);
1156 	x1 = centre.x - (v->wid / 2);
1157 	y2 = y1 + v->hgt - 1;
1158 	x2 = x1 + v->wid - 1;
1159 
1160 	/* No random monsters in vaults. */
1161 	generate_mark(c, y1, x1, y2, x2, SQUARE_MON_RESTRICT);
1162 
1163 	/* Place dungeon features and objects */
1164 	for (t = data, y = y1; y <= y2 && *t; y++) {
1165 		for (x = x1; x <= x2 && *t; x++, t++) {
1166 			struct loc grid = loc(x, y);
1167 			/* Skip non-grids */
1168 			if (*t == ' ') continue;
1169 
1170 			/* Lay down a floor */
1171 			square_set_feat(c, grid, FEAT_FLOOR);
1172 
1173 			/* Debugging assertion */
1174 			assert(square_isempty(c, grid));
1175 
1176 			/* By default vault squares are marked icky */
1177 			icky = true;
1178 
1179 			/* Analyze the grid */
1180 			switch (*t) {
1181 			case '%': {
1182 				/* In this case, the square isn't really part of the
1183 				 * vault, but rather is part of the "door step" to the
1184 				 * vault. We don't mark it icky so that the tunneling
1185 				 * code knows its allowed to remove this wall. */
1186 				set_marked_granite(c, grid, SQUARE_WALL_OUTER);
1187 				icky = false;
1188 				break;
1189 			}
1190 				/* Inner granite wall */
1191 			case '#': set_marked_granite(c, grid, SQUARE_WALL_INNER); break;
1192 				/* Permanent wall */
1193 			case '@': square_set_feat(c, grid, FEAT_PERM); break;
1194 				/* Gold seam */
1195 			case '*': {
1196 				square_set_feat(c, grid, one_in_(2) ? FEAT_MAGMA_K :
1197 								FEAT_QUARTZ_K);
1198 				break;
1199 			}
1200 				/* Rubble */
1201 			case ':': {
1202 				square_set_feat(c, grid, one_in_(2) ? FEAT_PASS_RUBBLE :
1203 								FEAT_RUBBLE);
1204 				break;
1205 			}
1206 				/* Secret door */
1207 			case '+': place_secret_door(c, grid); break;
1208 				/* Trap */
1209 			case '^': if (one_in_(4)) place_trap(c, grid, -1, c->depth); break;
1210 				/* Treasure or a trap */
1211 			case '&': {
1212 				if (randint0(100) < 75) {
1213 					place_object(c, grid, c->depth, false, false, ORIGIN_VAULT,
1214 								 0);
1215 				} else if (one_in_(4)) {
1216 					place_trap(c, grid, -1, c->depth);
1217 				}
1218 				break;
1219 			}
1220 				/* Stairs */
1221 			case '<': {
1222 				if (OPT(player, birth_levels_persist)) break;
1223 				square_set_feat(c, grid, FEAT_LESS); break;
1224 			}
1225 			case '>': {
1226 				if (OPT(player, birth_levels_persist)) break;
1227 				/* No down stairs at bottom or on quests */
1228 				if (is_quest(c->depth) || c->depth >= z_info->max_depth - 1)
1229 					square_set_feat(c, grid, FEAT_LESS);
1230 				else
1231 					square_set_feat(c, grid, FEAT_MORE);
1232 				break;
1233 			}
1234 				/* Lava */
1235 			case '`': square_set_feat(c, grid, FEAT_LAVA); break;
1236 				/* Included to allow simple inclusion of FA vaults */
1237 			case '/': /*square_set_feat(c, grid, FEAT_WATER)*/; break;
1238 			case ';': /*square_set_feat(c, grid, FEAT_TREE)*/; break;
1239 			}
1240 
1241 			/* Part of a vault */
1242 			sqinfo_on(square(c, grid)->info, SQUARE_ROOM);
1243 			if (icky) sqinfo_on(square(c, grid)->info, SQUARE_VAULT);
1244 		}
1245 	}
1246 
1247 
1248 	/* Place regular dungeon monsters and objects */
1249 	for (t = data, y = y1; y <= y2 && *t; y++) {
1250 		for (x = x1; x <= x2 && *t; x++, t++) {
1251 			struct loc grid = loc(x, y);
1252 			/* Hack -- skip "non-grids" */
1253 			if (*t == ' ') continue;
1254 
1255 			/* Most alphabetic characters signify monster races. */
1256 			if (isalpha(*t) && (*t != 'x') && (*t != 'X')) {
1257 				/* If the symbol is not yet stored, ... */
1258 				if (!strchr(racial_symbol, *t)) {
1259 					/* ... store it for later processing. */
1260 					if (races_local < 30)
1261 						racial_symbol[races_local++] = *t;
1262 				}
1263 			}
1264 
1265 			/* Otherwise, analyze the symbol */
1266 			else
1267 				switch (*t) {
1268 					/* An ordinary monster, object (sometimes good), or trap. */
1269 				case '1': {
1270 					if (one_in_(2)) {
1271 						pick_and_place_monster(c, grid, c->depth , true, true,
1272 											   ORIGIN_DROP_VAULT);
1273 					} else if (one_in_(2)) {
1274 						place_object(c, grid, c->depth,
1275 									 one_in_(8) ? true : false, false,
1276 									 ORIGIN_VAULT, 0);
1277 					} else if (one_in_(4)) {
1278 						place_trap(c, grid, -1, c->depth);
1279 					}
1280 					break;
1281 				}
1282 					/* Slightly out of depth monster. */
1283 				case '2': pick_and_place_monster(c, grid, c->depth + 5, true,
1284 												 true, ORIGIN_DROP_VAULT);
1285 					break;
1286 					/* Slightly out of depth object. */
1287 				case '3': place_object(c, grid, c->depth + 3, false, false,
1288 									   ORIGIN_VAULT, 0); break;
1289 					/* Monster and/or object */
1290 				case '4': {
1291 					if (one_in_(2))
1292 						pick_and_place_monster(c, grid, c->depth + 3, true,
1293 											   true, ORIGIN_DROP_VAULT);
1294 					if (one_in_(2))
1295 						place_object(c, grid, c->depth + 7, false, false,
1296 									 ORIGIN_VAULT, 0);
1297 					break;
1298 				}
1299 					/* Out of depth object. */
1300 				case '5': place_object(c, grid, c->depth + 7, false, false,
1301 									   ORIGIN_VAULT, 0); break;
1302 					/* Out of depth monster. */
1303 				case '6': pick_and_place_monster(c, grid, c->depth + 11, true,
1304 												 true, ORIGIN_DROP_VAULT);
1305 					break;
1306 					/* Very out of depth object. */
1307 				case '7': place_object(c, grid, c->depth + 15, false, false,
1308 									   ORIGIN_VAULT, 0); break;
1309 					/* Very out of depth monster. */
1310 				case '0': pick_and_place_monster(c, grid, c->depth + 20, true,
1311 												 true, ORIGIN_DROP_VAULT);
1312 					break;
1313 					/* Meaner monster, plus treasure */
1314 				case '9': {
1315 					pick_and_place_monster(c, grid, c->depth + 9, true, true,
1316 										   ORIGIN_DROP_VAULT);
1317 					place_object(c, grid, c->depth + 7, true, false,
1318 								 ORIGIN_VAULT, 0);
1319 					break;
1320 				}
1321 					/* Nasty monster and treasure */
1322 				case '8': {
1323 					pick_and_place_monster(c, grid, c->depth + 40, true, true,
1324 										   ORIGIN_DROP_VAULT);
1325 					place_object(c, grid, c->depth + 20, true, true,
1326 								 ORIGIN_VAULT, 0);
1327 					break;
1328 				}
1329 					/* A chest. */
1330 				case '~': place_object(c, grid, c->depth + 5, false, false,
1331 									   ORIGIN_VAULT, TV_CHEST); break;
1332 					/* Treasure. */
1333 				case '$': place_gold(c, grid, c->depth, ORIGIN_VAULT);break;
1334 					/* Armour. */
1335 				case ']': {
1336 					int	tval = 0, temp = one_in_(3) ? randint1(9) : randint1(8);
1337 					switch (temp) {
1338 					case 1: tval = TV_BOOTS; break;
1339 					case 2: tval = TV_GLOVES; break;
1340 					case 3: tval = TV_HELM; break;
1341 					case 4: tval = TV_CROWN; break;
1342 					case 5: tval = TV_SHIELD; break;
1343 					case 6: tval = TV_CLOAK; break;
1344 					case 7: tval = TV_SOFT_ARMOR; break;
1345 					case 8: tval = TV_HARD_ARMOR; break;
1346 					case 9: tval = TV_DRAG_ARMOR; break;
1347 					}
1348 					place_object(c, grid, c->depth + 3, true, false,
1349 								 ORIGIN_VAULT, tval);
1350 					break;
1351 				}
1352 					/* Weapon. */
1353 				case '|': {
1354 					int	tval = 0, temp = randint1(4);
1355 					switch (temp) {
1356 					case 1: tval = TV_SWORD; break;
1357 					case 2: tval = TV_POLEARM; break;
1358 					case 3: tval = TV_HAFTED; break;
1359 					case 4: tval = TV_BOW; break;
1360 					}
1361 					place_object(c, grid, c->depth + 3, true, false,
1362 								 ORIGIN_VAULT, tval);
1363 					break;
1364 				}
1365 					/* Ring. */
1366 				case '=': place_object(c, grid, c->depth + 3, one_in_(4), false,
1367 									   ORIGIN_VAULT, TV_RING); break;
1368 					/* Amulet. */
1369 				case '"': place_object(c, grid, c->depth + 3, one_in_(4), false,
1370 									   ORIGIN_VAULT, TV_AMULET); break;
1371 					/* Potion. */
1372 				case '!': place_object(c, grid, c->depth + 3, one_in_(4), false,
1373 									   ORIGIN_VAULT, TV_POTION); break;
1374 					/* Scroll. */
1375 				case '?': place_object(c, grid, c->depth + 3, one_in_(4), false,
1376 									   ORIGIN_VAULT, TV_SCROLL); break;
1377 					/* Staff. */
1378 				case '_': place_object(c, grid, c->depth + 3, one_in_(4), false,
1379 									   ORIGIN_VAULT, TV_STAFF); break;
1380 					/* Wand or rod. */
1381 				case '-': place_object(c, grid, c->depth + 3, one_in_(4), false,
1382 									   ORIGIN_VAULT,
1383 									   one_in_(2) ? TV_WAND : TV_ROD);
1384 					break;
1385 					/* Food or mushroom. */
1386 				case ',': place_object(c, grid, c->depth + 3, one_in_(4), false,
1387 									   ORIGIN_VAULT, TV_FOOD); break;
1388 				}
1389 		}
1390 	}
1391 
1392 	/* Place specified monsters */
1393 	get_vault_monsters(c, racial_symbol, v->typ, data, y1, y2, x1, x2);
1394 
1395 	return true;
1396 }
1397 
1398 /**
1399  * Helper function for building vaults.
1400  * \param c the chunk the room is being built in
1401  *\ param centre the room centre; out of chunk centre invokes find_space()
1402  * \param typ the vault type
1403  * \param label name of the vault type (eg "Greater vault")
1404  * \return success
1405  */
build_vault_type(struct chunk * c,struct loc centre,const char * typ)1406 static bool build_vault_type(struct chunk *c, struct loc centre,
1407 							 const char *typ)
1408 {
1409 	struct vault *v = random_vault(c->depth, typ);
1410 	if (v == NULL) {
1411 		/*quit_fmt("got NULL from random_vault(%s)", typ);*/
1412 		return false;
1413 	}
1414 
1415 	/* Build the vault */
1416 	if (!build_vault(c, centre, v))
1417 		return false;
1418 
1419 	ROOM_LOG("%s (%s)", typ, v->name);
1420 
1421 	/* Boost the rating */
1422 	c->mon_rating += v->rat;
1423 
1424 	return true;
1425 }
1426 
1427 /**
1428  * Helper for rooms of chambers; builds a marked wall grid if appropriate
1429  * \param c the chunk the room is being built in
1430  * \param y co-ordinates
1431  * \param x co-ordinates
1432  */
make_inner_chamber_wall(struct chunk * c,int y,int x)1433 static void make_inner_chamber_wall(struct chunk *c, int y, int x)
1434 {
1435 	struct loc grid = loc(x, y);
1436 	if ((square(c, grid)->feat != FEAT_GRANITE) &&
1437 		(square(c, grid)->feat != FEAT_MAGMA))
1438 		return;
1439 	if (square_iswall_outer(c, grid)) return;
1440 	if (square_iswall_solid(c, grid)) return;
1441 	set_marked_granite(c, grid, SQUARE_WALL_INNER);
1442 }
1443 
1444 /**
1445  * Helper function for rooms of chambers.  Fill a room matching
1446  * the rectangle input with magma, and surround it with inner wall.
1447  * Create a door in a random inner wall grid along the border of the
1448  * rectangle.
1449  * \param c the chunk the room is being built in
1450  * \param y1 chamber dimensions
1451  * \param x1 chamber dimensions
1452  * \param y2 chamber dimensions
1453  * \param x2 chamber dimensions
1454  */
make_chamber(struct chunk * c,int y1,int x1,int y2,int x2)1455 static void make_chamber(struct chunk *c, int y1, int x1, int y2, int x2)
1456 {
1457 	int i, d, y, x;
1458 	int count;
1459 
1460 	/* Fill with soft granite (will later be replaced with floor). */
1461 	fill_rectangle(c, y1 + 1, x1 + 1, y2 - 1, x2 - 1, FEAT_MAGMA,
1462 				   SQUARE_NONE);
1463 
1464 	/* Generate inner walls over dungeon granite and magma. */
1465 	for (y = y1; y <= y2; y++) {
1466 		/* left wall */
1467 		make_inner_chamber_wall(c, y, x1);
1468 		/* right wall */
1469 		make_inner_chamber_wall(c, y, x2);
1470 	}
1471 
1472 	for (x = x1; x <= x2; x++) {
1473 		/* top wall */
1474 		make_inner_chamber_wall(c, y1, x);
1475 		/* bottom wall */
1476 		make_inner_chamber_wall(c, y2, x);
1477 	}
1478 
1479 	/* Try a few times to place a door. */
1480 	for (i = 0; i < 20; i++) {
1481 		/* Pick a square along the edge, not a corner. */
1482 		if (one_in_(2)) {
1483 			/* Somewhere along the (interior) side walls. */
1484 			x = one_in_(2) ? x1 : x2;
1485 			y = y1 + randint0(1 + ABS(y2 - y1));
1486 		} else {
1487 			/* Somewhere along the (interior) top and bottom walls. */
1488 			y = one_in_(2) ? y1 : y2;
1489 			x = x1 + randint0(1 + ABS(x2 - x1));
1490 		}
1491 
1492 		/* If not an inner wall square, try again. */
1493 		if (!square_iswall_inner(c, loc(x, y)))
1494 			continue;
1495 
1496 		/* Paranoia */
1497 		if (!square_in_bounds_fully(c, loc(x, y)))
1498 			continue;
1499 
1500 		/* Reset wall count */
1501 		count = 0;
1502 
1503 		/* If square has not more than two adjacent walls, and no adjacent
1504 		 * doors, place door. */
1505 		for (d = 0; d < 9; d++) {
1506 			/* Extract adjacent (legal) location */
1507 			int yy = y + ddy_ddd[d];
1508 			int xx = x + ddx_ddd[d];
1509 
1510 			/* No doors beside doors. */
1511 			if (square(c, loc(xx, yy))->feat == FEAT_OPEN)
1512 				break;
1513 
1514 			/* Count the inner walls. */
1515 			if (square_iswall_inner(c, loc(xx, yy)))
1516 				count++;
1517 
1518 			/* No more than two walls adjacent (plus the one we're on). */
1519 			if (count > 3)
1520 				break;
1521 
1522 			/* Checked every direction? */
1523 			if (d == 8) {
1524 				/* Place an open door. */
1525 				square_set_feat(c, loc(x, y), FEAT_OPEN);
1526 
1527 				/* Success. */
1528 				return;
1529 			}
1530 		}
1531 	}
1532 }
1533 
1534 /**
1535  * Expand in every direction from a start point, turning magma into rooms.
1536  * Stop only when the magma and the open doors totally run out.
1537  * \param c the chunk the room is being built in
1538  * \param y co-ordinates to start hollowing
1539  * \param x co-ordinates to start hollowing
1540  */
hollow_out_room(struct chunk * c,struct loc grid)1541 static void hollow_out_room(struct chunk *c, struct loc grid)
1542 {
1543 	int d;
1544 
1545 	for (d = 0; d < 9; d++) {
1546 		/* Extract adjacent location */
1547 		struct loc grid1 = loc_sum(grid, ddgrid_ddd[d]);
1548 
1549 		/* Change magma to floor. */
1550 		if (square(c, grid1)->feat == FEAT_MAGMA) {
1551 			square_set_feat(c, grid1, FEAT_FLOOR);
1552 
1553 			/* Hollow out the room. */
1554 			hollow_out_room(c, grid1);
1555 		}
1556 		/* Change open door to broken door. */
1557 		else if (square(c, grid1)->feat == FEAT_OPEN) {
1558 			square_set_feat(c, grid1, FEAT_BROKEN);
1559 
1560 			/* Hollow out the (new) room. */
1561 			hollow_out_room(c, grid1);
1562 		}
1563 	}
1564 }
1565 
1566 
1567 
1568 /**
1569  * ------------------------------------------------------------------------
1570  * Room builders
1571  * ------------------------------------------------------------------------ */
1572 /**
1573  * Build a staircase to connect with a previous staircase on the level one up
1574  * or (occasionally) one down
1575  */
build_staircase(struct chunk * c,struct loc centre,int rating)1576 bool build_staircase(struct chunk *c, struct loc centre, int rating)
1577 {
1578 	struct connector *join = dun->join;
1579 
1580 	/* Find and reserve one grid in the dungeon */
1581 	if (!find_space(&centre, 1, 1))
1582 		return false;
1583 
1584 	/* Generate new room and outer walls */
1585 	generate_room(c, centre.y - 1, centre.x - 1, centre.y + 1, centre.x + 1,
1586 				  false);
1587 	draw_rectangle(c, centre.y - 1, centre.x - 1, centre.y + 1, centre.x + 1,
1588 				   FEAT_GRANITE, SQUARE_WALL_OUTER);
1589 
1590 	/* Place the correct stair */
1591 	while (join) {
1592 		if (loc_eq(join->grid, centre)) {
1593 			square_set_feat(c, join->grid, join->feat);
1594 			break;
1595 		}
1596 		join = join->next;
1597 	}
1598 	if (!join) {
1599 		quit_fmt("Stair connect mismatch y=%d x=%d!", centre.y, centre.x);
1600 	}
1601 
1602 	/* Success */
1603 	return true;
1604 }
1605 
1606 /**
1607  * Build a circular room (interior radius 4-7).
1608  * \param c the chunk the room is being built in
1609  *\ param centre the room centre; out of chunk centre invokes find_space()
1610  * \return success
1611  */
build_circular(struct chunk * c,struct loc centre,int rating)1612 bool build_circular(struct chunk *c, struct loc centre, int rating)
1613 {
1614 	/* Pick a room size */
1615 	int radius = 2 + randint1(2) + randint1(3);
1616 
1617 	/* Occasional light */
1618 	bool light = c->depth <= randint1(25) ? true : false;
1619 
1620 	/* Find and reserve lots of space in the dungeon.  Get center of room. */
1621 	if ((centre.y >= c->height) || (centre.x >= c->width)) {
1622 		if (!find_space(&centre, 2 * radius + 10, 2 * radius + 10))
1623 			return (false);
1624 	}
1625 
1626 	/* Generate outer walls and inner floors */
1627 	fill_circle(c, centre.y, centre.x, radius + 1, 1, FEAT_GRANITE,
1628 				SQUARE_WALL_OUTER, light);
1629 	fill_circle(c, centre.y, centre.x, radius, 0, FEAT_FLOOR,
1630 				SQUARE_NONE, light);
1631 
1632 	/* Especially large circular rooms will have a middle chamber */
1633 	if (radius - 4 > 0 && randint0(4) < radius - 4) {
1634 		/* choose a random direction */
1635 		struct loc offset;
1636 		rand_dir(&offset);
1637 
1638 		/* draw a room with a closed door on a random side */
1639 		draw_rectangle(c, centre.y - 2, centre.x - 2, centre.y + 2,
1640 					   centre.x + 2, FEAT_GRANITE, SQUARE_WALL_INNER);
1641 		place_closed_door(c, loc(centre.x + offset.x * 2,
1642 								 centre.y + offset.y * 2));
1643 
1644 		/* Place a treasure in the vault */
1645 		vault_objects(c, centre, c->depth, randint0(2));
1646 
1647 		/* create some monsterss */
1648 		vault_monsters(c, centre, c->depth + 1, randint0(3));
1649 	}
1650 
1651 	return true;
1652 }
1653 
1654 
1655 /**
1656  * Builds a normal rectangular room.
1657  * \param c the chunk the room is being built in
1658  *\ param centre the room centre; out of chunk centre invokes find_space()
1659  * \return success
1660  */
build_simple(struct chunk * c,struct loc centre,int rating)1661 bool build_simple(struct chunk *c, struct loc centre, int rating)
1662 {
1663 	int y, x, y1, x1, y2, x2;
1664 	int light = false;
1665 
1666 	/* Pick a room size */
1667 	int height = 1 + randint1(4) + randint1(3);
1668 	int width = 1 + randint1(11) + randint1(11);
1669 
1670 	/* Find and reserve some space in the dungeon.  Get center of room. */
1671 	if ((centre.y >= c->height) || (centre.x >= c->width)) {
1672 		if (!find_space(&centre, height + 2, width + 2))
1673 			return (false);
1674 	}
1675 
1676 	/* Pick a room size */
1677 	y1 = centre.y - height / 2;
1678 	x1 = centre.x - width / 2;
1679 	y2 = y1 + height - 1;
1680 	x2 = x1 + width - 1;
1681 
1682 	/* Occasional light */
1683 	if (c->depth <= randint1(25)) light = true;
1684 
1685 	/* Generate new room */
1686 	generate_room(c, y1-1, x1-1, y2+1, x2+1, light);
1687 
1688 	/* Generate outer walls and inner floors */
1689 	draw_rectangle(c, y1-1, x1-1, y2+1, x2+1, FEAT_GRANITE, SQUARE_WALL_OUTER);
1690 	fill_rectangle(c, y1, x1, y2, x2, FEAT_FLOOR, SQUARE_NONE);
1691 
1692 	if (one_in_(20)) {
1693 		/* Sometimes make a pillar room */
1694 		for (y = y1; y <= y2; y += 2)
1695 			for (x = x1; x <= x2; x += 2)
1696 				set_marked_granite(c, loc(x, y), SQUARE_WALL_INNER);
1697 
1698 	} else if (one_in_(50)) {
1699 		/* Sometimes make a ragged-edge room */
1700 		for (y = y1 + 2; y <= y2 - 2; y += 2) {
1701 			set_marked_granite(c, loc(x1, y), SQUARE_WALL_INNER);
1702 			set_marked_granite(c, loc(x2, y), SQUARE_WALL_INNER);
1703 		}
1704 
1705 		for (x = x1 + 2; x <= x2 - 2; x += 2) {
1706 			set_marked_granite(c, loc(x, y1), SQUARE_WALL_INNER);
1707 			set_marked_granite(c, loc(x, y2), SQUARE_WALL_INNER);
1708 		}
1709 	}
1710 	return true;
1711 }
1712 
1713 
1714 /**
1715  * Builds an overlapping rectangular room.
1716  * \param c the chunk the room is being built in
1717  *\ param centre the room centre; out of chunk centre invokes find_space()
1718  * \return success
1719  */
build_overlap(struct chunk * c,struct loc centre,int rating)1720 bool build_overlap(struct chunk *c, struct loc centre, int rating)
1721 {
1722 	int y1a, x1a, y2a, x2a;
1723 	int y1b, x1b, y2b, x2b;
1724 	int height, width;
1725 
1726 	int light = false;
1727 
1728 	/* Occasional light */
1729 	if (c->depth <= randint1(25)) light = true;
1730 
1731 	/* Determine extents of room (a) */
1732 	y1a = randint1(4);
1733 	x1a = randint1(11);
1734 	y2a = randint1(3);
1735 	x2a = randint1(10);
1736 
1737 	/* Determine extents of room (b) */
1738 	y1b = randint1(3);
1739 	x1b = randint1(10);
1740 	y2b = randint1(4);
1741 	x2b = randint1(11);
1742 
1743 	/* Calculate height and width */
1744 	height = 2 * MAX(MAX(y1a, y2a), MAX(y1b, y2b)) + 1;
1745 	width = 2 * MAX(MAX(x1a, x2a), MAX(x1b, x2b)) + 1;
1746 
1747 	/* Find and reserve some space in the dungeon.  Get center of room. */
1748 	if ((centre.y >= c->height) || (centre.x >= c->width)) {
1749 		if (!find_space(&centre, height + 2, width + 2))
1750 			return (false);
1751 	}
1752 
1753 	/* locate room (a) */
1754 	y1a = centre.y - y1a;
1755 	x1a = centre.x - x1a;
1756 	y2a = centre.y + y2a;
1757 	x2a = centre.x + x2a;
1758 
1759 	/* locate room (b) */
1760 	y1b = centre.y - y1b;
1761 	x1b = centre.x - x1b;
1762 	y2b = centre.y + y2b;
1763 	x2b = centre.x + x2b;
1764 
1765 	/* Generate new room (a) */
1766 	generate_room(c, y1a-1, x1a-1, y2a+1, x2a+1, light);
1767 
1768 	/* Generate new room (b) */
1769 	generate_room(c, y1b-1, x1b-1, y2b+1, x2b+1, light);
1770 
1771 	/* Generate outer walls (a) */
1772 	draw_rectangle(c, y1a-1, x1a-1, y2a+1, x2a+1,
1773 				   FEAT_GRANITE, SQUARE_WALL_OUTER);
1774 
1775 	/* Generate outer walls (b) */
1776 	draw_rectangle(c, y1b-1, x1b-1, y2b+1, x2b+1,
1777 				   FEAT_GRANITE, SQUARE_WALL_OUTER);
1778 
1779 	/* Generate inner floors (a) */
1780 	fill_rectangle(c, y1a, x1a, y2a, x2a, FEAT_FLOOR, SQUARE_NONE);
1781 
1782 	/* Generate inner floors (b) */
1783 	fill_rectangle(c, y1b, x1b, y2b, x2b, FEAT_FLOOR, SQUARE_NONE);
1784 
1785 	return true;
1786 }
1787 
1788 
1789 /**
1790  * Builds a cross-shaped room.
1791  * \param c the chunk the room is being built in
1792  *\ param centre the room centre; out of chunk centre invokes find_space()
1793  * \return success
1794  *
1795  * Room "a" runs north/south, and Room "b" runs east/east
1796  * So a "central pillar" would run from x1a,y1b to x2a,y2b.
1797  *
1798  * Note that currently, the "center" is always 3x3, but I think that the code
1799  * below will work for 5x5 (and perhaps even for unsymetric values like 4x3 or
1800  * 5x3 or 3x4 or 3x5).
1801  */
build_crossed(struct chunk * c,struct loc centre,int rating)1802 bool build_crossed(struct chunk *c, struct loc centre, int rating)
1803 {
1804 	int y, x;
1805 	int height, width;
1806 
1807 	int y1a, x1a, y2a, x2a;
1808 	int y1b, x1b, y2b, x2b;
1809 
1810 	int dy, dx, wy, wx;
1811 
1812 	int light = false;
1813 
1814 	/* Occasional light */
1815 	if (c->depth <= randint1(25)) light = true;
1816 
1817 	/* Pick inner dimension */
1818 	wy = 1;
1819 	wx = 1;
1820 
1821 	/* Pick outer dimension */
1822 	dy = rand_range(3, 4);
1823 	dx = rand_range(3, 11);
1824 
1825 	/* Determine extents of room (a) */
1826 	y1a = dy;
1827 	x1a = wx;
1828 	y2a = dy;
1829 	x2a = wx;
1830 
1831 	/* Determine extents of room (b) */
1832 	y1b = wy;
1833 	x1b = dx;
1834 	y2b = wy;
1835 	x2b = dx;
1836 
1837 	/* Calculate height and width */
1838 	height = MAX(y1a + y2a + 1, y1b + y2b + 1);
1839 	width = MAX(x1a + x2a + 1, x1b + x2b + 1);
1840 
1841 	/* Find and reserve some space in the dungeon.  Get center of room. */
1842 	if ((centre.y >= c->height) || (centre.x >= c->width)) {
1843 		if (!find_space(&centre, height + 2, width + 2))
1844 			return (false);
1845 	}
1846 
1847 	/* locate room (b) */
1848 	y1a = centre.y - dy;
1849 	x1a = centre.x - wx;
1850 	y2a = centre.y + dy;
1851 	x2a = centre.x + wx;
1852 
1853 	/* locate room (b) */
1854 	y1b = centre.y - wy;
1855 	x1b = centre.x - dx;
1856 	y2b = centre.y + wy;
1857 	x2b = centre.x + dx;
1858 
1859 	/* Generate new room (a) */
1860 	generate_room(c, y1a - 1, x1a - 1, y2a + 1, x2a + 1, light);
1861 
1862 	/* Generate new room (b) */
1863 	generate_room(c, y1b - 1, x1b - 1, y2b + 1, x2b + 1, light);
1864 
1865 	/* Generate outer walls (a) */
1866 	draw_rectangle(c, y1a - 1, x1a - 1, y2a + 1, x2a + 1,
1867 				   FEAT_GRANITE, SQUARE_WALL_OUTER);
1868 
1869 	/* Generate outer walls (b) */
1870 	draw_rectangle(c, y1b - 1, x1b - 1, y2b + 1, x2b + 1,
1871 				   FEAT_GRANITE, SQUARE_WALL_OUTER);
1872 
1873 	/* Generate inner floors (a) */
1874 	fill_rectangle(c, y1a, x1a, y2a, x2a, FEAT_FLOOR, SQUARE_NONE);
1875 
1876 	/* Generate inner floors (b) */
1877 	fill_rectangle(c, y1b, x1b, y2b, x2b, FEAT_FLOOR, SQUARE_NONE);
1878 
1879 	/* Special features */
1880 	switch (randint1(4)) {
1881 		/* Nothing */
1882 	case 1: break;
1883 
1884 		/* Large solid middle pillar */
1885 	case 2: {
1886 		fill_rectangle(c, y1b, x1a, y2b, x2a, FEAT_GRANITE, SQUARE_WALL_INNER);
1887 		break;
1888 	}
1889 
1890 		/* Inner treasure vault */
1891 	case 3: {
1892 		/* Generate a small inner vault */
1893 		draw_rectangle(c, y1b, x1a, y2b, x2a, FEAT_GRANITE, SQUARE_WALL_INNER);
1894 
1895 		/* Open the inner vault with a secret door */
1896 		generate_hole(c, y1b, x1a, y2b, x2a, FEAT_SECRET);
1897 
1898 		/* Place a treasure in the vault */
1899 		place_object(c, centre, c->depth, false, false, ORIGIN_SPECIAL, 0);
1900 
1901 		/* Let's guard the treasure well */
1902 		vault_monsters(c, centre, c->depth + 2, randint0(2) + 3);
1903 
1904 		/* Traps naturally */
1905 		vault_traps(c, centre, 4, 4, randint0(3) + 2);
1906 
1907 		break;
1908 	}
1909 
1910 		/* Something else */
1911 	case 4: {
1912 		if (one_in_(3)) {
1913 			/* Occasionally pinch the center shut */
1914 
1915 			/* Pinch the east/west sides */
1916 			for (y = y1b; y <= y2b; y++) {
1917 				if (y == centre.y) continue;
1918 				set_marked_granite(c, loc(x1a - 1, y), SQUARE_WALL_INNER);
1919 				set_marked_granite(c, loc(x2a + 1, y), SQUARE_WALL_INNER);
1920 			}
1921 
1922 			/* Pinch the north/south sides */
1923 			for (x = x1a; x <= x2a; x++) {
1924 				if (x == centre.x) continue;
1925 				set_marked_granite(c, loc(x, y1b - 1), SQUARE_WALL_INNER);
1926 				set_marked_granite(c, loc(x, y2b + 1), SQUARE_WALL_INNER);
1927 			}
1928 
1929 			/* Open sides with doors */
1930 			if (one_in_(3))
1931 				generate_open(c, y1b - 1, x1a - 1, y2b + 1, x2a + 1,
1932 							  FEAT_CLOSED);
1933 
1934 		} else if (one_in_(3)) {
1935 			/* Occasionally put a "plus" in the center */
1936 			generate_plus(c, y1b, x1a, y2b, x2a,
1937 						  FEAT_GRANITE, SQUARE_WALL_INNER);
1938 
1939 		} else if (one_in_(3)) {
1940 			/* Occasionally put a "pillar" in the center */
1941 			set_marked_granite(c, centre, SQUARE_WALL_INNER);
1942 		}
1943 
1944 		break;
1945 	}
1946 	}
1947 
1948 	return true;
1949 }
1950 
1951 
1952 /**
1953  * Build a large room with an inner room.
1954  * \param c the chunk the room is being built in
1955  *\ param centre the room centre; out of chunk centre invokes find_space()
1956  * \return success
1957  *
1958  * Possible sub-types:
1959  *	1 - An inner room
1960  *	2 - An inner room with a small inner room
1961  *	3 - An inner room with a pillar or pillars
1962  *	4 - An inner room with a checkerboard
1963  *	5 - An inner room with four compartments
1964  */
build_large(struct chunk * c,struct loc centre,int rating)1965 bool build_large(struct chunk *c, struct loc centre, int rating)
1966 {
1967 	int y, x, y1, x1, y2, x2;
1968 	int height = 9;
1969 	int width = 23;
1970 
1971 	int light = false;
1972 
1973 	/* Occasional light */
1974 	if (c->depth <= randint1(25)) light = true;
1975 
1976 	/* Find and reserve some space in the dungeon.  Get center of room. */
1977 	if ((centre.y >= c->height) || (centre.x >= c->width)) {
1978 		if (!find_space(&centre, height + 2, width + 2))
1979 			return (false);
1980 	}
1981 
1982 	/* Large room */
1983 	y1 = centre.y - height / 2;
1984 	y2 = centre.y + height / 2;
1985 	x1 = centre.x - width / 2;
1986 	x2 = centre.x + width / 2;
1987 
1988 	/* Generate new room */
1989 	generate_room(c, y1 - 1, x1 - 1, y2 + 1, x2 + 1, light);
1990 
1991 	/* Generate outer walls */
1992 	draw_rectangle(c, y1 - 1, x1 - 1, y2 + 1, x2 + 1, FEAT_GRANITE,
1993 				   SQUARE_WALL_OUTER);
1994 
1995 	/* Generate inner floors */
1996 	fill_rectangle(c, y1, x1, y2, x2, FEAT_FLOOR, SQUARE_NONE);
1997 
1998 	/* The inner room */
1999 	y1 = y1 + 2;
2000 	y2 = y2 - 2;
2001 	x1 = x1 + 2;
2002 	x2 = x2 - 2;
2003 
2004 	/* Generate inner walls */
2005 	draw_rectangle(c, y1 - 1, x1 - 1, y2 + 1, x2 + 1, FEAT_GRANITE,
2006 				   SQUARE_WALL_INNER);
2007 
2008 	/* Inner room variations */
2009 	switch (randint1(5)) {
2010 		/* An inner room */
2011 	case 1: {
2012 		/* Open the inner room with a door and place a monster */
2013 		generate_hole(c, y1 - 1, x1 - 1, y2 + 1, x2 + 1, FEAT_CLOSED);
2014 		vault_monsters(c, centre, c->depth + 2, 1);
2015 		break;
2016 	}
2017 
2018 
2019 		/* An inner room with a small inner room */
2020 	case 2: {
2021 		/* Open the inner room with a door */
2022 		generate_hole(c, y1 - 1, x1 - 1, y2 + 1, x2 + 1, FEAT_CLOSED);
2023 
2024 		/* Place another inner room */
2025 		draw_rectangle(c, centre.y - 1, centre.x - 1, centre.y + 1,
2026 					   centre.x + 1, FEAT_GRANITE, SQUARE_WALL_INNER);
2027 
2028 		/* Open the inner room with a locked door */
2029 		generate_hole(c, centre.y - 1, centre.x - 1, centre.y + 1, centre.x + 1,
2030 					  FEAT_CLOSED);
2031 		for (y = centre.y - 1; y <= centre.y + 1; y++) {
2032 			for (x = centre.x - 1; x <= centre.x + 1; x++) {
2033 				struct loc grid = loc(x, y);
2034 				if (square_iscloseddoor(c, grid)) {
2035 					square_set_door_lock(c, grid, randint1(7));
2036 				}
2037 			}
2038 		}
2039 
2040 		/* Monsters to guard the treasure */
2041 		vault_monsters(c, centre, c->depth + 2, randint1(3) + 2);
2042 
2043 		/* Object (80%) or Stairs (20%) */
2044 		if ((randint0(100) < 80) || OPT(player, birth_levels_persist))
2045 			place_object(c, centre, c->depth, false, false, ORIGIN_SPECIAL, 0);
2046 		else
2047 			place_random_stairs(c, centre);
2048 
2049 		/* Traps to protect the treasure */
2050 		vault_traps(c, centre, 4, 10, 2 + randint1(3));
2051 
2052 		break;
2053 	}
2054 
2055 
2056 		/* An inner room with an inner pillar or pillars */
2057 	case 3: {
2058 		/* Open the inner room with a secret door */
2059 		generate_hole(c, y1 - 1, x1 - 1, y2 + 1, x2 + 1, FEAT_CLOSED);
2060 
2061 		/* Inner pillar */
2062 		fill_rectangle(c, centre.y - 1, centre.x - 1, centre.y + 1,
2063 					   centre.x + 1, FEAT_GRANITE, SQUARE_WALL_INNER);
2064 
2065 		/* Occasionally, two more Large Inner Pillars */
2066 		if (one_in_(2)) {
2067 			if (one_in_(2)) {
2068 				fill_rectangle(c, centre.y - 1, centre.x - 7, centre.y + 1,
2069 							   centre.x - 5, FEAT_GRANITE, SQUARE_WALL_INNER);
2070 				fill_rectangle(c, centre.y - 1, centre.x + 5, centre.y + 1,
2071 							   centre.x + 7, FEAT_GRANITE, SQUARE_WALL_INNER);
2072 			} else {
2073 				fill_rectangle(c, centre.y - 1, centre.x - 6, centre.y + 1,
2074 							   centre.x - 4, FEAT_GRANITE, SQUARE_WALL_INNER);
2075 				fill_rectangle(c, centre.y - 1, centre.x + 4, centre.y + 1,
2076 							   centre.x + 6, FEAT_GRANITE, SQUARE_WALL_INNER);
2077 			}
2078 		}
2079 
2080 		/* Occasionally, some Inner rooms */
2081 		if (one_in_(3)) {
2082 			/* Inner rectangle */
2083 			draw_rectangle(c, centre.y - 1, centre.x - 5, centre.y + 1,
2084 						   centre.x + 5, FEAT_GRANITE, SQUARE_WALL_INNER);
2085 
2086 			/* Secret doors (random top/bottom) */
2087 			place_secret_door(c, loc(centre.x - 3,
2088 									 centre.y - 3 + (randint1(2) * 2)));
2089 			place_secret_door(c, loc(centre.x + 3,
2090 									 centre.y - 3 + (randint1(2) * 2)));
2091 
2092 			/* Monsters */
2093 			vault_monsters(c, loc(centre.x - 2, centre.y), c->depth + 2,
2094 						   randint1(2));
2095 			vault_monsters(c, loc(centre.x + 2, centre.y), c->depth + 2,
2096 						   randint1(2));
2097 
2098 			/* Objects */
2099 			if (one_in_(3))
2100 				place_object(c, loc(centre.x - 2, centre.y), c->depth, false,
2101 							 false, ORIGIN_SPECIAL, 0);
2102 			if (one_in_(3))
2103 				place_object(c, loc(centre.x + 2, centre.y), c->depth, false,
2104 							 false, ORIGIN_SPECIAL, 0);
2105 		}
2106 
2107 		break;
2108 	}
2109 
2110 
2111 		/* An inner room with a checkerboard */
2112 	case 4: {
2113 		/* Open the inner room with a secret door */
2114 		generate_hole(c, y1 - 1, x1 - 1, y2 + 1, x2 + 1, FEAT_CLOSED);
2115 
2116 		/* Checkerboard */
2117 		for (y = y1; y <= y2; y++)
2118 			for (x = x1; x <= x2; x++)
2119 				if ((x + y) & 0x01)
2120 					set_marked_granite(c, loc(x, y), SQUARE_WALL_INNER);
2121 
2122 		/* Monsters just love mazes. */
2123 		vault_monsters(c, loc(centre.x - 5, centre.y), c->depth + 2,
2124 					   randint1(3));
2125 		vault_monsters(c, loc(centre.x + 5, centre.y), c->depth + 2,
2126 					   randint1(3));
2127 
2128 		/* Traps make them entertaining. */
2129 		vault_traps(c, loc(centre.x - 3, centre.y), 2, 8, randint1(3));
2130 		vault_traps(c, loc(centre.x + 3, centre.y), 2, 8, randint1(3));
2131 
2132 		/* Mazes should have some treasure too. */
2133 		vault_objects(c, centre, c->depth, 3);
2134 
2135 		break;
2136 	}
2137 
2138 
2139 		/* Four small rooms. */
2140 	case 5: {
2141 		/* Inner "cross" */
2142 		generate_plus(c, y1, x1, y2, x2, FEAT_GRANITE, SQUARE_WALL_INNER);
2143 
2144 		/* Doors into the rooms */
2145 		if (randint0(100) < 50) {
2146 			int i = randint1(10);
2147 			place_closed_door(c, loc(centre.x - i, y1 - 1));
2148 			place_closed_door(c, loc(centre.x + i, y1 - 1));
2149 			place_closed_door(c, loc(centre.x - i, y2 + 1));
2150 			place_closed_door(c, loc(centre.x + i, y2 + 1));
2151 		} else {
2152 			int i = randint1(3);
2153 			place_closed_door(c, loc(x1 - 1, centre.y + i));
2154 			place_closed_door(c, loc(x1 - 1, centre.y - i));
2155 			place_closed_door(c, loc(x2 + 1, centre.y + i));
2156 			place_closed_door(c, loc(x2 + 1, centre.y - i));
2157 		}
2158 
2159 		/* Treasure, centered at the center of the cross */
2160 		vault_objects(c, centre, c->depth, 2 + randint1(2));
2161 
2162 		/* Gotta have some monsters */
2163 		vault_monsters(c, loc(centre.x - 4, centre.y + 1), c->depth + 2,
2164 					   randint1(4));
2165 		vault_monsters(c, loc(centre.x + 4, centre.y + 1), c->depth + 2,
2166 					   randint1(4));
2167 		vault_monsters(c, loc(centre.x - 4, centre.y - 1), c->depth + 2,
2168 					   randint1(4));
2169 		vault_monsters(c, loc(centre.x + 4, centre.y - 1), c->depth + 2,
2170 					   randint1(4));
2171 
2172 		break;
2173 	}
2174 	}
2175 
2176 	return true;
2177 }
2178 
2179 
2180 /**
2181  * Build a monster nest
2182  * \param c the chunk the room is being built in
2183  *\ param centre the room centre; out of chunk centre invokes find_space()
2184  * \return success
2185  *
2186  * A monster nest consists of a rectangular moat around a room containing
2187  * monsters of a given type.
2188  *
2189  * The monsters are chosen from a set of 64 randomly selected monster races,
2190  * to allow the nest creation to fail instead of having "holes".
2191  *
2192  * Note the use of the "get_mon_num_prep()" function to prepare the
2193  * "monster allocation table" in such a way as to optimize the selection
2194  * of "appropriate" non-unique monsters for the nest.
2195  *
2196  * The available monster nests are specified in edit/pit.txt.
2197  *
2198  * Note that get_mon_num() function can fail, in which case the nest will be
2199  * empty, and will not affect the level rating.
2200  *
2201  * Monster nests will never contain unique monsters.
2202  */
build_nest(struct chunk * c,struct loc centre,int rating)2203 bool build_nest(struct chunk *c, struct loc centre, int rating)
2204 {
2205 	struct loc grid;
2206 	int y1, x1, y2, x2;
2207 	int i;
2208 	int alloc_obj;
2209 	struct monster_race *what[64];
2210 	bool empty = false;
2211 	int light = false;
2212 	int size_vary = randint0(4);
2213 	int height = 9;
2214 	int width = 11 + 2 * size_vary;
2215 	struct monster_group_info info = {0, 0};
2216 
2217 	/* Find and reserve some space in the dungeon.  Get center of room. */
2218 	if ((centre.y >= c->height) || (centre.x >= c->width)) {
2219 		if (!find_space(&centre, height + 2, width + 2))
2220 			return (false);
2221 	}
2222 
2223 	/* Large room */
2224 	y1 = centre.y - height / 2;
2225 	y2 = centre.y + height / 2;
2226 	x1 = centre.x - width / 2;
2227 	x2 = centre.x + width / 2;
2228 
2229 	/* Generate new room */
2230 	generate_room(c, y1 - 1, x1 - 1, y2 + 1, x2 + 1, light);
2231 
2232 	/* Generate outer walls */
2233 	draw_rectangle(c, y1 - 1, x1 - 1, y2 + 1, x2 + 1, FEAT_GRANITE,
2234 				   SQUARE_WALL_OUTER);
2235 
2236 	/* Generate inner floors */
2237 	fill_rectangle(c, y1, x1, y2, x2, FEAT_FLOOR, SQUARE_NONE);
2238 
2239 	/* Advance to the center room */
2240 	y1 = y1 + 2;
2241 	y2 = y2 - 2;
2242 	x1 = x1 + 2;
2243 	x2 = x2 - 2;
2244 
2245 	/* Generate inner walls */
2246 	draw_rectangle(c, y1 - 1, x1 - 1, y2 + 1, x2 + 1, FEAT_GRANITE,
2247 				   SQUARE_WALL_INNER);
2248 
2249 	/* Open the inner room with a secret door */
2250 	generate_hole(c, y1 - 1, x1 - 1, y2 + 1, x2 + 1, FEAT_CLOSED);
2251 
2252 	/* Decide on the pit type */
2253 	set_pit_type(c->depth, 2);
2254 
2255 	/* Chance of objects on the floor */
2256 	alloc_obj = dun->pit_type->obj_rarity;
2257 
2258 	/* Prepare allocation table */
2259 	get_mon_num_prep(mon_pit_hook);
2260 
2261 	/* Pick some monster types */
2262 	for (i = 0; i < 64; i++) {
2263 		/* Get a (hard) monster type */
2264 		what[i] = get_mon_num(c->depth + 10);
2265 
2266 		/* Notice failure */
2267 		if (!what[i]) empty = true;
2268 	}
2269 
2270 	/* Prepare allocation table */
2271 	get_mon_num_prep(NULL);
2272 
2273 	/* Oops */
2274 	if (empty) return false;
2275 
2276 	/* Describe */
2277 	ROOM_LOG("Monster nest (%s)", dun->pit_type->name);
2278 
2279 	/* Increase the level rating */
2280 	c->mon_rating += (size_vary + dun->pit_type->ave / 20);
2281 
2282 	/* Place some monsters */
2283 	for (grid.y = y1; grid.y <= y2; grid.y++) {
2284 		for (grid.x = x1; grid.x <= x2; grid.x++) {
2285 			/* Figure out what monster is being used, and place that monster */
2286 			struct monster_race *race = what[randint0(64)];
2287 			place_new_monster(c, grid, race, false, false, info,
2288 							  ORIGIN_DROP_PIT);
2289 
2290 			/* Occasionally place an item, making it good 1/3 of the time */
2291 			if (randint0(100) < alloc_obj)
2292 				place_object(c, grid, c->depth + 10, one_in_(3), false,
2293 							 ORIGIN_PIT, 0);
2294 		}
2295 	}
2296 
2297 	return true;
2298 }
2299 
2300 /**
2301  * Build a monster pit
2302  * \param c the chunk the room is being built in
2303  *\ param centre the room centre; out of chunk centre invokes find_space()
2304  * \return success
2305  *
2306  * Monster pits are laid-out similarly to monster nests.
2307  *
2308  * The available monster pits are specified in edit/pit.txt.
2309  *
2310  * The inside room in a monster pit appears as shown below, where the
2311  * actual monsters in each location depend on the type of the pit
2312  *
2313  *   #############
2314  *   #11000000011#
2315  *   #01234543210#
2316  *   #01236763210#
2317  *   #01234543210#
2318  *   #11000000011#
2319  *   #############
2320  *
2321  * Note that the monsters in the pit are chosen by using get_mon_num() to
2322  * request 16 "appropriate" monsters, sorting them by level, and using the
2323  * "even" entries in this sorted list for the contents of the pit.
2324  *
2325  * Note the use of get_mon_num_prep() to prepare the monster allocation
2326  * table in such a way as to optimize the selection of appropriate non-unique
2327  * monsters for the pit.
2328  *
2329  * The get_mon_num() function can fail, in which case the pit will be empty,
2330  * and will not effect the level rating.
2331  *
2332  * Like monster nests, monster pits will never contain unique monsters.
2333  */
build_pit(struct chunk * c,struct loc centre,int rating)2334 bool build_pit(struct chunk *c, struct loc centre, int rating)
2335 {
2336 	struct monster_race *what[16];
2337 	int i, j, y, x, y1, x1, y2, x2;
2338 	bool empty = false;
2339 	int light = false;
2340 	int alloc_obj;
2341 	int height = 9;
2342 	int width = 15;
2343 	int group_index = 0;
2344 	struct monster_group_info info = {0, 0};
2345 
2346 	/* Find and reserve some space in the dungeon.  Get center of room. */
2347 	if ((centre.y >= c->height) || (centre.x >= c->width)) {
2348 		if (!find_space(&centre, height + 2, width + 2))
2349 			return (false);
2350 	}
2351 
2352 	/* Large room */
2353 	y1 = centre.y - height / 2;
2354 	y2 = centre.y + height / 2;
2355 	x1 = centre.x - width / 2;
2356 	x2 = centre.x + width / 2;
2357 
2358 	/* Generate new room, outer walls and inner floor */
2359 	generate_room(c, y1 - 1, x1 - 1, y2 + 1, x2 + 1, light);
2360 	draw_rectangle(c, y1 - 1, x1 - 1, y2 + 1, x2 + 1, FEAT_GRANITE,
2361 				   SQUARE_WALL_OUTER);
2362 	fill_rectangle(c, y1, x1, y2, x2, FEAT_FLOOR, SQUARE_NONE);
2363 
2364 	/* Advance to the center room */
2365 	y1 = y1 + 2;
2366 	y2 = y2 - 2;
2367 	x1 = x1 + 2;
2368 	x2 = x2 - 2;
2369 
2370 	/* Generate inner walls, and open with a secret door */
2371 	draw_rectangle(c, y1 - 1, x1 - 1, y2 + 1, x2 + 1, FEAT_GRANITE,
2372 				   SQUARE_WALL_INNER);
2373 	generate_hole(c, y1 - 1, x1 - 1, y2 + 1, x2 + 1, FEAT_CLOSED);
2374 
2375 	/* Decide on the pit type */
2376 	set_pit_type(c->depth, 1);
2377 
2378 	/* Chance of objects on the floor */
2379 	alloc_obj = dun->pit_type->obj_rarity;
2380 
2381 	/* Prepare allocation table */
2382 	get_mon_num_prep(mon_pit_hook);
2383 
2384 	/* Pick some monster types */
2385 	for (i = 0; i < 16; i++) {
2386 		/* Get a (hard) monster type */
2387 		what[i] = get_mon_num(c->depth + 10);
2388 
2389 		/* Notice failure */
2390 		if (!what[i]) empty = true;
2391 	}
2392 
2393 	/* Prepare allocation table */
2394 	get_mon_num_prep(NULL);
2395 
2396 	/* Oops */
2397 	if (empty)
2398 		return false;
2399 
2400 	ROOM_LOG("Monster pit (%s)", dun->pit_type->name);
2401 
2402 	/* Sort the entries XXX XXX XXX */
2403 	for (i = 0; i < 16 - 1; i++) {
2404 		/* Sort the entries */
2405 		for (j = 0; j < 16 - 1; j++) {
2406 			int i1 = j;
2407 			int i2 = j + 1;
2408 
2409 			int p1 = what[i1]->level;
2410 			int p2 = what[i2]->level;
2411 
2412 			/* Bubble */
2413 			if (p1 > p2) {
2414 				struct monster_race *tmp = what[i1];
2415 				what[i1] = what[i2];
2416 				what[i2] = tmp;
2417 			}
2418 		}
2419 	}
2420 
2421 	/* Select every other entry */
2422 	for (i = 0; i < 8; i++)
2423 		what[i] = what[i * 2];
2424 
2425 	/* Increase the level rating */
2426 	c->mon_rating += (3 + dun->pit_type->ave / 20);
2427 
2428 	/* Get a group ID */
2429 	group_index = monster_group_index_new(c);
2430 
2431 	/* Center monster */
2432 	info.index = group_index;
2433 	info.role = MON_GROUP_LEADER;
2434 	place_new_monster(c, centre, what[7], false, false, info, ORIGIN_DROP_PIT);
2435 
2436 	/* Remaining monsters are servants */
2437 	info.role = MON_GROUP_SERVANT;
2438 
2439 	/* Top and bottom rows (middle) */
2440 	for (x = centre.x - 3; x <= centre.x + 3; x++) {
2441 		place_new_monster(c, loc(x, centre.y - 2), what[0], false, false, info,
2442 						  ORIGIN_DROP_PIT);
2443 		place_new_monster(c, loc(x, centre.y + 2), what[0], false, false, info,
2444 						  ORIGIN_DROP_PIT);
2445 	}
2446 
2447 	/* Corners */
2448 	for (x = centre.x - 5; x <= centre.x - 4; x++) {
2449 		place_new_monster(c, loc(x, centre.y - 2), what[1], false, false, info,
2450 						  ORIGIN_DROP_PIT);
2451 		place_new_monster(c, loc(x, centre.y + 2), what[1], false, false, info,
2452 						  ORIGIN_DROP_PIT);
2453 	}
2454 
2455 	for (x = centre.x + 4; x <= centre.x + 5; x++) {
2456 		place_new_monster(c, loc(x, centre.y - 2), what[1], false, false, info,
2457 						  ORIGIN_DROP_PIT);
2458 		place_new_monster(c, loc(x, centre.y + 2), what[1], false, false, info,
2459 						  ORIGIN_DROP_PIT);
2460 	}
2461 
2462 	/* Corners */
2463 
2464 	/* Middle columns */
2465 	for (y = centre.y - 1; y <= centre.y + 1; y++) {
2466 		place_new_monster(c, loc(centre.x - 5, y), what[0], false, false, info,
2467 						  ORIGIN_DROP_PIT);
2468 		place_new_monster(c, loc(centre.x + 5, y), what[0], false, false, info,
2469 						  ORIGIN_DROP_PIT);
2470 
2471 		place_new_monster(c, loc(centre.x - 4, y), what[1], false, false, info,
2472 						  ORIGIN_DROP_PIT);
2473 		place_new_monster(c, loc(centre.x + 4, y), what[1], false, false, info,
2474 						  ORIGIN_DROP_PIT);
2475 
2476 		place_new_monster(c, loc(centre.x - 3, y), what[2], false, false, info,
2477 						  ORIGIN_DROP_PIT);
2478 		place_new_monster(c, loc(centre.x + 3, y), what[2], false, false, info,
2479 						  ORIGIN_DROP_PIT);
2480 
2481 		place_new_monster(c, loc(centre.x - 2, y), what[3], false, false, info,
2482 						  ORIGIN_DROP_PIT);
2483 		place_new_monster(c, loc(centre.x + 2, y), what[3], false, false, info,
2484 						  ORIGIN_DROP_PIT);
2485 	}
2486 
2487 	/* Corners around the middle monster */
2488 	place_new_monster(c, loc(centre.x - 1, centre.y - 1), what[4], false, false,
2489 					  info, ORIGIN_DROP_PIT);
2490 	place_new_monster(c, loc(centre.x + 1, centre.y - 1), what[4], false, false,
2491 					  info, ORIGIN_DROP_PIT);
2492 	place_new_monster(c, loc(centre.x - 1, centre.y + 1), what[4], false, false,
2493 					  info, ORIGIN_DROP_PIT);
2494 	place_new_monster(c, loc(centre.x + 1, centre.y + 1), what[4], false, false,
2495 					  info, ORIGIN_DROP_PIT);
2496 
2497 	/* Above/Below the center monster */
2498 	for (x = centre.x - 1; x <= centre.x + 1; x++) {
2499 		place_new_monster(c, loc(x, centre.y + 1), what[5], false, false, info,
2500 						  ORIGIN_DROP_PIT);
2501 		place_new_monster(c, loc(x, centre.y - 1), what[5], false, false, info,
2502 						  ORIGIN_DROP_PIT);
2503 	}
2504 
2505 	/* Next to the center monster */
2506 	place_new_monster(c, loc(centre.x + 1, centre.y), what[6], false, false,
2507 					  info, ORIGIN_DROP_PIT);
2508 	place_new_monster(c, loc(centre.x - 1, centre.y), what[6], false, false,
2509 					  info, ORIGIN_DROP_PIT);
2510 
2511 	/* Place some objects */
2512 	for (y = centre.y - 2; y <= centre.y + 2; y++) {
2513 		for (x = centre.x - 9; x <= centre.x + 9; x++) {
2514 			/* Occasionally place an item, making it good 1/3 of the time */
2515 			if (randint0(100) < alloc_obj)
2516 				place_object(c, loc(x, y), c->depth + 10, one_in_(3), false,
2517 							 ORIGIN_PIT, 0);
2518 		}
2519 	}
2520 
2521 	return true;
2522 }
2523 
2524 /**
2525  * Build a template room
2526  * \param c the chunk the room is being built in
2527  *\ param centre the room centre; out of chunk centre invokes find_space()
2528  * \return success
2529 */
build_template(struct chunk * c,struct loc centre,int rating)2530 bool build_template(struct chunk *c, struct loc centre, int rating)
2531 {
2532 	/* All room templates currently have type 1 */
2533 	return build_room_template_type(c, centre, 1, rating);
2534 }
2535 
2536 
2537 
2538 
2539 /**
2540  * Build an interesting room.
2541  * \param c the chunk the room is being built in
2542  *\ param centre the room centre; out of chunk centre invokes find_space()
2543  * \return success
2544  */
build_interesting(struct chunk * c,struct loc centre,int rating)2545 bool build_interesting(struct chunk *c, struct loc centre, int rating)
2546 {
2547 	return build_vault_type(c, centre, "Interesting room");
2548 }
2549 
2550 
2551 /**
2552  * Build a lesser vault.
2553  * \param c the chunk the room is being built in
2554  *\ param centre the room centre; out of chunk centre invokes find_space()
2555  * \return success
2556  */
build_lesser_vault(struct chunk * c,struct loc centre,int rating)2557 bool build_lesser_vault(struct chunk *c, struct loc centre, int rating)
2558 {
2559 	if (!streq(dun->profile->name, "classic") && (one_in_(2)))
2560 		return build_vault_type(c, centre, "Lesser vault (new)");
2561 	return build_vault_type(c, centre, "Lesser vault");
2562 }
2563 
2564 
2565 /**
2566  * Build a medium vault.
2567  * \param c the chunk the room is being built in
2568  *\ param centre the room centre; out of chunk centre invokes find_space()
2569  * \return success
2570  */
build_medium_vault(struct chunk * c,struct loc centre,int rating)2571 bool build_medium_vault(struct chunk *c, struct loc centre, int rating)
2572 {
2573 	if (!streq(dun->profile->name, "classic") && (one_in_(2)))
2574 		return build_vault_type(c, centre, "Medium vault (new)");
2575 	return build_vault_type(c, centre, "Medium vault");
2576 }
2577 
2578 
2579 /**
2580  * Build a greater vaults.
2581  * \param c the chunk the room is being built in
2582  *\ param centre the room centre; out of chunk centre invokes find_space()
2583  * \return success
2584  *
2585  * Classic profile:
2586  * Since Greater Vaults are so large (4x6 blocks, in a 6x18 dungeon) there is
2587  * a 63% chance that a randomly chosen quadrant to start a GV on won't work.
2588  * To balance this, we give Greater Vaults an artificially high probability
2589  * of being attempted, and then in this function use a depth check to cancel
2590  * vault creation except at deep depths.
2591  *
2592  * Newer profiles:
2593  * We reject 2/3 of attempts which pass other checks to get roughly the same
2594  * chnce of a GV as the classic profile
2595  *
2596  * The following code should make a greater vault with frequencies:
2597  * dlvl  freq
2598  * 100+  18.0%
2599  * 90-99 16.0 - 18.0%
2600  * 80-89 10.0 - 11.0%
2601  * 70-79  5.7 -  6.5%
2602  * 60-69  3.3 -  3.8%
2603  * 50-59  1.8 -  2.1%
2604  * 0-49   0.0 -  1.0%
2605  */
build_greater_vault(struct chunk * c,struct loc centre,int rating)2606 bool build_greater_vault(struct chunk *c, struct loc centre, int rating)
2607 {
2608 	int i;
2609 	int numerator   = 1;
2610 	int denominator = 3;
2611 
2612 	/* Only try to build a GV as the first room. */
2613 	if (dun->cent_n > 0) return false;
2614 
2615 	/* Level 90+ has a 1/3 chance, level 80-89 has 2/9, ... */
2616 	for (i = 90; i > c->depth; i -= 10) {
2617 		numerator *= 2;
2618 		denominator *= 3;
2619 	}
2620 
2621 	/* Attempt to pass the depth check and build a GV */
2622 	if (randint0(denominator) >= numerator) return false;
2623 
2624 	/* Non-classic profiles need to adjust the probability */
2625 	if (!streq(dun->profile->name, "classic") && !one_in_(3)) return false;
2626 
2627 	if (!streq(dun->profile->name, "classic") && (one_in_(2))) {
2628 		return build_vault_type(c, centre, "Greater vault (new)");
2629 	}
2630 	return build_vault_type(c, centre, "Greater vault");
2631 }
2632 
2633 
2634 /**
2635  * Moria room (from Oangband).  Uses the "starburst room" code.
2636  * \param c the chunk the room is being built in
2637  *\ param centre the room centre; out of chunk centre invokes find_space()
2638  * \return success
2639  */
build_moria(struct chunk * c,struct loc centre,int rating)2640 bool build_moria(struct chunk *c, struct loc centre, int rating)
2641 {
2642 	int y1, x1, y2, x2;
2643 	int i;
2644 	int height, width;
2645 
2646 	bool light = c->depth <= randint1(35);
2647 
2648 	/* Pick a room size */
2649 	height = 8 + randint0(5);
2650 	width = 10 + randint0(5);
2651 
2652 
2653 	/* Try twice to find space for a room. */
2654 	for (i = 0; i < 2; i++) {
2655 		/* Really large room - only on first try. */
2656 		if ((i == 0) && one_in_(15)) {
2657 			height *= 1 + randint1(2);
2658 			width *= 2 + randint1(3);
2659 		}
2660 
2661 		/* Long, narrow room.  Sometimes tall and thin. */
2662 		else if (!one_in_(4)) {
2663 			if (one_in_(15))
2664 				height *= 2 + randint0(2);
2665 			else
2666 				width *= 2 + randint0(3);
2667 		}
2668 
2669 		/* Find and reserve some space in the dungeon.  Get center of room. */
2670 		if ((centre.y >= c->height) || (centre.x >= c->width)) {
2671 			if (!find_space(&centre, height, width)) {
2672 				if (i == 0) continue;  /* Failed first attempt */
2673 				if (i == 1) return (false);  /* Failed second attempt */
2674 			} else break;  /* Success */
2675 		} else break;   /* Not finding space */
2676 	}
2677 
2678 	/* Locate the room */
2679 	y1 = centre.y - height / 2;
2680 	x1 = centre.x - width / 2;
2681 	y2 = y1 + height - 1;
2682 	x2 = x1 + width - 1;
2683 
2684 
2685 	/* Generate starburst room.  Return immediately if out of bounds. */
2686 	if (!generate_starburst_room(c, y1, x1, y2, x2, light, FEAT_FLOOR, true)) {
2687 		return (false);
2688 	}
2689 
2690 	/* Sometimes, the room may have rubble in it. */
2691 	if (one_in_(10))
2692 		(void) generate_starburst_room(c, y1 + randint0(height / 4),
2693 									   x1 + randint0(width / 4),
2694 									   y2 - randint0(height / 4),
2695 									   x2 - randint0(width / 4), false,
2696 									   FEAT_PASS_RUBBLE, false);
2697 
2698 	/* Success */
2699 	return (true);
2700 }
2701 
2702 /**
2703  * Rooms of chambers
2704  * \param c the chunk the room is being built in
2705  *\ param centre the room centre; out of chunk centre invokes find_space()
2706  * \return success
2707  *
2708  * Build a room, varying in size between 22x22 and 44x66, consisting of
2709  * many smaller, irregularly placed, chambers all connected by doors or
2710  * short tunnels. -LM-
2711  *
2712  * Plop down an area-dependent number of magma-filled chambers, and remove
2713  * blind doors and tiny rooms.
2714  *
2715  * Hollow out a chamber near the center, connect it to new chambers, and
2716  * hollow them out in turn.  Continue in this fashion until there are no
2717  * remaining chambers within two squares of any cleared chamber.
2718  *
2719  * Clean up doors.  Neaten up the wall types.  Turn floor grids into rooms,
2720  * illuminate if requested.
2721  *
2722  * Fill the room with up to 35 (sometimes up to 50) monsters of a creature
2723  * race or type that offers a challenge at the character's depth.  This is
2724  * similar to monster pits, except that we choose among a wider range of
2725  * monsters.
2726  *
2727  */
build_room_of_chambers(struct chunk * c,struct loc centre,int rating)2728 bool build_room_of_chambers(struct chunk *c, struct loc centre, int rating)
2729 {
2730 	int i, d;
2731 	int area, num_chambers;
2732 	int y1, x1, y2, x2;
2733 	struct loc grid;
2734 	int height, width, count;
2735 
2736 	char name[40];
2737 
2738 	/* Deeper in the dungeon, chambers are less likely to be lit. */
2739 	bool light = (randint0(45) > c->depth) ? true : false;
2740 
2741 	/* Calculate a level-dependent room size. */
2742 	height = 20 + m_bonus(20, c->depth);
2743 	width = 20 + randint1(20) + m_bonus(20, c->depth);
2744 
2745 	/* Find and reserve some space in the dungeon.  Get center of room. */
2746 	if ((centre.y >= c->height) || (centre.x >= c->width)) {
2747 		if (!find_space(&centre, height, width))
2748 			return (false);
2749 	}
2750 
2751 	/* Calculate the borders of the room. */
2752 	y1 = centre.y - (height / 2);
2753 	x1 = centre.x - (width / 2);
2754 	y2 = centre.y + (height - 1) / 2;
2755 	x2 = centre.x + (width - 1) / 2;
2756 
2757 	/* Make certain the room does not cross the dungeon edge. */
2758 	if ((!square_in_bounds(c, loc(x1, y1))) ||
2759 		(!square_in_bounds(c, loc(x2, y2))))
2760 		return (false);
2761 
2762 	/* Determine how much space we have. */
2763 	area = ABS(y2 - y1) * ABS(x2 - x1);
2764 
2765 	/* Calculate the number of smaller chambers to make. */
2766 	num_chambers = 10 + area / 80;
2767 
2768 	/* Build the chambers. */
2769 	for (i = 0; i < num_chambers; i++) {
2770 		int c_y1, c_x1, c_y2, c_x2;
2771 		int size, width_local, height_local;
2772 
2773 		/* Determine size of chamber. */
2774 		size = 3 + randint0(4);
2775 		width_local = size + randint0(10);
2776 		height_local = size + randint0(4);
2777 
2778 		/* Pick an upper-left corner at random. */
2779 		c_y1 = y1 + randint0(1 + y2 - y1 - height_local);
2780 		c_x1 = x1 + randint0(1 + x2 - x1 - width_local);
2781 
2782 		/* Determine lower-right corner of chamber. */
2783 		c_y2 = c_y1 + height_local;
2784 		if (c_y2 > y2) c_y2 = y2;
2785 
2786 		c_x2 = c_x1 + width_local;
2787 		if (c_x2 > x2) c_x2 = x2;
2788 
2789 		/* Make me a (magma filled) chamber. */
2790 		make_chamber(c, c_y1, c_x1, c_y2, c_x2);
2791 	}
2792 
2793 	/* Remove useless doors, fill in tiny, narrow rooms. */
2794 	for (grid.y = y1; grid.y <= y2; grid.y++) {
2795 		for (grid.x = x1; grid.x <= x2; grid.x++) {
2796 			count = 0;
2797 
2798 			/* Stay legal. */
2799 			if (!square_in_bounds_fully(c, grid))
2800 				continue;
2801 
2802 			/* Check all adjacent grids. */
2803 			for (d = 0; d < 8; d++) {
2804 				/* Extract adjacent location */
2805 				struct loc grid1 = loc_sum(grid, ddgrid_ddd[d]);
2806 
2807 				/* Count the walls and dungeon granite. */
2808 				if ((square(c, grid1)->feat == FEAT_GRANITE) &&
2809 					(!square_iswall_outer(c, grid1)) &&
2810 					(!square_iswall_solid(c, grid1)))
2811 					count++;
2812 			}
2813 
2814 			/* Five adjacent walls: Change non-chamber to wall. */
2815 			if ((count == 5) && (square(c, grid)->feat != FEAT_MAGMA))
2816 				set_marked_granite(c, grid, SQUARE_WALL_INNER);
2817 
2818 			/* More than five adjacent walls: Change anything to wall. */
2819 			else if (count > 5)
2820 				set_marked_granite(c, grid, SQUARE_WALL_INNER);
2821 		}
2822 	}
2823 
2824 	/* Pick a random magma spot near the center of the room. */
2825 	for (i = 0; i < 50; i++) {
2826 		grid = loc(x1 + ABS(x2 - x1) / 4 + randint0(ABS(x2 - x1) / 2),
2827 				   y1 + ABS(y2 - y1) / 4 + randint0(ABS(y2 - y1) / 2));
2828 		if (square(c, grid)->feat == FEAT_MAGMA)
2829 			break;
2830 	}
2831 
2832 	/* Hollow out the first room. */
2833 	square_set_feat(c, grid, FEAT_FLOOR);
2834 	hollow_out_room(c, grid);
2835 
2836 	/* Attempt to change every in-room magma grid to open floor. */
2837 	for (i = 0; i < 100; i++) {
2838 		/* Assume this run will do no useful work. */
2839 		bool joy = false;
2840 
2841 		/* Make new doors and tunnels between magma and open floor. */
2842 		for (grid.y = y1; grid.y < y2; grid.y++) {
2843 			for (grid.x = x1; grid.x < x2; grid.x++) {
2844 				/* Current grid must be magma. */
2845 				if (square(c, grid)->feat != FEAT_MAGMA) continue;
2846 
2847 				/* Stay legal. */
2848 				if (!square_in_bounds_fully(c, grid)) continue;
2849 
2850 				/* Check only horizontal and vertical directions. */
2851 				for (d = 0; d < 4; d++) {
2852 					struct loc grid1, grid2;
2853 
2854 					/* Extract adjacent location */
2855 					grid1 = loc_sum(grid, ddgrid_ddd[d]);
2856 
2857 					/* Need inner wall. */
2858 					if (!square_iswall_inner(c, grid1))
2859 						continue;
2860 
2861 					/* Keep going in the same direction, if in bounds. */
2862 					grid2 = loc_sum(grid1, ddgrid_ddd[d]);
2863 					if (!square_in_bounds(c, grid2)) continue;
2864 
2865 					/* If we find open floor, place a door. */
2866 					if (square(c, grid2)->feat == FEAT_FLOOR) {
2867 						joy = true;
2868 
2869 						/* Make a broken door in the wall grid. */
2870 						square_set_feat(c, grid1, FEAT_BROKEN);
2871 
2872 						/* Hollow out the new room. */
2873 						square_set_feat(c, grid, FEAT_FLOOR);
2874 						hollow_out_room(c, grid);
2875 
2876 						break;
2877 					}
2878 
2879 					/* If we find more inner wall... */
2880 					if (square_iswall_inner(c, grid2)) {
2881 						/* ...Keep going in the same direction. */
2882 						struct loc grid3 = loc_sum(grid2, ddgrid_ddd[d]);
2883 						if (!square_in_bounds(c, grid3)) continue;
2884 
2885 						/* If we /now/ find floor, make a tunnel. */
2886 						if (square(c, grid3)->feat == FEAT_FLOOR) {
2887 							joy = true;
2888 
2889 							/* Turn both wall grids into floor. */
2890 							square_set_feat(c, grid1, FEAT_FLOOR);
2891 							square_set_feat(c, grid2, FEAT_FLOOR);
2892 
2893 							/* Hollow out the new room. */
2894 							square_set_feat(c, grid, FEAT_FLOOR);
2895 							hollow_out_room(c, grid);
2896 
2897 							break;
2898 						}
2899 					}
2900 				}
2901 			}
2902 		}
2903 
2904 		/* If we could find no work to do, stop. */
2905 		if (!joy) break;
2906 	}
2907 
2908 
2909 	/* Turn broken doors into a random kind of door, remove open doors. */
2910 	for (grid.y = y1; grid.y <= y2; grid.y++) {
2911 		for (grid.x = x1; grid.x <= x2; grid.x++) {
2912 			if (square(c, grid)->feat == FEAT_OPEN)
2913 				set_marked_granite(c, grid, SQUARE_WALL_INNER);
2914 			else if (square(c, grid)->feat == FEAT_BROKEN)
2915 				place_random_door(c, grid);
2916 		}
2917 	}
2918 
2919 
2920 	/* Turn all walls and magma not adjacent to floor into dungeon granite. */
2921 	/* Turn all floors and adjacent grids into rooms, sometimes lighting them */
2922 	for (grid.y = (y1 - 1 > 0 ? y1 - 1 : 0);
2923 		 grid.y < (y2 + 2 < c->height ? y2 + 2 : c->height); grid.y++) {
2924 		for (grid.x = (x1 - 1 > 0 ? x1 - 1 : 0);
2925 			 grid.x < (x2 + 2 < c->width ? x2 + 2 : c->width); grid.x++) {
2926 
2927 			if (square_iswall_inner(c, grid)
2928 				|| (square(c, grid)->feat == FEAT_MAGMA)) {
2929 				for (d = 0; d < 9; d++) {
2930 					/* Extract adjacent location */
2931 					struct loc grid1 = loc_sum(grid, ddgrid_ddd[d]);
2932 
2933 					/* Stay legal */
2934 					if (!square_in_bounds(c, grid1)) continue;
2935 
2936 					/* No floors allowed */
2937 					if (square(c, grid1)->feat == FEAT_FLOOR) break;
2938 
2939 					/* Turn me into dungeon granite. */
2940 					if (d == 8)
2941 						set_marked_granite(c, grid, SQUARE_NONE);
2942 				}
2943 			}
2944 			if (square_isfloor(c, grid)) {
2945 				for (d = 0; d < 9; d++) {
2946 					/* Extract adjacent location */
2947 					struct loc grid1 = loc_sum(grid, ddgrid_ddd[d]);
2948 
2949 					/* Stay legal */
2950 					if (!square_in_bounds(c, grid1)) continue;
2951 
2952 					/* Turn into room, forbid stairs. */
2953 					sqinfo_on(square(c, grid1)->info, SQUARE_ROOM);
2954 					sqinfo_on(square(c, grid1)->info, SQUARE_NO_STAIRS);
2955 
2956 					/* Illuminate if requested. */
2957 					if (light) sqinfo_on(square(c, grid1)->info, SQUARE_GLOW);
2958 				}
2959 			}
2960 		}
2961 	}
2962 
2963 
2964 	/* Turn all inner wall grids adjacent to dungeon granite into outer walls */
2965 	for (grid.y = (y1 - 1 > 0 ? y1 - 1 : 0);
2966 		 grid.y < (y2 + 2 < c->height ? y2 + 2 : c->height); grid.y++) {
2967 		for (grid.x = (x1 - 1 > 0 ? x1 - 1 : 0);
2968 			 grid.x < (x2 + 2 < c->width ? x2 + 2 : c->width); grid.x++) {
2969 
2970 			/* Stay legal. */
2971 			if (!square_in_bounds_fully(c, grid)) continue;
2972 
2973 			if (square_iswall_inner(c, grid)) {
2974 				for (d = 0; d < 9; d++) {
2975 					/* Extract adjacent location */
2976 					struct loc grid1 = loc_sum(grid, ddgrid_ddd[d]);
2977 
2978 					/* Look for dungeon granite */
2979 					if ((square(c, grid1)->feat == FEAT_GRANITE) &&
2980 						(!square_iswall_inner(c, grid)) &&
2981 						(!square_iswall_outer(c, grid)) &&
2982 						(!square_iswall_solid(c, grid)))
2983 					{
2984 						/* Turn me into outer wall. */
2985 						set_marked_granite(c, grid, SQUARE_WALL_OUTER);
2986 
2987 						/* Done; */
2988 						break;
2989 					}
2990 				}
2991 			}
2992 		}
2993 	}
2994 
2995 	/*** Now we get to place the monsters. ***/
2996 	get_chamber_monsters(c, y1, x1, y2, x2, name, height * width);
2997 
2998 	/* Increase the level rating */
2999 	c->mon_rating += 10;
3000 
3001 	/* Describe */
3002 	ROOM_LOG("Room of chambers (%s)", strlen(name) ? name : "empty");
3003 
3004 	/* Success. */
3005 	return (true);
3006 }
3007 
3008 /**
3009  * A single starburst-shaped room of extreme size, usually dotted or
3010  * even divided with irregularly-shaped fields of rubble. No special
3011  * monsters.  Appears deeper than level 40.
3012  * \param c the chunk the room is being built in
3013  *\ param centre the room centre; out of chunk centre invokes find_space()
3014  * \return success
3015  *
3016  * These are the largest, most difficult to position, and thus highest-
3017  * priority rooms in the dungeon.  They should be rare, so as not to
3018  * interfere with greater vaults.
3019  */
build_huge(struct chunk * c,struct loc centre,int rating)3020 bool build_huge(struct chunk *c, struct loc centre, int rating)
3021 {
3022 	bool light;
3023 
3024 	int i, count;
3025 
3026 	int y1, x1, y2, x2;
3027 	int y1_tmp, x1_tmp, y2_tmp, x2_tmp;
3028 	int width_tmp, height_tmp;
3029 
3030 	int height = 30 + randint0(10);
3031 	int width = 45 + randint0(50);
3032 
3033 	/* Only try to build a huge room as the first room. */
3034 	if (dun->cent_n > 0) return false;
3035 
3036 	/* Flat 5% chance */
3037 	if (!one_in_(20)) return false;
3038 
3039 	/* This room is usually lit. */
3040 	light = !one_in_(3);
3041 
3042 	/* Find and reserve some space.  Get center of room. */
3043 	if ((centre.y >= c->height) || (centre.x >= c->width)) {
3044 		if (!find_space(&centre, height, width))
3045 			return (false);
3046 	}
3047 
3048 	/* Locate the room */
3049 	y1 = centre.y - height / 2;
3050 	x1 = centre.x - width / 2;
3051 	y2 = y1 + height - 1;
3052 	x2 = x1 + width - 1;
3053 
3054 	/* Make a huge starburst room with optional light. */
3055 	if (!generate_starburst_room(c, y1, x1, y2, x2, light, FEAT_FLOOR, false))
3056 		return (false);
3057 
3058 	/* Often, add rubble to break things up a bit. */
3059 	if (randint1(5) > 2) {
3060 		/* Determine how many rubble fields to add (between 1 and 6). */
3061 		count = height * width * randint1(2) / 1100;
3062 
3063 		/* Make the rubble fields. */
3064 		for (i = 0; i < count; i++) {
3065 			height_tmp = 8 + randint0(16);
3066 			width_tmp = 10 + randint0(24);
3067 
3068 			/* Semi-random location. */
3069 			y1_tmp = y1 + randint0(height - height_tmp);
3070 			x1_tmp = x1 + randint0(width - width_tmp);
3071 			y2_tmp = y1_tmp + height_tmp;
3072 			x2_tmp = x1_tmp + width_tmp;
3073 
3074 			/* Make the rubble field. */
3075 			generate_starburst_room(c, y1_tmp, x1_tmp, y2_tmp, x2_tmp,
3076 									false, FEAT_PASS_RUBBLE, false);
3077 		}
3078 	}
3079 
3080 	/* Describe */
3081 	ROOM_LOG("Huge room");
3082 
3083 	/* Success. */
3084 	return (true);
3085 }
3086 
3087 /**
3088  * Attempt to build a room of the given type at the given block
3089  *
3090  * \param c the chunk the room is being built in
3091  * \param by0 block co-ordinates of the top left block
3092  * \param bx0 block co-ordinates of the top left block
3093  * \param profile the profile of the rooom we're trying to build
3094  * \param finds_own_space whether we are allowing the room to place itself
3095  * \return success
3096  *
3097  * Note that this code assumes that profile height and width are the maximum
3098  * possible grid sizes, and then allocates a number of blocks that will always
3099  * contain them.
3100  *
3101  * Note that we restrict the number of pits/nests to reduce
3102  * the chance of overflowing the monster list during level creation.
3103  */
room_build(struct chunk * c,int by0,int bx0,struct room_profile profile,bool finds_own_space)3104 bool room_build(struct chunk *c, int by0, int bx0, struct room_profile profile,
3105 	bool finds_own_space)
3106 {
3107 	/* Extract blocks */
3108 	int by1 = by0;
3109 	int bx1 = bx0;
3110 	int by2 = by0 + profile.height / dun->block_hgt;
3111 	int bx2 = bx0 + profile.width / dun->block_wid;
3112 
3113 	struct loc centre;
3114 	int by, bx;
3115 
3116 	/* Enforce the room profile's minimum depth */
3117 	if (c->depth < profile.level) return false;
3118 
3119 	/* Only allow at most two pit/nests room per level */
3120 	if ((dun->pit_num >= z_info->level_pit_max) && (profile.pit)) return false;
3121 
3122 	/* Expand the number of blocks if we might overflow */
3123 	if (profile.height % dun->block_hgt) by2++;
3124 	if (profile.width % dun->block_wid) bx2++;
3125 
3126 	/* Does the profile allocate space, or the room find it? */
3127 	if (finds_own_space) {
3128 		/* Try to build a room, pass silly place so room finds its own */
3129 		if (!profile.builder(c, loc(c->width, c->height), profile.rating))
3130 			return false;
3131 	} else {
3132 		/* Never run off the screen */
3133 		if (by1 < 0 || by2 >= dun->row_blocks) return false;
3134 		if (bx1 < 0 || bx2 >= dun->col_blocks) return false;
3135 
3136 		/* Verify open space */
3137 		for (by = by1; by <= by2; by++) {
3138 			for (bx = bx1; bx <= bx2; bx++) {
3139 				/* previous rooms prevent new ones */
3140 				if (dun->room_map[by][bx]) return false;
3141 			}
3142 		}
3143 
3144 		/* Get the location of the room */
3145 		centre = loc(((bx1 + bx2 + 1) * dun->block_wid) / 2,
3146 					 ((by1 + by2 + 1) * dun->block_hgt) / 2);
3147 
3148 		/* Try to build a room */
3149 		if (!profile.builder(c, centre, profile.rating)) return false;
3150 
3151 		/* Save the room location */
3152 		if (dun->cent_n < z_info->level_room_max) {
3153 			dun->cent[dun->cent_n] = centre;
3154 			dun->cent_n++;
3155 		}
3156 
3157 		/* Reserve some blocks */
3158 		for (by = by1; by < by2; by++) {
3159 			for (bx = bx1; bx < bx2; bx++) {
3160 				dun->room_map[by][bx] = true;
3161 			}
3162 		}
3163 	}
3164 
3165 	/* Count pit/nests rooms */
3166 	if (profile.pit) dun->pit_num++;
3167 
3168 	/* Success */
3169 	return true;
3170 }
3171