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(¢re, 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(¢re, 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(¢re, 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(¢re, 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(¢re, 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(¢re, 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(¢re, 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(¢re, 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(¢re, 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(¢re, 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(¢re, 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(¢re, 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(¢re, 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